]> granicus.if.org Git - nethack/commitdiff
experimental change for tty perm_invent
authorPatR <rankin@nethack.org>
Thu, 23 Jun 2022 09:05:52 +0000 (02:05 -0700)
committerPatR <rankin@nethack.org>
Thu, 23 Jun 2022 09:05:52 +0000 (02:05 -0700)
This checks for 'TTYINV' in the environment and if found, it uses that
as a number describing a bit mask for how to show the perm_invent.
 0 = current behavior, a-zA-Z in two columns (I've started referring
     to those as panels because "column" is already used a lot);
 1 = "show gold" => $a-zA-Z# in two columns; requires 1 more line;
 2 = "sparse" => list all letters a-z in the left panel and A-Z in
     the right whether there is an item in the slot or not, so that
     open slots will be obvious;
 3 = 1|2, "sparse" with $a-zA-Z$ instead of just letters;
 4 = "in use" => full lines instead of side-by-side panels, listing
     only items with non-zero obj->owornmask; currently requires 17
     lines instead of 28 (or 29 for show-gold):  room for top border,
     15 lines of worn/wielded items, and bottom border; normal usage
     would be capped at 3 weapon slots, 7 armor slots, and 4 accessory
     slots, but it is possible to have more items in use (simplest
     case is to pick up the iron ball while punished).
The #4 case isn't displaying its bottom border correctly and I haven't
figured out why.

If this turns out to be useful, perm_invent can become a compound or
some new option for perminv mode could be added.

win/tty/wintty.c

index b538f449afad16d43d1df0b5b5457a5e884b100d..b4809569a261427a3ba6972392d31b2051687f00 100644 (file)
@@ -253,7 +253,7 @@ void g_pututf8(uint8 *utf8str);
 
 #ifdef TTY_PERM_INVENT
 void tty_perm_invent_toggled(boolean negated);
-static int tty_create_invent(int, struct WinDesc *);
+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;
 /* this could/should be static */
@@ -261,6 +261,8 @@ struct tty_perminvent_cell zerottycell = { 0, 0, 0, 0, { 0 } };
 static glyph_info zerogi = { 0 };
 enum { border_left, border_middle, border_right, border_elements };
 static int bordercol[border_elements] = { 0, 0, 0 }; /* left, middle, right */
+enum { InvNormal = 0, InvShowGold = 1, InvSparse = 2, InvInUse = 4 };
+static int ttyinvmode = InvNormal;
 #endif
 
 /*
@@ -1590,7 +1592,12 @@ tty_create_nhwindow(int type)
         break;
 #ifdef TTY_PERM_INVENT
     case NHW_TTYINVENT:
-        return tty_create_invent(newid, newwin);
+        {
+            /*TEMPORARY*/
+            char *envtmp = nh_getenv("TTYINV");
+            ttyinvmode = envtmp ? atoi(envtmp) : InvNormal;
+        }
+        return ttyinv_create_window(newid, newwin);
 #endif
     default:
         panic("Tried to create window type %d\n", (int) type);
@@ -1625,9 +1632,9 @@ tty_create_nhwindow(int type)
 #ifdef TTY_PERM_INVENT
 
 static int
