Skip to content

Setting up a shop

This page shows you how to build a shop where the player can see what’s for sale, buy things if they can afford them, and sell things back. It uses Quest Viva’s built-in money feature, a stockroom the player can never reach, and three commands: BUY, BROWSE and SELL. The same three commands work for every shop in your game.

As an example, we’ll build a bakery selling a lamington, a Victoria sponge and a fairy cake.

  1. On the game object’s Features tab, tick “Money”. The player’s money now appears in the status pane.
  2. On the game object’s Player tab, set “Format for money”. The ! stands for the amount, so £! shows 10 as “£10”. Money is always a whole number, so decide whether your unit is pounds or pence. See DisplayMoney for more formats.
  3. On the player object’s Player tab, set “Starting money”. If you leave it, the player starts with nothing.

There’s more about money, and the “Increase money” and “Decrease money” script commands, in Score, health and money.

Create the shop as an ordinary room, “bakery”, with exits to and from it as usual.

Then create a second room, “bakery stock”, and give it no exits. This is the stockroom. Put everything the bakery sells inside it, and on each item’s Inventory tab, set its “Price”. Because the player can never get to the stockroom, they can’t see or take anything in it - the only way to get stock out is to buy it.

Finally, link the shop to its stockroom. On the bakery’s Attributes tab, add an attribute called stock, set its type to “Object”, and choose “bakery stock”. Every room with a stock attribute is a shop, and the commands below look in whichever stockroom it points to.

You can also set it in a script, such as the game’s start script on the Scripts tab:

bakery.stock = bakery stock

Add a command with the “Add Command” button, and set:

  • Pattern: “Command pattern”, buy #object#; purchase #object#
  • Scope: stock
  • Unresolved object text: “Text”, That isn't for sale here.

Setting the scope to stock tells Quest Viva to look for #object# among the contents of the stockroom that the current room’s stock attribute points to. Anywhere that isn’t a shop, there’s no stock attribute, so BUY finds nothing for sale.

Then paste this into the command’s script (click “Code view” in the script editor first):

if (not HasObject(game.pov.parent, "stock")) {
msg ("There's nothing for sale here.")
}
else if (object.parent = game.pov) {
msg ("You already have " + object.article + ".")
}
else if (not object.parent = game.pov.parent.stock) {
msg ("That isn't for sale here.")
}
else if (object.price > game.pov.money) {
msg ("You can't afford " + GetDisplayName(object) + ". It costs " + DisplayMoney(object.price) + ".")
}
else {
DecreaseMoney (object.price)
MoveObject (object, game.pov)
msg ("You buy " + GetDisplayName(object) + " for " + DisplayMoney(object.price) + ".")
}

The checks run in order:

  1. The player isn’t in a shop. If Quest Viva can’t find the object in a stockroom, it also looks in the room and the player’s inventory, so BUY LAMINGTON outside the shop can still match a lamington the player is carrying.
  2. The player already has the item - for example, BUY SPONGE after buying the only sponge.
  3. The item is somewhere else, such as lying on the shop floor, rather than in this shop’s stockroom.
  4. The player can’t afford it. Because the purchase only happens when the price is no more than the player’s money, money can never go below zero. A player with exactly enough money can buy the item and is left with nothing.
  5. Otherwise, the item is sold. DecreaseMoney takes the price off the player’s money, and the item moves from the stockroom to the player.

Here’s how it plays, starting with £10:

> buy sponge
You buy a Victoria sponge for £8.
> buy lamington
You can't afford a lamington. It costs £3.
> buy fairy cake
You buy a fairy cake for £2.
> buy sponge
You already have it.

Your BUY command takes the place of the built-in BUY verb, which only ever tells the player they can’t buy the object.

The player can’t see into the stockroom, so give them a way to list it. Add a second command with the pattern browse; list stock; wares, leave the scope blank, and paste in this script:

if (not HasObject(game.pov.parent, "stock")) {
msg ("There's nothing for sale here.")
}
else {
items = GetDirectChildren(game.pov.parent.stock)
if (ListCount(items) = 0) {
msg ("Everything has sold out.")
}
else {
msg ("For sale:")
foreach (item, items) {
msg ("- " + CapFirst(GetDisplayAlias(item)) + ", " + DisplayMoney(item.price))
}
}
}
> browse
For sale:
- Lamington, £3
- Victoria sponge, £8
- Fairy cake, £2

Items the player has bought are no longer in the stockroom, so they drop off the list. You can also mention the command in the shop’s description so the player knows it’s there, for example “A sign says: BROWSE to see what’s for sale.”

Selling works the other way round: the item goes from the player into the shop’s stockroom, and the player gets money for it. Add a third command:

  • Pattern: “Command pattern”, sell #object#
  • Scope: inventory
  • Unresolved object text: “Text”, You aren't carrying that.

The inventory scope makes Quest Viva look in the player’s inventory first. Paste in this script:

if (not HasObject(game.pov.parent, "stock")) {
msg ("There's no one here to buy it.")
}
else if (not object.parent = game.pov) {
msg ("You aren't carrying " + object.article + ".")
}
else if (object.price = 0) {
msg ("The shopkeeper doesn't want " + object.article + ".")
}
else {
offer = object.price / 2
IncreaseMoney (offer)
MoveObject (object, game.pov.parent.stock)
msg ("You sell " + GetDisplayName(object) + " for " + DisplayMoney(offer) + ".")
}

The shop pays half the item’s price, so the player can’t make money by buying and selling the same thing. Dividing one whole number by another gives a whole number, rounded down, so a £3 lamington sells for £1. Items with no price, such as a pebble the player picked up, can’t be sold.

Sold items go into the shop’s stockroom, so they appear in BROWSE and the player can buy them back at the full price:

> sell lamington
You sell a lamington for £1.
> browse
For sale:
- Victoria sponge, £8
- Fairy cake, £2
- Lamington, £3

If you don’t want the player to sell anything at all, leave this command out.

For each new shop, create its room and a stockroom, put the stock in the stockroom, and give the shop a stock attribute pointing to it. You don’t need to change the commands.

To let the player buy as many of an item as they like, sell them a copy - a clone - and leave the original in the stockroom. In the BUY script, replace the MoveObject line with:

CloneObjectAndMove (object, game.pov)

The original never leaves the stockroom, so it stays in BROWSE, and BUY LAMINGTON always finds it before any lamington the player is carrying.

Selling a clone back would then leave two lamingtons in the stockroom. Instead, in the SELL script, get rid of clones and only move originals into the stockroom. Replace the MoveObject line with:

if (HasObject(object, "prototype")) {
RemoveObject (object)
}
else {
MoveObject (object, game.pov.parent.stock)
}

Every clone has a prototype attribute pointing to the object it was copied from, so this is how you tell them apart.