From 44cc716fe4491ddff4b2569846d4340b0c76554f Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Sun, 22 Mar 2009 00:23:57 +0000 Subject: [PATCH] enhanced interactive role selection (trunk only) [See cvs log for src/role.c for a much longer description.] When picking role, race, and so forth, new menu entries allow you to pick any of the other items before the one currently being handled. After picking all four of race, role, gender, and alignment (or if you answered 'y' to "shall I pick for you?"), there is a followup prompt to confirm the choices. It's a menu which also provides a chance to rename the character. This has only been implemented in win/tty's player_selection(), with some support code in the core that might be useful to other interfaces. And so far, the chance to rename is only presented as a menu choice if you've given an answer to "who are you?" prompt earlier during startup. Also, ports that use pcmain.c aren't able to perform hero renaming yet. --- doc/fixes35.0 | 1 + include/extern.h | 10 +- include/flag.h | 2 + include/winprocs.h | 8 + sys/be/bemain.c | 37 ++- sys/mac/macmain.c | 45 ++- sys/mac/macunix.c | 3 +- sys/share/pcmain.c | 44 ++- sys/unix/unixmain.c | 67 ++-- sys/unix/unixunix.c | 6 + sys/vms/vmsmain.c | 69 ++-- sys/vms/vmsunix.c | 6 + win/tty/wintty.c | 768 +++++++++++++++++++++++++++----------------- 13 files changed, 693 insertions(+), 373 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 86873aa6a..f51df1bae 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -448,6 +448,7 @@ win32gui: added menu options "Copy ASCII Screenshot To Clipboard" and "Save win32tty: support for 'selectsaved' option for menu of existing save files to choose from at game startup tty: add window port routines for saving/restoring message history +tty: enhanced role, race, &c selection during at start of new game smartphone: added "Type Cmd" command that allows to type arbitrary commands using phone keypad smartphone: added Q(quiver) command to "Attack" layout diff --git a/include/extern.h b/include/extern.h index 811e71980..ce93bc144 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1965,14 +1965,16 @@ E boolean FDECL(ok_gend, (int, int, int, int)); E int FDECL(pick_gend, (int, int, int, int)); E boolean FDECL(ok_align, (int, int, int, int)); E int FDECL(pick_align, (int, int, int, int)); -E void NDECL(role_init); E void NDECL(rigid_role_checks); +E boolean FDECL(setrolefilter, (char *)); +E char *FDECL(build_plselection_prompt, (char *,int,int,int,int,int)); +E char *FDECL(root_plselection_prompt, (char *,int,int,int,int,int)); E void NDECL(plnamesuffix); +E void FDECL(role_selection_prolog, (int,winid)); +E void FDECL(role_menu_extra, (int,winid)); +E void NDECL(role_init); E const char *FDECL(Hello, (struct monst *)); E const char *NDECL(Goodbye); -E char *FDECL(build_plselection_prompt, (char *, int, int, int, int, int)); -E char *FDECL(root_plselection_prompt, (char *, int, int, int, int, int)); -E boolean FDECL(setrolefilter, (char *)); /* ### rumors.c ### */ diff --git a/include/flag.h b/include/flag.h index e45a374d3..de24b9501 100644 --- a/include/flag.h +++ b/include/flag.h @@ -182,6 +182,8 @@ struct instance_flags { boolean menu_tab_sep; /* Use tabs to separate option menu fields */ boolean menu_requested; /* Flag for overloaded use of 'm' prefix * on some non-move commands */ + boolean renameallowed; /* can change hero name during role selection */ + boolean renameinprogress; /* we are changing hero name */ boolean zerocomp; /* write zero-compressed save files */ boolean rlecomp; /* run-length comp of levels when writing savefile */ uchar num_pad_mode; diff --git a/include/winprocs.h b/include/winprocs.h index 11ad3ba28..2623abaa7 100644 --- a/include/winprocs.h +++ b/include/winprocs.h @@ -254,4 +254,12 @@ struct wc_Opt { unsigned long wc_bit; }; +/* role selection by player_selection(); this ought to be in the core... */ +#define RS_NAME 0 +#define RS_ROLE 1 +#define RS_RACE 2 +#define RS_GENDER 3 +#define RS_ALGNMNT 4 +#define RS_menu_arg(x) (ROLE_RANDOM - ((x) + 1)) /* 0..4 -> -3..-7 */ + #endif /* WINPROCS_H */ diff --git a/sys/be/bemain.c b/sys/be/bemain.c index 35dee04d3..3f67fc0c0 100644 --- a/sys/be/bemain.c +++ b/sys/be/bemain.c @@ -44,14 +44,15 @@ int MAIN(int argc, char **argv) process_options(argc, argv); /* command line options */ set_playmode(); /* sets plname to "wizard" for wizard mode */ - if(!*plname || !strncmp(plname, "player", 4) - || !strncmp(plname, "games", 4)) - askname(); - plnamesuffix(); /* strip suffix from name; calls askname() */ - /* again if suffix was whole name */ - /* accepts any suffix */ + /* strip role,race,&c suffix; calls askname() if plname[] is empty + or holds a generic user name like "player" or "games" */ + plnamesuffix(); + /* unlike Unix where the game might be invoked with a script + which forces a particular character name for each player + using a shared account, we always allow player to rename + the character during role/race/&c selection */ + iflags.renameallowed = TRUE; - Sprintf(lock,"%d%s", getuid(), plname); getlock(); dlb_init(); /* must be before newgame() */ @@ -75,6 +76,11 @@ int MAIN(int argc, char **argv) display_gamewindows(); + /* + * First, try to find and restore a save file for specified character. + * We'll return here if new game player_selection() renames the hero. + */ + attempt_restore: if ((fd = restore_saved_game()) >= 0) { #ifdef NEWS if(iflags.news) { @@ -99,7 +105,21 @@ int MAIN(int argc, char **argv) } if (!resuming) { - player_selection(); + /* new game: start by choosing role, race, etc; + player might change the hero's name while doing that, + in which case we try to restore under the new name + and skip selection this time if that didn't succeed */ + if (!iflags.renameinprogress) { + player_selection(); + if (iflags.renameinprogress) { + /* player has renamed the hero while selecting role; + discard current lock file and create another for + the new character name */ + delete_levelfile(0); /* remove empty lock file */ + getlock(); + goto attempt_restore; + } + } newgame(); if (discover) You("are in non-scoring discovery mode."); @@ -221,6 +241,7 @@ void getlock(void) { int fd; + Sprintf(lock, "%d%s", getuid(), plname); regularize(lock); set_levelfile_name(lock, 0); fd = creat(lock, FCMASK); diff --git a/sys/mac/macmain.c b/sys/mac/macmain.c index 7a0d287a3..0ad68009e 100644 --- a/sys/mac/macmain.c +++ b/sys/mac/macmain.c @@ -80,16 +80,22 @@ main (void) display_gamewindows(); set_playmode(); /* sets plname to "wizard" for wizard mode */ - if (!*plname || !strncmp(plname, "player", 4) || - !strncmp(plname, "games", 4)) - askname(); - plnamesuffix(); /* strip suffix from name; calls askname() */ - /* again if suffix was whole name */ - /* accepts any suffix */ + /* strip role,race,&c suffix; calls askname() if plname[] is empty + or holds a generic user name like "player" or "games" */ + plnamesuffix(); + /* unlike Unix where the game might be invoked with a script + which forces a particular character name for each player + using a shared account, we always allow player to rename + the character during role/race/&c selection */ + iflags.renameallowed = TRUE; - Sprintf (lock, "%d%s", getuid (), plname); - getlock (); + getlock(); + /* + * First, try to find and restore a save file for specified character. + * We'll return here if new game player_selection() renames the hero. + */ + attempt_restore: if ((fd = restore_saved_game()) >= 0) { #ifdef NEWS if(iflags.news) { @@ -102,6 +108,8 @@ main (void) game_active = 1; if (dorecover(fd)) { resuming = TRUE; /* not starting new game */ + if (discover) + You("are in non-scoring discovery mode."); if (discover || wizard) { if(yn("Do you want to keep the save file?") == 'n') (void) delete_savefile(); @@ -113,14 +121,27 @@ main (void) } if (!resuming) { - player_selection(); + /* new game: start by choosing role, race, etc; + player might change the hero's name while doing that, + in which case we try to restore under the new name + and skip selection this time if that didn't succeed */ + if (!iflags.renameinprogress) { + player_selection(); + if (iflags.renameinprogress) { + /* player has renamed the hero while selecting role; + discard current lock file and create another for + the new character name */ + delete_levelfile(0); /* remove empty lock file */ + getlock(); + goto attempt_restore; + } + } game_active = 1; /* done with selection, draw active game window */ newgame(); + if (discover) + You("are in non-scoring discovery mode."); } - if (discover) - You("are in non-scoring discovery mode."); - UndimMenuBar (); /* Yes, this is the place for it (!) */ moveloop(resuming); diff --git a/sys/mac/macunix.c b/sys/mac/macunix.c index e29035fd3..5e31dcdb9 100644 --- a/sys/mac/macunix.c +++ b/sys/mac/macunix.c @@ -22,7 +22,8 @@ getlock(void) { int fd; int pid = getpid(); /* Process ID */ - + + Sprintf(lock, "%d%s", getuid(), plname); set_levelfile_name (lock, 0); if ((fd = open (lock, O_RDWR | O_EXCL | O_CREAT, LEVL_TYPE)) == -1) { diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index 36f140697..bee05f9dc 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -338,12 +338,23 @@ char *argv[]; # endif #endif - if (!*plname) - askname(); - plnamesuffix(); /* strip suffix from name; calls askname() */ - /* again if suffix was whole name */ - /* accepts any suffix */ + /* strip role,race,&c suffix; calls askname() if plname[] is empty + or holds a generic user name like "player" or "games" */ + plnamesuffix(); set_playmode(); /* sets plname to "wizard" for wizard mode */ +#if 0 + /* unlike Unix where the game might be invoked with a script + which forces a particular character name for each player + using a shared account, we always allow player to rename + the character during role/race/&c selection */ + iflags.renameallowed = TRUE; +#else + /* until the getlock code is resolved, override askname()'s + setting of renameallowed; when False, player_selection() + won't resent renaming as an option */ + iflags.renameallowed = FALSE; +#endif + #if defined(PC_LOCKING) /* 3.3.0 added this to support detection of multiple games * under the same plname on the same machine in a windowed @@ -427,6 +438,11 @@ char *argv[]; getreturn_enabled = TRUE; #endif + /* + * First, try to find and restore a save file for specified character. + * We'll return here if new game player_selection() renames the hero. + */ + attempt_restore: if ((fd = restore_saved_game()) >= 0) { #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done1); @@ -455,7 +471,23 @@ char *argv[]; } if (!resuming) { - player_selection(); + /* new game: start by choosing role, race, etc; + player might change the hero's name while doing that, + in which case we try to restore under the new name + and skip selection this time if that didn't succeed */ + if (!iflags.renameinprogress) { + player_selection(); + if (iflags.renameinprogress) { + /* player has renamed the hero while selecting role; + discard current lock file and create another for + the new character name */ +#if 0 /* this needs to be reconciled with the getlock mess above... */ + delete_levelfile(0); /* remove empty lock file */ + getlock(); +#endif + goto attempt_restore; + } + } newgame(); if (discover) You("are in non-scoring discovery mode."); diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 4119d1e03..81b033cef 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -192,10 +192,7 @@ char *argv[]; /* wizard mode access is deferred until here */ set_playmode(); /* sets plname to "wizard" for wizard mode */ - if(!*plname || !strncmp(plname, "player", 4) - || !strncmp(plname, "games", 4)) { - askname(); - } else if (exact_username) { + if (exact_username) { /* guard against user names with hyphens in them */ int len = strlen(plname); /* append the current role, if any, so that last dash is ours */ @@ -203,27 +200,33 @@ char *argv[]; (void)strncat(strcat(plname, "-"), pl_character, sizeof plname - len - 1); } - plnamesuffix(); /* strip suffix from name; calls askname() */ - /* again if suffix was whole name */ - /* accepts any suffix */ + /* strip role,race,&c suffix; calls askname() if plname[] is empty + or holds a generic user name like "player" or "games" */ + plnamesuffix(); + #ifdef WIZARD - if(!wizard) { + if (wizard) { + /* use character name rather than lock letter for file names */ + locknum = 0; + } else #endif - /* - * check for multiple games under the same name - * (if !locknum) or check max nr of players (otherwise) - */ + { + /* suppress interrupts while processing lock file */ (void) signal(SIGQUIT,SIG_IGN); (void) signal(SIGINT,SIG_IGN); - if(!locknum) - Sprintf(lock, "%d%s", (int)getuid(), plname); - getlock(); -#ifdef WIZARD - } else { - Sprintf(lock, "%d%s", (int)getuid(), plname); - getlock(); } -#endif /* WIZARD */ + /* + * getlock() complains and quits if there is already a game + * in progress for current character name (when locknum == 0) + * or if there are too many active games (when locknum > 0). + * When proceeding, it creates an empty .0 file to + * designate the current game. + * getlock() constructs based on the character + * name (for !locknum) or on first available of alock, block, + * clock, &c not currently in use in the playground directory + * (for locknum > 0). + */ + getlock(); program_state.preserve_locks = 0; /* after getlock() */ dlb_init(); /* must be before newgame() */ @@ -247,6 +250,11 @@ char *argv[]; display_gamewindows(); + /* + * First, try to find and restore a save file for specified character. + * We'll return here if new game player_selection() renames the hero. + */ + attempt_restore: if ((fd = restore_saved_game()) >= 0) { const char *fq_save = fqname(SAVEF, SAVEPREFIX, 1); @@ -275,7 +283,24 @@ char *argv[]; } if (!resuming) { - player_selection(); + /* new game: start by choosing role, race, etc; + player might change the hero's name while doing that, + in which case we try to restore under the new name + and skip selection this time if that didn't succeed */ + if (!iflags.renameinprogress) { + player_selection(); + if (iflags.renameinprogress) { + /* player has renamed the hero while selecting role; + if locking alphabetically, the existing lock file + can still be used; otherwise, discard current one + and create another for the new character name */ + if (!locknum) { + delete_levelfile(0); /* remove empty lock file */ + getlock(); + } + goto attempt_restore; + } + } newgame(); wd_message(); } diff --git a/sys/unix/unixunix.c b/sys/unix/unixunix.c index d47ebe7c7..c6dc21545 100644 --- a/sys/unix/unixunix.c +++ b/sys/unix/unixunix.c @@ -112,6 +112,12 @@ getlock() error("%s", ""); } + /* default value of lock[] is "1lock" where '1' gets changed to + 'a','b',&c below; override the default and use + if we aren't restricting the number of simultaneous games */ + if (!locknum) + Sprintf(lock, "%u%s", (unsigned)getuid(), plname); + regularize(lock); set_levelfile_name(lock, 0); diff --git a/sys/vms/vmsmain.c b/sys/vms/vmsmain.c index 4ed280a88..9c6474891 100644 --- a/sys/vms/vmsmain.c +++ b/sys/vms/vmsmain.c @@ -128,30 +128,33 @@ char *argv[]; /* wizard mode access is deferred until here */ set_playmode(); /* sets plname to "wizard" for wizard mode */ - if (!*plname || !strncmpi(plname, "games", 4) || - !strcmpi(plname, "nethack")) - askname(); - plnamesuffix(); /* strip suffix from name; calls askname() */ - /* again if suffix was whole name */ - /* accepts any suffix */ + /* strip role,race,&c suffix; calls askname() if plname[] is empty + or holds a generic user name like "player" or "games" */ + plnamesuffix(); + #ifdef WIZARD - if(!wizard) { + if (wizard) { + /* use character name rather than lock letter for file names */ + locknum = 0; + } else #endif - /* - * check for multiple games under the same name - * (if !locknum) or check max nr of players (otherwise) - */ - (void) signal(SIGQUIT,SIG_IGN); - (void) signal(SIGINT,SIG_IGN); - if(!locknum) - Sprintf(lock, "_%u%s", (unsigned)getuid(), plname); - getlock(); -#ifdef WIZARD - } else { - Sprintf(lock, "_%u%s", (unsigned)getuid(), plname); - getlock(); + { + /* suppress interrupts while processing lock file */ + (void) signal(SIGQUIT, SIG_IGN); + (void) signal(SIGINT, SIG_IGN); } -#endif /* WIZARD */ + /* + * getlock() complains and quits if there is already a game + * in progress for current character name (when locknum == 0) + * or if there are too many active games (when locknum > 0). + * When proceeding, it creates an empty .0 file to + * designate the current game. + * getlock() constructs based on the character + * name (for !locknum) or on first available of alock, block, + * clock, &c not currently in use in the playground directory + * (for locknum > 0). + */ + getlock(); dlb_init(); /* must be before newgame() */ @@ -174,6 +177,11 @@ char *argv[]; display_gamewindows(); + /* + * First, try to find and restore a save file for specified character. + * We'll return here if new game player_selection() renames the hero. + */ + attempt_restore: if ((fd = restore_saved_game()) >= 0) { const char *fq_save = fqname(SAVEF, SAVEPREFIX, 1); @@ -200,7 +208,24 @@ char *argv[]; } if (!resuming) { - player_selection(); + /* new game: start by choosing role, race, etc; + player might change the hero's name while doing that, + in which case we try to restore under the new name + and skip selection this time if that didn't succeed */ + if (!iflags.renameinprogress) { + player_selection(); + if (iflags.renameinprogress) { + /* player has renamed the hero while selecting role; + if locking alphabetically, the existing lock file + can still be used; otherwise, discard current one + and create another for the new character name */ + if (!locknum) { + delete_levelfile(0); /* remove empty lock file */ + getlock(); + } + goto attempt_restore; + } + } newgame(); wd_message(); } diff --git a/sys/vms/vmsunix.c b/sys/vms/vmsunix.c index 24fefaa0d..3b7dab480 100644 --- a/sys/vms/vmsunix.c +++ b/sys/vms/vmsunix.c @@ -94,6 +94,12 @@ getlock() error("Quitting."); } + /* default value of lock[] is "1lock" where '1' gets changed to + 'a','b',&c below; override the default and use + if we aren't restricting the number of simultaneous games */ + if (!locknum) + Sprintf(lock, "_%u%s", (unsigned)getuid(), plname); + regularize(lock); set_levelfile_name(lock, 0); if(locknum > 25) locknum = 25; diff --git a/win/tty/wintty.c b/win/tty/wintty.c index f946e519a..7d7e614f9 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -353,343 +353,509 @@ char** argv; tty_display_nhwindow(BASE_WINDOW, FALSE); } +/* 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() { - int i, k, n; - char pick4u = 'n', thisch, lastch = 0; - char pbuf[QBUFSZ], plbuf[QBUFSZ]; - winid win; - anything any; - menu_item *selected = 0; + int i, k, n, choice, nextpick; + boolean getconfirmation; + char pick4u = 'n', thisch, lastch = 0; + char pbuf[QBUFSZ], plbuf[QBUFSZ]; + winid win; + anything any; + menu_item *selected = 0; - /* prevent an unnecessary prompt */ - rigid_role_checks(); + if (flags.randomall) { + 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; + } - /* 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)) { - int echoline; - char *prompt = build_plselection_prompt(pbuf, QBUFSZ, flags.initrole, - flags.initrace, flags.initgend, flags.initalign); + /* prevent an unnecessary prompt */ + 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 (index(quitchars, pick4u)) pick4u = 'y'; + } while (!index(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, ""); - echoline = wins[BASE_WINDOW]->cury; - tty_putstr(BASE_WINDOW, 0, prompt); - do { - pick4u = lowc(readchar()); - if (index(quitchars, pick4u)) pick4u = 'y'; - } while(!index(ynqchars, 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 != 'n') { -give_up: /* Quit */ - if (selected) free((genericptr_t) selected); - bail((char *)0); - /*NOTREACHED*/ - return; - } - } + } 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); - (void) root_plselection_prompt(plbuf, QBUFSZ - 1, - flags.initrole, flags.initrace, flags.initgend, flags.initalign); + if (pick4u != 'y' && pick4u != 'a' && pick4u != 'n') goto give_up; + } - /* 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[QBUFSZ]; - /* 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) { - tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); - flags.initrole = randrole(); - } - } else { - tty_clear_nhwindow(BASE_WINDOW); - tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); - /* Prompt for a role */ - win = create_nhwindow(NHW_MENU); - start_menu(win); - any = zeroany; /* 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 */ + 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(); + } + } else { + /* Prompt for a role */ + char rolenamebuf[QBUFSZ]; + + tty_clear_nhwindow(BASE_WINDOW); + role_selection_prolog(RS_ROLE, BASE_WINDOW); + win = create_nhwindow(NHW_MENU); + start_menu(win); + any = zeroany; /* zero out all bits */ + for (i = 0; roles[i].name.m; i++) { + if (!ok_role(i, RACE, GEND, ALGN)) continue; + 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); + 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); + } + } + 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); + role_menu_extra(ROLE_RANDOM, win); + any.a_int = 0; /* separator, not a choice */ + add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, + "", MENU_UNSELECTED); + role_menu_extra(RS_RACE, win); + role_menu_extra(RS_GENDER, win); + role_menu_extra(RS_ALGNMNT, win); + role_menu_extra(ROLE_NONE, win); /* quit */ + Strcpy(pbuf, "Pick a role or profession"); + end_menu(win, pbuf); + n = select_menu(win, PICK_ONE, &selected); + choice = (n == 1) ? selected[0].item.a_int : ROLE_NONE; + if (selected) free((genericptr_t) selected), selected = 0; + 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, QBUFSZ - 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) { - tty_putstr(BASE_WINDOW, 0, "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; - } + 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 == ROLE_RANDOM) { + k = pick_role(RACE, GEND, ALGN, PICK_RANDOM); + if (k < 0) k = randrole(); + } else { + k = choice - 1; } } + ROLE = k; + } /* needed role */ + } /* picking role */ - /* Permit the user to pick, if there is more than one */ - if (n > 1) { - tty_clear_nhwindow(BASE_WINDOW); - tty_putstr(BASE_WINDOW, 0, "Choosing Race"); - win = create_nhwindow(NHW_MENU); - start_menu(win); - any = zeroany; /* zero out all bits */ + 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(flags.initrole, i, flags.initgend, - flags.initalign)) { - any.a_int = i+1; /* must be non-zero */ + 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); + any = zeroany; /* zero out all bits */ + for (i = 0; races[i].noun; i++) { + if (!ok_race(ROLE, i, GEND, ALGN)) continue; + 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); + 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 */ + role_menu_extra(ROLE_RANDOM, win); + any.a_int = 0; /* separator, not a choice */ + add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, + "", MENU_UNSELECTED); + role_menu_extra(RS_ROLE, win); + role_menu_extra(RS_GENDER, win); + role_menu_extra(RS_ALGNMNT, win); + role_menu_extra(ROLE_NONE, win); /* quit */ + Strcpy(pbuf, "Pick a race or species"); + end_menu(win, pbuf); + n = select_menu(win, PICK_ONE, &selected); + choice = (n == 1) ? selected[0].item.a_int : ROLE_NONE; + if (selected) free((genericptr_t) selected), selected = 0; + destroy_nhwindow(win); - k = selected[0].item.a_int - 1; - free((genericptr_t) selected), selected = 0; - } - flags.initrace = k; - } - (void) root_plselection_prompt(plbuf, QBUFSZ - 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) { - tty_putstr(BASE_WINDOW, 0, "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; + 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 == 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 */ - /* Permit the user to pick, if there is more than one */ - if (n > 1) { - tty_clear_nhwindow(BASE_WINDOW); - tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); - win = create_nhwindow(NHW_MENU); - start_menu(win); - any = zeroany; /* zero out all bits */ + 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(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, QBUFSZ - 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) { - tty_putstr(BASE_WINDOW, 0, "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)) { + 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); + any = zeroany; /* zero out all bits */ + for (i = 0; i < ROLE_GENDERS; i++) { + if (!ok_gend(ROLE, RACE, i, ALGN)) continue; + any.a_int = i + 1; /* non-zero */ + add_menu(win, NO_GLYPH, &any, genders[i].adj[0], + 0, ATR_NONE, genders[i].adj, MENU_UNSELECTED); + } + role_menu_extra(ROLE_RANDOM, win); + any.a_int = 0; /* separator, not a choice */ + add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, + "", MENU_UNSELECTED); + role_menu_extra(RS_ROLE, win); + role_menu_extra(RS_RACE, win); + role_menu_extra(RS_ALGNMNT, win); + role_menu_extra(ROLE_NONE, win); /* quit */ + Strcpy(pbuf, "Pick a gender or sex"); + end_menu(win, pbuf); + n = select_menu(win, PICK_ONE, &selected); + choice = (n == 1) ? selected[0].item.a_int : 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 == 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 */ - /* Permit the user to pick, if there is more than one */ - if (n > 1) { - tty_clear_nhwindow(BASE_WINDOW); - tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); - win = create_nhwindow(NHW_MENU); - start_menu(win); - any = zeroany; /* zero out all bits */ + 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(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); + if (ok_align(ROLE, RACE, GEND, i)) { + n++; + k = i; } - 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 */ + 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); + any = zeroany; /* zero out all bits */ + for (i = 0; i < ROLE_ALIGNS; i++) { + if (!ok_align(ROLE, RACE, GEND, i)) continue; + any.a_int = i + 1; /* non-zero */ + add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], + 0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED); + } + role_menu_extra(ROLE_RANDOM, win); + any.a_int = 0; /* separator, not a choice */ + add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, + "", MENU_UNSELECTED); + role_menu_extra(RS_ROLE, win); + role_menu_extra(RS_RACE, win); + role_menu_extra(RS_GENDER, win); + role_menu_extra(ROLE_NONE, win); /* quit */ + Strcpy(pbuf, "Pick an alignment or creed"); + end_menu(win, pbuf); + n = select_menu(win, PICK_ONE, &selected); + choice = (n == 1) ? selected[0].item.a_int : ROLE_NONE; + if (selected) free((genericptr_t) selected), selected = 0; + destroy_nhwindow(win); - k = selected[0].item.a_int - 1; - free((genericptr_t) selected), selected = 0; + 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 == ROLE_RANDOM) { + k = pick_align(ROLE, RACE, GEND, PICK_RANDOM); + if (k < 0) k = randalign(ROLE, RACE); + } else { + k = choice - 1; + } + } } - flags.initalign = k; - } + 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 = (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); + any = 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 */ + Sprintf(pbuf, "%s, %s%s %s %s", + plname, aligns[ALGN].adj, plbuf, races[FACE].adj, + (GEND == 1 && roles[ROLE].name.f) ? + roles[ROLE].name.f : roles[ROLE].name.m); + add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, + pbuf, MENU_UNSELECTED); + /* blank separator */ + any.a_int = 0; + add_menu(win, NO_GLYPH, &any, ' ', 0, ATR_NONE, + "", MENU_UNSELECTED); + /* [ynaq] menu choices */ + any.a_int = 1; + add_menu(win, NO_GLYPH, &any, 'y', 0, ATR_NONE, + "Yes; start game", MENU_SELECTED); + any.a_int = 2; + add_menu(win, NO_GLYPH, &any, 'n', 0, ATR_NONE, + "No; choose role again", MENU_UNSELECTED); + if (iflags.renameallowed) { + any.a_int = 3; + add_menu(win, NO_GLYPH, &any, 'a', 0, ATR_NONE, + "Not yet; choose another name", MENU_UNSELECTED); } - /* Success! */ - tty_display_nhwindow(BASE_WINDOW, FALSE); + any.a_int = -1; + add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, + "Quit", MENU_UNSELECTED); + 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; + + 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; + *plname = '\0'; + plnamesuffix(); /* calls askname() when 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; + + give_up: + /* Quit */ + if (selected) free((genericptr_t) selected); /* [obsolete] */ + bail((char *)0); + /*NOTREACHED*/ + return; } +#undef ROLE +#undef RACE +#undef GEND +#undef ALGN + /* * plname is filled either by an option (-u Player or -uPlayer) or * explicitly (by being the wizard) or by askname. @@ -703,7 +869,7 @@ tty_askname() register int c, ct, tryct = 0; #ifdef SELECTSAVED - if (iflags.wc2_selectsaved) + if (iflags.wc2_selectsaved && !iflags.renameinprogress) switch (restore_menu(BASE_WINDOW)) { case -1: bail("Until next time then..."); /* quit */ /*NOTREACHED*/ @@ -784,6 +950,10 @@ tty_askname() /* move to next line to simulate echo of user's */ tty_curs(BASE_WINDOW, 1, wins[BASE_WINDOW]->cury + 1); + + /* since we let user pick an arbitrary name now, he/she can pick + another one during role selection */ + iflags.renameallowed = TRUE; } void