1
! ---------------------------------------------------------------------------- !
2
! Daemons.h by Andrew Plotkin and Roger Firth (roger.firth@tesco.net,
3
! to whom all problems should be notified).
6
! Converted to Inform 6 and Glulx by Roger Firth.
9
! Original version for Inform 5.5 by Andrew Plotkin.
11
! This file is in the public domain.
12
! ---------------------------------------------------------------------------- !
13
! Installation: add the lines:
15
! Replace StartDaemon;
18
! before your Include "Parser" line. Also, add the line:
22
! near the end of your game AFTER you've defined an object which uses a
23
! "daemon_priority" property.
25
! ---------------------------------------------------------------------------- !
27
! This is a package which you can include to make the daemons and timers of
28
! the Inform libraries behave predictably. They will execute in the order
29
! defined by the optional "daemon_priority" property of each object in the
30
! daemon/timer list. Higher priorities go first; if priorities are equal,
31
! they execute in the order in which they were started up. The default
32
! daemon_priority is zero, but you can assign any numerical value to the
33
! property, including negative ones.
35
! There are a few restrictions:
37
! - daemon_priority must be a simple variable containing a number; it cannot
38
! be an embedded routine which returns a number.
39
! - you should assign a new value to a daemon_priority property only while
40
! the object's daemon/timer is *not* running. This means that if an object
41
! has both a daemon and a timer, they must run at the same priority.
42
! - it is illegal to call StartDaemon() or StartTimer() from inside a
43
! daemon or timer routine. It *is* legal to call StopDaemon() or
44
! StopTimer() at any time.
46
! A bonus utility routine IsDaemonActive(obj) returns 1 if obj currently has
47
! an active daemon, 2 for an active timer, 3 for both, 0 for neither.
49
! Here is an example daemon:
52
! with daemon_priority 1000,
57
! ---------------------------------------------------------------------------- !
59
#ifndef WORD_HIGHBIT; ! Is already defined in Glulx compiler.
60
Constant WORD_HIGHBIT $8000; ! Topmost bit in Z-machine word, used by
61
#endif; ! the Library to flag daemons in the_timers.
63
! GetPriority() is a utility routine which masks out the daemon-or-timer flag
64
! and fetches the value of the daemon_priority property.
67
obj = obj & ~WORD_HIGHBIT;
68
if (obj provides daemon_priority) return obj.daemon_priority;
72
! StartDaemonOrTimer() is a utility routine which inserts the given object
73
! in the_timers list, at the position defined by its daemon_priority. That is,
74
! the object is inserted after all objects with a greater-or-equal priority,
75
! and before all objects with a lesser priority.
77
[ StartDaemonOrTimer obj
80
! If obj already in the list, do nothing
81
for (i=0 : i<active_timers : i++)
82
if (the_timers-->i == obj) rfalse;
84
! Compress the list, removing empty slots
85
for (i=0,j=0 : i<active_timers : i++)
88
the_timers-->j = the_timers-->i;
94
! Check for capacity to run another daemon/timer
96
if (active_timers == MAX_TIMERS) { RunTimeError(4); rfalse; }
98
! Find the first slot at a lower priority
99
for (i=0 : i<active_timers : i++)
100
if (GetPriority(the_timers-->i) < GetPriority(obj)) break;
102
! Shift upwards that slot and those above it
103
for ( : j>i : j--) the_timers-->j = the_timers-->(j-1);
105
! Insert the new object
106
the_timers-->i = obj;
107
return ++active_timers;
110
! Replacement for the standard Library version of StartDaemon().
113
StartDaemonOrTimer(obj+WORD_HIGHBIT);
116
! Replacement for the standard Library version of StartTimer().
118
[ StartTimer obj timer;
119
if (obj.&time_left == 0) { RunTimeError(5, obj); return; }
120
if (StartDaemonOrTimer(obj)) obj.time_left = timer;
123
! ---------------------------------------------------------------------------- !
127
! IsDaemonActive() tests whether an object's daemon and/or timer is
128
! currently scheduled to run.
132
for (i=0,j=0 : i<active_timers : i++) {
133
if (the_timers-->i == obj) j = 2;
134
else if (the_timers-->i == obj + WORD_HIGHBIT) j++;
139
! ---------------------------------------------------------------------------- !