示例#1
0
文件: pager.c 项目: DanielT/NitroHack
void nh_describe_pos(int x, int y, struct nh_desc_buf *bufs)
{
    int monid = dbuf_get_mon(x, y);
    
    bufs->bgdesc[0] = '\0';
    bufs->trapdesc[0] = '\0';
    bufs->objdesc[0] = '\0';
    bufs->mondesc[0] = '\0';
    bufs->invisdesc[0] = '\0';
    bufs->effectdesc[0] = '\0';
    bufs->objcount = -1;
    
    if (!program_state.game_running || !api_entry_checkpoint())
	return;
    
    describe_bg(x, y, level->locations[x][y].mem_bg, bufs->bgdesc);
    
    if (level->locations[x][y].mem_trap)
	strcpy(bufs->trapdesc, trapexplain[level->locations[x][y].mem_trap - 1]);
    
    bufs->objcount = describe_object(x, y, level->locations[x][y].mem_obj - 1,
				     bufs->objdesc);
    
    describe_mon(x, y, monid - 1, bufs->mondesc);
    
    if (level->locations[x][y].mem_invis)
	strcpy(bufs->invisdesc, invisexplain);
    
    if (u.uswallow && (x != u.ux || y != u.uy)) {
	/* all locations when swallowed other than the hero are the monster */
	sprintf(bufs->effectdesc, "interior of %s", Blind ? "a monster" : a_monnam(u.ustuck));
    }
    
    api_exit();
}
示例#2
0
boolean nh_exit_game(int exit_type)
{
    boolean log_disabled = iflags.disable_log;
    
    if (!api_entry_checkpoint()) { /* not sure anything in here can actually call panic */
	iflags.disable_log = log_disabled;
	return TRUE; /* terminate was called, so exit is successful */
    }
    
    program_state.forced_exit = TRUE;
    
    /* clean up after viewing a game replay */
    if (program_state.viewing)
	nh_view_replay_finish();
	
    xmalloc_cleanup();
    iflags.disable_log = TRUE;
    if (program_state.game_running) {
	switch (exit_type) {
	    case EXIT_REQUEST_SAVE:
		dosave(); /* will ask "really save?" and, if 'y', eventually call terminate. */
		break;
		
	    case EXIT_FORCE_SAVE:
		dosave0(TRUE);
		terminate();
		break;
		
	    case EXIT_REQUEST_QUIT:
		done2();
		break;
		    
	    case EXIT_FORCE_QUIT:
		done(QUIT);
		break; /* not reached */
		
	    case EXIT_PANIC:
		/* freeing things should be safe */
		freedynamicdata();
		dlb_cleanup();
		panic("UI problem.");
		break;
	}
	
	iflags.disable_log = log_disabled;
	api_exit();
	return FALSE;
    }
    
    iflags.disable_log = log_disabled;
    /* calling terminate() will get us out of nested contexts safely, eg:
     * UI_cmdloop -> nh_command -> UI_update_screen (problem happens here) -> nh_exit_game
     * will jump all the way back to UI_cmdloop */
    terminate();
    
    api_exit(); /* not reached */
    return TRUE;
}
示例#3
0
boolean nh_set_option(const char *name, union nh_optvalue value, boolean isstring)
{
	boolean rv;
	
	if (!api_entry_checkpoint())
	    return FALSE;
	
	rv = set_option(name, value, isstring);
	
	api_exit();
	return rv;
}
示例#4
0
void nh_lib_init(const struct nh_window_procs *procs, char **paths)
{
    int i;
            
    if (!api_entry_checkpoint()) /* not sure anything in here can actually call panic */
	return;
    
    windowprocs = *procs;
    
    for (i = 0; i < PREFIX_COUNT; i++)
	fqn_prefix[i] = strdup(paths[i]);
    
    u.uhp = 1;	/* prevent RIP on early quits */
    init_opt_struct();
    turntime = 0;
    
    current_timezone = get_tz_offset();
    
    api_exit();
}
示例#5
0
boolean nh_start_game(int fd, const char *name, int irole, int irace, int igend,
		      int ialign, enum nh_game_modes playmode)
{
    unsigned int seed = 0;
    
    if (!api_entry_checkpoint())
	return FALSE; /* init failed; programmer error! */

    if (fd == -1 || !name || !*name)
	goto err_out;
    
    if (!program_state.restoring) {
	turntime = (unsigned long long)time(NULL);
	seed = turntime ^ get_seedval();
	/* initialize the random number generator */
	mt_srand(seed);
    } /* else: turntime and rng seeding are done in logreplay.c */
    
    startup_common(name, playmode);
    
    if (!validrole(irole) || !validrace(irole, irace) ||
	!validgend(irole, irace, igend) || !validalign(irole, irace, ialign))
	goto err_out;
    u.initrole = irole; u.initrace = irace;
    u.initgend = igend; u.initalign = ialign;

    /* write out a new logfile header "NHGAME ..." with all the initial details */
    log_init();
    log_newgame(fd, turntime, seed, playmode);

    newgame();
    was_on_elbereth = !sengr_at("Elbereth", u.ux, u.uy); /* force botl update later */
    wd_message();

    api_exit();
    return TRUE;
    
err_out:
    api_exit();
    return FALSE;
}
示例#6
0
struct nh_topten_entry *
nh_get_topten(int *out_len, char *statusbuf,
              const char * volatile player, int top,
              int around, boolean own)
{
    struct toptenentry *ttlist, newtt;
    struct nh_topten_entry *score_list;
    boolean game_inited = (wiz1_level.dlevel != 0);
    boolean game_complete = game_inited && moves && program_state.gameover;
    int rank = -1;      /* index of the completed game in the topten list */
    int fd, i, j, sel_count;
    boolean *selected, off_list = FALSE;

    statusbuf[0] = '\0';
    *out_len = 0;

    if (!api_entry_checkpoint())
        return NULL;

    if (!game_inited) {
        /* If nh_get_topten() isn't called after a game, we never went through
           initialization. */
        dlb_init();
        init_dungeons();
    }

    if (!player) {
        if (game_complete)
            player = plname;
        else
            player = "";
    }

    fd = open_datafile(RECORD, O_RDONLY, SCOREPREFIX);
    ttlist = read_topten(fd, TTLISTLEN);
    close(fd);
    if (!ttlist) {
        strcpy(statusbuf, "Cannot open record file!");
        api_exit();
        return NULL;
    }

    /* find the rank of a completed game in the score list */
    if (game_complete && !strcmp(player, plname)) {
        fill_topten_entry(&newtt, end_how);

        /* find this entry in the list */
        for (i = 0; i < TTLISTLEN && validentry(ttlist[i]); i++)
            if (!memcmp(&ttlist[i], &newtt, sizeof (struct toptenentry)))
                rank = i;

        if (wizard || discover)
            sprintf(statusbuf,
                    "Since you were in %s mode, your game was not "
                    "added to the score list.", wizard ? "wizard" : "discover");
        else if (rank >= 0 && rank < 10)
            sprintf(statusbuf, "You made the top ten list!");
        else if (rank)
            sprintf(statusbuf, "You reached the %d%s place on the score list.",
                    rank + 1, ordin(rank + 1));
    }

    /* select scores for display */
    sel_count = 0;
    selected = calloc(TTLISTLEN, sizeof (boolean));

    for (i = 0; i < TTLISTLEN && validentry(ttlist[i]); i++) {
        if (top == -1 || i < top)
            selected[i] = TRUE;

        if (own && !strcmp(player, ttlist[i].name))
            selected[i] = TRUE;

        if (rank != -1 && rank - around <= i && i <= rank + around)
            selected[i] = TRUE;

        if (selected[i])
            sel_count++;
    }

    if (game_complete && sel_count == 0) {
        /* didn't make it onto the list and nothing else is selected */
        ttlist[0] = newtt;
        selected[0] = TRUE;
        sel_count++;
        off_list = TRUE;
    }


    score_list = xmalloc(sel_count * sizeof (struct nh_topten_entry));
    memset(score_list, 0, sel_count * sizeof (struct nh_topten_entry));
    *out_len = sel_count;
    j = 0;
    for (i = 0; i < TTLISTLEN && validentry(ttlist[i]); i++) {
        if (selected[i])
            fill_nh_score_entry(&ttlist[i], &score_list[j++], i + 1, i == rank);
    }

    if (off_list) {
        score_list[0].rank = -1;
        score_list[0].highlight = TRUE;
    }

    if (!game_inited) {
        free_dungeon();
        dlb_cleanup();
    }

    free(selected);
    free(ttlist);

    api_exit();
    return score_list;
}
示例#7
0
/* command wrapper function: make sure the game is able to run commands, perform
 * logging and generate reasonable return values for api clients with no access
 * to internal state */
