Unexpected error messages with nested Wait { }

DavyB
22 Apr 2018, 10:10A game I'm working on has nested wait operations to release text in chunks. When I respond to a 'continue' with the space bar I sometimes get an error message:
Error running script: Only one wait can be in progress at a time.
Anyone know why this happens and what I can do about it?
The Pixie
22 Apr 2018, 11:11It means that Quest is still waiting for the first continue to be clicked when the second starts, which would suggest your wait
blocks are not properly nested. Just guessing, but do you have more than two? I would see if the thord is properly nested in the second.

DavyB
22 Apr 2018, 13:59As this is a transient error I'm assuming it is something to do with the way that Quest is preprocessing the code for execution and executing it in parallel with user input. I've simplified the structure and removed one of the waits, which seems to have made the problem go away!

hegemonkhan
22 Apr 2018, 16:09other possibilities (though bad syntax/nesting is the most likely cause, unless you're trying to do looping - see below):
-
you're looping, which just can't be done with waited-on-inputs from the player, be it 'wait', 'get input', 'show menu', or whatever else, unfortunately in quest)
-
you're having scripts (which use the 'wait') running at the same time, such as maybe through using the special 'change' scripts.

DavyB
22 Apr 2018, 20:26Is this sort of code a problem as well? ...why does 'faulty code' not fail every time?
if (test) {
wait {...}
}
else {
wait {...}
}
The Pixie
22 Apr 2018, 20:40That should be fine.
The only reason for it only happening sometimes is that some of the code is only firing sometimes. This will fail if test is true, but will be fine if it is false:
if (test) {
wait {...}
}
wait {...}

DavyB
24 Apr 2018, 06:53I keep hoping someone will say "Hey, I've had that problem, here's what you do..." I'm going to have to investigate to explain more about this issue. It does feel as if something is happening lower down over which I have no control and no knowledge. Back soon...
The Pixie
24 Apr 2018, 07:05Here is an example game that has your problem. If you look at the room, it will be okay, unless you are holding the teapot, in which case you will get your error message. The problem is in the "description" script of the room.
<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="wait_error">
<gameid>0f0486a9-e5b2-4f8a-abc3-1519b40c8737</gameid>
<version>1.0</version>
<firstpublished>2018</firstpublished>
</game>
<object name="room">
<inherit name="editor_room" />
<description type="script">
msg ("You look around the room...")
if (Got(teapot)) {
wait {
msg ("Even as you feel the weight of the teapot in your arms...")
}
}
wait {
msg ("... It's just a room.")
}
</description>
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
<object name="teapot">
<inherit name="editor_object" />
<take />
</object>
</object>
</asl>

