Commands Specific to Rooms

queste
26 Feb 2020, 08:52

An example: There is a post box and a letter. If I want something to happen when the letter is put into the post box I could copy the core PUT command and add my code into that.

However is the better way to use a command specific to a room? As the post box will never change room this seems to make sense.

So I've made a command in the room with the same regex as the core PUT command

^(put|insert|place|drop) (?<object1>.*) (on|in|on to|in to|into) (?<object2>.*)$

Put my code in ... and it works ... sort of. I can put the letter in the post box and have what I need happen. However any other combination of objects results in a null response.

Which makes sense, I therefore need to change the regex to only be specific to putting things in the post box. I assume doing this will then make my room specific code only work when the post box is referenced as the second object. Any other object combination will use the core PUT command code.

Regex makes my head explode. What do I have to do to the (?<object2>.*) part to make it specific to the object named 'post box'?

Hopes this makes sense. Is the best way to overriding core complex commands.


Doctor Agon
26 Feb 2020, 09:22

Replace object2 with object_post box.

So in your example it would be:

^(put|insert|place|drop) (?<object1>.*) (on|in|on to|in to|into) (?<object_post box>.*)$

If it is just the letter that you can only put into the post box, you could further refine it by the following:

^(put|insert|place|drop) (?<object_letter>.*) (on|in|on to|in to|into) (?<object_post box>.*)$

There is a section in the documentation on dealing with complex commands which really helped me to get to grips with regex:

http://docs.textadventures.co.uk/quest/complex_commands.html


Dcoder
26 Feb 2020, 10:05

never mind, my mistake.


mrangel
26 Feb 2020, 14:17

Make the post box a container.

Set it to run a script when an object is added to it (the addscript script attribute)

if (object = letter) {
  // do stuff here
}
else {
  msg (CapFirst (object.article)+" won't fit in the slot.")
}

There is no need to make a separate command.


queste
26 Feb 2020, 14:42

Thanks everyone.

mrangle, duh, I knew that, just didn't remember, thanks again.


mrangel
26 Feb 2020, 15:48

You could alternatively use the letter's "drop" script:

if (destination = post box) {
  // do stuff here
}
else {
  MoveObject (this, destination)
}

If you really wanted to make your own command for some reason (like you wanted to do something that the built-in one can't do), it would be possible to call the default command as a backup. You'd make your own command's script something like:

if (object1 = letter and object2 = post box) {
  // do stuff here
}
else {
  params = NewDictionary()
  dictionary add (params, "object1", object1)
  dictionary add (params, "object2", object2)
  do (put, "script", params)
}

@Doctor Agon

^(put|insert|place|drop) (?<object_letter>.*) (on|in|on to|in to|into) (?<object_post box>.*)$

If the player types "put cat in oven", then your command is still run. The command has a variable named object_letter which points to a cat, and object_post box which points to an oven.

You've changed the names of the variables, but that doesn't change what is in the variables. It just makes them incorrectly named.

You probably meant: ^(put|insert|place|drop) (?<object1>letter) (on|in|on to|in to|into) (?<object2>post box)$

That version only works if the object names the player types are exactly "letter" and "post box". But, this requires them to match exactly. If the player types "put lette in post box", it will run the default put command, and then determine that "lette" is the start of "letter".

Forcing the input like this could be useful; but you need to be careful, because it can end up giving the player a very confusing experience. For most of the game, shortening an object name Quest will know what you mean. On the game where I first suggested this method because someone wanted a "kill boar" command, it would be confusing that "kill boar" works but "kill boa" responds as if it was an unknown command. And in this case, having it work but give a different outcome if you leave a letter off could be very, very confusing for the player.


Dcoder
26 Feb 2020, 21:29

@mrangel -
Using (?<object>someobject) should work in the regex pattern, but it doesn't. Using (?<exit>north) or (?<text>somewords) does work for me though. Do you get the same result?


mrangel
26 Feb 2020, 22:32

Using (?<object>someobject) should work in the regex pattern, but it doesn't.

Just tested. It works exactly as expected for me.

What's the full pattern you're using, and the command entered to test it?


Dcoder
27 Feb 2020, 02:07

I tested this in a barebones game, and everything works the way it should. It just doesn't work in my real game. I could not reproduce the error in the barebones game, and I can't figure out why it doesn't work in my real game. Go figure.


Dcoder
27 Feb 2020, 02:41

In my real game, (?<object>someobject) works with commands that have new verbs I made up in the regex pattern (kick, smash, etc.), but it does not work in regex patterns with verbs that already exist as Quest default commands (put, use, etc.) -- with these verbs, Quest will ignore my alternative regex pattern command and go with the default command. Changing the order of the commands makes no difference.

I've also noticed that, in (?<object>someobject), someobject only works with the object's alias, not with the object's name (if different), and not with alt names.


mrangel
27 Feb 2020, 08:58

but it does not work in regex patterns with verbs that already exist as Quest default commands

You mean commands which would collide with one of the core commands?
I'm not sure, but I think that in a case with multiple equally-weighted matches, Quest uses the first command found, unless one is in a specific room. It's the same as creating two commands with the same pattern.

Is your command in a specific room? If it is, then there must be some mismatch between the pattern and what the player typed. If you have a specific example I could take a look at it.

If you have a global command with the same pattern, you would need to ensure it is found before the default one. You could possibly do this by cloning and disabling the default command. Or you could make your command more specific (less of the command is captured by named groups) by doing something like (?<object>someobjec)t.

only works with the object's alias, not with the object's name

What do you mean?

If you use (?<object>some alias here), it will only match if the player types exactly "some alias here". It doesn't matter if that string is an object's alias, an alt, or part of an alias - but the command typed by the player must match the pattern. It can be any string that the player could type to refer to that object.

If an object has alternate names, you would need to do something like (?<object>some object|alternate name|alternate name 2)