1
!====================================================================================
2
! TIMESYS 1.0 INFORM TIME-ORIENTED GAME EXTENSION
4
! An Inform library to provide an understanding of English time
5
! strings, and give an enhanced Wait command.
7
! (c) Kevin Forchione, 1998, but freely usable.
8
! Compatible with Inform 6.15, library 6/7.
9
! Based on WaitTime.h by L. Ross Raszewski, 1996
10
! and TimeWait.h by Andrew Clover, 1995
11
! with much appreciation for their efforts.
13
! IMPLEMENTATION REQUIREMENTS:
15
! Time-oriented games only
16
! Replace DrawStatus; and set constant to STYLE you wish (see STYLES below)
17
! Replace WaitSub(); (the replacement routine is already provided in the
19
! Change WAIT verb to META in GRAMMAR.H
20
! #include TimeSys.h somewhere after #include "Grammar";
21
! Set the day-of-the-week (if desired) in Initialise() with
22
! TimeSys('day'); (see below)
23
! Day-of-week advancement (if desired) At the top of TimePasses();
24
! call TimeSys.NextDay() for automatic handling of day-of-week advancement.
28
! This is hardly an ideal solution (That being an overhaul of the
29
! InformLibrary itself to extend its time-keeping capabilities.)
31
! Nonetheless, by making the WAIT command META we take control out of the
32
! InformLibrary's Turn__end process and allow the extension to process
33
! Waiting() and StopWaiting() requests without falling back into final execution
34
! of InformLibrary.End_Turn_Sequence, which causes problems with StopWaiting()
35
! requests. (i.e. the request stops the extension at the desired time, but
36
! InformLibrary.Turn__end gets the final word and bumps the time up one more step.)
38
! DRAWBACKS: However, there are some drawbacks...
40
! Unfortunately the functions of the TimeSys object are completely dependent
41
! upon being called through the wait subroutines as were those of it's predecessor
42
! tw_waiting (It's never in scope).
44
! Making the WAIT verb META compounds the difficulty in generation of actions
45
! to an object's before() and Orders().
47
! ENHANCEMENTS: The TimeSys object has been significantly enhanced over
48
! the old tw_waiting object.
50
! The variables in TimeSys have all been made private. Access methods
51
! It now contains coding for the advancement of the day-of-week, which should
52
! be called from TimePasses() with TimeSys.NextDay().
54
! The redundant call to TimePasses() in the Waiting process that occurred in
55
! WaitTime.h has been removed and this process moved to the TimeSys object
56
! instead of being handled in a standalone routine. In addition this means
57
! that the wait process is effected only once each cycle by the
58
! InformLibrary.End_Turn_Sequence().
60
! You can set a wait default (independent of time_step) which will allow you
61
! to wait a default number of minutes (such as in Infocom's "Sherlock: The Riddle
62
! of the Crown Jewels").
64
! The non-waiting time_rate is kept independent of the waiting process, so
65
! that you can SetTime() for any rate you wish for the normal (non-waiting)
66
! passage of time. Waiting converts minutes to turns (as WaitTime.h did),
67
! then when the waiting process is finished the original non-waiting time_rate
70
! Other features are documented below.
72
!====================================================================================
74
Object TimeSys "TimeSys"
77
TS_day 0 ! Day-of-the-week numeric value
78
,TS_WaitDefault 10 ! Default value for Wait with no operand
79
,TS_WaitMax 1440 ! Maximum number of minutes allowed in a Wait
80
,TS_wait_time_initial 0 ! Number of minutes to be waited
81
,TS_wait_time_remaining 0 ! Number of minutes for waiting remaining
82
,TS_normal_time_rate 0 ! Saved value of non-wait game time-rate
83
,TS_prev_time_save 0 ! Saved value used to determine new day
88
if (noun > self.TS_WaitMax) {give self locked; "That's too long to wait.";};
89
if (noun==0) {give self locked; "Time doesn't pass.^";};
90
print "Time passes...^";
92
self.TS_wait_time_initial=noun;
93
self.TS_wait_time_remaining=noun;
94
self.TS_normal_time_rate=time_rate;
97
for (i=noun : (i>0)&&(deadflag==0)&&(self has on) : i--)
100
self.TS_wait_time_remaining--;
102
#ifdef InformLibrary;
103
InformLibrary.End_Turn_Sequence();
105
#ifdef EndTurnSequence;
108
Message fatalerror "waittime.h requires \
109
InformLibrary.End_Turn_Sequence() or \
110
EndTurnSequence() to be defined (this should be done \
111
by the Inform Library)";
119
SetTime(the_time,self.TS_normal_time_rate);
120
if ((self hasnt on)&&(self.TS_wait_time_remaining>0)&&(deadflag==0))
121
print "^(waiting stopped)^";
124
!--------------------------------------------------------------------------------------
125
! This routine allows the author to code StopWaiting requests for any event s/he chooses.
126
! It also give the player the choice of continued waiting if they wish.
127
!----------------------------------------------------------------------------------------
130
if (self.TS_wait_time_remaining==0) rfalse;
137
print "^Do you want to continue waiting?";
138
if (YesOrNo()==0) give self ~on;
142
[ d; self.TS_WaitDefault=d;
146
[; return self.TS_WaitDefault;
149
!-----------------------------------------------------------------------------------------
150
! This function allows the author to set the game day using the name for the
151
! day-of-the-week, instead of having to use its numeric value. This allows TimeSys
152
! to keep this variable private.
153
!-----------------------------------------------------------------------------------------
157
{ 'Sunday','sunday','Sun','sun',"Sunday","sunday","Sun","sun":
159
'Monday','monday','Mon','mon',"Monday","monday","Mon","mon":
161
'Tuesday','tuesday','Tue','tue',"Tuesday","tuesday","Tue","tue":
163
'Wednesday','wednesday','Wed','wed',"Wednesday","wednesday","Wed","wed":
165
'Thursday','thursday','Thu','thu',"Thursday","thursday","Thur","thur":
167
'Friday','friday','Fri','fri',"Friday","friday","Fri","fri":
169
'Saturday','saturday','Sat','sat',"Saturday","saturday","Sat","sat":
171
default: self.TS_day=d;
175
!-----------------------------------------------------------------------------------------
176
! This function allows time-oriented games to have the day-of-the-week pushed forward with
177
! the passage of time. Although it goes beyond the scope of purely 'waiting' it aspires to
178
! a more mature time-keeping system we can only now dream of.
180
! This should be called from TimePasses() as TimeSys.NextDay() for automatic advancement.
181
!------------------------------------------------------------------------------------------
184
if (the_time < self.TS_prev_time_save) {self.TS_day++;};
185
if (self.TS_day > 6) {self.TS_day=0;};
186
self.TS_prev_time_save=the_time;
189
!------------------------------------------------------------------------------------------
190
! This routine returns either the number value or the associated name for the
191
! day_of_the_week, and can be included in any StatusLine routine that needs to know the
193
!------------------------------------------------------------------------------------------
196
if (f==0) return self.TS_day;
220
!------------------------------------------------------------------------------------------
223
! Some of the styles listed below mimic styles from classic Infocom games
224
! (versions may differ). To select a style of statusline simply define the
225
! constant listed below as one of the following:
227
! BASIC_STYLE: Mimics statuslines of the following:
228
! Cutthroats Release 23 / Serial number 840809
229
! Deadline: An Interlogic Mystery Release 27 / Serial Number 831005
230
! MoonMist Release 9 / Serial Number 861022
231
! Suspect: An Interactive Mystery Release 14 / Serial Number 841005
232
! The_Witness: An Interlogic Mystery Release 22 / Serial Number 840924
233
! Wishbringer: The Magick Stone of Dreams Release 69 / Serial Number 850920
235
! STANDARD_STYLE: Displays day/time information
237
! FULL_STYLE: Displays day/time/score information
239
! SHERLOCK_STYLE: Mimics statuslines of Infocom's Sherlock game, which used
240
! an hh:mm:ss format, even though the game didn't handle seconds:
241
! Sherlock: The Riddle of the Crown Jewels Release 21 / Interpreter 6 /
242
! Version j / Serial Number 871214
244
!===========================================================================================
249
[ DrawStatusLine i width pos;
250
@split_window 1; @set_window 1; @set_cursor 1 1; style reverse;
252
if (width == 0) width = 80;
254
@set_cursor 1 2; PrintShortName(location);
258
i=sline1%12; if (i<10) print " ";
261
if (sline2<10) print "0";
263
if ((sline1/12) > 0) print " pm"; else print " am";
264
@set_cursor 1 1; style roman; @set_window 0;
266
#ENDIF; ! BASIC_STYLE
268
#IFDEF STANDARD_STYLE;
269
[ DrawStatusLine i width pos;
270
@split_window 1; @set_window 1; @set_cursor 1 1; style reverse;
272
if (width == 0) width = 80;
275
@set_cursor 1 2; PrintShortName(location);
277
print (string) TimeSys.GetDay(1);
278
i=sline1%12; if (i<10) print " ";
281
if (sline2<10) print "0";
283
if ((sline1/12) > 0) print " pm"; else print " am";
284
@set_cursor 1 1; style roman; @set_window 0;
286
#ENDIF; !STANDARD_STYLE
289
[ DrawStatusLine i width pos;
290
@split_window 1; @set_window 1; @set_cursor 1 1; style reverse;
292
if (width == 0) width = 80;
294
@set_cursor 1 2; PrintShortName(location);
297
print (string) TimeSys.GetDay(1);
298
i=sline1%12; if (i<10) print " ";
301
if (sline2<10) print "0";
303
if ((sline1/12) > 0) print " pm"; else print " am";
305
@set_cursor 1 pos; print "Score: ", score;
306
@set_cursor 1 1; style roman; @set_window 0;
310
#IFDEF SHERLOCK_STYLE;
311
[ DrawStatusLine i width pos;
312
@split_window 1; @set_window 1; @set_cursor 1 1; style reverse;
314
if (width == 0) width = 80;
316
@set_cursor 1 2; PrintShortName(location);
319
print (string) TimeSys.GetDay(1);
320
i=sline1%12; if (i<10) print " ";
323
if (sline2<10) print "0";
325
if ((sline1/12) > 0) print ":00 p.m."; else print ":00 a.m.";
327
@set_cursor 1 pos; print "Score: ", score;
328
@set_cursor 1 1; style roman; @set_window 0;
330
#ENDIF; ! SHERLOCK_STYLE
332
!------------------------------------------------------------------------------------------
333
!Action routines for Wait command...
334
!------------------------------------------------------------------------------------------
337
noun=TimeSys.GetDefault();
341
[ WaitMovesSub; TimeSys.Waiting(); ];
349
if (parsed_number>=the_time) noun=parsed_number-the_time;
350
if (parsed_number<the_time)
351
{parsed_number=the_time-parsed_number;
352
noun=1440-parsed_number;
354
if (noun==0) {noun=1440; print "(tomorrow)^^";};
359
!-----------------------------------------------------------------------------------
360
! ParseTime takes data from the next words (using wn) and returns a
361
! the_time format time number, or -1 for unrecognisable. It can recognise
362
! time expressed in any of the following formats:
364
! a. <"0"-"59">|<"one"-"twenty">|"half"|"quarter" ["minutes"|"minute"]
365
! "past"|"to" <"1"-"12">|<"one"-"twelve"> ["am"|"pm"]
366
! b. <"1"-"12">|<"one"-"twelve"> ["o'clock"] ["am"|"pm"]
367
! c. <"1"-"12">|<"one"-"twelve"> <"0"-"59">|<"one"-"twenty"> ["am"|"pm"]
368
! d. <"1"-"12">":"<"0"-"59"> ["am"|"pm"]
369
! e. "midnight"|"midday"|"noon"
370
! If no am/pm is specified, the next time likely to come up is chosen; that
371
! is, the one that's just ahead of the current time. However, if this
372
! happens, the TimeSys object is given the 'general' attribute. Thus you
373
! can change the time returned by twelve hours in an action like SetClock
376
! The next dictionary command is there to allow us to compare a typed
377
! string with "o'clock", something we can't normally do as it is bounded by
379
!-----------------------------------------------------------------------------------
381
constant TS_OCLOCK 'o^clock';
383
[ ParseTime i j k flg loop dig hr mn;
384
give TimeSys ~general;
386
if (i=='midday' or 'noon' or 'midnight') ! then case (e) applies
393
parsed_number=(hr*60+mn);
397
k=(wn-1)*4+1; ! test for case (d)
402
for (loop=0:loop<k:loop++)
408
if ((k>2)&&(k<6)&&(flg==1)) ! then case (d) applies
418
if (dig=='0') { hr=hr+0; jump tw_diglph; }
419
if (dig=='1') { hr=hr+1; jump tw_diglph; }
420
if (dig=='2') { hr=hr+2; jump tw_diglph; }
421
if (dig=='3') { hr=hr+3; jump tw_diglph; }
422
if (dig=='4') { hr=hr+4; jump tw_diglph; }
423
if (dig=='5') { hr=hr+5; jump tw_diglph; }
424
if (dig=='6') { hr=hr+6; jump tw_diglph; }
425
if (dig=='7') { hr=hr+7; jump tw_diglph; }
426
if (dig=='8') { hr=hr+8; jump tw_diglph; }
427
if (dig=='9') { hr=hr+9; jump tw_diglph; }
428
if (dig~=':') return -1;
433
if (dig=='0') { mn=mn+0; jump tw_digokm; }
434
if (dig=='1') { mn=mn+1; jump tw_digokm; }
435
if (dig=='2') { mn=mn+2; jump tw_digokm; }
436
if (dig=='3') { mn=mn+3; jump tw_digokm; }
437
if (dig=='4') { mn=mn+4; jump tw_digokm; }
438
if (dig=='5') { mn=mn+5; jump tw_digokm; }
439
if (dig=='6') { mn=mn+6; jump tw_digokm; }
440
if (dig=='7') { mn=mn+7; jump tw_digokm; }
441
if (dig=='8') { mn=mn+8; jump tw_digokm; }
442
if (dig=='9') { mn=mn+9; jump tw_digokm; }
446
} ! decode digital time
451
if ((j==TS_OCLOCK or -1)||(j=='am' or 'pm')) ! then case (c) applies
461
if (k~=-1000) ! then case (b) applies
466
else ! well, must be case (a)
471
if (i=='twenty-five')
473
if (i=='half' or 'thirty')
475
if (j=='minute' or 'minutes')
476
j=NextWord(); ! ignore 'minutes'
479
if (j~='past' or 'to')
491
if ((hr>12)||(hr<1)||(mn>59)||(mn<0))
495
if (hr==12) ! now sort out am/pm
501
if (i~='am') ! am or pm implied, then?
503
give TimeSys general;
516
parsed_number=(hr*60+mn);
519
if (parsed_number==-1)
525
!----------------------------------------------------------------------------
526
! Now the grammar for the new Wait actions.
527
! You can use parsetime in other new actions. For example, you could perhaps
528
! allow setting of watches, etc. with grammar like:
530
! * is_timepiece "to" parsetime -> SetClock;
531
!----------------------------------------------------------------------------
533
extend 'wait' replace
535
* 'until'/'til'/'till'/'for' parsetime -> WaitUntil
536
* 'for' number 'hour'/'hours' -> WaitHours
537
* 'for' number 'minute'/'minutes' -> WaitMoves
538
* 'for' number 'hour'/'hours' number 'minute'/'minutes' -> WaitHours
539
* 'for' number 'hour'/'hours' 'and' number 'minute'/'minutes' -> WaitHours
540
* number 'minute'/'minutes' -> WaitMoves
541
* number 'hour'/'hours' -> WaitHours
542
* number -> WaitMoves
543
* number 'hour'/'hours' number 'minute'/'minutes' -> WaitHours
544
* number 'hour'/'hours' 'and' number 'minute'/'minutes' -> WaitHours
545
* parsetime -> WaitUntil;