void replay_commandloop(int fd) { int key, move, count; char buf[BUFSZ], qbuf[BUFSZ]; nh_bool ret, firsttime = TRUE; struct nh_replay_info rinfo; struct nh_cmd_arg noarg; struct nh_cmd_desc *cmd; create_game_windows(); if (!nh_view_replay_start(fd, &curses_replay_windowprocs, &rinfo)) return; load_keymap(); while (1) { draw_msgwin(); curses_update_status(NULL); draw_sidebar(); draw_replay_info(&rinfo); if (firsttime) show_replay_help(); firsttime = FALSE; key = get_map_key(TRUE); switch (key) { /* step forward */ case KEY_RIGHT: case ' ': ret = nh_view_replay_step(&rinfo, REPLAY_FORWARD, 1); draw_replay_info(&rinfo); if (ret == FALSE) { key = curses_msgwin("You have reached the end of this game. " "Go back or press ESC to exit."); if (key == KEY_ESC) goto out; } break; /* step backward */ case KEY_LEFT: nh_view_replay_step(&rinfo, REPLAY_BACKWARD, 1); draw_replay_info(&rinfo); break; case KEY_ESC: goto out; case 'g': strncpy(qbuf, "What move do you want to jump to?", BUFSZ); if (rinfo.max_moves > 0) sprintf(qbuf + strlen(qbuf), " (Max: %d)", rinfo.max_moves); curses_getline(qbuf, buf); if (buf[0] == '\033' || !(move = atoi(buf))) break; nh_view_replay_step(&rinfo, REPLAY_GOTO, move); break; case KEY_F(12): /* timetest! */ if (allow_timetest()) timetest(fd, &rinfo); break; default: count = 0; noarg.argtype = CMD_ARG_NONE; cmd = keymap[key]; if (!cmd) break; if (cmd->flags & CMD_UI) handle_internal_cmd(&cmd, &noarg, &count); if (cmd) nh_command(cmd->name, count, &noarg); break; } } out: nh_view_replay_finish(); free_keymap(); destroy_game_windows(); cleanup_messages(); }
static nh_bool option_change_callback(struct nh_option_desc *option) { if (!strcmp(option->name, "classic_status") || !strcmp(option->name, "darkmsg") || !strcmp(option->name, "frame") || !strcmp(option->name, "frame_hp_color") || !strcmp(option->name, "status3") || !strcmp(option->name, "sidebar")) { rebuild_ui(); return TRUE; } else if (!strcmp(option->name, "showexp") || !strcmp(option->name, "showscore") || !strcmp(option->name, "time")) { curses_update_status(NULL); } else if (!strcmp(option->name, "darkroom") || !strcmp(option->name, "hilite_peaceful") || !strcmp(option->name, "hilite_pet") || !strcmp(option->name, "mapcolors")) { draw_map(player.x, player.y); } else if (!strcmp(option->name, "darkgray")) { set_darkgray(); draw_map(player.x, player.y); } else if (!strcmp(option->name, "dungeon_name")) { settings.dungeon_name = option->value.e; rebuild_ui(); } else if (!strcmp(option->name, "menu_headings")) { settings.menu_headings = option->value.e; } else if (!strcmp(option->name, "graphics")) { settings.graphics = option->value.e; switch_graphics(option->value.e); if (ui_flags.ingame) { draw_map(player.x, player.y); redraw_game_windows(); } } else if (!strcmp(option->name, "scores_top")) { settings.end_top = option->value.i; } else if (!strcmp(option->name, "scores_around")) { settings.end_around = option->value.i; } else if (!strcmp(option->name, "optstyle")) { settings.optstyle = option->value.e; } else if (!strcmp(option->name, "msgheight")) { settings.msgheight = option->value.i; rebuild_ui(); } else if (!strcmp(option->name, "msghistory")) { settings.msghistory = option->value.i; alloc_hist_array(); } #if defined(PDCURSES) && defined(WIN32) else if (!strcmp(option->name, "win_width")) { settings.win_width = option->value.i; resize_term(settings.win_height, settings.win_width); handle_resize(); } else if (!strcmp(option->name, "win_height")) { settings.win_height = option->value.i; resize_term(settings.win_height, settings.win_width); handle_resize(); } #endif else if (!strcmp(option->name, "name")) { if (option->value.s) strcpy(settings.plname, option->value.s); else settings.plname[0] = '\0'; } else return FALSE; return TRUE; }
static void timetest(int fd, struct nh_replay_info *rinfo) { char buf[BUFSZ]; hp_time t_start, t_end; long ms; int mmax, initial, revpos; initial = rinfo->moves; nh_view_replay_step(rinfo, REPLAY_GOTO, 0); /* run forward */ gettime(&t_start); while (rinfo->actions < rinfo->max_actions) { nh_view_replay_step(rinfo, REPLAY_FORWARD, 1); curses_update_status(NULL); draw_replay_info(rinfo); doupdate(); } draw_msgwin(); gettime(&t_end); ms = clock_delta_ms(&t_start, &t_end); snprintf(buf, BUFSZ, "%d actions replayed with display in %ld ms. (%ld actions/sec)", rinfo->max_actions, ms, rinfo->max_actions * 1000 / ms); curses_msgwin(buf); /* reset the entire replay state to delete checkpoints */ mmax = rinfo->moves; /* max_moves may not be available if this is a replay of a crashed game */ nh_view_replay_finish(); nh_view_replay_start(fd, &curses_replay_windowprocs, rinfo); /* run forward without showing the map etc. */ gettime(&t_start); nh_view_replay_step(rinfo, REPLAY_GOTO, mmax); gettime(&t_end); ms = clock_delta_ms(&t_start, &t_end); snprintf(buf, BUFSZ, "%d actions replayed without display in %ld ms. (%ld actions/sec)", rinfo->actions, ms, rinfo->actions * 1000 / ms); curses_msgwin(buf); /* run backward */ revpos = rinfo->actions; gettime(&t_start); while (rinfo->actions > 0 && revpos < rinfo->actions + 1000) { nh_view_replay_step(rinfo, REPLAY_BACKWARD, 1); curses_update_status(NULL); draw_msgwin(); draw_replay_info(rinfo); doupdate(); } gettime(&t_end); ms = clock_delta_ms(&t_start, &t_end); snprintf(buf, BUFSZ, "%d actions replayed backward with display in %ld ms. (%ld actions/sec)", revpos - rinfo->actions, ms, (revpos - rinfo->actions) * 1000 / ms); curses_msgwin(buf); nh_view_replay_step(rinfo, REPLAY_GOTO, initial); }
int curses_getpos(int *x, int *y, nh_bool force, const char *goal) { int result = 0; int cx, cy; int key, dx, dy; int sidx; static const char pick_chars[] = " \r\n.,;:"; static const int pick_vals[] = {1, 1, 1, 1, 2, 3, 4}; const char *cp; char printbuf[BUFSZ]; char *matching = NULL; enum nh_direction dir; struct coord *monpos = NULL; int moncount, monidx; int firstmove = 1; werase(statuswin); mvwaddstr(statuswin, 0, 0, "Move the cursor with the direction keys. Press " "the letter of a dungeon symbol"); mvwaddstr(statuswin, 1, 0, "to select it or use m to move to a nearby " "monster. Finish with one of .,;:"); wrefresh(statuswin); cx = *x >= 1 ? *x : player.x; cy = *y >= 0 ? *y : player.y; wmove(mapwin, cy, cx - 1); while (1) { if (!firstmove) { struct nh_desc_buf descbuf; int mx = 0, my = 0; nh_describe_pos(cx, cy, &descbuf, NULL); werase(statuswin); place_desc_message(statuswin, &mx, &my, descbuf.effectdesc); place_desc_message(statuswin, &mx, &my, descbuf.invisdesc); place_desc_message(statuswin, &mx, &my, descbuf.mondesc); place_desc_message(statuswin, &mx, &my, descbuf.objdesc); place_desc_message(statuswin, &mx, &my, descbuf.trapdesc); place_desc_message(statuswin, &mx, &my, descbuf.bgdesc); wrefresh(statuswin); wmove(mapwin, cy, cx - 1); } firstmove = 0; dx = dy = 0; key = get_map_key(FALSE); if (key == KEY_ESC) { cx = cy = -10; result = -1; break; } if ((cp = strchr(pick_chars, (char)key)) != 0) { /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */ result = pick_vals[cp - pick_chars]; break; } dir = key_to_dir(key); if (dir != DIR_NONE) { dx = xdir[dir]; dy = ydir[dir]; } else if ((dir = key_to_dir(tolower((char)key))) != DIR_NONE) { /* a shifted movement letter */ dx = xdir[dir] * 8; dy = ydir[dir] * 8; } if (dx || dy) { /* truncate at map edge */ if (cx + dx < 1) dx = 1 - cx; if (cx + dx > COLNO - 1) dx = COLNO - 1 - cx; if (cy + dy < 0) dy = -cy; if (cy + dy > ROWNO - 1) dy = ROWNO - 1 - cy; cx += dx; cy += dy; goto nxtc; } if (key == 'm') { if (!monpos) { int i, j; moncount = 0; for (i = 0; i < ROWNO; i++) for (j = 0; j < COLNO; j++) if (display_buffer[i][j].mon && (j != player.x || i != player.y)) moncount++; monpos = malloc(moncount * sizeof (struct coord)); monidx = 0; for (i = 0; i < ROWNO; i++) for (j = 0; j < COLNO; j++) if (display_buffer[i][j].mon && (j != player.x || i != player.y)) { monpos[monidx].x = j; monpos[monidx].y = i; monidx++; } monidx = 0; qsort(monpos, moncount, sizeof (struct coord), compare_coord_dist); } if (moncount) { /* there is at least one monster to move to */ cx = monpos[monidx].x; cy = monpos[monidx].y; monidx = (monidx + 1) % moncount; } } else { int k = 0, tx, ty; int pass, lo_x, lo_y, hi_x, hi_y; matching = malloc(default_drawing->num_bgelements); memset(matching, 0, default_drawing->num_bgelements); for (sidx = default_drawing->bg_feature_offset; sidx < default_drawing->num_bgelements; sidx++) if (key == default_drawing->bgelements[sidx].ch) matching[sidx] = (char)++k; if (k) { for (pass = 0; pass <= 1; pass++) { /* pass 0: just past current pos to lower right; pass 1: upper left corner to current pos */ lo_y = (pass == 0) ? cy : 0; hi_y = (pass == 0) ? ROWNO - 1 : cy; for (ty = lo_y; ty <= hi_y; ty++) { lo_x = (pass == 0 && ty == lo_y) ? cx + 1 : 1; hi_x = (pass == 1 && ty == hi_y) ? cx : COLNO - 1; for (tx = lo_x; tx <= hi_x; tx++) { k = display_buffer[ty][tx].bg; if (k && matching[k]) { cx = tx; cy = ty; goto nxtc; } } /* column */ } /* row */ } /* pass */ sprintf(printbuf, "Can't find dungeon feature '%c'.", (char)key); curses_msgwin(printbuf); } else { sprintf(printbuf, "Unknown direction%s.", !force ? " (ESC to abort)" : ""); curses_msgwin(printbuf); } } if (force) goto nxtc; cx = -1; cy = 0; result = 0; /* not -1 */ break; nxtc: wmove(mapwin, cy, cx - 1); wrefresh(mapwin); } *x = cx; *y = cy; if (monpos) free(monpos); if (matching) free(matching); curses_update_status(NULL); /* clear the help message */ return result; }