Updated:
by Mike Potter (Zugg)
NOTE: This document refers to zMUD v6.26
and later.
Introduction
There are many situations in playing MUDs that involve time. The MUD
itself spawns new mobs and treasures on a timer (a "tick" timer), you
might want to save your character periodically, or you might just want to issue
a command to a MUD after a delay (especially if the MUD has a limit on how fast
it will accept commands).
There have always been ways to control time in zMUD. While you can't
use zMUD to visit ancient Greece, you can still perform quite a lot of magic if
you know what you are doing.
Tick Timer
The most basic timer in zMUD, which has been in zMUD since the original
version, is the tick timer. The intent of the tick timer is to synchronize
with the timer used on the MUD to control spawns, to help you predict when the
next "tick" on the MUD will arrive. Every MUD has a different
tick timer interval, although one minute seems to be common. The
"tick" on the MUD controls everything from mob and object spawning, to
the weather changes.
The main difference between the Tick Timer in zMUD and other timers described
later is the ability of the tick timer to synchronize with the MUD. You
initially set the rough interval of the tick timer using the #TS command:
#TS 60
would set the timer to a 60 second interval. The real trick is using
the #TS command without any argument to synchronize the timer. If you can
detect the actual tick on the MUD using a trigger, you can use the #TS command
to adjust the tick interval to match the MUD exactly. For example, if the
weather changes on your MUD, you can use a trigger like this:
#TRIGGER {It is raining} {#TS}
Whenever that text is received from the MUD, the #TS command will tell the
tick timer that tick just happened, and it will readjust itself accordingly.
The tick timer countdown is also shown in the status bar by default. By
right-clicking on this timer, you can select the Timer Dialog box. In this
dialog box you can change the timer interval, start and stop the timer, and
change the command executed on each tick. You can also turn off the
"TICK IN 5 SECONDS" message from that dialog.
More Timers
In many cases you need more than one timer. Some people try to use the
tick timer for generic timers, but that's not what it is for. Reserve the
tick timer for the application it was intended (predicting MUD ticks).
The #ALARM command can be used to set up all sorts of timers. The most
common syntax for a recurring timer is:
#ALARM *nnn {commands}
where nnn is the timer interval. For example:
#ALARM *10:00 {save}
will save your MUD character every 10 minutes. Note that you can
specify the time as a number of seconds, or as hours:minutes:seconds.
Executing commands at a specific time
You can also use the #ALARM command to execute a command at a specific
time-of-day. For example, the alarm:
#ALARM 12:00:00 {#echo "It's lunch time!"}
Will display the string "It's lunch time!" on the screen at 12
noon. zMUD uses 24-hour time, so to set an alarm for 1 o'clock in the
afternoon, use #ALARM 13:00:00
The MUD Connection time
Instead of executing commands at a specific time of day in the real world,
you can also execute commands after being connected to the MUD for a certain
amount of time. For example, the alarm
#ALARM -5:00:00 {#echo "You've been playing 5 hours!"}
will fire after you have been connected to the MUD for 5 hours. The
minus sign - at the front of the trigger tells zMUD to use "MUD Time"
instead of "Real Time" and can be used in front of most alarm
commands.
Specific Times and Intervals
You can set up an alarm to fire at regular intervals at specific times.
For example, to execute a command every 10 minutes, but at 15-seconds after the
minute, use:
#ALARM *:*10:15 {command}
The * tells the alarm command to match anything. So, the first *
matches any hour, the second *10 matches any minute that is an interval of 10
(0,10,20,30,etc), and the 15 matches only the 15-second moment in time.
Delaying an action
Sometimes you simply want to delay an action by a certain time. For
example, perhaps you want to wait 10 seconds and then cast a spell. You'd
use an Alarm like this:
#ALARM +10 {cast spell}
The + character tells zMUD to create a "one-time-only" alarm with
the specified interval. So, after a 10 second delay, the alarm fires,
executes the command, then deletes itself.
You can also use a fractional number of seconds to delay short intervals:
#ALARM +0.5 {cast spell}
will cast the spell after a delay of only 1/2 second. Windows can only
time things with a resolution of 10 ms or so, so don't try a really small delay
or it probably won't work.
Delays in Triggers
Often the commands you want to delay are the result of a trigger. You
might fire a trigger on some specific text that tells you when you should
execute another command after a delay. You can use the Wait trigger states
for this. For example, the trigger:
#TRIGGER {You are tired.} {sit}
#CONDITION {} {stand} {Wait|Param=5000}
will watch the MUD for the text "You are tired.". When this
text arrives, the "sit" command is sent to the MUD. Five seconds
later (5000 ms), the "stand" command is sent to the MUD by the Wait
condition added to the trigger. For more examples of trigger conditions,
see the Advanced Trigger guide.
The #WAIT Command
Ahh, the dreaded #WAIT command. This is probably the most heavily
abused command in zMUD, and the cause of many scripting problems. Early
versions of zMUD did not have the #ALARM command, so only the #WAIT command
could be used. The general rule of thumb now is: DO NOT USE #WAIT UNLESS
YOU MUST! Repeat this to yourself 10 times.
OK, if you promise not to use the #WAIT command, I'll go ahead and tell you
how it works and what it is really used for. The #WAIT command is used for
adding delays to loops in zMUD. That's all. Any other time delay can
be accomplished using the #ALARM and Trigger Wait condition.
So, if you wanted to send the numbers 1-5 to the MUD with a one-second delay
between each number, you would do this:
#LOOP 1,10 {%i;#WAIT 1000}
There is no easy way to do this using the #ALARM command, so you are allowed
to use #WAIT for this. Do NOT use #WAIT within a
trigger!!
Repeat: DO NOT USE #WAIT WITHIN A TRIGGER! Why? Here is a simple
example:
#TRIGGER {You lose concentration} {#WAIT 5000;recast spell}
Now, we all know you can do this using a Wait condition like this:
#TRIGGER {You lose concentration}
#CONDITION {} {recast spell} {Wait|Param=5000}
or you could use an alarm like this:
#TRIGGER {You lose concentration} {#ALARM +5 {recast spell}}
But, since we are talking about the evils of the #WAIT command, lets look at
the #WAIT example. If you run it, it seems to work. So what is the
problem? What happens if you get the text twice before the 5 seconds is
over. For example:
You lose concentration
<3 seconds later>
You lose concentration
Perhaps you tried to execute a spell twice? Now, if Windows was a
perfect system, what we expect to happen is that the command "recast
spell" is sent 5 seconds after the first text, then sent again 5 seconds
after the second text. But this isn't what happens. Because of how
Windows works (as we'll see in a minute), you get the command "recast
spell" sent twice, 8 seconds after the initial text (the 3 second delay
between the text plus the 5 second delay in the #WAIT command).
So what happened? Why did the #WAIT command from the first text get
displayed 8 seconds later along with the second one? Well, the #WAIT
command tells Windows to pause for the given amount of time. But Windows
continues to process messages (to avoid freezing the application). 3
seconds later you get the second message, and this causes the #WAIT command to
run again, pausing Windows for 5 seconds. But Windows only has a single
execution thread by default. So, while that second command is waiting for
5 seconds, the original wait command is also waiting. When the second
command is done, it then returns to the first command, which notices that more
than 5 seconds is up and executes. So, both triggers wait the full 8
seconds.
If zMUD was multi-threaded, this wouldn't be a problem. Each #WAIT
command could run in a separate thread and then they wouldn't interfere.
But multi-threaded programs are *very* complex to write, and zMUD was originally
written before threads were available. In particular, different threads
cannot access the same resource without complex locking and synchronization, and
the screen output is one of these resources. Trying to resolve the
synchronization problem so that each thread could write to the screen would be
enormously difficult.
So, just don't worry about any of this technical jargon. Just stop
using the #WAIT command and start using #ALARM and Trigger Wait states
instead. You're scripts will work a lot better then!