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 following conditions can bring us to here: + * 1. iflags.perm_invent is on + * AND + * g.core_invent_state is still zero. * - * The window port informs the core of the number of - * slots that it will process. + * OR * - * The core tells the window port what the contents of the - * inventory slots should be. - * - * The core requests the window port when to render, after - * all the content has been updated. - * - * 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 int ttyinv_create_window(int, struct WinDesc *); - -static void tty_invent_box_glyph_init(struct WinDesc *cw); 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 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) { +#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; + } + 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); + } + return wri; +#endif +} + #ifdef TTY_PERM_INVENT -#ifndef CORE_INVENT - static char Empty[1] = { '\0' }; - struct WinDesc *cw; + +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; + } + + /* + * 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 + + *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 ((ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z')) + slot = (show_gold ? 1 : 0) + inuse_only_start++; + } + } + return 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; - struct obj *obj; - char invbuf[BUFSZ], *text, nxtlet; - int row, col, side, slot, maxslot; - winid window = g.perm_invent_win; + char invbuf[BUFSZ], *text; boolean force_redraw = g.program_state.in_docrt ? TRUE : FALSE, show_gold = (ttyinvmode & InvShowGold) != 0, - inuse_only = (ttyinvmode & InvInUse) != 0, - sparse = (ttyinvmode & InvSparse) != 0; + inuse_only = (ttyinvmode & InvInUse) != 0; + int rows_per_side = (!show_gold ? 26 : 27); - 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; - } - display_nhwindow(g.perm_invent_win, FALSE); - window = g.perm_invent_win; + slot_limit = SIZE(slot_tracker); + if (inuse_only) { + rows_per_side = cw->maxrow - 2; /* -2 top and bottom borders */ } - /* we just return if the window creation failed, probably due to - not meeting size requirements */ - if (window == WIN_ERR) - return; - - 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; - } - if ((cw = wins[window]) == (struct WinDesc *) 0) - panic(winpanicstr, window); - - if (!done_tty_perm_invent_init) { - tty_invent_box_glyph_init(cw); - } - - 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; - } 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 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 */ + 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);