-tty_create_invent(int newid, struct WinDesc *newwin)
+ttyinv_create_window(int newid, struct WinDesc *newwin)
 {
-    int i, r, c;
+    int i, r, c, minrow;
     unsigned n;
 
     /* Is there enough real estate to do this beyond the status line?
@@ -1662,19 +1669,30 @@ tty_create_invent(int newid, struct WinDesc *newwin)
     newwin->cols = ttyDisplay->cols;
     newwin->maxrow = 0;
     newwin->maxcol = 79;  /* bhaak */
-    /* these weren't initialized as of yet, and as such could
-       be non-zero which would cause tty_destroy_window()
-       and friends to try and free non-malloc'd memory */
+    /* 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 (newwin->rows < tty_pi_minrow || newwin->cols < tty_pi_mincol) {
+    minrow = tty_pi_minrow;
+    if ((ttyinvmode & InvShowGold) != 0)
+        minrow += 1;
+    /* "normal" max for items in use would be 3 weapon + 7 armor + 4
+       accessories == 14, but being punished and picking up the ball will
+       add 1, and some quest artifacts have an an #invoke property that's
+       tracked via obj->owornmask so could add more; if hero ends up with
+       more than 15 in-use items, some will be left out;
+       Qt's "paper doll" adds first lit lamp/candle and first active
+       leash; those aren't tracked via owornmask so we don't notice them */
+    if ((ttyinvmode & InvInUse) != 0)
+        minrow = 1 + 15 + 1; /* top border + 15 lines + border border */
+
+    if (newwin->rows < minrow || newwin->cols < tty_pi_mincol) {
         tty_destroy_nhwindow(newid); /* sets g.tty_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.",
-              tty_pi_minrow + 1 + ROWNO + 3, tty_pi_mincol,
+              minrow + 1 + ROWNO + 3, tty_pi_mincol,
               ttyDisplay->rows, ttyDisplay->cols);
         tty_wait_synch();
         set_option_mod_status("perm_invent", set_gameview);
@@ -1685,12 +1703,15 @@ tty_create_invent(int newid, struct WinDesc *newwin)
     /*
      * Terminal/window/screen is big enough.
      */
-    newwin->maxrow = tty_pi_minrow;
+    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);
@@ -3442,6 +3463,10 @@ tty_message_menu(char let, int how, const char *mesg)
 
 #ifdef TTY_PERM_INVENT
 static boolean done_tty_perm_invent_init = FALSE;
+static void ttyinv_populate_slot(struct WinDesc *, int, int, const char *);
+#ifndef NOINVSYM /* invent.c */
+#define NOINVSYM '#'
+#endif
 DISABLE_WARNING_FORMAT_NONLITERAL
 #endif
 
@@ -3450,14 +3475,17 @@ void
 tty_update_inventory(int arg UNUSED)
 {
 #ifdef TTY_PERM_INVENT
-    int row, col, pass, ccnt;
-    struct WinDesc *cw = 0;
-    winid window = g.tty_invent_win;
-    struct obj *obj;
-    char invbuf[BUFSZ], *text, null[1] = {'\0'};
-    boolean force_redraw = g.program_state.in_docrt ? TRUE
-                            : FALSE;
+    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.tty_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;
 
     /* we just return if the window creation failed, probably due to
        not meeting size requirements */
@@ -3482,57 +3510,68 @@ tty_update_inventory(int arg UNUSED)
         tty_invent_box_glyph_init(cw);
     }
 
+    text = Empty; /* lint suppression */
+    maxslot = cw->maxrow - 1;
     obj = g.invent;
-    text = null;
-    ccnt = 0;
-    if (obj) {
-        if (obj->invlet == '$')
-            obj = obj->nobj;
-        if (obj) {
-            Snprintf(invbuf, sizeof invbuf, "%c - %s", obj->invlet,
-                     doname(obj));
-            text = invbuf;
+    for (slot = 0; slot < maxslot; ++slot) {
+        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;
         }
-    }
-    for (pass = 0; pass < 2; ++pass) {
-        for (row = 1; row < (cw->maxrow - 1); ++row) { /* row below top border */
-            for (col = (pass ? bordercol[border_middle] + 1
-                             : bordercol[border_left] + 1);
-                 col < (pass ? bordercol[border_right]
-                             : bordercol[border_middle]);
-                 ++col) {
-                cell = &cw->cells[row][col];
-                if (obj && *text && ccnt < (bordercol[border_middle] - 1)) {
-                    if (cell->content.ttychar != *text)
-                        cell->refresh = 1;
-                    cell->content.ttychar = *text;
-                    text++;
-                    ccnt++;
-                } else {
-                    if (cell->content.ttychar != ' ')
-                        cell->refresh = 1;
-                    cell->content.ttychar = ' ';
-                }
-                cell->text = 1;
-                cell->glyph = 0;
+
+        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;
             }
-            if (obj) {
-                obj = obj->nobj;
-                if (obj) {
-                    if (obj->invlet == '$')
-                        obj = obj->nobj;
-                    if (obj) {
-                        Snprintf(invbuf, sizeof invbuf, "%c - %s",
-                                 obj->invlet, doname(obj));
-                        text = invbuf;
-                        ccnt = 0;
-                    }
-                }
+            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 */
+            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 = null;
+                text = Empty; /* "" => fill slot with spaces */
             }
         }
+
+        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, text);
     }
+
     calling_from_update_inventory = TRUE;
     /* now render to the display */
     for (row = 0; row < cw->maxrow; ++row)
@@ -3541,8 +3580,7 @@ tty_update_inventory(int arg UNUSED)
             if (cell->refresh || force_redraw) {
                 if (cell->glyph) {
                     tty_print_glyph(window, col + 1, row,
-                                    cell->content.gi,
-                                    &nul_glyphinfo);
+                                    cell->content.gi, &nul_glyphinfo);
                     end_glyphout();
                 } else {
                     if (col != cw->curx || row != cw->cury)
@@ -3561,6 +3599,38 @@ tty_update_inventory(int arg UNUSED)
 
 #ifdef TTY_PERM_INVENT
 
+/* put the formatted object description for one item into a particular row
+   and left/right panel, truncating if long or padding with spaces if short */
+static void
+ttyinv_populate_slot(
+     struct WinDesc *cw,
+     int row, /* 'row' within the window, not within screen */
+     int side, /* 'side'==0 is left panel or ==1 is right panel */
+     const char *text)
+{
+    struct tty_perminvent_cell *cell;
+    char c;
+    int ccnt, col, endcol;
+
+    col = bordercol[side] + 1;
+    endcol = bordercol[side + 1] - 1;
+    cell = &cw->cells[row][col];
+    for (ccnt = col; ccnt <= endcol; ++ccnt, ++cell) {
+        if ((c = *text) != '\0') {
+            if (cell->content.ttychar != c)
+                cell->refresh = 1;
+            cell->content.ttychar = c;
+            ++text;
+        } else {
+            if (cell->content.ttychar != ' ')
+                cell->refresh = 1;
+            cell->content.ttychar = ' ';
+        }
+        cell->text = 1;
+        cell->glyph = 0;
+    }
+}
+
 void
 tty_refresh_inventory(int start, int stop, int y)
 {
@@ -3599,18 +3669,12 @@ tty_refresh_inventory(int start, int stop, int y)
     }
 }
 
-static void tty_invent_box_glyph_init(struct WinDesc *cw)
+static void
+tty_invent_box_glyph_init(struct WinDesc *cw)
 {
     int row, col, glyph;
     struct tty_perminvent_cell *cell;
 
-/*
-          1         2         3         4         5         6         7
-01234567890123456789012345678901234567890123456789012345678901234567890123456789
-x                                       x                                     x
-01234567890123456789012345678901234567890123456789012345678901234567890123456789
-*/
-
     for (row = 0; row < cw->maxrow; ++row)
         for (col = 0; col < cw->maxcol; ++col) {
             cell = &cw->cells[row][col];