I’m trying to create a “wait for” command that can take in such inputs as “wait a minute” or “wait for 30 seconds” or even “wait for 92 seconds”. With regexp trickery I can dig out the number and the info if it’s minutes or seconds, but I get the input as text (“30”, “92”) and I can’t seem to find a way to convert this to a number for some arithmetics done in seconds. Is there a simple way I’ve just overlooked?
Well, if you only needed minutes and hours, that could work out of the box: if you write an action applying to a time and an understand token like “wait for [a time period]”, then Inform already understand “wait for two minutes” or “wait for an hour” as referring to the specified time periods. See section 17.9 of Writing with Inform on how the Understand line referring to a value works (in particular, there is an idiosyncrasy where the value is “a time” but the understand token is “[a time period]”), and see example 386, “Nine AM Appointment,” for an implementation of the “wait for” command.
Seconds are a bit harder, because they’re not defined as time periods out of the box. However, you shouldn’t have to resort to regexp trickery. You can define your own units and write actions applying to them; if necessary you can define two different “wait for” actions that apply to the different time periods. Here’s a way of defining time periods in units of seconds and writing an action applying to them:
[code]Lab is a room.
Before reading a command: say “The time is [time of day].” [using “before reading a command” because we’re running the turn sequence rules repeatedly, so using an “every turn” rule would print a message every minute]
A fractional time period is a kind of value. 999 seconds specifies a fractional time period.
Fractional waiting is an action applying to one fractional time period. Understand “wait [a fractional time period]” or “wait for [a fractional time period]” or “wait for a/an [a fractional time period]” or “wait a/an [a fractional time period]” as fractional waiting.
Carry out fractional waiting:
let X be the fractional time period understood;
let M be X divided by 60 seconds; [rounds down]
if M is 0:
say “Trying to cut things too fine, you wait an entire minute.”;
now M is 1;
try waiting more M. [that is, waiting M minutes]
[this is copied from example 386]
Waiting more is an action applying to one number.
Understand “wait [a time period]” or “wait for [a time period]” or “wait for a/an [a time period]” or “wait a/an [a time period]” as waiting more.
Carry out waiting more:
let the target time be the time of day plus the time understood;
decrease the target time by one minute;
while the time of day is not the target time:
follow the turn sequence rules.[/code]
There might be more elegant ways of telling Inform that 60 seconds is a minute; I’m not sure.
And here’s some sample output:
“An hour and a half” didn’t work but the rest did.
Are you using Variable Time Control perchance? That seems like it’d be pretty useful if you were trying to make every second count.
This is the sort of thing Inform’s value-parsing was designed for. Use “Understand ‘wait [a time period]’ as waiting for.” and the built-in routines will parse “wait one minute”, “wait half an hour”, “wait three hours”, etc.
EDIT: What Matt said.
There is, but I’m not sure it would be appropriate for this situation, and it might be dangerous to manipulate the basic definition of time (which this would). Check out Writing with Inform section 15.10: Scaling and Equivalents. (I can’t link it because the online version of WI is broken? It’s included in the IDE anyway.) With this you MAY be able to write:
1 second specifies a time scaled down by 60.
and now seconds are defined such that “60 seconds” and “1 minute” mean the same thing. However, the underlying representation of a time is changed by this declaration, and I think that will probably cause problems to the normal passage of time (1 minute per turn).
Thanks for the help! The situation I’m facing is that for reasons of the story, the player should in sequence wait for, say 20min, 1m30sec, 0m58s, 23m24s and so forth, and in the end I’ll have to get a figure of how many of these went wrong. I’m wondering if I should just do a quick&dirty and force the player to write the times in a certain format and parse the raw text, but it just feels so inelegant. This does’t have to have anything to do with the turn structure.
I haven’t touched Inform properly in a couple of years and I’m annoyingly rusty, I started with monstrosity like this that obviously doesn’t work since I don’t even remember how to convert text to a number which I could multiply >.<
Carry out waiting for:
if "[topic understood]" is "a minute", now waittime is "60";
if "[topic understood]" matches the regular expression "<0-9>+\s*s(ec)*(onds)*":
now waittime is "[topic understood]";
replace the regular expression "\s*s(ec)*(onds)*" in waittime with "";
if "[topic understood]" matches the regular expression "<0-9>+\s*m(in)*(utes)*":
now waittime is "[topic understood]";
replace the regular expression "\s*m(in)*(utes)*" in waittime with "";
now waittime is waittime times 60;
say "[topic understood] - [waittime]";
I think you should definitely still use the unit structure rather than trying to parse raw text! Imagine how unhappy your player will be if she types “wait for 90 seconds” and she fails the puzzle because she was supposed to type “wait for 1m30s” or something like that.
And if the waiting-for mechanism doesn’t interact with the turn sequence mechanism then you can skip a lot of annoying stuff.
[Ugh, here I noticed that Approximate Metric Units by Graham Nelson has minutes and seconds included, but it’s really pretty useless for our purposes as far as I can tell. I can’t write “1 minute 30 seconds” in the source code, “1 minute” gets glomped by the existing time period value, and for reasons that are completely beyond me I can’t set N to a random variable and then set an elapsed time value to “N seconds.” Plus it has fractional seconds.]
This has annoyed me enough that I don’t want to try something out again, but Writing with Inform 15.14 tells you how you can set up a notation for a value with two numbers in it, so you could write something like “An interval is a kind of value. 3:59 specifies an interval with parts minutes and seconds (optional, preamble optional).”–At the very least, if you do this, you can force the player to write “wait 1:30” and get the results you’re getting now without ugly raw text parsing.
You can construct values with a phrase like “let T be the elapsed time with hours part 0 minutes part 0 seconds part N”. I find it easier to wrap this in a phrase like “to decide what elapsed time is (N - number) seconds:”.
But elapsed time in the Approximate Metric Values extension doesn’t have parts; it scales seconds to minutes (and hours) so that 1 minute is automatically 60 seconds. And then I can’t figure out a way to turn a number variable into an elapsed time.
let T be an elapsed time;
now T is 44 seconds;
But this doesn’t:
let T be an elapsed time;
let N be a number;
now N is 44;
now T is N seconds;
“T is N seconds” throws a “something unrecognised” compiler error.
For these and other reasons I think it’d be better to go with a multipart time and use a phrase like your “(n - number) in seconds” to deal with it. The issue then might be figuring out ways to program in synonyms so the game can understand “wait 90 seconds” and “wait 90s” and “wait 1:30” and “wait 1m30s” and “wait 1m 30 s” and “wait 1 m 30 s” and all that.
This is hacky, but could you multiply N by one second to get a time?