I wondered if it would be safe to create code like this:
int storebutton;
int count;
function repeatedly_execute_always() {
if (count>1) count--;
if (count==1 && (mouse.IsButtonDown(eMouseRight) || mouse.IsButtonDown(eMouseLeft)) && player.Moving) {
player.StopMoving(); // Cancel wahtever blocking action was going on
}
}
function on_mouse_click(MouseButton button) {
storebutton=button;
count=15;
}
Why wouldn't it be? Well, if you had an interaction that did:
function hotspot1_a() {
// script for Hotspot 1 (Hotspot 1): Interact hotspot
player.Walk(hotspot[1].WalkToX, hotspot[1].WalkToY, eBlock);
player.Say("Done");
}
then stopping the character walkign in rep_ex_always will leave the Say function never called. Does AGS build up some stack of "hung functions" when you do this, or does it just give up on them? Becasue it seems to work in a quick test (i.e. clicking during blocking stops the action) but maybe after 100 or 1000 cancelled walks, it would die?
You could simulate this by using (pseudo code)
rep_ex_always
if (!player.Moving) hotspot[1].RunInteraction(eCursorMode_Interact); else player.StopMoving();
and just let it run.
Yes, the code that you've posted is safe. By calling StopMoving in rep_exec_always, it will mark the character as Stopped, then the main thread will notice that the character has finished, and continue to run. I'm not sure why you claim that "Say" would never be called -- I just tried a sample game with this code and when StopMoving was called from rep_exec_always, the main scirpt resumed and the Say() was executed as expected.
For more on blocking scripts see here:
http://www.adventuregamestudio.co.uk/manual/BlockingScripts.htm
Well, in http://ssh.me.uk/cancel.zip you can click on the coloured bits at each end with the "interact" cursor and the following happens:
a) if you click away the "Doing" message, roger cancels his walk and says "Done", i.e. finishes the script
b) if you wait until he starts moving then click, he stops and doesn't say "Done"
c) if you set walkto points on the hotspots and then click to cancel, he doesn't even say "doing"
I think I'd found the reason of your problem, actually no matter what the second "Done" message DID display.
The problem lies in here:
if (count==1 && (mouse.IsButtonDown(eMouseRight) || mouse.IsButtonDown(eMouseLeft)) && player.Moving) {
So, if you click while he's moving, when the StopMoving(); function is called it's obvious that you must still be holding the mouse button in that particular loop, when the Display() line is executed, it's registered as a mouse click so the text goes away immediately.
If you click it while "Doing" is displayed, when you click away the text the mouse click had been registered, if you're still holding the button it won't be considered as another click when "Done" is displayed.
You may test it by adding some visible effect which won't be clicked away after the player moves (like Rawprinting a message, etc.), and you'll see the subsequent actions are indeed called.
EDIT:
Another fast way to check is, that you insert another Display() after "Done" (like "Done2" say for example), and you'll see that when you click while walking it looks as if the first "Done" is not executed (actually you clicked the text away) but the second "Done2" is still visible.
Yes, Gilbert's explanation sounds plausible.
Because IsButtonDown is asynchronous, you will probably detect the mouse being down before AGS actually processes it as a click itself, therefore that will then click away the Say() line.
Also, clicks usually register on MouseUp