static int curses_inline_query(const char *msg, int (*validator)(int, void*), void *arg, nh_bool cursor_visible, enum keyreq_context context) { if (!game_is_running) { curses_impossible("Trying to create inline query outside game."); return curses_msgwin_generic(msg, validator, arg, cursor_visible, context); } else if (!msgwin) { curses_impossible("Trying to create inline query without msgwin."); return curses_msgwin_generic(msg, validator, arg, cursor_visible, context); } /* We use a temporary message as the game will send a summary of the decision along later. */ curses_temp_message(msg); draw_msgwin(); /* We do not respect cursor_visible here, since we want the cursor focused on the prompt. We need to leave a space after it, though. */ int y, x; getyx(msgwin, y, x); if (x < COLNO - 1) wmove(msgwin, y, x + 1); int rv = -1; while (rv == -1) rv = validator(nh_wgetch(msgwin, context), arg); curses_clear_temp_messages(); draw_msgwin(); return rv; }
void pause_messages(void) { draw_msgwin(); if (msglines[curline][0]) /* new text printed this turn */ more(); }
/* called from get_command */ void new_action(void) { action++; start_of_turn_curline = last_redraw_curline = curline; draw_msgwin(); }
static void more(void) { int key, attr = A_NORMAL; int cursx, cursy; draw_msgwin(); if (settings.standout) attr = A_STANDOUT; if (getmaxy(msgwin) == 1) { wmove(msgwin, getmaxy(msgwin) - 1, COLNO - 8); wattron(msgwin, attr); waddstr(msgwin, "--More--"); wattroff(msgwin, attr); wrefresh(msgwin); } else { newline(); draw_msgwin(); wmove(msgwin, getmaxy(msgwin) - 1, COLNO / 2 - 4); wattron(msgwin, attr); waddstr(msgwin, "--More--"); wattroff(msgwin, attr); wrefresh(msgwin); } getyx(msgwin, cursy, cursx); wtimeout(msgwin, 666); /* enable blinking */ do { key = nh_wgetch(msgwin); draw_map(player.x, player.y); wmove(msgwin, cursy, cursx); doupdate(); } while (key != '\n' && key != '\r' && key != ' ' && key != KEY_ESC); wtimeout(msgwin, -1); if (getmaxy(msgwin) == 1) newline(); draw_msgwin(); if (key == KEY_ESC) stopprint = TRUE; /* we want to --more-- by screenfuls, not lines */ last_redraw_curline = curline; }
/* Create a new dialog, or reposition an existing one, in an appropriate position for showing prompts. Also draw a border around it. */ WINDOW * newdialog(int height, int width, int dismissable, WINDOW *win) { int starty, startx; if (height < 3) height = 3; if (height > LINES) height = LINES; if (width > COLS) width = COLS; if (game_is_running) { /* instead of covering up messages, draw the dialog as if it were a message */ fresh_message_line(TRUE); draw_msgwin(); if (getmaxx(msgwin) < getmaxx(stdscr)) width = getmaxx(msgwin) + (ui_flags.draw_outer_frame_lines ? 2 : 0); else width = getmaxx(stdscr); startx = 0; starty = getmaxy(msgwin) - (ui_flags.draw_outer_frame_lines ? 0 : 1); } else { /* out of game, keep dialogs centred */ starty = (LINES - height) / 2; startx = (COLS - width) / 2; } redraw_popup_windows(); if (!win) win = newwin_onscreen(height, width, starty, startx); else { mvwin(win, starty, startx); wresize(win, height, width); } werase(win); keypad(win, TRUE); meta(win, TRUE); nh_window_border(win, dismissable); return win; }
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 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); }
static void curses_print_message_core(int turn, const char *msg, nh_bool canblock) { int hsize, vsize, maxlen; nh_bool died; if (!msghistory) alloc_hist_array(); if (turn != prevturn) start_of_turn_curline = last_redraw_curline = curline; if (turn < prevturn) /* going back in time can happen during replay */ prune_messages(turn); if (!*msg) return; /* empty message. done. */ if (action > prevaction) { /* re-enable output if it was stopped and start a new line */ stopprint = FALSE; newline(); } prevturn = turn; prevaction = action; store_message(turn, msg); if (stopprint) return; /* * generally we want to put as many messages on one line as possible to * maximize space usage. A new line is begun after each player turn or if * more() is called via pause_messages(). "You die" also deserves its own line. * * If the message area is only one line high, space for "--More--" must be * reserved at the end of the line, otherwise --More-- is shown on a new line. */ getmaxyx(msgwin, vsize, hsize); maxlen = hsize; if (maxlen >= COLNO) maxlen = COLNO - 1; if (vsize == 1) maxlen -= 8; /* for "--More--" */ died = !strncmp(msg, "You die", 7); if (strlen(msglines[curline]) + strlen(msg) + 1 < maxlen && !died) { if (msglines[curline][0]) strcat(msglines[curline], " "); strcat(msglines[curline], msg); } else { int idx, output_count; char **output; wrap_text(maxlen, msg, &output_count, &output); for (idx = 0; idx < output_count; idx++) { if (strlen(msglines[curline]) > 0) fresh_message_line(canblock); if (stopprint) break; /* may get set in more() */ strcpy(msglines[curline], output[idx]); } free_wrap(output); } draw_msgwin(); }