Posted by
| Nick Gammon
Australia (23,120 posts) Bio
Forum Administrator |
Message
| After reading the posts about speedwalks which wait for you to move from room to room, I thought it might be handy to have a way of building into a script the ability to wait for a line to arrive (eg. Exits: north west) OR a time limit to elapse (eg. 10 seconds).
That way, a script could terminate itself if the desired line did not arrive in a reasonable time.
To do this, the relevant part of the exampscript.lua file has been modified, as below. Lines which have changed are in bold.
Now you can supply an optional timeout argument to the calls to waitforregexp or waitfor. This is the number of seconds to wait.
The functions do this by adding a trigger and a timer. If the trigger fires, it has "send to script" set to delete the corresponding timer. If the timer fires, it deletes the trigger.
In both cases, the thread is resumed. However the return from the resume will indicate whether it timed out or not.
-- ----------------------------------------------------------
-- table of outstanding threads that are waiting
-- ----------------------------------------------------------
wait_table = {}
-- ----------------------------------------------------------
-- called by a timer to resume a thread
-- ----------------------------------------------------------
function wait_timer_resume (name)
thread = wait_table [name]
if thread then
assert (coroutine.resume (thread))
end -- if
end -- function wait_timer_resume
-- ----------------------------------------------------------
-- called by a trigger to resume a thread
-- ----------------------------------------------------------
function wait_trigger_resume (name, line, wildcards)
EnableTrigger (name, false) -- don't want it to fire again
DoAfterSpecial (1, "DeleteTrigger ('" .. name .. "')", 12) -- delete it
thread = wait_table [name]
if thread then
assert (coroutine.resume (thread, line, wildcards))
end -- if
end -- function wait_trigger_resume
-- ----------------------------------------------------------
-- we call this to wait in a script
-- ----------------------------------------------------------
function wait (thread, seconds, id)
id = id or "wait_" .. GetUniqueNumber ()
hours = math.floor (seconds / 3600)
seconds = seconds - (hours * 3600)
minutes = math.floor (seconds / 60)
seconds = seconds - (minutes * 60)
status = AddTimer (id, hours, minutes, seconds,
"DeleteTrigger ('" .. id .. "')",
timer_flag.Enabled + timer_flag.OneShot +
timer_flag.Temporary + timer_flag.Replace,
"wait_timer_resume")
assert (status == error_code.eOK, error_desc [status])
SetTimerOption (id, "send_to", "12") -- send to script
wait_table [id] = thread
return coroutine.yield ()
end -- function wait
-- ----------------------------------------------------------
-- we call this to wait for a trigger with a regexp
-- ----------------------------------------------------------
function waitforregexp (thread, regexp, timeout)
local id = "wait_" .. GetUniqueNumber ()
status = AddTriggerEx (id, regexp,
"DeleteTimer ('" .. id .. "')", -- script to delete the timeout timer
trigger_flag.Enabled + trigger_flag.RegularExpression +
trigger_flag.Temporary + trigger_flag.Replace,
custom_colour.NoChange,
0, "", -- wildcard number, sound file name
"wait_trigger_resume",
12, 100) -- send to scripting
assert (status == error_code.eOK, error_desc [status])
if timeout and timeout > 0 then
return wait (thread, timeout, id)
end -- if having a timeout
wait_table [id] = thread
return coroutine.yield () -- return line, wildcards
end -- function waitforregexp
-- ----------------------------------------------------------
-- we call this to wait for a trigger (not a regexp)
-- ----------------------------------------------------------
function waitfor (thread, match, timeout)
return waitforregexp (thread, MakeRegularExpression (match), timeout)
end -- function waitfor
An example of using it is in this alias:
<aliases>
<alias
match="test"
enabled="y"
send_to="12"
sequence="100"
>
<send>
do local t = coroutine.create (function (t)
print ("about to wait for 'east' or 5 seconds")
line, wildcards = waitforregexp (t, "east", 5)
if line then
print ("line = " .. line)
else
print ("timeout!")
end -- if
end) assert (coroutine.resume (t, t)) end
</send>
</alias>
</aliases>
This simple example waits for the word "east" to match the regular expression, or 5 seconds. You can tell from the return codes, whether it timed out or not. If the returned line is nil, then the timer fired, and therefore it timed out. If it is not nil, then the matching line is returned.
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|