Skip to content

Merchants: How to "Destroy" items sold to Merc;hant

Is there a way to make merchants "destroy" the items players sell to them - making the items sold to the merchant un-buyable because they're removed from the shops inventory?

Comments

  • YigorYigor Member Posts: 798
    What's the purpose of this destruction?
  • Ugly_DuckUgly_Duck Member Posts: 182
    edited February 2023
    so the items don't clutter up the vendor's inventory, and also, i dont want players to be able to buy these items back
  • MelkiorMelkior Member Posts: 204
    edited February 2023
    The simplest way might be to use the OnAcquireItem event. Check that the caller is a merchant, then get the object and use the DestroyObject function on it. It should be possible to exclude certain merchants if you really want to.

    But if your only motivation was to clear up the merchant's inventory, that could be done by having a merchant shop which sells nothing and then have it erase everything in its inventory every time the shop is closed. Players will still be able to buy objects from the merchant, but only until someone closes their access to the shop.

    All merchants which sell things would be set to not buy anything. The player would need to access a different shop in order to sell items.
  • ProlericProleric Member Posts: 1,316
    Problem is, merchants don't fire the OnAcquireItem event.

    The OnUnAcquireItem event isn't much help, either, as far as I can see - you can detect that a PC has lost an item, but you can't easily discover whether it was sold or lost in some other way.

    So the OnStoreClosed method is probably the only one. There's no way to prevent the PC from buying an item back before the store closes.
  • MelkiorMelkior Member Posts: 204
    Proleric wrote: »
    Problem is, merchants don't fire the OnAcquireItem event.

    The OnUnAcquireItem event isn't much help, either, as far as I can see - you can detect that a PC has lost an item, but you can't easily discover whether it was sold or lost in some other way.

    So the OnStoreClosed method is probably the only one. There's no way to prevent the PC from buying an item back before the store closes.

    It looks to me as though it should be possible to use OnUnAcquireItem, by using GetModuleItemLost() along with GetItemPossessor(). Then use GetObjectType() on the object returned by the last function and if it's a merchant, use DestroyObject() to get rid of the item which was returned by GetModuleItemLost().
  • ProlericProleric Member Posts: 1,316
    Unfortunately, when a PC sells an item to a merchant, the OnUnAcquireItem event fires, but GetModuleItemLost() and GetItemPossessor() don't return useful values. I tested the same script by giving an item to a companion - that works perfectly.

    Nice idea, but NWScript event functions are surprisingly picky about the exact circumstances in which they will work as expected.

    I'd be pretty cautious about destroying items, on refection. Obviously, truly "mission-critical" items should be Plot, to prevent game-breaking mistakes, but there is a grey area of "very useful" items which maybe you don't want to destroy irreversably. I've lost count of the number of times I've sold an item which turns out to be pretty effective against a monster, but can't remember who I sold it to...
  • mmatmmat Member Posts: 18
    This is my solution to the problem. The Items which are regular in the shop need to be marked on the first open event:

    // put this in the "OnOpenStore"-event
    void main()
    {
    if (GetLocalInt(OBJECT_SELF, "init_done")) return;
    SetLocalInt(OBJECT_SELF, "init_done", 1);

    object o = GetFirstItemInInventory(OBJECT_SELF);
    while (GetIsObjectValid(o))
    {
    SetDescription (o, "1", FALSE);
    o = GetNextItemInInventory(OBJECT_SELF);
    }
    }

    // put this in the "OnStoreClosed"-event
    void main()
    {
    object o = GetFirstItemInInventory(OBJECT_SELF);
    while (GetIsObjectValid(o))
    {
    string s = GetDescription (o, FALSE, FALSE);
    if (s != "1") DestroyObject (o);
    o = GetNextItemInInventory(OBJECT_SELF);
    }
  • MelkiorMelkior Member Posts: 204
    edited March 2023
    Bracketing the previous script in code markers, and correcting a couple of small mistakes:
    // put this in the "OnOpenStore"-event
    void main()
    {
      if (GetLocalInt(OBJECT_SELF, "init_done")) return;
      SetLocalInt(OBJECT_SELF, "init_done", 1);
    
      object o = GetFirstItemInInventory(OBJECT_SELF);
      while (GetIsObjectValid(o))
      {
        SetDescription (o, "1", FALSE);
        o = GetNextItemInInventory(OBJECT_SELF);
      }
    }
    
    // put this in the "OnStoreClosed"-event
    void main()
    {
      object o = GetFirstItemInInventory(OBJECT_SELF);
      string s;
      while (GetIsObjectValid(o))
      {
        s = GetDescription (o, FALSE, FALSE);
        if (s != "1") DestroyObject (o);
        o = GetNextItemInInventory(OBJECT_SELF);
      } 
    }
    
    That's a clever way of doing it. I would have tried using local variables rather than the unidentified item description, but your way certainly will work, so long as no script ever makes the item "unidentified" again (which may happen with a custom crafting system). It's possible that using a local variable would not work, depending on how the game handles items in shops.
  • mmatmmat Member Posts: 18
    Hello,

    >> Bracketing the previous script in code markers, and correcting a couple of small mistakes:

    Didn't find the button for "bracketing". Now I see one must open the drop down menu at the pilcrow ... Sorry.



  • MelkiorMelkior Member Posts: 204
    mmat wrote: »
    Hello,

    >> Bracketing the previous script in code markers, and correcting a couple of small mistakes:

    Didn't find the button for "bracketing". Now I see one must open the drop down menu at the pilcrow ... Sorry.

    The simplest way I found is to use the word "code" enclosed in square braces "[" and "]" just before the code segment and use "/code" (also enclosed in square braces) just after the end. Using the menu options inserts those markers, but I find typing them by hand easier than messing around with menu options. But then again, I touch-type so ymmv.
  • McLaineMcLaine Member Posts: 6
    I've only recently started checking this forum again, so sorry am a bit late.
    If all the items you want to keep are marked as infinite, then having this script in the merchant's 'onstoreclosed' event will get rid of anything the PC has just sold to the merchant.
    void main()
    {
        object oStore = OBJECT_SELF;
    
        object oInventoryItem = GetFirstItemInInventory( oStore );
    
        while( GetIsObjectValid( oInventoryItem ) )
        {
            if( !GetInfiniteFlag( oInventoryItem ) ) DestroyObject( oInventoryItem );
    
            oInventoryItem = GetNextItemInInventory( oStore );
        }
    }
    
  • Ugly_DuckUgly_Duck Member Posts: 182
    McLaine wrote: »
    I've only recently started checking this forum again, so sorry am a bit late.
    If all the items you want to keep are marked as infinite, then having this script in the merchant's 'onstoreclosed' event will get rid of anything the PC has just sold to the merchant.
    void main()
    {
        object oStore = OBJECT_SELF;
    
        object oInventoryItem = GetFirstItemInInventory( oStore );
    
        while( GetIsObjectValid( oInventoryItem ) )
        {
            if( !GetInfiniteFlag( oInventoryItem ) ) DestroyObject( oInventoryItem );
    
            oInventoryItem = GetNextItemInInventory( oStore );
        }
    }
    

    I tried this and it worked great! Thanks friend!
Sign In or Register to comment.