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

No Item Sharing v1.11

  • Like
Reactions: Apheraz Lucent
JASS:
library NoItemSharing /*
    
                        No Item Sharing v1.11 by Flux
    -------------------------------------------------------------------------
    This System disable players from selling other player's item.
    It also allows other players from not using a certain player's item
    and/or disable its Stats Bonus. 
    It also allows to change icons and tooltips of Shared Items for easily 
    indicating the difference in-game.
    -------------------------------------------------------------------------
    
    */ requires /*
        */ optional Table /*  http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/
        If not found, this system will use a hashtable instead. Hashtables is limited to
        256 per map. If your map is close to the hashtable limit, it is recommended
        to use Table
    
    NOTES:
          - Dropping a Shared Item in the ground will turn it into the Original Item
            thus Shared Item only appear in Inventory. That way, you don't need to edit the Text
            Description (ides) of the Shared Version decreasing the overall purple data fields 
            of the map.
          - The Original Version and the Shared Version must be manually created at Object Editor
          - Useful in AoS, Hero Arena and Hero Defense Maps by not allowing team feeding to a certain
            player who will carry the whole team.
          - Added Bonus: Coincidentally make the Treasure Chest Play an opening animation when dropped.
          - To fully understand how the system works, test with DEBUG_SYSTEM = true and run in Debug Mode.
    
    -----------------------------------------------------------------------------------------
        Item Shared Version can either be:
         - Disabled Shared: The Shared Item is unuseable/provides no stats and cannot be sold
                            It is recommended to use a Disabled Icon for items like this.
                            Demo Example: Boots of Speed, Claws of Attack.
         - Usabled Shared:  The Shared Item can be used but cannot be sold. 
                            Demo Example: Clarity Potion
    -----------------------------------------------------------------------------------------
    
     ******************************************************************
     ***************************** API: *******************************
     ******************************************************************
        
        function ItemShare.data takes integer origId, integer shareId returns nothing
            - Tells the system the the shared item type of origId is sharedId.
        
        function ItemShare.getOwner takes item it returns player
            - Returns the owner of a certain item, returns null if item has no owner.
            - Returns null if item type is not in Database.
        
        function ItemShare.setOwner item it, player p returns nothing
            - Set the new owner of an item.
            - It automatically transform the items based on the new owner. If the new
              owner is null, the item is automatically dropped and the first player to
              pick it will be the new owner.
              
     ******************************************************************
     
     
  CREDITS:
     Bribe - Table
    
*/
    //===============================================================================
    //============================= CONFIGURATION ===================================
    //===============================================================================
    //! textmacro ITEM_SHARING_INITIAL_DATA
        //*** Input Item rawcodes here **
        //call ItemShare.data(original Item Type, shared Item Type)
        call ItemShare.data('I000', 'I001')
        call ItemShare.data('I002', 'I003')
        call ItemShare.data('I004', 'I005')
        call ItemShare.data('I006', 'I007')
        //** Add more here **
        //call ItemShare.data(original Item Type, shared Item Type)
        //........
    //! endtextmacro
    
    globals
        //Show Debug Messages to help you understand how the system works.
        private constant boolean DEBUG_SYSTEM = true
    endglobals
    //===============================================================================
    //=========================== END CONFIGURATION =================================
    //===============================================================================
    
    struct ItemShare extends array
        //Integer: alternate type (uses itemTypeId)
        //Player: owner (uses GetHandleId)
        //Boolean: status (uses itemTypeId) - true if original, false if shared
        static if LIBRARY_Table then
            private static Table tb
            private static Table holder
        else
            private static hashtable hash = InitHashtable() 
            
        endif
        
        private static trigger pickTrg = CreateTrigger()
        private static trigger dropTrg = CreateTrigger()
        
        static if DEBUG_SYSTEM then
            private static constant string prefix = "|cffffcc00[NoItemSharing]|r: "
        endif
        
        static method data takes integer origId, integer shareId returns nothing
            static if LIBRARY_Table then
                set tb[origId] = shareId
                set tb[shareId] = origId
                set tb.boolean[origId] = true     
                set tb.boolean[shareId] = false
            else
                call SaveInteger(hash, origId, 0, shareId)
                call SaveInteger(hash, shareId, 0, origId)
                call SaveBoolean(hash, origId, 0, true)
                call SaveBoolean(hash, shareId, 0, false)
            endif
        endmethod
        
        private static method convert takes nothing returns nothing
            local timer t = GetExpiredTimer()
            local integer handleId = GetHandleId(t)
            local real x
            local real y
            
            static if LIBRARY_Table then
                local item it = tb.item[handleId]
                local integer itemType1 = GetItemTypeId(it)
                local integer itemType2 = tb[itemType1]
                local boolean shared = not tb.boolean[itemType1] and tb.boolean[itemType2]
                local integer id = GetHandleId(it)
                local player owner = tb.player[id]
            else
                local item it = LoadItemHandle(hash, handleId, 0)
                local integer itemType1 = GetItemTypeId(it)
                local integer itemType2 = LoadInteger(hash, itemType1, 0)
                local boolean shared = not LoadBoolean(hash, itemType1, 0) and LoadBoolean(hash, itemType2, 0)
                local integer id = GetHandleId(it)
                local player owner = LoadPlayerHandle(hash, id, 0)
            endif
            
            if shared and not IsItemOwned(it) then
                set x = GetItemX(it)
                set y = GetItemY(it)
                static if DEBUG_SYSTEM then
                    call BJDebugMsg(prefix + "|cffffcc00" + GetItemName(it) + "|r is converted to its original form")
                endif
                call RemoveItem(it)
                set it = CreateItem(itemType2, x, y)
                static if LIBRARY_Table then
                    call tb.player.remove(id)
                    set tb.player[GetHandleId(it)] = owner
                else
                    call RemoveSavedHandle(hash, id, 0)
                    call SavePlayerHandle(hash, GetHandleId(it), 0, owner)
                endif
            endif
            
            static if LIBRARY_Table then
                call tb.item.remove(handleId)
            else
                call RemoveSavedHandle(hash, handleId, 0)
            endif
            
            set it = null
            call DestroyTimer(t)
            set t = null
            set owner = null
        endmethod
        

        private static method onDrop takes nothing returns boolean
            local item it = GetManipulatedItem()
            local integer itemType1 = GetItemTypeId(it)
            local integer id = GetHandleId(it)
            local timer t
            
            static if LIBRARY_Table then
                local integer itemType2 = tb[itemType1]
                if not tb.boolean[itemType1] and tb.boolean[itemType2] then
                    static if DEBUG_SYSTEM then
                        call BJDebugMsg(prefix + GetPlayerName(GetTriggerPlayer()) + " has dropped a shared Item belonging to " + GetPlayerName(tb.player[GetHandleId(it)]))
                    endif
                    set t = CreateTimer()
                    set tb.item[GetHandleId(t)] = it
                    call TimerStart(t, 0.0, false, function thistype.convert)
                    set t = null
                else
                    static if DEBUG_SYSTEM then
                        call BJDebugMsg(prefix + GetPlayerName(GetTriggerPlayer()) + " has dropped an original Item belonging to " + GetPlayerName(tb.player[GetHandleId(it)]))
                    endif
                endif
            else
                local integer itemType2 = LoadInteger(hash, itemType1, 0)
                if not LoadBoolean(hash, itemType1, 0) and LoadBoolean(hash, itemType2, 0) then
                    static if DEBUG_SYSTEM then
                        call BJDebugMsg(prefix + GetPlayerName(GetTriggerPlayer()) + " has dropped a shared Item belonging to " + GetPlayerName(LoadPlayerHandle(hash, GetHandleId(it), 0)))
                    endif
                    set t = CreateTimer()
                    call SaveItemHandle(hash, GetHandleId(t), 0, it)
                    call TimerStart(t, 0.0, false, function thistype.convert)
                    set t = null
                else
                    static if DEBUG_SYSTEM then
                        call BJDebugMsg(prefix + GetPlayerName(GetTriggerPlayer()) + " has dropped an original Item belonging to " + GetPlayerName(LoadPlayerHandle(hash, GetHandleId(it), 0)))
                    endif
                endif
            endif
            
            static if LIBRARY_Table then
                call holder.unit.remove(id)
            else
                call RemoveSavedHandle(hash, id, 1)
            endif
            
            set it = null
            return false
        endmethod
        
        private static method onPick takes nothing returns boolean
            local item it = GetManipulatedItem()
            local unit u = GetTriggerUnit()
            local integer id = GetHandleId(it)
            local player trigPlayer = GetTriggerPlayer()
            local integer itemType1 = GetItemTypeId(it)
            
            static if LIBRARY_Table then
                local integer itemType2 = tb[itemType1]
                local boolean orig = tb.boolean[itemType1] and not tb.boolean[itemType2]
                local boolean shared = not tb.boolean[itemType1] and tb.boolean[itemType2]
                local player prevPlayer = tb.player[id]
            else
                local integer itemType2 = LoadInteger(hash, itemType1, 0)
                local boolean orig = LoadBoolean(hash, itemType1, 0) and not LoadBoolean(hash, itemType2, 0)
                local boolean shared = not LoadBoolean(hash, itemType1, 0) and LoadBoolean(hash, itemType2, 0)
                local player prevPlayer = LoadPlayerHandle(hash, id, 0)
            endif
            
            static if DEBUG_SYSTEM then
                call BJDebugMsg(prefix + GetPlayerName(trigPlayer) + " has picked |cffffcc00" + GetItemName(it) + "|r which originally belongs to " + GetPlayerName(prevPlayer))
            endif
            
            //If item is in the database
            if (orig or shared) then
                //If item has no owner
                if prevPlayer == null then
                    static if LIBRARY_Table then
                        set tb.player[id] = trigPlayer
                    else
                        call SavePlayerHandle(hash, id, 0, trigPlayer)
                    endif
                    static if DEBUG_SYSTEM then
                        call BJDebugMsg(prefix + GetPlayerName(trigPlayer) + " is the now the owner of |cffffcc00" + GetItemName(it) + "|r")
                    endif
                endif
                
                //orig -> shared will happen if a player happens to pick an item belonging to other players
                //shared -> orig will happen if you're the owner or if there is no owner or if you're the owner
                if (orig and trigPlayer != prevPlayer and prevPlayer != null) or (shared and (prevPlayer == null or trigPlayer == prevPlayer)) then
                    //Convert
                    call DisableTrigger(pickTrg)
                    call DisableTrigger(dropTrg)                
                    static if DEBUG_SYSTEM then
                        call BJDebugMsg(prefix + "|cffffcc00" + GetItemName(it) + "|r is converted")
                    endif
                    call RemoveItem(it)
                    set it = CreateItem(itemType2, 0, 0)
                    call UnitAddItem(u, it)
                    static if LIBRARY_Table then
                        call tb.player.remove(id)
                        set tb.player[GetHandleId(it)] = prevPlayer
                    else
                        call RemoveSavedHandle(hash, id, 0)
                        call SavePlayerHandle(hash, GetHandleId(it), 0, prevPlayer)
                    endif
                    call EnableTrigger(pickTrg)
                    call EnableTrigger(dropTrg)
                endif
                
                //Save Unit holding the item to have O(1) operation for unit dropping the item
                static if LIBRARY_Table then
                    set holder.unit[GetHandleId(it)] = u
                else
                    call SaveUnitHandle(hash, GetHandleId(it), 1, u)
                endif
            else
                static if DEBUG_SYSTEM then
                    call BJDebugMsg(prefix + "|cffffcc00" + GetItemName(it) + "|r is not in the database. It will treate it as a normal item")
                endif
            endif
            
            set it = null
            set u = null
            set trigPlayer = null
            set prevPlayer = null
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            local integer i = 0
            loop
                call TriggerRegisterPlayerUnitEvent(pickTrg, Player(i), EVENT_PLAYER_UNIT_PICKUP_ITEM, null)
                call TriggerRegisterPlayerUnitEvent(dropTrg, Player(i), EVENT_PLAYER_UNIT_DROP_ITEM, null)
                set i = i + 1
                exitwhen i == bj_MAX_PLAYER_SLOTS
            endloop
            call TriggerAddCondition(pickTrg, Condition(function thistype.onPick))
            call TriggerAddCondition(dropTrg, Condition(function thistype.onDrop))
            static if LIBRARY_Table then
                set tb = Table.create()
                set holder = Table.create()
            endif
            //! runtextmacro ITEM_SHARING_INITIAL_DATA()
        endmethod
        
        static method getOwner takes item it returns player
            static if LIBRARY_Table then
                return tb.player[GetHandleId(it)]
            else
                return LoadPlayerHandle(hash, GetHandleId(it), 0)
            endif
        endmethod
        
        static method setOwner takes item it, player p returns nothing
            local integer itemType1 = GetItemTypeId(it)
            local unit u
            
            static if LIBRARY_Table then
                local integer itemType2 = tb[itemType1]
                local boolean orig = tb.boolean[itemType1] and not tb.boolean[itemType2]
                local boolean shared = not tb.boolean[itemType1] and tb.boolean[itemType2]
            else
                local integer itemType2 = LoadInteger(hash, itemType1, 0)
                local boolean orig = LoadBoolean(hash, itemType1, 0) and not LoadBoolean(hash, itemType2, 0)
                local boolean shared = not LoadBoolean(hash, itemType1, 0) and LoadBoolean(hash, itemType2, 0)
            endif
            
            if orig or shared then
                if p == null then  
                    static if LIBRARY_Table then
                        call tb.player.remove(GetHandleId(it))
                    else
                        call RemoveSavedHandle(hash, GetHandleId(it), 0)
                    endif
                else
                    static if LIBRARY_Table then
                        set tb.player[GetHandleId(it)] = p
                    else
                        call SavePlayerHandle(hash, GetHandleId(it), 0, p)
                    endif
                endif    
                
                //Refresh Item Status
                if IsItemOwned(it) then
                    static if LIBRARY_Table then
                        set u = holder.unit[GetHandleId(it)]
                    else
                        set u = LoadUnitHandle(hash, GetHandleId(it), 1)
                    endif
                    call UnitRemoveItem(u, it)
                    if p != null then
                        call UnitAddItem(u, it)
                    endif
                    set u = null
                endif
            endif
        endmethod
    endstruct

endlibrary


Changelog:
v1.00 - [7 July 2015]
- Initial Release

v1.01 - [7 July 2015]
- Uses Table instead to achieve O(1) operation

v1.02 [7 July 2015]
- Uses Table to store owner of Item instead of using ItemUserData
- Removed some unused variables
- Uses Disabled Icon on unuseable Shared Item.

v1.03 [13 July 2015]
- Fixed bug when obtaining an item not in the Database
- Fixed bug when passing a shared Item from player to another player (directly without dropping) who is also not the original owner.
- Added a lot of useful debug messages.
- Added a GetItemOwner API
- Improved test map demo.

v1.04 [27 July, 2015]
- Non-error messages placed in static ifs
- Used method Table.has to remove the +1 in PlayerId.

v1.05 [7 August, 2015]
- Made some code scripting changes like variable naming, debugging, etc.

v1.10 [28 May 2016]
- Completely rewrite the system.
- Made Table an optional requirement.
- Improved the coding.
- Changed API name.
- Added a function to allow users to change the owner of the item.

v1.11 [4 June 2016]
- ItemShare.setOwner now only works on items in the database.
- ItemShare.setOwner when item is owned is now an O(1) operation. It will no longer enumerate each unit to find the unit holding the item.
- Removed unnecessary disabling and re-enabling of triggers in method convert.

Keywords:
restrict, item, sharing, share
Contents

No Item Sharing (Map)

Reviews
Reviewer:KILLCIDE Time:12:06 Date:3 June 2016 Review:Link Status:Approved 19:46 - 28 May 2016 KILLCIDE: Status set to Pending on author's request. No Item Sharing v1.04 | Reviewed by BPower | 27.07.2015 Concept[/COLOR]] Allows...
Level 4
Joined
Jan 7, 2014
Messages
69
I highly doubt it has the same functionality as mine. 10 lines? Maybe what you did was dropped the item if it is picked up by another player. Mine is very different from that, you should have seen it for yourself.

smth like that, but not exactly. im still dont see the point for usin lot of useless code(libs) and create lot of dummy objects for that wich discrease a map size and loading speed. code should be a maximum simple everytime, i know u understand what i mean. if you wanna make simular dota codes, then i wanna tell u epic true: lot of things in dota released very bad and this is a last instance where u should look how smth is released or copy ideas. sor for my english, im not english speaker :). yes, dota map got alot of good and unique ideas, but how they are released, its another question (im still wondering, how this map still didnt get desync problem with that:)) :ogre_haosis: anyway you did a good code. GL HF
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
In my opinion, this is not useless. I made this system for my map and I just shared it here in hive if ever anyone else would need it.
The point is, to allow allies to pick your items but not allowing them to sell it. If you just did a simple: "If item is not yours, then drop it", then your ally wouldn't be able to pick your items. Plus, it has additional feature which you can configure if they can use the shared item or not.
You don't have proof to what you claim the 'epic truth'.
 
