enum nh_restore_status nh_restore_game(int fd, struct nh_window_procs *rwinprocs, boolean force_replay) { int playmode, irole, irace, igend, ialign; char namebuf[PL_NSIZ]; /* some compilers can't cope with the fact that all subsequent stores to error * are not dead, but become important if the error handler longjumps back * volatile is required to prevent invalid optimization based on that wrong * assumption. */ volatile enum nh_restore_status error = GAME_RESTORED; if (fd == -1) return ERR_BAD_ARGS; switch (nh_get_savegame_status(fd, NULL)) { case LS_INVALID: return ERR_BAD_FILE; case LS_DONE: return ERR_GAME_OVER; case LS_CRASHED: force_replay = TRUE; break; case LS_IN_PROGRESS: return ERR_IN_PROGRESS; case LS_SAVED: break; /* default, everything is A-OK */ } if (!api_entry_checkpoint()) goto error_out; error = ERR_BAD_FILE; replay_set_logfile(fd); /* store the fd and try to get a lock or exit */ replay_begin(); program_state.restoring = TRUE; iflags.disable_log = TRUE; /* don't log any of the commands, they're already in the log */ /* Read the log header for this game. */ replay_read_newgame(&turntime, &playmode, namebuf, &irole, &irace, &igend, &ialign); /* set special windowprocs which will autofill requests for user input * with data from the log file */ replay_setup_windowprocs(rwinprocs); startup_common(namebuf, playmode); u.initrole = irole; u.initrace = irace; u.initgend = igend; u.initalign = ialign; if (!force_replay) { error = ERR_RESTORE_FAILED; replay_run_cmdloop(TRUE, FALSE, TRUE); replay_jump_to_endpos(); if (!dorecover_fd(fd)) { replay_undo_jump_to_endpos(); goto error_out2; } replay_undo_jump_to_endpos(); wd_message(); program_state.game_running = 1; post_init_tasks(); } else { replay_run_cmdloop(TRUE, TRUE, FALSE); /* option setup only */ newgame(); /* try replaying instead */ error = ERR_REPLAY_FAILED; replay_run_cmdloop(FALSE, FALSE, TRUE); replay_sync_save(); } /* restore standard window procs */ replay_restore_windowprocs(); program_state.restoring = FALSE; iflags.disable_log = FALSE; /* clean up data used for replay */ replay_end(); log_truncate(); log_init(); /* must be called before we start writing to the log */ /* info might not have reached the ui while alternate window procs were set */ doredraw(); /* nh_start_game() does this via newgame(), but since this function doesn't * call newgame(), we have to do it here instead. */ notify_levelchange(NULL); bot(); flush_screen(); was_on_elbereth = !sengr_at("Elbereth", u.ux, u.uy); /* force botl update later */ welcome(FALSE); realtime_messages(TRUE, TRUE); update_inventory(); api_exit(); return GAME_RESTORED; error_out2: api_exit(); error_out: replay_restore_windowprocs(); program_state.restoring = FALSE; iflags.disable_log = FALSE; replay_end(); unlock_fd(fd); if (error == ERR_RESTORE_FAILED) { raw_printf("Restore failed. Attempting to replay instead.\n"); error = nh_restore_game(fd, rwinprocs, TRUE); } return error; }
static void newgame(void) { int i; flags.ident = 1; for (i = 0; i < NUMMONS; i++) mvitals[i].mvflags = mons[i].geno & G_NOCORPSE; init_objects(); /* must be before u_init() */ flags.pantheon = -1;/* role_init() will reset this */ role_init(); /* must be before init_dungeons(), u_init(), * and init_artifacts() */ init_dungeons(); /* must be before u_init() to avoid rndmonst() * creating odd monsters for any tins and eggs * in hero's initial inventory */ init_artifacts(); u_init(); /* struct you must have some basic data for mklev to work right */ load_qtlist(); /* load up the quest text info */ level = mklev(&u.uz); u_init_inv_skills();/* level must be valid to create items */ u_on_upstairs(); vision_reset(); /* set up internals for level (after mklev) */ check_special_room(FALSE); iflags.botl = 1; /* Move the monster from under you or else * makedog() will fail when it calls makemon(). * - ucsfcgl!kneller */ if (MON_AT(level, u.ux, u.uy)) mnexto(m_at(level, u.ux, u.uy)); makedog(); doredraw(); if (Role_if(PM_CONVICT)) { setworn(mkobj(level, CHAIN_CLASS, TRUE), W_CHAIN); setworn(mkobj(level, BALL_CLASS, TRUE), W_BALL); uball->spe = 1; /* attach the ball to the hero */ placebc(); } /* help the window port get it's display charset/tiles sorted out */ notify_levelchange(NULL); if (flags.legacy) { flush_screen(); com_pager(Role_if(PM_CONVICT) ? 199 : 1); } /* Stop autoexplore revisiting the entrance stairs (or position). */ level->locations[u.ux][u.uy].mem_stepped = 1; program_state.something_worth_saving++; /* useful data now exists */ historic_event(FALSE, "entered the Dungeons of Doom to retrieve the Amulet of Yendor!"); /* Success! */ welcome(TRUE); maybe_tutorial(); /* Prepare for the first move. */ flags.move = 0; set_wear(); pickup(1); log_command_result(); program_state.game_running = TRUE; youmonst.movement = NORMAL_SPEED; /* give the hero some movement points */ realtime_tasks(); post_init_tasks(); return; }