DavyB
24 Apr 2018, 07:29Here is test code that shows the problem...at least on my machine!
<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="Nested Waits">
<gameid>3b83f264-2b03-4ce5-8dac-95788bb3dfb7</gameid>
<version>1.0</version>
<firstpublished>2018</firstpublished>
</game>
<object name="room">
<inherit name="editor_room" />
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
<object name="wait responder">
<inherit name="editor_object" />
<dowait type="script"><![CDATA[
msg ("Start here...")
wait {
msg ("We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable Rights, that among these are Life, Liberty and the pursuit of Happiness. — That to secure these rights, Governments are instituted among Men, deriving their just powers from the consent of the governed, — That whenever any Form of Government becomes destructive of these ends, it is the Right of the People to alter or to abolish it, and to institute new Government, laying its foundation on such principles and organizing its powers in such form, as to them shall seem most likely to effect their Safety and Happiness. Prudence, indeed, will dictate that Governments long established should not be changed for light and transient causes; and accordingly all experience hath shewn that mankind are more disposed to suffer, while evils are sufferable than to right themselves by abolishing the forms to which they are accustomed. But when a long train of abuses and usurpations, pursuing invariably the same Object evinces a design to reduce them under absolute Despotism, it is their right, it is their duty, to throw off such Government, and to provide new Guards for their future security. — Such has been the patient sufferance of these Colonies; and such is now the necessity which constrains them to alter their former Systems of Government. The history of the present King of Great Britain is a history of repeated injuries and usurpations, all having in direct object the establishment of an absolute Tyranny over these States. To prove this, let Facts be submitted to a candid world.<br/>")
wait {
msg ("We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable Rights, that among these are Life, Liberty and the pursuit of Happiness. — That to secure these rights, Governments are instituted among Men, deriving their just powers from the consent of the governed, — That whenever any Form of Government becomes destructive of these ends, it is the Right of the People to alter or to abolish it, and to institute new Government, laying its foundation on such principles and organizing its powers in such form, as to them shall seem most likely to effect their Safety and Happiness. Prudence, indeed, will dictate that Governments long established should not be changed for light and transient causes; and accordingly all experience hath shewn that mankind are more disposed to suffer, while evils are sufferable than to right themselves by abolishing the forms to which they are accustomed. But when a long train of abuses and usurpations, pursuing invariably the same Object evinces a design to reduce them under absolute Despotism, it is their right, it is their duty, to throw off such Government, and to provide new Guards for their future security. — Such has been the patient sufferance of these Colonies; and such is now the necessity which constrains them to alter their former Systems of Government. The history of the present King of Great Britain is a history of repeated injuries and usurpations, all having in direct object the establishment of an absolute Tyranny over these States. To prove this, let Facts be submitted to a candid world.<br/>")
wait {
msg ("We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable Rights, that among these are Life, Liberty and the pursuit of Happiness. — That to secure these rights, Governments are instituted among Men, deriving their just powers from the consent of the governed, — That whenever any Form of Government becomes destructive of these ends, it is the Right of the People to alter or to abolish it, and to institute new Government, laying its foundation on such principles and organizing its powers in such form, as to them shall seem most likely to effect their Safety and Happiness. Prudence, indeed, will dictate that Governments long established should not be changed for light and transient causes; and accordingly all experience hath shewn that mankind are more disposed to suffer, while evils are sufferable than to right themselves by abolishing the forms to which they are accustomed. But when a long train of abuses and usurpations, pursuing invariably the same Object evinces a design to reduce them under absolute Despotism, it is their right, it is their duty, to throw off such Government, and to provide new Guards for their future security. — Such has been the patient sufferance of these Colonies; and such is now the necessity which constrains them to alter their former Systems of Government. The history of the present King of Great Britain is a history of repeated injuries and usurpations, all having in direct object the establishment of an absolute Tyranny over these States. To prove this, let Facts be submitted to a candid world.<br/>")
wait {
msg ("We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable Rights, that among these are Life, Liberty and the pursuit of Happiness. — That to secure these rights, Governments are instituted among Men, deriving their just powers from the consent of the governed, — That whenever any Form of Government becomes destructive of these ends, it is the Right of the People to alter or to abolish it, and to institute new Government, laying its foundation on such principles and organizing its powers in such form, as to them shall seem most likely to effect their Safety and Happiness. Prudence, indeed, will dictate that Governments long established should not be changed for light and transient causes; and accordingly all experience hath shewn that mankind are more disposed to suffer, while evils are sufferable than to right themselves by abolishing the forms to which they are accustomed. But when a long train of abuses and usurpations, pursuing invariably the same Object evinces a design to reduce them under absolute Despotism, it is their right, it is their duty, to throw off such Government, and to provide new Guards for their future security. — Such has been the patient sufferance of these Colonies; and such is now the necessity which constrains them to alter their former Systems of Government. The history of the present King of Great Britain is a history of repeated injuries and usurpations, all having in direct object the establishment of an absolute Tyranny over these States. To prove this, let Facts be submitted to a candid world.<br/>")
wait {
msg ("We hold these truths to be self-evident, that all men are created equal, that they are endowed by their Creator with certain unalienable Rights, that among these are Life, Liberty and the pursuit of Happiness. — That to secure these rights, Governments are instituted among Men, deriving their just powers from the consent of the governed, — That whenever any Form of Government becomes destructive of these ends, it is the Right of the People to alter or to abolish it, and to institute new Government, laying its foundation on such principles and organizing its powers in such form, as to them shall seem most likely to effect their Safety and Happiness. Prudence, indeed, will dictate that Governments long established should not be changed for light and transient causes; and accordingly all experience hath shewn that mankind are more disposed to suffer, while evils are sufferable than to right themselves by abolishing the forms to which they are accustomed. But when a long train of abuses and usurpations, pursuing invariably the same Object evinces a design to reduce them under absolute Despotism, it is their right, it is their duty, to throw off such Government, and to provide new Guards for their future security. — Such has been the patient sufferance of these Colonies; and such is now the necessity which constrains them to alter their former Systems of Government. The history of the present King of Great Britain is a history of repeated injuries and usurpations, all having in direct object the establishment of an absolute Tyranny over these States. To prove this, let Facts be submitted to a candid world.<br/>")
}
}
}
}
}
]]></dowait>
<look>Code to illustrate nested wait problem.</look>
</object>
</object>
<verb>
<property>dowait</property>
<pattern>dowait</pattern>
<defaultexpression>"You can't dowait " + object.article + "."</defaultexpression>
</verb>
</asl>
mrangel
24 Apr 2018, 08:05Does it work if you changed the contents of the big messages?
If it only happens if you're displaying huge messages, maybe it could be some kind of timing issue or race condition?