Level 4
Joined
Jan 7, 2014
Messages
69
In my opinion, this is not useless. I made this system for my map and I just shared it here in hive if ever anyone else would need it.
The point is, to allow allies to pick your items but not allowing them to sell it. If you just did a simple: "If item is not yours, then drop it", then your ally wouldn't be able to pick your items. Plus, it has additional feature which you can configure if they can use the shared item or not.
You don't have proof to what you claim the 'epic truth'.

first - i can make for alli heroes share items but not for enemies, anyway its + 1-2 lines in code for that but not tons of code and tons of libs. and second about epic true, i have proof, but ofc i will not share this. if u need this for ur map, ok use it, but really some ppls who dont know something they will use ur system in maps and same copy tons of objects, code and weird libs wich really unuseless...
 
Level 4
Joined
Jan 7, 2014
Messages
69
Can you show that 1-2 lines you speak of?

simple condition if IsPlayerAlly(GetOwningPlayer(heromanipulating item),Player(...)) then
code
else
code
endif

+ 3 lines :)
dude, i have nothing against ur system, but for make it works in other maps, need to do alot of work in map with copy+past objects and adding in tables...and now imagine, if map got over 200 items or more wich should be in this system...and imagine if player wanna ruin the game and dont wanna give item back to owner...or he will destroy the item. owner will lost gold and will have no item in result.


