]> granicus.if.org Git - nethack/commitdiff
tty-style role selection for curses
authorPatR <rankin@nethack.org>
Tue, 13 Dec 2022 00:30:27 +0000 (16:30 -0800)
committerPatR <rankin@nethack.org>
Tue, 13 Dec 2022 00:30:27 +0000 (16:30 -0800)
Move the tty role/race/&c selection from wintty.c to role.c and remove
its references to BASE_WINDOW.  Have curses call the same routine now
so that the player has the option to choose role, race, gender, and
alignment in any order and to confirm or override random settings
prior to starting play.  Also if you went through "who are you?" then
final confirmation includes an extra menu choice to rename the hero.

It still has the quirk of sometimes remembering some of the previous
aspects when you re-pick a new value for some aspect which already
been selected.

The menus pop up on top of the copyright screen and that looks a bit
strange.  I don't think core code has any way to erase that base
window without erasing the entire screen so to fix the strangeness
the window ports would need to do that before calling the selection
routine.  I didn't do that because the very first prompt, "Shall I
pick ... for you? [ynaq]" shows up in that window rather than in a
popup over it, and having it be all by itself on an otherwise blank
screen seemed to be even stranger.

X11 and Qt both have more sophisticated selection routines so I
haven't tried to switch either of them to use this.  They both use a
fancy role-selection-specific menu with all the aspects present at
once so this wouldn't fit without more work than I care to tackle.

include/extern.h
include/wincurs.h
src/role.c
win/curses/cursinit.c
win/curses/cursmain.c
win/tty/wintty.c

index 8a88f5abceff37c950a08adf67afa013dbb26fa5..3e446f7a6d725ffa029a627483cc36d24f70b6a2 100644 (file)
@@ -2417,6 +2417,8 @@ extern void role_init(void);
 extern const char *Hello(struct monst *);
 extern const char *Goodbye(void);
 extern const struct Race *character_race(short);
+extern void genl_player_selection(void);
+extern int genl_player_setup(void);
 
 /* ### rumors.c ### */
 
index 363fa4d772d8dba9c309cee69d07373ce30db7bb..88b4da29a354b548c6b5bb3a0a0b5d7dcf75e9fd 100644 (file)
@@ -154,7 +154,7 @@ extern int curses_read_char(void);
 extern void curses_toggle_color_attr(WINDOW *win, int color, int attr,
                                      int onoff);
 extern void curses_menu_color_attr(WINDOW *, int, int, int);
-extern void curses_bail(const char *mesg);
+ATTRNORETURN extern void curses_bail(const char *mesg) NORETURN;
 extern winid curses_get_wid(int type);
 extern char *curses_copy_of(const char *s);
 extern int curses_num_lines(const char *str, int width);
index e1d6a183e9e06f3cf7fcb62d11290589378595fe..188125e3c82b3dfac15a7d864424666d47b7fcb7 100644 (file)
@@ -2095,4 +2095,846 @@ character_race(short pmindex)
     return (const struct Race *) NULL;
 }
 
