Quest verb crash
paul_one
02 Mar 2007, 15:43verb <look on> if property <#quest.lastobject#; list> then exec <look on #quest.lastobject#;normal> else msg <You don't see anything on the #quest.lastobject#>
I know this is because it goes into an infinite loop (as quest crashes and doesn't produce a message box.. And I've done it before by an infinite loop).
But is there any way to get exec to bypass the verb and get onto the normal list activity?
I say this because I am planning to do alot of verb's in a library for commands and may want to do the normal action for some things (take for example).
.. On that side note, I'll be releasing a preliminary user test in the not too distance future to see how people like the way it's displayed, and would like as much feedback as possible to improve it.
Alex
02 Mar 2007, 15:56Not quite sure what you're trying to do with that code?
Why not implement it using a command instead?
Why not implement it using a command instead?
paul_one
02 Mar 2007, 16:49Two reasons, simplicity and the fact "command #@object#" doesn't catch all objects - simply because objects without aliases don't get parsed (although in my right-proper game/preview will have 'em).
Plus I'd have to do more coding with a command.
I'm currently investigating possible ways forward.
Plus I'd have to do more coding with a command.
I'm currently investigating possible ways forward.
Alex
02 Mar 2007, 16:54"command #@object#" does catch all objects.
You don't need to do any more coding with a command, in your case. In fact I think it makes things a lot simpler.
You don't need to do any more coding with a command, in your case. In fact I think it makes things a lot simpler.
command <look on #@object#> if property <#object#; list> then exec <look on #object#;normal> else msg <You don't see anything on the #@object#>
paul_one
02 Mar 2007, 17:32Yeah, sorry - I was getting the "I cannot see that object here" message.. which threw me off a typo in code with a "#qobject#" instead of "#object#".
I tried that, and it still crashes Quest when using that command.
The command is as yours above, and;
That is correct - no?
Also, is there a way to get a list of objects in a container?
list doesn't contain anything as a property.
[Edit]
One additional note - the command is in a library.. Not sure if that'll make a difference to how the commands are evaluated.
I tried that, and it still crashes Quest when using that command.
The command is as yours above, and;
define object <table>
surface
end define
define object <cup>
parent <table>
end define
That is correct - no?
Also, is there a way to get a list of objects in a container?
list doesn't contain anything as a property.
[Edit]
One additional note - the command is in a library.. Not sure if that'll make a difference to how the commands are evaluated.
Freak
02 Mar 2007, 20:13That problem is a stack overflow, not an infinite loop.
It is possible to rewrite the Quest runner so as to fail more gracefully on stack overflow (I'm trying to implement the new Geas in that way), but CAS/ASL is difficult to handle in such a manner.
It is possible to rewrite the Quest runner so as to fail more gracefully on stack overflow (I'm trying to implement the new Geas in that way), but CAS/ASL is difficult to handle in such a manner.
paul_one
02 Mar 2007, 21:15The stack overflows because of the infinite loop..
You're correct in saying that the car blows up because the fuel was flammable - but I am saying that I see a guy throwing a match towards the leaking fuel tank.. If you get the analogy. (you could also argue that several other flames were in the vicinity so any one of them could potentially cause the fuel to ignite the same way..)
I actually found a way around my little problem using the built-in list commands for the objects..
Using "list empty" and making the object invisible (which actually helps things for me a little in the situation).. So I guess this thread can become dormant now..
You're correct in saying that the car blows up because the fuel was flammable - but I am saying that I see a guy throwing a match towards the leaking fuel tank.. If you get the analogy. (you could also argue that several other flames were in the vicinity so any one of them could potentially cause the fuel to ignite the same way..)
I actually found a way around my little problem using the built-in list commands for the objects..
Using "list empty" and making the object invisible (which actually helps things for me a little in the situation).. So I guess this thread can become dormant now..
Freak
02 Mar 2007, 22:37An infinite loop leads to repeating the exact same state. It won't crash the program.
paul_one
03 Mar 2007, 14:50If you want to get technical about it, there's no such thing as an infinite loop. Power failures, the fact that there can NEVER be an exact repetition of all the events which caused that first loop (being it down the the electron level).
There is always a 'limit' on things which are potentially 'infinite'.. Otherwise we would have proof that infinity exists - and to my knowledge there has been only theory.
This 'infinite' loop calls itself, which calls itself, causing the stack to overflow..
It's a recursive, continual loop which is self-sustaining.. I don't know what else to call this other than "infinite" where the limit is the amount of stack space.
There is always a 'limit' on things which are potentially 'infinite'.. Otherwise we would have proof that infinity exists - and to my knowledge there has been only theory.
This 'infinite' loop calls itself, which calls itself, causing the stack to overflow..
It's a recursive, continual loop which is self-sustaining.. I don't know what else to call this other than "infinite" where the limit is the amount of stack space.
Alex
07 Mar 2007, 18:31I've found the original problem is due to a bug with the "normal" parameter to the "exec" command - this is broken in v4.0, and will still process user-defined commands and verbs, hence the "out of stack space" error.
For v4.01, I've fixed this problem. I've also made Quest fail gracefully even if you try something like:
command <test> exec <test>
For v4.01, I've fixed this problem. I've also made Quest fail gracefully even if you try something like:
command <test> exec <test>
Freak
07 Mar 2007, 19:41I think the problem is more due to the fact that Quest requires every verb / command, once matched, to handle the command.
Alex
07 Mar 2007, 19:55Yes, that is the current design - although it's not every verb/command that matches the input, but the first one.
I can see how there may be alternative approaches - some kind of flag marking whether a particular command or verb has already been run as part of a turn, for example - but I can't see anything particularly neat or simple that would avoid this problem.
Besides, I think the comparative simplicity of the command handler is a strength - it takes out a lot of the guesswork involved in questions like "how might Quest interpret this particular input?" and "how can I get this particular command to work?".
Of course I'm grateful for any feedback on this if you have any ideas for improvements to the parser.
I can see how there may be alternative approaches - some kind of flag marking whether a particular command or verb has already been run as part of a turn, for example - but I can't see anything particularly neat or simple that would avoid this problem.
Besides, I think the comparative simplicity of the command handler is a strength - it takes out a lot of the guesswork involved in questions like "how might Quest interpret this particular input?" and "how can I get this particular command to work?".
Of course I'm grateful for any feedback on this if you have any ideas for improvements to the parser.
Freak
07 Mar 2007, 21:16The TADS 2 method (IIRC):
- The library contains a "Thing" class, which has action routines for all system verbs.
- It also contains a class "Container", derived from Thing, which has the "open", "close", "look in", etc. routines replaced. There are similar classes corresponding to supporters, clothing, and so on.
- An action routine can call the corresponding action routine in the parent class.
So you could have something like:
MetalThing is a subclass of Thing. IronThing is a subclass of MetalThing.
In IronThing, doTake() is
In MetalThing, doTake() is
And Thing.doTake() checks the player's capacity, and, if all tests pass, moves the object to the player's inventory and prints appropriate output.
The Inform method:
- For each verb, there is a ____Sub routine that does the typical work.
- An object may have one or more "before" routines.
- Whenever the parser tries to run an action, it will call the direct object's before routines in sequence.
- Each one may return true, to indicate that it has handled the action, or false, to indicate that it has not.
- The parser will continue to run the before routines until one returns true, or it runs out. If it runs out, it calls the ____Sub routine.
The important thing is that both methods have a way of passing the buck, if they can't immediately process it, and passing in such a way will always bottom out. Also, none of those commands are special; inherited, rtrue, and rfalse are also ordinary variables / commands.
- The library contains a "Thing" class, which has action routines for all system verbs.
- It also contains a class "Container", derived from Thing, which has the "open", "close", "look in", etc. routines replaced. There are similar classes corresponding to supporters, clothing, and so on.
- An action routine can call the corresponding action routine in the parent class.
So you could have something like:
MetalThing is a subclass of Thing. IronThing is a subclass of MetalThing.
In IronThing, doTake() is
{
if (magnetic_field.is_on)
"It's solidly stuck to the floor!";
else
inherited.doTake();
}
In MetalThing, doTake() is
{
if (this.is_hot)
"You try to, but it's too hot.";
else
inherited.toTake();
}
And Thing.doTake() checks the player's capacity, and, if all tests pass, moves the object to the player's inventory and prints appropriate output.
The Inform method:
- For each verb, there is a ____Sub routine that does the typical work.
- An object may have one or more "before" routines.
- Whenever the parser tries to run an action, it will call the direct object's before routines in sequence.
- Each one may return true, to indicate that it has handled the action, or false, to indicate that it has not.
- The parser will continue to run the before routines until one returns true, or it runs out. If it runs out, it calls the ____Sub routine.
The important thing is that both methods have a way of passing the buck, if they can't immediately process it, and passing in such a way will always bottom out. Also, none of those commands are special; inherited, rtrue, and rfalse are also ordinary variables / commands.
Freak
08 Mar 2007, 18:12Alex wrote:I've found the original problem is due to a bug with the "normal" parameter to the "exec" command - this is broken in v4.0, and will still process user-defined commands and verbs, hence the "out of stack space" error.
For v4.01, I've fixed this problem. I've also made Quest fail gracefully even if you try something like:
command <test> exec <test>
How are you doing this? Did you switch from the system stack to an explicit stack, or are you comparing an exec'd command against the current command?
Alex
08 Mar 2007, 18:29Neither. The stack error still actually occurs, but Quest now handles the error so it doesn't fall over. When the stack error occurs, Quest stops processing the script.
This means that the result is a small delay while it is recursively calling functions, but then an error is written to the ASL log and play can resume.
This means that the result is a small delay while it is recursively calling functions, but then an error is written to the ASL log and play can resume.
Elexxorine
09 Mar 2007, 09:17So it now realises it's in an endless loops and exits it?
Alex
09 Mar 2007, 10:38Essentially, yes.
Elexxorine
09 Mar 2007, 19:57Neat.... That'll be a life-saver.