function IsIventoryFull takes unit u returns boolean
local item it
local integer slot = 0
local integer count = 0
loop
exitwhen slot > 6
set it = UnitItemInSlot(u,slot)
if it != null then
set count = count + 1
endif
set slot = slot + 1
endloop
set it = null
if count == 6 then
return true
else
return false
endif
endfunction

function ChangeDummyItem takes unit u, player p, integer newitemid returns nothing
local item it
local real x = GetUnitX(u)
local real y = GetUnitY(u)
set it = CreateItem(newitemid, x,y )
if not IsIventoryFull(u) then
call UnitAddItem(u, it)
endif
call SetItemInvulnerable( it, true )
call SetItemPlayer( it, p, true )
set it = null
endfunction


function BuyItem takes nothing returns boolean
local item it = GetSoldItem()
local integer i = 1
//all fake items i did as ITEM_TYPE_CHARGED for avoid unuselles trigger actions.
if GetItemType(it) == ITEM_TYPE_CHARGED then
loop
//this is not a fake item, this is for be possible buy item anyway if inventory is full (items in shops released as books)
exitwhen GetItemTypeId(it) == udg_ItemShopDummy or i > FakeItemsTotal
set i = i + 1
endloop
call RemoveItem(it)
call ChangeDummyItem(GetBuyingUnit(),GetOwningPlayer(GetBuyingUnit()),udg_ItemShopOriginal)
endif
set it = null
return false
endfunction

//===========================================================================
function InitTrig_BuyItem takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterPlayerUnitEvent(t, Player(10), EVENT_PLAYER_UNIT_SELL_ITEM, null)
call TriggerRegisterPlayerUnitEvent(t, Player(11), EVENT_PLAYER_UNIT_SELL_ITEM, null)
call TriggerAddCondition( t, Condition(function BuyItem) )
set t = null
endfunction

