! ----------------------------------------------------------------------------
! TimeWait - an Inform library to provide understanding of English time
! strings, and give an enhanced Wait command. Time games only!
!
! Include it just after Grammar.
! (c) Andrew Clover, 1995, but freely usable. Release 3.
! Compatible with Inform 5.5, library 5/12.
! ----------------------------------------------------------------------------
! The tw_waiting object is a dodgy way of having a global variable without using
! a global (which we can't because we're #included at an inconvenient time). If
! any importantish messages appear, you should give this object 'on', and any
! multiple waits will stop. This is intended for events such as "Bob threatens
! to kill you unless you give him a fish within the next three moves", but not
! each turn messages like "The radio blares out a Hammond organ rendition of the
! Mr. Blobby song". The only point at which it is essential you set this is if
! you move the clock backwards, or forwards 24 hours or more.
object tw_waiting "tw";
! Action routines for Wait command...
[ WaitMovesSub i;
if (noun==0)
"I don't understand how to wait that long.";
L__M(##Wait);
give tw_waiting ~on;
for (i= noun: (i>1) && (deadflag==0) && (tw_waiting hasnt on): i--)
{
turns--;
EndTurnSequence();
DisplayStatus();
#IFV5;
DrawStatusLine();
#ENDIF;
}
if ((tw_waiting has on) && (i>1) && (deadflag==0))
{
print "^(waiting stopped)^";
meta= 1;
}
];
[ WaitUntilSub i j;
parsed_number=(parsed_number-1);
if (parsed_number<0)
parsed_number=parsed_number+1440;
parsed_number=parsed_number % 1440;
if (i==0)
{
if (parsed_number<the_time)
{
print "(tomorrow)^^";
i=1;
}
}
else
i=i-1;
L__M(##Wait);
give tw_waiting ~on;
while (((the_time<parsed_number)||(i>0))&&(tw_waiting hasnt on)&&(deadflag==0))
{
j=the_time;
turns--;
EndTurnSequence();
if (the_time<j)
{
i=i-1;
}
DisplayStatus();
#IFV5;
DrawStatusLine();
#ENDIF;
}
if ((tw_waiting has on)&&(deadflag==0))
{
print "^(waiting stopped)^";
meta= 1;
}
];
! ParseTime takes data from the next words (using wn) and returns a the_time
! format time number, or -1 for unrecognisable. It can recognise time expressed
! in any of the following formats:
!
! a. <"0"-"59">|<"one"-"twenty">|"half"|"quarter" ["minutes"|"minute"]
! "past"|"to" <"1"-"12">|<"one"-"twelve"> ["am"|"pm"]
! b. <"1"-"12">|<"one"-"twelve"> ["o'clock"] ["am"|"pm"]
! c. <"1"-"12">|<"one"-"twelve"> <"0"-"59">|<"one"-"twenty"> ["am"|"pm"]
! d. <"1"-"12">":"<"0"-"59"> ["am"|"pm"]
! e. "midnight"|"midday"|"noon"
!
! If no am/pm is specified, the next time likely to come up is chosen; that is,
! the one that's just ahead of the current time. However, if this happens, the
! tw_waiting object is given the 'general' attribute. Thus you can change the
! time returned by twelve hours in an action like SetClock if necessary.
!
! The next dictionary command is there to allow us to compare a typed string
! with "o'clock", something we can't normally do as it is bounded by single
! quotes.
[ ParseTime i j k flg loop dig hr mn;
give tw_waiting ~general;
i=NextWord();
if (i=='midday' or 'noon' or 'midnight') ! then case (e) applies
{
if (i=='midnight')
hr=0;
else
hr=12;
mn=0;
parsed_number=(hr*60+mn);
}
else
{
k=(wn-1)*4+1; ! test for case (d)
j=parse->k;
j=j+buffer;
k=parse->(k-1);
flg=0;
for (loop=0:loop<k:loop++)
{
dig=j->loop;
if (dig==':')
flg=1;
}
if ((k>2)&&(k<6)&&(flg==1)) ! then case (d) applies
{
hr=0;
mn=0;
loop=0;
.tw_diglph;
dig=j->loop;
loop++;
if (dig~=':')
hr=hr*10;
if (dig=='0') { hr=hr+0; jump tw_diglph; }
if (dig=='1') { hr=hr+1; jump tw_diglph; }
if (dig=='2') { hr=hr+2; jump tw_diglph; }
if (dig=='3') { hr=hr+3; jump tw_diglph; }
if (dig=='4') { hr=hr+4; jump tw_diglph; }
if (dig=='5') { hr=hr+5; jump tw_diglph; }
if (dig=='6') { hr=hr+6; jump tw_diglph; }
if (dig=='7') { hr=hr+7; jump tw_diglph; }
if (dig=='8') { hr=hr+8; jump tw_diglph; }
if (dig=='9') { hr=hr+9; jump tw_diglph; }
if (dig~=':') return -1;
while (loop<k)
{
dig=j->loop;
mn=mn*10;
if (dig=='0') { mn=mn+0; jump tw_digokm; }
if (dig=='1') { mn=mn+1; jump tw_digokm; }
if (dig=='2') { mn=mn+2; jump tw_digokm; }
if (dig=='3') { mn=mn+3; jump tw_digokm; }
if (dig=='4') { mn=mn+4; jump tw_digokm; }
if (dig=='5') { mn=mn+5; jump tw_digokm; }
if (dig=='6') { mn=mn+6; jump tw_digokm; }
if (dig=='7') { mn=mn+7; jump tw_digokm; }
if (dig=='8') { mn=mn+8; jump tw_digokm; }
if (dig=='9') { mn=mn+9; jump tw_digokm; }
return -1;
.tw_digokm;
loop++;
} ! decode digital time
}
else
{
j=NextWordStopped();
if ((j=='o^clock' or -1)||(j=='am' or 'pm')) ! then case (c) applies
{
hr=TryNumber(wn-2);
mn=0;
if (j~='o^clock')
wn--;
}
else
{
k=TryNumber(wn-1);
if (k~=-1000) ! then case (b) applies
{
mn=k;
hr=TryNumber(wn-2);
}
else ! well, must be case (a)
{
mn=TryNumber(wn-2);
if (i=='quarter')
mn=15;
if (i=='twenty-five')
mn=25;
if (i=='half' or 'thirty')
mn=30;
if (j=='minute' or 'minutes')
j=NextWord(); ! ignore 'minutes'
hr=TryNumber(wn);
wn++;
if (j~='past' or 'to')
hr=-1;
if (j=='to')
{
hr--;
mn=60-mn;
if (hr==0)
hr=12;
}
}
}
}
if ((hr>12)||(hr<1)||(mn>59)||(mn<0))
parsed_number=-1;
else
{
if (hr==12) ! now sort out am/pm
hr=0;
i=NextWord();
if (i=='pm')
hr=hr+12;
else
if (i~='am') ! am or pm implied, then?
{
give tw_waiting general;
wn--;
i=(hr*60+mn);
j=((hr+12)*60+mn);
i=i-the_time;
j=j-the_time;
if (i<0)
i=i+(24*60);
if (j<0)
j=j+(24*60);
if (i>j)
hr=hr+12;
}
parsed_number=(hr*60+mn);
}
}
if (parsed_number==-1)
return -1;
else
return 1;
];
! Now the grammar for the new Wait actions.
! You can use parsetime in other new actions. For example, you could perhaps
! allow setting of watches, etc. with grammar like:
!
! extend "set" first
! * is_timepiece "to" parsetime -> SetClock;
!
! You may also like to extend wait to allow "Wait for <something>" extend this
! "first" to make this take precedence over "Wait for <time>" (the parsefors
! in the grammar line represent 0 or 1 occurances of the word 'for').
extend "wait"
* "until" parsetime -> WaitUntil
* "til" parsetime -> WaitUntil
* "till" parsetime -> WaitUntil
* number -> WaitMoves
* parsefor number "minute" -> WaitMins
* parsefor number "minutes" -> WaitMins
* parsefor number "hour" -> WaitHours
* parsefor number "hours" -> WaitHours;