DavyB
24 Apr 2018, 08:22I found it happening when there were several levels of nesting and quite a bit of text to display. I thought it might be due to hitting the space bar while text was being displayed but I found this code brought up the problem immediately though not every time! ...so it looks like a race condition issue.


K.V.
24 Apr 2018, 11:20I keep hoping someone will say "Hey, I've had that problem, here's what you do..."
Hey, I've had that problem!
Here's what I do: http://textadventures.co.uk/forum/quest/topic/fi7rs8pxxkmfgb6z2xk5eg/unexpected-error-messages-with-nested-wait#51ca5b7f-a217-4836-b762-1991d57289b0
...but that is what you did in your example game, and your example works on my machine...
Have you tested your example game to make sure it throws errors? Or did you just assume it would? (I only ask because I make such assumptions quite frequently, only to find that I failed to recreate the error.)

DavyB
24 Apr 2018, 12:35Hi KV, that game fails on my machine quite consistently. I'm running Windows 8. It fails in different ways in different places. I made Quest hang up completely at one point and needed to use the Task Manager to stop it! I can try it on Windows 7...

DavyB
24 Apr 2018, 12:48...yes, I can get it to fail under Windows 7 as well. Have you tried hitting the space bar while text is being displayed? i.e. not waiting for the continue to appear?

K.V.
24 Apr 2018, 12:50Have you tried hitting the space bar while text is being displayed?
I just spammed the spacebar all the way through it. No errors here.
I'm going to try on my Windows 7 machine.

K.V.
24 Apr 2018, 13:02No errors using Windows 7 on my end, either.

K.V.
24 Apr 2018, 13:06Hi KV, that game fails on my machine quite consistently. I'm running Windows 8.
This is referencing the example game that you just posted, correct?
It fails in different ways in different places.
Which different ways in which different places?
I can only find one way to trigger the script. From there, I can either click the link (which is error-free on my end) or press any key (which is error-free on my end).
I'm not implying that you have an imaginary problem or anything. I just can't recreate the error, and I wanted to see it so I could help.

DavyB
24 Apr 2018, 13:25KV, I've sent a screen shot to you by gmail. Couldn't seem to paste it here?

K.V.
24 Apr 2018, 13:59Got the screenshot.
It looks like that is being clicked more than once in the pane. Each click starts the script from the beginning instead of ending the wait.
In playercore.js, in the initial function, in the bit of code starting on line 97:
I changed the onclick script for the elementmenu class to avoid the error when clicking on something in the pane during a wait:
$(document).on("click", ".elementmenu", function (event) {
// KV added this check for wait mode
if(_waitMode){
endWait();
return;
}
// END OF ADDITION BY KV
if (!$(this).hasClass("disabled")) {
event.preventDefault();
event.stopPropagation();
$(this).jjmenu_popup();
$(this).blur();
return false;
}
});

