Add optional auto-save/restore feature using -a <filename> option
To enable use with online Bulletin Board Systems (BBSes) where users may be disconnected unexpectedly, but would naturally want to resume playing their same game, added support for an optional save game path/filename to be specified on the command-line (very similar to "-r <filename>"), except this save/restore file is: 1. automatically loaded/restored if it exists 2. automatically created when starting a new game 3. automatically updated when exiting a game for any reason 4. cannot be changed to a different path/filename by the user Since a BBS server program can be expected to send a SIGHUP or SIGTERM to the game process upon user disconnection (or timeout), those signals are caught and a graceful termination will occur which saves the current game state. Build with ADVENT_AUTOSAVE defined to enable this option. BUG: The 'info' command still reports the save/suspend/pause commands as valid, though they are not when this build option is used (same is true of ADVENT_NOSAVE, and that doesn't apparently bother anyone).
This commit is contained in:
parent
426684fec2
commit
dfff80faa8
5 changed files with 57 additions and 6 deletions
1
Makefile
1
Makefile
|
@ -1,6 +1,7 @@
|
|||
# Makefile for the open-source release of adventure 2.5
|
||||
|
||||
# To build with save/resume disabled, pass CFLAGS="-DADVENT_NOSAVE"
|
||||
# To build with auto-save/resume enabled, pass CFLAGS="-D ADVENT_AUTOSAVE"
|
||||
|
||||
VERS=$(shell sed -n <NEWS '/^[0-9]/s/:.*//p' | head -1)
|
||||
|
||||
|
|
3
advent.h
3
advent.h
|
@ -244,6 +244,9 @@ extern int32_t randrange(int32_t);
|
|||
extern int score(enum termination);
|
||||
extern void terminate(enum termination) __attribute__((noreturn));
|
||||
extern int savefile(FILE *, int32_t);
|
||||
#if defined ADVENT_AUTOSAVE
|
||||
extern void autosave(void);
|
||||
#endif
|
||||
extern int suspend(void);
|
||||
extern int resume(void);
|
||||
extern int restore(FILE *);
|
||||
|
|
52
main.c
52
main.c
|
@ -18,6 +18,18 @@
|
|||
|
||||
#define DIM(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
#if defined ADVENT_AUTOSAVE
|
||||
static FILE* autosave_fp;
|
||||
void autosave(void)
|
||||
{
|
||||
if (autosave_fp != NULL) {
|
||||
rewind(autosave_fp);
|
||||
savefile(autosave_fp, /* version (auto): */0);
|
||||
fflush(autosave_fp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// LCOV_EXCL_START
|
||||
// exclude from coverage analysis because it requires interactivity to test
|
||||
static void sig_handler(int signo)
|
||||
|
@ -26,6 +38,11 @@ static void sig_handler(int signo)
|
|||
if (settings.logfp != NULL)
|
||||
fflush(settings.logfp);
|
||||
}
|
||||
|
||||
#if defined ADVENT_AUTOSAVE
|
||||
if (signo == SIGHUP || signo == SIGTERM)
|
||||
autosave();
|
||||
#endif
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
@ -50,7 +67,12 @@ int main(int argc, char *argv[])
|
|||
|
||||
/* Options. */
|
||||
|
||||
#ifndef ADVENT_NOSAVE
|
||||
#if defined ADVENT_AUTOSAVE
|
||||
const char* opts = "l:oa:";
|
||||
const char* usage = "Usage: %s [-l logfilename] [-o] [-a filename] [script...]\n";
|
||||
FILE *rfp = NULL;
|
||||
const char* autosave_filename = NULL;
|
||||
#elif !defined ADVENT_NOSAVE
|
||||
const char* opts = "l:or:";
|
||||
const char* usage = "Usage: %s [-l logfilename] [-o] [-r restorefilename] [script...]\n";
|
||||
FILE *rfp = NULL;
|
||||
|
@ -72,7 +94,14 @@ int main(int argc, char *argv[])
|
|||
settings.oldstyle = true;
|
||||
settings.prompt = false;
|
||||
break;
|
||||
#ifndef ADVENT_NOSAVE
|
||||
#ifdef ADVENT_AUTOSAVE
|
||||
case 'a':
|
||||
rfp = fopen(optarg, READ_MODE);
|
||||
autosave_filename = optarg;
|
||||
signal(SIGHUP, sig_handler);
|
||||
signal(SIGTERM, sig_handler);
|
||||
break;
|
||||
#elif !defined ADVENT_NOSAVE
|
||||
case 'r':
|
||||
rfp = fopen(optarg, "r");
|
||||
if (rfp == NULL)
|
||||
|
@ -88,7 +117,10 @@ int main(int argc, char *argv[])
|
|||
" -l create a log file of your game named as specified'\n");
|
||||
fprintf(stderr,
|
||||
" -o 'oldstyle' (no prompt, no command editing, displays 'Initialising...')\n");
|
||||
#ifndef ADVENT_NOSAVE
|
||||
#if defined ADVENT_AUTOSAVE
|
||||
fprintf(stderr,
|
||||
" -a automatic save/restore from specified saved game file\n");
|
||||
#elif !defined ADVENT_NOSAVE
|
||||
fprintf(stderr,
|
||||
" -r restore from specified saved game file\n");
|
||||
#endif
|
||||
|
@ -105,14 +137,26 @@ int main(int argc, char *argv[])
|
|||
/* Initialize game variables */
|
||||
int seedval = initialise();
|
||||
|
||||
#ifndef ADVENT_NOSAVE
|
||||
#if !defined ADVENT_NOSAVE
|
||||
if (!rfp) {
|
||||
game.novice = yes_or_no(arbitrary_messages[WELCOME_YOU], arbitrary_messages[CAVE_NEARBY], arbitrary_messages[NO_MESSAGE]);
|
||||
if (game.novice)
|
||||
game.limit = NOVICELIMIT;
|
||||
} else {
|
||||
restore(rfp);
|
||||
#if defined ADVENT_AUTOSAVE
|
||||
score(scoregame);
|
||||
#endif
|
||||
}
|
||||
#if defined ADVENT_AUTOSAVE
|
||||
if (autosave_filename != NULL) {
|
||||
if ((autosave_fp = fopen(autosave_filename, WRITE_MODE)) == NULL) {
|
||||
perror(autosave_filename);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
autosave();
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
game.novice = yes_or_no(arbitrary_messages[WELCOME_YOU], arbitrary_messages[CAVE_NEARBY], arbitrary_messages[NO_MESSAGE]);
|
||||
if (game.novice)
|
||||
|
|
|
@ -62,7 +62,7 @@ int suspend(void)
|
|||
* battles or to start over after learning zzword).
|
||||
* If ADVENT_NOSAVE is defined, do nothing instead. */
|
||||
|
||||
#ifdef ADVENT_NOSAVE
|
||||
#if defined ADVENT_NOSAVE || defined ADVENT_AUTOSAVE
|
||||
return GO_UNKNOWN;
|
||||
#endif
|
||||
FILE *fp = NULL;
|
||||
|
@ -93,7 +93,7 @@ int resume(void)
|
|||
/* Resume. Read a suspended game back from a file.
|
||||
* If ADVENT_NOSAVE is defined, do nothing instead. */
|
||||
|
||||
#ifdef ADVENT_NOSAVE
|
||||
#if defined ADVENT_NOSAVE || defined ADVENT_AUTOSAVE
|
||||
return GO_UNKNOWN;
|
||||
#endif
|
||||
FILE *fp = NULL;
|
||||
|
|
3
score.c
3
score.c
|
@ -117,6 +117,9 @@ void terminate(enum termination mode)
|
|||
/* End of game. Let's tell him all about it. */
|
||||
{
|
||||
int points = score(mode);
|
||||
#if defined ADVENT_AUTOSAVE
|
||||
autosave();
|
||||
#endif
|
||||
|
||||
if (points + game.trnluz + 1 >= mxscor && game.trnluz != 0)
|
||||
rspeak(TOOK_LONG);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue