Verb abuse - attributes for the web editor

This is something I've done a few times, but not sure if I ever shared. So if there's anyone else using the Quest web editor (for example because you've not got a Windows PC to run the desktop one), I thought it might be worth making a little post.

You presumably know that you can add attributes to an object by using its initialisation script; but this can be a little awkward when you have to enable it for every object. So why not abuse the verb system?

For example, I want to give every monster in my RPG a message which it says when it's defeated.
So I give each monster a verb called "defeatmsg", and give it a text response. I now have a string attribute named defeatmsg, which I can use however I want.

Or another example. I've got a simple shop system, and I want some items to run a script when they're purchased. There's already a script to run after the player takes an object, but maybe I want something to run after the player buys something. Maybe some weapons have a random chance of coming with ammo, and the type is only determined after you buy it. And I need an attribute for the price as well. So I create a verb "price", and a verb "buy". The price is going to be a string; that's not a problem.

But then… what if the player types "defeatmsg dragon" or "price sword"? Even worse, what if they type "buy shotgun" and its initialisation happens early?

Well, there's a simple way around that. In the start script, I could put:

destroy ("price")
destroy ("defeatmsg")

to delete the verbs. Then I'd just have normal attributes. However, this isn't ideal. Quest builds a dictionary of verbs during initialisation, and deleting verbs at this point could cause errors in some circumstances, or cause the verbs that no longer exist to appear in automatically-generated verb menus.

It's better to do this in the UI Initialisation script - but that is also run when a saved game is loaded, so you need to check if the game is currently running, but in Quest that isn't hard.

There's a couple of other little tweaks as well, which make it a little more intuitive during the editing process. I can just do this once, and than use my "Verbs" tab as if it were the desktop editor's "attributes" tab.
So now my UI Initialisation script looks like this:

// Only do this when initialising the game for the first time
firsttime {

  // destroy the command objects for the verbs that aren't actually verbs
  destroy ("price")
  destroy ("defeatmsg")

  // We can convert the "price" attribute to an int as we start, to save effort later
  foreach (obj, AllObjects()) {
    if (HasString (obj, "price")) {
      if (IsInt (obj.price)) {
        obj.price = ToInt (obj.price)
      }
    }
  }

  // I'm not going to destroy 'buy', because it's useful. I just want it to not behave like a standard verb
  // ... this means that the "Buy" menu will show up on the verbs list of any object with a "price"
  //     attribute, even though that isn't the name of the verb
  buy.property = "price"
  // ... and we change the 'script' for the buy command, so it does what we want:
  buy.script => {
    if (Got (object)) {
      msg ("You already have it!")
    }
    else  if (not IsShop (game.pov.parent)) {
      // assuming that function esists
      msg ("This isn't a shop.")
    }
    else if (HasString (object, "price")) {
      // If the 'price' is a non-numeric string, assume it's a message saying why you can't buy it
      msg (object.price)
    }
    else if (not HasInt (object, "price")) {
      msg (CapFirst (WriteVerb (object, "isn't")) + " for sale.")
    }
    else if (object.price >= game.pov.money) {
      msg (CapFirst (WriteVerb (object, "cost")) + " " + DisplayMoney (object.price) + " and you only have " + DisplayMoney (game.pov.money) + ".")
    }
    else {
      // No problems buying that!
      AddToInventory (object)
      if (HasString (object, "buy")) {
        msg (object.buy)
      }
      else if (HasScript (object, "buy")) {
        do (object, "buy")
      }
      else {
        msg ("You buy the {object:" + object.name + "}.")
      }
    }
  }
}

Basically, once the game starts verbs are treated like any other command. You can change their attributes in the UI Initialisation script to change the way they behave:

  • property is the name of the attribute that the verb checks for, when deciding whether or not it will appear in an automatically generated verb menu
    • Note that you can set this to null if you don't want it on the generated verbs list, or set the property attribute of any command if you do want it to appear
  • displayverb is the name that will display on those verb menus
  • script is the script that will run for the command. By default, for verbs, it checks if the object has a string or script in the atribute named in property, and displays/runs it. But you can replace it with any script you want.
  • pattern is a regexp to match the command. For the buy command, it will be ^(buy|purchase) (?<object>.+)$, but you can change it at any time before the first command is run.

OK, this post is longer than I intended. But hopefully, I've shown that you can use the "Verbs" tab for things it was never intended for, in order to make editing using the web editor just a little easier.


Log in to post a reply.

Support

Forums