X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=main.c;h=c53660081b3fa5abfc8444c03ce244cb7e76113c;hb=dfff80faa8b5cf4cd286fee2d1ef5eebcdb49829;hp=dca022a5d9657a044e58a2b0b1ad0354ce230d61;hpb=865e10e6d0d15df04ac6209990394277ba1da2a7;p=open-adventure.git diff --git a/main.c b/main.c index dca022a..c536600 100644 --- a/main.c +++ b/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 @@ -97,7 +129,7 @@ int main(int argc, char *argv[]) } } - /* copy inncation line part after switches */ + /* copy invocation line part after switches */ settings.argc = argc - optind; settings.argv = argv + optind; settings.optind = 0; @@ -105,16 +137,28 @@ int main(int argc, char *argv[]) /* Initialize game variables */ int seedval = initialise(); -#ifndef ADVENT_NOSAVE +#if !defined ADVENT_NOSAVE if (!rfp) { - game.novice = yes(arbitrary_messages[WELCOME_YOU], arbitrary_messages[CAVE_NEARBY], arbitrary_messages[NO_MESSAGE]); + 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(arbitrary_messages[WELCOME_YOU], arbitrary_messages[CAVE_NEARBY], arbitrary_messages[NO_MESSAGE]); + game.novice = yes_or_no(arbitrary_messages[WELCOME_YOU], arbitrary_messages[CAVE_NEARBY], arbitrary_messages[NO_MESSAGE]); if (game.novice) game.limit = NOVICELIMIT; #endif @@ -139,43 +183,43 @@ int main(int argc, char *argv[]) char *myreadline(const char *prompt) { /* - * This function isbn't required for gameplay, readline() straight - * up would suffice for tat. It's where we interpret command-line + * This function isn't required for gameplay, readline() straight + * up would suffice for that. It's where we interpret command-line * logfiles for testing purposes. */ /* Normal case - no script arguments */ if (settings.argc == 0) - return readline(prompt); + return readline(prompt); - char *buf = malloc(BUFSIZ); + char *buf = malloc(LINESIZE + 1); for (;;) { - if (settings.scriptfp == NULL || feof(settings.scriptfp)) { - if (settings.optind >= settings.argc) { - free(buf); - return NULL; - } - - char *next = settings.argv[settings.optind++]; - - if (settings.scriptfp != NULL && feof(settings.scriptfp)) - fclose(settings.scriptfp); - if (strcmp(next, "-") == 0) - settings.scriptfp = stdin; // LCOV_EXCL_LINE - else - settings.scriptfp = fopen(next, "r"); - } - - if (isatty(fileno(settings.scriptfp))) { - free(buf); // LCOV_EXCL_LINE - return readline(prompt); // LCOV_EXCL_LINE - } else { - char *ln = fgets(buf, BUFSIZ-1, settings.scriptfp); - if (ln != NULL) { - fputs(PROMPT, stdout); - fputs(ln, stdout); - return ln; - } - } + if (settings.scriptfp == NULL || feof(settings.scriptfp)) { + if (settings.optind >= settings.argc) { + free(buf); + return NULL; + } + + char *next = settings.argv[settings.optind++]; + + if (settings.scriptfp != NULL && feof(settings.scriptfp)) + fclose(settings.scriptfp); + if (strcmp(next, "-") == 0) + settings.scriptfp = stdin; // LCOV_EXCL_LINE + else + settings.scriptfp = fopen(next, "r"); + } + + if (isatty(fileno(settings.scriptfp))) { + free(buf); // LCOV_EXCL_LINE + return readline(prompt); // LCOV_EXCL_LINE + } else { + char *ln = fgets(buf, LINESIZE, settings.scriptfp); + if (ln != NULL) { + fputs(PROMPT, stdout); + fputs(ln, stdout); + return ln; + } + } } return NULL; @@ -255,16 +299,16 @@ static void checkhints(void) game.hintlc[hint] = 0; return; default: // LCOV_EXCL_LINE - // Should never hap[pen + // Should never happen BUG(HINT_NUMBER_EXCEEDS_GOTO_LIST); // LCOV_EXCL_LINE } /* Fall through to hint display */ game.hintlc[hint] = 0; - if (!yes(hints[hint].question, arbitrary_messages[NO_MESSAGE], arbitrary_messages[OK_MAN])) + if (!yes_or_no(hints[hint].question, arbitrary_messages[NO_MESSAGE], arbitrary_messages[OK_MAN])) return; rspeak(HINT_COST, hints[hint].penalty, hints[hint].penalty); - game.hinted[hint] = yes(arbitrary_messages[WANT_HINT], hints[hint].hint, arbitrary_messages[OK_MAN]); + game.hinted[hint] = yes_or_no(arbitrary_messages[WANT_HINT], hints[hint].hint, arbitrary_messages[OK_MAN]); if (game.hinted[hint] && game.limit > WARNTIME) game.limit += WARNTIME * hints[hint].penalty; } @@ -519,14 +563,14 @@ static void croak(void) * death and exit. */ rspeak(DEATH_CLOSING); terminate(endgame); - } else if (!yes(query, yes_response, arbitrary_messages[OK_MAN]) + } else if (!yes_or_no(query, yes_response, arbitrary_messages[OK_MAN]) || game.numdie == NDEATHS) { - /* Player is asked if he wants to try again. If not, or if + /* Player is asked if he wants to try again. If not, or if * he's already used all of his lives, we end the game */ terminate(endgame); } else { - /* If player wishes to continue, we empty the liquids in the - * user's inventory, turn off the lamp, and drop all items + /* If player wishes to continue, we empty the liquids in the + * user's inventory, turn off the lamp, and drop all items * where he died. */ game.place[WATER] = game.place[OIL] = LOC_NOWHERE; if (TOTING(LAMP)) @@ -542,11 +586,11 @@ static void croak(void) } } -static void describe_location(void) +static void describe_location(void) /* Describe the location to the user */ { const char* msg = locations[game.loc].description.small; - + if (MOD(game.abbrev[game.loc], game.abbnum) == 0 || msg == NO_MESSAGE) msg = locations[game.loc].description.big; @@ -559,7 +603,7 @@ static void describe_location(void) rspeak(TAME_BEAR); speak(msg); - + if (game.loc == LOC_Y2 && PCT(25) && !game.closng) rspeak(SAYS_PLUGH); } @@ -656,7 +700,7 @@ static void playermove(int motion) /* Look for a way to fulfil the motion verb passed in - travel_entry indexes * the beginning of the motion entries for here (game.loc). */ for (;;) { - if (T_TERMINATE(travel[travel_entry]) || + if ((travel[travel_entry].motion == HERE) || travel[travel_entry].motion == motion) break; if (travel[travel_entry].stop) { @@ -1047,20 +1091,20 @@ static void listobjects(void) static bool preprocess_command(command_t *command) /* Pre-processes a command input to see if we need to tease out a few specific cases: - * - "enter water" or "enter stream": - * wierd specific case that gets the user wet, and then kicks us back to get another command + * - "enter water" or "enter stream": + * weird specific case that gets the user wet, and then kicks us back to get another command * - : - * Irregular form of input, but should be allowed. We switch back to form for - * furtherprocessing. + * Irregular form of input, but should be allowed. We switch back to form for + * further processing. * - "grate": - * If in location with grate, we move to that grate. If we're in a number of other places, + * If in location with grate, we move to that grate. If we're in a number of other places, * we move to the entrance. * - "water plant", "oil plant", "water door", "oil door": * Change to "pour water" or "pour oil" based on context * - "cage bird": * If bird is present, we change to "carry bird" * - * Returns true if pre-processing is complete, and we're ready to move to the primary command + * Returns true if pre-processing is complete, and we're ready to move to the primary command * processing, false otherwise. */ { if (command->word[0].type == MOTION && command->word[0].id == ENTER @@ -1088,12 +1132,12 @@ static bool preprocess_command(command_t *command) if (game.loc == LOC_COBBLE || game.loc == LOC_DEBRIS || game.loc == LOC_AWKWARD || - game.loc == LOC_BIRD || + game.loc == LOC_BIRDCHAMBER || game.loc == LOC_PITTOP) { command->word[0].id = ENTRANCE; } } - if ((command->word[0].id == WATER || command->word[0].id == OIL) && + if ((command->word[0].id == WATER || command->word[0].id == OIL) && (command->word[1].id == PLANT || command->word[1].id == DOOR)) { if (AT(command->word[1].id)) { command->word[1] = command->word[0]; @@ -1109,16 +1153,16 @@ static bool preprocess_command(command_t *command) } /* If no word type is given for the first word, we assume it's a motion. */ - if(command->word[0].type == NO_WORD_TYPE) + if (command->word[0].type == NO_WORD_TYPE) command->word[0].type = MOTION; - + command->state = PREPROCESSED; return true; } return false; } -static bool do_move(void) +static bool do_move(void) /* Actually execute the move to the new location and dwarf movement */ { /* Can't leave cave once it's closing (except by main office). */ @@ -1180,16 +1224,16 @@ static bool do_command() listobjects(); - /* Command not yet given; keep getting commands from user + /* Command not yet given; keep getting commands from user * until valid command is both given and executed. */ clear_command(&command); while (command.state <= GIVEN) { if (game.closed) { - /* If closing time, check for any objects being toted with - * game.prop < 0 and stash them. This way objects won't be - * described until they've been picked up and put down - * separate from their respective piles. */ + /* If closing time, check for any objects being toted with + * game.prop < 0 and stash them. This way objects won't be + * described until they've been picked up and put down + * separate from their respective piles. */ if (game.prop[OYSTER] < 0 && TOTING(OYSTER)) pspeak(OYSTER, look, true, 1); for (size_t i = 1; i <= NOBJECTS; i++) { @@ -1198,7 +1242,7 @@ static bool do_command() } } - /* Check to see if the room is dark. If the knife is here, + /* Check to see if the room is dark. If the knife is here, * and it's dark, the knife permanently disappears */ game.wzdark = DARK(game.loc); if (game.knfloc != LOC_NOWHERE && game.knfloc != game.loc) @@ -1219,10 +1263,10 @@ static bool do_command() } /* check if game is closed, and exit if it is */ - if (closecheck() ) + if (closecheck() ) return true; - /* loop until all words in command are procesed */ + /* loop until all words in command are processed */ while (command.state == PREPROCESSED ) { command.state = PROCESSING; @@ -1267,7 +1311,7 @@ static bool do_command() } break;// LCOV_EXCL_LINE default: // LCOV_EXCL_LINE - case NO_WORD_TYPE: // LCOV_EXCL_LINE + case NO_WORD_TYPE: // LCOV_EXCL_LINE BUG(VOCABULARY_TYPE_N_OVER_1000_NOT_BETWEEN_0_AND_3); // LCOV_EXCL_LINE } @@ -1313,7 +1357,7 @@ static bool do_command() default: // LCOV_EXCL_LINE BUG(ACTION_RETURNED_PHASE_CODE_BEYOND_END_OF_SWITCH); // LCOV_EXCL_LINE } - } /* while command has nob been fully processed */ + } /* while command has not been fully processed */ } /* while command is not yet given */ } /* while command is not executed */