• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[Solved] Protecting Players' items

Status
Not open for further replies.
Level 15
Joined
Aug 7, 2013
Messages
1,338
Hi,

What is the best way to make it so some subset of items cannot be picked up by another player?

I want to bind some items permanently to player A, so he can't just give them to Player B or if he drops one, player B can't pick it up.

What is the most efficient way to do this?
 
Level 15
Joined
Aug 7, 2013
Messages
1,338
Thank you for your brief answers. But none really helped...

I shall try to clarify my question, since I might have not worded it so good.

1) What is the best way to bind an item to a player, so I can check who owns that item, regardless of where the item is (in the inventory or on the ground).

2) Once I have 1) in place, what is the best way to either prevent the unit from picking it up, or forcing it to drop it immediately?

I am hoping for something simple like this:

JASS:
private function main takes nothing returns boolean
    if GetManipulatedItem() does not belong to TriggeringPlayer() then
       call TriggerUnit() to unequip item
    endif
    return false
endfunction

private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterPlayerUnitEventSimple(t, Player(0), EVENT_PLAYER_UNIT_PICKUP_ITEM)
    call TriggerAddCondition(t, Condition(function main))
    set t = null
endfunction

Put some pseudcode in, but the main point should be klar.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,259
When a player picks up such an item, use a hashtable to map the item to its owner. Remember to account for item destruction to prevent a leak (you should anyway since killed items are never removed otherwise and leak). If a player picks up a previously owned item (has hashtable entry) then you need to remove the item from his inventory.

If I recall, you need to use a 0 second timer to add some delay before dropping the item as immediately removing it in response to the event will result in the unit immediately picking it up again and forming an infinite loop.
 
Level 15
Joined
Aug 7, 2013
Messages
1,338
Oh so there's no internal flag in Items (like say units) that marks its owner?

I had thought I saw a native this native GetItemUserData which checked if an item belonged to some player?
 

Chaosy

Tutorial Reviewer
Level 40
Joined
Jun 9, 2011
Messages
13,219
here you go nice and simple
  • Untitled Trigger 003
    • Events
      • Unit - A unit Acquires an item
    • Conditions
    • Actions
      • Custom script: local integer i = GetItemUserData(GetManipulatedItem())
      • Custom script: local integer i2 = GetPlayerId(GetOwningPlayer(GetTriggerUnit())) + 1
      • Custom script: if i == 0 then
      • Custom script: call SetItemUserData(GetManipulatedItem(), i2)
      • Custom script: elseif i != i2 then
      • Hero - Drop (Item being manipulated) from (Hero manipulating item)
      • Game - Display to (All players) the text: asd
      • Custom script: endif
I had this laying in my finished systems folder :p
 
Or you could simply use the custom value of an item and by that bind it to a player.
I don't know when you want it "soul bound". I assume it is when a unit picks up an item for the first time.
Set the custom value of the item being manipulated to, let's say 1 for Player 1, and just refer to the custom value in all of you item handling triggers.
 
Level 15
Joined
Aug 7, 2013
Messages
1,338
Or you could simply use the custom value of an item and by that bind it to a player.
I don't know when you want it "soul bound". I assume it is when a unit picks up an item for the first time.
Set the custom value of the item being manipulated to, let's say 1 for Player 1, and just refer to the custom value in all of you item handling triggers.

That would be a good time probably. What's the native to read and set this value?

And if it's that easy, why did no one else recommend this?

Also, if I have multiple item pick up events but only a single generic one where I check for ownership, will that intercept the other ones from firing off, or do I need to perform the check in each and every trigger action that involves a manipulated item?
 
Level 15
Joined
Aug 7, 2013
Messages
1,338
1. I use that in my trigger I showed you.
2. when I talked about hashtables I thought of protecting a item to a unitl. You only wanted to protect the item for a player

What do you mean by "protect a item to a unit?" As in bind an item to a specific unit versus a player?

I don't know GUI, so when I read it I thought I saw hash table. But second glance shows otherwise, my mistake!
 
That would be a good time probably. What's the native to read and set this value?

And if it's that easy, why did no one else recommend this?

Also, if I have multiple item pick up events but only a single generic one where I check for ownership, will that intercept the other ones from firing off, or do I need to perform the check in each and every trigger action that involves a manipulated item?

Actually I have no idea if it works. But that's how I would start out. Perhaps no one thought of that particular solution, I don't know.

I believe you must check the custom value each time a unit acquire an item.
If you fx. have item drops you must set the custom value to a value that is not equal to a number of a player. Unless dropped items gets soulbound when dropped of course.

The native?
You mean the Jass function? I'm only experienced in GUI...
 
Level 37
Joined
Mar 6, 2006
Messages
9,243
You could do it like this
  • Untitled Trigger 001
    • Events
      • Unit - A unit Acquires an item
    • Conditions
    • Actions
      • Custom script: set udg_id = GetHandleId(GetManipulatedItem())
      • Set pid = (Player number of (Triggering player))
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (0 is stored as a Integer of id in itemHt) Equal to True
        • Then - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • pid Equal to (Load 0 of id from itemHt)
            • Then - Actions
              • Trigger - Run Untitled Trigger 002 <gen> (checking conditions)
              • Trigger - Run Untitled Trigger 003 <gen> (checking conditions)
              • Trigger - Run Untitled Trigger 004 <gen> (checking conditions)
            • Else - Actions
              • Hero - Drop (Item being manipulated) from (Triggering unit)
        • Else - Actions
          • Hashtable - Save pid as 0 of id in itemHt
          • Trigger - Run Untitled Trigger 002 <gen> (checking conditions)
          • Trigger - Run Untitled Trigger 003 <gen> (checking conditions)
          • Trigger - Run Untitled Trigger 004 <gen> (checking conditions)
This locks the item to the player who first picked it up. It runs the other triggers only if an item is successfully picked up. You could filter out tomes and runes, items that do not end up in your inventory. Run the triggers ignoring conditions if they do not have anything in the main condition.
 
Level 14
Joined
Jun 27, 2008
Messages
1,325
This should do the job. Just copy it into your map.

JASS:
library ItemBinding initializer init
    private function pickupItem takes nothing returns nothing
        local item i = GetManipulatedItem()
        local unit u = GetTriggerUnit()
        // check if item is bound
        if GetItemUserData(i) == 0 then
            // not bound, bind it
            call SetItemUserData(i, GetPlayerId(GetOwningPlayer(u))+1)
        else
            // bound
            if GetItemUserData(i) != GetPlayerId(GetOwningPlayer(u))+1 then
                call UnitDropItemPoint(u, i, GetUnitX(u), GetUnitY(u))
                call DisplayTextToPlayer(GetOwningPlayer(u), 0., 0., "This item is bound")
            endif
        endif
    endfunction

    private function init takes nothing returns nothing
        set gg_trg_Item_Binding = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ(gg_trg_Item_Binding, EVENT_PLAYER_UNIT_PICKUP_ITEM)
        call TriggerAddAction(gg_trg_Item_Binding, function pickupItem)
    endfunction
endlibrary

It uses the items custom value. This works perfectly fine and is fast and simple (as you dont have to care about cleaning up hashtables when items get removed), the only problem is when you need the items custom value for something else then you get conflicts.
 

Attachments

  • Item Binding.w3x
    17.7 KB · Views: 41
Level 15
Joined
Aug 7, 2013
Messages
1,338
Thank you everyone again for the code provided. I am well on my way to doing this system now! I guess we can consider this solved?!
 
Status
Not open for further replies.
Top