summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
426684f)
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).
# Makefile for the open-source release of adventure 2.5
# To build with save/resume disabled, pass CFLAGS="-DADVENT_NOSAVE"
# 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)
VERS=$(shell sed -n <NEWS '/^[0-9]/s/:.*//p' | head -1)
extern int score(enum termination);
extern void terminate(enum termination) __attribute__((noreturn));
extern int savefile(FILE *, 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 *);
extern int suspend(void);
extern int resume(void);
extern int restore(FILE *);
#define DIM(a) (sizeof(a)/sizeof(a[0]))
#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)
// LCOV_EXCL_START
// exclude from coverage analysis because it requires interactivity to test
static void sig_handler(int signo)
if (settings.logfp != NULL)
fflush(settings.logfp);
}
if (settings.logfp != NULL)
fflush(settings.logfp);
}
+
+#if defined ADVENT_AUTOSAVE
+ if (signo == SIGHUP || signo == SIGTERM)
+ autosave();
+#endif
exit(EXIT_FAILURE);
}
// LCOV_EXCL_STOP
exit(EXIT_FAILURE);
}
// LCOV_EXCL_STOP
+#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;
const char* opts = "l:or:";
const char* usage = "Usage: %s [-l logfilename] [-o] [-r restorefilename] [script...]\n";
FILE *rfp = NULL;
settings.oldstyle = true;
settings.prompt = false;
break;
settings.oldstyle = true;
settings.prompt = false;
break;
+#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)
case 'r':
rfp = fopen(optarg, "r");
if (rfp == NULL)
" -l create a log file of your game named as specified'\n");
fprintf(stderr,
" -o 'oldstyle' (no prompt, no command editing, displays 'Initialising...')\n");
" -l create a log file of your game named as specified'\n");
fprintf(stderr,
" -o 'oldstyle' (no prompt, no command editing, displays 'Initialising...')\n");
+#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
fprintf(stderr,
" -r restore from specified saved game file\n");
#endif
/* Initialize game variables */
int seedval = initialise();
/* Initialize game variables */
int seedval = initialise();
+#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 (!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)
#else
game.novice = yes_or_no(arbitrary_messages[WELCOME_YOU], arbitrary_messages[CAVE_NEARBY], arbitrary_messages[NO_MESSAGE]);
if (game.novice)
* battles or to start over after learning zzword).
* If ADVENT_NOSAVE is defined, do nothing instead. */
* battles or to start over after learning zzword).
* If ADVENT_NOSAVE is defined, do nothing instead. */
+#if defined ADVENT_NOSAVE || defined ADVENT_AUTOSAVE
return GO_UNKNOWN;
#endif
FILE *fp = NULL;
return GO_UNKNOWN;
#endif
FILE *fp = NULL;
/* Resume. Read a suspended game back from a file.
* If ADVENT_NOSAVE is defined, do nothing instead. */
/* Resume. Read a suspended game back from a file.
* If ADVENT_NOSAVE is defined, do nothing instead. */
+#if defined ADVENT_NOSAVE || defined ADVENT_AUTOSAVE
return GO_UNKNOWN;
#endif
FILE *fp = NULL;
return GO_UNKNOWN;
#endif
FILE *fp = NULL;
/* End of game. Let's tell him all about it. */
{
int points = score(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);
if (points + game.trnluz + 1 >= mxscor && game.trnluz != 0)
rspeak(TOOK_LONG);