Comparing the real date post-restore

My goal is to print a reminder message after the player restores their game after a long period of (real) time has passed.

In my search for something that can mark the real date, month, and year I found Ron Newcomb’s extension “Real Date and Time” in the Inform 7 library.

I’m trying to store values when the player saves. I’ll then compare values when they restore the file. I haven’t gotten to the comparison part as I’m unsuccessful using the below to store those values.

Include Real Date and Time by Ron Newcomb.

The save the game rule response (B) is "[italic type]Ok, game saved.[paragraph break][SaveGameMessage][roman type]".

The restore the game rule response (B) is "[italic type]Ok.[paragraph break][RestoreGameMessage][roman type]".

The Laboratory is a room. "There are many scientific instruments here.".

SaveGameMonth is a month that varies.
SaveGameDay is a number that varies.
SaveGameYear is a number that varies.

To say SaveGameMessage:
	if the player's time is available:
		say "[the player's month], [the player's day], [the player's year]";
		now SaveGameMonth is the player's month;
		now SaveGameDay is the player's day;
		now SaveGameYear is the player's year;	

To say RestoreGameMessage:
	say "[SaveGameMonth], [SaveGameDay], [SaveGameYear]";

Is “to say” an appropriate way to save the values via the response? How can I get the three values to store the data from the extension in that SaveGameMessage? Right now they’re not storing that data. Is this extension the best way to approach this?

1 Like

The contents of the global variables that you set up to hold these should be saved as part of the save game data. I think the issue is that the point at which you are saving them is too late, i.e. after the save occurs.

The actual save happens when the save the game rule is followed. This rule is in the carry out saving the game rules.

You can move the code to set the globals to a rule in the same rulebook:

First carry out saving the game (this is the store date data when saving rule):
	now SaveGameMonth is the player's month;
	now SaveGameDay is the player's day;
	now SaveGameYear is the player's year;
4 Likes

Doing the comparison has been more tricky than I realized as the date values (Month, Day, Year) stored by the extension are independent and have no relation to each other. As in, there’s no easy way to compare a date like December 15, 2021 to January 26, 2022. Crossing years like that is especially tricky.

Best I can figure is to assign a value to the day based on where it falls within the 365-day calendar. Assign a value to the save game file’s day and then assign a value to “today’s” day, the date the player restores the file. Then, compare the distance between them. Since the intent of this is to display a message to the player when they’re been away from the game for a while (reminding them of available verbs, hint system, etc) I figure after a certain length of time we can stop worrying about being specific: the player hasn’t played in a long time, whether that’s six months or six years.

I’m too much of a coward to go messing with my laptop’s system clock not having done it before, but maybe tonight I can dig out my old laptop. This is what I’ve got so far:

Include Real Date and Time by Ron Newcomb.

The save the game rule response (B) is "[italic type]Ok, game saved.[roman type]".

The restore the game rule response (B) is "[italic type]Restored.[line break][RestoreGameMessage][roman type]".

First carry out saving the game (this is the store date data when saving rule):
	if the player's time is available:
		now SaveGameMonth is the player's month;
		now SaveGameDay is the player's day;
		now SaveGameYear is the player's year;
		now BaseSavedDay is 0;
		now BaseTodayDay is 0;
		now TotalDaysPassed is 0;

The Laboratory is a room. "There are many scientific instruments here.".

[core saved values updated upon save]
SaveGameMonth is a month that varies.
SaveGameDay is a number that varies.
SaveGameYear is a number that varies.