+/*--------------------------------------------------------------------------*/
+
+/* potential interface routine */
+void
+genl_player_selection(void)
+{
+    if (genl_player_setup())
+        return;
+
+    /* player cancelled role/race/&c selection, so quit */
+    nh_terminate(EXIT_SUCCESS);
+    /*NOTREACHED*/
+}
+
+#if defined(TTY_GRAPHICS) || defined(CURSES_GRAPHICS)
+/* ['#else' far below] */
+
+static boolean reset_role_filtering(void);
+static winid plsel_startmenu(void);
+static void setup_rolemenu(winid, boolean, int, int, int);
+static void setup_racemenu(winid, boolean, int, int, int);
+static void setup_gendmenu(winid, boolean, int, int, int);
+static void setup_algnmenu(winid, boolean, int, int, int);
+
+/* try to reduce clutter in the code below... */
+#define ROLE flags.initrole
+#define RACE flags.initrace
+#define GEND flags.initgend
+#define ALGN flags.initalign
+
+/* guts of tty's player_selection() */
+int
+genl_player_setup(void)
+{
+    char pbuf[QBUFSZ];
+    anything any;
+    int i, k, n, choice, nextpick;
+    boolean getconfirmation, picksomething;
+    winid win = WIN_ERR;
+    menu_item *selected = 0;
+    int clr = 0;
+    char pick4u = 'n';
+
+    /* Used to avoid "Is this ok?" if player has already specified all
+     * four facets of role.
+     * Note that rigid_role_checks might force any unspecified facets to
+     * have a specific value, but that will still require confirmation;
+     * player can specify the forced ones if avoiding that is demanded.
+     */
+    picksomething = (ROLE == ROLE_NONE || RACE == ROLE_NONE
+                     || GEND == ROLE_NONE || ALGN == ROLE_NONE);
+    /* Used for '-@';
+     * choose randomly without asking for all unspecified facets.
+     */
+    if (flags.randomall && picksomething) {
+        if (ROLE == ROLE_NONE)
+            ROLE = ROLE_RANDOM;
+        if (RACE == ROLE_NONE)
+            RACE = ROLE_RANDOM;
+        if (GEND == ROLE_NONE)
+            GEND = ROLE_RANDOM;
+        if (ALGN == ROLE_NONE)
+            ALGN = ROLE_RANDOM;
+    }
+
+    /* prevent unnecessary prompting if role forces race (samurai) or gender
+       (valkyrie) or alignment (rogue), or race forces alignment (orc), &c */
+    rigid_role_checks();
+
+    if (ROLE == ROLE_NONE || RACE == ROLE_NONE
+        || GEND == ROLE_NONE || ALGN == ROLE_NONE) {
+        char *prompt = build_plselection_prompt(pbuf, QBUFSZ,
+                                                ROLE, RACE, GEND, ALGN);
+        /* prompt[] contains "Shall I pick ... for you? [ynaq] "
+           y - game picks role,&c then asks player to confirm;
+           n - player manually chooses via menu selections;
+           a - like 'y', but skips confirmation and starts game;
+           q - quit
+         */
+#if 1
+        trimspaces(prompt); /* 'prompt' is constructed with trailing space */
+        /* accept any character and do validation ourselves so that we can
+           shorten prompt; it will be "Shall I pick ... for you? [ynaq] "
+           with final space appended by yn_function() [for tty at least] */
+        do {
+            pick4u = yn_function(prompt, (char *) 0, '\0', FALSE);
+            pick4u = lowc(pick4u);
+            if (pick4u == '\033' || pick4u == 'q') /* handle [q] */
+                return 0;
+            if (pick4u == ' ' || pick4u == '\n') /* default is 'y' */
+                pick4u = 'y';
+            else if (pick4u == '@') /* similar to '-@' on command line */
+                pick4u = 'a';
+            /* TODO? handle response of '?' */
+        } while (pick4u != 'y' && pick4u != 'a' && pick4u != 'n'); /* [yna] */
+
+#else /* slightly simpler but more likely to end up being wrapped */
+
+        char *p;
+        /* strip choices off prompt string; yn_function() will show them */
+        if ((p = strchr(prompt, '[')) != 0)
+            *p = '\0';
+        trimspaces(prompt); /* remove trailing space */
+        /* prompt becomes "Shall I pick ... for you? [ynaq] (y) "
+           with " [ynaq] (y) " appended by yn_function() which also changes
+           user's <space> and <return> to 'y', <escape> to 'q' */
+        pick4u = yn_function(prompt, ynaqchars, 'y', FALSE);
+        if (pick4u != 'y' && pick4u != 'a' && pick4u != 'n')
+            return 0; /* bail */
+#endif
+    }
+
+ makepicks:
+    nextpick = RS_ROLE;
+    do {
+        if (nextpick == RS_ROLE) {
+            nextpick = RS_RACE;
+            /* Select a role, if necessary;
+               we'll try to be compatible with pre-selected
+               race/gender/alignment, but may not succeed. */
+            if (ROLE < 0) {
+                /* process the choice */
+                if (pick4u == 'y' || pick4u == 'a' || ROLE == ROLE_RANDOM) {
+                    /* pick a random role */
+                    k = pick_role(RACE, GEND, ALGN, PICK_RANDOM);
+                    if (k < 0) {
+                        pline("Incompatible role!");
+                        k = randrole(FALSE);
+                    }
+                } else {
+                    /* prompt for a role */
+                    win = plsel_startmenu();
+                    /* populate the menu with role choices */
+                    setup_rolemenu(win, TRUE, RACE, GEND, ALGN);
+                    /* add miscellaneous menu entries */
+                    role_menu_extra(ROLE_RANDOM, win, TRUE);
+                    any = cg.zeroany; /* separator, not a choice */
+                    add_menu(win, &nul_glyphinfo, &any, 0, 0,
+                             ATR_NONE, clr, "", MENU_ITEMFLAGS_NONE);
+                    role_menu_extra(RS_RACE, win, FALSE);
+                    role_menu_extra(RS_GENDER, win, FALSE);
+                    role_menu_extra(RS_ALGNMNT, win, FALSE);
+                    role_menu_extra(RS_filter, win, FALSE);
+                    role_menu_extra(ROLE_NONE, win, FALSE); /* quit */
+                    Strcpy(pbuf, "Pick a role or profession");
+                    end_menu(win, pbuf);
+                    n = select_menu(win, PICK_ONE, &selected);
+                    /*
+                     * PICK_ONE with preselected choice behaves strangely:
+                     *  n == -1 -- <escape>, so use quit choice;
+                     *  n ==  0 -- explicitly chose preselected entry,
+                     *             toggling it off, so use it;
+                     *  n ==  1 -- implicitly chose preselected entry
+                     *             with <space> or <return>;
+                     *  n ==  2 -- explicitly chose a different entry, so
+                     *             both it and preselected one are in list.
+                     */
+                    if (n > 0) {
+                        choice = selected[0].item.a_int;
+                        if (n > 1 && choice == ROLE_RANDOM)
+                            choice = selected[1].item.a_int;
+                    } else
+                        choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE;
+                    if (selected)
+                        free((genericptr_t) selected), selected = 0;
+                    destroy_nhwindow(win), win = WIN_ERR;
+
+                    if (choice == ROLE_NONE) {
+                        return 0; /* selected quit */
+                    } else if (choice == RS_menu_arg(RS_ALGNMNT)) {
+                        ALGN = k = ROLE_NONE;
+                        nextpick = RS_ALGNMNT;
+                    } else if (choice == RS_menu_arg(RS_GENDER)) {
+                        GEND = k = ROLE_NONE;
+                        nextpick = RS_GENDER;
+                    } else if (choice == RS_menu_arg(RS_RACE)) {
+                        RACE = k = ROLE_NONE;
+                        nextpick = RS_RACE;
+                    } else if (choice == RS_menu_arg(RS_filter)) {
+                        ROLE = k = ROLE_NONE;
+                        (void) reset_role_filtering();
+                        nextpick = RS_ROLE;
+                    } else if (choice == ROLE_RANDOM) {
+                        k = pick_role(RACE, GEND, ALGN, PICK_RANDOM);
+                        if (k < 0)
+                            k = randrole(FALSE);
+                    } else {
+                        k = choice - 1;
+                    }
+                }
+                ROLE = k;
+            } /* needed role */
+        }     /* picking role */
+
+        if (nextpick == RS_RACE) {
+            nextpick = (ROLE < 0) ? RS_ROLE : RS_GENDER;
+            /* Select a race, if necessary;
+               force compatibility with role, try for compatibility
+               with pre-selected gender/alignment. */
+            if (RACE < 0 || !validrace(ROLE, RACE)) {
+                /* no race yet, or pre-selected race not valid */
+                if (pick4u == 'y' || pick4u == 'a' || RACE == ROLE_RANDOM) {
+                    k = pick_race(ROLE, GEND, ALGN, PICK_RANDOM);
+                    if (k < 0) {
+                        pline("Incompatible race!");
+                        k = randrace(ROLE);
+                    }
+                } else { /* pick4u == 'n' */
+                    /* Count the number of valid races */
+                    n = 0; /* number valid */
+                    k = 0; /* valid race */
+                    for (i = 0; races[i].noun; i++)
+                        if (ok_race(ROLE, i, GEND, ALGN)) {
+                            n++;
+                            k = i;
+                        }
+                    if (n == 0) {
+                        for (i = 0; races[i].noun; i++)
+                            if (validrace(ROLE, i)) {
+                                n++;
+                                k = i;
+                            }
+                    }
+                    /* Permit the user to pick, if there is more than one */
+                    if (n > 1) {
+                        win = plsel_startmenu();
+                        any = cg.zeroany; /* zero out all bits */
+                        /* populate the menu with role choices */
+                        setup_racemenu(win, TRUE, ROLE, GEND, ALGN);
+                        /* add miscellaneous menu entries */
+                        role_menu_extra(ROLE_RANDOM, win, TRUE);
+                        any.a_int = 0; /* separator, not a choice */
+                        add_menu(win, &nul_glyphinfo, &any, 0, 0,
+                                 ATR_NONE, clr, "", MENU_ITEMFLAGS_NONE);
+                        role_menu_extra(RS_ROLE, win, FALSE);
+                        role_menu_extra(RS_GENDER, win, FALSE);
+                        role_menu_extra(RS_ALGNMNT, win, FALSE);
+                        role_menu_extra(RS_filter, win, FALSE);
+                        role_menu_extra(ROLE_NONE, win, FALSE); /* quit */
+                        Strcpy(pbuf, "Pick a race or species");
+                        end_menu(win, pbuf);
+                        n = select_menu(win, PICK_ONE, &selected);
+                        if (n > 0) {
+                            choice = selected[0].item.a_int;
+                            if (n > 1 && choice == ROLE_RANDOM)
+                                choice = selected[1].item.a_int;
+                        } else
+                            choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE;
+                        if (selected)
+                            free((genericptr_t) selected), selected = 0;
+                        destroy_nhwindow(win), win = WIN_ERR;
+
+                        if (choice == ROLE_NONE) {
+                            return 0; /* selected quit */
+                        } else if (choice == RS_menu_arg(RS_ALGNMNT)) {
+                            ALGN = k = ROLE_NONE;
+                            nextpick = RS_ALGNMNT;
+                        } else if (choice == RS_menu_arg(RS_GENDER)) {
+                            GEND = k = ROLE_NONE;
+                            nextpick = RS_GENDER;
+                        } else if (choice == RS_menu_arg(RS_ROLE)) {
+                            ROLE = k = ROLE_NONE;
+                            nextpick = RS_ROLE;
+                        } else if (choice == RS_menu_arg(RS_filter)) {
+                            RACE = k = ROLE_NONE;
+                            if (reset_role_filtering())
+                                nextpick = RS_ROLE;
+                            else
+                                nextpick = RS_RACE;
+                        } else if (choice == ROLE_RANDOM) {
+                            k = pick_race(ROLE, GEND, ALGN, PICK_RANDOM);
+                            if (k < 0)
+                                k = randrace(ROLE);
+                        } else {
+                            k = choice - 1;
+                        }
+                    }
+                }
+                RACE = k;
+            } /* needed race */
+        }     /* picking race */
+
+        if (nextpick == RS_GENDER) {
+            nextpick = (ROLE < 0) ? RS_ROLE : (RACE < 0) ? RS_RACE
+                       : RS_ALGNMNT;
+            /* Select a gender, if necessary;
+               force compatibility with role/race, try for compatibility
+               with pre-selected alignment. */
+            if (GEND < 0 || !validgend(ROLE, RACE, GEND)) {
+                /* no gender yet, or pre-selected gender not valid */
+                if (pick4u == 'y' || pick4u == 'a' || GEND == ROLE_RANDOM) {
+                    k = pick_gend(ROLE, RACE, ALGN, PICK_RANDOM);
+                    if (k < 0) {
+                        pline("Incompatible gender!");
+                        k = randgend(ROLE, RACE);
+                    }
+                } else { /* pick4u == 'n' */
+                    /* Count the number of valid genders */
+                    n = 0; /* number valid */
+                    k = 0; /* valid gender */
+                    for (i = 0; i < ROLE_GENDERS; i++)
+                        if (ok_gend(ROLE, RACE, i, ALGN)) {
+                            n++;
+                            k = i;
+                        }
+                    if (n == 0) {
+                        for (i = 0; i < ROLE_GENDERS; i++)
+                            if (validgend(ROLE, RACE, i)) {
+                                n++;
+                                k = i;
+                            }
+                    }
+                    /* Permit the user to pick, if there is more than one */
+                    if (n > 1) {
+                        win = plsel_startmenu();
+                        any = cg.zeroany; /* zero out all bits */
+                        /* populate the menu with gender choices */
+                        setup_gendmenu(win, TRUE, ROLE, RACE, ALGN);
+                        /* add miscellaneous menu entries */
+                        role_menu_extra(ROLE_RANDOM, win, TRUE);
+                        any.a_int = 0; /* separator, not a choice */
+                        add_menu(win, &nul_glyphinfo, &any, 0, 0,
+                                 ATR_NONE, clr, "", MENU_ITEMFLAGS_NONE);
+                        role_menu_extra(RS_ROLE, win, FALSE);
+                        role_menu_extra(RS_RACE, win, FALSE);
+                        role_menu_extra(RS_ALGNMNT, win, FALSE);
+                        role_menu_extra(RS_filter, win, FALSE);
+                        role_menu_extra(ROLE_NONE, win, FALSE); /* quit */
+                        Strcpy(pbuf, "Pick a gender or sex");
+                        end_menu(win, pbuf);
+                        n = select_menu(win, PICK_ONE, &selected);
+                        if (n > 0) {
+                            choice = selected[0].item.a_int;
+                            if (n > 1 && choice == ROLE_RANDOM)
+                                choice = selected[1].item.a_int;
+                        } else
+                            choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE;
+                        if (selected)
+                            free((genericptr_t) selected), selected = 0;
+                        destroy_nhwindow(win), win = WIN_ERR;
+
+                        if (choice == ROLE_NONE) {
+                            return 0; /* selected quit */
+                        } else if (choice == RS_menu_arg(RS_ALGNMNT)) {
+                            ALGN = k = ROLE_NONE;
+                            nextpick = RS_ALGNMNT;
+                        } else if (choice == RS_menu_arg(RS_RACE)) {
+                            RACE = k = ROLE_NONE;
+                            nextpick = RS_RACE;
+                        } else if (choice == RS_menu_arg(RS_ROLE)) {
+                            ROLE = k = ROLE_NONE;
+                            nextpick = RS_ROLE;
+                        } else if (choice == RS_menu_arg(RS_filter)) {
+                            GEND = k = ROLE_NONE;
+                            if (reset_role_filtering())
+                                nextpick = RS_ROLE;
+                            else
+                                nextpick = RS_GENDER;
+                        } else if (choice == ROLE_RANDOM) {
+                            k = pick_gend(ROLE, RACE, ALGN, PICK_RANDOM);
+                            if (k < 0)
+                                k = randgend(ROLE, RACE);
+                        } else {
+                            k = choice - 1;
+                        }
+                    }
+                }
+                GEND = k;
+            } /* needed gender */
+        }     /* picking gender */
+
+        if (nextpick == RS_ALGNMNT) {
+            nextpick = (ROLE < 0) ? RS_ROLE : (RACE < 0) ? RS_RACE : RS_GENDER;
+            /* Select an alignment, if necessary;
+               force compatibility with role/race/gender. */
+            if (ALGN < 0 || !validalign(ROLE, RACE, ALGN)) {
+                /* no alignment yet, or pre-selected alignment not valid */
+                if (pick4u == 'y' || pick4u == 'a' || ALGN == ROLE_RANDOM) {
+                    k = pick_align(ROLE, RACE, GEND, PICK_RANDOM);
+                    if (k < 0) {
+                        pline("Incompatible alignment!");
+                        k = randalign(ROLE, RACE);
+                    }
+                } else { /* pick4u == 'n' */
+                    /* Count the number of valid alignments */
+                    n = 0; /* number valid */
+                    k = 0; /* valid alignment */
+                    for (i = 0; i < ROLE_ALIGNS; i++)
+                        if (ok_align(ROLE, RACE, GEND, i)) {
+                            n++;
+                            k = i;
+                        }
+                    if (n == 0) {
+                        for (i = 0; i < ROLE_ALIGNS; i++)
+                            if (validalign(ROLE, RACE, i)) {
+                                n++;
+                                k = i;
+                            }
+                    }
+                    /* Permit the user to pick, if there is more than one */
+                    if (n > 1) {
+                        win = plsel_startmenu();
+                        any = cg.zeroany; /* zero out all bits */
+                        setup_algnmenu(win, TRUE, ROLE, RACE, GEND);
+                        role_menu_extra(ROLE_RANDOM, win, TRUE);
+                        any.a_int = 0; /* separator, not a choice */
+                        add_menu(win, &nul_glyphinfo, &any, 0, 0,
+                                 ATR_NONE, clr, "", MENU_ITEMFLAGS_NONE);
+                        role_menu_extra(RS_ROLE, win, FALSE);
+                        role_menu_extra(RS_RACE, win, FALSE);
+                        role_menu_extra(RS_GENDER, win, FALSE);
+                        role_menu_extra(RS_filter, win, FALSE);
+                        role_menu_extra(ROLE_NONE, win, FALSE); /* quit */
+                        Strcpy(pbuf, "Pick an alignment or creed");
+                        end_menu(win, pbuf);
+                        n = select_menu(win, PICK_ONE, &selected);
+                        if (n > 0) {
+                            choice = selected[0].item.a_int;
+                            if (n > 1 && choice == ROLE_RANDOM)
+                                choice = selected[1].item.a_int;
+                        } else
+                            choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE;
+                        if (selected)
+                            free((genericptr_t) selected), selected = 0;
+                        destroy_nhwindow(win), win = WIN_ERR;
+
+                        if (choice == ROLE_NONE) {
+                            return 0; /* selected quit */
+                        } else if (choice == RS_menu_arg(RS_GENDER)) {
+                            GEND = k = ROLE_NONE;
+                            nextpick = RS_GENDER;
+                        } else if (choice == RS_menu_arg(RS_RACE)) {
+                            RACE = k = ROLE_NONE;
+                            nextpick = RS_RACE;
+                        } else if (choice == RS_menu_arg(RS_ROLE)) {
+                            ROLE = k = ROLE_NONE;
+                            nextpick = RS_ROLE;
+                        } else if (choice == RS_menu_arg(RS_filter)) {
+                            ALGN = k = ROLE_NONE;
+                            if (reset_role_filtering())
+                                nextpick = RS_ROLE;
+                            else
+                                nextpick = RS_ALGNMNT;
+                        } else if (choice == ROLE_RANDOM) {
+                            k = pick_align(ROLE, RACE, GEND, PICK_RANDOM);
+                            if (k < 0)
+                                k = randalign(ROLE, RACE);
+                        } else {
+                            k = choice - 1;
+                        }
+                    }
+                }
+                ALGN = k;
+            } /* needed alignment */
+        }     /* picking alignment */
+
+    } while (ROLE < 0 || RACE < 0 || GEND < 0 || ALGN < 0);
+
+    /*
+     *  Role, race, &c have now been determined;
+     *  ask for confirmation and maybe go back to choose all over again.
+     *
+     *  Uses ynaq for familiarity, although 'a' is usually a
+     *  superset of 'y' but here is an alternate form of 'n'.
+     *  Menu layout:
+     *   title:  Is this ok? [ynaq]
+     *   blank:
+     *    text:  $name, $alignment $gender $race $role
+     *   blank:
+     *    menu:  y + yes; play
+     *           n - no; pick again
+     *   maybe:  a - no; rename hero
+     *           q - quit
+     *           (end)
+     */
+    getconfirmation = (picksomething && pick4u != 'a' && !flags.randomall);
+    while (getconfirmation) {
+        win = plsel_startmenu();
+        any = cg.zeroany; /* zero out all bits */
+#if 0
+        start_menu(win, MENU_BEHAVE_STANDARD);
+        any.a_int = 0;
+        char plbuf[QBUFSZ];
+        if (!roles[ROLE].name.f
+            && ((roles[ROLE].allow & ROLE_GENDMASK)
+                == (ROLE_MALE | ROLE_FEMALE)))
+            Sprintf(plbuf, " %s", genders[GEND].adj);
+        else
+            *plbuf = '\0'; /* omit redundant gender */
+        Snprintf(pbuf, sizeof pbuf, "%s, %s%s %s %s", gp.plname,
+                 aligns[ALGN].adj, plbuf, races[RACE].adj,
+                 (GEND == 1 && roles[ROLE].name.f) ? roles[ROLE].name.f
+                                                   : roles[ROLE].name.m);
+        add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, clr, pbuf,
+                 MENU_ITEMFLAGS_NONE);
+        /* blank separator */
+        any.a_int = 0;
+        add_menu(win, &nul_glyphinfo, &any, 0, 0,
+                 ATR_NONE, clr, "", MENU_ITEMFLAGS_NONE);
+#endif
+        /* [ynaq] menu choices */
+        any.a_int = 1;
+        add_menu(win, &nul_glyphinfo, &any, 'y', 0,
+                 ATR_NONE, clr, "Yes; start game", MENU_ITEMFLAGS_SELECTED);
+        any.a_int = 2;
+        add_menu(win, &nul_glyphinfo, &any, 'n', 0,
+                 ATR_NONE, clr, "No; choose role again", MENU_ITEMFLAGS_NONE);
+        if (iflags.renameallowed) {
+            any.a_int = 3;
+            add_menu(win, &nul_glyphinfo, &any, 'a', 0, ATR_NONE,
+                     clr, "Not yet; choose another name", MENU_ITEMFLAGS_NONE);
+        }
+        any.a_int = -1;
+        add_menu(win, &nul_glyphinfo, &any, 'q', 0,
+                 ATR_NONE, clr, "Quit", MENU_ITEMFLAGS_NONE);
+        Sprintf(pbuf, "Is this ok? [yn%sq]", iflags.renameallowed ? "a" : "");
+        end_menu(win, pbuf);
+        n = select_menu(win, PICK_ONE, &selected);
+        /* [pick-one menus with a preselected entry behave oddly...] */
+        choice = (n > 0) ? selected[n - 1].item.a_int : (n == 0) ? 1 : -1;
+        if (selected)
+            free((genericptr_t) selected), selected = 0;
+        destroy_nhwindow(win);
+
+        switch (choice) {
+        default: /* 'q' or ESC */
+            return 0; /* quit */
+            break;
+        case 3: { /* 'a' */
+            /*
+             * TODO: what, if anything, should be done if the name is
+             * changed to or from "wizard" after port-specific startup
+             * code has set flags.debug based on the original name?
+             */
+            int saveROLE, saveRACE, saveGEND, saveALGN;
+
+            iflags.renameinprogress = TRUE;
+            /* plnamesuffix() can change any or all of ROLE, RACE,
+               GEND, ALGN; we'll override that and honor only the name */
+            saveROLE = ROLE, saveRACE = RACE, saveGEND = GEND, saveALGN = ALGN;
+            *gp.plname = '\0';
+            plnamesuffix(); /* calls askname() when gp.plname[] is empty */
+            ROLE = saveROLE, RACE = saveRACE, GEND = saveGEND, ALGN = saveALGN;
+            break; /* getconfirmation is still True */
+        }
+        case 2: /* 'n' */
+            /* start fresh, but bypass "shall I pick everything for you?"
+               step; any partial role selection via config file, command
+               line, or name suffix is discarded this time */
+            pick4u = 'n';
+            ROLE = RACE = GEND = ALGN = ROLE_NONE;
+            goto makepicks;
+            break;
+        case 1: /* 'y' or Space or Return/Enter */
+            /* success; drop out through end of function */
+            getconfirmation = FALSE;
+            break;
+        }
+    }
+
+    /* Success! */
+    return 1;
+}
+
+static boolean
+reset_role_filtering(void)
+{
+    winid win;
+    anything any;
+    int i, n, clr = 0;
+    char filterprompt[QBUFSZ];
+    menu_item *selected = 0;
+
+    win = create_nhwindow(NHW_MENU);
+    start_menu(win, MENU_BEHAVE_STANDARD);
+    any = cg.zeroany;
+
+    /* no extra blank line preceding this entry; end_menu supplies one */
+    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, clr,
+             "Unacceptable roles", MENU_ITEMFLAGS_NONE);
+    setup_rolemenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE);
+
+    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE,
+             clr, "", MENU_ITEMFLAGS_NONE);
+    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE,
+             clr, "Unacceptable races", MENU_ITEMFLAGS_NONE);
+    setup_racemenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE);
+
+    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE,
+             clr, "", MENU_ITEMFLAGS_NONE);
+    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE,
+             clr, "Unacceptable genders", MENU_ITEMFLAGS_NONE);
+    setup_gendmenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE);
+
+    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE,
+             clr, "", MENU_ITEMFLAGS_NONE);
+    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE,
+             clr, "Unacceptable alignments", MENU_ITEMFLAGS_NONE);
+    setup_algnmenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE);
+
+    Sprintf(filterprompt, "Pick all that apply%s",
+            gotrolefilter() ? " and/or unpick any that no longer apply" : "");
+    end_menu(win, filterprompt);
+    n = select_menu(win, PICK_ANY, &selected);
+
+    if (n >= 0) { /* n==0: clear current filters and don't set new ones */
+        clearrolefilter();
+        for (i = 0; i < n; i++)
+            setrolefilter(selected[i].item.a_string);
+
+        ROLE = RACE = GEND = ALGN = ROLE_NONE;
+    }
+    if (selected)
+        free((genericptr_t) selected), selected = 0;
+    destroy_nhwindow(win);
+    return (n > 0) ? TRUE : FALSE;
+}
+
+/* start a menu; show role aspects specified so far as a header line */
+static winid
+plsel_startmenu(void)
+{
+    char qbuf[QBUFSZ];
+    winid win;
+    anything any;
+    const char *rolename;
+    int clr = 0;
+
+    /* whatever aspect was just chosen might force others (Orc => chaotic,
+       Samurai => Human+lawful, Valkyrie => female) */
+    rigid_role_checks();
+
+    rolename = (ROLE < 0) ? "<role>"
+               : (GEND == 1 && roles[ROLE].name.f) ? roles[ROLE].name.f
+                 : roles[ROLE].name.m;
+    if (!*gp.plname || ROLE < 0 || RACE < 0 || GEND < 0 || ALGN < 0) {
+        /* "<role> <race.noun> <gender> <alignment>" */
+        Sprintf(qbuf, "%.20s %.20s %.20s %.20s",
+                rolename,
+                (RACE < 0) ? "<race>" : races[RACE].noun,
+                (GEND < 0) ? "<gender>" : genders[GEND].adj,
+                (ALGN < 0) ? "<alignment>" : aligns[ALGN].adj);
+    } else {
+        /* "<name> the <alignment> <gender> <race.adjective> <role>" */
+        Sprintf(qbuf, "%.20s the %.20s %.20s %.20s %.20s",
+                gp.plname,
+                aligns[ALGN].adj,
+                genders[GEND].adj,
+                races[RACE].adj,
+                rolename);
+    }
+
+    win = create_nhwindow(NHW_MENU);
+    if (win == WIN_ERR)
+        panic("could not create role selection window");
+    start_menu(win, MENU_BEHAVE_STANDARD);
+
+    any = cg.zeroany;
+    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, clr,
+             qbuf, MENU_ITEMFLAGS_NONE);
+    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, clr,
+             "", MENU_ITEMFLAGS_NONE);
+    return win;
+}
+
+#undef ROLE
+#undef RACE
+#undef GEND
+#undef ALGN
+
+/* add entries a-Archeologist, b-Barbarian, &c to menu being built in 'win' */
+static void
+setup_rolemenu(
+    winid win,
+    boolean filtering, /* True => exclude filtered roles;
+                        * False => filter reset */
+    int race, int gend, int algn) /* all ROLE_NONE for !filtering case */
+{
+    anything any;
+    int i;
+    boolean role_ok;
+    char thisch, lastch = '\0', rolenamebuf[50];
+    int clr = 0;
+
+    any = cg.zeroany; /* zero out all bits */
+    for (i = 0; roles[i].name.m; i++) {
+        /* role can be constrained by any of race, gender, or alignment */
+        role_ok = (ok_role(i, race, gend, algn)
+                   && ok_race(i, race, gend, algn)
+                   && ok_gend(i, race, gend, algn)
+                   && ok_align(i, race, gend, algn));
+        if (filtering && !role_ok)
+            continue;
+        if (filtering)
+            any.a_int = i + 1;
+        else
+            any.a_string = roles[i].name.m;
+        thisch = lowc(*roles[i].name.m);
+        if (thisch == lastch)
+            thisch = highc(thisch);
+        Strcpy(rolenamebuf, roles[i].name.m);
+        if (roles[i].name.f) {
+            /* role has distinct name for female (C,P) */
+            if (gend == 1) {
+                /* female already chosen; replace male name */
+                Strcpy(rolenamebuf, roles[i].name.f);
+            } else if (gend < 0) {
+                /* not chosen yet; append slash+female name */
+                Strcat(rolenamebuf, "/");
+                Strcat(rolenamebuf, roles[i].name.f);
+            }
+        }
+        /* !filtering implies reset_role_filtering() where we want to
+           mark this role as preseleted if current filter excludes it */
+        add_menu(win, &nul_glyphinfo, &any, thisch, 0,
+                 ATR_NONE, clr, an(rolenamebuf),
+                 (!filtering && !role_ok)
+                    ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE);
+        lastch = thisch;
+    }
+}
+
+static void
+setup_racemenu(
+    winid win,
+    boolean filtering,
+    int role, int gend, int algn)
+{
+    anything any;
+    boolean race_ok;
+    int i;
+    char this_ch;
+    int clr = 0;
+
+    any = cg.zeroany;
+    for (i = 0; races[i].noun; i++) {
+        /* no ok_gend(); race isn't constrained by gender */
+        race_ok = (ok_race(role, i, gend, algn)
+                   && ok_role(role, i, gend, algn)
+                   && ok_align(role, i, gend, algn));
+        if (filtering && !race_ok)
+            continue;
+        if (filtering)
+            any.a_int = i + 1;
+        else
+            any.a_string = races[i].noun;
+        this_ch = *races[i].noun;
+        /* filtering: picking race, so choose by first letter, with
+           capital letter as unseen accelerator;
+           !filtering: resetting filter rather than picking, choose by
+           capital letter since lowercase role letters will be present */
+        add_menu(win, &nul_glyphinfo, &any,
+                 filtering ? this_ch : highc(this_ch),
+                 filtering ? highc(this_ch) : 0,
+                 ATR_NONE, clr, races[i].noun,
+                 (!filtering && !race_ok)
+                    ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE);
+    }
+}
+
+static void
+setup_gendmenu(
+    winid win,
+    boolean filtering,
+    int role, int race, int algn)
+{
+    anything any;
+    boolean gend_ok;
+    int i;
+    char this_ch;
+    int clr = 0;
+
+    any = cg.zeroany;
+    for (i = 0; i < ROLE_GENDERS; i++) {
+        /* no ok_align(); gender isn't constrained by alignment */
+        gend_ok = (ok_gend(role, race, i, algn)
+                   && ok_role(role, race, i, algn)
+                   && ok_race(role, race, i, algn));
+        if (filtering && !gend_ok)
+            continue;
+        if (filtering)
+            any.a_int = i + 1;
+        else
+            any.a_string = genders[i].adj;
+        this_ch = *genders[i].adj;
+        /* (see setup_racemenu for explanation of selector letters
+           and setup_rolemenu for preselection) */
+        add_menu(win, &nul_glyphinfo, &any,
+                 filtering ? this_ch : highc(this_ch),
+                 filtering ? highc(this_ch) : 0,
+                 ATR_NONE, clr, genders[i].adj,
+                 (!filtering && !gend_ok)
+                    ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE);
+    }
+}
+
+static void
+setup_algnmenu(
+    winid win,
+    boolean filtering,
+    int role, int race, int gend)
+{
+    anything any;
+    boolean algn_ok;
+    int i;
+    char this_ch;
+    int clr = 0;
+
+    any = cg.zeroany;
+    for (i = 0; i < ROLE_ALIGNS; i++) {
+        /* no ok_gend(); alignment isn't constrained by gender */
+        algn_ok = (ok_align(role, race, gend, i)
+                   && ok_role(role, race, gend, i)
+                   && ok_race(role, race, gend, i));
+        if (filtering && !algn_ok)
+            continue;
+        if (filtering)
+            any.a_int = i + 1;
+        else
+            any.a_string = aligns[i].adj;
+        this_ch = *aligns[i].adj;
+        /* (see setup_racemenu for explanation of selector letters
+           and setup_rolemenu for preselection) */
+        add_menu(win, &nul_glyphinfo, &any,
+                 filtering ? this_ch : highc(this_ch),
+                 filtering ? highc(this_ch) : 0,
+                 ATR_NONE, clr, aligns[i].adj,
+                 (!filtering && !algn_ok)
+                    ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE);
+    }
+}
+
+#else /* !TTY_GRAPHICS */
+
+int
+genl_player_setup(void)
+{
+    return 0;
+}
+
+#endif /* ?TTY_GRAPHICS */
+
 /* role.c */
