-/* NetHack 3.6 wintty.c $NHDT-Date: 1449052583 2015/12/02 10:36:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.116 $ */
+/* NetHack 3.6 wintty.c $NHDT-Date: 1575245194 2019/12/02 00:06:34 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.227 $ */
/* Copyright (c) David Cohrs, 1991 */
/* NetHack may be freely redistributed. See license for details. */
-/*
-** Japanese version (by Issei Numata)
-** For 3.4, Copyright (c) Kentaro Shirakata, 2002-2003
-** JNetHack may be freely redistributed. See license for details.
-*/
+/* JNetHack Copyright */
+/* (c) Issei Numata 1994-2000 */
+/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020 */
+/* JNetHack may be freely redistributed. See license for details. */
/*
* Neither a standard out nor character-based control codes should be
#include "wintty.h"
#ifdef CLIPPING /* might want SIGWINCH */
-#if defined(BSD) || defined(ULTRIX) || defined(AIX_31) \
- || defined(_BULL_SOURCE)
+#if defined(BSD) || defined(ULTRIX) || defined(AIX_31) || defined(_BULL_SOURCE)
#include <signal.h>
#endif
#endif
-extern char mapped_menu_cmds[]; /* from options.c */
+#ifdef TTY_TILES_ESCCODES
+extern short glyph2tile[];
+#define TILE_ANSI_COMMAND 'z'
+#define AVTC_GLYPH_START 0
+#define AVTC_GLYPH_END 1
+#define AVTC_SELECT_WINDOW 2
+#define AVTC_INLINE_SYNC 3
+#endif
-/* this is only needed until tty_status_* routines are written */
-extern NEARDATA winid WIN_STATUS;
+#ifdef HANGUP_HANDLING
+/*
+ * NetHack's core switches to a dummy windowing interface when it
+ * detects SIGHUP, but that's no help for any interface routine which
+ * is already in progress at the time, and there have been reports of
+ * runaway disconnected processes which use up all available CPU time.
+ * HUPSKIP() and HUPSKIP_RETURN(x) are used to try to cut them off so
+ * that they return to the core instead attempting more terminal I/O.
+ */
+#define HUPSKIP() \
+ do { \
+ if (program_state.done_hup) { \
+ morc = '\033'; \
+ return; \
+ } \
+ } while (0)
+ /* morc=ESC - in case we bypass xwaitforspace() which sets that */
+#define HUPSKIP_RESULT(RES) \
+ do { \
+ if (program_state.done_hup) \
+ return (RES); \
+ } while (0)
+#else /* !HANGUP_HANDLING */
+#define HUPSKIP() /*empty*/
+#define HUPSKIP_RESULT(RES) /*empty*/
+#endif /* ?HANGUP_HANDLING */
+
+extern char mapped_menu_cmds[]; /* from options.c */
/* Interface definition, for windows.c */
struct window_procs tty_procs = {
"tty",
+ (0
#ifdef MSDOS
- WC_TILED_MAP | WC_ASCII_MAP |
+ | WC_TILED_MAP | WC_ASCII_MAP
#endif
#if defined(WIN32CON)
- WC_MOUSE_SUPPORT |
+ | WC_MOUSE_SUPPORT
#endif
- WC_COLOR | WC_HILITE_PET | WC_INVERSE | WC_EIGHT_BIT_IN,
+ | WC_COLOR | WC_HILITE_PET | WC_INVERSE | WC_EIGHT_BIT_IN),
+ (0
#if defined(SELECTSAVED)
- WC2_SELECTSAVED |
+ | WC2_SELECTSAVED
+#endif
+#if defined(STATUS_HILITES)
+ | WC2_HILITE_STATUS | WC2_HITPOINTBAR | WC2_FLUSH_STATUS
+ | WC2_RESET_STATUS
+#endif
+ | WC2_DARKGRAY | WC2_SUPPRESS_HIST | WC2_STATUSLINES),
+#ifdef TEXTCOLOR
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */
+#else
+ {1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1},
#endif
- WC2_DARKGRAY,
tty_init_nhwindows, tty_player_selection, tty_askname, tty_get_nh_event,
tty_exit_nhwindows, tty_suspend_nhwindows, tty_resume_nhwindows,
tty_create_nhwindow, tty_clear_nhwindow, tty_display_nhwindow,
/* other defs that really should go away (they're tty specific) */
tty_start_screen, tty_end_screen, genl_outrip,
-#if defined(WIN32)
- nttty_preference_update,
-#else
- genl_preference_update,
-#endif
+ tty_preference_update,
tty_getmsghistory, tty_putmsghistory,
-#ifdef STATUS_VIA_WINDOWPORT
tty_status_init,
- genl_status_finish, genl_status_enablefield,
- tty_status_update,
+ genl_status_finish, tty_status_enablefield,
#ifdef STATUS_HILITES
- tty_status_threshold,
-#endif
+ tty_status_update,
+#else
+ genl_status_update,
#endif
genl_can_suspend_yes,
};
-static int maxwin = 0; /* number of windows in use */
winid BASE_WINDOW;
struct WinDesc *wins[MAXWIN];
struct DisplayDesc *ttyDisplay; /* the tty display descriptor */
#else
STATIC_DCL void NDECL(getret);
#endif
-STATIC_DCL void FDECL(erase_menu_or_text,
- (winid, struct WinDesc *, BOOLEAN_P));
+STATIC_DCL void FDECL(bail, (const char *)); /* __attribute__((noreturn)) */
+STATIC_DCL void NDECL(new_status_window);
+STATIC_DCL void FDECL(erase_menu_or_text, (winid, struct WinDesc *,
+ BOOLEAN_P));
STATIC_DCL void FDECL(free_window_info, (struct WinDesc *, BOOLEAN_P));
STATIC_DCL void FDECL(dmore, (struct WinDesc *, const char *));
STATIC_DCL void FDECL(set_item_state, (winid, int, tty_menu_item *));
-STATIC_DCL void FDECL(set_all_on_page,
- (winid, tty_menu_item *, tty_menu_item *));
-STATIC_DCL void FDECL(unset_all_on_page,
- (winid, tty_menu_item *, tty_menu_item *));
-STATIC_DCL void FDECL(invert_all_on_page,
- (winid, tty_menu_item *, tty_menu_item *, CHAR_P));
-STATIC_DCL void FDECL(invert_all,
- (winid, tty_menu_item *, tty_menu_item *, CHAR_P));
+STATIC_DCL void FDECL(set_all_on_page, (winid, tty_menu_item *,
+ tty_menu_item *));
+STATIC_DCL void FDECL(unset_all_on_page, (winid, tty_menu_item *,
+ tty_menu_item *));
+STATIC_DCL void FDECL(invert_all_on_page, (winid, tty_menu_item *,
+ tty_menu_item *, CHAR_P));
+STATIC_DCL void FDECL(invert_all, (winid, tty_menu_item *,
+ tty_menu_item *, CHAR_P));
+STATIC_DCL void FDECL(toggle_menu_attr, (BOOLEAN_P, int, int));
STATIC_DCL void FDECL(process_menu_window, (winid, struct WinDesc *));
STATIC_DCL void FDECL(process_text_window, (winid, struct WinDesc *));
STATIC_DCL tty_menu_item *FDECL(reverse, (tty_menu_item *));
STATIC_DCL const char *FDECL(compress_str, (const char *));
STATIC_DCL void FDECL(tty_putsym, (winid, int, int, CHAR_P));
-STATIC_DCL void FDECL(bail, (const char *)); /* __attribute__((noreturn)) */
STATIC_DCL void FDECL(setup_rolemenu, (winid, BOOLEAN_P, int, int, int));
STATIC_DCL void FDECL(setup_racemenu, (winid, BOOLEAN_P, int, int, int));
STATIC_DCL void FDECL(setup_gendmenu, (winid, BOOLEAN_P, int, int, int));
STATIC_DCL void FDECL(setup_algnmenu, (winid, BOOLEAN_P, int, int, int));
STATIC_DCL boolean NDECL(reset_role_filtering);
+#ifdef STATUS_HILITES
+STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P, int *));
+STATIC_DCL void NDECL(render_status);
+STATIC_DCL void FDECL(tty_putstatusfield, (const char *, int, int));
+STATIC_DCL boolean NDECL(check_windowdata);
+STATIC_DCL void NDECL(set_condition_length);
+STATIC_DCL int FDECL(make_things_fit, (BOOLEAN_P));
+STATIC_DCL void FDECL(shrink_enc, (int));
+STATIC_DCL void FDECL(shrink_dlvl, (int));
+#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
+STATIC_DCL void NDECL(status_sanity_check);
+#endif /* NH_DEVEL_STATUS */
+#endif
/*
* A string containing all the default commands -- to add to a list
MENU_INVERT_PAGE, MENU_SEARCH, 0 /* null terminator */
};
+#ifdef TTY_TILES_ESCCODES
+static int vt_tile_current_window = -2;
+
+void
+print_vt_code(i, c, d)
+int i, c, d;
+{
+ HUPSKIP();
+ if (iflags.vt_tiledata) {
+ if (c >= 0) {
+ if (i == AVTC_SELECT_WINDOW) {
+ if (c == vt_tile_current_window)
+ return;
+ vt_tile_current_window = c;
+ }
+ if (d >= 0)
+ printf("\033[1;%d;%d;%d%c", i, c, d, TILE_ANSI_COMMAND);
+ else
+ printf("\033[1;%d;%d%c", i, c, TILE_ANSI_COMMAND);
+ } else {
+ printf("\033[1;%d%c", i, TILE_ANSI_COMMAND);
+ }
+ }
+}
+#else
+# define print_vt_code(i, c, d) ;
+#endif /* !TTY_TILES_ESCCODES */
+#define print_vt_code1(i) print_vt_code((i), -1, -1)
+#define print_vt_code2(i,c) print_vt_code((i), (c), -1)
+#define print_vt_code3(i,c,d) print_vt_code((i), (c), (d))
+
+
/* clean up and quit */
STATIC_OVL void
bail(mesg)
{
clearlocks();
tty_exit_nhwindows(mesg);
- terminate(EXIT_SUCCESS);
+ nh_terminate(EXIT_SUCCESS);
/*NOTREACHED*/
}
#if defined(SIGWINCH) && defined(CLIPPING)
+STATIC_DCL void FDECL(winch_handler, (int));
+
+ /*
+ * This really ought to just set a flag like the hangup handler does,
+ * then check the flag at "safe" times, in case the signal arrives
+ * while something fragile is executing. Better to have a brief period
+ * where display updates don't fit the new size than for tty internals
+ * to become corrupted.
+ *
+ * 'winch_seen' has been "notyet" for a long time....
+ */
+/*ARGUSED*/
STATIC_OVL void
-winch()
+winch_handler(sig_unused) /* signal handler is called with at least 1 arg */
+int sig_unused UNUSED;
{
int oldLI = LI, oldCO = CO, i;
register struct WinDesc *cw;
cw = wins[WIN_MESSAGE];
cw->curx = cw->cury = 0;
- tty_destroy_nhwindow(WIN_STATUS);
- WIN_STATUS = tty_create_nhwindow(NHW_STATUS);
-
+ new_status_window();
if (u.ux) {
-#ifdef CLIPPING
- if (CO < COLNO || LI < ROWNO + 3) {
- setclipped();
- tty_cliparound(u.ux, u.uy);
- } else {
- clipping = FALSE;
- clipx = clipy = 0;
- }
-#endif
i = ttyDisplay->toplin;
ttyDisplay->toplin = 0;
docrt();
}
#endif
+/* destroy and recreate status window; extracted from winch_handler()
+ and augmented for use by tty_preference_update() */
+STATIC_OVL void
+new_status_window()
+{
+ if (WIN_STATUS != WIN_ERR) {
+ /* if it's shrinking, clear it before destroying so that
+ dropped portion won't show anything that's now becoming stale */
+ if (wins[WIN_STATUS]->maxrow > iflags.wc2_statuslines)
+ tty_clear_nhwindow(WIN_STATUS);
+
+ tty_destroy_nhwindow(WIN_STATUS), WIN_STATUS = WIN_ERR;
+ }
+ /* frees some status tracking data */
+ genl_status_finish();
+ /* creates status window and allocates tracking data */
+ tty_status_init();
+ tty_clear_nhwindow(WIN_STATUS); /* does some init, sets context.botlx */
+#ifdef STATUS_HILITES
+ status_initialize(REASSESS_ONLY);
+#endif
+
+#ifdef CLIPPING
+ if (u.ux) {
+ if (LI < 1 + ROWNO + iflags.wc2_statuslines) {
+ setclipped();
+ tty_cliparound(u.ux, u.uy);
+ } else {
+ clipping = FALSE;
+ clipx = clipy = 0;
+ }
+ }
+#endif
+}
+
/*ARGSUSED*/
void
tty_init_nhwindows(argcp, argv)
{
int wid, hgt, i;
-/*
- * Remember tty modes, to be restored on exit.
- *
- * gettty() must be called before tty_startup()
- * due to ordering of LI/CO settings
- * tty_startup() must be called before initoptions()
- * due to ordering of graphics settings
- */
+ /* options aren't processed yet so wc2_statuslines might be 0;
+ make sure that it has a reasonable value during tty setup */
+ iflags.wc2_statuslines = (iflags.wc2_statuslines < 3) ? 2 : 3;
+ /*
+ * Remember tty modes, to be restored on exit.
+ *
+ * gettty() must be called before tty_startup()
+ * due to ordering of LI/CO settings
+ * tty_startup() must be called before initoptions()
+ * due to ordering of graphics settings
+ */
#if defined(UNIX) || defined(VMS)
setbuf(stdout, obuf);
#endif
setftty(); /* calls start_screen */
/* set up tty descriptor */
- ttyDisplay = (struct DisplayDesc *) alloc(sizeof(struct DisplayDesc));
+ ttyDisplay = (struct DisplayDesc *) alloc(sizeof (struct DisplayDesc));
ttyDisplay->toplin = 0;
ttyDisplay->rows = hgt;
ttyDisplay->cols = wid;
ttyDisplay->lastwin = WIN_ERR;
#if defined(SIGWINCH) && defined(CLIPPING) && !defined(NO_SIGNAL)
- (void) signal(SIGWINCH, winch);
+ (void) signal(SIGWINCH, (SIG_RET_TYPE) winch_handler);
#endif
- /* add one a space forward menu command alias */
- add_menu_cmd_alias(' ', MENU_NEXT_PAGE);
-
tty_clear_nhwindow(BASE_WINDOW);
tty_putstr(BASE_WINDOW, 0, "");
tty_putstr(BASE_WINDOW, 0, "");
#endif
tty_display_nhwindow(BASE_WINDOW, FALSE);
+
+ /* 'statuslines' defaults to SET_IN_FILE, allowed but invisible;
+ make it dynamically settable if feasible, otherwise visible */
+ if (tty_procs.wincap2 & WC2_STATUSLINES)
+ set_wc2_option_mod_status(WC2_STATUSLINES,
+#ifndef CLIPPING
+ (LI < 1 + ROWNO + 2) ? DISP_IN_GAME :
+#endif
+ SET_IN_GAME);
+}
+
+void
+tty_preference_update(pref)
+const char *pref;
+{
+ if (!strcmp(pref, "statuslines") && iflags.window_inited) {
+ new_status_window();
+ }
+
+#if defined(WIN32)
+ nttty_preference_update(pref);
+#else
+ genl_preference_update(pref);
+#endif
+ return;
}
/* try to reduce clutter in the code below... */
tty_player_selection()
{
int i, k, n, choice, nextpick;
- boolean getconfirmation;
+ boolean getconfirmation, picksomething;
char pick4u = 'n';
char pbuf[QBUFSZ], plbuf[QBUFSZ];
winid win;
anything any;
menu_item *selected = 0;
- if (flags.randomall) {
+ /* Used to avoid "Is this ok?" if player has already specified all
+ * four facets of role.
+ * Note that rigid_role_checks might force any unspecified facets to
+ * have a specific value, but that will still require confirmation;
+ * player can specify the forced ones if avoiding that is demanded.
+ */
+ picksomething = (ROLE == ROLE_NONE || RACE == ROLE_NONE
+ || GEND == ROLE_NONE || ALGN == ROLE_NONE);
+ /* Used for '-@';
+ * choose randomly without asking for all unspecified facets.
+ */
+ if (flags.randomall && picksomething) {
if (ROLE == ROLE_NONE)
ROLE = ROLE_RANDOM;
if (RACE == ROLE_NONE)
ALGN = ROLE_RANDOM;
}
- /* prevent an unnecessary prompt */
+ /* prevent unnecessary prompting if role forces race (samurai) or gender
+ (valkyrie) or alignment (rogue), or race forces alignment (orc), &c */
rigid_role_checks();
/* Should we randomly pick for the player? */
goto give_up;
}
-makepicks:
+ makepicks:
nextpick = RS_ROLE;
do {
if (nextpick == RS_ROLE) {
k = pick_role(RACE, GEND, ALGN, PICK_RANDOM);
if (k < 0) {
tty_putstr(BASE_WINDOW, 0, "Incompatible role!");
- k = randrole();
+ k = randrole(FALSE);
}
} else {
/* Prompt for a role */
/* populate the menu with role choices */
setup_rolemenu(win, TRUE, RACE, GEND, ALGN);
/* add miscellaneous menu entries */
- role_menu_extra(ROLE_RANDOM, win);
- any.a_int = 0; /* separator, not a choice */
- add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, "",
+ role_menu_extra(ROLE_RANDOM, win, TRUE);
+ any = zeroany; /* separator, not a choice */
+ add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "",
MENU_UNSELECTED);
- role_menu_extra(RS_RACE, win);
- role_menu_extra(RS_GENDER, win);
- role_menu_extra(RS_ALGNMNT, win);
+ role_menu_extra(RS_RACE, win, FALSE);
+ role_menu_extra(RS_GENDER, win, FALSE);
+ role_menu_extra(RS_ALGNMNT, win, FALSE);
if (gotrolefilter())
- role_menu_extra(RS_filter, win);
- role_menu_extra(ROLE_NONE, win); /* quit */
+ role_menu_extra(RS_filter, win, FALSE);
+ role_menu_extra(ROLE_NONE, win, FALSE); /* quit */
/*JP
Strcpy(pbuf, "Pick a role or profession");
*/
Strcpy(pbuf, "\90E\8bÆ\82ð\91I\82ñ\82Å\82\82¾\82³\82¢");
end_menu(win, pbuf);
n = select_menu(win, PICK_ONE, &selected);
- choice = (n == 1) ? selected[0].item.a_int : ROLE_NONE;
+ /*
+ * PICK_ONE with preselected choice behaves strangely:
+ * n == -1 -- <escape>, so use quit choice;
+ * n == 0 -- explicitly chose preselected entry,
+ * toggling it off, so use it;
+ * n == 1 -- implicitly chose preselected entry
+ * with <space> or <return>;
+ * n == 2 -- explicitly chose a different entry, so
+ * both it and preselected one are in list.
+ */
+ if (n > 0) {
+ choice = selected[0].item.a_int;
+ if (n > 1 && choice == ROLE_RANDOM)
+ choice = selected[1].item.a_int;
+ } else
+ choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE;
if (selected)
free((genericptr_t) selected), selected = 0;
destroy_nhwindow(win);
} else if (choice == ROLE_RANDOM) {
k = pick_role(RACE, GEND, ALGN, PICK_RANDOM);
if (k < 0)
- k = randrole();
+ k = randrole(FALSE);
} else {
k = choice - 1;
}
/* populate the menu with role choices */
setup_racemenu(win, TRUE, ROLE, GEND, ALGN);
/* add miscellaneous menu entries */
- role_menu_extra(ROLE_RANDOM, win);
+ role_menu_extra(ROLE_RANDOM, win, TRUE);
any.a_int = 0; /* separator, not a choice */
- add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, "",
+ add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "",
MENU_UNSELECTED);
- role_menu_extra(RS_ROLE, win);
- role_menu_extra(RS_GENDER, win);
- role_menu_extra(RS_ALGNMNT, win);
+ role_menu_extra(RS_ROLE, win, FALSE);
+ role_menu_extra(RS_GENDER, win, FALSE);
+ role_menu_extra(RS_ALGNMNT, win, FALSE);
if (gotrolefilter())
- role_menu_extra(RS_filter, win);
- role_menu_extra(ROLE_NONE, win); /* quit */
+ role_menu_extra(RS_filter, win, FALSE);
+ role_menu_extra(ROLE_NONE, win, FALSE); /* quit */
/*JP
Strcpy(pbuf, "Pick a race or species");
*/
Strcpy(pbuf, "\8eí\91°\82ð\91I\82ñ\82Å\82\82¾\82³\82¢");
end_menu(win, pbuf);
n = select_menu(win, PICK_ONE, &selected);
- choice = (n == 1) ? selected[0].item.a_int
- : ROLE_NONE;
+ if (n > 0) {
+ choice = selected[0].item.a_int;
+ if (n > 1 && choice == ROLE_RANDOM)
+ choice = selected[1].item.a_int;
+ } else
+ choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE;
if (selected)
free((genericptr_t) selected), selected = 0;
destroy_nhwindow(win);
/* populate the menu with gender choices */
setup_gendmenu(win, TRUE, ROLE, RACE, ALGN);
/* add miscellaneous menu entries */
- role_menu_extra(ROLE_RANDOM, win);
+ role_menu_extra(ROLE_RANDOM, win, TRUE);
any.a_int = 0; /* separator, not a choice */
- add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, "",
+ add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "",
MENU_UNSELECTED);
- role_menu_extra(RS_ROLE, win);
- role_menu_extra(RS_RACE, win);
- role_menu_extra(RS_ALGNMNT, win);
+ role_menu_extra(RS_ROLE, win, FALSE);
+ role_menu_extra(RS_RACE, win, FALSE);
+ role_menu_extra(RS_ALGNMNT, win, FALSE);
if (gotrolefilter())
- role_menu_extra(RS_filter, win);
- role_menu_extra(ROLE_NONE, win); /* quit */
+ role_menu_extra(RS_filter, win, FALSE);
+ role_menu_extra(ROLE_NONE, win, FALSE); /* quit */
/*JP
Strcpy(pbuf, "Pick a gender or sex");
*/
Strcpy(pbuf, "\90«\95Ê\82ð\91I\82ñ\82Å\82\82¾\82³\82¢");
end_menu(win, pbuf);
n = select_menu(win, PICK_ONE, &selected);
- choice = (n == 1) ? selected[0].item.a_int
- : ROLE_NONE;
+ if (n > 0) {
+ choice = selected[0].item.a_int;
+ if (n > 1 && choice == ROLE_RANDOM)
+ choice = selected[1].item.a_int;
+ } else
+ choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE;
if (selected)
free((genericptr_t) selected), selected = 0;
destroy_nhwindow(win);
start_menu(win);
any = zeroany; /* zero out all bits */
setup_algnmenu(win, TRUE, ROLE, RACE, GEND);
- role_menu_extra(ROLE_RANDOM, win);
+ role_menu_extra(ROLE_RANDOM, win, TRUE);
any.a_int = 0; /* separator, not a choice */
- add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, "",
+ add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "",
MENU_UNSELECTED);
- role_menu_extra(RS_ROLE, win);
- role_menu_extra(RS_RACE, win);
- role_menu_extra(RS_GENDER, win);
+ role_menu_extra(RS_ROLE, win, FALSE);
+ role_menu_extra(RS_RACE, win, FALSE);
+ role_menu_extra(RS_GENDER, win, FALSE);
if (gotrolefilter())
- role_menu_extra(RS_filter, win);
- role_menu_extra(ROLE_NONE, win); /* quit */
+ role_menu_extra(RS_filter, win, FALSE);
+ role_menu_extra(ROLE_NONE, win, FALSE); /* quit */
/*JP
Strcpy(pbuf, "Pick an alignment or creed");
*/
Strcpy(pbuf, "\91®\90«\82ð\91I\82ñ\82Å\82\82¾\82³\82¢");
end_menu(win, pbuf);
n = select_menu(win, PICK_ONE, &selected);
- choice = (n == 1) ? selected[0].item.a_int
- : ROLE_NONE;
+ if (n > 0) {
+ choice = selected[0].item.a_int;
+ if (n > 1 && choice == ROLE_RANDOM)
+ choice = selected[1].item.a_int;
+ } else
+ choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE;
if (selected)
free((genericptr_t) selected), selected = 0;
destroy_nhwindow(win);
* q - quit
* (end)
*/
- getconfirmation = (pick4u != 'a' && !flags.randomall);
+ getconfirmation = (picksomething && pick4u != 'a' && !flags.randomall);
while (getconfirmation) {
tty_clear_nhwindow(BASE_WINDOW);
role_selection_prolog(ROLE_NONE, BASE_WINDOW);
(GEND == 1 && roles[ROLE].name.f) ? roles[ROLE].name.f
: roles[ROLE].name.m);
#endif
- add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, pbuf,
+ add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, pbuf,
MENU_UNSELECTED);
/* blank separator */
any.a_int = 0;
- add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, "", MENU_UNSELECTED);
+ add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
/* [ynaq] menu choices */
any.a_int = 1;
/*JP
tty_display_nhwindow(BASE_WINDOW, FALSE);
return;
-give_up:
+ give_up:
/* Quit */
if (selected)
free((genericptr_t) selected); /* [obsolete] */
add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
- "Uncceptable alignments", MENU_UNSELECTED);
+ "Unacceptable alignments", MENU_UNSELECTED);
setup_algnmenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE);
end_menu(win, "Pick all that apply");
if (tryct > 10)
bail("Giving up after 10 tries.\n");
tty_curs(BASE_WINDOW, 1, wins[BASE_WINDOW]->cury - 1);
-/*JP
+#if 0 /*JP*/
tty_putstr(BASE_WINDOW, 0, "Enter a name for your character...");
-*/
- tty_putstr(BASE_WINDOW, 0, "\82 \82È\82½\82Ì\83L\83\83\83\89\83N\83^\82Ì\96¼\91O\82Í\81H");
- /* erase previous prompt (in case of ESC after partial response)
- */
+#else
+ tty_putstr(BASE_WINDOW, 0, "\82 \82È\82½\82Ì\83L\83\83\83\89\83N\83^\82Ì\96¼\91O\82Í\81H");
+#endif
+ /* erase previous prompt (in case of ESC after partial response) */
tty_curs(BASE_WINDOW, 1, wins[BASE_WINDOW]->cury), cl_end();
}
tty_putstr(BASE_WINDOW, 0, who_are_you);
while ((c = tty_nhgetch()) != '\n') {
if (c == EOF)
c = '\033';
+ if (c == '\r')
+ break;
if (c == '\033') {
ct = 0;
break;
/* some people get confused when their erase char is not ^H */
if (c == '\b' || c == '\177') {
#if 1 /*JP*/
- moreback:
+ moreback:
#endif
if (ct) {
ct--;
#endif
}
#if 1 /*JP*/
- if(is_kanji2(ptmpname, ct))
- goto moreback;
+ if(is_kanji2(ptmpname, ct))
+ goto moreback;
#endif
continue;
}
#if defined(UNIX) || defined(VMS)
# if 0 /*JP*/
if (c != '-' && c != '@')
- if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') &&
+ if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z')
/* reject leading digit but allow digits elsewhere
(avoids ambiguity when character name gets
appended to uid to construct save file name) */
- !(c >= '0' && c <= '9' && ct > 0))
+ && !(c >= '0' && c <= '9' && ct > 0))
c = '_';
# endif /*JP*/
#endif
# if 0 /*JP*/
(void) putchar(c);
# else
- (void) cputchar(c);
+ (void) cputchar(c);
# ifdef NO_TERMS
- ttyDisplay->curx++;
- wins[BASE_WINDOW]->curx++;
+ ttyDisplay->curx++;
+ wins[BASE_WINDOW]->curx++;
# endif
# endif /*JP*/
} else
/*JP
msmsg("%c", c);
*/
- (void) putchar(c);
+ (void) putchar(c);
#else
(void) putchar(c);
#endif
#if 0 /*JP*/
plname[ct++] = c;
#else
- ptmpname[ct++] = c;
+ ptmpname[ct++] = c;
#endif
#ifdef WIN32CON
ttyDisplay->curx++;
#if 0 /*JP*/
plname[ct] = 0;
#else
- ptmpname[ct] = 0;
+ ptmpname[ct] = 0;
#endif
} while (ct == 0);
STATIC_OVL void
getret()
{
+ HUPSKIP();
#if 1 /*JP*/
- jputchar('\0');
+ jputchar('\0');
#endif
xputs("\n");
if (flags.standout)
}
}
WIN_MAP = WIN_MESSAGE = WIN_INVEN = WIN_ERR; /* these are all gone now */
-#ifndef STATUS_VIA_WINDOWPORT
WIN_STATUS = WIN_ERR;
-#endif
#ifdef FREE_ALL_MEMORY
if (BASE_WINDOW != WIN_ERR && wins[BASE_WINDOW]) {
free_window_info(wins[BASE_WINDOW], TRUE);
#ifndef NO_TERMS /*(until this gets added to the window interface)*/
tty_shutdown(); /* cleanup termcap/terminfo/whatever */
#endif
+#ifdef WIN32
+ nttty_exit();
+#endif
iflags.window_inited = 0;
}
int type;
{
struct WinDesc *newwin;
- int i;
+ int i, rowoffset;
int newid;
- if (maxwin == MAXWIN)
+ for (newid = 0; newid < MAXWIN; ++newid)
+ if (wins[newid] == 0)
+ break;
+ if (newid == MAXWIN) {
+ panic("No window slots!");
+ /*NOTREACHED*/
return WIN_ERR;
+ }
+
+ newwin = (struct WinDesc *) alloc(sizeof (struct WinDesc));
+ wins[newid] = newwin;
- newwin = (struct WinDesc *) alloc(sizeof(struct WinDesc));
newwin->type = type;
newwin->flags = 0;
newwin->active = FALSE;
newwin->maxcol = newwin->cols = 0;
break;
case NHW_STATUS:
- /* status window, 2 lines long, full width, bottom of screen */
+ /* status window, 2 or 3 lines long, full width, bottom of screen */
+ if (iflags.wc2_statuslines < 2
+#ifndef CLIPPING
+ || (LI < 1 + ROWNO + 3)
+#endif
+ || iflags.wc2_statuslines > 3)
+ iflags.wc2_statuslines = 2;
newwin->offx = 0;
+ rowoffset = ttyDisplay->rows - iflags.wc2_statuslines;
#if defined(USE_TILES) && defined(MSDOS)
if (iflags.grmode) {
- newwin->offy = ttyDisplay->rows - 2;
+ newwin->offy = rowoffset;
} else
#endif
- newwin->offy = min((int) ttyDisplay->rows - 2, ROWNO + 1);
- newwin->rows = newwin->maxrow = 2;
+ newwin->offy = min(rowoffset, ROWNO + 1);
+ newwin->rows = newwin->maxrow = iflags.wc2_statuslines;
newwin->cols = newwin->maxcol = ttyDisplay->cols;
break;
case NHW_MAP:
break;
case NHW_MENU:
case NHW_TEXT:
- /* inventory/menu window, variable length, full width, top of screen
- */
- /* help window, the same, different semantics for display, etc */
+ /* inventory/menu window, variable length, full width, top of screen;
+ help window, the same, different semantics for display, etc */
newwin->offx = newwin->offy = 0;
newwin->rows = 0;
newwin->cols = ttyDisplay->cols;
break;
default:
panic("Tried to create window type %d\n", (int) type);
- return WIN_ERR;
- }
-
- for (newid = 0; newid < MAXWIN; newid++) {
- if (wins[newid] == 0) {
- wins[newid] = newwin;
- break;
- }
- }
- if (newid == MAXWIN) {
- panic("No window slots!");
+ /*NOTREACHED*/
return WIN_ERR;
}
if (newwin->maxrow) {
- newwin->data =
- (char **) alloc(sizeof(char *) * (unsigned) newwin->maxrow);
- newwin->datlen =
- (short *) alloc(sizeof(short) * (unsigned) newwin->maxrow);
- if (newwin->maxcol) {
- /* WIN_STATUS */
- for (i = 0; i < newwin->maxrow; i++) {
+ newwin->data = (char **) alloc(
+ (unsigned) (newwin->maxrow * sizeof (char *)));
+ newwin->datlen = (short *) alloc(
+ (unsigned) (newwin->maxrow * sizeof (short)));
+ for (i = 0; i < newwin->maxrow; i++) {
+ if (newwin->maxcol) { /* WIN_STATUS */
newwin->data[i] = (char *) alloc((unsigned) newwin->maxcol);
newwin->datlen[i] = (short) newwin->maxcol;
- }
- } else {
- for (i = 0; i < newwin->maxrow; i++) {
+ } else {
newwin->data[i] = (char *) 0;
newwin->datlen[i] = 0;
}
struct WinDesc *cw;
boolean clear;
{
- if (cw->offx == 0)
+ if (cw->offx == 0) {
if (cw->offy) {
tty_curs(window, 1, 0);
cl_eos();
- } else if (clear)
+ } else if (clear) {
clear_screen();
- else
+ } else {
docrt();
- else
+ }
+ } else {
docorner((int) cw->offx, cw->maxrow + 1);
+ }
}
STATIC_OVL void
tty_menu_item *temp;
while ((temp = cw->mlist) != 0) {
- cw->mlist = cw->mlist->next;
+ cw->mlist = temp->next;
if (temp->str)
free((genericptr_t) temp->str);
free((genericptr_t) temp);
tty_clear_nhwindow(window)
winid window;
{
+ int i, j, m, n;
register struct WinDesc *cw = 0;
+ HUPSKIP();
if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
panic(winpanicstr, window);
ttyDisplay->lastwin = window;
+ print_vt_code2(AVTC_SELECT_WINDOW, window);
+
switch (cw->type) {
case NHW_MESSAGE:
if (ttyDisplay->toplin) {
}
break;
case NHW_STATUS:
- tty_curs(window, 1, 0);
- cl_end();
- tty_curs(window, 1, 1);
- cl_end();
+ m = cw->maxrow;
+ n = cw->cols;
+ for (i = 0; i < m; ++i) {
+ tty_curs(window, 1, i);
+ cl_end();
+
+ for (j = 0; j < n - 1; ++j)
+ cw->data[i][j] = ' ';
+ cw->data[i][n - 1] = '\0';
+ /*finalx[i][NOW] = finalx[i][BEFORE] = 0;*/
+ }
+ context.botlx = 1;
break;
case NHW_MAP:
/* cheap -- clear the whole thing and tell nethack to redraw botl */
context.botlx = 1;
- /* fall into ... */
+ /*FALLTHRU*/
case NHW_BASE:
clear_screen();
+ /*for (i = 0; i < cw->maxrow; ++i) */
+ /* finalx[i][NOW] = finalx[i][BEFORE] = 0;*/
break;
case NHW_MENU:
case NHW_TEXT:
const char *prompt = cw->morestr ? cw->morestr : defmorestr;
int offset = (cw->type == NHW_TEXT) ? 1 : 2;
+ HUPSKIP();
tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + offset,
(int) ttyDisplay->cury);
if (flags.standout)
{
const char *p;
p = prompt;
- while(*p){
- jputchar(*(p++));
- ttyDisplay->curx++;
- }
+ while(*p){
+ jputchar(*(p++));
+ ttyDisplay->curx++;
+ }
}
/* jputs(prompt);*/
#endif
{
char ch = item->selected ? (item->count == -1L ? '+' : '#') : '-';
+ HUPSKIP();
tty_curs(window, 4, lineno);
term_start_attr(item->attr);
/*JP
}
}
+/* support menucolor in addition to caller-supplied attribute */
+STATIC_OVL void
+toggle_menu_attr(on, color, attr)
+boolean on;
+int color, attr;
+{
+ if (on) {
+ term_start_attr(attr);
+#ifdef TEXTCOLOR
+ if (color != NO_COLOR)
+ term_start_color(color);
+#endif
+ } else {
+#ifdef TEXTCOLOR
+ if (color != NO_COLOR)
+ term_end_color();
+#endif
+ term_end_attr(attr);
+ }
+
+#ifndef TEXTCOLOR
+ nhUse(color);
+#endif
+}
+
STATIC_OVL void
process_menu_window(window, cw)
winid window;
{
tty_menu_item *page_start, *page_end, *curr;
long count;
- int n, curr_page, page_lines, resp_len;
+ int n, attr_n, curr_page, page_lines, resp_len;
boolean finished, counting, reset_count;
char *cp, *rp, resp[QBUFSZ], gacc[QBUFSZ], *msave, *morestr, really_morc;
#define MENU_EXPLICIT_CHOICE 0x7f /* pseudo menu manipulation char */
/* loop until finished */
while (!finished) {
+ HUPSKIP();
if (reset_count) {
counting = FALSE;
count = 0;
page_end = cw->plist[curr_page + 1];
for (page_lines = 0, curr = page_start; curr != page_end;
page_lines++, curr = curr->next) {
- int color = NO_COLOR, attr = ATR_NONE;
- boolean menucolr = FALSE;
+ int attr, color = NO_COLOR;
+
if (curr->selector)
*rp++ = curr->selector;
#if 0 /*JP*/
(void) putchar(' ');
#else
- (void) jputchar(' ');
+ (void) jputchar(' ');
#endif
++ttyDisplay->curx;
+
+ if (!iflags.use_menu_color
+ || !get_menu_coloring(curr->str, &color, &attr))
+ attr = curr->attr;
+
+ /* which character to start attribute highlighting;
+ whole line for headers and such, after the selector
+ character and space and selection indicator for menu
+ lines (including fake ones that simulate grayed-out
+ entries, so we don't rely on curr->identifier here) */
+ attr_n = 0; /* whole line */
+ if (curr->str[0] && curr->str[1] == ' '
+ && curr->str[2] && index("-+#", curr->str[2])
+ && curr->str[3] == ' ')
+ /* [0]=letter, [1]==space, [2]=[-+#], [3]=space */
+ attr_n = 4; /* [4:N]=entry description */
+
/*
* Don't use xputs() because (1) under unix it calls
* tputstr() which will interpret a '*' as some kind
* actually output the character. We're faster doing
* this.
*/
- if (iflags.use_menu_color
- && (menucolr = get_menu_coloring(curr->str, &color,
- &attr))) {
- term_start_attr(attr);
-#ifdef TEXTCOLOR
- if (color != NO_COLOR)
- term_start_color(color);
-#endif
- } else
- term_start_attr(curr->attr);
for (n = 0, cp = curr->str;
+ *cp &&
#ifndef WIN32CON
- *cp
- && (int) ++ttyDisplay->curx < (int) ttyDisplay->cols;
- cp++, n++)
+ (int) ++ttyDisplay->curx < (int) ttyDisplay->cols;
#else
- *cp
- && (int) ttyDisplay->curx < (int) ttyDisplay->cols;
- cp++, n++, ttyDisplay->curx++)
+ (int) ttyDisplay->curx < (int) ttyDisplay->cols;
+ ttyDisplay->curx++,
#endif
- if (n == 2 && curr->identifier.a_void != 0
+ cp++, n++) {
+ if (n == attr_n && (color != NO_COLOR
+ || attr != ATR_NONE))
+ toggle_menu_attr(TRUE, color, attr);
+ if (n == 2
+ && curr->identifier.a_void != 0
&& curr->selected) {
if (curr->count == -1L)
#if 0 /*JP*/
(void) putchar('+'); /* all selected */
#else
- (void) jputchar('+'); /* all selected */
+ (void) jputchar('+'); /* all selected */
#endif
else
#if 0 /*JP*/
(void) putchar('#'); /* count selected */
#else
- (void) jputchar('#'); /* count selected */
+ (void) jputchar('#'); /* count selected */
#endif
} else
#if 0 /*JP*/
(void) putchar(*cp);
#else
- (void) jputchar(*cp);
-#endif
- if (iflags.use_menu_color && menucolr) {
-#ifdef TEXTCOLOR
- if (color != NO_COLOR)
- term_end_color();
+ (void) jputchar(*cp);
#endif
- term_end_attr(attr);
- } else
- term_end_attr(curr->attr);
- }
+ } /* for *cp */
+ if (n > attr_n && (color != NO_COLOR || attr != ATR_NONE))
+ toggle_menu_attr(FALSE, color, attr);
+ } /* if npages > 0 */
} else {
page_start = 0;
page_end = 0;
/* set extra chars.. */
Strcat(resp, default_menu_cmds);
+ Strcat(resp, " "); /* next page or end */
Strcat(resp, "0123456789\033\n\r"); /* counts, quit */
Strcat(resp, gacc); /* group accelerators */
Strcat(resp, mapped_menu_cmds);
if (cw->npages > 1)
#if 0 /*JP*/
Sprintf(cw->morestr, "(%d of %d)", curr_page + 1,
+ (int) cw->npages);
#else
- Sprintf(cw->morestr, "(%d/%d)", curr_page + 1,
-#endif
+ Sprintf(cw->morestr, "(%d/%d)", curr_page + 1,
(int) cw->npages);
+#endif
else if (msave)
Strcpy(cw->morestr, msave);
else
/* special case: '0' is also the default ball class */
if (!counting && index(gacc, morc))
goto group_accel;
- /* fall through to count the zero */
+ /* fall through to count the zero */
+ /*FALLTHRU*/
case '1':
case '2':
case '3':
break;
}
/* else fall through */
+ case ' ':
case MENU_NEXT_PAGE:
if (cw->npages > 0 && curr_page != cw->npages - 1) {
curr_page++;
page_start = 0;
- } else
- finished = TRUE; /* questionable behavior */
+ } else if (morc == ' ') {
+ /* ' ' finishes menus here, but stop '>' doing the same. */
+ finished = TRUE;
+ }
break;
case MENU_PREVIOUS_PAGE:
if (cw->npages > 0 && curr_page != 0) {
tty_nhbell();
break;
} else {
- char searchbuf[BUFSZ + 2], tmpbuf[BUFSZ];
+ char searchbuf[BUFSZ + 2], tmpbuf[BUFSZ] = DUMMY;
boolean on_curr_page = FALSE;
int lineno = 0;
tty_nhbell();
break;
} else if (index(gacc, morc)) {
- group_accel:
+ group_accel:
/* group accelerator; for the PICK_ONE case, we know that
it matches exactly one item in order to be in gacc[] */
invert_all(window, page_start, page_end, morc);
struct WinDesc *cw;
{
int i, n, attr;
+#if 0 /*JP*/
+ boolean linestart;
+#endif
register char *cp;
for (n = 0, i = 0; i < cw->maxrow; i++) {
+ HUPSKIP();
if (!cw->offx && (n + cw->offy == ttyDisplay->rows - 1)) {
tty_curs(window, 1, n);
cl_end();
#if 0 /*JP*/
(void) putchar(' ');
#else
- (void) jputchar(' ');
+ (void) jputchar(' ');
#endif
++ttyDisplay->curx;
}
term_start_attr(attr);
+#if 0 /*JP*/
+ for (cp = &cw->data[i][1], linestart = TRUE;
+#else
for (cp = &cw->data[i][1];
+#endif
#ifndef WIN32CON
*cp && (int) ++ttyDisplay->curx < (int) ttyDisplay->cols;
- cp++)
+ cp++
#else
*cp && (int) ttyDisplay->curx < (int) ttyDisplay->cols;
- cp++, ttyDisplay->curx++)
+ cp++, ttyDisplay->curx++
#endif
+ ) {
+ /* message recall for msg_window:full/combination/reverse
+ might have output from '/' in it (see redotoplin()) */
#if 0 /*JP*/
- (void) putchar(*cp);
+ if (linestart && (*cp & 0x80) != 0) {
+ g_putch(*cp);
+ end_glyphout();
+ linestart = FALSE;
+ } else {
+ (void) putchar(*cp);
+ }
#else
- (void) jputchar(*cp);
+ (void) jputchar(*cp);
#endif
+ }
term_end_attr(attr);
}
}
register struct WinDesc *cw = 0;
short s_maxcol;
+ HUPSKIP();
if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
panic(winpanicstr, window);
if (cw->flags & WIN_CANCELLED)
ttyDisplay->lastwin = window;
ttyDisplay->rawprint = 0;
+ print_vt_code2(AVTC_SELECT_WINDOW, window);
+
switch (cw->type) {
case NHW_MESSAGE:
if (ttyDisplay->toplin == 1) {
tty_display_nhwindow(WIN_MESSAGE, TRUE);
return;
}
+ /*FALLTHRU*/
case NHW_BASE:
(void) fflush(stdout);
break;
if (ttyDisplay->toplin == 1)
tty_display_nhwindow(WIN_MESSAGE, TRUE);
#ifdef H2344_BROKEN
- if (cw->maxrow >= (int) ttyDisplay->rows)
+ if (cw->maxrow >= (int) ttyDisplay->rows
+ || !iflags.menu_overlay)
#else
- if (cw->offx == 10 || cw->maxrow >= (int) ttyDisplay->rows)
+ if (cw->offx == 10 || cw->maxrow >= (int) ttyDisplay->rows
+ || !iflags.menu_overlay)
#endif
{
cw->offx = 0;
- if (cw->offy) {
+ if (cw->offy || iflags.menu_overlay) {
tty_curs(window, 1, 0);
cl_eos();
} else
{
register struct WinDesc *cw = 0;
+ HUPSKIP();
if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
panic(winpanicstr, window);
+ print_vt_code2(AVTC_SELECT_WINDOW, window);
+
switch (cw->type) {
case NHW_MESSAGE:
if (ttyDisplay->toplin)
tty_display_nhwindow(WIN_MESSAGE, TRUE);
- /*FALLTHRU*/
+ /*FALLTHRU*/
case NHW_STATUS:
case NHW_BASE:
case NHW_MAP:
free_window_info(cw, TRUE);
free((genericptr_t) cw);
- wins[window] = 0;
+ wins[window] = 0; /* available for re-use */
}
void
int cx = ttyDisplay->curx;
int cy = ttyDisplay->cury;
+ HUPSKIP();
if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
panic(winpanicstr, window);
ttyDisplay->lastwin = window;
+ print_vt_code2(AVTC_SELECT_WINDOW, window);
+
#if defined(USE_TILES) && defined(MSDOS)
adjust_cursor_flags(cw);
#endif
#ifdef DEBUG
if (x < 0 || y < 0 || y >= cw->rows || x > cw->cols) {
const char *s = "[unknown type]";
+
switch (cw->type) {
case NHW_MESSAGE:
s = "[topl window]";
s = "[base window]";
break;
}
- debugpline4("bad curs positioning win %d %s (%d,%d)", window, s, x,
- y);
- return;
+ debugpline4("bad curs positioning win %d %s (%d,%d)", window, s, x, y);
+ /* This return statement caused a functional difference between
+ DEBUG and non-DEBUG operation, so it is being commented
+ out. It caused tty_curs() to fail to move the cursor to the
+ location it needed to be if the x,y range checks failed,
+ leaving the next piece of output to be displayed at whatever
+ random location the cursor happened to be at prior. */
+
+ /* return; */
}
#endif
x += cw->offx;
# if 0 /*JP*/
(void) putchar('\r');
# else
- (void) cputchar('\r');
+ (void) cputchar('\r');
# endif
ttyDisplay->curx = 0;
nocmov(x, y);
char ch;
{
register struct WinDesc *cw = 0;
-#if 1 /*JP*/
- static int prev_win;
-#endif
+ HUPSKIP();
if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0)
panic(winpanicstr, window);
+ print_vt_code2(AVTC_SELECT_WINDOW, window);
+
switch (cw->type) {
+#ifndef STATUS_HILITES
case NHW_STATUS:
+#endif
case NHW_MAP:
case NHW_BASE:
tty_curs(window, x, y);
#if 0 /*JP*/
(void) putchar(ch);
#else
- if(cw->type!=NHW_MAP)
- (void) jputchar(ch);
- else {
- (void) cputchar(ch);
- }
+ if(cw->type!=NHW_MAP)
+ (void) jputchar(ch);
+ else {
+ (void) cputchar(ch);
+ }
#endif
ttyDisplay->curx++;
cw->curx++;
impossible("Can't putsym to window type %d", cw->type);
break;
}
-#if 1 /*JP*/
- prev_win = cw->type;
-#endif
}
STATIC_OVL const char *
const char *str;
{
static char cbuf[BUFSZ];
- /* compress in case line too long */
- if ((int) strlen(str) >= CO) {
- register const char *bp0 = str;
- register char *bp1 = cbuf;
- do {
-#ifdef CLIPPING
- if (*bp0 != ' ' || bp0[1] != ' ')
-#else
- if (*bp0 != ' ' || bp0[1] != ' ' || bp0[2] != ' ')
-#endif
- *bp1++ = *bp0;
- } while (*bp0++);
- } else
- return str;
- return cbuf;
+ /* compress out consecutive spaces if line is too long;
+ topline wrapping converts space at wrap point into newline,
+ we reverse that here */
+ if ((int) strlen(str) >= CO || index(str, '\n')) {
+ const char *in_str = str;
+ char c, *outstr = cbuf, *outend = &cbuf[sizeof cbuf - 1];
+ boolean was_space = TRUE; /* True discards all leading spaces;
+ False would retain one if present */
+
+ while ((c = *in_str++) != '\0' && outstr < outend) {
+ if (c == '\n')
+ c = ' ';
+ if (was_space && c == ' ')
+ continue;
+ *outstr++ = c;
+ was_space = (c == ' ');
+ }
+ if ((was_space && outstr > cbuf) || outstr == outend)
+ --outstr; /* remove trailing space or make room for terminator */
+ *outstr = '\0';
+ str = cbuf;
+ }
+ return str;
}
void
{
register struct WinDesc *cw = 0;
register char *ob;
+ register long i, n0;
+#ifndef STATUS_HILITES
register const char *nb;
- register long i, j, n0;
+ register long j;
#if 1 /*JP*/
- int kchar2 = 0; /* if 1, kanji 2nd byte */
+ int kchar2 = 0; /* if 1, kanji 2nd byte */
+#endif
#endif
+ HUPSKIP();
/* Assume there's a real problem if the window is missing --
* probably a panic message
*/
#if 1 /*JP*/
- jputchar('\0'); /* RESET */
+ jputchar('\0'); /* RESET */
#endif
if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) {
ttyDisplay->lastwin = window;
+ print_vt_code2(AVTC_SELECT_WINDOW, window);
+
switch (cw->type) {
- case NHW_MESSAGE:
+ case NHW_MESSAGE: {
+ int suppress_history = (attr & ATR_NOHISTORY);
+
+ /* in case we ever support display attributes for topline
+ messages, clear flag mask leaving only display attr */
+ /*attr &= ~(ATR_URGENT | ATR_NOHISTORY);*/
+
/* really do this later */
#if defined(USER_SOUNDS) && defined(WIN32CON)
play_sound_for_message(str);
#endif
- update_topl(str);
+ if (!suppress_history) {
+ /* normal output; add to current top line if room, else flush
+ whatever is there to history and then write this */
+ update_topl(str);
+ } else {
+ /* put anything already on top line into history */
+ remember_topl();
+ /* write to top line without remembering what we're writing */
+ show_topl(str);
+ }
break;
-
+ }
+#ifndef STATUS_HILITES
case NHW_STATUS:
ob = &cw->data[cw->cury][j = cw->curx];
if (context.botlx)
- *ob = 0;
+ *ob = '\0';
if (!cw->cury && (int) strlen(str) >= CO) {
/* the characters before "St:" are unnecessary */
nb = index(str, ':');
break;
}
#if 0 /*JP*/
- if (*ob != *nb)
#else /* this code updates all status line at any time */
# if 0
-/* check 2-bytes character for Japanese */
-/* by issei 93/12/2 */
- uc = *((unsigned char *)nb);
- if((!(uc & 0x80) && *ob != *nb) || kflg){
- tty_putsym(WIN_STATUS, i, cw->cury, *nb);
- }
- else{
- if(*ob != *nb || *(ob+1)!= *(nb+1)){
- tty_putsym(WIN_STATUS, i, cw->cury, *nb);
- kflg = 1;
- }
- }
-# endif /* 0 */
-#define ismbchar(c) (((unsigned char)(c)) & 0x80)
-#define KANJI2 1
-#define KUPDATE 2
- if (kchar2) /* kanji 2nd byte */
- {
- if (kchar2 & KUPDATE)
- tty_putsym(WIN_STATUS, i, cw->cury, *nb);
- kchar2 = 0;
- }
- else if (ismbchar(*nb)) /* kanji 1st byte */
- {
- kchar2 = KANJI2;
- /* Kanji char must be checked as 2-bytes pair. */
- /* check i to prevent putting only kanji 1st byte at last. */
- if ((*nb != *ob || *(nb+1) != *(ob+1)) && i < n0-1)
- {
- tty_putsym(WIN_STATUS, i, cw->cury, *nb);
- kchar2 |= KUPDATE; /* must do update */
- }
- /* else nb is the same char as old, so need not to update */
- }
- /* not kanji char */
- else if (*nb != *ob)
+/* check 2-bytes character for Japanese */
+/* by issei 93/12/2 */
+ uc = *((unsigned char *)nb);
+ if((!(uc & 0x80) && *ob != *nb) || kflg){
+ tty_putsym(WIN_STATUS, i, cw->cury, *nb);
+ }
+ else{
+ if(*ob != *nb || *(ob+1)!= *(nb+1)){
+ tty_putsym(WIN_STATUS, i, cw->cury, *nb);
+ kflg = 1;
+ }
+ }
+# endif /* 0 */
+#define ismbchar(c) (((unsigned char)(c)) & 0x80)
+#define KANJI2 1
+#define KUPDATE 2
+ if (kchar2) /* kanji 2nd byte */
+ {
+ if (kchar2 & KUPDATE)
+ tty_putsym(WIN_STATUS, i, cw->cury, *nb);
+ kchar2 = 0;
+ }
+ else if (ismbchar(*nb)) /* kanji 1st byte */
+ {
+ kchar2 = KANJI2;
+ /* Kanji char must be checked as 2-bytes pair. */
+ /* check i to prevent putting only kanji 1st byte at last. */
+ if ((*nb != *ob || *(nb+1) != *(ob+1)) && i < n0-1)
+ {
+ tty_putsym(WIN_STATUS, i, cw->cury, *nb);
+ kchar2 |= KUPDATE; /* must do update */
+ }
+ /* else nb is the same char as old, so need not to update */
+ }
+ /* not kanji char */
+ else
#endif
+ if (*ob != *nb)
tty_putsym(WIN_STATUS, i, cw->cury, *nb);
if (*ob)
ob++;
(void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1);
cw->data[cw->cury][cw->cols - 1] = '\0'; /* null terminate */
-#ifdef STATUS_VIA_WINDOWPORT
- if (!iflags.use_status_hilites) {
-#endif
- cw->cury = (cw->cury + 1) % 2;
- cw->curx = 0;
-#ifdef STATUS_VIA_WINDOWPORT
- }
-#endif
+ cw->cury = (cw->cury + 1) % cw->maxrow;
+ cw->curx = 0;
break;
+#endif /* STATUS_HILITES */
case NHW_MAP:
tty_curs(window, cw->curx + 1, cw->cury);
term_start_attr(attr);
#if 0 /*JP*/
(void) putchar(*str);
#else
- (void) cputchar(*str);
+ (void) cputchar(*str);
#endif
str++;
ttyDisplay->curx++;
#if 0 /*JP*/
(void) putchar(*str);
#else
- (void) jputchar(*str);
+ (void) jputchar(*str);
#endif
str++;
ttyDisplay->curx++;
}
if (cw->data[cw->cury])
free((genericptr_t) cw->data[cw->cury]);
- n0 = strlen(str) + 1;
+ n0 = (long) strlen(str) + 1L;
ob = cw->data[cw->cury] = (char *) alloc((unsigned) n0 + 1);
*ob++ = (char) (attr + 1); /* avoid nuls, for convenience */
Strcpy(ob, str);
break;
}
#if 1 /*JP*/
- jputchar('\0'); /* RESET */
+ jputchar('\0'); /* RESET */
#endif
}
}
if (complain)
sleep(10); /* want to wait_synch() but stdin is gone */
- terminate(EXIT_FAILURE);
+ nh_terminate(EXIT_FAILURE);
}
(void) close(fd);
#ifdef notyet
const char *newstr;
char buf[4 + BUFSZ];
+ HUPSKIP();
if (str == (const char *) 0)
return;
cw->nitems++;
if (identifier->a_void) {
- int len = strlen(str);
+ int len = (int) strlen(str);
if (len >= BUFSZ) {
/* We *think* everything's coming in off at most BUFSZ bufs... */
} else
newstr = str;
- item = (tty_menu_item *) alloc(sizeof(tty_menu_item));
+ item = (tty_menu_item *) alloc(sizeof *item);
item->identifier = *identifier;
item->count = -1L;
item->selected = preselected;
MENU_UNSELECTED);
}
- /* XXX another magic number? 52 */
+ /* 52: 'a'..'z' and 'A'..'Z'; avoids selector duplication within a page */
lmax = min(52, (int) ttyDisplay->rows - 1); /* # lines per page */
cw->npages = (cw->nitems + (lmax - 1)) / lmax; /* # of pages */
+ /*
+ * TODO?
+ * For really tall page, allow 53 if '$' or '#' is present and
+ * 54 if both are. [Only for single page menu, otherwise pages
+ * without those could try to use too many letters.]
+ * Probably not worth bothering with; anyone with a display big
+ * for this to matter will likely switch from tty to curses for
+ * multi-line message window and/or persistent inventory window.
+ */
/* make sure page list is large enough */
- if (cw->plist_size < cw->npages + 1 /*need 1 slot beyond last*/) {
+ if (cw->plist_size < cw->npages + 1) { /* +1: need one slot beyond last */
if (cw->plist)
free((genericptr_t) cw->plist);
cw->plist_size = cw->npages + 1;
cw->plist = (tty_menu_item **) alloc(cw->plist_size
- * sizeof(tty_menu_item *));
+ * sizeof (tty_menu_item *));
}
cw->cols = 0; /* cols is set when the win is initialized... (why?) */
int how;
const char *mesg;
{
+ HUPSKIP();
/* "menu" without selection; use ordinary pline, no more() */
if (how == PICK_NONE) {
pline("%s", mesg);
void
tty_mark_synch()
{
+ HUPSKIP();
(void) fflush(stdout);
}
void
tty_wait_synch()
{
+ HUPSKIP();
/* we just need to make sure all windows are synch'd */
if (!ttyDisplay || ttyDisplay->rawprint) {
getret();
register int y;
register struct WinDesc *cw = wins[WIN_MAP];
+ HUPSKIP();
+#if 0 /* this optimization is not valuable enough to justify
+ abusing core internals... */
if (u.uswallow) { /* Can be done more efficiently */
swallowed(1);
+ /* without this flush, if we happen to follow --More-- displayed in
+ leftmost column, the cursor gets left in the wrong place after
+ <docorner<more<update_topl<tty_putstr calls unwind back to core */
+ flush_screen(0);
return;
}
+#endif /*0*/
#if defined(SIGWINCH) && defined(CLIPPING)
if (ymax > LI)
void
end_glyphout()
{
+ HUPSKIP();
#if defined(ASCIIGRAPH) && !defined(NO_TERMS)
if (GFlag) {
GFlag = FALSE;
{
register char ch = (char) in_ch;
+ HUPSKIP();
#if defined(ASCIIGRAPH) && !defined(NO_TERMS)
- if (SYMHANDLING(H_IBM) || iflags.eight_bit_tty) {
+ if (SYMHANDLING(H_IBM)
+ /* for DECgraphics, lower-case letters with high bit set mean
+ switch character set and render with high bit clear;
+ user might want 8-bits for other characters */
+ || (iflags.eight_bit_tty && (!SYMHANDLING(H_DEC)
+ || (in_ch & 0x7f) < 0x60))) {
/* IBM-compatible displays don't need other stuff */
# if 0 /*JP*/
(void) putchar(ch);
# else
- (void) cputchar(ch);
+ (void) cputchar(ch);
# endif
} else if (ch & 0x80) {
if (!GFlag || HE_resets_AS) {
# if 0 /*JP*/
(void) putchar((ch ^ 0x80)); /* Strip 8th bit */
# else
- (void) cputchar((ch ^ 0x80)); /* Strip 8th bit */
+ (void) cputchar((ch ^ 0x80)); /* Strip 8th bit */
# endif
} else {
if (GFlag) {
# if 0 /*JP*/
(void) putchar(ch);
# else
- (void) jputchar(ch);
+ (void) jputchar(ch);
# endif
}
clipping = TRUE;
clipx = clipy = 0;
clipxmax = CO;
- clipymax = LI - 3;
+ clipymax = LI - 1 - iflags.wc2_statuslines;
}
void
tty_cliparound(x, y)
int x, y;
{
- extern boolean restoring;
int oldx = clipx, oldy = clipy;
+ HUPSKIP();
if (!clipping)
return;
if (x < clipx + 5) {
}
if (y < clipy + 2) {
clipy = max(0, y - (clipymax - clipy) / 2);
- clipymax = clipy + (LI - 3);
+ clipymax = clipy + (LI - 1 - iflags.wc2_statuslines);
} else if (y > clipymax - 2) {
clipymax = min(ROWNO, clipymax + (clipymax - clipy) / 2);
- clipy = clipymax - (LI - 3);
+ clipy = clipymax - (LI - 1 - iflags.wc2_statuslines);
}
if (clipx != oldx || clipy != oldy) {
- if (on_level(&u.uz0, &u.uz) && !restoring)
- (void) doredraw();
+ redraw_map(); /* ask the core to resend the map window's data */
}
}
#endif /* CLIPPING */
int color;
unsigned special;
+ HUPSKIP();
#ifdef CLIPPING
if (clipping) {
if (x <= clipx || y < clipy || x >= clipxmax || y >= clipymax)
}
#endif
/* map glyph to character and color */
- (void) mapglyph(glyph, &ch, &color, &special, x, y);
+ (void) mapglyph(glyph, &ch, &color, &special, x, y, 0);
+
+ print_vt_code2(AVTC_SELECT_WINDOW, window);
/* Move the cursor. */
tty_curs(window, x, y);
+ print_vt_code3(AVTC_GLYPH_START, glyph2tile[glyph], special);
+
#ifndef NO_TERMS
if (ul_hack && ch == '_') { /* non-destructive underscore */
# if 0 /*JP*/
(void) putchar((char) ' ');
# else
- (void) cputchar((char) ' ');
+ (void) cputchar((char) ' ');
# endif
backsp();
}
/* must be after color check; term_end_color may turn off inverse too */
if (((special & MG_PET) && iflags.hilite_pet)
|| ((special & MG_OBJPILE) && iflags.hilite_pile)
- || ((special & MG_DETECT) && iflags.use_inverse)) {
+ || ((special & MG_DETECT) && iflags.use_inverse)
+ || ((special & MG_BW_LAVA) && iflags.use_inverse)) {
term_start_attr(ATR_INVERSE);
reverse_on = TRUE;
}
#endif
}
+ print_vt_code1(AVTC_GLYPH_END);
+
wins[window]->curx++; /* one character over */
ttyDisplay->curx++; /* the real cursor moved too */
}
tty_raw_print(str)
const char *str;
{
+ HUPSKIP();
if (ttyDisplay)
ttyDisplay->rawprint++;
+ print_vt_code2(AVTC_SELECT_WINDOW, NHW_BASE);
#if defined(MICRO) || defined(WIN32CON)
msmsg("%s\n", str);
#else
tty_raw_print_bold(str)
const char *str;
{
+ HUPSKIP();
if (ttyDisplay)
ttyDisplay->rawprint++;
+ print_vt_code2(AVTC_SELECT_WINDOW, NHW_BASE);
term_start_raw_bold();
#if defined(MICRO) || defined(WIN32CON)
msmsg("%s", str);
char nestbuf;
#endif
+ HUPSKIP_RESULT('\033');
+ print_vt_code1(AVTC_INLINE_SYNC);
(void) fflush(stdout);
/* Note: if raw_print() and wait_synch() get called to report terminal
* initialization problems, then wins[] and ttyDisplay might not be
*/
if (WIN_MESSAGE != WIN_ERR && wins[WIN_MESSAGE])
wins[WIN_MESSAGE]->flags &= ~WIN_STOP;
+ if (iflags.debug_fuzzer) {
+ i = randomkey();
+ } else {
#ifdef UNIX
- i = (++nesting == 1) ? tgetch()
- : (read(fileno(stdin), (genericptr_t) &nestbuf, 1)
- == 1) ? (int) nestbuf : EOF;
- --nesting;
+ i = (++nesting == 1)
+ ? tgetch()
+ : (read(fileno(stdin), (genericptr_t) &nestbuf, 1) == 1)
+ ? (int) nestbuf : EOF;
+ --nesting;
#else
- i = tgetch();
+ i = tgetch();
#endif
+ }
if (!i)
i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */
else if (i == EOF)
i = '\033'; /* same for EOF */
if (ttyDisplay && ttyDisplay->toplin == 1)
ttyDisplay->toplin = 2;
+#ifdef TTY_TILES_ESCCODES
+ {
+ /* hack to force output of the window select code */
+ int tmp = vt_tile_current_window;
+
+ vt_tile_current_window++;
+ print_vt_code2(AVTC_SELECT_WINDOW, tmp);
+ }
+#endif /* TTY_TILES_ESCCODES */
return i;
}
tty_nh_poskey(x, y, mod)
int *x, *y, *mod;
{
-#if defined(WIN32CON)
int i;
+
+ HUPSKIP_RESULT('\033');
+#if defined(WIN32CON)
(void) fflush(stdout);
/* Note: if raw_print() and wait_synch() get called to report terminal
* initialization problems, then wins[] and ttyDisplay might not be
i = '\033'; /* map NUL or EOF to ESC, nethack doesn't expect either */
if (ttyDisplay && ttyDisplay->toplin == 1)
ttyDisplay->toplin = 2;
- return i;
#else /* !WIN32CON */
nhUse(x);
nhUse(y);
nhUse(mod);
- return tty_nhgetch();
+ i = tty_nhgetch();
#endif /* ?WIN32CON */
+ return i;
}
void
{
if (dir != WININIT)
return;
-#if defined(WIN32CON)
- if (!strncmpi(windowprocs.name, "tty", 3))
- nttty_open(0);
-#endif
return;
}
video_update_positionbar(posbar);
#endif
}
-#endif
+#endif /* POSITIONBAR */
+
+
+/*
+ * +------------------+
+ * | STATUS CODE |
+ * +------------------+
+ */
+
+/*
+ * ----------------------------------------------------------------
+ * tty_status_update
+ *
+ * Called from the NetHack core and receives info hand-offs
+ * from the core, processes them, storing some information
+ * for rendering to the tty.
+ * -> make_things_fit()
+ * -> render_status()
+ *
+ * make_things_fit
+ *
+ * Called from tty_status_update(). It calls check_fields()
+ * (described next) to get the required number of columns
+ * and tries a few different ways to squish a representation
+ * of the status window values onto the 80 column tty display.
+ * ->check_fields()
+ * ->set_condition_length() - update the width of conditions
+ * ->shrink_enc() - shrink encumbrance message word
+ * ->shrink_dlvl() - reduce the width of Dlvl:42
+ *
+ * check_fields
+ *
+ * Verifies that all the fields are ready for display, and
+ * returns FALSE if called too early in the startup
+ * processing sequence. It also figures out where everything
+ * needs to go, taking the current shrinking attempts into
+ * account. It returns number of columns needed back to
+ * make_things_fit(), so make_things_fit() can make attempt
+ * to make adjustments.
+ *
+ * render_status
+ *
+ * Goes through each of the status row's fields and
+ * calls tty_putstatusfield() to place them on the display.
+ * ->tty_putstatusfield()
+ * At the end of the for-loop, the NOW values get copied
+ * to BEFORE values.
+ *
+ * tty_putstatusfield()
+ *
+ * Move the cursor to the target spot, and output the field
+ * asked for by render_status().
+ *
+ * ----------------------------------------------------------------
+ */
-#ifdef STATUS_VIA_WINDOWPORT
/*
* The following data structures come from the genl_ routines in
* src/windows.c and as such are considered to be on the window-port
* "side" of things, rather than the NetHack-core "side" of things.
*/
-
-extern const char *status_fieldnm[MAXBLSTATS];
extern const char *status_fieldfmt[MAXBLSTATS];
extern char *status_vals[MAXBLSTATS];
extern boolean status_activefields[MAXBLSTATS];
extern winid WIN_STATUS;
#ifdef STATUS_HILITES
-typedef struct hilite_data_struct {
- int thresholdtype;
- anything threshold;
- int behavior;
- int under;
- int over;
-} hilite_data_t;
-static hilite_data_t tty_status_hilites[MAXBLSTATS];
-static int tty_status_colors[MAXBLSTATS];
-
-struct color_option {
- int color;
- int attr_bits;
+#ifdef TEXTCOLOR
+STATIC_DCL int FDECL(condcolor, (long, unsigned long *));
+#endif
+STATIC_DCL int FDECL(condattr, (long, unsigned long *));
+static unsigned long *tty_colormasks;
+static long tty_condition_bits;
+static struct tty_status_fields tty_status[2][MAXBLSTATS]; /* 2: NOW,BEFORE */
+static int hpbar_percent, hpbar_color;
+static struct condition_t {
+ long mask;
+ const char *text[3]; /* 3: potential display vals, progressively shorter */
+} conditions[] = {
+ /* The sequence order of these matters */
+ { BL_MASK_STONE, { "Stone", "Ston", "Sto" } },
+ { BL_MASK_SLIME, { "Slime", "Slim", "Slm" } },
+ { BL_MASK_STRNGL, { "Strngl", "Stngl", "Str" } },
+ { BL_MASK_FOODPOIS, { "FoodPois", "Fpois", "Poi" } },
+ { BL_MASK_TERMILL, { "TermIll" , "Ill", "Ill" } },
+ { BL_MASK_BLIND, { "Blind", "Blnd", "Bl" } },
+ { BL_MASK_DEAF, { "Deaf", "Def", "Df" } },
+ { BL_MASK_STUN, { "Stun", "Stun", "St" } },
+ { BL_MASK_CONF, { "Conf", "Cnf", "Cf" } },
+ { BL_MASK_HALLU, { "Hallu", "Hal", "Hl" } },
+ { BL_MASK_LEV, { "Lev", "Lev", "Lv" } },
+ { BL_MASK_FLY, { "Fly", "Fly", "Fl" } },
+ { BL_MASK_RIDE, { "Ride", "Rid", "Rd" } },
};
-
-static void FDECL(start_color_option, (struct color_option));
-static void FDECL(end_color_option, (struct color_option));
-static void FDECL(apply_color_option, (struct color_option, const char *));
-static void FDECL(add_colored_text, (const char *, char *));
+static const char *encvals[3][6] = {
+ { "", "Burdened", "Stressed", "Strained", "Overtaxed", "Overloaded" },
+ { "", "Burden", "Stress", "Strain", "Overtax", "Overload" },
+ { "", "Brd", "Strs", "Strn", "Ovtx", "Ovld" }
+};
+#define blPAD BL_FLUSH
+#define MAX_PER_ROW 15
+/* 2 or 3 status lines */
+static const enum statusfields
+ twolineorder[3][MAX_PER_ROW] = {
+ { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN,
+ BL_SCORE, BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD },
+ { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX,
+ BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER,
+ BL_CAP, BL_CONDITION, BL_FLUSH },
+ /* third row of array isn't used for twolineorder */
+ { BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD,
+ blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD }
+},
+ /* Align moved from 1 to 2, Leveldesc+Time+Condition moved from 2 to 3 */
+ threelineorder[3][MAX_PER_ROW] = {
+ { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
+ BL_SCORE, BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD },
+ { BL_ALIGN, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX,
+ BL_AC, BL_XP, BL_EXP, BL_HD, BL_HUNGER,
+ BL_CAP, BL_FLUSH, blPAD, blPAD },
+ { BL_LEVELDESC, BL_TIME, BL_CONDITION, BL_FLUSH, blPAD, blPAD,
+ blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD }
+};
+static const enum statusfields (*fieldorder)[MAX_PER_ROW];
+
+static int finalx[3][2]; /* [rows][NOW or BEFORE] */
+static boolean windowdata_init = FALSE;
+static int cond_shrinklvl = 0;
+static int enclev = 0, enc_shrinklvl = 0;
+static int dlvl_shrinklvl = 0;
+static boolean truncation_expected = FALSE;
+#define FORCE_RESET TRUE
+#define NO_RESET FALSE
+
+/* This controls whether to skip fields that aren't
+ * flagged as requiring updating during the current
+ * render_status().
+ *
+ * Hopefully that can be confirmed as working correctly
+ * for all platforms eventually and the conditional
+ * setting below can be removed.
+ */
+static int do_field_opt =
+#if defined(DISABLE_TTY_FIELD_OPT)
+ 0;
+#else
+ 1;
#endif
+#endif /* STATUS_HILITES */
+
+/*
+ * tty_status_init()
+ * -- initialize the tty-specific data structures.
+ * -- call genl_status_init() to initialize the general data.
+ */
void
tty_status_init()
{
- int i;
+#ifdef STATUS_HILITES
+ int i, num_rows;
- /* let genl_status_init do most of the initialization */
- genl_status_init();
+ num_rows = (iflags.wc2_statuslines < 3) ? 2 : 3;
+ fieldorder = (num_rows != 3) ? twolineorder : threelineorder;
for (i = 0; i < MAXBLSTATS; ++i) {
-#ifdef STATUS_HILITES
- tty_status_colors[i] = NO_COLOR; /* no color */
- tty_status_hilites[i].thresholdtype = 0;
- tty_status_hilites[i].behavior = BL_TH_NONE;
- tty_status_hilites[i].under = BL_HILITE_NONE;
- tty_status_hilites[i].over = BL_HILITE_NONE;
-#endif /* STATUS_HILITES */
+ tty_status[NOW][i].idx = BL_FLUSH;
+ tty_status[NOW][i].color = NO_COLOR; /* no color */
+ tty_status[NOW][i].attr = ATR_NONE;
+ tty_status[NOW][i].x = tty_status[NOW][i].y = 0;
+ tty_status[NOW][i].valid = FALSE;
+ tty_status[NOW][i].dirty = FALSE;
+ tty_status[NOW][i].redraw = FALSE;
+ tty_status[NOW][i].sanitycheck = FALSE;
+ tty_status[BEFORE][i] = tty_status[NOW][i];
}
+ tty_condition_bits = 0L;
+ hpbar_percent = 0, hpbar_color = NO_COLOR;
+#endif /* STATUS_HILITES */
+
+ /* let genl_status_init do most of the initialization */
+ genl_status_init();
+}
+
+void
+tty_status_enablefield(fieldidx, nm, fmt, enable)
+int fieldidx;
+const char *nm;
+const char *fmt;
+boolean enable;
+{
+ genl_status_enablefield(fieldidx, nm, fmt, enable);
}
+#ifdef STATUS_HILITES
+
/*
* *_status_update()
* -- update the value of a status field.
* BL_LEVELDESC, BL_EXP, BL_CONDITION
* -- fldindex could also be BL_FLUSH (-1), which is not really
* a field index, but is a special trigger to tell the
+ * windowport that it should output all changes received
+ * to this point. It marks the end of a bot() cycle.
+ * -- fldindex could also be BL_RESET (-3), which is not really
+ * a field index, but is a special advisory to to tell the
* windowport that it should redisplay all its status fields,
* even if no changes have been presented to it.
* -- ptr is usually a "char *", unless fldindex is BL_CONDITION.
* If fldindex is BL_CONDITION, then ptr is a long value with
* any or none of the following bits set (from botl.h):
- * BL_MASK_BLIND 0x00000001L
- * BL_MASK_CONF 0x00000002L
- * BL_MASK_FOODPOIS 0x00000004L
- * BL_MASK_ILL 0x00000008L
- * BL_MASK_HALLU 0x00000010L
- * BL_MASK_STUNNED 0x00000020L
- * BL_MASK_SLIMED 0x00000040L
- * -- The value passed for BL_GOLD includes a leading
- * symbol for GOLD "$:nnn". If the window port needs to use
- * the textual gold amount without the leading "$:" the port
- * will have to add 2 to the passed "ptr" for the BL_GOLD case.
+ * BL_MASK_STONE 0x00000001L
+ * BL_MASK_SLIME 0x00000002L
+ * BL_MASK_STRNGL 0x00000004L
+ * BL_MASK_FOODPOIS 0x00000008L
+ * BL_MASK_TERMILL 0x00000010L
+ * BL_MASK_BLIND 0x00000020L
+ * BL_MASK_DEAF 0x00000040L
+ * BL_MASK_STUN 0x00000080L
+ * BL_MASK_CONF 0x00000100L
+ * BL_MASK_HALLU 0x00000200L
+ * BL_MASK_LEV 0x00000400L
+ * BL_MASK_FLY 0x00000800L
+ * BL_MASK_RIDE 0x00001000L
+ * -- The value passed for BL_GOLD usually includes an encoded leading
+ * symbol for GOLD "\GXXXXNNNN:nnn". If the window port needs to use
+ * the textual gold amount without the leading "$:" the port will
+ * have to skip past ':' in the passed "ptr" for the BL_GOLD case.
+ * -- color is an unsigned int.
+ * color_index = color & 0x00FF; CLR_* value
+ * attribute = (color >> 8) & 0x00FF; HL_ATTCLR_* mask
+ * This holds the color and attribute that the field should
+ * be displayed in.
+ * This is relevant for everything except BL_CONDITION fldindex.
+ * If fldindex is BL_CONDITION, this parameter should be ignored,
+ * as condition highlighting is done via the next colormasks
+ * parameter instead.
+ *
+ * -- colormasks - pointer to cond_hilites[] array of colormasks.
+ * Only relevant for BL_CONDITION fldindex. The window port
+ * should ignore this parameter for other fldindex values.
+ * Each condition bit must only ever appear in one of the
+ * CLR_ array members, but can appear in multiple HL_ATTCLR_
+ * offsets (because more than one attribute can co-exist).
+ * See doc/window.doc for more details.
*/
+
void
-tty_status_update(fldidx, ptr, chg, percent)
-int fldidx, chg, percent;
+tty_status_update(fldidx, ptr, chg, percent, color, colormasks)
+int fldidx, chg UNUSED, percent, color;
genericptr_t ptr;
+unsigned long *colormasks;
{
- long cond, *condptr = (long *) ptr;
- register int i;
+ int attrmask;
+ long *condptr = (long *) ptr;
char *text = (char *) ptr;
- /* Mapping BL attributes to tty attributes
- * BL_HILITE_NONE -1 + 3 = 2 (statusattr[2])
- * BL_HILITE_INVERSE -2 + 3 = 1 (statusattr[1])
- * BL_HILITE_BOLD -3 + 3 = 0 (statusattr[0])
- */
- int statusattr[] = { ATR_BOLD, ATR_INVERSE, ATR_NONE };
- int attridx = 0;
- long value = -1L;
- static boolean beenhere = FALSE;
- enum statusfields fieldorder[2][15] = {
- { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN,
- BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH,
- BL_FLUSH },
- { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX,
- BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER,
- BL_CAP, BL_CONDITION, BL_FLUSH }
- };
+ char goldbuf[40], *lastchar, *p;
+ const char *fmt;
+ boolean reset_state = NO_RESET;
- if (fldidx != BL_FLUSH) {
- if (!status_activefields[fldidx])
- return;
- switch (fldidx) {
- case BL_CONDITION:
- cond = *condptr;
- *status_vals[fldidx] = '\0';
- if (cond & BL_MASK_BLIND)
- Strcat(status_vals[fldidx], " Blind");
- if (cond & BL_MASK_CONF)
- Strcat(status_vals[fldidx], " Conf");
- if (cond & BL_MASK_FOODPOIS)
- Strcat(status_vals[fldidx], " FoodPois");
- if (cond & BL_MASK_ILL)
- Strcat(status_vals[fldidx], " Ill");
- if (cond & BL_MASK_STUNNED)
- Strcat(status_vals[fldidx], " Stun");
- if (cond & BL_MASK_HALLU)
- Strcat(status_vals[fldidx], " Hallu");
- if (cond & BL_MASK_SLIMED)
- Strcat(status_vals[fldidx], " Slime");
- value = cond;
- break;
- default:
- value = atol(text);
- Sprintf(status_vals[fldidx],
- status_fieldfmt[fldidx] ? status_fieldfmt[fldidx] : "%s",
- text);
- break;
+ if ((fldidx < BL_RESET) || (fldidx >= MAXBLSTATS))
+ return;
+
+ if ((fldidx >= 0 && fldidx < MAXBLSTATS) && !status_activefields[fldidx])
+ return;
+
+ switch (fldidx) {
+ case BL_RESET:
+ reset_state = FORCE_RESET;
+ /*FALLTHRU*/
+ case BL_FLUSH:
+ if (make_things_fit(reset_state) || truncation_expected) {
+ render_status();
+#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
+ status_sanity_check();
+#endif
}
+ return;
+ case BL_CONDITION:
+ tty_status[NOW][fldidx].idx = fldidx;
+ tty_condition_bits = *condptr;
+ tty_colormasks = colormasks;
+ tty_status[NOW][fldidx].valid = TRUE;
+ tty_status[NOW][fldidx].dirty = TRUE;
+ tty_status[NOW][fldidx].sanitycheck = TRUE;
+ truncation_expected = FALSE;
+ break;
+ case BL_GOLD:
+ text = decode_mixed(goldbuf, text);
+ /*FALLTHRU*/
+ default:
+ attrmask = (color >> 8) & 0x00FF;
+#ifndef TEXTCOLOR
+ color = NO_COLOR;
+#endif
+ fmt = status_fieldfmt[fldidx];
+ if (!fmt)
+ fmt = "%s";
+ /* should be checking for first enabled field here rather than
+ just first field, but 'fieldorder' doesn't start any rows
+ with fields which can be disabled so [any_row][0] suffices */
+ if (*fmt == ' ' && (fldidx == fieldorder[0][0]
+ || fldidx == fieldorder[1][0]
+ || fldidx == fieldorder[2][0]))
+ ++fmt; /* skip leading space for first field on line */
+ Sprintf(status_vals[fldidx], fmt, text);
+ tty_status[NOW][fldidx].idx = fldidx;
+ tty_status[NOW][fldidx].color = (color & 0x00FF);
+ tty_status[NOW][fldidx].attr = term_attr_fixup(attrmask);
+ tty_status[NOW][fldidx].lth = strlen(status_vals[fldidx]);
+ tty_status[NOW][fldidx].valid = TRUE;
+ tty_status[NOW][fldidx].dirty = TRUE;
+ tty_status[NOW][fldidx].sanitycheck = TRUE;
+ break;
+ }
-#ifdef STATUS_HILITES
- switch (tty_status_hilites[fldidx].behavior) {
- case BL_TH_NONE:
- tty_status_colors[fldidx] = NO_COLOR;
- break;
- case BL_TH_UPDOWN:
- if (chg > 0)
- tty_status_colors[fldidx] = tty_status_hilites[fldidx].over;
- else if (chg < 0)
- tty_status_colors[fldidx] = tty_status_hilites[fldidx].under;
- else
- tty_status_colors[fldidx] = NO_COLOR;
- break;
- case BL_TH_VAL_PERCENTAGE: {
- int pct_th = 0;
+ /* The core botl engine sends a single blank to the window port
+ for carrying-capacity when its unused. Let's suppress that */
+ if (fldidx >= 0 && fldidx < MAXBLSTATS
+ && tty_status[NOW][fldidx].lth == 1
+ && status_vals[fldidx][0] == ' ') {
+ status_vals[fldidx][0] = '\0';
+ tty_status[NOW][fldidx].lth = 0;
+ }
- if (tty_status_hilites[fldidx].thresholdtype != ANY_INT) {
- impossible(
- "tty_status_update: unsupported percentage threshold type %d",
- tty_status_hilites[fldidx].thresholdtype);
- } else {
- pct_th = tty_status_hilites[fldidx].threshold.a_int;
- tty_status_colors[fldidx] = (percent >= pct_th)
- ? tty_status_hilites[fldidx].over
- : tty_status_hilites[fldidx].under;
+ /* default processing above was required before these */
+ switch (fldidx) {
+ case BL_HP:
+ if (iflags.wc2_hitpointbar) {
+ /* Special additional processing for hitpointbar */
+ hpbar_percent = percent;
+ hpbar_color = (color & 0x00FF);
+ tty_status[NOW][BL_TITLE].color = hpbar_color;
+ tty_status[NOW][BL_TITLE].dirty = TRUE;
+ }
+ break;
+ case BL_LEVELDESC:
+ dlvl_shrinklvl = 0; /* caller is passing full length string */
+ /*FALLTHRU*/
+ case BL_HUNGER:
+ /* The core sends trailing blanks for some fields.
+ Let's suppress the trailing blanks */
+ if (tty_status[NOW][fldidx].lth > 0) {
+ p = status_vals[fldidx];
+ for (lastchar = eos(p); lastchar > p && *--lastchar == ' '; ) {
+ *lastchar = '\0';
+ tty_status[NOW][fldidx].lth--;
}
+ }
+ break;
+ case BL_TITLE:
+ /* when hitpointbar is enabled, rendering will enforce a length
+ of 30 on title, padding with spaces or truncating if necessary */
+ if (iflags.wc2_hitpointbar)
+ tty_status[NOW][fldidx].lth = 30 + 2; /* '[' and ']' */
+ break;
+ case BL_GOLD:
+ /* \GXXXXNNNN counts as 1 [moot since we use decode_mixed() above] */
+ if ((p = index(status_vals[fldidx], '\\')) != 0 && p[1] == 'G')
+ tty_status[NOW][fldidx].lth -= (10 - 1);
+ break;
+ case BL_CAP:
+ enc_shrinklvl = 0; /* caller is passing full length string */
+ enclev = stat_cap_indx();
+ break;
+ }
+ /* As of 3.6.2 we only render on BL_FLUSH (or BL_RESET) */
+ return;
+}
+
+STATIC_OVL int
+make_things_fit(force_update)
+boolean force_update;
+{
+ int trycnt, fitting = 0, requirement;
+ int rowsz[3], num_rows, condrow, otheroptions = 0;
+
+ num_rows = (iflags.wc2_statuslines < 3) ? 2 : 3;
+ condrow = num_rows - 1; /* always last row, 1 for 0..1 or 2 for 0..2 */
+ cond_shrinklvl = 0;
+ if (enc_shrinklvl > 0 && num_rows == 2)
+ shrink_enc(0);
+ if (dlvl_shrinklvl > 0)
+ shrink_dlvl(0);
+ set_condition_length();
+ for (trycnt = 0; trycnt < 6 && !fitting; ++trycnt) {
+ /* FIXME: this remeasures each line every time even though it
+ is only attempting to shrink one of them and the other one
+ (or two) remains the same */
+ if (!check_fields(force_update, rowsz)) {
+ fitting = 0;
break;
}
- case BL_TH_VAL_ABSOLUTE: {
- int c = NO_COLOR;
- int o = tty_status_hilites[fldidx].over;
- int u = tty_status_hilites[fldidx].under;
- anything *t = &tty_status_hilites[fldidx].threshold;
- switch (tty_status_hilites[fldidx].thresholdtype) {
- case ANY_LONG:
- c = (value >= t->a_long) ? o : u;
- break;
- case ANY_INT:
- c = (value >= t->a_int) ? o : u;
- break;
- case ANY_UINT:
- c = ((unsigned long) value >= t->a_uint) ? o : u;
- break;
- case ANY_ULONG:
- c = ((unsigned long) value >= t->a_ulong) ? o : u;
- break;
- case ANY_MASK32:
- c = (value & t->a_ulong) ? o : u;
- break;
- default:
- impossible(
- "tty_status_update: unsupported absolute threshold type %d\n",
- tty_status_hilites[fldidx].thresholdtype);
+ requirement = rowsz[condrow] - 1;
+ if (requirement <= wins[WIN_STATUS]->cols - 1) {
+ fitting = requirement;
+ break; /* we're good */
+ }
+ if (trycnt < 2) {
+ if (cond_shrinklvl < trycnt + 1) {
+ cond_shrinklvl = trycnt + 1;
+ set_condition_length();
+ }
+ continue;
+ }
+ if (cond_shrinklvl >= 2) {
+ /* We've exhausted the condition identifiers shrinkage,
+ * so let's try shrinking other things...
+ */
+ if (otheroptions < 2) {
+ /* try shrinking the encumbrance word, but
+ only when it's on the same line as conditions */
+ if (num_rows == 2)
+ shrink_enc(otheroptions + 1);
+ } else if (otheroptions == 2) {
+ shrink_dlvl(1);
+ } else {
+ /* Last resort - turn on trunction */
+ truncation_expected = TRUE;
break;
}
- tty_status_colors[fldidx] = c;
- break;
- } /* case */
- } /* switch */
-#endif /* STATUS_HILITES */
+ ++otheroptions;
+ }
}
+ return fitting;
+}
- /* For now, this version copied from the genl_ version currently
- * updates everything on the display, everytime
- */
+/*
+ * This is the routine where we figure out where each field
+ * should be placed, and flag whether the on-screen details
+ * must be updated because they need to change.
+ * This is now done at an individual field case-by-case level.
+ */
+STATIC_OVL boolean
+check_fields(forcefields, sz)
+boolean forcefields;
+int sz[3];
+{
+ int c, i, row, col, num_rows, idx;
+ boolean valid = TRUE, matchprev, update_right;
- if (!beenhere || !iflags.use_status_hilites) {
- char newbot1[MAXCO], newbot2[MAXCO];
+ if (!windowdata_init && !check_windowdata())
+ return FALSE;
- newbot1[0] = '\0';
- for (i = 0; fieldorder[0][i] >= 0; ++i) {
- int idx1 = fieldorder[0][i];
+ num_rows = (iflags.wc2_statuslines < 3) ? 2 : 3;
- if (status_activefields[idx1])
- Strcat(newbot1, status_vals[idx1]);
- }
- newbot2[0] = '\0';
- for (i = 0; fieldorder[1][i] >= 0; ++i) {
- int idx2 = fieldorder[1][i];
+ for (row = 0; row < num_rows; ++row) {
+ sz[row] = 0;
+ col = 1;
+ update_right = FALSE;
+ for (i = 0; (idx = fieldorder[row][i]) != BL_FLUSH; ++i) {
+ if (!status_activefields[idx])
+ continue;
+ if (!tty_status[NOW][idx].valid)
+ valid = FALSE;
+ /* might be called more than once for shrink tests, so need
+ to reset these (redraw and x at any rate) each time */
+ tty_status[NOW][idx].redraw = FALSE;
+ tty_status[NOW][idx].y = row;
+ tty_status[NOW][idx].x = col;
+
+ /* On a change to the field location, everything further
+ to the right must be updated as well. (Not necessarily
+ everything; it's possible for complementary changes across
+ multiple fields to put stuff further right back in sync.) */
+ if (tty_status[NOW][idx].x + tty_status[NOW][idx].lth
+ != tty_status[BEFORE][idx].x + tty_status[BEFORE][idx].lth)
+ update_right = TRUE;
+ else if (tty_status[NOW][idx].lth != tty_status[BEFORE][idx].lth
+ || tty_status[NOW][idx].x != tty_status[BEFORE][idx].x)
+ tty_status[NOW][idx].redraw = TRUE;
+ else /* in case update_right is set, we're back in sync now */
+ update_right = FALSE;
+
+ matchprev = FALSE; /* assume failure */
+ if (valid && !update_right && !forcefields
+ && !tty_status[NOW][idx].redraw) {
+ /*
+ * Check values against those already on the display.
+ * - Is the additional processing time for this worth it?
+ */
+ if (do_field_opt
+ /* color/attr checks aren't right for 'condition'
+ and neither is examining status_vals[BL_CONDITION]
+ so skip same-contents optimization for conditions */
+ && idx != BL_CONDITION
+ && (tty_status[NOW][idx].color
+ == tty_status[BEFORE][idx].color)
+ && (tty_status[NOW][idx].attr
+ == tty_status[BEFORE][idx].attr)) {
+ matchprev = TRUE; /* assume success */
+ if (tty_status[NOW][idx].dirty) {
+ /* compare values */
+ const char *ob, *nb; /* old byte, new byte */
+ struct WinDesc *cw = wins[WIN_STATUS];
+
+ c = col - 1;
+ ob = &cw->data[row][c];
+ nb = status_vals[idx];
+ while (*nb && c < cw->cols) {
+ if (*nb != *ob)
+ break;
+ nb++;
+ ob++;
+ c++;
+ }
+ /* if we're not at the end of new string, no match;
+ we don't need to worry about whether there might
+ be leftover old string; that could only happen
+ if they have different lengths, in which case
+ 'update_right' will be set and we won't get here */
+ if (*nb)
+ matchprev = FALSE;
+#if 0
+ if (*nb || (*ob && *ob != ' '
+ && (*ob != '/' || idx != BL_XP)
+ && (*ob != '(' || (idx != BL_HP
+ && idx != BL_ENE))))
+ matchprev = FALSE;
+#endif
+ }
+ }
+ }
+
+ if (forcefields || update_right
+ || (tty_status[NOW][idx].dirty && !matchprev))
+ tty_status[NOW][idx].redraw = TRUE;
- if (status_activefields[idx2])
- Strcat(newbot2, status_vals[idx2]);
+ col += tty_status[NOW][idx].lth;
}
+ sz[row] = col;
+ }
+ return valid;
+}
- curs(WIN_STATUS, 1, 0);
- putstr(WIN_STATUS, 0, newbot1);
- curs(WIN_STATUS, 1, 1);
- putmixed(WIN_STATUS, 0, newbot2); /* putmixed() due to GOLD glyph */
- beenhere = TRUE;
+#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
+STATIC_OVL void
+status_sanity_check(VOID_ARGS)
+{
+ int i;
+ static boolean in_sanity_check = FALSE;
+ static const char *const idxtext[] = {
+ "BL_TITLE", "BL_STR", "BL_DX", "BL_CO", "BL_IN", "BL_WI", /* 0.. 5 */
+ "BL_CH","BL_ALIGN", "BL_SCORE", "BL_CAP", "BL_GOLD", /* 6.. 10 */
+ "BL_ENE", "BL_ENEMAX", "BL_XP", "BL_AC", "BL_HD", /* 11.. 15 */
+ "BL_TIME", "BL_HUNGER", "BL_HP", "BL_HPMAX", /* 16.. 19 */
+ "BL_LEVELDESC", "BL_EXP", "BL_CONDITION" /* 20.. 22 */
+ };
+
+ if (in_sanity_check)
return;
+ in_sanity_check = TRUE;
+ /*
+ * Make sure that every field made it down to the
+ * bottom of the render_status() for-loop.
+ */
+ for (i = 0; i < MAXBLSTATS; ++i) {
+ if (tty_status[NOW][i].sanitycheck) {
+ char panicmsg[BUFSZ];
+
+ Sprintf(panicmsg, "failed on tty_status[NOW][%s].", idxtext[i]);
+ paniclog("status_sanity_check", panicmsg);
+ tty_status[NOW][i].sanitycheck = FALSE;
+ /*
+ * Attention developers: If you encounter the above
+ * message in paniclog, it almost certainly means that
+ * a recent code change has caused a failure to reach
+ * the bottom of render_status(), at least for the BL_
+ * field identified in the impossible() message.
+ *
+ * That could be because of the addition of a continue
+ * statement within the render_status() for-loop, or a
+ * premature return from render_status() before it finished
+ * its housekeeping chores.
+ */
+ }
}
+ in_sanity_check = FALSE;
+}
+#endif /* NHDEVEL_STATUS */
+
+/*
+ * This is what places a field on the tty display.
+ */
+STATIC_OVL void
+tty_putstatusfield(text, x, y)
+const char *text;
+int x, y;
+{
+ int i, n, ncols, nrows, lth = 0;
+ struct WinDesc *cw = 0;
- curs(WIN_STATUS, 1, 0);
- for (i = 0; fieldorder[0][i] != BL_FLUSH; ++i) {
- int fldidx1 = fieldorder[0][i];
+ if (WIN_STATUS == WIN_ERR
+ || (cw = wins[WIN_STATUS]) == (struct WinDesc *) 0)
+ panic("tty_putstatusfield: Invalid WinDesc\n");
- if (status_activefields[fldidx1]) {
- if (tty_status_colors[fldidx1] < 0 &&
- tty_status_colors[fldidx1] >= -3) {
- /* attribute, not a color */
- attridx = tty_status_colors[fldidx1] + 3;
- term_start_attr(statusattr[attridx]);
- putstr(WIN_STATUS, 0, status_vals[fldidx1]);
- term_end_attr(statusattr[attridx]);
-#ifdef TEXTCOLOR
- } else if (tty_status_colors[fldidx1] != CLR_MAX) {
- if (tty_status_colors[fldidx1] != NO_COLOR)
- term_start_color(tty_status_colors[fldidx1]);
- putstr(WIN_STATUS, 0, status_vals[fldidx1]);
- if (tty_status_colors[fldidx1] != NO_COLOR)
- term_end_color();
+ ncols = cw->cols;
+ nrows = cw->maxrow;
+ lth = (int) strlen(text);
+
+ print_vt_code2(AVTC_SELECT_WINDOW, NHW_STATUS);
+
+ if (x < ncols && y < nrows) {
+ if (x != cw->curx || y != cw->cury)
+ tty_curs(NHW_STATUS, x, y);
+ for (i = 0; i < lth; ++i) {
+ n = i + x;
+ if (n < ncols && *text) {
+#if 0 /*JP*/
+ (void) putchar(*text);
+#else
+ (void) jputchar(*(unsigned char *)text);
#endif
- } else
- putstr(WIN_STATUS, 0, status_vals[fldidx1]);
+ ttyDisplay->curx++;
+ cw->curx++;
+ cw->data[y][n - 1] = *text;
+ text++;
+ }
+ }
+ }
+#if 0
+ else {
+ if (truncation_expected) {
+ /* Now we're truncating */
+ ; /* but we knew in advance */
}
}
- curs(WIN_STATUS, 1, 1);
- for (i = 0; fieldorder[1][i] != BL_FLUSH; ++i) {
- int fldidx2 = fieldorder[1][i];
-
- if (status_activefields[fldidx2]) {
- if (tty_status_colors[fldidx2] < 0 &&
- tty_status_colors[fldidx2] >= -3) {
- /* attribute, not a color */
- attridx = tty_status_colors[fldidx2] + 3;
- term_start_attr(statusattr[attridx]);
- putstr(WIN_STATUS, 0, status_vals[fldidx2]);
- term_end_attr(statusattr[attridx]);
-#ifdef TEXTCOLOR
- } else if (tty_status_colors[fldidx2] != CLR_MAX) {
- if (tty_status_colors[fldidx2] != NO_COLOR)
- term_start_color(tty_status_colors[fldidx2]);
- if (fldidx2 == BL_GOLD) {
- /* putmixed() due to GOLD glyph */
- putmixed(WIN_STATUS, 0, status_vals[fldidx2]);
- } else {
- putstr(WIN_STATUS, 0, status_vals[fldidx2]);
- }
- if (tty_status_colors[fldidx2] != NO_COLOR)
- term_end_color();
#endif
- } else
- putstr(WIN_STATUS, 0, status_vals[fldidx2]);
+}
+
+/* caller must set cond_shrinklvl (0..2) before calling us */
+STATIC_OVL void
+set_condition_length()
+{
+ long mask;
+ int c, lth = 0;
+
+ if (tty_condition_bits) {
+ for (c = 0; c < SIZE(conditions); ++c) {
+ mask = conditions[c].mask;
+ if ((tty_condition_bits & mask) == mask)
+ lth += 1 + (int) strlen(conditions[c].text[cond_shrinklvl]);
}
}
- return;
+ tty_status[NOW][BL_CONDITION].lth = lth;
+}
+
+STATIC_OVL void
+shrink_enc(lvl)
+int lvl;
+{
+ /* shrink or restore the encumbrance word */
+ if (lvl <= 2) {
+ enc_shrinklvl = lvl;
+ Sprintf(status_vals[BL_CAP], " %s", encvals[lvl][enclev]);
+ }
+ tty_status[NOW][BL_CAP].lth = strlen(status_vals[BL_CAP]);
+}
+
+STATIC_OVL void
+shrink_dlvl(lvl)
+int lvl;
+{
+ /* try changing Dlvl: to Dl: */
+ char buf[BUFSZ];
+ char *levval = index(status_vals[BL_LEVELDESC], ':');
+
+ if (levval) {
+ dlvl_shrinklvl = lvl;
+ Strcpy(buf, (lvl == 0) ? "Dlvl" : "Dl");
+ Strcat(buf, levval);
+ Strcpy(status_vals[BL_LEVELDESC], buf);
+ tty_status[NOW][BL_LEVELDESC].lth = strlen(status_vals[BL_LEVELDESC]);
+ }
}
-#ifdef STATUS_HILITES
/*
- * status_threshold(int fldidx, int threshholdtype, anything threshold,
- * int behavior, int under, int over)
- *
- * -- called when a hiliting preference is added, changed, or
- * removed.
- * -- the fldindex identifies which field is having its hiliting
- * preference set. It is an integer index value from botl.h
- * -- fldindex could be any one of the following from botl.h:
- * BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
- * BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX,
- * BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX,
- * BL_LEVELDESC, BL_EXP, BL_CONDITION
- * -- datatype is P_INT, P_UINT, P_LONG, or P_MASK.
- * -- threshold is an "anything" union which can contain the
- * datatype value.
- * -- behavior is used to define how threshold is used and can
- * be BL_TH_NONE, BL_TH_VAL_PERCENTAGE, BL_TH_VAL_ABSOLUTE,
- * or BL_TH_UPDOWN. BL_TH_NONE means don't do anything above
- * or below the threshold. BL_TH_VAL_PERCENTAGE treats the
- * threshold value as a precentage of the maximum possible
- * value. BL_TH_VAL_ABSOLUTE means that the threshold is an
- * actual value. BL_TH_UPDOWN means that threshold is not
- * used, and the two below/above hilite values indicate how
- * to display something going down (under) or rising (over).
- * -- under is the hilite attribute used if value is below the
- * threshold. The attribute can be BL_HILITE_NONE,
- * BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one
- * of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN,
- * CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY,
- * CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE,
- * CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15).
- * -- over is the hilite attribute used if value is at or above
- * the threshold. The attribute can be BL_HILITE_NONE,
- * BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one
- * of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN,
- * CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY,
- * CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE,
- * CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15).
+ * Ensure the underlying status window data start out
+ * blank and null-terminated.
*/
-void
-tty_status_threshold(fldidx, thresholdtype, threshold, behavior, under, over)
-int fldidx, thresholdtype;
-int behavior, under, over;
-anything threshold;
-{
- tty_status_hilites[fldidx].thresholdtype = thresholdtype;
- tty_status_hilites[fldidx].threshold = threshold;
- tty_status_hilites[fldidx].behavior = behavior;
- tty_status_hilites[fldidx].under = under;
- tty_status_hilites[fldidx].over = over;
+STATIC_OVL boolean
+check_windowdata(VOID_ARGS)
+{
+ if (WIN_STATUS == WIN_ERR || wins[WIN_STATUS] == (struct WinDesc *) 0) {
+ paniclog("check_windowdata", " null status window.");
+ return FALSE;
+ } else if (!windowdata_init) {
+ tty_clear_nhwindow(WIN_STATUS); /* also sets cw->data[] to spaces */
+ windowdata_init = TRUE;
+ }
+ return TRUE;
+}
+
+#ifdef TEXTCOLOR
+/*
+ * Return what color this condition should
+ * be displayed in based on user settings.
+ */
+STATIC_OVL int
+condcolor(bm, bmarray)
+long bm;
+unsigned long *bmarray;
+{
+ int i;
+
+ if (bm && bmarray)
+ for (i = 0; i < CLR_MAX; ++i) {
+ if ((bm & bmarray[i]) != 0)
+ return i;
+ }
+ return NO_COLOR;
+}
+#else
+/* might need something more elaborate if some compiler complains that
+ the condition where this gets used always has the same value */
+#define condcolor(bm,bmarray) NO_COLOR
+#define term_start_color(color) /*empty*/
+#define term_end_color() /*empty*/
+#endif /* TEXTCOLOR */
+
+STATIC_OVL int
+condattr(bm, bmarray)
+long bm;
+unsigned long *bmarray;
+{
+ int attr = 0;
+ int i;
+
+ if (bm && bmarray) {
+ for (i = HL_ATTCLR_DIM; i < BL_ATTCLR_MAX; ++i) {
+ if ((bm & bmarray[i]) != 0) {
+ switch (i) {
+ case HL_ATTCLR_DIM:
+ attr |= HL_DIM;
+ break;
+ case HL_ATTCLR_BLINK:
+ attr |= HL_BLINK;
+ break;
+ case HL_ATTCLR_ULINE:
+ attr |= HL_ULINE;
+ break;
+ case HL_ATTCLR_INVERSE:
+ attr |= HL_INVERSE;
+ break;
+ case HL_ATTCLR_BOLD:
+ attr |= HL_BOLD;
+ break;
+ }
+ }
+ }
+ }
+ return attr;
+}
+
+#define Begin_Attr(m) \
+ do { \
+ if (m) { \
+ if ((m) & HL_BOLD) \
+ term_start_attr(ATR_BOLD); \
+ if ((m) & HL_INVERSE) \
+ term_start_attr(ATR_INVERSE); \
+ if ((m) & HL_ULINE) \
+ term_start_attr(ATR_ULINE); \
+ if ((m) & HL_BLINK) \
+ term_start_attr(ATR_BLINK); \
+ if ((m) & HL_DIM) \
+ term_start_attr(ATR_DIM); \
+ } \
+ } while (0)
+
+#define End_Attr(m) \
+ do { \
+ if (m) { \
+ if ((m) & HL_DIM) \
+ term_end_attr(ATR_DIM); \
+ if ((m) & HL_BLINK) \
+ term_end_attr(ATR_BLINK); \
+ if ((m) & HL_ULINE) \
+ term_end_attr(ATR_ULINE); \
+ if ((m) & HL_INVERSE) \
+ term_end_attr(ATR_INVERSE); \
+ if ((m) & HL_BOLD) \
+ term_end_attr(ATR_BOLD); \
+ } \
+ } while (0)
+
+STATIC_OVL void
+render_status(VOID_ARGS)
+{
+ long mask, bits;
+ int i, x, y, idx, c, row, tlth, num_rows, coloridx = 0, attrmask = 0;
+ char *text;
+ struct WinDesc *cw = 0;
+
+ if (WIN_STATUS == WIN_ERR
+ || (cw = wins[WIN_STATUS]) == (struct WinDesc *) 0) {
+ paniclog("render_status", "WIN_ERR on status window.");
+ return;
+ }
+
+ num_rows = (iflags.wc2_statuslines < 3) ? 2 : 3;
+ for (row = 0; row < num_rows; ++row) {
+ HUPSKIP();
+ y = row;
+ tty_curs(WIN_STATUS, 1, y);
+ for (i = 0; (idx = fieldorder[row][i]) != BL_FLUSH; ++i) {
+ if (!status_activefields[idx])
+ continue;
+ x = tty_status[NOW][idx].x;
+ text = status_vals[idx]; /* always "" for BL_CONDITION */
+ tlth = (int) tty_status[NOW][idx].lth; /* valid for BL_CONDITION */
+
+ if (tty_status[NOW][idx].redraw || !do_field_opt) {
+ boolean hitpointbar = (idx == BL_TITLE
+ && iflags.wc2_hitpointbar);
+
+ if (idx == BL_CONDITION) {
+ /*
+ * +-----------------+
+ * | Condition Codes |
+ * +-----------------+
+ */
+ bits = tty_condition_bits;
+ /* if no bits are set, we can fall through condition
+ rendering code to finalx[] handling (and subsequent
+ rest-of-line erasure if line is shorter than before) */
+ if (num_rows == 3 && bits != 0L) {
+ int k;
+ char *dat = &cw->data[y][0];
+
+ /* line up with hunger (or where it would have
+ been when currently omitted); if there isn't
+ enough room for that, right justify; or place
+ as-is if not even enough room for /that/; we
+ expect hunger to be on preceding row, in which
+ case its current data has been moved to [BEFORE] */
+ if (tty_status[BEFORE][BL_HUNGER].y < row
+ && x < tty_status[BEFORE][BL_HUNGER].x
+ && (tty_status[BEFORE][BL_HUNGER].x + tlth
+ < cw->cols - 1))
+ k = tty_status[BEFORE][BL_HUNGER].x;
+ else if (x + tlth < cw->cols - 1)
+ k = cw->cols - tlth;
+ else
+ k = x;
+ while (x < k) {
+ if (dat[x - 1] != ' ')
+ tty_putstatusfield(" ", x, y);
+ ++x;
+ }
+ tty_status[NOW][BL_CONDITION].x = x;
+ tty_curs(WIN_STATUS, x, y);
+ }
+ for (c = 0; c < SIZE(conditions) && bits != 0L; ++c) {
+ mask = conditions[c].mask;
+ if (bits & mask) {
+ const char *condtext;
+
+ tty_putstatusfield(" ", x++, y);
+ if (iflags.hilite_delta) {
+ attrmask = condattr(mask, tty_colormasks);
+ Begin_Attr(attrmask);
+ coloridx = condcolor(mask, tty_colormasks);
+ if (coloridx != NO_COLOR)
+ term_start_color(coloridx);
+ }
+ condtext = conditions[c].text[cond_shrinklvl];
+ if (x >= cw->cols && !truncation_expected) {
+ impossible(
+ "Unexpected condition placement overflow for \"%s\"",
+ condtext);
+ condtext = "";
+ bits = 0L; /* skip any remaining conditions */
+ }
+ tty_putstatusfield(condtext, x, y);
+ x += (int) strlen(condtext);
+ if (iflags.hilite_delta) {
+ if (coloridx != NO_COLOR)
+ term_end_color();
+ End_Attr(attrmask);
+ }
+ bits &= ~mask;
+ }
+ }
+ /* 'x' is 1-based and 'cols' and 'data' are 0-based,
+ so x==cols means we just stored in data[N-2] and
+ are now positioned at data[N-1], the terminator;
+ that's ok as long as we don't write there */
+ if (x > cw->cols) {
+ static unsigned once_only = 0;
+
+ if (!truncation_expected && !once_only++)
+ paniclog("render_status()",
+ " unexpected truncation.");
+ x = cw->cols;
+ }
+ } else if (hitpointbar) {
+ /*
+ * +-------------------------+
+ * | Title with Hitpoint Bar |
+ * +-------------------------+
+ */
+ /* hitpointbar using hp percent calculation */
+ int bar_len, bar_pos = 0;
+ char bar[MAXCO], *bar2 = (char *) 0, savedch = '\0';
+ boolean twoparts = (hpbar_percent < 100);
+
+ /* force exactly 30 characters, padded with spaces
+ if shorter or truncated if longer */
+ if (strlen(text) != 30) {
+ Sprintf(bar, "%-30.30s", text);
+ Strcpy(status_vals[BL_TITLE], bar);
+ } else
+ Strcpy(bar, text);
+ bar_len = (int) strlen(bar); /* always 30 */
+ tlth = bar_len + 2;
+ /* when at full HP, the whole title will be highlighted;
+ when injured or dead, there will be a second portion
+ which is not highlighted */
+ if (twoparts) {
+ /* figure out where to separate the two parts */
+ bar_pos = (bar_len * hpbar_percent) / 100;
+ if (bar_pos < 1 && hpbar_percent > 0)
+ bar_pos = 1;
+ if (bar_pos >= bar_len && hpbar_percent < 100)
+ bar_pos = bar_len - 1;
+ bar2 = &bar[bar_pos];
+ savedch = *bar2;
+ *bar2 = '\0';
+ }
+ tty_putstatusfield("[", x++, y);
+ if (*bar) { /* always True, unless twoparts+dead (0 HP) */
+ term_start_attr(ATR_INVERSE);
+ if (iflags.hilite_delta && hpbar_color != NO_COLOR)
+ term_start_color(hpbar_color);
+ tty_putstatusfield(bar, x, y);
+ x += (int) strlen(bar);
+ if (iflags.hilite_delta && hpbar_color != NO_COLOR)
+ term_end_color();
+ term_end_attr(ATR_INVERSE);
+ }
+ if (twoparts) { /* no highlighting for second part */
+ *bar2 = savedch;
+ tty_putstatusfield(bar2, x, y);
+ x += (int) strlen(bar2);
+ }
+ tty_putstatusfield("]", x++, y);
+ } else {
+ /*
+ * +-----------------------------+
+ * | Everything else that is not |
+ * | in a special case above |
+ * +-----------------------------+
+ */
+ if (iflags.hilite_delta) {
+ while (*text == ' ') {
+ tty_putstatusfield(" ", x++, y);
+ text++;
+ }
+ if (*text == '/' && idx == BL_EXP) {
+ tty_putstatusfield("/", x++, y);
+ text++;
+ }
+ attrmask = tty_status[NOW][idx].attr;
+ Begin_Attr(attrmask);
+ coloridx = tty_status[NOW][idx].color;
+ if (coloridx != NO_COLOR)
+ term_start_color(coloridx);
+ }
+ tty_putstatusfield(text, x, y);
+ x += (int) strlen(text);
+ if (iflags.hilite_delta) {
+ if (coloridx != NO_COLOR)
+ term_end_color();
+ End_Attr(attrmask);
+ }
+ }
+ } else {
+ /* not rendered => same text as before */
+ x += tlth;
+ }
+ finalx[row][NOW] = x - 1;
+ /* reset .redraw and .dirty now that field has been rendered */
+ tty_status[NOW][idx].dirty = FALSE;
+ tty_status[NOW][idx].redraw = FALSE;
+ tty_status[NOW][idx].sanitycheck = FALSE;
+ /*
+ * For comparison of current and previous:
+ * - Copy the entire tty_status struct.
+ */
+ tty_status[BEFORE][idx] = tty_status[NOW][idx];
+ }
+ x = finalx[row][NOW];
+ if ((x < finalx[row][BEFORE] || !finalx[row][BEFORE])
+ && x + 1 < cw->cols) {
+ tty_curs(WIN_STATUS, x + 1, y);
+ cl_end();
+ }
+ /*
+ * For comparison of current and previous:
+ * - Copy the last written column number on the row.
+ */
+ finalx[row][BEFORE] = finalx[row][NOW];
+ }
return;
}
#endif /* STATUS_HILITES */
-#endif /*STATUS_VIA_WINDOWPORT*/
#endif /* TTY_GRAPHICS */