King of bodges

I've decided I don't like some of the code in CoreParser.aslx; so, I started writing my own version. Just a couple of functions. The problem is that on the web editor I can't override the default ones (and my computer won't handle the offline editor).

So, I think I see a way around this. I create a command with the pattern #text#. This command simply passes its parameter to my own version of HandleSingleCommand(). But that'll not be triggered for the builtin commands like 'look', 'use', etc.
So I stick in an initialisation script that loops over AllCommands(), finds the ones that would benefit from my mod_HandleSingleCommand(), and changes their parent to a room somewhere out of the way. So now my mod_HandleSingleCommand() just needs to do what the default one does, but looking in an additional location for global commands.

I am aware that this is a horrible, horrible bodge; one workaround built on another to let me mess around with the parser. But just in case anyone's played around with this stuff before… are there any gotchas I need to look out for?
And is there an easier way to do this

(If you're curious, the real aim of this is to mangle GetScope(), so that the disambiguation menus aren't cluttered with irrelevant junk. My put (?<object1>.*) in (?<object2>.*) command has the scope [email protected],object2:isopen ... I can't wait to get all the dodgy workarounds dealt with so that I can test my actual mod_GetScope())

[EDIT: Realise I was being a bit dumb. Rather than moving all the commands around, I can just stick catchall_command.parent = game.pov.parent in a turn script. Would still prefer if I could override GetScope() without jumping through so many hoops. But it's actually proving quite a fun challenge]

I cannot see any issues here. GetScope is a partly attempt to do what you want to do, and depending on how this goes I might look to incorporate it into Quest (i.e., it is not going to break existing games).

Not being able to override functions is possibly the biggest drawback of the online editor (no Attribute tabs is a problem, but can be worked around fairly easily). I am not sure if how that can be resolved.

Are you on Mac or Linux? How about building a version of Quest on there? I would love to see desktop Quest for Mac and Linux.

I'm on linux at present. Tried running it under WINE, but it exits without any indication what's wrong. No idea if this is Quest, some compatibility issue, or if my WINE is broken (given that it's an out-of-the-box install, and I don't have anything else to try it with)

At this point I've got a rough function mod_GetScope(objtype, variable) thrown together. Then mod_ResolveNameInternal(variable, value, objtype), which differs only in calling mod_GetScope() and passing an extra argument to it (If there's a global variable somewhere tracking which variable we're currently looking at, I must have missed it). Then I need to make mod_ResolveName(variable, value, objtype) in order to call mod_ResolveNameInternal, and so on up the stack to mod_HandleSingleCommandPattern(); which would be called by my "catchall" command.

That seems like an awful lot of functions to create, though most of them are a direct copy-paste from CoreParser with just one function call changed. If I had the desktop version, I could test my GetScope() while only changing one function.

I was uncertain whether to change the format of the "scope" attribute of a command (but remain backwards-compatible), or to add a series of attributes along the lines of "parameter_scope_for_"+variable … if I was working on the desktop version I might have gone for the latter, and look into changing the editor forms to allow input of them. But on the web editor, I figured that adding attributes to a command isn't easy, so I'd go with the slightly uglier form.

Also wondering if it would be possible to build on this with some kind of automatic command continuation. A flag in the scope string maybe, indicating that a variable is required. So I could do put (?<object1>.*?) ((in|on) (?<object2>.*)? and maybe scope [email protected],object2?:isopen, with a ? picked up somewhere in the parser to indicate that if object2 isn't specified, the parser will call GetScope() anyway and present the user with a list of open containers. That much is still idle speculation, though. I haven't looked into how hard that might be.

OK ... got it mostly behaving, but unacceptably inefficient. Now working on making a cache, so that the Command's "scope" attribute is parsed once the first time it's used, and the results cached.

At the moment, I've got one string containing both per-variable, and whole-Command scope terms.

Existing commands should work fine unless their scope contains one of the characters :[email protected]/=<>,… I seriously hope nobody's got those characters in an object or attribute name.
The "scope" attribute for a command now consists of a comma separated list of variables, each one followed by 'filters'. Filters may include:

:attribute - attribute exists and is not false, zero, or the empty string
:attribute=value - attribute is an int or a string
:attribute>value - attribute is an int
:attribute=/regex/ - attribute is a string
/regex/ - object name, alias, or alt matches the regex
@inventory - object is in the inventory (and similar for anything else that the standard Command scope could be)
@everything - AllObjects() - just in case you want a debugging command that correctly completes the names of objects the player can't see
@inventory+black box - lists items in the inventory, and those in the black box
@=inventory - lists items directly in the inventory, not inside another container
@=room - items in the current room (alias for @=notheld)

A set of filters without a variable name are considered to apply to all variables specified later in the list. A filter that doesn't have a symbol character in front of it assumes an @ (in order to ensure compatibility with all the Core commands)

Is there anything I'm missing?

Ugh ... found a quicker/simpler bodge for a couple of cases. Would likely to become a real pain if I had a lot of commands, but for now it allows me to play with things a bit at a time.

I now have 3 "put" commands

  • put0, with pattern ^put\s*$
  • put1, with pattern ^put\s+(?<object1>.*)(\s+[io]n\s*)?$
  • put (which is the default)

Each one just shows a menu for the next argument; filtered by sensible criteria.
I'm thinking it would be quite easy to programatically create these sub-commands … if there's a way to actually create a command?


This is all WAY over my head, but, as far as the command is concerned, have you seen Pixie's CHEAT command?

It's one command, but it's really 3-in-1.

That might help, if I understand that last post...

...and if you're not already aware of it.

I'm on linux at present. Tried running it under WINE, but it exits without any indication what's wrong. No idea if this is Quest, some compatibility issue, or if my WINE is broken (given that it's an out-of-the-box install, and I don't have anything else to try it with)

I installed every thing I could find that mentioned WINE, MONO, ASP.NET (I even updated the .NET framework), and more last night, in Linux Mint 18 as well as in Arch Linux, but I couldn't get Quest to start up in either one. It installs. I open it. Then: nothing at all happens.

One thing I noticed was the WINE installer didn't ask which folder I'd like to install to. I wanted to choose my own folder so I'd know it would put ALL the files in one place. (I'm pretty sure I read a post here from Pixie saying you were better off installing to one folder in some instances, because it won't put any necessary files in the app_data folder. (It may not have been Pixie...))

I'm also not sure about Java working inside of WINE, or how that even works at all (or if it even matters). (I'm basically just bumbling, honestly.)

I installed MONODEVELOP this morning. It claims I can build Visual Studio projects with it, and it will compile it to C# for Linux. (NOTE: I think that's what it's supposed to do. Sometimes those descriptions are a little vague, and the programs don't do what I expect at all!)

I also found a post on WineHQ from someone saying they got Quest 4.03 to run under WINE, but I think 4.05 was the earliest build I could find, and it didn't work in much the same way the newer version doesn't work.

Anyway, I'm trying one or two more things to get Quest running in Linux. (Quest is the only reason I even log into Windows at the moment.)

I'll drop an update if I get it going.

I also wonder if it might be better to focus on QuestJS. ...or QuestKit... or whichever was the last iteration... instead.

@KV: I've not sean the cheat command, but I've got something pretty similar for debugging.
In this case, it's not so much getting multiple behaviours out of one command, as turning one command into three on the fly.

Hmm ... it might actually be possible to stack them in a single command, but that would be even more horrible. A command with multiple scripts… I wonder if that would work.

Yes, thankyou :D

My init script now has:

foreach (cmd, AllCommands()) {
  if (HasAttribute(game, "override_scope")) {
    if (DictionaryContains(game.override_scope, {
      cmd.complexscope = StringDictionaryItem(game.override_scope,
  if (HasAttribute(game, "override_pattern")) {
    if (DictionaryContains(game.override_pattern, {
      cmd.pattern = StringDictionaryItem(game.override_pattern,
  if (HasAttribute (cmd, "complexscope") {
    cmd.original_script = cmd.script
    cmd.script => {
      found_all_args = true
      foreach (arg, GetRequiredArguments(cmd.complexscope)) {
        if (found_all_args and not IsDefined (arg)) {
          // Yeah, it's not finished yet
          // TODO - do the menu thing, providing a list of suitable items
          msg ("You need to specify a value for "+arg)
          msg ("Eventually there will be a show menu command here")
          found_all_args = false
      // looks like a command's arguments are passed directly into the script's scope, so to pass them to a different script we need to enumerate them
      if (found_all_args) {
        command_args = NewDictionary()
        foreach (arg, GetAllArguments(cmd.pattern)) {
          if (IsDefined (arg)) {
            // Have I missed something obvious? There must be a better way to do this
            dictionary add (command_args, arg, Eval(arg))
        invoke (this, "original_script", command_args)

That was something quickly thrown together off the top of my head as proof of concept, so no doubt there's silly bugs in there. But it basically means that I could do something like:

dictionary add (game.override_scope, "give", "[email protected],object2!:is_npc")
dictionary add (game.override_pattern, "give", "^give\s*( (?<object1>.+)(( to)( (?<object2>.+))?)?)?$")

OK, the regex is hairy. But then the 'give' command will be rebuilt in the init script. Its new script will:

  • If the player types "give", will display a "..." and a menu of objects in your inventory
  • If the player types "give button" or "give button to", will display a "..." and a menu listing everything in the current room with an "is_npc" attribute
  • If the player types "give button to John", it'll run the original script for the "give" command.

Yes, I could have done that just by implementing a new-and-more-complex 'give' command. But for some of them, the built-in command body is pretty complex, and I don't want to make it even more so.

And yes, I'm a masochist. I love playing with particularly strange and ugly code sometimes.

... and no. This doesn't actually do what I was hoping. It'll give you a menu of options if you enter an incomplete command, and means that you can put "give" or "put in" on an object's verb list for reasonable results, but it still won't give you a sensible set of suggestions if you type a partial object name.
And it looks like I'm still re-implementing a lot of the functionality from CoreParser.

Still, it's an interesting way to do it.

(I know there's an error in that script, I copied it over while I was still working on it and got an unchecked bit in. But I'm not allowed to update it now)


I have Quest open in Visual Studio right now.

I've just built a Debug 'release', and it works great (on WIndows, of course).

I thought it best to successfully build it in Windows before I tried it in Linux using Monodevelop. Which is what I'm off to do right now!

More on this as it comes in.

Log in to post a reply.