Easiest way to interrupt the command queue?
K.V.
13 May 2021, 05:09Hello.
Lets say I have a game with a butt-load of turn scripts. (Okay?)
Sometimes, one of the turn scripts might print something. Sometimes, none of them will. (With me so far?)
Now, occasionally, when a turn script does print something, the text is something important. Like, it might be telling you that a one-eyed, one-horned, flying, purple people-eater just came out of the sky and lit in a tree. Such information might make an adventurer want to take different action than originally intended, and it would be polite to stop all the pending actions, if any exist.
Or, say there's a random chance an adventurer might fall through a trap door after entering a certain room, but this is unbeknownst to the player. Plus, the player just travelled through that room last time but forgot to save the game. So, the player knows that N.W.E.GET LAMP.D.D should get them from the current location to the place they were last time (with lamp in hand), but this time they fall through the trap door after going west. On top of this, something in the darkness below the trap door asks you a question (WHAT?!?! IS YOUR FAVOURITE COLOUR???), and this particular something was very ornery and felt that any answer other than a colour (no matter which colour) was punishable by death?
Well, normally that command (N.W.E.GET LAMP.D.D) would go like this (I'll spread them out into single commands so you can see the process):
>N
You are in front of The Super-Spreader.
You can see topless dancers here.
You can go west or south.
>W
You go west.
You are in front of The Manhattan Restaurant of the Mind.
You can see Jake Chambers here.
Suddenly, you hear a strange noise coming from the sewer grate beneath your feet. Before you have time to register that you are looking at a pair of glowing, yellow eyes, whatever it is down there reaches up and snatches you down into the sewer!
It is pitch black.
The thing with the yellow eyes speaks. "WHAT?!?!" it groans, "IS YOUR FAVOURITE COLOUR???"
>E
"NOT A COLOUR!!!" The thing is shrieking, possibly laughing, as its eyes grow larger and closer to you. You can smell the thing's foul breath just before it reaches in, rips your heart out of your chest, and eats it right in front of you.
**** You have died. ****
>GET LAMP
You stay out of this, you're dead. A silver spaceship improbably appears with a BAMF! It lights up the sewer. The shadow of the yellow-eyed thing scurries away just before a tall, slender alien steps out of the ship and approaches you.
>D
You sure do try to move around a lot for a dead person! The alien looks at you for a moment, then says, "Dent?" After a moment, it asks again, "Arthur Phillip Dent?"
After another moment, the alien calls you a jerk and a complete knee-biter, gets back into its ship, and disappears the same way it arrived, with a BAMF!
We are about to give you your score. Put on your peril-sensitive sunglasses now. (Hit RETURN or ENTER when ready.) >
What if?
Now, wouldn't it be nice if there was a function which stopped all pending commands (and probably turn scripts, too) from firing?
Then, we could stop all pending actions if something big happened. Like:
>N.W.E.GET LAMP.D.D
You are in front of The Super-Spreader.
You can see topless dancers here.
You can go west or south.
You go west.
You are in front of The Manhattan Restaurant of the Mind.
You can see Jake Chambers here.
Suddenly, you hear a strange noise coming from the sewer grate beneath your feet. Before you have time to register that you are looking at a pair of glowing, yellow eyes, whatever it is down there reaches up and snatches you down into the sewer!
It is pitch black.
The thing with the yellow eyes speaks. "WHAT?!?!" it groans, "IS YOUR FAVOURITE COLOUR???"
>
The Pixie
13 May 2021, 06:14This is why Quest 6 does not even support concatenating commands.
And why would a player do that? It is just as much typing as doing it one command at a time.
[Sorry - that was no actual help]
mrangel
13 May 2021, 11:41And why would a player do that? It is just as much typing as doing it one command at a time.
If you're using the web player, there can be significant lag before a command is accepted. If you've already made a map of a town, and you know where you're going, it seems quite reasonable to enter a whole bunch of directions at once to get there.
"NOT A COLOUR!!!" The thing is shrieking,
I don't think that should happen. Multiple commands on a line are put into a stringlist and then iterated over. If one of them triggers a get input
, it should expect input from the client as normal, not from the command list.
On the other hand, if the player is expected to enter the command "say yellow" or something, that would be a problem. As it would if the player enters a colour, only for the remainder of their queued commands to execute.
Therefore I would suggest that traps, wandering monsters, and other unexpected events should always do:
game.pov.commandqueue = null
or possibly:
JS.eval("$('#txtCommand').val() || $('#txtCommand').val('" + Replace(Replace (Join (game.pov.commandqueue, "."), "\\", "\\\\"), "'", "\\'") + "');")
game.pov.commandqueue = null
to type the remaining commands into the command bar for you, so that if the player wants to continue with their plan they can just hit enter.
K.V.
13 May 2021, 15:16And why would a player do that? It is just as much typing as doing it one command at a time.
I can't really explain why, but I do it all the time. I've done it ever since I learned it was possible back in the 1980s.
If it's Infocom, you can separate commands with .
or then
. So, sometimes it just feels natural.
You are in the Whack-A-Mole room.
You can see a hammer.
You can see a Mole.
>get hammer then whack mole
Taken.
Done.
The mole retreats into its hole.
When it comes to Quest, I've received quite a few emails with games-in-progress attached and a note to paste in something like "NW.N.NE.E.CLAP.NE.NE.SE.HOP.CLAP" to get to the point in the game where there is an issue.
(I guess the walkthrough feature isn't something most people know about.)
[Sorry - that was no actual help]
Oh, that's cool. Someone opining that whatever I'm doing might possibly be pointless is definitely helpful when I'm not thinking things through clearly.
I always want people to point out such things, as they are usually true and save me tons of wasted time.
:)
"NOT A COLOUR!!!" The thing is shrieking,
I don't think that should happen. Multiple commands on a line are put into a
stringlist
and then iterated over. If one of them triggers a get input, it should expect input from the client as normal, not from the command list.
Hrmmm...
I need to test this out.
...but anytime I use get input once play has begun, my default switch case is HandleSingleCommand(result)
as a way to let the player ignore the get input like they can certain show menus.
Now I wonder how these two things will work together. (Exciting!)
Also, game.pov.commandqueue = null
was the first thing I tried. I've got tons of turnscripts and stuff running in the game I'm porting, and this throws multiple errors.
But pulling the command queue to paste it into the text input field with this?
JS.eval("$('#txtCommand').val() || $('#txtCommand').val('" + Replace(Replace (Join (game.pov.commandqueue, "."), "\\", "\\\\"), "'", "\\'") + "');")
That is an awesome idea!
Anyway, last night I couldn't fall asleep until I figured out how to make it work in the game I'm porting.
Here's a dumb example (as my code has all sorts of extra stuff in it which would be distracting, but this example has the same functions that handle all his stuff):
<turnscript name="testerturnscript">
<enabled />
<script>
firsttime{
this.counter = 0
}
this.counter = this.counter + 1
if (this.counter % 3 = 0) {
msg ("Something important printed!")
this.interrupt = true
}
else {
msg("This text is not very important.")
}
</script>
</turnscript>
<function name="HandleNextCommandQueueItem"><![CDATA[
if (GetBoolean(game.pov, "commandqueueinterrupt")) {
// STOP THE PRESS!
}
else if (TypeOf(game.pov, "commandqueue") = "stringlist") {
queuelength = ListCount(game.pov.commandqueue)
if (queuelength > 0) {
thiscommand = Trim(StringListItem(game.pov.commandqueue, 0))
if (queuelength = 1) {
game.pov.commandqueue = null
}
else {
newqueue = NewStringList()
for (i, 1, queuelength - 1) {
list add (newqueue, StringListItem(game.pov.commandqueue, i))
}
game.pov.commandqueue = newqueue
}
if (LengthOf(thiscommand) > 0) {
HandleSingleCommand (thiscommand)
}
else {
HandleNextCommandQueueItem
}
}
}
set (game.pov, "commandqueueinterrupt", false)
]]></function>
<function name="RunTurnScripts">
if (IsGameRunning()) {
if (game.menucallback = null) {
foreach (turnscript, ObjectListSort(AllTurnScripts(), "name")) {
if (GetBoolean(turnscript, "enabled")) {
inscope = false
if (turnscript.parent = game or turnscript.parent = null) {
inscope = true
}
else {
if (Contains(turnscript.parent, game.pov)) {
inscope = true
}
}
if (inscope) {
turnscript.interrupt = false
do (turnscript, "script")
if (turnscript.interrupt) {
//msg ("DEBUGGING MESSAGE: Stopping the press!")
StopThePress
}
turnscript.interrupt = false
}
}
}
}
}
</function>
<function name="StopThePress">
game.pov.commandqueueinterrupt = true
game.suppressturnscripts = true
</function>
...and it doesn't mess up the save feature.
I think that uses start transaction
rather than "handling" commands, but I'm not positive about that.
The Pixie
13 May 2021, 19:30Thanks a bunch, now I have had to change QuestJS to allow players to do that!
In QuestJS, just call parser.abort()
.
mrangel
13 May 2021, 19:48Hrmmm...
I need to test this out.
OK… it seems that get input
confuses the game. After asking the question, it executes the remaining queued commands, skipping over any parts that are inside an on ready
. So it leaves the room with the trap in, walks around normally, but doesn't display any more room descriptions or trigger room enter scripts. Then when it finishes the queue, it expects a get input
response from the player; after which the trap script finishes, followed by all the room descriptions and enter scripts from the remainder of the queued commands.
...but anytime I use get input once play has begun, my default switch case is
HandleSingleCommand(result)
as a way to let the player ignore the get input like they can certain show menus.
HandleSingleCommand(result)
should be unaffected by any commands in the command queue. If one of the commands results in an extra command being called in this way, it will resolve before resuming the queue.
Also,
game.pov.commandqueue = null
was the first thing I tried. I've got tons of turnscripts and stuff running in the game I'm porting, and this throws multiple errors.
Can't reproduce. Can you show an example of a game that causes an error if you use this method? I tried making a simple game using a bunch of random turnscripts that could interrupt, and I completely failed to get it to fail. Would be interested to know the situation where it has a problem.
Also, now I tested it, that JS might be better converted to:
JS.eval("$('#txtCommand').val() || $('#txtCommand').val('" + Replace(Replace (Join (game.pov.commandqueue, ". "), "\\", "\\\\"), "'", "\\'") + "').select();")
This puts the remaining commands back in the queue, but also selects them. So if the player starts typing again in response to the trap or whatever, they will replace the queued commands with their own; but if they want to keep doing the same thing anyway, they can just hit enter.
mrangel
13 May 2021, 20:09(I worked around the get input
problem now:
paused_commandqueue = game.pov.commandqueue
game.pov.commandqueue = null
get input {
if (result = "purple") {
msg ("Correct! You may continue!")
game.pov.commandqueue = paused_commandqueue
HandleNextCommandQueueItem
}
else if (result = "yellow") {
msg ("A good answer, but not the best. You can continue if you still have confidence.")
game.pov.HP = game.pov.HP / 2
if (TypeOf (paused_commandqueue) = "stringlist")) {
JS.eval("$('#txtCommand').val() || $('#txtCommand').val('" + Replace(Replace (Join (paused_commandqueue, ". "), "\\", "\\\\"), "'", "\\'") + "').select();")
}
else {
msg ("Ooops! Something terrible happens!")
game.pov.parent = mysterious jail cell
}
}
K.V.
13 May 2021, 20:11Thanks a bunch, now I have had to change QuestJS to allow players to do that!
This made me laugh, but I promise I'm laughing with you.
(I learned that this was a thing I should have already known to handle in games after reading "Learning ZIL" by Steve Meretzky. Lots of good stuff in there! Most of it is already in QuestJS, in one form or another.)
it seems that
get input
confuses the game.
Damn and blast!
I was hoping it wouldn't.
I got distracted fooling around with the hint system and forgot to test it.
Can't reproduce. Can you show an example of a game that causes an error if you use this method?
Laughing maniacally. . .
I'm porting a game from ZIL to Quest. To do that easily (or at least to make the process more simple), I am using delegates and and have modified ResolveNextName
and all kinds of other stuff.
I'm pretty sure the errors are . . .
Hrmm. . . I honestly have no clue what I've got going on that deleting game.pov.currentcommandqueue
could break. All I know is it breaks it.
Once I've got the first act completed, I plan to post the code. So, you'll definitely get to see it within a week or three.
I also expect everyone will ask why I did this, and why I did that once I post this code, and I can't wait to see all the ways I could have handle things differently. (Seriously. I'm not being a smart-ass or anything.)
This puts the remaining commands back in the queue, but also selects them. So if the player starts typing again in response to the trap or whatever, they will replace the queued commands with their own; but if they want to keep doing the same thing anyway, they can just hit enter.
Hot dog!
I love it when a plan comes together!
mrangel
13 May 2021, 20:14Damn and blast!
Don't worry :) Look at the code I posted above (probably at the same time you were writing that response!)
I just edited it to show how it can handle different circumstances
mrangel
13 May 2021, 20:19Opinion: At the end of ResolveNextName
, where it goes:
if (HasScript(game.pov.currentcommandpattern, "script")) {
// This is the bit that actually runs the commands
do (game.pov.currentcommandpattern, "script", game.pov.currentcommandresolvedelements)
}
//
//Setting game.runturnscripts to true to run turn scripts after ShowMenu , show menu, ask, or Ask.
//This works in conjuction with FinishTurn, which has also been modified as of Quest 5.8.
//- KV, 2018/05/25
game.runturnscripts = true
FinishTurn
HandleNextCommandQueueItem
}
]]></function>
it should be:
if (HasScript(game.pov.currentcommandpattern, "script")) {
// This is the bit that actually runs the commands
do (game.pov.currentcommandpattern, "script", game.pov.currentcommandresolvedelements)
}
//
//Setting game.runturnscripts to true to run turn scripts after ShowMenu , show menu, ask, or Ask.
//This works in conjuction with FinishTurn, which has also been modified as of Quest 5.8.
//- KV, 2018/05/25
on ready {
game.runturnscripts = true
FinishTurn
on ready {
HandleNextCommandQueueItem
}
}
}
]]></function>
in order to prevent get input
in the command from screwing up either pending turnscripts, or other commands in the command queue.
K.V.
13 May 2021, 20:35At the end of
ResolveNextName
, where it goes [...] it should be [...] in order to preventget input
in the command from screwing up either pending turnscripts, or other commands in the command queue.
Brilliant! That's a very, very good idea!
@Pixie, how do we test that thoroughly? I think that is technically a bug fix.
Speaking of getting input, here's a small peek at a bit of what I've done to poor Quest to port easily from ZIL:
https://textadventures.co.uk/forum/quest/topic/bmaft_5vjee0zainnm6tkw/asking-yes-or-no-questions-without-get-input-or-ask-a-complete-waste-of-t
K.V.
14 May 2021, 02:29Hehehe.
Check this out.
If you just enter "TAKE" or "GET", it will trigger a script to ask you what you want to get. If you enter an object, it tries to take it. If you enter something other than an object, it handles your text as a command.
UPDATED
<!--Saved by Quest 5.8.7753.35184-->
<asl version="580">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="alternate input getter">
<gameid>400426c7-e5f8-4f10-8702-9324e15f55c6</gameid>
<version>1.0</version>
<firstpublished>2021</firstpublished>
<start type="script">
</start>
</game>
<object name="room">
<inherit name="editor_room" />
<isroom />
<description><![CDATA[<br/>This is a white room with black curtains.]]></description>
<firstenter type="script">
msg ("PLEASE ENTER YOUR NAME")
game.awaiting_reply = 1
GetInput2
on ready {
TextCatcher
}
</firstenter>
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
<object name="red herring">
<inherit name="editor_object" />
<take />
<look>It's a herring, and it's red.</look>
</object>
<object name="black curtains">
<inherit name="editor_object" />
<inherit name="plural" />
<scenery />
<look>The curtains aren't important.{notfirst: Get on with game!}</look>
</object>
</object>
<command name="yes_cmd">
<pattern>yes;y;affirmative</pattern>
<script>
if (not HasAttribute(game, "awaiting_reply")) {
game.awaiting_reply = 0
}
switch (game.awaiting_reply) {
case (2) {
msg ("Well, hello, {game.pname}! I'm a computer! Nice to meet you!")
msg ("")
msg ("Now, let's get the story!")
msg ("")
ShowRoomDescription
}
default {
msg ("You sure do sound positive!")
}
}
</script>
</command>
<command name="no_cmd">
<pattern>no;negative;n</pattern>
<script>
if (not HasAttribute(game, "awaiting_reply")) {
game.awaiting_reply = 0
}
switch (game.awaiting_reply) {
case (2) {
msg ("Okay. Forget that then. The story begins. . .")
game.pname = null
}
default {
msg ("You sure do sound negative. . .")
}
}
</script>
</command>
<command name="take_helper">
<pattern>take;get;grab</pattern>
<script><![CDATA[
msg ("What do you want to " + game.pov.currentcommand + "?")
GetInput2
on ready {
o = ResolveNameInternal("object", game.giresult, "object")
if (o <> null) {
HandleSingleCommand (game.pov.currentcommand + " " + game.giresult)
}
else {
msg ("<br/>> " + game.giresult)
HandleSingleCommand (game.giresult)
}
}
]]></script>
</command>
<function name="ResolveNextName"><![CDATA[
resolvedall = false
queuetype = TypeOf(game.pov, "currentcommandvarlistqueue")
if (queuetype = "stringlist") {
queuelength = ListCount(game.pov.currentcommandvarlistqueue)
if (queuelength > 0) {
// Pop next variable off the queue
var = StringListItem(game.pov.currentcommandvarlistqueue, 0)
if (queuelength = 1) {
game.pov.currentcommandvarlistqueue = null
}
else {
newqueue = NewStringList()
for (i, 1, queuelength - 1) {
list add (newqueue, StringListItem(game.pov.currentcommandvarlistqueue, i))
}
game.pov.currentcommandvarlistqueue = newqueue
}
// Resolve variable
value = StringDictionaryItem(game.pov.currentcommandvarlist, var)
if (value <> "") {
result = null
resolvinglist = false
// This is to resolve issue 626
if (StartsWith(var, "objectexit")) {
result = ResolveName(var, value, "exit")
}
if (result = null) {
if (StartsWith(var, "object")) {
if (GetBoolean(game.pov.currentcommandpattern, "allow_all")) {
scope = FilterByAttribute(GetScope("object", "", "object"), "scenery", false)
game.pov.currentcommandpendingobjectscope = ListExclude(scope, FilterByAttribute(scope, "not_all", true))
game.pov.currentcommandpendingvariable = var
ResolveNameList (value, "object")
resolvinglist = true
}
else if (HasScript(game.pov.currentcommandpattern, "multipleobjects")) {
game.pov.currentcommandpendingobjectlist = NewObjectList()
game.pov.currentcommandpendingvariable = var
do (game.pov.currentcommandpattern, "multipleobjects")
ResolveNameList (value, "object")
resolvinglist = true
}
else {
result = ResolveName(var, value, "object")
}
}
else if (StartsWith(var, "exit")) {
result = ResolveName(var, value, "exit")
}
else if (StartsWith(var, "text")) {
result = StringDictionaryItem(game.pov.currentcommandvarlist, var)
}
else {
error ("Unhandled command variable '" + var + "' - command variable names must begin with 'object', 'exit' or 'text'")
}
}
// at this point, ResolveName has returned - either an object name, unresolved, or pending
if (result = null) {
if ((not resolvinglist) and LengthOf(GetString(game.pov, "currentcommandpendingvariable")) = 0) {
UnresolvedCommand (value, var)
}
}
else {
AddToResolvedNames (var, result)
}
}
else {
ResolveNextName
}
}
else {
resolvedall = true
}
}
else if (queuetype = "null") {
resolvedall = true
}
else {
error ("Invalid queue type")
}
if (resolvedall) {
// All the objects have been resolved, so now we can actually do the command
// TO DO: game.lastobjects should be game.pov.lastobjects
game.lastobjects = game.pov.currentcommandresolvedobjects
if (not DictionaryContains(game.pov.currentcommandresolvedelements, "multiple")) {
dictionary add (game.pov.currentcommandresolvedelements, "multiple", false)
}
if (not GetBoolean(game.pov.currentcommandpattern, "isundo")) {
if (LengthOf(game.pov.currentcommand) > 0) {
start transaction (game.pov.currentcommand)
}
}
if (not GetBoolean(game.pov.currentcommandpattern, "isoops")) {
// TO DO: game.unresolved* should be game.pov.unresolved*
game.unresolvedcommand = null
game.unresolvedcommandvarlist = null
game.unresolvedcommandkey = null
}
if (DictionaryContains(game.pov.currentcommandresolvedelements, "object")) {
game.text_processor_this = ObjectDictionaryItem(game.pov.currentcommandresolvedelements, "object")
}
else if (DictionaryContains(game.pov.currentcommandresolvedelements, "object1")) {
game.text_processor_this = ObjectDictionaryItem(game.pov.currentcommandresolvedelements, "object1")
}
if (HasScript(game.pov.currentcommandpattern, "script")) {
// This is the bit that actually runs the commands
do (game.pov.currentcommandpattern, "script", game.pov.currentcommandresolvedelements)
}
//
// Setting game.runturnscripts to true to run turn scripts after ShowMenu , show menu, ask, or Ask.
// This works in conjuction with FinishTurn, which has also been modified as of Quest 5.8.
// - KV, 2018/05/25
on ready {
game.runturnscripts = true
FinishTurn
on ready {
HandleNextCommandQueueItem
}
}
}
]]></function>
<function name="GetInput2">
paused_commandqueue = game.pov.commandqueue
game.pov.commandqueue = null
get input {
game.giresult = result
}
on ready {
game.pov.commandqueue = paused_commandqueue
HandleNextCommandQueueItem
}
</function>
<function name="TextCatcher"><![CDATA[
text = game.giresult
if (not HasAttribute(game, "awaiting_reply")) {
game.awaiting_reply = 0
}
switch (game.awaiting_reply) {
case (1) {
game.pname = text
msg ("Would you like me to save that name (" + text + ") to my database?")
game.awaiting_reply = 2
if (GetObject("noreply") <> null) {
destroy ("noreply")
}
SetTurnTimeoutID (1, "noreply") {
game.awaiting_reply = 0
}
}
default {
// msg("I didn't understand your command.")
HandleSingleCommand (text)
}
}
]]></function>
</asl>
mrangel
14 May 2021, 18:43Edit edit edit … so many silly typos in this code
If you just enter "TAKE" or "GET", it will trigger a script to ask you what you want to get. If you enter an object, it tries to take it. If you enter something other than an object, it handles your text as a command.
That's pretty neat, but… I think this will require a modified object-resolution script. Otherwise, I think you could end up with something like this:
==> put bunny in box
OK==> take
What do you want to take?==> it
Which "it" do you mean?
- Bunny
- Box
Unknown command: it.
==> 1
What do you want to take?==>
(I don't remember the phrasing of all of the messages, but you see what I mean)
The problem being that the default ResolveNameInternal
will return an object if you enter an object name (works fine), or return null if you entered a command (so it tries to parse the command, works fine), but if you entered something that matches multiple names, it displays a disambiguation menu and returns null
. This means that your script attempts to interpret the player's input as a command, and gives an error message.
If they then choose a menu option (whether by typing the appropriate number or clicking), the menu response script will attempt to resolve any outstanding objects and then run game.pov.currentcommandpattern
. So this time, it's running take_helper
again, with an object
parameter that it didn't ask for. Which then asks you to choose another object, even though you just chose one.
Worse would be if you entered a partial name such as "n". Because it could display a disambiguation menu, and then go north. This means that it gets as far as running HandleSingleCommandPattern
, so you end up with something like:
==> take
What do you want to take?==> ne
Which "ne" do you mean?
- Needle
- Newt
- Nebuchadnezzar's cigar case
You can't go that way.
==> 2
Error: undefined variable exit in expression exit.visible
Because this time, game.pov.currentcommand
and game.pov.currentcommandpattern
have been successfully changed to be "ne"
and go
respectively, but the menu hasn't been cancelled. So the response script for the disambiguation menu attempts to pass the parameter object = newt
to the go
command, which is expecting an exit
parameter, not object
, and therefore fails with an undefined variable error.
I'm working off the top of my head here, haven't actually tested it… but I'm pretty confident that this script as it stands will only work correctly in a game that doesn't allow disambiguation of object names.
mrangel
14 May 2021, 19:02A more logical approach, I think, would be checking if the input matches a command first. For example, have your helper command save the command that it was trying to execute, and enable a command with pattern #object#
that pushes its parameter into the saved command.
Something like…
<!-- This command catches a single command such as "take", and responds by enabling the 'catchall' command -->
<command name="take_helper">
<pattern>take;get;grab</pattern>
<script><![CDATA[
msg ("What do you want to " + game.pov.currentcommand + "?")
catchall.command = game.pov.currentcommand
RemoveObject (catchall)
]]></script>
</command>
<!-- this matches a command such as "sandwich" or "teddy bear" that is just an object name -->
<!-- It will always have the lowest match strength of any command, as it is entirely parameters -->
<command name="catchall">
<pattern>#text#</pattern>
<script>
HandleSingleCommand (this.command + " " + text)
</script>
</command>
<!-- this turnscript will disable 'catchall' again as soon as the player enters something which matches some command's pattern -->
<turnscript name="cancel_catchall">
<enabled />
<script>
if (HasObject (game.pov, "currentcommandpattern")) {
if (not game.pov.currentcommandpattern = take_helper) {
AddToInventory (catchall)
}
}
</turnscript>
K.V.
13 Jun 2021, 05:51Well, I can safely say that I am scatter-brained!
:)
I forgot all about this thread.
There's good stuff here. There's a bug fix, and I need to test mrangel's code in that last post.