K.V.
24 Apr 2018, 14:04I also just noticed that pressing ENTER while a button in the pane is selected has a different effect than clicking it!
This will cause the error, too!!!
Be right back!

K.V.
24 Apr 2018, 14:22Okay...
When clicking on a button in the pane, the button remains selected. Then, pressing enter "clicks" that button, but it doesn't seem to be handled as an actual click. Something to do with submitting forms I think...

DavyB
24 Apr 2018, 14:40Just to summarise my understanding so far. If a player waits for continue to appear and clicks on it, all is fine. Hitting any key should also work and I'd become used to hitting the space bar instead of clicking. Failures can sometimes occur in that situation if the space bar is pushed before the next continue appears. Experimenting, I find that hitting most keys is also fine but return is a problem as well as the space bar. I guess this hasn't come up before because most players patiently wait to click 'continue'!

K.V.
24 Apr 2018, 14:52Alrighty...
When clicking on "dowait" in the pane under 'wait responder', the button stays selected. Pressing a key afterwards caused that to somehow simulate a button click which onclick couldn't prevent. So, I added code to take the focus off of a ui-button on clicking it.
$('.ui-button').on("click",function(e){$(this).blur();if (_waitMode){endWait();e.preventDefault;e.stopPropagation;}});
That works as long as the player doesn't use tab to select the button.
This keeps the player from selecting a button during a wait:
$('.ui-button').on("focus",function(e){if (_waitMode){$(this).blur();}});
So, I put it all together, and add this line to game.inituserinterface:
JS.eval ("$(document).on(\"click\", \".elementmenu\", function (event) {if(_waitMode){endWait();return;}if (!$(this).hasClass(\"disabled\")) {event.preventDefault();event.stopPropagation();$(this).jjmenu_popup();$(this).blur();return false;}});$('.ui-button').on(\"click\",function(e){$(this).blur();if (_waitMode){endWait();e.preventDefault;e.stopPropagation;}});$('.ui-button').on(\"focus\",function(e){if (_waitMode){$(this).blur();}});")

DavyB
24 Apr 2018, 15:12Thanks KV, all now seems perfect. Will that code be in the next release?

K.V.
24 Apr 2018, 18:35It works!
Awesome!
That's definitely a bug. I think something that has the same effect will probably be added. (Pixie will probably know a better (or more efficient) way to handle it.)