BaseSavedDay is a number that varies. [Sets the number of days that have occurred in the year up until that month. Then, we'll add the GameSaveDay to it. e.g. February 5 is 31 + 5 = 36; 31 days in January and then 5 days into February. This is for the save file.]

BaseTodayDay is a number that varies. [We do the same with this variable. This is for the date "today" when the player has restored the game file. Now, we're able to compare the two variables and calculate the difference between them.]

TotalDaysPassed is a number that varies. [When we compare the two Base variables (subtract BaseTodayDay by BaseSavedDay) we store the resulting number here.]

TotalYearsPassed is a number that varies. [Things get screwy if the player goes a very long time between saving and restoring. So, it's necessary to separate out if/thens based on how many years have gone by.]

To say RestoreGameMessage:
	if the player's time is available:
		if SaveGameYear is the player's year: [the save file is the same year as the restore date]
			if the SaveGameMonth is January, now BaseSavedDay is 0; [giving the two variables a base value]
			if the player's month is January, now BaseTodayDay is 0;
			if the SaveGameMonth is February, now BaseSavedDay is 31;
			if the player's month is February, now BaseTodayDay is 31;
			if the SaveGameMonth is March, now BaseSavedDay is 59;
			if the player's month is March, now BaseTodayDay is 59;
			if the SaveGameMonth is April, now BaseSavedDay is 90;
			if the player's month is April, now BaseTodayDay is 90;
			if the SaveGameMonth is May, now BaseSavedDay is 120;
			if the player's month is May, now BaseTodayDay is 120;
			if the SaveGameMonth is June, now BaseSavedDay is 151;
			if the player's month is June, now BaseTodayDay is 151;
			if the SaveGameMonth is July, now BaseSavedDay is 181;
			if the player's month is July, now BaseTodayDay is 181;
			if the SaveGameMonth is August, now BaseSavedDay is 212;
			if the player's month is August, now BaseTodayDay is 212;
			if the SaveGameMonth is September, now BaseSavedDay is 243;
			if the player's month is September, now BaseTodayDay is 243;
			if the SaveGameMonth is October, now BaseSavedDay is 273;
			if the player's month is October, now BaseTodayDay is 273;
			if the SaveGameMonth is November, now BaseSavedDay is 304;
			if the player's month is November, now BaseTodayDay is 304;
			if the SaveGameMonth is December, now BaseSavedDay is 334;
			if the player's month is December, now BaseTodayDay is 334;
			increase BaseSavedDay by SaveGameDay; [adding the day of the actual month to give the two variables their true "rank"]
			increase BaseTodayDay by the player's day;
			let TotalDaysPassed be BaseTodayDay minus BaseSavedDay; [the distance between the two values is stored here]
			if TotalDaysPassed < 7 and TotalDaysPassed > 0:
				say "Less than a week has passed ([TotalDaysPassed] days; [SaveGameMonth] [SaveGameDay], [SaveGameYear]) since the creation of this save file.";
			otherwise if TotalDaysPassed is 0:
				say "Your last save was today.";
			otherwise if TotalDaysPassed >= 7 and TotalDaysPassed < 32:
				say "Over a week ([TotalDaysPassed] days; [SaveGameMonth] [SaveGameDay], [SaveGameYear]) has passed since this save file was created.";
			otherwise if TotalDaysPassed >= 32:
				say "Over a month ([TotalDaysPassed] days; [SaveGameMonth] [SaveGameDay], [SaveGameYear]) has passed since this save file was created."; [You could keep going with various messages and measurements (3 months, six months, etc) but this felt like more than enough.] 
		otherwise if SaveGameYear < the player's year:
			let TotalYearsPassed be the player's year minus SaveGameYear;
			if TotalYearsPassed > 1: [You could add in multiple different messages exclaiming how many years have past since the save file, but "more than 1" seems sufficient. Also, only accounts for the year, the number, changing and not partial years having passed. e.g. January 1, 2023 to December 31, 2024 is counted as one year difference even though common sense says two]
				say "More than a year has passed since this save file was created. ([SaveGameMonth] [SaveGameDay], [SaveGameYear])";
			otherwise if TotalYearsPassed is 1 and the SaveGameMonth is December and the player's month is January:
				increase BaseSavedDay by SaveGameDay; [similar logic to the first section above, but shrinking things down to just look at the passage of time between December and January. BaseSavedDay starts at 0 and then is increased depending on the number of days into December. BaseTodayDay starts at 31 since December is over, and then adds the number of January days that have passed]
				now BaseTodayDay is 31;
				increase BaseTodayDay by the player's day;
				let TotalDaysPassed be BaseTodayDay minus BaseSavedDay;
				if TotalDaysPassed < 7 and TotalDaysPassed > 0:
					say "Less than a week ([TotalDaysPassed] days; [SaveGameMonth] [SaveGameDay], [SaveGameYear]) has passed since the creation of this save file.";
				otherwise if TotalDaysPassed >= 7:
					say "Over a week ([TotalDaysPassed] days; [SaveGameMonth] [SaveGameDay], [SaveGameYear]) has passed since this save file was created.";
			otherwise if TotalYearsPassed is 1 and the SaveGameMonth is December and the player's month is not January:
				say "Over a month ([TotalDaysPassed] days; [SaveGameMonth] [SaveGameDay], [SaveGameYear]) has passed since this save file was created.";  [this is a little bit of a shortcut as you'd have to copy all the crazy month math we do in first section above, but then throw on December's days. I figure it's not worth it.]
			otherwise if TotalYearsPassed is 1 and the SaveGameMonth is not December:
				say "Over a month ([TotalDaysPassed] days; [SaveGameMonth] [SaveGameDay], [SaveGameYear]) has passed since this save file was created."; [Ditto here.]

I don’t know if the extension you’re using gives you convenient access to it, but Glk can also give you the system time as number of seconds since 1970 (“Unix time”), possibly scaled by some factor to stave off the Year 2038 problem. Computing elapsed time between two timestamps is much easier in that format since you don’t need to juggle calendar dates or worry about daylight savings time changes.

2 Likes

I don’t think the Inform extensions supply that value, but it wouldn’t be hard to extend them to. If you post the extensions you’re using, I can add the I6 code for the extra Glk call.

Ya’ll mean using “Real Date and Time by Ron Newcomb.” as the base?

I didn’t know which particular extension you were using, but yep, it works with that one!

For that one it’s actually very easy:

To decide what number is the current timestamp in seconds: (- (countofseconds-->1) -).

That extension stores the current time in a three-word array called countofseconds, which it then converts into whatever other format you request. The first word is the high 32 bits of the second count, the second word is the low 32 bits of the second count, and the third word is the microseconds. So this snippet of code just gives you the low 32 bits. This will be fine until 6:28 AM on February 7, 2106; if you want to keep using this code after that point, you’ll need to make a couple changes.

(Actually it’ll be fine after that date too. It just won’t be fine across that date. That’s when you’ll need to think about the high bits. It’ll also be a problem if you go across 12:00 AM on January 1, 1970.)

EDIT: Wait, no, Inform does signed comparison of integers. So it’ll be a problem in 2038, not 2106. Oh well.