From: nhmall Date: Sun, 3 Jul 2022 04:34:08 +0000 (-0400) Subject: rework TTY_PERM_INVENT; update window port interface X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c84e0ba6e1a37d6dde9d6a14a41176597f01d197;p=nethack rework TTY_PERM_INVENT; update window port interface Change the inner workings of the experimental TTY_PERM_INVENT. Switch to delivering the content to tty for the experimental perm_invent via the existing window port interface (start_menu(), add_menu(), end_menu). This also adds a new window port interface call ctrl_nhwindow() for delivering information to the window port, and/or obtaining specific information from the window port. The information and requests can be extended as required. To be documented later once the changes settle down. Due to the intrusive nature of these changes and the possibility of some bugs in the new code, I'm going to leave TTY_PERM_INVENT commented out in the repository for a day or two. Anyone wishing to test it out can do so by uncommenting TTY_PERM_INVENT in config.h. --- diff --git a/include/config.h b/include/config.h index 2e9df46d7..9ed4e3273 100644 --- a/include/config.h +++ b/include/config.h @@ -562,7 +562,7 @@ typedef unsigned char uchar; /* An experimental minimalist inventory list capability under tty if you have * at least 28 additional rows beneath the status window on your terminal */ -#define TTY_PERM_INVENT +/* #define TTY_PERM_INVENT */ /* NetHack will execute an external program whenever a new message-window * message is shown. The program to execute is given in environment variable diff --git a/include/decl.h b/include/decl.h index 140cde5f9..5e6ee46e3 100644 --- a/include/decl.h +++ b/include/decl.h @@ -972,8 +972,10 @@ struct instance_globals { persistent one doesn't get shrunk during filtering for item selection then regrown to full inventory, possibly being resized in the process */ winid cached_pickinv_win; - winid perm_invent_win; int core_invent_state; + int in_sync_perminvent; + int perm_invent_toggling_direction; + long glyph_reset_timestamp; /* query objlist callback: return TRUE if obj type matches "this_type" */ int this_type; diff --git a/include/extern.h b/include/extern.h index b114cf6bc..5efb5aa0b 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1176,6 +1176,7 @@ extern const char *currency(long); extern void silly_thing(const char *, struct obj *); extern void sync_perminvent(void); extern void perm_invent_toggled(boolean negated); +extern void prepare_perminvent(winid window); /* ### ioctl.c ### */ diff --git a/include/winX.h b/include/winX.h index 725d4e902..94b89ce35 100644 --- a/include/winX.h +++ b/include/winX.h @@ -487,6 +487,6 @@ extern void genl_outrip(winid, int, time_t); extern void X11_preference_update(const char *); extern void X11_update_inventory(int); -extern perminvent_info *X11_update_invent_slot(winid, int, perminvent_info *); +extern win_request_info *X11_ctrl_nhwindow(winid, int, win_request_info *); #endif /* WINX_H */ diff --git a/include/wincurs.h b/include/wincurs.h index 83df0113b..580ad3adf 100644 --- a/include/wincurs.h +++ b/include/wincurs.h @@ -113,7 +113,7 @@ extern void genl_outrip(winid tmpwin, int how, time_t when); extern void curses_preference_update(const char *pref); extern void curs_reset_windows(boolean, boolean); extern void curses_update_inventory(int); -extern perminvent_info *curses_update_invent_slot(winid, int, perminvent_info *); +extern win_request_info *curses_ctrl_nhwindow(winid, int, win_request_info *); /* curswins.c */ diff --git a/include/winprocs.h b/include/winprocs.h index 9ad5667a6..8d7ee6164 100644 --- a/include/winprocs.h +++ b/include/winprocs.h @@ -92,7 +92,7 @@ struct window_procs { unsigned long *); boolean (*win_can_suspend)(void); void (*win_update_inventory)(int); - perminvent_info *(*win_update_invent_slot)(winid, int, perminvent_info *); + win_request_info *(*win_ctrl_nhwindow)(winid, int, win_request_info *); }; extern @@ -174,7 +174,7 @@ extern */ #define status_enablefield (*windowprocs.win_status_enablefield) #define status_update (*windowprocs.win_status_update) -#define update_invent_slot (*windowprocs.win_update_invent_slot) +#define ctrl_nhwindow (*windowprocs.win_ctrl_nhwindow) /* * @@ -491,7 +491,7 @@ extern void stdio_nonl_raw_print(const char *); extern void stdio_raw_print_bold(const char *); extern void stdio_wait_synch(void); extern void safe_update_inventory(int); -extern perminvent_info *safe_update_invent_slot(winid, int, perminvent_info *); +extern win_request_info *safe_ctrl_nhwindow(winid, int, win_request_info *); extern int stdio_nhgetch(void); #endif /* SAFEPROCS */ #endif /* WINPROCS_H */ diff --git a/include/wintty.h b/include/wintty.h index e6cbe68ae..e59cf6a50 100644 --- a/include/wintty.h +++ b/include/wintty.h @@ -12,7 +12,7 @@ #ifdef TTY_PERM_INVENT -enum { tty_pi_minrow = 28, tty_pi_mincol = 79 }; +enum { tty_perminv_minrow = 28, tty_perminv_mincol = 79 }; /* for static init of zerottycell, put pointer first */ union ttycellcontent { glyph_info *gi; @@ -283,7 +283,7 @@ E void genl_outrip(winid, int, time_t); E char *tty_getmsghistory(boolean); E void tty_putmsghistory(const char *, boolean); E void tty_update_inventory(int); -E perminvent_info *tty_update_invent_slot(winid, int, perminvent_info *); +E win_request_info *tty_ctrl_nhwindow(winid, int, win_request_info *); #ifdef TTY_PERM_INVENT E void tty_refresh_inventory(int start, int stop, int y); diff --git a/include/wintype.h b/include/wintype.h index 3ebb3db56..dd69b9446 100644 --- a/include/wintype.h +++ b/include/wintype.h @@ -169,6 +169,9 @@ typedef struct gi { */ #define MENU_BEHAVE_STANDARD 0x0000000U +#define MENU_BEHAVE_PERMINV 0x0000001U + +enum perm_invent_toggles {toggling_off = -1, toggling_not = 0, toggling_on = 1 }; /* inventory modes */ enum inv_modes { InvNormal = 0, InvShowGold = 1, InvSparse = 2, InvInUse = 4 }; @@ -180,9 +183,8 @@ enum to_core_flags { }; enum from_core_requests { - request_settings = 1, - update_slot = 2, - render = 3 + set_mode = 1, + request_settings = 2, }; struct to_core { @@ -197,24 +199,16 @@ struct to_core { struct from_core { enum from_core_requests core_request; enum inv_modes invmode; - boolean force_redraw; - int slot; /* which inventory slot + 1; 0 indicates request */ - int invlet; - char text[BUFSZ]; - int32_t clr; /* adjusted color 0 = ignore - * 1-16 = NetHack color + 1 - * 17..16,777,233 = 24-bit color + 17 - */ }; -struct perminvent_info_t { +struct win_request_info_t { struct to_core tocore; struct from_core fromcore; }; -typedef struct perminvent_info_t perminvent_info; +typedef struct win_request_info_t win_request_info; -#define CORE_INVENT +/* #define CORE_INVENT */ /* clang-format on */ diff --git a/src/allmain.c b/src/allmain.c index 342190545..a10faacac 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -619,6 +619,8 @@ stop_occupation(void) void display_gamewindows(void) { + int menu_behavior = MENU_BEHAVE_STANDARD; + WIN_MESSAGE = create_nhwindow(NHW_MESSAGE); if (VIA_WINDOWPORT()) { status_initialize(0); @@ -627,9 +629,15 @@ display_gamewindows(void) } WIN_MAP = create_nhwindow(NHW_MAP); WIN_INVEN = create_nhwindow(NHW_MENU); +#ifdef TTY_PERM_INVENT + if (WINDOWPORT(tty) && WIN_INVEN != WIN_ERR) { + menu_behavior = MENU_BEHAVE_PERMINV; + prepare_perminvent(WIN_INVEN); + } +#endif /* in case of early quit where WIN_INVEN could be destroyed before ever having been used, use it here to pacify the Qt interface */ - start_menu(WIN_INVEN, 0U), end_menu(WIN_INVEN, (char *) 0); + start_menu(WIN_INVEN, menu_behavior), end_menu(WIN_INVEN, (char *) 0); #ifdef MAC /* This _is_ the right place for this - maybe we will diff --git a/src/decl.c b/src/decl.c index f72478632..70260c017 100644 --- a/src/decl.c +++ b/src/decl.c @@ -435,8 +435,10 @@ const struct instance_globals g_init = { NULL, /* invbuf */ 0, /* inbufsize */ WIN_ERR, /* cached_pickinv_win */ - WIN_ERR, /* perm_invent_win */ 0, /* core_invent_state */ + 0, /* in_sync_perminvent */ + 0, /* perm_invent_toggling_direction */ + 0L, /* glyph_reset_timestamp */ 0, /* this_type */ NULL, /* this_title */ UNDEFINED_VALUES, /* only (coord) */ diff --git a/src/display.c b/src/display.c index 1b83021c6..228028f2c 100644 --- a/src/display.c +++ b/src/display.c @@ -2775,6 +2775,7 @@ reset_glyphmap(enum glyphmap_change_triggers trigger) color = NO_COLOR; gmap->sym.color = color; } + g.glyph_reset_timestamp = g.moves; } /* ------------------------------------------------------------------------ */ diff --git a/src/invent.c b/src/invent.c index b91e6c192..07c74ca3c 100644 --- a/src/invent.c +++ b/src/invent.c @@ -42,6 +42,12 @@ static boolean item_naming_classification(struct obj *, char *, char *); static int item_reading_classification(struct obj *, char *); static void mime_action(const char *); +/* enum and structs are defined in wintype.h */ +static win_request_info zerowri = { { 0L, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0 } }; +static win_request_info wri_info; +static int done_setting_perminv_flags = 0; +static boolean in_perm_invent_toggled; + /* wizards can wish for venom, which will become an invisible inventory * item without this. putting it in inv_order would mean venom would * suddenly become a choice for all the inventory-class commands, which @@ -2440,7 +2446,7 @@ update_inventory(void) */ save_suppress_price = iflags.suppress_price; iflags.suppress_price = 0; -#if defined(TTY_PERM_INVENT) && defined(CORE_INVENT) +#if defined(TTY_PERM_INVENT) if (WINDOWPORT(tty)) sync_perminvent(); else @@ -3183,27 +3189,40 @@ display_pickinv( char ilet, ret, *formattedobj; const char *invlet = flags.inv_order; int n, classcount; - winid win; /* windows being used */ + winid win; /* windows being used */ anything any; menu_item *selected; unsigned sortflags; Loot *sortedinvent, *srtinv; boolean wizid = (wizard && iflags.override_ID), gotsomething = FALSE; - int clr = 0; + int clr = 0, menu_behavior = MENU_BEHAVE_STANDARD; + boolean show_gold = TRUE, sparse = FALSE, inuse_only = FALSE, + doing_perm_invent = FALSE, save_flags_sortpack = flags.sortpack; if (lets && !*lets) lets = 0; /* simplify tests: (lets) instead of (lets && *lets) */ - if (iflags.perm_invent && (lets || xtra_choice || wizid)) { + if ((iflags.perm_invent && (lets || xtra_choice || wizid)) +#ifdef TTY_PERM_INVENT + || !g.in_sync_perminvent +#endif + || WIN_INVEN == WIN_ERR) { /* partial inventory in perm_invent setting; don't operate on full inventory window, use an alternate one instead; create the first time needed and keep it for re-use as needed later */ if (g.cached_pickinv_win == WIN_ERR) g.cached_pickinv_win = create_nhwindow(NHW_MENU); win = g.cached_pickinv_win; - } else + } else { win = WIN_INVEN; - + menu_behavior = MENU_BEHAVE_PERMINV; + prepare_perminvent(win); + show_gold = ((wri_info.fromcore.invmode & InvShowGold) != 0); + sparse = ((wri_info.fromcore.invmode & InvSparse) != 0); + inuse_only = ((wri_info.fromcore.invmode & InvInUse) != 0); + doing_perm_invent = TRUE; + nhUse(sparse); + } /* * Exit early if no inventory -- but keep going if we are doing * a permanent inventory update. We need to keep going so the @@ -3266,10 +3285,18 @@ display_pickinv( sortflags = (flags.sortloot == 'f') ? SORTLOOT_LOOT : SORTLOOT_INVLET; if (flags.sortpack) sortflags |= SORTLOOT_PACK; +#ifdef TTY_PERM_INVENT + if (doing_perm_invent && WINDOWPORT(tty)) { + sortflags = SORTLOOT_INVLET; + save_flags_sortpack = flags.sortpack; + flags.sortpack = FALSE; + } +#else + nhUse(save_flags_sortpack); +#endif sortedinvent = sortloot(&g.invent, sortflags, FALSE, (boolean (*)(OBJ_P)) 0); - - start_menu(win, MENU_BEHAVE_STANDARD); + start_menu(win, menu_behavior); any = cg.zeroany; if (wizid) { int unid_cnt; @@ -3327,6 +3354,11 @@ display_pickinv( if (!flags.sortpack || otmp->oclass == *invlet) { if (wizid && !not_fully_identified(otmp)) continue; + if (doing_perm_invent + && ((otmp->invlet == GOLD_SYM && !show_gold) + || ((otmp->invlet != GOLD_SYM) + && (!otmp->owornmask && inuse_only)))) + continue; any = cg.zeroany; /* all bits zero */ ilet = otmp->invlet; if (flags.sortpack && !classcount) { @@ -3387,6 +3419,10 @@ display_pickinv( not_carrying_anything, MENU_ITEMFLAGS_NONE); want_reply = FALSE; } +#ifdef TTY_PERM_INVENT + if (doing_perm_invent && WINDOWPORT(tty)) + flags.sortpack = save_flags_sortpack; +#endif end_menu(win, (query && *query) ? query : (char *) 0); n = select_menu(win, @@ -5361,47 +5397,39 @@ display_binventory(coordxy x, coordxy y, boolean as_if_seen) return n; } -#if defined(CORE_INVENT) -/* enum and structs are defined in wintype.h */ -static perminvent_info zeropi = { {0L,0,0,0,0,0,0,0}, {0,0,0,0,0,{0},0} }; -static perminvent_info pi_info; -static char Empty[1] = { '\0' }; -static int done_environment_var = 0; -#ifdef TTY_PERM_INVENT -extern void tty_perm_invent_toggled(boolean negated); -static boolean in_perm_invent_toggled; -#endif +void +prepare_perminvent(winid window) +{ + win_request_info *wri UNUSED; + + if (!done_setting_perminv_flags) { + wri_info = zerowri; + /*TEMPORARY*/ + char *envtmp = nh_getenv("TTYINV"); + wri_info.fromcore.invmode = envtmp ? atoi(envtmp) : InvNormal; + /* relay the mode settings to the window port */ + wri = ctrl_nhwindow(window, set_mode, &wri_info); + done_setting_perminv_flags = 1; + } +} void sync_perminvent(void) { - static perminvent_info *pi = 0; - char *text, nxtlet; - int slot; - boolean show_gold, inuse_only, sparse; + static win_request_info *wri = 0; const char *wport_id; - struct obj *obj; - - if (!done_environment_var) { - pi_info = zeropi; - /*TEMPORARY*/ - char *envtmp = nh_getenv("TTYINV"); - pi_info.fromcore.invmode = envtmp ? atoi(envtmp) : InvNormal; - done_environment_var = 1; - } - show_gold = (pi_info.fromcore.invmode & InvShowGold) != 0; - inuse_only = (pi_info.fromcore.invmode & InvInUse) != 0; - sparse = (pi_info.fromcore.invmode & InvSparse) != 0; - if ((g.perm_invent_win == WIN_ERR && g.core_invent_state) - || (pi_info.tocore.tocore_flags & prohibited)) + if (WIN_INVEN == WIN_ERR) { + if ((g.core_invent_state + || (wri_info.tocore.tocore_flags & prohibited)) + && !(in_perm_invent_toggled + && g.perm_invent_toggling_direction == toggling_on)) return; + } + if (!done_setting_perminv_flags && WIN_INVEN != WIN_ERR) + prepare_perminvent(WIN_INVEN); - if ((!iflags.perm_invent && g.core_invent_state) -#ifdef TTY_PERM_INVENT - && !in_perm_invent_toggled -#endif - ){ + if ((!iflags.perm_invent && g.core_invent_state)) { /* Odd - but this could be end-of-game disclosure * which just sets boolean iflag.perm_invent to * FALSE without actually doing anything else. @@ -5413,157 +5441,81 @@ sync_perminvent(void) (void) doredraw(); return; } - if (!iflags.perm_invent -#ifdef TTY_PERM_INVENT -&& !in_perm_invent_toggled -#endif - ) - return; + /* - * The core looks after what content goes into the - * inventory slots, and deals with things like obj - * chains etc, so the window port doesn't have to. - * - * The window port informs the core of the number of - * slots that it will process. - * - * The core tells the window port what the contents of the - * inventory slots should be. + * The following conditions can bring us to here: + * 1. iflags.perm_invent is on + * AND + * g.core_invent_state is still zero. * - * The core requests the window port when to render, after - * all the content has been updated. + * OR * - * The window port looks after the placement of an inventory - * slot's contents onto the display in an appropriate fashion, - * The core doesn't care, and leaves that up to the window port. - * - * The core slot handling is no longer tied to TTY_PERM_INVENT, - * although at this point that's the only window port to utilize - * it. The rest are still rolling their own via the basic - * [port]_update_inventory() mechanism. + * 2. iflags.perm_invent is off, but we're in the + * midst of toggling it on. */ - if (WINDOWPORT(tty) && iflags.perm_invent) - wport_id = "tty perm_invent"; - else - wport_id = "perm_invent"; - - pi_info.fromcore.core_request = 0; if ((iflags.perm_invent && !g.core_invent_state) -#ifdef TTY_PERM_INVENT - || in_perm_invent_toggled -#endif - ) { - /* Send the wport a request to get the related settings. */ - pi_info.fromcore.core_request = request_settings; - if ((pi = update_invent_slot(g.perm_invent_win, (slot = 0), &pi_info))) { - if ((pi->tocore.tocore_flags & prohibited) != 0) { - /* sizes aren't good enough */ - set_option_mod_status("perm_invent", set_gameview); - iflags.perm_invent = FALSE; - pline("%s could not be enabled.", wport_id); - pline("%s needs a terminal that is at least %dx%d, yours is %dx%d.", - wport_id, - pi->tocore.needrows, pi->tocore.needcols, - pi->tocore.haverows, pi->tocore.havecols); - wait_synch(); - return; + || ((!iflags.perm_invent + && (in_perm_invent_toggled + && g.perm_invent_toggling_direction == toggling_on)))) { + + /* Send windowport a request to return the related settings to us */ + if ((iflags.perm_invent && !g.core_invent_state) + || in_perm_invent_toggled) { + if ((wri = ctrl_nhwindow(WIN_INVEN, request_settings, &wri_info))) { + if ((wri->tocore.tocore_flags & prohibited) != 0) { + /* sizes aren't good enough */ + set_option_mod_status("perm_invent", set_gameview); + iflags.perm_invent = FALSE; + if (WIN_INVEN != WIN_ERR) + destroy_nhwindow(WIN_INVEN), WIN_INVEN = WIN_ERR; + if (WINDOWPORT(tty) && iflags.perm_invent) + wport_id = "tty perm_invent"; + else + wport_id = "perm_invent"; + pline("%s could not be enabled.", wport_id); + pline("%s needs a terminal that is at least %dx%d, yours " + "is %dx%d.", + wport_id, wri->tocore.needrows, + wri->tocore.needcols, wri->tocore.haverows, + wri->tocore.havecols); + wait_synch(); + return; + } } + g.core_invent_state++; } - g.perm_invent_win = create_nhwindow(NHW_PERMINVENT); - if (g.perm_invent_win == WIN_ERR) - return; - display_nhwindow(g.perm_invent_win, FALSE); - g.core_invent_state++; } - if (!pi || pi->tocore.maxslot == 0) + + if (!wri || wri->tocore.maxslot == 0) return; - text = Empty; /* lint suppression */ - pi_info.fromcore.core_request = update_slot; - obj = g.invent; - for (slot = 0; slot < pi->tocore.maxslot; ++slot) { - nxtlet = '?'; /* always gets set to something else if actually used */ - if (!sparse) { - while (obj && ((obj->invlet == GOLD_SYM && !show_gold) - || (!obj->owornmask && inuse_only))) - obj = obj->nobj; - } else { - if (!show_gold) - nxtlet = (slot < 26) ? ('a' + slot) : ('A' + slot - 26); - else - nxtlet = (slot == 0) ? GOLD_SYM - : (slot < 27) ? ('a' + slot - 1) - : (slot < 53) ? ('A' + slot - 27) - : NOINVSYM; - for (obj = g.invent; obj; obj = obj->nobj) - if (obj->invlet == nxtlet) - break; - } - if (obj) { - /* TODO: check for MENUCOLORS match */ - text = doname(obj); /* 'text' will switch to fromcore.text below */ - /* strip away "a"/"an"/"the" prefix to show a bit more of the - interesting part of the object's description; - this is inline version of pi_article_skip() from cursinvt.c; - should move that to hacklib.c and use it here */ - if (text[0] == 'a') { - if (text[1] == ' ') - text += 2; - else if (text[1] == 'n' && text[2] == ' ') - text += 3; - } else if (text[0] == 't') { - if (text[1] == 'h' && text[2] == 'e' && text[3] == ' ') - text += 4; - } - Snprintf(pi_info.fromcore.text, - sizeof pi_info.fromcore.text, - "%c - %s", obj->invlet, text); - text = pi_info.fromcore.text; - obj = obj->nobj; /* set up for next iteration */ - } else if (sparse) { - Sprintf(pi_info.fromcore.text, "%c", nxtlet); /* empty slot */ - text = pi_info.fromcore.text; - } else { - if (slot == 0) { - Sprintf(pi_info.fromcore.text, "%-4s[%s]", "", - !g.invent ? "empty" - : inuse_only ? "no items are in use" - : "only gold"); - text = pi_info.fromcore.text; - } else { - text = Empty; /* "" => fill slot with spaces */ - } - } - if (!*text) - pi_info.fromcore.text[0] = Empty[0]; - pi = update_invent_slot(g.perm_invent_win, slot + 1, &pi_info); + if (in_perm_invent_toggled && g.perm_invent_toggling_direction == toggling_on) { + WIN_INVEN = create_nhwindow(NHW_MENU); } - pi_info.fromcore.force_redraw = g.program_state.in_docrt ? TRUE : FALSE, - pi_info.fromcore.core_request = render; - pi = update_invent_slot(g.perm_invent_win, (slot = 0), &pi_info); - pi_info.fromcore.core_request = 0; + if (WIN_INVEN != WIN_ERR && g.program_state.beyond_savefile_load) { + g.in_sync_perminvent = 1; + (void) display_inventory((char *) 0, FALSE); + g.in_sync_perminvent = 0; + } } void perm_invent_toggled(boolean negated) { -#ifdef TTY_PERM_INVENT in_perm_invent_toggled = TRUE; -#endif if (negated) { - if (g.perm_invent_win != WIN_ERR) - destroy_nhwindow(g.perm_invent_win), g.perm_invent_win = WIN_ERR; + g.perm_invent_toggling_direction = toggling_off; + if (WIN_INVEN != WIN_ERR) + destroy_nhwindow(WIN_INVEN), WIN_INVEN = WIN_ERR; g.core_invent_state = 0; } else { + g.perm_invent_toggling_direction = toggling_on; sync_perminvent(); } -#ifdef TTY_PERM_INVENT + g.perm_invent_toggling_direction = toggling_not; in_perm_invent_toggled = FALSE; -#endif } -#endif /* CORE_INVENT */ - /*invent.c*/ diff --git a/src/mdlib.c b/src/mdlib.c index ec5ac9f6c..7f889914d 100644 --- a/src/mdlib.c +++ b/src/mdlib.c @@ -96,13 +96,13 @@ char optbuf[COLBUFSZ]; static struct version_info version; static const char opt_indent[] = " "; -struct win_info { +struct win_information { const char *id, /* DEFAULT_WINDOW_SYS string */ *name; /* description, often same as id */ boolean valid; }; -static struct win_info window_opts[] = { +static struct win_information window_opts[] = { #ifdef TTY_GRAPHICS { "tty", /* testing 'USE_TILES' here would bring confusion because it could diff --git a/src/options.c b/src/options.c index 07fe3598b..81ad50f49 100644 --- a/src/options.c +++ b/src/options.c @@ -4415,7 +4415,7 @@ optfn_boolean(int optidx, int req, boolean negated, char *opts, char *op) -> sync_perminvent() -> tty_create_nhwindow(NHW_PERMINVENT) gives feedback for failure (terminal too small) */ - if (g.perm_invent_win == WIN_ERR) + if (WIN_INVEN == WIN_ERR) return optn_silenterr; } #endif @@ -8964,6 +8964,10 @@ enhance_menu_text( if (thisopt->setwhere == set_gameview) Snprintf(eos(buf), availsz, " *terminal size is too small"); } +#else + nhUse(availsz); + nhUse(bool_p); + nhUse(thisopt); #endif return; } diff --git a/src/windows.c b/src/windows.c index 7fccf5b12..6a1d52547 100644 --- a/src/windows.c +++ b/src/windows.c @@ -536,7 +536,7 @@ static void hup_void_fdecl_int(int); static void hup_void_fdecl_winid(winid); static void hup_void_fdecl_winid_ulong(winid, unsigned long); static void hup_void_fdecl_constchar_p(const char *); -static perminvent_info *hup_update_invent_slot(winid, int, perminvent_info *); +static win_request_info *hup_ctrl_nhwindow(winid, int, win_request_info *); static struct window_procs hup_procs = { WPID(hup), 0L, 0L, @@ -585,7 +585,7 @@ static struct window_procs hup_procs = { genl_status_enablefield, hup_status_update, genl_can_suspend_no, hup_void_fdecl_int, /* update_inventory */ - hup_update_invent_slot, /* update_invent_slot */ + hup_ctrl_nhwindow, }; static void (*previnterface_exit_nhwindows)(const char *) = 0; @@ -841,15 +841,13 @@ hup_void_fdecl_constchar_p(const char *string UNUSED) } /*ARGUSED*/ -perminvent_info * -hup_update_invent_slot( +win_request_info * +hup_ctrl_nhwindow( winid window UNUSED, /* window to use, must be of type NHW_MENU */ - int inventory_slot UNUSED, /* slot id: 0 - info return to core */ - /* 1 - gold slot */ - /* 2 - 29 obj slots */ - perminvent_info *pi UNUSED) + int request UNUSED, + win_request_info *wri UNUSED) { - return (perminvent_info *) 0; + return (win_request_info *) 0; } #endif /* HANGUPHANDLING */ diff --git a/sys/windows/win32api.h b/sys/windows/win32api.h index 3d59fa30c..ba19ec912 100644 --- a/sys/windows/win32api.h +++ b/sys/windows/win32api.h @@ -35,6 +35,12 @@ #pragma pack(8) #endif +#ifdef DEBUG +#define _CRTDBG_MAP_ALLOC +#include +#include +#endif + #define WIN32_LEAN_AND_MEAN #include diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index 4fc5261c7..db1fdc46c 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -5,6 +5,7 @@ /* main.c - Windows */ #include "win32api.h" /* for GetModuleFileName */ + #include "hack.h" #ifdef DLB #include "dlb.h" @@ -424,6 +425,10 @@ mingw_main(int argc, char *argv[]) char fnamebuf[BUFSZ], encodedfnamebuf[BUFSZ]; char failbuf[BUFSZ]; +#ifdef _MSC_VER + _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); +#endif + /* * Get a set of valid safe windowport function * pointers during early startup initialization. diff --git a/win/Qt/qt_bind.cpp b/win/Qt/qt_bind.cpp index 277383cad..d75e32dc8 100644 --- a/win/Qt/qt_bind.cpp +++ b/win/Qt/qt_bind.cpp @@ -490,15 +490,13 @@ void NetHackQtBind::qt_update_inventory(int arg UNUSED) */ } -perminvent_info *NetHackQtBind::qt_update_invent_slot( - winid wid UNUSED, /* window to use, must be of type NHW_MENU */ - int inventory_slot UNUSED, /* slot id: 0 - info return to core */ - /* 1 - gold slot */ - /* 2 - 29 obj slots */ - perminvent_info *pi UNUSED) +win_request_info *NetHackQtBind::qt_ctrl_nhwindow( + winid wid UNUSED, + int request UNUSED, + win_request_info *wri UNUSED) { NetHackQtWindow* window UNUSED =id_to_window[(int)wid]; - return (perminvent_info *) 0; + return (win_request_info *) 0; } void NetHackQtBind::qt_mark_synch() @@ -1111,7 +1109,7 @@ struct window_procs Qt_procs = { #endif genl_can_suspend_yes, nethack_qt_::NetHackQtBind::qt_update_inventory, - nethack_qt_::NetHackQtBind::qt_update_invent_slot, + nethack_qt_::NetHackQtBind::qt_ctrl_nhwindow, }; #ifndef WIN32 diff --git a/win/Qt/qt_bind.h b/win/Qt/qt_bind.h index 522532c46..204483838 100644 --- a/win/Qt/qt_bind.h +++ b/win/Qt/qt_bind.h @@ -89,7 +89,7 @@ public: static void qt_outrip(winid wid, int how, time_t when); static int qt_kbhit(); static void qt_update_inventory(int); - static perminvent_info *qt_update_invent_slot(winid, int, perminvent_info *); + static win_request_info *qt_ctrl_nhwindow(winid, int, win_request_info *); static QWidget *mainWidget() { return main; } diff --git a/win/X11/winX.c b/win/X11/winX.c index ea4c77147..4d8d923f4 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -142,7 +142,7 @@ struct window_procs X11_procs = { X11_status_update, genl_can_suspend_no, /* XXX may not always be correct */ X11_update_inventory, - X11_update_invent_slot, + X11_ctrl_nhwindow, }; /* @@ -1272,15 +1272,13 @@ X11_update_inventory(int arg) return; } -perminvent_info * -X11_update_invent_slot( - winid window UNUSED, /* window to use, must be of type NHW_MENU */ - int inventory_slot UNUSED, /* slot id: 0 - info return to core */ - /* 1 - gold slot */ - /* 2 - 29 obj slots */ - perminvent_info *pi UNUSED) +win_request_info * +X11_ctrl_nhwindow( + winid window UNUSED, + int request UNUSED, + win_request_info *wri UNUSED) { - return (perminvent_info *) 0; + return (win_request_info *) 0; } /* The current implementation has all of the saved lines on the screen. */ diff --git a/win/chain/wc_chainin.c b/win/chain/wc_chainin.c index 27e1f1061..7b8b6a419 100644 --- a/win/chain/wc_chainin.c +++ b/win/chain/wc_chainin.c @@ -75,7 +75,7 @@ void chainin_status_update(int, genericptr_t, int, int, int, boolean chainin_can_suspend(void); void chainin_update_inventory(int); -perminvent_info *chainin_update_invent_slot(winid, int, perminvent_info *); +win_request_info *chainin_ctrl_nhwindow(winid, int, win_request_info *); void *chainin_procs_chain(int cmd, int n, void *me, void *nextprocs, void *nextdata); void chainin_procs_init(int dir); @@ -578,18 +578,16 @@ chainin_can_suspend(void) return rv; } -perminvent_info * -chainin_update_invent_slot( - winid window, /* window to use, must be of type NHW_MENU */ - int inventory_slot, /* slot id: 0 - info return to core */ - /* 1 - gold slot */ - /* 2 - 29 obj slots */ - perminvent_info *pi) +win_request_info * +chainin_ctrl_nhwindow( + winid window, + int request, + win_request_info *wri) { boolean rv; - rv = (*cibase->nprocs->win_update_invent_slot)(cibase->ndata, window, - inventory_slot, pi); + rv = (*cibase->nprocs->win_ctrl_nhwindow)(cibase->ndata, window, + request, wri); return rv; } @@ -639,5 +637,5 @@ struct window_procs chainin_procs = { chainin_status_update, chainin_can_suspend, chainin_update_inventory, - chainin_update_invent_slot, + chainin_ctrl_nhwindow, }; diff --git a/win/chain/wc_chainout.c b/win/chain/wc_chainout.c index 0ebcd72be..71e9603b8 100644 --- a/win/chain/wc_chainout.c +++ b/win/chain/wc_chainout.c @@ -75,7 +75,7 @@ void chainout_status_update(void *,int, genericptr_t, int, int, int, boolean chainout_can_suspend(void *); void chainout_update_inventory(void *, int); -perminvent_info *chainout_update_invent_slot(void *, winid, int, perminvent_info *); +win_request_info *chainout_ctrl_nhwindow(void *, winid, int, win_request_info *); void chainout_procs_init(int dir); void *chainout_procs_chain(int cmd, int n, void *me, void *nextprocs, void *nextdata); @@ -700,19 +700,17 @@ chainout_can_suspend(void *vp) return rv; } -perminvent_info * -chainout_update_invent_slot( - winid window, /* window to use, must be of type NHW_MENU */ - int inventory_slot, /* slot id: 0 - info return to core */ - /* 1 - gold slot */ - /* 2 - 29 obj slots */ - perminvent_info *pi) +win_request_info * +chainout_ctrl_nhwindow( + winid window, + int request, + win_request_info *wri) { struct chainout_data *tdp = vp; boolean rv; - rv = (*tdp->nprocs->win_update_invent_slot)(window, - inventory_slot, pi); + rv = (*tdp->nprocs->win_ctrl_nhwindow)(window, + request, wri); return rv; } @@ -763,5 +761,5 @@ struct chain_procs chainout_procs = { chainout_status_update, chainout_can_suspend, chainout_update_inventory, - chainout_update_invent_slot, + chainout_ctrl_nhwindow, }; diff --git a/win/curses/cursmain.c b/win/curses/cursmain.c index fd1865c00..a1ce68223 100644 --- a/win/curses/cursmain.c +++ b/win/curses/cursmain.c @@ -117,7 +117,7 @@ struct window_procs curses_procs = { curses_status_update, genl_can_suspend_yes, curses_update_inventory, - curses_update_invent_slot, + curses_ctrl_nhwindow, }; /* @@ -695,15 +695,13 @@ curses_update_inventory(int arg) } } -perminvent_info * -curses_update_invent_slot( - winid window UNUSED, /* window to use, must be of type NHW_MENU */ - int inventory_slot UNUSED, /* slot id: 0 - info return to core */ - /* 1 - gold slot */ - /* 2 - 29 obj slots */ - perminvent_info *pi UNUSED) +win_request_info * +curses_ctrl_nhwindow( + winid window UNUSED, + int request UNUSED, + win_request_info *wri UNUSED) { - return (perminvent_info *) 0; + return (win_request_info *) 0; } /* diff --git a/win/share/safeproc.c b/win/share/safeproc.c index e3f655ee7..6e497ee5c 100644 --- a/win/share/safeproc.c +++ b/win/share/safeproc.c @@ -101,7 +101,7 @@ struct window_procs safe_procs = { safe_status_update, safe_can_suspend, safe_update_inventory, - safe_update_invent_slot, + safe_ctrl_nhwindow, }; struct window_procs * @@ -479,15 +479,13 @@ safe_update_inventory(int arg UNUSED) return; } -perminvent_info * -safe_update_invent_slot( - winid window, /* window to use, must be of type NHW_MENU */ - int inventory_slot, /* slot id: 0 - info return to core */ - /* 1 - gold slot */ - /* 2 - 29 obj slots */ - perminvent_info *pi) +win_request_info * +safe_ctrl_nhwindow( + winid window, + int request, + win_request_info *wri) { - return (perminvent_info *) 0; + return (win_request_info *) 0; } /************************************************************** diff --git a/win/shim/winshim.c b/win/shim/winshim.c index 49e74dc88..59046fd5b 100644 --- a/win/shim/winshim.c +++ b/win/shim/winshim.c @@ -183,21 +183,19 @@ void shim_update_inventory(int a1 UNUSED) { display_inventory(NULL, FALSE); } } -perminvent_info * -shim_update_invent_slot( - winid window UNUSED, /* window to use, must be of type NHW_MENU */ - int inventory_slot UNUSED, /* slot id: 0 - info return to core */ - /* 1 - gold slot */ - /* 2 - 29 obj slots */ - perminvent_info *pi UNUSED) { - return (perminvent_info *) 0; +win_request_info * +shim_ctrl_nhwindow( + winid window UNUSED, + int request, + win_request_info *wri UNUSED) { + return (win_request_info *) 0; } #else /* !__EMSCRIPTEN__ */ VDECLCB(shim_update_inventory,(int a1 UNUSED) -DECLB(perminvent_info *, shim_update_invent_slot, - (winid window, int inventory_slot, perminvent_info *pi), +DECLB(win_request_info *, shim_ctrl_nhwindow, + (winid window, int request, win_request_info *wri), "viip", - A2P window UNUSED, A2P inventory_slot UNUSED, P2V pi UNUSED) + A2P window UNUSED, A2P request UNUSED, P2V wri UNUSED) #endif /* Interface definition used in windows.c */ @@ -257,7 +255,7 @@ struct window_procs shim_procs = { #endif genl_can_suspend_yes, shim_update_inventory, - shim_update_invent_slot, + shim_ctrl_nhwindow, }; #ifdef __EMSCRIPTEN__ diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 83d4a6e32..df4986903 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -167,7 +167,7 @@ struct window_procs tty_procs = { #endif genl_can_suspend_yes, tty_update_inventory, - tty_update_invent_slot, + tty_ctrl_nhwindow, }; winid BASE_WINDOW; @@ -254,28 +254,32 @@ void g_pututf8(uint8 *utf8str); #endif #ifdef TTY_PERM_INVENT -void tty_perm_invent_toggled(boolean negated); +static char Empty[1] = { '\0' }; static struct tty_perminvent_cell zerottycell = { 0, 0, 0, { 0 }, 0 }; static glyph_info zerogi = { 0 }; -#ifdef CORE_INVENT static struct to_core zero_tocore = { 0 }; -#endif enum { border_left, border_middle, border_right, border_elements }; static int bordercol[border_elements] = { 0, 0, 0 }; /* left, middle, right */ static int ttyinvmode = InvNormal; /* enum is in wintype.h */ +static int inuse_only_start = 0; static boolean done_tty_perm_invent_init = FALSE; +enum { tty_slots = 52 + 1 + 1 }; +static boolean slot_tracker[tty_slots]; +static long last_glyph_reset_when; #ifndef NOINVSYM /* invent.c */ #define NOINVSYM '#' #endif -/* not static, core_update_invent_slot() needs to see it from invent.c */ -boolean in_tty_perm_invent_toggled = FALSE; +static boolean calling_from_update_inventory = FALSE; static int ttyinv_create_window(int, struct WinDesc *); - +static void ttyinv_add_menu(winid, struct WinDesc *, char ch, int attr, + int clr, const char *str); +static void ttyinv_render(winid window, struct WinDesc *cw); static void tty_invent_box_glyph_init(struct WinDesc *cw); -static boolean calling_from_update_inventory = FALSE; static boolean assesstty(enum inv_modes, short *, short *, - long *, long *, long *, long *, long *); -static void ttyinv_populate_slot(struct WinDesc *, int, int, const char *, int32_t); + long *, long *, long *, long *, long *); +static void ttyinv_populate_slot(struct WinDesc *, int, int, + const char *, int32_t); +static int selector_to_slot(char ch, const int invflags, boolean *ignore); #endif /* @@ -564,8 +568,8 @@ tty_preference_update(const char *pref) the way to render them might change too (Handling: DEC/UTF8/&c) */ if ((!strcmp(pref, "symset") || !strcmp(pref, "perm_invent")) && iflags.window_inited) { - if (g.perm_invent_win != WIN_ERR) - tty_invent_box_glyph_init(wins[g.perm_invent_win]); + if (WIN_INVEN != WIN_ERR) + tty_invent_box_glyph_init(wins[WIN_INVEN]); } #endif return; @@ -1617,10 +1621,6 @@ tty_create_nhwindow(int type) newwin->cols = ttyDisplay->cols; newwin->maxrow = newwin->maxcol = 0; break; -#ifdef TTY_PERM_INVENT - case NHW_PERMINVENT: - return ttyinv_create_window(newid, newwin); -#endif default: panic("Tried to create window type %d\n", (int) type); /*NOTREACHED*/ @@ -1651,100 +1651,6 @@ tty_create_nhwindow(int type) return newid; } -#ifdef TTY_PERM_INVENT - -static int -ttyinv_create_window(int newid, struct WinDesc *newwin) -{ - int i, r, c; - long minrow; /* long to match maxrow declaration */ - unsigned n; - - /* Is there enough real estate to do this beyond the status line? - * Rows: - * Top border line (1) - * 26 inventory rows (26) - * [should be 27 to have room for '$' and '#'] - * Bottom border line (1) - * 1 + 26 + 1 = 28 - * - * Cols: - * Left border (1) - * Left inventory items (38) - * Middle separation (1) - * Right inventory items (38) - * Right border (1) - * 1 + 38 + 1 + 38 + 1 = 79 - * - * The topline + map rows + status lines require: - * 1 + 21 + 2 (or 3) = 24 (or 25 depending on status line count). - * So we can only present a full inventory on tty if there are - * 28 + 24 (or 25) available (52 or 53 rows on the terminal). - * Correspondingly ttyDisplay->rows has to be at least 52 (or 53). - * [The top and bottom borderlines aren't necessary. Suppressing - * them would reduce the number of rows needed by 2.] - * - */ - - /* preliminary init in case tty_desctroy_nhwindow() gets called */ - newwin->data = (char **) 0; - newwin->datlen = (short *) 0; - newwin->cells = (struct tty_perminvent_cell **) 0; - - if (!assesstty(ttyinvmode, - &newwin->offx, &newwin->offy, &newwin->rows, &newwin->cols, - &newwin->maxcol, &minrow, &newwin->maxrow)) { - tty_destroy_nhwindow(newid); /* sets g.perm_invent_win to WIN_ERR */ - pline("%s.", "tty perm_invent could not be enabled"); - pline( - "tty perm_invent needs a terminal that is at least %dx%d, yours is %dx%d.", - (int) (minrow + 1 + ROWNO + 3), tty_pi_mincol, - ttyDisplay->rows, ttyDisplay->cols); - tty_wait_synch(); - set_option_mod_status("perm_invent", set_gameview); - iflags.perm_invent = FALSE; - return WIN_ERR; - } - - /* - * Terminal/window/screen is big enough. - */ - newwin->maxrow = minrow; - newwin->maxcol = newwin->cols; - /* establish the borders */ - bordercol[border_left] = 0; - bordercol[border_middle] = (newwin->maxcol + 1) / 2; - bordercol[border_right] = newwin->maxcol - 1; - /* for in-use mode, use full lines */ - if ((ttyinvmode & InvInUse) != 0) - bordercol[border_middle] = bordercol[border_right]; - - n = (unsigned) (newwin->maxrow * sizeof (struct tty_perminvent_cell *)); - newwin->cells = (struct tty_perminvent_cell **) alloc(n); - - n = (unsigned) (newwin->maxcol * sizeof (struct tty_perminvent_cell)); - for (i = 0; i < newwin->maxrow; i++) - newwin->cells[i] = (struct tty_perminvent_cell *) alloc(n); - - n = (unsigned) sizeof (glyph_info); - for (r = 0; r < newwin->maxrow; r++) - for (c = 0; c < newwin->maxcol; c++) { - newwin->cells[r][c] = zerottycell; - if (r == 0 || r == newwin->maxrow - 1 - || c == bordercol[border_left] - || c == bordercol[border_middle] - || c == bordercol[border_right]) { - newwin->cells[r][c].content.gi = (glyph_info *) alloc(n); - *newwin->cells[r][c].content.gi = zerogi; - newwin->cells[r][c].glyph = 1; - } - } - if (!done_tty_perm_invent_init) - tty_invent_box_glyph_init(newwin); - return newid; -} -#endif /* TTY_PERM_INVENT */ - static void erase_menu_or_text(winid window, struct WinDesc *cw, boolean clear) { @@ -2764,7 +2670,7 @@ tty_destroy_nhwindow(winid window) cw->rows = cw->cols = 0; } cw->maxrow = cw->maxcol = 0; - g.perm_invent_win = WIN_ERR; + WIN_INVEN = WIN_ERR; done_tty_perm_invent_init = FALSE; } #endif @@ -2961,7 +2867,7 @@ tty_putstr(winid window, int attr, const char *str) return; if (cw->type != NHW_MESSAGE #ifdef TTY_PERM_INVENT - && window != g.perm_invent_win + && window != WIN_INVEN #endif ) str = compress_str(str); @@ -3221,12 +3127,37 @@ tty_display_file(const char *fname, boolean complain) void tty_start_menu(winid window, unsigned long mbehavior) { - wins[window]->mbehavior = mbehavior; + struct WinDesc *cw = 0; + + if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) + panic(winpanicstr, window); + +#ifdef TTY_PERM_INVENT + if (window != WIN_ERR && cw->mbehavior == MENU_BEHAVE_PERMINV) { + /* PERMINV is ready to go already; not much to do here */ + inuse_only_start = 0; + return; + } + if (mbehavior == MENU_BEHAVE_PERMINV + && (iflags.perm_invent + || g.perm_invent_toggling_direction == toggling_on)) { + winid w = ttyinv_create_window(window, wins[window]); + if (w == WIN_ERR) { + /* something went wrong, so add clean up code here */ + } else { + cw->mbehavior = mbehavior; + } + return; + } +#else + nhUse(mbehavior); +#endif + tty_clear_nhwindow(window); return; } -/*ARGSUSED*/ + /*ARGSUSED*/ /* * Add a menu item to the beginning of the menu list. This list is reversed * later. @@ -3259,6 +3190,13 @@ tty_add_menu( || cw->type != NHW_MENU) panic(winpanicstr, window); +#ifdef TTY_PERM_INVENT + if (cw->mbehavior == MENU_BEHAVE_PERMINV) { + ttyinv_add_menu(window, cw, ch, attr, clr, str); + return; + } +#endif + cw->nitems++; if (identifier->a_void) { int len = (int) strlen(str); @@ -3322,8 +3260,23 @@ tty_end_menu(winid window, /* menu to use */ int clr = 0; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0 - || cw->type != NHW_MENU) + || cw->type != NHW_MENU) { + /* this can happen if start_menu failed due to size requirements + for the tty perm inventory window. It isn't a situation that + requires a panic, just an early return. */ + if (window == WIN_INVEN && !cw) + return; panic(winpanicstr, window); + } +#ifdef TTY_PERM_INVENT + if (cw->mbehavior == MENU_BEHAVE_PERMINV + && (iflags.perm_invent || g.perm_invent_toggling_direction == toggling_on) + && window == WIN_INVEN) { + if (g.program_state.in_moveloop) + ttyinv_render(window, cw); + return; + } +#endif /* Reverse the list so that items are in correct order. */ cw->mlist = reverse(cw->mlist); @@ -3433,6 +3386,9 @@ tty_select_menu(winid window, int how, menu_item **menu_list) || cw->type != NHW_MENU) panic(winpanicstr, window); + if (cw->mbehavior == MENU_BEHAVE_PERMINV) { + return 0; + } *menu_list = (menu_item *) 0; cw->how = (short) how; morc = 0; @@ -3493,129 +3449,287 @@ tty_message_menu(char let, int how, const char *mesg) return ((how == PICK_ONE && morc == let) || morc == '\033') ? morc : '\0'; } -/* update persistent inventory window */ -void -tty_update_inventory(int arg UNUSED) +RESTORE_WARNING_FORMAT_NONLITERAL + +win_request_info * +tty_ctrl_nhwindow(winid window UNUSED, int request, win_request_info *wri) { -#ifdef TTY_PERM_INVENT -#ifndef CORE_INVENT - static char Empty[1] = { '\0' }; - struct WinDesc *cw; - struct tty_perminvent_cell *cell; - struct obj *obj; - char invbuf[BUFSZ], *text, nxtlet; - int row, col, side, slot, maxslot; - winid window = g.perm_invent_win; - boolean force_redraw = g.program_state.in_docrt ? TRUE : FALSE, - show_gold = (ttyinvmode & InvShowGold) != 0, - inuse_only = (ttyinvmode & InvInUse) != 0, - sparse = (ttyinvmode & InvSparse) != 0; - - if (g.perm_invent_win == WIN_ERR - && !done_tty_perm_invent_init && iflags.perm_invent) { - g.perm_invent_win = create_nhwindow(NHW_PERMINVENT); - if (g.perm_invent_win == WIN_ERR) { - tty_perm_invent_toggled(TRUE); /* TRUE means negated */ - return; +#if !defined(TTY_PERM_INVENT) + return (win_request_info *) 0; + nhUse(window); + nhUse(request); + nhUse(wri); +#else + boolean tty_ok /*, show_gold */, inuse_only; + int maxslot; + /* these types are set match the wintty.h field declarations */ + long minrow; /* long to match maxrow declaration in wintty.h */ + short offx, offy; + long rows, cols, maxrow, maxcol; + + if (!wri) + return (win_request_info *) 0; + + switch (request) { + case set_mode: + case request_settings: + ttyinvmode = wri->fromcore.invmode; + /* show_gold = (ttyinvmode & InvShowGold) != 0; */ + inuse_only = ((ttyinvmode & InvInUse) != 0); + if (request == set_mode) + break; + wri->tocore = zero_tocore; + tty_ok = assesstty(ttyinvmode, &offx, &offy, &rows, &cols, &maxcol, + &minrow, &maxrow); + wri->tocore.needrows = (int) (minrow + 1 + ROWNO + 3); + wri->tocore.needcols = (int) tty_perminv_mincol; + wri->tocore.haverows = (int) ttyDisplay->rows; + wri->tocore.havecols = (int) ttyDisplay->cols; + if (!tty_ok) { + wri->tocore.tocore_flags |= prohibited; /* prohibited */ + return wri; } - display_nhwindow(g.perm_invent_win, FALSE); - window = g.perm_invent_win; + maxslot = (maxrow - 2) * (!inuse_only ? 2 : 1); + wri->tocore.maxslot = maxslot; + return wri; + break; + default: + impossible("invalid request to tty_update_invent_slot %u", request); } - /* we just return if the window creation failed, probably due to - not meeting size requirements */ - if (window == WIN_ERR) - return; + return wri; +#endif +} - if (!iflags.perm_invent) { - if (done_tty_perm_invent_init) { - /* Odd - but this could be end-of-game disclosure - * which just sets boolean iflag.perm_invent to - * FALSE without actually doing anything else. - */ - tty_perm_invent_toggled(TRUE); /* TRUE means negated */ - (void) doredraw(); - } - return; +#ifdef TTY_PERM_INVENT + +static int +ttyinv_create_window(int newid, struct WinDesc *newwin) +{ + int i, r, c; + long minrow; /* long to match maxrow declaration */ + unsigned n; + + /* Is there enough real estate to do this beyond the status line? + * Rows: + * Top border line (1) + * 26 inventory rows (26) + * [should be 27 to have room for '$' and '#'] + * Bottom border line (1) + * 1 + 26 + 1 = 28 + * + * Cols: + * Left border (1) + * Left inventory items (38) + * Middle separation (1) + * Right inventory items (38) + * Right border (1) + * 1 + 38 + 1 + 38 + 1 = 79 + * + * The topline + map rows + status lines require: + * 1 + 21 + 2 (or 3) = 24 (or 25 depending on status line count). + * So we can only present a full inventory on tty if there are + * 28 + 24 (or 25) available (52 or 53 rows on the terminal). + * Correspondingly ttyDisplay->rows has to be at least 52 (or 53). + * [The top and bottom borderlines aren't necessary. Suppressing + * them would reduce the number of rows needed by 2.] + * + */ + + /* preliminary init in case tty_desctroy_nhwindow() gets called */ + newwin->data = (char **) 0; + newwin->datlen = (short *) 0; + newwin->cells = (struct tty_perminvent_cell **) 0; + + + if (!assesstty(ttyinvmode, &newwin->offx, &newwin->offy, &newwin->rows, + &newwin->cols, &newwin->maxcol, &minrow, + &newwin->maxrow)) { + tty_destroy_nhwindow(newid); /* sets WIN_INVEN to WIN_ERR */ + pline("%s.", "tty perm_invent could not be enabled"); + pline("tty perm_invent needs a terminal that is at least %dx%d, " + "yours is %dx%d.", + (int) (minrow + 1 + ROWNO + 3), tty_perminv_mincol, + ttyDisplay->rows, ttyDisplay->cols); + tty_wait_synch(); + set_option_mod_status("perm_invent", set_gameview); + iflags.perm_invent = FALSE; + return WIN_ERR; } - if ((cw = wins[window]) == (struct WinDesc *) 0) - panic(winpanicstr, window); - if (!done_tty_perm_invent_init) { - tty_invent_box_glyph_init(cw); + /* + * Terminal/window/screen is big enough. + */ + newwin->maxrow = minrow; + newwin->maxcol = newwin->cols; + /* establish the borders */ + bordercol[border_left] = 0; + bordercol[border_middle] = (newwin->maxcol + 1) / 2; + bordercol[border_right] = newwin->maxcol - 1; + /* for in-use mode, use full lines */ + if ((ttyinvmode & InvInUse) != 0) + bordercol[border_middle] = bordercol[border_right]; + + n = (unsigned) (newwin->maxrow * sizeof(struct tty_perminvent_cell *)); + newwin->cells = (struct tty_perminvent_cell **) alloc(n); + + n = (unsigned) (newwin->maxcol * sizeof(struct tty_perminvent_cell)); + for (i = 0; i < newwin->maxrow; i++) + newwin->cells[i] = (struct tty_perminvent_cell *) alloc(n); + + n = (unsigned) sizeof(glyph_info); + for (r = 0; r < newwin->maxrow; r++) + for (c = 0; c < newwin->maxcol; c++) { + newwin->cells[r][c] = zerottycell; + if (r == 0 || r == newwin->maxrow - 1 + || c == bordercol[border_left] + || c == bordercol[border_middle] + || c == bordercol[border_right]) { + newwin->cells[r][c].content.gi = (glyph_info *) alloc(n); + *newwin->cells[r][c].content.gi = zerogi; + newwin->cells[r][c].glyph = 1; + } + } + newwin->active = 1; + tty_invent_box_glyph_init(newwin); + return newid; +} + +static void +ttyinv_add_menu(winid window UNUSED, struct WinDesc *cw, char ch, + int attr UNUSED, int clr UNUSED, const char *str) +{ + char invbuf[BUFSZ]; + const char *text; + boolean inuse_only = (ttyinvmode & InvInUse) != 0, + show_gold = (ttyinvmode & InvShowGold) != 0, + /* sparse = (ttyinvmode & InvSparse) != 0, */ + ignore = FALSE; + int row, side, slot = 0, rows_per_side = (!show_gold ? 26 : 27); + + if (!g.program_state.in_moveloop) + return; + slot = selector_to_slot(ch, ttyinvmode, &ignore); + if (!ignore) { + /* inuse_only = ((ttyinvmode & InvInUse) != 0); */ + slot_tracker[slot] = TRUE; + text = Empty; /* lint suppression */ + /* maxslot = ((int) cw->maxrow - 2) * (!inuse_only ? 2 : + * 1); */ + + /* TODO: check for MENUCOLORS match */ + text = str; /* 'text' will switch to invbuf[] below */ + /* strip away "a"/"an"/"the" prefix to show a bit more of + the interesting part of the object's description; this + is inline version of pi_article_skip() from cursinvt.c; + should move that to hacklib.c and use it here */ + if (text[0] == 'a') { + if (text[1] == ' ') + text += 2; + else if (text[1] == 'n' && text[2] == ' ') + text += 3; + } else if (text[0] == 't') { + if (text[1] == 'h' && text[2] == 'e' && text[3] == ' ') + text += 4; + } + Snprintf(invbuf, sizeof invbuf, "%c - %s", ch, text); + text = invbuf; + row = (slot % rows_per_side) + 1; /* +1: top border */ + /* side: left side panel or right side panel, not a window column */ + side = slot < rows_per_side ? 0 : 1; + if (!(inuse_only && side == 1)) + ttyinv_populate_slot(cw, row, side, text, 0); } + return; +} +static int +selector_to_slot(char ch, const int invflags, boolean *ignore) +{ + int slot = 0; + boolean show_gold = (invflags & InvShowGold) != 0, + inuse_only = (invflags & InvInUse) != 0; +#if 0 + sparse = (invflags & InvSparse) != 0, +#endif - text = Empty; /* lint suppression */ - maxslot = ((int) cw->maxrow - 2) * (!inuse_only ? 2 : 1); - obj = g.invent; - for (slot = 0; slot < maxslot; ++slot) { - nxtlet = '?'; /* always gets set to something else if actually used */ - if (!sparse) { - while (obj && ((obj->invlet == GOLD_SYM && !show_gold) - || (!obj->owornmask && inuse_only))) - obj = obj->nobj; + *ignore = FALSE; + switch (ch) { + case '$': + if (!show_gold) + *ignore = TRUE; + slot = 0; + break; + case '#': + slot = 52 + (show_gold ? 1 : 0); + break; + case 0: + *ignore = TRUE; + break; + default: + if (!inuse_only) { + if (ch >= 'a' && ch <= 'z') + slot = (ch - 'a') + (show_gold ? 1 : 0); + if (ch >= 'A' && ch <= 'Z') + slot = (ch - 'A') + (show_gold ? 1 : 0) + 26; } else { - if (!show_gold) - nxtlet = (slot < 26) ? ('a' + slot) : ('A' + slot - 26); - else - nxtlet = (slot == 0) ? GOLD_SYM - : (slot < 27) ? ('a' + slot - 1) - : (slot < 53) ? ('A' + slot - 27) - : NOINVSYM; - for (obj = g.invent; obj; obj = obj->nobj) - if (obj->invlet == nxtlet) - break; + if ((ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z')) + slot = (show_gold ? 1 : 0) + inuse_only_start++; } + } + return slot; +} - if (obj) { - /* TODO: check for MENUCOLORS match */ - text = doname(obj); /* 'text' will switch to invbuf[] below */ - /* strip away "a"/"an"/"the" prefix to show a bit more of the - interesting part of the object's description; - this is inline version of pi_article_skip() from cursinvt.c; - should move that to hacklib.c and use it here */ - if (text[0] == 'a') { - if (text[1] == ' ') - text += 2; - else if (text[1] == 'n' && text[2] == ' ') - text += 3; - } else if (text[0] == 't') { - if (text[1] == 'h' && text[2] == 'e' && text[3] == ' ') - text += 4; - } - Snprintf(invbuf, sizeof invbuf, "%c - %s", obj->invlet, text); - text = invbuf; - obj = obj->nobj; /* set up for next iteration */ - } else if (sparse) { - Sprintf(invbuf, "%c", nxtlet); /* empty slot */ +static void +ttyinv_render(winid window, struct WinDesc *cw) +{ + int row, col, slot, side, filled_count = 0, slot_limit; + struct tty_perminvent_cell *cell; + char invbuf[BUFSZ], *text; + boolean force_redraw = g.program_state.in_docrt ? TRUE : FALSE, + show_gold = (ttyinvmode & InvShowGold) != 0, + inuse_only = (ttyinvmode & InvInUse) != 0; + int rows_per_side = (!show_gold ? 26 : 27); + + slot_limit = SIZE(slot_tracker); + if (inuse_only) { + rows_per_side = cw->maxrow - 2; /* -2 top and bottom borders */ + } + for (slot = 0; slot < slot_limit; ++slot) + if (slot_tracker[slot]) + filled_count++; + for (slot = 0; slot < slot_limit; ++slot) { + if (slot_tracker[slot]) + continue; + if (slot == 0 && !filled_count) { + Sprintf(invbuf, "%-4s[%s]", "", + !filled_count ? "empty" + : inuse_only ? "no items are in use" + : "only gold"); text = invbuf; } else { - if (slot == 0) { - Sprintf(invbuf, "%-4s[%s]", "", - !g.invent ? "empty" - : inuse_only ? "no items are in use" - : "only gold"); - text = invbuf; - } else { - text = Empty; /* "" => fill slot with spaces */ - } + text = Empty; /* "" => fill slot with spaces */ } - - row = (slot % (!show_gold ? 26 : 27)) + 1; /* +1: top border */ + row = (slot % rows_per_side) + 1; /* +1: top border */ /* side: left side panel or right side panel, not a window column */ - side = slot < (!show_gold ? 26 : 27) ? 0 : 1; - - ttyinv_populate_slot(cw, row, side, text, 0); + side = slot < rows_per_side ? 0 : 1; + if (!(inuse_only && side == 1)) + ttyinv_populate_slot(cw, row, side, text, 0); } - + /* has there been a glyph reset since we last got here? */ + if (g.glyph_reset_timestamp > last_glyph_reset_when) { + // tty_invent_box_glyph_init(wins[WIN_INVEN]); + last_glyph_reset_when = g.glyph_reset_timestamp; + force_redraw = TRUE; + } + /* render to the display */ calling_from_update_inventory = TRUE; - /* now render to the display */ for (row = 0; row < cw->maxrow; ++row) for (col = 0; col < cw->maxcol; ++col) { cell = &cw->cells[row][col]; if (cell->refresh || force_redraw) { if (cell->glyph) { - tty_print_glyph(window, col + 1, row, - cell->content.gi, &nul_glyphinfo); + tty_print_glyph(window, col + 1, row, cell->content.gi, + &nul_glyphinfo); end_glyphout(); } else { if (col != cw->curx || row != cw->cury) @@ -3627,113 +3741,13 @@ tty_update_inventory(int arg UNUSED) cell->refresh = 0; } } + tty_curs(window, 1, 0); + for (slot = 0; slot < SIZE(slot_tracker); ++slot) + slot_tracker[slot] = 0; calling_from_update_inventory = FALSE; -#endif /* CORE_INVENT */ -#endif /* TTY_PERM_INVENT */ return; } -perminvent_info * -tty_update_invent_slot( - winid window, /* window to use, must be of type NHW_MENU */ - int slot, - perminvent_info *pi) -{ -#if !defined(TTY_PERM_INVENT) || !defined(CORE_INVENT) - return (perminvent_info *) 0; - nhUse(window); - nhUse(slot); - nhUse(pi); -#else - boolean force_redraw, tty_ok, show_gold, inuse_only; - int row, col, side, maxslot; - /* winid window = g.perm_invent_win; */ - struct WinDesc *cw; - struct tty_perminvent_cell *cell; - /* these types are set match the wintty.h field declarations */ - long minrow; /* long to match maxrow declaration in wintty.h */ - short offx, offy; - long rows, cols, maxrow, maxcol; - - if (!pi) - return (perminvent_info *) 0; - if (!done_tty_perm_invent_init - && pi->fromcore.core_request != request_settings) { - pi->tocore.tocore_flags |= no_init_done; - return pi; - } - ttyinvmode = pi->fromcore.invmode; - show_gold = (ttyinvmode & InvShowGold) != 0; - inuse_only = (ttyinvmode & InvInUse) != 0; - /* sparse isn't needed port-side */ - - switch(pi->fromcore.core_request) { - case request_settings: - pi->tocore = zero_tocore; - tty_ok = assesstty(ttyinvmode, - &offx, &offy, &rows, &cols, - &maxcol, &minrow, &maxrow); - pi->tocore.needrows = (int) (minrow + 1 + ROWNO + 3); - pi->tocore.needcols = (int) tty_pi_mincol; - pi->tocore.haverows = (int) ttyDisplay->rows; - pi->tocore.havecols = (int) ttyDisplay->cols; - if (!tty_ok) { - pi->tocore.tocore_flags |= prohibited; /* prohibited */ - return pi; - } - maxslot = (maxrow - 2) * (!inuse_only ? 2 : 1); - pi->tocore.maxslot = maxslot; - return pi; - break; - case update_slot: - if ((cw = wins[window]) == (struct WinDesc *) 0) - panic(winpanicstr, window); - slot -= 1; /* 0 is used for commands */ - row = (slot % (!show_gold ? 26 : 27)) + 1; /* +1: top border */ - /* side: left side panel or right side panel, not a window column */ - side = slot < (!show_gold ? 26 : 27) ? 0 : 1; - ttyinv_populate_slot(cw, row, side, - pi->fromcore.text, pi->fromcore.clr); - break; - case render: - if ((cw = wins[window]) == (struct WinDesc *) 0) - panic(winpanicstr, window); - /* render to the display */ - force_redraw = pi->fromcore.force_redraw; - calling_from_update_inventory = TRUE; - for (row = 0; row < cw->maxrow; ++row) - for (col = 0; col < cw->maxcol; ++col) { - cell = &cw->cells[row][col]; - if (cell->refresh || force_redraw) { - if (cell->glyph) { - tty_print_glyph(window, col + 1, row, - cell->content.gi, &nul_glyphinfo); - end_glyphout(); - } else { - if (col != cw->curx || row != cw->cury) - tty_curs(window, col + 1, row); - (void) putchar(cell->content.ttychar); - ttyDisplay->curx++; - cw->curx++; - } - cell->refresh = 0; - } - } - tty_curs(window, 1, 0); - ttyDisplay->curx = 1; - calling_from_update_inventory = FALSE; - break; - default: - impossible("invalid request to tty_update_invent_slot %u", - pi->fromcore.core_request); - } - return pi; -#endif -} - -RESTORE_WARNING_FORMAT_NONLITERAL - -#ifdef TTY_PERM_INVENT /* * returns TRUE if things are ok */ @@ -3753,7 +3767,7 @@ assesstty( *offy = 1 + ROWNO + 3; /* 3: + 2 + (iflags.wc2_statuslines > 2) */ *rows = (ttyDisplay->rows - (*offy)); *cols = ttyDisplay->cols; - *minrow = tty_pi_minrow; + *minrow = tty_perminv_minrow; if (show_gold) *minrow += 1; /* "normal" max for items in use would be 3 weapon + 7 armor + 4 @@ -3767,7 +3781,7 @@ assesstty( *minrow = 1 + 15 + 1; /* top border + 15 lines + bottom border */ *maxrow = *minrow; *maxcol = *cols; - return !(*rows < *minrow || *cols < tty_pi_mincol); + return !(*rows < *minrow || *cols < tty_perminv_mincol); } /* put the formatted object description for one item into a particular row @@ -3783,7 +3797,12 @@ ttyinv_populate_slot( char c; int ccnt, col, endcol; - col = bordercol[side] + 1; + /* FIXME: this needs a review. Crashed under InvInUse without */ + if ((ttyinvmode & InvInUse) != 0) + col = bordercol[0] + 1; + else + col = bordercol[side] + 1; + endcol = bordercol[side + 1] - 1; cell = &cw->cells[row][col]; if (cell->color != color) @@ -3819,7 +3838,7 @@ tty_refresh_inventory(int start, int stop, int y) { int row = y, col, col_limit = stop; struct WinDesc *cw = 0; - winid window = g.perm_invent_win; + winid window = WIN_INVEN; struct tty_perminvent_cell *cell; if (window == WIN_ERR || !iflags.perm_invent || y < 0) @@ -3856,11 +3875,14 @@ RESTORE_WARNING_FORMAT_NONLITERAL static void tty_invent_box_glyph_init(struct WinDesc *cw) -{ + { int row, col; uchar sym; struct tty_perminvent_cell *cell; + if (cw == 0 || !cw->active) + return; + for (row = 0; row < cw->maxrow; ++row) for (col = 0; col < cw->maxcol; ++col) { cell = &cw->cells[row][col]; @@ -3927,9 +3949,16 @@ tty_invent_box_glyph_init(struct WinDesc *cw) } done_tty_perm_invent_init = TRUE; } - #endif /* TTY_PERM_INVENT */ +/* update persistent inventory window */ +void +tty_update_inventory(int arg UNUSED) +{ + /* currently not used */ + return; +} + void tty_mark_synch(void) { @@ -3972,8 +4001,8 @@ docorner(register int xmin, register int ymax, int ystart_between_menu_pages) #ifdef TTY_PERM_INVENT struct WinDesc *icw = 0; - if (g.perm_invent_win != WIN_ERR) - icw = wins[g.perm_invent_win]; + if (WIN_INVEN != WIN_ERR) + icw = wins[WIN_INVEN]; #endif HUPSKIP(); diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 8876dae45..35667ce8c 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -120,7 +120,7 @@ struct window_procs mswin_procs = { mswin_status_update, genl_can_suspend_yes, mswin_update_inventory, - mswin_update_invent_slot, + mswin_ctrl_nhwindow, }; /* @@ -1245,15 +1245,13 @@ mswin_update_inventory(int arg) display_inventory(NULL, FALSE); } -perminvent_info * -mswin_update_invent_slot( - winid window, /* window to use, must be of type NHW_MENU */ - int inventory_slot, /* slot id: 0 - info return to core */ - /* 1 - gold slot */ - /* 2 - 29 obj slots */ - perminvent_info *pi) +win_request_info * +mswin_ctrl_nhwindow( + winid window, + int request, + win_request_info *wri) { - return (perminvent_info *) 0; + return (win_request_info *) 0; } /* diff --git a/win/win32/winMS.h b/win/win32/winMS.h index 940f089d3..23d98b736 100644 --- a/win/win32/winMS.h +++ b/win/win32/winMS.h @@ -193,7 +193,7 @@ void mswin_status_enablefield(int fieldidx, const char *nm, const char *fmt, boolean enable); void mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, unsigned long *colormasks); void mswin_update_inventory(int); -perminvent_info *mswin_update_invent_slot(winid, int, perminvent_info *); +win_request_info *mswin_ctrl_nhwindow(winid, int, win_request_info *); /* helper function */ HWND mswin_hwnd_from_winid(winid wid);