AND ANITHSARE
function try_share takes nothing returns boolean
if IsItemInvulnerable(GetManipulatedItem()) and GetItemPlayer(GetManipulatedItem()) != GetOwningPlayer(GetManipulatingUnit()) then
call UnitRemoveItem(GetManipulatingUnit(), GetManipulatedItem())
endif
return false
endfunction

//===========================================================================
function InitTrig_player_try_share takes nothing returns nothing
local trigger t = CreateTrigger( )
call AddEventPlayer(t, EVENT_PLAYER_UNIT_PICKUP_ITEM)
call TriggerAddCondition( t, Condition( function try_share ) )
set t = null
endfunction
 
Last edited:
Level 22
Joined
Feb 6, 2014
Messages
2,466
Lol those were not three lines.
I know adding the item to the list and creating the 'shared version' is a BIG con, but if your OCD strikes and really want it to be like in Dota ItemSharingSystem (like my case), then this is the system for you.

That was the point, you can destroy (or hide) enemy items but not steal its effect. Or any user could just set the item hp to very high if he/she didn't want items to get destroyed.
 
Level 4
Joined
Jan 7, 2014
Messages
69
Lol those were not three lines.
I know adding the item to the list and creating the 'shared version' is a BIG con, but if your OCD strikes and really want it to be like in Dota ItemSharingSystem (like my case), then this is the system for you.

That was the point, you can destroy (or hide) enemy items but not steal its effect. Or any user could just set the item hp to very high if he/she didn't want items to get destroyed.
antishare code 5 lines ok. not 3 )

why lot of ppl copying from dota things, while icefrog didnt make nothing himself and only steal systems, heroes, ideas without donate autors??? i still didnt get it, really. and afterall ppl thinks that its "from dota"...sad, really. ok. i see no point to continue this. GL HF
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Fuck, I failed to think of storing the unit holding the item in Table/Hashtable instead of Picking all Units in the Map.

Don't review this yet reviewers/mods until the next update.

EDUT: Actually, nevermind. Go review this so I can fix it all in the next update. Another error in the code is it should be tb.item.remove instead of tb.remove..
 
Level 37
Joined
Jul 22, 2015
Messages
3,485
All though the concept is not anything new, this will be an extremely useful system to many map makers and a great addition to the Hive! The API is extremely easy, and the code looks good to me (the optional Table is a plus). There are just a few minor things I questioned:
  • The local integer and loop on init to register the unit event makes it look soo convoluted. Some red text is nice!
  • In static method convert, what is the reason for disabling and enabling pickTrg and dropTrg? My only conclusion is that you wanted to avoid an infinite loop, but I can not see the possibility of it ever happening with this system
  • The addition of "(Shared)" into the names of items is a bit misleading
Of course they are extremely minor things, so the status is set to Approved with a 4/5 rating from me.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
The local integer and loop on init to register the unit event makes it look soo convoluted. Some red text is nice!
It is to avoid looping twice. I know it's a minor thing, but it was already there before this update so there's no point in changing it back to use the BJ function.


In static method convert, what is the reason for disabling and enabling pickTrg and dropTrg? My only conclusion is that you wanted to avoid an infinite loop, but I can not see the possibility of it ever happening with this system
Yes, good find. It was indeed unnecessary to disable/enable it.


The addition of "(Shared)" into the names of items is a bit misleading
Why?

Anyway, I was not expecting this would not be approved yet because of the rushed submission with O(n) operation. Anyway, it is fixed now (I just updated it).
 
Level 37
Joined
Jul 22, 2015
Messages
3,485
It is to avoid looping twice. I know it's a minor thing, but it was already there before this update so there's no point in changing it back to use the BJ function.
Yeah excuse my suggestion on that. It is indeed better to not have to loop twice through the player slots. It's only good to use the bj when you have one event.

People can mistaken it for an item that can actually be shared (as in being able to use it + gain stats).

Anyway, I was not expecting this would not be approved yet because of the rushed submission with O(n) operation. Anyway, it is fixed now (I just updated it).
I trusted that you would fix it considering the one you used in your DummyRecycler works flawwlessly. The overall system worked without any obvious issues on my tests as well, so I didn't see an issue not approving it.
 
Last edited:
Top