Adding displayverb to shop items you just sold

Edited post
When using: "Setting up a shop". The uncloned items in inventory will not show "Sell" in the inventory item's drop-down box of verbs.
I am attempting to do this through the player.changedparent script. You can see the addition I made.

I get an error stating: Can not modify the contents of the list as it is defined by an inherited type. And it needs to be cloned first.
What say ye?

Edited script

if (HasAttribute(game.pov.parent, "is_shop")) {
  foreach (object, GetDirectChildren (player)) {
    list add (object.displayverbs, "Sell")
  }
}
if (game.pov = this) {
  if (IsDefined("oldvalue")) {
    OnEnterRoom (oldvalue)
  }
  else {
    OnEnterRoom (null)
  }
  if (game.gridmap) {
    MergePOVCoordinates
  }
}
this.hasbeenmoved = true

First, I haven't used Pixie's Shop library, although I've created my own shop in my game(s).

Second, you should not use the player.changedparent script -- it is not necessary to do it there, and more unnecessary code there will add overhead to your game.

It sounds like you want to add the "Buy" displayverb to items the player sells to the shop, in case he wants to buy them back again later? If so, can't you just put the list add (object.displayverbs, "Buy") code into your "sell" command? Maybe I'm not understanding your intent.


Oh, you're trying to add the "Buy" displayverb to all the new items the shop is selling. In that case, why are the items in the player's inventory instead of in the shop room, i.e. foreach (object, GetDirectChildren (player)? Maybe that should be foreach (object, GetDirectChildren (game.pov.parent)? (You'll have to remove the player from the object list.)


KV had a simple way of copying an object's displayverbs list so that it could be modified:

object.displayverbs = ListExclude(object.displayverbs, "")

http://textadventures.co.uk/forum/samples/topic/d1-rxlik1ewi-zhkb5mqoa/easy-way-to-alter-an-objects-displayverbs-list


So I would start at the source, i.e., the code that adds/creates the sellable items to the shop (instead of player.changedparent) -- add scripting there that iterates through the list of sellable items with a foreach script, and run 1) KV's code on each item, plus 2) the list add (object.displayverbs, "Buy") code on each item.

I will try to follow up with a coded example.

@mrangel -
Feel free to jump in if you feel the need...


So sorry, Dcoder. Somehow I put in the wrong verb and explanation. Was late here. Was last working on buy script and goofed up on post.
Buy should be sell.
When player is in a shop, all of their inventory should have a sell verb added.
Right now they can type it in but I would like to see the sell button.
When they move around there will be no sell button till they enter a shop flagged shop. Then when they leave it disappears.


A simple example -- I made a few sellable objects and put them in the room YourShop:

SellablesList = GetDirectChildren(YourShop)
list remove (SellablesList, game.pov)
foreach (item, SellablesList) {
  item.displayverbs = ListExclude(item.displayverbs, "")
  list add (item.displayverbs, "Buy")
}

Now each (sellable) item in YourShop minus the player will have the "Buy" displayverb added to it.


Ok, in that case, go to the Shop room's "Scripts" tab, where it says "After entering the room:", and put in this code:

PlayerSellList = GetDirectChildren(game.pov)
foreach (item, PlayerSellList) {
  item.inventoryverbs = ListExclude(item.inventoryverbs, "")
  list add (item.inventoryverbs, "Sell")
}

To get rid of all the "Sell" inventoryverbs when the player leaves the Shop is a bit trickier, but definitely doable. More code to follow...


That worked like a charm


Actually, getting rid of all the "Sell" verbs should be easier. Just put this in the Shop's "After leaving the room:" section:

PlayerSellList = GetAllChildObjects(game.pov)
foreach (item, PlayerSellList) {
  list remove (item.inventoryverbs, "Sell")
}

I think that that will be OK. Trying to remove the "Sell" inventoryverb from an object that doesn't have it in its list should be OK.

I used GetAllChildObjects instead of GetDirectChildren in case the player put sellable objects in containers he was carrying, while he was in the shop.


Works on entry. but if I buy it back it has two sell verbs. and when I sell it it has two buy verbs... This is probably something else on my end. Will have to investigate...


Modified code for the Shop's "After entering the room:" section:

PlayerSellList = GetDirectChildren(game.pov)
foreach (item, PlayerSellList) {
  item.inventoryverbs = ListExclude(item.inventoryverbs, "")
  if (not ListContains(item.inventoryverbs, "Sell")) {
    list add (item.inventoryverbs, "Sell")
  }
}

Conversely, modified Buy code for the Shop, also add to Shop's "After entering..." section:

ShopSellList = GetDirectChildren(YourShop)
list remove (ShopSellList, game.pov)
foreach (item, ShopSellList) {
  item.displayverbs = ListExclude(item.displayverbs, "")
  if (not ListContains(item.displayverbs, "Buy")) {
    list add (item.displayverbs, "Buy")
  }
}

One issue is that items you have just sold will still have their "Sell" verb and no "Buy" verb, and items you have just bought will still have their "Buy" verb and no "Sell" verb, until you re-enter the Shop.

To resolve this, either a) put list remove and list add scripts on your "Sell" and "Buy" commands, so that the item's display/inventory verbs will be updated immediately, or b) have a local turn script (in the Shop) run the code every turn.


I'll make it simple -- delete all the above code and start over. Put this in the Shop's "Scripts" tab as a local turn script:

PlayerSellList = GetAllChildObjects(game.pov)
foreach (item, PlayerSellList) {
  item.inventoryverbs = ListExclude(item.inventoryverbs, "")
  if (not ListContains(item.inventoryverbs, "Sell")) {
    list add (item.inventoryverbs, "Sell")
  list remove (item.inventoryverbs, "Buy")
  }
}
ShopSellList = GetDirectChildren(YourShop)
list remove (ShopSellList, game.pov)
foreach (item, ShopSellList) {
  item.displayverbs = ListExclude(item.displayverbs, "")
  if (not ListContains(item.displayverbs, "Buy")) {
    list add (item.displayverbs, "Buy")
  list remove (item.displayverbs, "Sell")
  }
}

This will put a "Sell" verb on everything the player is carrying and remove any "Buy" verbs. The reverse is true of the Shop's merchandise. It's overkill but it should work.

Then, in the Shop's "After leaving the room:" section:

foreach (item, GetAllChildObjects(game.pov)) {
  list remove (item.inventoryverbs, "Sell")
}

As far as I can tell after some testing, you have got this running 100%. Impressive


(edited slightly because I don't know the shop system that well; fixed a minor issue)

That seems a bigger piece of code than I would have expected.

I'd comment that item.inventoryverbs = ListExclude(item.inventoryverbs, "") is inefficient because you're looping over the whole list to check if any of the elements is "". I think you can just do item.inventoryverbs = item.inventoryverbs; because assignment to an object attribute implicitly serialises lists and dictionaries. ISTR the ListExclude trick is only necessary if the thing to the left hand side of the = is a local variable.

Also a little confused by list remove (item.inventoryverbs, "Buy") - surely "Buy" will never be on an object's inventoryverbs, and "Sell" will never be in its displayverbs. Or do the existing parts of your shop script add the verbs to both lists?

I'd probably have done it by adding a few lines to a core function:

  <function name="GetDisplayVerbs" parameters="object" type="stringlist">
    if (Contains(game.pov, object)) {
      baselist = object.inventoryverbs
      shopverb = "Sell"
    }
    else {
      baselist = object.displayverbs
      shopverb = "Buy"
    }

    if (not game.autodisplayverbs or GetBoolean(object, "usestandardverblist") or not HasAttribute(game, "verbattributes")) {
      return (baselist)
    }
    else {
      if (HasAttribute(object, "generatedverbslist")) {
        verbs = object.generatedverbslist
      }
      else {
        verbs = NewStringList()
        foreach (attr, GetAttributeNames(object, false)) {
          if (ListContains(game.verbattributes, attr)) {
            cmd = ObjectDictionaryItem(game.verbattributeslookup, attr)
            if (HasString(cmd, "displayverb")) {
              displayverb = CapFirst(cmd.displayverb)
            }
            else {
              displayverb = CapFirst(attr)
            }
            if (not ListContains(baselist, displayverb)) {
              list add (verbs, displayverb)
            }
          }
        }
        object.generatedverbslist = verbs
      }      if (GetBoolean (object, "sell") and HasAttribute(game.pov.parent, "is_shop")) {
        verbs = ListCombine (Split (shopverb), ListExclude (verbs, Split("Buy;Sell")))
      }
      if (GetBoolean(object, "useindividualverblist")) {
        return (verbs)
      }
      else {
        return (ListCombine(baselist, verbs))
      } 
    }
  </function>

Have to make sure any items that start in the shop have their display verbs set correctly. Those items were giving me grief but setting the verbs fixed it. We'll see what happens down the road.

Kinda scared to touch it now Mrangel. But I will make another copy of the game to test your code.


@Forgewright -
Ok, as per mrangel, in my local turnscript, just replace the 2 lines in bold (they are replaced below). This will reduce some of the overhead:

PlayerSellList = GetAllChildObjects(game.pov)
foreach (item, PlayerSellList) {
  item.inventoryverbs = item.inventoryverbs
  if (not ListContains(item.inventoryverbs, "Sell")) {
    list add (item.inventoryverbs, "Sell")
  list remove (item.inventoryverbs, "Buy")
  }
}
ShopSellList = GetDirectChildren(YourShop)
list remove (ShopSellList, game.pov)
foreach (item, ShopSellList) {
  item.displayverbs = item.displayverbs
  if (not ListContains(item.displayverbs, "Buy")) {
    list add (item.displayverbs, "Buy")
  list remove (item.displayverbs, "Sell")
  }
}

@mrangel -
As for the buy/sell verbs, when you buy an item from the store, the buy verb will still be on the bought item in the player's inventory; the sell verb will still be on an item after being sold to the shop. In order to update those verbs immediately, that is why the additional listremove lines are there.


I think you misunderstood my question; but in explaining why I get "sorry, you can't post that here".

So a shortened form: Is there ever a reason why the player would need buy an object that's in their inventory; or sell an object they don't own?

It seems to me that "Buy" would only go in the object's displayverbs, and "Sell" should only go in inventoryverbs.

So I questioned why your code is removing those verbs from lists I think they would never be in.


How about this:

PlayerSellList = GetAllChildObjects(game.pov)
foreach (item, PlayerSellList) {
  item.inventoryverbs = item.inventoryverbs
  if (not ListContains(item.inventoryverbs, "Sell")) {
    list add (item.inventoryverbs, "Sell")
  list remove (item.displayverbs, "Buy")               // This line changed
  }
}
ShopSellList = GetDirectChildren(YourShop)
list remove (ShopSellList, game.pov)
foreach (item, ShopSellList) {
  item.displayverbs = item.displayverbs
  if (not ListContains(item.displayverbs, "Buy")) {
    list add (item.displayverbs, "Buy")
  list remove (item.inventoryverbs, "Sell")             // This line changed
  }
}

That's what I would have expected it to look like :)


I just realized that I have not paid attention to the 'Display and Inventory' differences. This would be a cause of some of my grief. Such an obvious part but I missed it. I thought the game would control this from the settings under the object verb set up. Completely went over my head. Dang


Ok, this is where I stand now.

sell #object# command:

if (not HasAttribute(game.pov.parent, "stock")) {
  ClearTurn
  msg ("You can't sell stuff here.")
}
else if (not object.parent = game.pov) {
  ClearTurn
  msg ("You're not carrying " + object.article + ".")
}
else if (HasAttribute(object, "burned")) {
  if (object.burned = true) {
    ClearTurn
    msg (player.parent.owner.alias + " says,<br><i>I have no use for a used torch.")
  }
}
else if (HasAttribute(object, "sell")) {
  ClearTurn
  game.selling_object = object
  Ask ("I will give you " + game.selling_object.price + " gold. OK?") {
    object = game.selling_object
    if (result) {
      msg ("You sell " + object.article + " for " + object.price + " gold.")
      game.pov.money = game.pov.money + object.price
      if (GetBoolean(object, "cloneme")) {
        RemoveObject (object)
      }
      else {
        object.parent = game.pov.parent.stock
        SetUpMerchandise (object)
      }
    }
    else {
      msg ("You turn down the offer of " + object.price + " gold.")
    }
  }
}

Then the buy #object# command.

if (object.price > game.pov.money) {
  msg ("You can't afford that!")
}
else {
  object.take = true
  object.parent = game.pov
  object.buy = null
  object.listalias = object.alias
  list remove (object.inventoryverbs, "Buy")
  player.money = game.pov.money - BuyingPrice(object)
  msg ("You decide to buy " + object.article + " for " + DisplayMoney(BuyingPrice(object)) + ".")
}

Next comes the SetUpMerchandise Function used above with obj parameter.

if (not HasString(obj, "alias")) {
  obj.alias = obj.name
}
obj.listalias = obj.alias + " (" + DisplayMoney(BuyingPrice(obj)) + ")"
obj.cloneme = false
obj.take => {
  StealObject (this)
}
obj.buy => {
  BuyObject (this)
}

Next is the BuyObject function also with the obj parameter used in SetUpMechandise function.

if (obj.price > game.pov.money) {
  msg ("You can't afford that!")
}
else {
  if (GetBoolean(obj, "cloneme")) {
    obj = CloneObject(obj)
  }
  list remove (obj.inventoryverbs, "Buy")
  obj.take = true
  obj.parent = game.pov
  obj.buy = null
  obj.listalias = obj.alias
  player.money = game.pov.money - BuyingPrice(obj)
  msg ("You buy " + obj.article + " for " + DisplayMoney(BuyingPrice(obj)) + ".")
}

So far everything checks out and I have yet to find a bug. That really isn't saying a lot though.


Oh. And the GetDisplayVerbs function is awesome.
I don't have items with multi states like a torch having an inventory verb 'Sell' because the use of a torch will not be allowed to sell. And I have not decided how and where to put the script for changing the inventory verb if it is not burned. However, the player can type it in and sell it if the torch is not used. If it is the shop owner tells them he has no use for a burned torch.

I thought that was a cool thing to do. Eh...


Another alternate way to do this :¬p

In the player's changedparent script, add a line


if (game.pov = this) {
  this.is_in_shop = GetBoolean (this.parent, "is_shop")
  if (IsDefined("oldvalue")) {
    OnEnterRoom (oldvalue)
  }
  else {
    OnEnterRoom (null)
  }
  if (game.gridmap) {
    MergePOVCoordinates
  }
}
this.hasbeenmoved = true

And then give him a script changedis_in_shop:

foreach (obj, ScopeVisibleInventory()) {
  obj.inventoryverbs = ListExclude (obj.inventoryverbs, "Sell")
  if (this.is_in_shop) {
    list add (obj.inventoryverbs, "Sell")
  }
}

It would be just as easy to add "Buy" to displayverbs in the same script; but there's no reason to do so. Because I believe if you followed the "Setting up a shop" guide, the buy and sell scripts will already add and remove the "Buy" verb as necessary.


I don't have items with multi states like a torch having an inventory verb 'Sell' because the use of a torch will not be allowed to sell. And I have not decided how and where to put the script for changing the inventory verb if it is not burned. However, the player can type it in and sell it if the torch is not used. If it is the shop owner tells them he has no use for a burned torch.

I thought that was a cool thing to do. Eh...

I thought of an alternative way to do that.
Where your 'sell' command has:

else if (HasAttribute(object, "burned")) {
  if (object.burned = true) {
    ClearTurn
    msg (player.parent.owner.alias + " says,<br><i>I have no use for a used torch.")
  }
}

you could change that to:

else if (HasString (object, "price")) {
  ClearTurn
  msg (player.parent.owner.alias + " says,<br><i>" + object.price + "</i>")
}

then in the script for using the torch, you could put:

this.burned = true
this.sell = false
this.price = "I have no use for a burned torch."

Changing the price of an object to a string causes the shopkeeper to refuse to accept it; changing sell to false removes the "Sell" inventory verb (if you're using my GetInventoryVerbs script above - I just fixed it because I didn't know that there was a sell boolean, so it previously checked if the object has a price)


Off-topic, but I have been gone a while and was wondering if KV was still active in the forums?


Wow, I somehow missed these last couple of posts from you Mrangel. I will make those changes.
Thank you Dcoder and Mrangel for your help. You really make my coding time so much less and teach me new and better ways to code.


This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums