Пример #1
0
/* case insensitive substring search */
char *strstri(const char *str, const char *sub)
{
    const char *s1, *s2;
    int i, k;
# define TABSIZ 0x20	/* 0x40 would be case-sensitive */
    char tstr[TABSIZ], tsub[TABSIZ];	/* nibble count tables */

    /* special case: empty substring */
    if (!*sub)	return (char *) str;

    /* do some useful work while determining relative lengths */
    for (i = 0; i < TABSIZ; i++)  tstr[i] = tsub[i] = 0;	/* init */
    for (k = 0, s1 = str; *s1; k++)  tstr[*s1++ & (TABSIZ-1)]++;
    for (	s2 = sub; *s2; --k)  tsub[*s2++ & (TABSIZ-1)]++;

    /* evaluate the info we've collected */
    if (k < 0)	return NULL;  /* sub longer than str, so can't match */
    for (i = 0; i < TABSIZ; i++)	/* does sub have more 'x's than str? */
	if (tsub[i] > tstr[i])	return NULL;  /* match not possible */

    /* now actually compare the substring repeatedly to parts of the string */
    for (i = 0; i <= k; i++) {
	s1 = &str[i];
	s2 = sub;
	while (lowc(*s1++) == lowc(*s2++))
	    if (!*s2)  return (char *) &str[i];		/* full match */
    }
    return NULL;	/* not found */
}
Пример #2
0
/*
 * This routine changes the address of obj. Be careful not to call it
 * when there might be pointers around in unknown places. For now: only
 * when obj is in the inventory.
 */
static void do_oname(struct obj *obj)
{
	char buf[BUFSZ], qbuf[QBUFSZ];
	const char *aname;
	short objtyp;

	sprintf(qbuf, "What do you want to name %s %s?",
		is_plural(obj) ? "these" : "this", xname(obj));
	getlin(qbuf, buf);
	if (!*buf || *buf == '\033')	return;
	/* strip leading and trailing spaces; unnames item if all spaces */
	mungspaces(buf);

	/* relax restrictions over proper capitalization for artifacts */
	if ((aname = artifact_name(buf, &objtyp)) != 0 && objtyp == obj->otyp)
		strcpy(buf, aname);

	if (obj->oartifact) {
		pline("The artifact seems to resist the attempt.");
		return;
	} else if (restrict_name(obj, buf) || exist_artifact(obj->otyp, buf)) {
		int n = rn2((int)strlen(buf));
		char c1, c2;

		c1 = lowc(buf[n]);
		do c2 = 'a' + rn2('z'-'a'); while (c1 == c2);
		buf[n] = (buf[n] == c1) ? c2 : highc(c2);  /* keep same case */
		pline("While engraving your %s slips.", body_part(HAND));
		win_pause_output(P_MESSAGE);
		pline("You engrave: \"%s\".",buf);
	}
	oname(obj, buf);
}
Пример #3
0
int
strncmpi(register const char *s1, register const char *s2, register int n)	/* case insensitive counted string comparison */
                             
                /*(should probably be size_t, which is usually unsigned)*/
{
    /*{ aka strncasecmp }*/
    register char t1, t2;

    while (n--) {
        if (!*s2) return (*s1 != 0);	/* s1 >= s2 */
        else if (!*s1) return -1;	/* s1  < s2 */
        t1 = lowc(*s1++);
        t2 = lowc(*s2++);
        if (t1 != t2) return (t1 > t2) ? 1 : -1;
    }
    return 0;				/* s1 == s2 */
}
Пример #4
0
/* compare two strings for equality, ignoring the presence of specified
   characters (typically whitespace) and possibly ignoring case */
boolean
fuzzymatch(const char *s1, const char *s2, const char *ignore_chars, boolean caseblind)
{
    register char c1, c2;

    do {
        while ((c1 = *s1++) != '\0' && index(ignore_chars, c1) != 0) continue;
        while ((c2 = *s2++) != '\0' && index(ignore_chars, c2) != 0) continue;
        if (!c1 || !c2) break;	/* stop when end of either string is reached */

        if (caseblind) {
            c1 = lowc(c1);
            c2 = lowc(c2);
        }
    } while (c1 == c2);

    /* match occurs only when the end of both strings has been reached */
    return (boolean)(!c1 && !c2);
}
Пример #5
0
/*
 * This routine changes the address of obj. Be careful not to call it
 * when there might be pointers around in unknown places. For now: only
 * when obj is in the inventory.
 */
int
do_oname(const struct nh_cmd_arg *arg)
{
    const char *qbuf, *buf;
    const char *aname;
    short objtyp;
    struct obj *obj;

    obj = getargobj(arg, nameable, "name");
    if (!obj)
        return 0;

    qbuf = msgprintf("What do you want to name %s %s?",
                     is_plural(obj) ? "these" : "this",
                     safe_qbuf("", sizeof("What do you want to name these ?"),
                               xname(obj), simple_typename(obj->otyp),
                               is_plural(obj) ? "things" : "thing"));
    buf = getarglin(arg, qbuf);
    if (!*buf || *buf == '\033')
        return 0;
    /* strip leading and trailing spaces; unnames item if all spaces */
    buf = msgmungspaces(buf);

    /* relax restrictions over proper capitalization for artifacts */
    if ((aname = artifact_name(buf, &objtyp)) != 0 && objtyp == obj->otyp)
        buf = aname;

    char slipbuf[strlen(buf) + 1];
    if (obj->oartifact) {
        pline("The artifact seems to resist the attempt.");
        return 0;
    } else if (restrict_name(obj, buf) || exist_artifact(obj->otyp, buf)) {
        int n = rn2((int)strlen(buf));
        char c1, c2;
        strcpy(slipbuf, buf);

        c1 = lowc(buf[n]);
        do
            c2 = 'a' + rn2('z' - 'a' + 1);
        while (c1 == c2);

        slipbuf[n] = (slipbuf[n] == c1) ? c2 : highc(c2);   /* keep same case */
        pline("While engraving your %s slips.", body_part(HAND));
        win_pause_output(P_MESSAGE);
        pline("You engrave: \"%s\".", slipbuf);
        buf = slipbuf;
    }
    oname(obj, buf);
    return 0;
}
Пример #6
0
int		main(int ac, char **av)
{
	int alert;
	int i;

	alert = 0;
	i = 0;
	while (++i < ac)
	{
		lowc(av[i]);
		if (cmp("president", av[i]) == 0)
			alert = 1;
		if (cmp("attack", av[i]) == 0)
			alert = 1;
		if (cmp("powers", av[i]) == 0)
			alert = 1;
	}
	if (alert == 1)
		write(1, "Alert!!!\n", 9);
	return (0);
}
Пример #7
0
int curses_ext_cmd()
{
    int count, letter, prompt_width, startx, starty, winx, winy;
    int messageh, messagew;
    int ret = -1;
    char cur_choice[BUFSZ];
    int matches = 0;
    WINDOW *extwin = NULL;

    if (iflags.extmenu)
    {
        return extcmd_via_menu();
    }
    
    if (iflags.wc_popup_dialog) /* Prompt in popup window */
    {
        startx = 1;
        starty = 1;
        extwin = curses_create_window(25, 1, UP);
    }
    else
    {
        curses_get_window_xy(MESSAGE_WIN, &winx, &winy);
        curses_get_window_size(MESSAGE_WIN, &messageh, &messagew);
        
        if (curses_window_has_border(MESSAGE_WIN))
        {
            winx++;
            winy++;
        }
        
        winy += messageh - 1;
        extwin = newwin(1, 25, winy, winx);
        startx = 0;
        starty = 0;
        pline("#");
    }

    cur_choice[0] = '\0';

    while (1)
    {
        wmove(extwin, starty, startx);
        waddstr(extwin, "# ");
        wmove(extwin, starty, startx + 2);
        curses_toggle_color_attr(extwin, NONE, A_UNDERLINE, ON);
        waddstr(extwin, cur_choice);
        curses_toggle_color_attr(extwin, NONE, A_UNDERLINE, OFF);
        wmove(extwin, starty, strlen(cur_choice) + startx + 2);
        wprintw(extwin, "          ", cur_choice);

        if (matches == 1)
        {
            wmove(extwin, starty, strlen(cur_choice) + startx + 2);
            wprintw(extwin, "%s          ", extcmdlist[ret].ef_txt
             + strlen(cur_choice));
        }

        wrefresh(extwin);
        letter = getch();
	    prompt_width = strlen(cur_choice);
        matches = 0;

        if (letter == '\033')
        {
            ret = -1;
            break;
        }

        if ((letter == '\r') || (letter == '\n'))
        {
            break;
        }

        if ((letter == '\b') || (letter == KEY_BACKSPACE))
        {
            if (prompt_width == 0)
            {
                ret = -1;
                break;
            }
            else
            {
                cur_choice[prompt_width - 1] = '\0';
                letter = '*';
                prompt_width--;
            }
        }
        
        for (count = 0; extcmdlist[count].ef_txt; count++)
        {
            if (strlen(extcmdlist[count].ef_txt) > prompt_width)
            {
                if (strncasecmp(cur_choice, extcmdlist[count].ef_txt,
                 prompt_width) == 0)
                {
                    if ((extcmdlist[count].ef_txt[prompt_width] ==
			 lowc(letter)) || letter == '*')
                    {
                        if ((matches == 0) && (letter != '*'))
                        {
                            ret = count;
                            cur_choice[prompt_width] = letter;
                            cur_choice[prompt_width + 1] = '\0';
                        }

                        matches++;
                    }
                }
            }
	    }
	}    
    
    curses_destroy_win(extwin);
    return ret;
}
Пример #8
0
/*
 * Look in the "data" file for more info.  Called if the user typed in the
 * whole name (user_typed_name == TRUE), or we've found a possible match
 * with a character/glyph.
 */
static void
checkfile(const char *inp, struct permonst *pm, boolean user_typed_name,
          boolean without_asking)
{
    dlb *fp;
    char buf[BUFSZ], newstr[BUFSZ];
    char *ep, *dbase_str;
    long txt_offset = 0;
    int chk_skip;
    boolean found_in_file = FALSE, skipping_entry = FALSE;

    fp = dlb_fopen(DATAFILE, "r");
    if (!fp) {
        pline("Cannot open data file!");
        return;
    }

    /* To prevent the need for entries in data.base like *ngel to account for
       Angel and angel, make the lookup string the same for both
       user_typed_name and picked name. */
    if (pm != NULL && !user_typed_name)
        dbase_str = strcpy(newstr, pm->mname);
    else
        dbase_str = strcpy(newstr, inp);

    for (ep = dbase_str; *ep; ep++)
        *ep = lowc(*ep);

    if (!strncmp(dbase_str, "interior of ", 12))
        dbase_str += 12;
    if (!strncmp(dbase_str, "a ", 2))
        dbase_str += 2;
    else if (!strncmp(dbase_str, "an ", 3))
        dbase_str += 3;
    else if (!strncmp(dbase_str, "the ", 4))
        dbase_str += 4;
    if (!strncmp(dbase_str, "tame ", 5))
        dbase_str += 5;
    else if (!strncmp(dbase_str, "peaceful ", 9))
        dbase_str += 9;
    if (!strncmp(dbase_str, "invisible ", 10))
        dbase_str += 10;
    if (!strncmp(dbase_str, "statue of ", 10))
        dbase_str[6] = '\0';
    else if (!strncmp(dbase_str, "figurine of ", 12))
        dbase_str[8] = '\0';

    /* Make sure the name is non-empty. */
    if (*dbase_str) {
        /* adjust the input to remove " [seen" and "named " and convert to
           lower case */
        const char *alt = 0;  /* alternate description */

        if ((ep = strstri_mutable(dbase_str, " [seen")) != 0)
            *ep = '\0';

        if ((ep = strstri_mutable(dbase_str, " named ")) != 0)
            alt = ep + 7;
        else
            ep = strstri_mutable(dbase_str, " called ");
        if (!ep)
            ep = strstri_mutable(dbase_str, ", ");
        if (ep && ep > dbase_str)
            *ep = '\0';

        /* 
         * If the object is named, then the name is the alternate description;
         * otherwise, the result of makesingular() applied to the name is. This
         * isn't strictly optimal, but named objects of interest to the user
         * will usually be found under their name, rather than under their
         * object type, so looking for a singular form is pointless.
         */

        if (!alt)
            alt = makesingular(dbase_str);
        else if (user_typed_name)
            alt = msglowercase(alt);

        /* skip first record; read second */
        txt_offset = 0L;
        if (!dlb_fgets(buf, BUFSZ, fp) || !dlb_fgets(buf, BUFSZ, fp)) {
            impossible("can't read 'data' file");
            dlb_fclose(fp);
            return;
        } else if (sscanf(buf, "%8lx\n", &txt_offset) < 1 || txt_offset <= 0)
            goto bad_data_file;

        /* look for the appropriate entry */
        while (dlb_fgets(buf, BUFSZ, fp)) {
            if (*buf == '.')
                break;  /* we passed last entry without success */

            if (digit(*buf)) {
                /* a number indicates the end of current entry */
                skipping_entry = FALSE;
            } else if (!skipping_entry) {
                if (!(ep = strchr(buf, '\n')))
                    goto bad_data_file;
                *ep = 0;
                /* if we match a key that begins with "~", skip this entry */
                chk_skip = (*buf == '~') ? 1 : 0;
                if (pmatch(&buf[chk_skip], dbase_str) ||
                    (alt && pmatch(&buf[chk_skip], alt))) {
                    if (chk_skip) {
                        skipping_entry = TRUE;
                        continue;
                    } else {
                        found_in_file = TRUE;
                        break;
                    }
                }
            }
        }
    }

    if (found_in_file) {
        long entry_offset;
        int entry_count;
        int i;

        /* skip over other possible matches for the info */
        do {
            if (!dlb_fgets(buf, BUFSZ, fp))
                goto bad_data_file;
        } while (!digit(*buf));

        if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2) {
        bad_data_file:impossible("'data' file in wrong format");
            dlb_fclose(fp);
            return;
        }

        if (user_typed_name || without_asking || yn("More info?") == 'y') {
            struct nh_menulist menu;

            if (dlb_fseek(fp, txt_offset + entry_offset, SEEK_SET) < 0) {
                pline("? Seek error on 'data' file!");
                dlb_fclose(fp);
                return;
            }

            init_menulist(&menu);

            for (i = 0; i < entry_count; i++) {
                if (!dlb_fgets(buf, BUFSZ, fp))
                    goto bad_data_file;
                if ((ep = strchr(buf, '\n')) != 0)
                    *ep = 0;
                if (strchr(buf + 1, '\t') != 0)
                    tabexpand(buf + 1);
                add_menutext(&menu, buf + 1);
            }

            display_menu(&menu, NULL, FALSE, PLHINT_ANYWHERE,
                         NULL);
        }
    } else if (user_typed_name)
        pline("I don't have any information on those things.");

    dlb_fclose(fp);
}
Пример #9
0
/* may return ROLE_RANDOM, or ROLE_NONE when the list is empty (which
 * can only mean that the role/race/gender/alignment combination that
 * the user supplied on the command line was not possible), or
 * ROLE_QUIT if the user pressed escape.
 */
static int do_player_selection_menu(const char *type,
    int (* func)(int what, char *buf))
{
  int i, kind;
  int valid = 0, total = 0, last = -1;

  winid window;
  anything any;
  int attr, choice;

  menu_item *selected = NULL;

  int used_accs[52] = { 0, };
  char accel;
  
  char name[BUFSZ];
  char prompt[BUFSZ];
  char randstr[BUFSZ];

  /* count valid entries */
  for (i=0; ; i++)
  {
    kind = (* func)(i, name);

    if (kind < 0)
      break;

    total++;

    if (kind > 0)
    {
      valid++;
      last = i;
    }
  }
  
  if (valid == 0)
    return ROLE_NONE;

  assert(last >= 0);

  /* -AJA- this is disabled -- it's better IMHO to show the user the
   *       single choice, letting them press ESC and pick some other
   *       role/race/gender if they're not satisfied.
   */
#if 0
  if (valid == 1)
    return last;
#endif
 
  /* create menu */

  sprintf(prompt,  "Pick your %s", type);
  sprintf(randstr, "Random %s", type);
 
  window = Sdlgl_create_nhwindow(NHW_MENU);
  assert(window != WIN_ERR);

  Sdlgl_start_menu(window);

  for (i=0; i < total; i++)
  {
    kind = (* func)(i, name);
    any.a_void = 0;
    attr = ATR_NONE;

    /* choose accelerator key */
    accel = lowc(name[0]);

    if (accel < 'a' || accel > 'z')
      accel = 0;
    else
    {
      if (! used_accs[accel - 'a'])
        used_accs[accel - 'a'] = 1;
      else
      {
        accel = highc(accel);

        if (! used_accs[accel - 'A' + 26])
          used_accs[accel - 'A' + 26] = 1;
        else
          accel = 0;
      }
    }

    if (kind > 0)
    {
      /* must add one, zero is not allowed */
      any.a_int = 1 + i;
    }
    else
    {
      /* shift name right (to align), and make dim */
      memmove(name + 5, name, strlen(name) + 1);
      memcpy(name, "     ", 5);
      attr = ATR_DIM;
    }

    Sdlgl_add_menu(window, NO_GLYPH, &any, accel,
        0 /* no groupacc */, attr, name, MENU_UNSELECTED);
  }

  /* add `Random' line (unless there's only one choice) */
  if (valid > 1)
  {
    any.a_int = 1 + total;

    Sdlgl_add_menu(window, NO_GLYPH, &any, '*',
          0 /* no groupacc */, ATR_NONE, randstr, MENU_UNSELECTED);
  }

  Sdlgl_end_menu(window, prompt);

  /* get result back from menu */

  i = Sdlgl_select_menu(window, PICK_ONE, &selected);
  Sdlgl_destroy_nhwindow(window);

  if (i <= 0)
    return ROLE_QUIT;

  assert(i == 1 && selected);

  choice = selected[0].item.a_int - 1;
  free(selected);

  assert(0 <= choice && choice <= total);

  if (choice == total)
    return ROLE_RANDOM;

  return choice;
}
Пример #10
0
void
rhack(const char *cmd)
{
	const struct func_tab *tlist = cmdlist;
	boolean         firsttime = FALSE;
	int res;

	if (!cmd) {
		firsttime = TRUE;
		flags.nopick = 0;
		cmd = parse();
	}
	if (!*cmd || (*cmd & 0377) == 0377 ||
	    (flags.no_rest_on_space && *cmd == ' ')) {
		sound_bell();
		flags.move = 0;
		return;		/* probably we just had an interrupt */
	}
	if (movecmd(*cmd)) {
walk:
		if (multi)
			flags.mv = 1;
		domove();
		return;
	}
	if (movecmd(lowc(*cmd))) {
		flags.run = 1;
rush:
		if (firsttime) {
			if (!multi)
				multi = COLNO;
			u.last_str_turn = 0;
		}
		flags.mv = 1;
#ifdef QUEST
		if (flags.run >= 4)
			finddir();
		if (firsttime) {
			u.ux0 = u.ux + u.dx;
			u.uy0 = u.uy + u.dy;
		}
#endif	/* QUEST */
		domove();
		return;
	}
	if ((*cmd == 'f' && movecmd(cmd[1])) || movecmd(unctrl(*cmd))) {
		flags.run = 2;
		goto rush;
	}
	if (*cmd == 'F' && movecmd(lowc(cmd[1]))) {
		flags.run = 3;
		goto rush;
	}
	if (*cmd == 'm' && movecmd(cmd[1])) {
		flags.run = 0;
		flags.nopick = 1;
		goto walk;
	}
	if (*cmd == 'M' && movecmd(lowc(cmd[1]))) {
		flags.run = 1;
		flags.nopick = 1;
		goto rush;
	}
#ifdef QUEST
	if (*cmd == cmd[1] && (*cmd == 'f' || *cmd == 'F')) {
		flags.run = 4;
		if (*cmd == 'F')
			flags.run += 2;
		if (cmd[2] == '-')
			flags.run += 1;
		goto rush;
	}
#endif	/* QUEST */
	while (tlist->f_char) {
		if (*cmd == tlist->f_char) {
			res = (*(tlist->f_funct)) ();
			if (!res) {
				flags.move = 0;
				multi = 0;
			}
			return;
		}
		tlist++;
	}
	{
		char            expcmd[10];
		char  *cp = expcmd;
		while (*cmd && cp - expcmd < (int)sizeof(expcmd) - 2) {
			if (*cmd >= 040 && *cmd < 0177)
				*cp++ = *cmd++;
			else {
				*cp++ = '^';
				*cp++ = *cmd++ ^ 0100;
			}
		}
		*cp++ = 0;
		pline("Unknown command '%s'.", expcmd);
	}
	multi = flags.move = 0;
}
Пример #11
0
void nds_player_selection()
{
  int i, k, n;
  char pick4u = 'n', thisch, lastch = 0;
  char pbuf[PROMPT_LAYER_WIDTH], plbuf[PROMPT_LAYER_WIDTH];
  winid win;
  anything any;
  menu_item *selected = 0;

  /* prevent an unnecessary prompt */
  rigid_role_checks();

  /* Should we randomly pick for the player? */
  if (!flags.randomall &&
      (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE ||
       flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) {

    char *prompt = build_plselection_prompt(pbuf, PROMPT_LAYER_WIDTH, flags.initrole,
                                            flags.initrace, flags.initgend, flags.initalign);
    int res = _nds_display_yes_no_prompt(prompt);

    if (res < 0) {
give_up:
      return;
    }

    if (res) {
      pick4u = 'y';
    }
  }

  root_plselection_prompt(plbuf, PROMPT_LAYER_WIDTH - 1,
                          flags.initrole, flags.initrace, flags.initgend, flags.initalign);

  /* Select a role, if necessary */
  /* we'll try to be compatible with pre-selected race/gender/alignment,
   * but may not succeed */

  if (flags.initrole < 0) {
    char rolenamebuf[PROMPT_LAYER_WIDTH];

    /* Process the choice */
    if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) {
      /* Pick a random role */
      flags.initrole = pick_role(flags.initrace, flags.initgend,
                                 flags.initalign, PICK_RANDOM);
      if (flags.initrole < 0) {
        iprintf("Incompatible role!");

        flags.initrole = randrole();
      }
    } else {
      /* Prompt for a role */

      win = create_nhwindow(NHW_MENU);
      start_menu(win);

      any.a_void = 0;         /* zero out all bits */

      for (i = 0; roles[i].name.m; i++) {
        if (ok_role(i, flags.initrace, flags.initgend,
                    flags.initalign)) {

          any.a_int = i+1;	/* must be non-zero */
          thisch = lowc(roles[i].name.m[0]);

          if (thisch == lastch) thisch = highc(thisch);

          if (flags.initgend != ROLE_NONE && flags.initgend != ROLE_RANDOM) {
            if (flags.initgend == 1  && roles[i].name.f)
              Strcpy(rolenamebuf, roles[i].name.f);
            else
              Strcpy(rolenamebuf, roles[i].name.m);
          } else {
            if (roles[i].name.f) {
              Strcpy(rolenamebuf, roles[i].name.m);
              Strcat(rolenamebuf, "/");
              Strcat(rolenamebuf, roles[i].name.f);
            } else 
              Strcpy(rolenamebuf, roles[i].name.m);
          }	

          add_menu(win, NO_GLYPH, &any, thisch,
                   0, ATR_NONE, an(rolenamebuf), MENU_UNSELECTED);

          lastch = thisch;
        }
      }

      any.a_int = pick_role(flags.initrace, flags.initgend,
                            flags.initalign, PICK_RANDOM)+1;

      if (any.a_int == 0)	/* must be non-zero */
        any.a_int = randrole()+1;

      add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
               "Random", MENU_UNSELECTED);

      any.a_int = i+1;	/* must be non-zero */

      add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
               "Quit", MENU_UNSELECTED);

      Sprintf(pbuf, "Pick a role for your %s", plbuf);

      end_menu(win, pbuf);

      n = select_menu(win, PICK_ONE, &selected);

      destroy_nhwindow(win);

      /* Process the choice */
      if (n != 1 || selected[0].item.a_int == any.a_int)
        goto give_up;		/* Selected quit */

      flags.initrole = selected[0].item.a_int - 1;
      free((genericptr_t) selected),	selected = 0;
    }

    (void)  root_plselection_prompt(plbuf, PROMPT_LAYER_WIDTH - 1,
                                    flags.initrole, flags.initrace, flags.initgend, flags.initalign);
  }

  /* Select a race, if necessary */
  /* force compatibility with role, try for compatibility with
   * pre-selected gender/alignment */

  if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
    /* pre-selected race not valid */

    if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) {
      flags.initrace = pick_race(flags.initrole, flags.initgend,
                                 flags.initalign, PICK_RANDOM);
      if (flags.initrace < 0) {
        iprintf("Incompatible race!");
        flags.initrace = randrace(flags.initrole);
      }
    } 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(flags.initrole, i, flags.initgend,
                    flags.initalign)) {
          n++;
          k = i;
        }
      }

      if (n == 0) {
        for (i = 0; races[i].noun; i++) {
          if (validrace(flags.initrole, i)) {
            n++;
            k = i;
          }
        }
      }

      /* Permit the user to pick, if there is more than one */
      if (n > 1) {
        win = create_nhwindow(NHW_MENU);

        start_menu(win);
        any.a_void = 0;         /* zero out all bits */

        for (i = 0; races[i].noun; i++)
          if (ok_race(flags.initrole, i, flags.initgend,
                      flags.initalign)) {
            any.a_int = i+1;	/* must be non-zero */
            add_menu(win, NO_GLYPH, &any, races[i].noun[0],
                     0, ATR_NONE, races[i].noun, MENU_UNSELECTED);
          }

        any.a_int = pick_race(flags.initrole, flags.initgend,
                              flags.initalign, PICK_RANDOM)+1;

        if (any.a_int == 0)	/* must be non-zero */
          any.a_int = randrace(flags.initrole)+1;

        add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
                 "Random", MENU_UNSELECTED);

        any.a_int = i+1;	/* must be non-zero */

        add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
                 "Quit", MENU_UNSELECTED);

        Sprintf(pbuf, "Pick the race of your %s", plbuf);
        end_menu(win, pbuf);

        n = select_menu(win, PICK_ONE, &selected);
        destroy_nhwindow(win);

        if (n != 1 || selected[0].item.a_int == any.a_int)
          goto give_up;		/* Selected quit */

        k = selected[0].item.a_int - 1;
        free((genericptr_t) selected),	selected = 0;
      }

      flags.initrace = k;
    }

    (void)  root_plselection_prompt(plbuf, PROMPT_LAYER_WIDTH - 1,
                                    flags.initrole, flags.initrace, flags.initgend, flags.initalign);
  }

  /* Select a gender, if necessary */
  /* force compatibility with role/race, try for compatibility with
   * pre-selected alignment */
  if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace,
                                       flags.initgend)) {
    /* pre-selected gender not valid */
    if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) {
      flags.initgend = pick_gend(flags.initrole, flags.initrace,
                                 flags.initalign, PICK_RANDOM);
      if (flags.initgend < 0) {
        iprintf("Incompatible gender!");
        flags.initgend = randgend(flags.initrole, flags.initrace);
      }
    } 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(flags.initrole, flags.initrace, i,
                    flags.initalign)) {
          n++;
          k = i;
        }
      }

      if (n == 0) {
        for (i = 0; i < ROLE_GENDERS; i++) {
          if (validgend(flags.initrole, flags.initrace, i)) {
            n++;
            k = i;
          }
        }
      }

      /* Permit the user to pick, if there is more than one */
      if (n > 1) {
        win = create_nhwindow(NHW_MENU);
        start_menu(win);

        any.a_void = 0;         /* zero out all bits */

        for (i = 0; i < ROLE_GENDERS; i++)
          if (ok_gend(flags.initrole, flags.initrace, i,
                      flags.initalign)) {
            any.a_int = i+1;
            add_menu(win, NO_GLYPH, &any, genders[i].adj[0],
                     0, ATR_NONE, genders[i].adj, MENU_UNSELECTED);
          }

        any.a_int = pick_gend(flags.initrole, flags.initrace,
                              flags.initalign, PICK_RANDOM)+1;

        if (any.a_int == 0)	/* must be non-zero */
          any.a_int = randgend(flags.initrole, flags.initrace)+1;

        add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
                 "Random", MENU_UNSELECTED);

        any.a_int = i+1;	/* must be non-zero */

        add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
                 "Quit", MENU_UNSELECTED);

        Sprintf(pbuf, "Pick the gender of your %s", plbuf);
        end_menu(win, pbuf);

        n = select_menu(win, PICK_ONE, &selected);
        destroy_nhwindow(win);

        if (n != 1 || selected[0].item.a_int == any.a_int)
          goto give_up;		/* Selected quit */

        k = selected[0].item.a_int - 1;
        free((genericptr_t) selected),	selected = 0;
      }

      flags.initgend = k;
    }

    (void)  root_plselection_prompt(plbuf, PROMPT_LAYER_WIDTH - 1,
                                    flags.initrole, flags.initrace, flags.initgend, flags.initalign);
  }

  /* Select an alignment, if necessary */
  /* force compatibility with role/race/gender */
  if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace,
                                         flags.initalign)) {
    /* pre-selected alignment not valid */
    if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) {
      flags.initalign = pick_align(flags.initrole, flags.initrace,
                                   flags.initgend, PICK_RANDOM);
      if (flags.initalign < 0) {
        iprintf("Incompatible alignment!");
        flags.initalign = randalign(flags.initrole, flags.initrace);
      }
    } 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(flags.initrole, flags.initrace, flags.initgend,
                     i)) {
          n++;
          k = i;
        }
      }

      if (n == 0) {
        for (i = 0; i < ROLE_ALIGNS; i++) {
          if (validalign(flags.initrole, flags.initrace, i)) {
            n++;
            k = i;
          }
        }
      }

      /* Permit the user to pick, if there is more than one */
      if (n > 1) {
        win = create_nhwindow(NHW_MENU);
        start_menu(win);

        any.a_void = 0;         /* zero out all bits */

        for (i = 0; i < ROLE_ALIGNS; i++)
          if (ok_align(flags.initrole, flags.initrace,
                       flags.initgend, i)) {
            any.a_int = i+1;
            add_menu(win, NO_GLYPH, &any, aligns[i].adj[0],
                     0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
          }

        any.a_int = pick_align(flags.initrole, flags.initrace,
                               flags.initgend, PICK_RANDOM)+1;

        if (any.a_int == 0)	/* must be non-zero */
          any.a_int = randalign(flags.initrole, flags.initrace)+1;

        add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
                 "Random", MENU_UNSELECTED);

        any.a_int = i+1;	/* must be non-zero */

        add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
                 "Quit", MENU_UNSELECTED);

        Sprintf(pbuf, "Pick the alignment of your %s", plbuf);
        end_menu(win, pbuf);

        n = select_menu(win, PICK_ONE, &selected);
        destroy_nhwindow(win);

        if (n != 1 || selected[0].item.a_int == any.a_int)
          goto give_up;		/* Selected quit */

        k = selected[0].item.a_int - 1;
        free((genericptr_t) selected),	selected = 0;
      }

      flags.initalign = k;
    }
  }
}
/* prompt the player to choose a role */
static int vultures_player_selection_role (void)
{
	winid window;
	anything identifier;
	menu_item *menu_list;
	int chosen, items, item = 0;
	char thisch, lastch;

	menu_list = 0;
	window = vultures_create_nhwindow(NHW_MENU);
	vultures_start_menu(window);
	items = 0;
	lastch = 0;

	/* add all possible roles to a menu */
	for (chosen = 0; roles[chosen].name.m || roles[chosen].name.f; chosen++)
	{
		identifier.a_int = chosen + 1;
		if (ok_role(chosen, flags.initrace, flags.initgend, flags.initalign))
		{
			items++;
			item = chosen;

			if (flags.initgend == 1 && roles[chosen].name.f)
			{
				thisch = lowc(roles[chosen].name.f[0]);
				if (thisch == lastch)
					thisch = highc(thisch);
				vultures_add_menu (window, NO_GLYPH, &identifier, thisch, 0, 0,
								roles[chosen].name.f, (chosen == flags.initrole));
			}
			else
			{
				thisch = lowc(roles[chosen].name.m[0]);
				if (thisch == lastch)
					thisch = highc(thisch);
				vultures_add_menu (window, NO_GLYPH, &identifier, thisch, 0, 0,
								roles[chosen].name.m, (chosen==flags.initrole));
			}
			lastch = thisch;
		}
	}

	/* if the menu contains only one item, select that automatically */
	if (items == 1)
	{
		flags.initrole = item;
		free(menu_list);
		vultures_destroy_nhwindow(window);
		return 1;
	}

	identifier.a_int=-1;
	vultures_add_menu(window, NO_GLYPH, &identifier, '*', 0, 0, "Random", (flags.initrole<0));

	/* Don't use the rolename here, otherwise we might get "Pick a role for your wizard"
	* which is rather silly. */
	vultures_end_menu(window, "Pick a role for your character");

	if (vultures_select_menu(window, PICK_ONE, &menu_list) == 1)
	{
		chosen = menu_list->item.a_int;
		if (chosen == -1)
			chosen = pick_role(flags.initrace,flags.initgend,flags.initalign,PICK_RANDOM);
		else
			chosen--;

		free(menu_list);
		flags.initrole=chosen;
		vultures_destroy_nhwindow(window);
		return 1;
	}
	else
		vultures_bail(NULL);

	flags.initrole = -1;
	vultures_destroy_nhwindow(window);
	return 0;
}
/* prompt the player to choose an alignment */
static int vultures_player_selection_alignment (void)
{
	winid window;
	anything identifier;
	menu_item *menu_list;
	int chosen, items, item = 0;
	char rolename[BUFSZ];
	char selection[BUFSZ];
	char thisch, lastch;

	menu_list = 0;
	window = vultures_create_nhwindow(NHW_MENU);
	vultures_start_menu(window);
	chosen = 0;
	items = 0;
	lastch = 0;

	/* add the potential alignments for this character to a menu */
	while (chosen < ROLE_ALIGNS)
	{
		identifier.a_int = chosen + 1;
		if (ok_align(flags.initrole, flags.initrace, flags.initgend, chosen))
		{
			items++;
			item = chosen;
			thisch = lowc(aligns[chosen].adj[0]);
			if (thisch == lastch)
				thisch = highc(thisch);
			lastch = thisch;
			vultures_add_menu ( window, NO_GLYPH, &identifier, thisch, 0, 0,
								aligns[chosen].adj, (chosen == flags.initalign));
		}
		chosen++;
	}

	/* if there is only one possible alignment, select it automatically */
	if (items == 1)
	{
		flags.initalign = item;
		free(menu_list);
		vultures_destroy_nhwindow(window);
		return 1;
	}

	identifier.a_int = -1;
	vultures_add_menu(window, NO_GLYPH, &identifier, '*', 0, 0, "Random", (flags.initalign < 0));

	vultures_player_selection_rolename((char *)&rolename);
	sprintf(selection,"Pick the alignment of your %s", strlen(rolename) ? rolename : "character");
	vultures_end_menu(window, selection);

	/* let the player pick an alignment */
	if (vultures_select_menu (window, PICK_ONE, &menu_list)==1)
	{
		chosen = menu_list->item.a_int;
		if (chosen == -1)
			chosen = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM);
		else
			chosen--;

		flags.initalign = chosen;
		free(menu_list);
		vultures_destroy_nhwindow(window);
		return 1;
	}
	else
		vultures_bail(NULL);

	flags.initalign = -1;
	vultures_destroy_nhwindow(window);
	return 0;
}
/* prompt the player to choose a gender */
static int vultures_player_selection_gender (void)
{
	winid window;
	anything identifier;
	menu_item *menu_list;
	int chosen, item = 0, items;
	char rolename[BUFSZ];
	char selection[BUFSZ];
	char thisch, lastch;

	menu_list = 0;
	window = vultures_create_nhwindow(NHW_MENU);
	vultures_start_menu(window);
	chosen = 0;
	items = 0;
	lastch = 0;

	/* add all possible genders to the menu */
	while (chosen < ROLE_GENDERS)
	{
		identifier.a_int = chosen + 1;
		if (ok_gend(flags.initrole, flags.initrole, chosen, flags.initalign))
		{
			thisch = lowc(genders[chosen].adj[0]);
			if (thisch == lastch)
				thisch = highc(thisch);
			lastch = thisch;
			vultures_add_menu(window, NO_GLYPH, &identifier, thisch, 0, 0,
								genders[chosen].adj, chosen==flags.initgend);
			items++;
			item = chosen;
		}
		chosen++;
	}

	if (items==1)
	{
		flags.initgend = item;
		free(menu_list);
		vultures_destroy_nhwindow(window);
		return 1;
	}

	identifier.a_int=-1;
	vultures_add_menu(window, NO_GLYPH, &identifier, '*', 0, 0, "Random", (flags.initgend<0));

	vultures_player_selection_rolename((char *)&rolename);
	sprintf(selection,"Pick the gender of your %s", strlen(rolename) ? rolename : "character");
	vultures_end_menu(window, selection);

	if (vultures_select_menu (window, PICK_ONE, &menu_list) == 1)
	{
		chosen=menu_list->item.a_int;
		if (chosen == -1)
			chosen = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM);
		else
			chosen--;

		flags.initgend = chosen;
		free(menu_list);
		vultures_destroy_nhwindow(window);
		return 1;
	}
	else
		vultures_bail(NULL);

	flags.initgend = -1;
	vultures_destroy_nhwindow(window);
	return 0;
}
/* prompt the player to choose a race */
static int vultures_player_selection_race (void)
{
	winid window;
	anything identifier;
	menu_item *menu_list;
	int chosen, items, item = 0;
	char rolename[BUFSZ];
	char selection[BUFSZ];
	char thisch, lastch;

	menu_list = 0;
	window = vultures_create_nhwindow(NHW_MENU);
	vultures_start_menu(window);

	items = 0;
	lastch = 0;

	/* add all possible races to a menu */
	for (chosen = 0; races[chosen].noun; chosen++)
	{
		identifier.a_int = chosen + 1;
		if (ok_race(flags.initrole, chosen, flags.initgend, flags.initalign))
		{
			items++;
			item = chosen;
			thisch = lowc(races[chosen].noun[0]);
			if (thisch == lastch)
				thisch = highc(thisch);
			lastch = thisch;
			vultures_add_menu(window, NO_GLYPH, &identifier, thisch, 0, 0,
							races[chosen].noun, chosen==flags.initrace);
		}
	}

	/* if the menu contains only one item, select that automatically */
	if (items == 1) {
		flags.initrace = item;
		free(menu_list);
		vultures_destroy_nhwindow(window);
		return 1;
	}

	identifier.a_int=-1;
	vultures_add_menu ( window, NO_GLYPH, &identifier, '*', 0, 0, "Random", (flags.initrace<0));

	vultures_player_selection_rolename((char *)&rolename);
	sprintf(selection,"Pick the race of your %s", strlen(rolename) ? rolename : "character");
	vultures_end_menu(window, selection);

	if (vultures_select_menu (window, PICK_ONE, &menu_list)==1)
	{
		chosen = menu_list->item.a_int;
		if (chosen == -1)
			chosen = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM);
		else
			chosen--;

		free(menu_list);
		flags.initrace = chosen;
		vultures_destroy_nhwindow(window);
		return 1;
	}
	else
		vultures_bail(NULL);

	flags.initrace = -1;
	vultures_destroy_nhwindow(window);
	return 0;

}