index b4a4351b09205dda660bfad3d4b70134b55db04c..26f0b9ecf5e484ab7689252cb5d5fb5b4efaa89d 100644 (file)
@@ -365,6 +365,8 @@ curses_init_nhcolors(void)
 #endif
 }
 
+#if 0   /* curses_choose_character + curses_character_dialog no longer used */
+
 /* Allow player to pick character's role, race, gender, and alignment.
    Borrowed from the Gnome window port. */
 void
@@ -675,6 +677,7 @@ curses_choose_character(void)
             flags.initalign = sel;
         }
     }
+    return;
 }
 
 /* Prompt user for character race, role, alignment, or gender */
@@ -731,6 +734,8 @@ curses_character_dialog(const char **choices, const char *prompt)
     return ret;
 }
 
+#endif /* 0 */
+
 /* Initialize and display options appropriately */
 void
 curses_init_options(void)
index 3fb243bc88a519f21c837ab182672daa6b323854..ab018c711ef67c55d0692342bfe389455bd6f7f3 100644 (file)
@@ -270,14 +270,21 @@ curses_init_nhwindows(int *argcp UNUSED,
     curses_display_splash_window();
 }
 
-/* Do a window-port specific player type selection. If player_selection()
-   offers a Quit option, it is its responsibility to clean up and terminate
-   the process. You need to fill in pl_character[0].
-*/
+/* Use the general role/race/&c selection originally implemented for tty. */
 void
 curses_player_selection(void)
 {
+#if 1
+    if (genl_player_setup())
+        return; /* success */
+
+    /* quit/cancel */
+    curses_bail((const char *) NULL);
+    /*NOTREACHED*/
+#else
+    /* still present cursinit.c but no longer used */
     curses_choose_character();
+#endif
 }
 
 
index b54fee8bbbe4f439ec49b8b9b31e1fb7af927737..fb0846cf631d84d83e1b08445f454b0d63c5db5d 100644 (file)
@@ -229,12 +229,9 @@ static void process_menu_window(winid, struct WinDesc *);
 static void process_text_window(winid, struct WinDesc *);
 static tty_menu_item *reverse(tty_menu_item *);
 static const char *compress_str(const char *);
+#ifndef STATUS_HILITES
 static void tty_putsym(winid, int, int, char);
-static void setup_rolemenu(winid, boolean, int, int, int);
-static void setup_racemenu(winid, boolean, int, int, int);
-static void setup_gendmenu(winid, boolean, int, int, int);
-static void setup_algnmenu(winid, boolean, int, int, int);
-static boolean reset_role_filtering(void);
+#endif
 #ifdef STATUS_HILITES
 #define MAX_STATUS_ROWS 3
 static boolean check_fields(boolean forcefields, int sz[MAX_STATUS_ROWS]);
@@ -575,772 +572,14 @@ tty_preference_update(const char *pref)
     return;
 }
 
-/* try to reduce clutter in the code below... */
-#define ROLE flags.initrole
-#define RACE flags.initrace
-#define GEND flags.initgend
-#define ALGN flags.initalign
-
 void
 tty_player_selection(void)
 {
-    int i, k, n, choice, nextpick;
-    boolean getconfirmation, picksomething;
-    char pick4u = 'n';
-    char pbuf[QBUFSZ], plbuf[QBUFSZ];
-    winid win;
-    anything any;
-    menu_item *selected = 0;
-    int clr = 0;
-
-    /* Used to avoid "Is this ok?" if player has already specified all
-     * four facets of role.
-     * Note that rigid_role_checks might force any unspecified facets to
-     * have a specific value, but that will still require confirmation;
-     * player can specify the forced ones if avoiding that is demanded.
-     */
-    picksomething = (ROLE == ROLE_NONE || RACE == ROLE_NONE
-                     || GEND == ROLE_NONE || ALGN == ROLE_NONE);
-    /* Used for '-@';
-     * choose randomly without asking for all unspecified facets.
-     */
-    if (flags.randomall && picksomething) {
-        if (ROLE == ROLE_NONE)
-            ROLE = ROLE_RANDOM;
-        if (RACE == ROLE_NONE)
-            RACE = ROLE_RANDOM;
-        if (GEND == ROLE_NONE)
-            GEND = ROLE_RANDOM;
-        if (ALGN == ROLE_NONE)
-            ALGN = ROLE_RANDOM;
-    }
-
-    /* prevent unnecessary prompting if role forces race (samurai) or gender
-       (valkyrie) or alignment (rogue), or race forces alignment (orc), &c */
-    rigid_role_checks();
-
-    /* Should we randomly pick for the player? */
-    if (ROLE == ROLE_NONE || RACE == ROLE_NONE || GEND == ROLE_NONE
-        || ALGN == ROLE_NONE) {
-        int echoline;
-        char *prompt = build_plselection_prompt(pbuf, QBUFSZ,
-                                                ROLE, RACE, GEND, ALGN);
-
-        /* this prompt string ends in "[ynaq]?":
-           y - game picks role,&c then asks player to confirm;
-           n - player manually chooses via menu selections;
-           a - like 'y', but skips confirmation and starts game;
-           q - quit
-         */
-        tty_putstr(BASE_WINDOW, 0, "");
-        echoline = wins[BASE_WINDOW]->cury;
-        tty_putstr(BASE_WINDOW, 0, prompt);
-        do {
-            pick4u = lowc(readchar());
-            if (strchr(quitchars, pick4u))
-                pick4u = 'y';
-        } while (!strchr(ynaqchars, pick4u));
-        if ((int) strlen(prompt) + 1 < CO) {
-            /* Echo choice and move back down line */
-            tty_putsym(BASE_WINDOW, (int) strlen(prompt) + 1, echoline,
-                       pick4u);
-            tty_putstr(BASE_WINDOW, 0, "");
-        } else
-            /* Otherwise it's hard to tell where to echo, and things are
-             * wrapping a bit messily anyway, so (try to) make sure the next
-             * question shows up well and doesn't get wrapped at the
-             * bottom of the window.
-             */
-            tty_clear_nhwindow(BASE_WINDOW);
-
-        if (pick4u != 'y' && pick4u != 'a' && pick4u != 'n')
-            goto give_up;
-    }
-
- makepicks:
-    nextpick = RS_ROLE;
-    do {
-        if (nextpick == RS_ROLE) {
-            nextpick = RS_RACE;
-            /* Select a role, if necessary;
-               we'll try to be compatible with pre-selected
-               race/gender/alignment, but may not succeed. */
-            if (ROLE < 0) {
-                /* Process the choice */
-                if (pick4u == 'y' || pick4u == 'a' || ROLE == ROLE_RANDOM) {
-                    /* Pick a random role */
-                    k = pick_role(RACE, GEND, ALGN, PICK_RANDOM);
-                    if (k < 0) {
-                        tty_putstr(BASE_WINDOW, 0, "Incompatible role!");
-                        k = randrole(FALSE);
-                    }
-                } else {
-                    /* Prompt for a role */
-                    tty_clear_nhwindow(BASE_WINDOW);
-                    role_selection_prolog(RS_ROLE, BASE_WINDOW);
-                    win = create_nhwindow(NHW_MENU);
-                    start_menu(win, MENU_BEHAVE_STANDARD);
-                    /* populate the menu with role choices */
-                    setup_rolemenu(win, TRUE, RACE, GEND, ALGN);
-                    /* add miscellaneous menu entries */
-                    role_menu_extra(ROLE_RANDOM, win, TRUE);
-                    any = cg.zeroany; /* separator, not a choice */
-                    add_menu(win, &nul_glyphinfo, &any, 0, 0,
-                             ATR_NONE, clr, "", MENU_ITEMFLAGS_NONE);
-                    role_menu_extra(RS_RACE, win, FALSE);
-                    role_menu_extra(RS_GENDER, win, FALSE);
-                    role_menu_extra(RS_ALGNMNT, win, FALSE);
-                    role_menu_extra(RS_filter, win, FALSE);
-                    role_menu_extra(ROLE_NONE, win, FALSE); /* quit */
-                    Strcpy(pbuf, "Pick a role or profession");
-                    end_menu(win, pbuf);
-                    n = select_menu(win, PICK_ONE, &selected);
-                    /*
-                     * PICK_ONE with preselected choice behaves strangely:
-                     *  n == -1 -- <escape>, so use quit choice;
-                     *  n ==  0 -- explicitly chose preselected entry,
-                     *             toggling it off, so use it;
-                     *  n ==  1 -- implicitly chose preselected entry
-                     *             with <space> or <return>;
-                     *  n ==  2 -- explicitly chose a different entry, so
-                     *             both it and preselected one are in list.
-                     */
-                    if (n > 0) {
-                        choice = selected[0].item.a_int;
-                        if (n > 1 && choice == ROLE_RANDOM)
-                            choice = selected[1].item.a_int;
-                    } else
-                        choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE;
-                    if (selected)
-                        free((genericptr_t) selected), selected = 0;
-                    destroy_nhwindow(win);
-
-                    if (choice == ROLE_NONE) {
-                        goto give_up; /* Selected quit */
-                    } else if (choice == RS_menu_arg(RS_ALGNMNT)) {
-                        ALGN = k = ROLE_NONE;
-                        nextpick = RS_ALGNMNT;
-                    } else if (choice == RS_menu_arg(RS_GENDER)) {
-                        GEND = k = ROLE_NONE;
-                        nextpick = RS_GENDER;
-                    } else if (choice == RS_menu_arg(RS_RACE)) {
-                        RACE = k = ROLE_NONE;
-                        nextpick = RS_RACE;
-                    } else if (choice == RS_menu_arg(RS_filter)) {
-                        ROLE = k = ROLE_NONE;
-                        (void) reset_role_filtering();
-                        nextpick = RS_ROLE;
-                    } else if (choice == ROLE_RANDOM) {
-                        k = pick_role(RACE, GEND, ALGN, PICK_RANDOM);
-                        if (k < 0)
-                            k = randrole(FALSE);
-                    } else {
-                        k = choice - 1;
-                    }
-                }
-                ROLE = k;
-            } /* needed role */
-        }     /* picking role */
-
-        if (nextpick == RS_RACE) {
-            nextpick = (ROLE < 0) ? RS_ROLE : RS_GENDER;
-            /* Select a race, if necessary;
-               force compatibility with role, try for compatibility
-               with pre-selected gender/alignment. */
-            if (RACE < 0 || !validrace(ROLE, RACE)) {
-                /* no race yet, or pre-selected race not valid */
-                if (pick4u == 'y' || pick4u == 'a' || RACE == ROLE_RANDOM) {
-                    k = pick_race(ROLE, GEND, ALGN, PICK_RANDOM);
-                    if (k < 0) {
-                        tty_putstr(BASE_WINDOW, 0, "Incompatible race!");
-                        k = randrace(ROLE);
-                    }
-                } else { /* pick4u == 'n' */
-                    /* Count the number of valid races */
-                    n = 0; /* number valid */
-                    k = 0; /* valid race */
-                    for (i = 0; races[i].noun; i++)
-                        if (ok_race(ROLE, i, GEND, ALGN)) {
-                            n++;
-                            k = i;
-                        }
-                    if (n == 0) {
-                        for (i = 0; races[i].noun; i++)
-                            if (validrace(ROLE, i)) {
-                                n++;
-                                k = i;
-                            }
-                    }
-                    /* Permit the user to pick, if there is more than one */
-                    if (n > 1) {
-                        tty_clear_nhwindow(BASE_WINDOW);
-                        role_selection_prolog(RS_RACE, BASE_WINDOW);
-                        win = create_nhwindow(NHW_MENU);
-                        start_menu(win, MENU_BEHAVE_STANDARD);
-                        any = cg.zeroany; /* zero out all bits */
-                        /* populate the menu with role choices */
-                        setup_racemenu(win, TRUE, ROLE, GEND, ALGN);
-                        /* add miscellaneous menu entries */
-                        role_menu_extra(ROLE_RANDOM, win, TRUE);
-                        any.a_int = 0; /* separator, not a choice */
-                        add_menu(win, &nul_glyphinfo, &any, 0, 0,
-                                 ATR_NONE, clr, "", MENU_ITEMFLAGS_NONE);
-                        role_menu_extra(RS_ROLE, win, FALSE);
-                        role_menu_extra(RS_GENDER, win, FALSE);
-                        role_menu_extra(RS_ALGNMNT, win, FALSE);
-                        role_menu_extra(RS_filter, win, FALSE);
-                        role_menu_extra(ROLE_NONE, win, FALSE); /* quit */
-                        Strcpy(pbuf, "Pick a race or species");
-                        end_menu(win, pbuf);
-                        n = select_menu(win, PICK_ONE, &selected);
-                        if (n > 0) {
-                            choice = selected[0].item.a_int;
-                            if (n > 1 && choice == ROLE_RANDOM)
-                                choice = selected[1].item.a_int;
-                        } else
-                            choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE;
-                        if (selected)
-                            free((genericptr_t) selected), selected = 0;
-                        destroy_nhwindow(win);
-
-                        if (choice == ROLE_NONE) {
-                            goto give_up; /* Selected quit */
-                        } else if (choice == RS_menu_arg(RS_ALGNMNT)) {
-                            ALGN = k = ROLE_NONE;
-                            nextpick = RS_ALGNMNT;
-                        } else if (choice == RS_menu_arg(RS_GENDER)) {
-                            GEND = k = ROLE_NONE;
-                            nextpick = RS_GENDER;
-                        } else if (choice == RS_menu_arg(RS_ROLE)) {
-                            ROLE = k = ROLE_NONE;
-                            nextpick = RS_ROLE;
-                        } else if (choice == RS_menu_arg(RS_filter)) {
-                            RACE = k = ROLE_NONE;
-                            if (reset_role_filtering())
-                                nextpick = RS_ROLE;
-                            else
-                                nextpick = RS_RACE;
-                        } else if (choice == ROLE_RANDOM) {
-                            k = pick_race(ROLE, GEND, ALGN, PICK_RANDOM);
-                            if (k < 0)
-                                k = randrace(ROLE);
-                        } else {
-                            k = choice - 1;
-                        }
-                    }
-                }
-                RACE = k;
-            } /* needed race */
-        }     /* picking race */
-
-        if (nextpick == RS_GENDER) {
-            nextpick = (ROLE < 0) ? RS_ROLE : (RACE < 0) ? RS_RACE
-                       : RS_ALGNMNT;
-            /* Select a gender, if necessary;
-               force compatibility with role/race, try for compatibility
-               with pre-selected alignment. */
-            if (GEND < 0 || !validgend(ROLE, RACE, GEND)) {
-                /* no gender yet, or pre-selected gender not valid */
-                if (pick4u == 'y' || pick4u == 'a' || GEND == ROLE_RANDOM) {
-                    k = pick_gend(ROLE, RACE, ALGN, PICK_RANDOM);
-                    if (k < 0) {
-                        tty_putstr(BASE_WINDOW, 0, "Incompatible gender!");
-                        k = randgend(ROLE, RACE);
-                    }
-                } else { /* pick4u == 'n' */
-                    /* Count the number of valid genders */
-                    n = 0; /* number valid */
-                    k = 0; /* valid gender */
-                    for (i = 0; i < ROLE_GENDERS; i++)
-                        if (ok_gend(ROLE, RACE, i, ALGN)) {
-                            n++;
-                            k = i;
-                        }
-                    if (n == 0) {
-                        for (i = 0; i < ROLE_GENDERS; i++)
-                            if (validgend(ROLE, RACE, i)) {
-                                n++;
-                                k = i;
-                            }
-                    }
-                    /* Permit the user to pick, if there is more than one */
-                    if (n > 1) {
-                        tty_clear_nhwindow(BASE_WINDOW);
-                        role_selection_prolog(RS_GENDER, BASE_WINDOW);
-                        win = create_nhwindow(NHW_MENU);
-                        start_menu(win, MENU_BEHAVE_STANDARD);
-                        any = cg.zeroany; /* zero out all bits */
-                        /* populate the menu with gender choices */
-                        setup_gendmenu(win, TRUE, ROLE, RACE, ALGN);
-                        /* add miscellaneous menu entries */
-                        role_menu_extra(ROLE_RANDOM, win, TRUE);
-                        any.a_int = 0; /* separator, not a choice */
-                        add_menu(win, &nul_glyphinfo, &any, 0, 0,
-                                 ATR_NONE, clr, "", MENU_ITEMFLAGS_NONE);
-                        role_menu_extra(RS_ROLE, win, FALSE);
-                        role_menu_extra(RS_RACE, win, FALSE);
-                        role_menu_extra(RS_ALGNMNT, win, FALSE);
-                        role_menu_extra(RS_filter, win, FALSE);
-                        role_menu_extra(ROLE_NONE, win, FALSE); /* quit */
-                        Strcpy(pbuf, "Pick a gender or sex");
-                        end_menu(win, pbuf);
-                        n = select_menu(win, PICK_ONE, &selected);
-                        if (n > 0) {
-                            choice = selected[0].item.a_int;
-                            if (n > 1 && choice == ROLE_RANDOM)
-                                choice = selected[1].item.a_int;
-                        } else
-                            choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE;
-                        if (selected)
-                            free((genericptr_t) selected), selected = 0;
-                        destroy_nhwindow(win);
-
-                        if (choice == ROLE_NONE) {
-                            goto give_up; /* Selected quit */
-                        } else if (choice == RS_menu_arg(RS_ALGNMNT)) {
-                            ALGN = k = ROLE_NONE;
-                            nextpick = RS_ALGNMNT;
-                        } else if (choice == RS_menu_arg(RS_RACE)) {
-                            RACE = k = ROLE_NONE;
-                            nextpick = RS_RACE;
-                        } else if (choice == RS_menu_arg(RS_ROLE)) {
-                            ROLE = k = ROLE_NONE;
-                            nextpick = RS_ROLE;
-                        } else if (choice == RS_menu_arg(RS_filter)) {
-                            GEND = k = ROLE_NONE;
-                            if (reset_role_filtering())
-                                nextpick = RS_ROLE;
-                            else
-                                nextpick = RS_GENDER;
-                        } else if (choice == ROLE_RANDOM) {
-                            k = pick_gend(ROLE, RACE, ALGN, PICK_RANDOM);
-                            if (k < 0)
-                                k = randgend(ROLE, RACE);
-                        } else {
-                            k = choice - 1;
-                        }
-                    }
-                }
-                GEND = k;
-            } /* needed gender */
-        }     /* picking gender */
-
-        if (nextpick == RS_ALGNMNT) {
-            nextpick = (ROLE < 0) ? RS_ROLE : (RACE < 0) ? RS_RACE : RS_GENDER;
-            /* Select an alignment, if necessary;
-               force compatibility with role/race/gender. */
-            if (ALGN < 0 || !validalign(ROLE, RACE, ALGN)) {
-                /* no alignment yet, or pre-selected alignment not valid */
-                if (pick4u == 'y' || pick4u == 'a' || ALGN == ROLE_RANDOM) {
-                    k = pick_align(ROLE, RACE, GEND, PICK_RANDOM);
-                    if (k < 0) {
-                        tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!");
-                        k = randalign(ROLE, RACE);
-                    }
-                } else { /* pick4u == 'n' */
-                    /* Count the number of valid alignments */
-                    n = 0; /* number valid */
-                    k = 0; /* valid alignment */
-                    for (i = 0; i < ROLE_ALIGNS; i++)
-                        if (ok_align(ROLE, RACE, GEND, i)) {
-                            n++;
-                            k = i;
-                        }
-                    if (n == 0) {
-                        for (i = 0; i < ROLE_ALIGNS; i++)
-                            if (validalign(ROLE, RACE, i)) {
-                                n++;
-                                k = i;
-                            }
-                    }
-                    /* Permit the user to pick, if there is more than one */
-                    if (n > 1) {
-                        tty_clear_nhwindow(BASE_WINDOW);
-                        role_selection_prolog(RS_ALGNMNT, BASE_WINDOW);
-                        win = create_nhwindow(NHW_MENU);
-                        start_menu(win, MENU_BEHAVE_STANDARD);
-                        any = cg.zeroany; /* zero out all bits */
-                        setup_algnmenu(win, TRUE, ROLE, RACE, GEND);
-                        role_menu_extra(ROLE_RANDOM, win, TRUE);
-                        any.a_int = 0; /* separator, not a choice */
-                        add_menu(win, &nul_glyphinfo, &any, 0, 0,
-                                 ATR_NONE, clr, "", MENU_ITEMFLAGS_NONE);
-                        role_menu_extra(RS_ROLE, win, FALSE);
-                        role_menu_extra(RS_RACE, win, FALSE);
-                        role_menu_extra(RS_GENDER, win, FALSE);
-                        role_menu_extra(RS_filter, win, FALSE);
-                        role_menu_extra(ROLE_NONE, win, FALSE); /* quit */
-                        Strcpy(pbuf, "Pick an alignment or creed");
-                        end_menu(win, pbuf);
-                        n = select_menu(win, PICK_ONE, &selected);
-                        if (n > 0) {
-                            choice = selected[0].item.a_int;
-                            if (n > 1 && choice == ROLE_RANDOM)
-                                choice = selected[1].item.a_int;
-                        } else
-                            choice = (n == 0) ? ROLE_RANDOM : ROLE_NONE;
-                        if (selected)
-                            free((genericptr_t) selected), selected = 0;
-                        destroy_nhwindow(win);
-
-                        if (choice == ROLE_NONE) {
-                            goto give_up; /* Selected quit */
-                        } else if (choice == RS_menu_arg(RS_GENDER)) {
-                            GEND = k = ROLE_NONE;
-                            nextpick = RS_GENDER;
-                        } else if (choice == RS_menu_arg(RS_RACE)) {
-                            RACE = k = ROLE_NONE;
-                            nextpick = RS_RACE;
-                        } else if (choice == RS_menu_arg(RS_ROLE)) {
-                            ROLE = k = ROLE_NONE;
-                            nextpick = RS_ROLE;
-                        } else if (choice == RS_menu_arg(RS_filter)) {
-                            ALGN = k = ROLE_NONE;
-                            if (reset_role_filtering())
-                                nextpick = RS_ROLE;
-                            else
-                                nextpick = RS_ALGNMNT;
-                        } else if (choice == ROLE_RANDOM) {
-                            k = pick_align(ROLE, RACE, GEND, PICK_RANDOM);
-                            if (k < 0)
-                                k = randalign(ROLE, RACE);
-                        } else {
-                            k = choice - 1;
-                        }
-                    }
-                }
-                ALGN = k;
-            } /* needed alignment */
-        }     /* picking alignment */
-
-    } while (ROLE < 0 || RACE < 0 || GEND < 0 || ALGN < 0);
-
-    /*
-     *  Role, race, &c have now been determined;
-     *  ask for confirmation and maybe go back to choose all over again.
-     *
-     *  Uses ynaq for familiarity, although 'a' is usually a
-     *  superset of 'y' but here is an alternate form of 'n'.
-     *  Menu layout:
-     *   title:  Is this ok? [ynaq]
-     *   blank:
-     *    text:  $name, $alignment $gender $race $role
-     *   blank:
-     *    menu:  y + yes; play
-     *           n - no; pick again
-     *   maybe:  a - no; rename hero
-     *           q - quit
-     *           (end)
-     */
-    getconfirmation = (picksomething && pick4u != 'a' && !flags.randomall);
-    while (getconfirmation) {
-        tty_clear_nhwindow(BASE_WINDOW);
-        role_selection_prolog(ROLE_NONE, BASE_WINDOW);
-        win = create_nhwindow(NHW_MENU);
-        start_menu(win, MENU_BEHAVE_STANDARD);
-        any = cg.zeroany; /* zero out all bits */
-        any.a_int = 0;
-        if (!roles[ROLE].name.f
-            && (roles[ROLE].allow & ROLE_GENDMASK)
-                   == (ROLE_MALE | ROLE_FEMALE))
-            Sprintf(plbuf, " %s", genders[GEND].adj);
-        else
-            *plbuf = '\0'; /* omit redundant gender */
-        Snprintf(pbuf, sizeof(pbuf), "%s, %s%s %s %s", gp.plname,
-                 aligns[ALGN].adj, plbuf, races[RACE].adj,
-                 (GEND == 1 && roles[ROLE].name.f) ? roles[ROLE].name.f
-                                                   : roles[ROLE].name.m);
-        add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, clr, pbuf,
-                 MENU_ITEMFLAGS_NONE);
-        /* blank separator */
-        any.a_int = 0;
-        add_menu(win, &nul_glyphinfo, &any, 0, 0,
-                 ATR_NONE, clr, "", MENU_ITEMFLAGS_NONE);
-        /* [ynaq] menu choices */
-        any.a_int = 1;
-        add_menu(win, &nul_glyphinfo, &any, 'y', 0,
-                 ATR_NONE, clr, "Yes; start game", MENU_ITEMFLAGS_SELECTED);
-        any.a_int = 2;
-        add_menu(win, &nul_glyphinfo, &any, 'n', 0,
-                 ATR_NONE, clr, "No; choose role again", MENU_ITEMFLAGS_NONE);
-        if (iflags.renameallowed) {
-            any.a_int = 3;
-            add_menu(win, &nul_glyphinfo, &any, 'a', 0, ATR_NONE,
-                     clr, "Not yet; choose another name", MENU_ITEMFLAGS_NONE);
-        }
-        any.a_int = -1;
-        add_menu(win, &nul_glyphinfo, &any, 'q', 0,
-                 ATR_NONE, clr, "Quit", MENU_ITEMFLAGS_NONE);
-        Sprintf(pbuf, "Is this ok? [yn%sq]", iflags.renameallowed ? "a" : "");
-        end_menu(win, pbuf);
-        n = select_menu(win, PICK_ONE, &selected);
-        /* [pick-one menus with a preselected entry behave oddly...] */
-        choice = (n > 0) ? selected[n - 1].item.a_int : (n == 0) ? 1 : -1;
-        if (selected)
-            free((genericptr_t) selected), selected = 0;
-        destroy_nhwindow(win);
-
-        switch (choice) {
-        default:          /* 'q' or ESC */
-            goto give_up; /* quit */
-            break;
-        case 3: { /* 'a' */
-            /*
-             * TODO: what, if anything, should be done if the name is
-             * changed to or from "wizard" after port-specific startup
-             * code has set flags.debug based on the original name?
-             */
-            int saveROLE, saveRACE, saveGEND, saveALGN;
-
-            iflags.renameinprogress = TRUE;
-            /* plnamesuffix() can change any or all of ROLE, RACE,
-               GEND, ALGN; we'll override that and honor only the name */
-            saveROLE = ROLE, saveRACE = RACE, saveGEND = GEND,
-                saveALGN = ALGN;
-            *gp.plname = '\0';
-            plnamesuffix(); /* calls askname() when gp.plname[] is empty */
-            ROLE = saveROLE, RACE = saveRACE, GEND = saveGEND,
-                ALGN = saveALGN;
-            break; /* getconfirmation is still True */
-        }
-        case 2:    /* 'n' */
-            /* start fresh, but bypass "shall I pick everything for you?"
-               step; any partial role selection via config file, command
-               line, or name suffix is discarded this time */
-            pick4u = 'n';
-            ROLE = RACE = GEND = ALGN = ROLE_NONE;
-            goto makepicks;
-            break;
-        case 1: /* 'y' or Space or Return/Enter */
-            /* success; drop out through end of function */
-            getconfirmation = FALSE;
-            break;
-        }
-    }
-
-    /* Success! */
-    tty_display_nhwindow(BASE_WINDOW, FALSE);
-    return;
+    if (genl_player_setup())
+        return;
 
- give_up:
-    /* Quit */
-    if (selected)
-        free((genericptr_t) selected); /* [obsolete] */
     bail((char *) 0);
     /*NOTREACHED*/
-    return;
-}
-
-static boolean
-reset_role_filtering(void)
-{
-    winid win;
-    anything any;
-    int i, n, clr = 0;
-    char filterprompt[QBUFSZ];
-    menu_item *selected = 0;
-
-    win = create_nhwindow(NHW_MENU);
-    start_menu(win, MENU_BEHAVE_STANDARD);
-    any = cg.zeroany;
-
-    /* no extra blank line preceding this entry; end_menu supplies one */
-    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, clr,
-             "Unacceptable roles", MENU_ITEMFLAGS_NONE);
-    setup_rolemenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE);
-
-    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE,
-             clr, "", MENU_ITEMFLAGS_NONE);
-    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE,
-             clr, "Unacceptable races", MENU_ITEMFLAGS_NONE);
-    setup_racemenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE);
-
-    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE,
-             clr, "", MENU_ITEMFLAGS_NONE);
-    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE,
-             clr, "Unacceptable genders", MENU_ITEMFLAGS_NONE);
-    setup_gendmenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE);
-
-    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE,
-             clr, "", MENU_ITEMFLAGS_NONE);
-    add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE,
-             clr, "Unacceptable alignments", MENU_ITEMFLAGS_NONE);
-    setup_algnmenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE);
-
-    Sprintf(filterprompt, "Pick all that apply%s",
-            gotrolefilter() ? " and/or unpick any that no longer apply" : "");
-    end_menu(win, filterprompt);
-    n = select_menu(win, PICK_ANY, &selected);
-
-    if (n >= 0) { /* n==0: clear current filters and don't set new ones */
-        clearrolefilter();
-        for (i = 0; i < n; i++)
-            setrolefilter(selected[i].item.a_string);
-
-        ROLE = RACE = GEND = ALGN = ROLE_NONE;
-    }
-    if (selected)
-        free((genericptr_t) selected), selected = 0;
-    destroy_nhwindow(win);
-    return (n > 0) ? TRUE : FALSE;
-}
-
-#undef ROLE
-#undef RACE
-#undef GEND
-#undef ALGN
-
-/* add entries a-Archeologist, b-Barbarian, &c to menu being built in 'win' */
-static void
-setup_rolemenu(
-    winid win,
-    boolean filtering, /* True => exclude filtered roles;
-                        * False => filter reset */
-    int race, int gend, int algn) /* all ROLE_NONE for !filtering case */
-{
-    anything any;
-    int i;
-    boolean role_ok;
-    char thisch, lastch = '\0', rolenamebuf[50];
-    int clr = 0;
-
-    any = cg.zeroany; /* zero out all bits */
-    for (i = 0; roles[i].name.m; i++) {
-        /* role can be constrained by any of race, gender, or alignment */
-        role_ok = (ok_role(i, race, gend, algn)
-                   && ok_race(i, race, gend, algn)
-                   && ok_gend(i, race, gend, algn)
-                   && ok_align(i, race, gend, algn));
-        if (filtering && !role_ok)
-            continue;
-        if (filtering)
-            any.a_int = i + 1;
-        else
-            any.a_string = roles[i].name.m;
-        thisch = lowc(*roles[i].name.m);
-        if (thisch == lastch)
-            thisch = highc(thisch);
-        Strcpy(rolenamebuf, roles[i].name.m);
-        if (roles[i].name.f) {
-            /* role has distinct name for female (C,P) */
-            if (gend == 1) {
-                /* female already chosen; replace male name */
-                Strcpy(rolenamebuf, roles[i].name.f);
-            } else if (gend < 0) {
-                /* not chosen yet; append slash+female name */
-                Strcat(rolenamebuf, "/");
-                Strcat(rolenamebuf, roles[i].name.f);
-            }
-        }
-        /* !filtering implies reset_role_filtering() where we want to
-           mark this role as preseleted if current filter excludes it */
-        add_menu(win, &nul_glyphinfo, &any, thisch, 0,
-                 ATR_NONE, clr, an(rolenamebuf),
-                 (!filtering && !role_ok)
-                    ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE);
-        lastch = thisch;
-    }
-}
-
-static void
-setup_racemenu(winid win, boolean filtering, int role, int gend, int algn)
-{
-    anything any;
-    boolean race_ok;
-    int i;
-    char this_ch;
-    int clr = 0;
-
-    any = cg.zeroany;
-    for (i = 0; races[i].noun; i++) {
-        /* no ok_gend(); race isn't constrained by gender */
-        race_ok = (ok_race(role, i, gend, algn)
-                   && ok_role(role, i, gend, algn)
-                   && ok_align(role, i, gend, algn));
-        if (filtering && !race_ok)
-            continue;
-        if (filtering)
-            any.a_int = i + 1;
-        else
-            any.a_string = races[i].noun;
-        this_ch = *races[i].noun;
-        /* filtering: picking race, so choose by first letter, with
-           capital letter as unseen accelerator;
-           !filtering: resetting filter rather than picking, choose by
-           capital letter since lowercase role letters will be present */
-        add_menu(win, &nul_glyphinfo, &any,
-                 filtering ? this_ch : highc(this_ch),
-                 filtering ? highc(this_ch) : 0,
-                 ATR_NONE, clr, races[i].noun,
-                 (!filtering && !race_ok)
-                    ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE);
-    }
-}
-
-static void
-setup_gendmenu(winid win, boolean filtering, int role, int race, int algn)
-{
-    anything any;
-    boolean gend_ok;
-    int i;
-    char this_ch;
-    int clr = 0;
-
-    any = cg.zeroany;
-    for (i = 0; i < ROLE_GENDERS; i++) {
-        /* no ok_align(); gender isn't constrained by alignment */
-        gend_ok = (ok_gend(role, race, i, algn)
-                   && ok_role(role, race, i, algn)
-                   && ok_race(role, race, i, algn));
-        if (filtering && !gend_ok)
-            continue;
-        if (filtering)
-            any.a_int = i + 1;
-        else
-            any.a_string = genders[i].adj;
-        this_ch = *genders[i].adj;
-        /* (see setup_racemenu for explanation of selector letters
-           and setup_rolemenu for preselection) */
-        add_menu(win, &nul_glyphinfo, &any,
-                 filtering ? this_ch : highc(this_ch),
-                 filtering ? highc(this_ch) : 0,
-                 ATR_NONE, clr, genders[i].adj,
-                 (!filtering && !gend_ok)
-                    ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE);
-    }
-}
-
-static void
-setup_algnmenu(winid win, boolean filtering, int role, int race, int gend)
-{
-    anything any;
-    boolean algn_ok;
-    int i;
-    char this_ch;
-    int clr = 0;
-
-    any = cg.zeroany;
-    for (i = 0; i < ROLE_ALIGNS; i++) {
-        /* no ok_gend(); alignment isn't constrained by gender */
-        algn_ok = (ok_align(role, race, gend, i)
-                   && ok_role(role, race, gend, i)
-                   && ok_race(role, race, gend, i));
-        if (filtering && !algn_ok)
-            continue;
-        if (filtering)
-            any.a_int = i + 1;
-        else
-            any.a_string = aligns[i].adj;
-        this_ch = *aligns[i].adj;
-        /* (see setup_racemenu for explanation of selector letters
-           and setup_rolemenu for preselection) */
-        add_menu(win, &nul_glyphinfo, &any,
-                 filtering ? this_ch : highc(this_ch),
-                 filtering ? highc(this_ch) : 0,
-                 ATR_NONE, clr, aligns[i].adj,
-                 (!filtering && !algn_ok)
-                    ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE);
-    }
 }
 
 /*
@@ -2783,6 +2022,7 @@ tty_curs(winid window,
     ttyDisplay->cury = y;
 }
 
+#ifndef STATUS_HILITES
 static void
 tty_putsym(winid window, int x, int y, char ch)
 {
@@ -2815,6 +2055,7 @@ tty_putsym(winid window, int x, int y, char ch)
         break;
     }
 }
+#endif
 
 static const char *
 compress_str(const char *str)