int nh_command(const char *cmd, int rep, struct nh_cmd_arg *arg)
{
    int cmdidx, cmdresult, pre_moves;
    unsigned int pre_rngstate;

    if (!program_state.game_running)
	return ERR_GAME_NOT_RUNNING;
    
    cmdidx = get_command_idx(cmd);
    if (program_state.viewing && (cmdidx < 0 || !(cmdlist[cmdidx].flags & CMD_NOTIME)))
	return ERR_COMMAND_FORBIDDEN; /*  */
	
    if (!api_entry_checkpoint()) {
	/* terminate() in end.c will arrive here */
	if (program_state.panicking)
	    return GAME_PANICKED;
	if (!program_state.gameover)
	    return GAME_SAVED;
	if (program_state.forced_exit)
	    return ERR_FORCED_EXIT;
	return GAME_OVER;
    }
    
    /* if the game is being restored, turntime is set in restore_read_command */
    turntime = time(NULL);
    log_command(cmdidx, rep, arg);
    
    pre_rngstate = mt_nextstate();
    pre_moves = moves;
    
    /* do the deed. command_input returns -1 if the command completed normally */
    cmdresult = command_input(cmdidx, rep, arg);
    
    /* make sure we actually want this command to be logged */
    if (cmdidx >= 0 && (cmdlist[cmdidx].flags & CMD_NOTIME) &&
	pre_rngstate == mt_nextstate() && pre_moves == moves)
	log_revert_command(); /* nope, cut it out of the log */
    else
	log_command_result(); /* log the result */

    api_exit(); /* no unsafe operations after this point */
    
    if (cmdresult != -1)
	return cmdresult;
    
    /*
     * performing a command can put the game into several different states:
     *  - the command completes immediately: a simple move or an attack etc
     *    multi == 0, occupation == NULL
     *  - if a count is given, the command will (usually) take count turns
     *    multi == count (> 0), occupation == NULL
     *  - the command may cause a delay: for ex. putting on or removing armor
     *    multi == -delay (< 0), occupation == NULL
     *    multi is incremented in you_moved
     *  - the command may take multiple moves, and require a callback to be
     *    run for each move. example: forcing a lock
     *    multi >= 0, occupation == callback
     */
    if (multi >= 0 && occupation)
	return OCCUPATION_IN_PROGRESS;
    else if (multi > 0)
	return MULTI_IN_PROGRESS;
    else if (multi < 0)
	return POST_ACTION_DELAY;
    
    return READY_FOR_INPUT;
}
示例#8
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;
}