示例#1
0
void
replay(void)
{
    char buf[BUFSZ];
    fnchar logdir[BUFSZ], savedir[BUFSZ], filename[1024], *dir, **files;
    struct nh_menuitem *items;
    int i, n, fd, icount, size, filecount, pick[1];
    enum nh_log_status status;
    struct nh_game_info gi;

    if (!get_gamedir(LOG_DIR, logdir))
        logdir[0] = '\0';
    if (!get_gamedir(SAVE_DIR, savedir))
        savedir[0] = '\0';

    if (*logdir)
        dir = logdir;
    else if (*savedir)
        dir = savedir;
    else {
        curses_msgwin("There are no games to replay.");
        return;
    }

    while (1) {
        filename[0] = '\0';
        files = list_gamefiles(dir, &filecount);
        /* make sure there are some files to show */
        if (!filecount) {
            if (dir == savedir) {
                curses_msgwin("There are no saved games to replay.");
                savedir[0] = '\0';
            } else {
                curses_msgwin("There are no completed games to replay.");
                logdir[0] = '\0';
            }

            dir = (dir == savedir) ? logdir : savedir;
            if (!*dir)
                return;
            continue;
        }

        icount = 0;
        size = filecount + 2;
        items = malloc(size * sizeof (struct nh_menuitem));

        /* add all the files to the menu */
        for (i = 0; i < filecount; i++) {
            fd = sys_open(files[i], O_RDWR, 0660);
            status = nh_get_savegame_status(fd, &gi);
            close(fd);

            describe_game(buf, status, &gi);
            add_menu_item(items, size, icount,
                          (status == LS_IN_PROGRESS) ? 0 : icount + 1, buf, 0,
                          FALSE);
        }

        if (dir == logdir && *savedir) {
            add_menu_txt(items, size, icount, "", MI_NORMAL);
            add_menu_item(items, size, icount, -1, "View saved games instead",
                          '!', FALSE);
        } else if (dir == savedir && *logdir) {
            add_menu_txt(items, size, icount, "", MI_NORMAL);
            add_menu_item(items, size, icount, -1, "View saved games instead",
                          '!', FALSE);
        }

        n = curses_display_menu(items, icount, "Pick a game to view", PICK_ONE,
                                PLHINT_ANYWHERE, pick);
        free(items);
        filename[0] = '\0';
        if (n > 0 && pick[0] != -1)
            fnncat(filename, files[pick[0] - 1],
                   sizeof (filename) / sizeof (fnchar) - 1);

        for (i = 0; i < filecount; i++)
            free(files[i]);
        free(files);

        if (n <= 0)
            return;

        if (pick[0] == -1) {
            dir = (dir == savedir) ? logdir : savedir;
            continue;
        }

        /* we have a valid filename */
        break;
    }

    fd = sys_open(filename, O_RDWR, 0660);
    replay_commandloop(fd);
    close(fd);
}
示例#2
0
nh_bool loadgame(void)
{
    char buf[BUFSZ];
    fnchar savedir[BUFSZ], filename[1024], **files;
    struct nh_menuitem *items;
    int size, icount, fd, i, n, ret, pick[1];
    enum nh_log_status status;
    struct nh_game_info gi;

    if (!get_gamedir(SAVE_DIR, savedir)) {
        curses_raw_print("Could not find or create the save directory.");
        return FALSE;
    }

    files = list_gamefiles(savedir, &size);
    if (!size) {
        curses_msgwin("No saved games found.");
        return FALSE;
    }

    icount = 0;
    items = malloc(size * sizeof(struct nh_menuitem));

    for (i = 0; i < size; i++) {
        fd = sys_open(files[i], O_RDWR, FILE_OPEN_MASK);
        status = nh_get_savegame_status(fd, &gi);
        close(fd);

        describe_game(buf, status, &gi);
        add_menu_item(items, size, icount, (status == LS_IN_PROGRESS) ? 0 : icount + 1,
                      buf, 0, FALSE);
    }

    n = curses_display_menu(items, icount, "saved games", PICK_ONE, pick);
    free(items);
    filename[0] = '\0';
    if (n > 0)
        fnncat(filename, files[pick[0]-1], sizeof(filename)/sizeof(fnchar)-1);

    for (i = 0; i < icount; i++)
        free(files[i]);
    free(files);
    if (n <= 0)
        return FALSE;

    fd = sys_open(filename, O_RDWR, FILE_OPEN_MASK);
    create_game_windows();
    if (nh_restore_game(fd, NULL, FALSE) != GAME_RESTORED) {
        destroy_game_windows();
        close(fd);
        if (curses_yn_function("Failed to load the save. Do you wish to delete the file?", "yn", 'n') == 'y')
            unlink(filename);
        return FALSE;
    }

    load_keymap(); /* need to load the keymap after the game has been started */
    ret = commandloop();
    free_keymap();
    close(fd);

    destroy_game_windows();
    cleanup_messages();
    game_ended(ret, filename);

    return TRUE;
}
示例#3
0
static void
ccmd_list_games(json_t * params)
{
    char filename[1024];
    int completed, limit, show_all, count, i, fd;
    struct gamefile_info *files;
    enum nh_log_status status;
    struct nh_game_info gi;
    json_t *jarr, *jobj;

    if (json_unpack
        (params, "{si,si*}", "completed", &completed, "limit", &limit) == -1)
        exit_client("Bad parameters for list_games");
    if (json_unpack(params, "{si*}", "show_all", &show_all) == -1)
        show_all = 0;

    /* step 1: get a list of files from the db. */
    files =
        db_list_games(completed, show_all ? 0 : user_info.uid, limit, &count);

    jarr = json_array();
    /* step 2: get extra info for each file. */
    for (i = 0; i < count; i++) {
        if (completed)
            snprintf(filename, 1024, "%s/completed/%s", settings.workdir,
                     files[i].filename);
        else
            snprintf(filename, 1024, "%s/save/%s/%s", settings.workdir,
                     user_info.username, files[i].filename);
        fd = open(filename, O_RDWR);
        if (fd == -1) {
            log_msg("Game file %s could not be opened in ccmd_list_games.",
                    files[i].filename);
            continue;
        }

        status = nh_get_savegame_status(fd, &gi);
        jobj =
            json_pack("{si,si,si,ss,ss,ss,ss,ss}", "gameid", files[i].gid,
                      "status", status, "playmode", gi.playmode, "plname",
                      gi.name, "plrole", gi.plrole, "plrace", gi.plrace,
                      "plgend", gi.plgend, "plalign", gi.plalign);
        if (status == LS_SAVED) {
            json_object_set_new(jobj, "level_desc", json_string(gi.level_desc));
            json_object_set_new(jobj, "moves", json_integer(gi.moves));
            json_object_set_new(jobj, "depth", json_integer(gi.depth));
            json_object_set_new(jobj, "has_amulet",
                                json_integer(gi.has_amulet));
        } else if (status == LS_DONE) {
            json_object_set_new(jobj, "death", json_string(gi.death));
            json_object_set_new(jobj, "moves", json_integer(gi.moves));
            json_object_set_new(jobj, "depth", json_integer(gi.depth));
        }
        json_array_append_new(jarr, jobj);

        free((void *)files[i].username);
        free((void *)files[i].filename);

        close(fd);
    }
    free(files);

    client_msg("list_games", json_pack("{so}", "games", jarr));
}
示例#4
0
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;
}