DavyB
24 Apr 2018, 19:16Okay, for the moment I can slot that code into games as a workaround. Thanks for your help.
mrangel
24 Apr 2018, 19:48That looks like quite an ugly workaround to me :S You're using script to move the focus off the buttons, rather than actually disabling the buttons. I think the error might still occur if a Timeout event (in Quest or in Javascript) starts a 'wait' while the player is clicking the verb button, before they release the mouse.
Wouldn't changing the verb buttons so they can't be clicked be more efficient? Or have I missed something? My first instinct would be to try changing the function that handles the click.
function paneButtonClick(target, button) {
if (_waitMode) return;
(followed by the rest of that function as it is)

mrangel
24 Apr 2018, 23:01OK, I don't understand that.
Does pressing enter on a verb button not call paneButtonClick?
EDIT: No, I don't get this at all.
Clicking the verb buttons calls paneButtonClick; which extracts the selected object name and the verb name, composes them into a command, and calls sendCommand()
.
Which should then return without doing anything if _waitMode
is true.
All the functions which actually pass data back to the server check _waitMode first, ensuring that no clicks get back to the server while waiting.
(... actually, only true in the web version. I assume the desktop version performs this check somewhere else?)

K.V.
25 Apr 2018, 02:11Seems to be doing the same in desktop version. It's confused me as well.
I tried onkeypress on everything, but to no avail. That's why I broke down and used onfocus to blur the damned button.

K.V.
25 Apr 2018, 02:29Aha! You led me to the problem, mrangel!
sendCommand()
doesn't check for _waitMode
in desktopplayer.js!
This seems to do the trick:
JS.eval ("function sendCommand(text, metadata) { if(_waitMode){endWait();return;} markScrollPosition(); var data = new Object(); data[\"command\"] = text; if (typeof metadata != \"undefined\") { data[\"metadata\"] = metadata; } UIEvent(\"RunCommand\", JSON.stringify(data));}")
The same thing in actual Javascript:
function sendCommand(text, metadata) {
// Added by KV
if(_waitMode){
endWait();
return;
}
// END OF ADDITION BY KV
markScrollPosition();
var data = new Object();
data["command"] = text;
if (typeof metadata != "undefined") {
data["metadata"] = metadata;
}
UIEvent("RunCommand", JSON.stringify(data));
}

DavyB
25 Apr 2018, 05:42...I've taken away [SOLVED] while the discussion continues... :)

K.V.
25 Apr 2018, 07:37If it were up to me (and no one pointed out any flaws), I would have this:
$(window).on('keydown',function(e){
if(_waitMode){
endWait();
e.preventDefault();
e.stopPropagation();
}
});
$(window).on('click',function(e){
if(_waitMode){
endWait();
e.preventDefault();
e.stopPropagation();
}
});
Any button press or any click anywhere in the window will runendWait()
with this setup. I've tested it out, and I can't see that it breaks anything. Plus, you can hit Enter or the spacebar while that button is in focus, and it doesn't throw the error.

DavyB
25 Apr 2018, 10:36That looks AND feels good. I've also tried it out and don't see any issues. You must be close to an optimal solution KV!
mrangel
25 Apr 2018, 11:05I'm not sure that catching all clicks is a good thing.
Would that mean that if you click the label of the inventory pane, for example, it would end the wait instead of expanding/collapsing the pane? Will clicking the scroll bar (as if anyone still uses that) end a wait?
I can imagine situations where the game gives you a "Continue ..." button before starting a timed puzzle; in which case players might still want to show the compass and inventory, and even select the relevant item in the inventory to save a second or two. I'd expect that to be supported; only triggering the 'continue' when you actually try to do something.
Different players might have different expectations, but I would expect that a "Continue..." link would block me from taking any game actions. I wouldn't expect it to be dismissed by clicking on display elements that don't correspond to any activity by the player character.
(haven't tested it yet, but I'm also curious how this would interact with my drag-and-dock panes script)

K.V.
25 Apr 2018, 11:50The clicks and keypresses already either end the wait, cause errors, or simply don't work when _waitMode
is true.
Is _waitMode
ever true without an author initiating it to pause play?

K.V.
25 Apr 2018, 12:24Would that mean that if you click the label of the inventory pane, for example, it would end the wait instead of expanding/collapsing the pane?
Good point!
Will clicking the scroll bar (as if anyone still uses that) end a wait?
It didn't, but I had to test it to make sure!
I can imagine situations where the game gives you a "Continue ..." button before starting a timed puzzle; in which case players might still want to show the compass and inventory, and even select the relevant item in the inventory to save a second or two. I'd expect that to be supported; only triggering the 'continue' when you actually try to do something.
Very good thinking!
$(window).on('keydown',function(e){
if(_waitMode){
endWait();
e.preventDefault();
e.stopPropagation();
}
});
$('#divOutuput').on('click',function(e){
if(_waitMode){
endWait();
e.preventDefault();
e.stopPropagation();
}
});

DavyB
04 Jun 2018, 20:57Did this fix end up in 5.8? I don't see it mentioned. Happy to continue with the patch but obviously better if I can leave it out.

K.V.
04 Jun 2018, 21:54I don't think it was added (not 100% sure, though).

K.V.
05 Jun 2018, 01:21For online authors (or desktop authors) who want to experiment with this, you can add this to your User Interface Initialisation script:
// Apply WAIT fix
JS.eval("$(window).on('keydown',function(e){ if(_waitMode){ endWait(); e.preventDefault(); e.stopPropagation(); } }); $('#divOutuput').on('click',function(e){ if(_waitMode){ endWait(); e.preventDefault(); e.stopPropagation(); } });")