Пример #1
0
void
startup(void)
{
	char *term;
	char *tptr;
	char *tbufptr, *pc;

	tptr = (char *) alloc(1024);

	tbufptr = tbuf;
	if(!(term = getenv("TERM")))
		error("Can't get TERM.");
	if(!strncmp(term, "5620", 4))
		flags.nonull = 1;	/* this should be a termcap flag */
	if(tgetent(tptr, term) < 1)
		error("Unknown terminal type: %s.", term);
	if ((pc = tgetstr("pc", &tbufptr)))
		PC = *pc;
	if(!(BC = tgetstr("le", &tbufptr))) {	
		if(!tgetflag("bs"))
			error("Terminal must backspace.");
		BC = tbufptr;
		tbufptr += 2;
		*BC = '\b';
	}
	HO = tgetstr("ho", &tbufptr);
	CO = tgetnum("co");
	LI = tgetnum("li");
	if(CO < COLNO || LI < ROWNO+2)
		setclipped();
	if(!(CL = tgetstr("cl", &tbufptr)))
		error("Hack needs CL.");
	ND = tgetstr("nd", &tbufptr);
	if(tgetflag("os"))
		error("Hack can't have OS.");
	CE = tgetstr("ce", &tbufptr);
	UP = tgetstr("up", &tbufptr);
	/* It seems that xd is no longer supported, and we should use
	   a linefeed instead; unfortunately this requires resetting
	   CRMOD, and many output routines will have to be modified
	   slightly. Let's leave that till the next release. */
	XD = tgetstr("xd", &tbufptr);
/* not: 		XD = tgetstr("do", &tbufptr); */
	if(!(CM = tgetstr("cm", &tbufptr))) {
		if(!UP && !HO)
			error("Hack needs CM or UP or HO.");
		printf("Playing hack on terminals without cm is suspect...\n");
		getret();
	}
	SO = tgetstr("so", &tbufptr);
	SE = tgetstr("se", &tbufptr);
	SG = tgetnum("sg");	/* -1: not fnd; else # of spaces left by so */
	if(!SO || !SE || (SG > 0)) SO = SE = 0;
	CD = tgetstr("cd", &tbufptr);
	set_whole_screen();		/* uses LI and CD */
	if(tbufptr-tbuf > sizeof(tbuf)) error("TERMCAP entry too big...\n");
	free(tptr);
}
Пример #2
0
int main()
{
    int n;

    while(scanf("%d", &n) != EOF)
    {
        printf("%d\n", getret(n));
    }
    return 0;
}
Пример #3
0
outrip(){
	register char **dp = rip;
	register char *dpx;
	char buf[BUFSZ];
	register x,y;

	cls();
	(void) strcpy(buf, plname);
	buf[16] = 0;
	center(6, buf);
	(void) sprintf(buf, "%ld AU", u.ugold);
	center(7, buf);
	(void) sprintf(buf, "killed by%s",
		!strncmp(killer, "the ", STRLEN("the ")) ? "" :
		!strcmp(killer, "starvation") ? "" :
		index(vowels, *killer) ? " an" : " a");
	center(8, buf);
	(void) strcpy(buf, killer);
	if(strlen(buf) > 16) {
	    register int i,i0,i1;
		i0 = i1 = 0;
		for(i = 0; i <= 16; i++)
			if(buf[i] == ' ') i0 = i, i1 = i+1;
		if(!i0) i0 = i1 = 16;
		buf[i1 + 16] = 0;
		center(10, buf+i1);
		buf[i0] = 0;
	}
	center(9, buf);
	(void) sprintf(buf, "%4d", getyear());
	center(11, buf);
	for(y=8; *dp; y++,dp++){
		x = 0;
		dpx = *dp;
		while(dpx[x]) {
			while(dpx[x] == ' ') x++;
			curs(x,y);
			while(dpx[x] && dpx[x] != ' '){
				extern int done_stopprint;
				if(done_stopprint)
					return;
				curx++;
				(void) putchar(dpx[x++]);
			}
		}
	}
	getret();
}
Пример #4
0
static void
chdirx(char *dir, boolean wr)
{
	gid_t gid;

#ifdef SECURE
	if(dir					/* User specified directory? */
#ifdef HACKDIR
	       && strcmp(dir, HACKDIR)		/* and not the default? */
#endif
		) {
		/* revoke privs */
		gid = getgid();
		setresgid(gid, gid, gid);
	}
#endif

#ifdef HACKDIR
	if(dir == NULL)
		dir = HACKDIR;
#endif

	if(dir && chdir(dir) < 0) {
		perror(dir);
		error("Cannot chdir to %s.", dir);
	}

	/* warn the player if he cannot write the record file */
	/* perhaps we should also test whether . is writable */
	/* unfortunately the access systemcall is worthless */
	if(wr) {
	    int fd;

	    if(dir == NULL)
		dir = ".";
	    if((fd = open(RECORD, O_RDWR)) < 0) {
		printf("Warning: cannot write %s/%s", dir, RECORD);
		getret();
	    } else
		(void) close(fd);
	}
}
Пример #5
0
int
child(int wt)
{
	int status;
	int f;
	char *home;
	gid_t gid;

	f = fork();
	if(f == 0){		/* child */
		settty((char *) 0);		/* also calls end_screen() */
		/* revoke privs */
		gid = getgid();
		setresgid(gid, gid, gid);
#ifdef CHDIR
		home = getenv("HOME");
		if (home == NULL || *home == '\0')
			home = "/";
		(void) chdir(home);
#endif /* CHDIR */
		return(1);
	}
	if(f == -1) {	/* cannot fork */
		pline("Fork failed. Try again.");
		return(0);
	}
	/* fork succeeded; wait for child to exit */
	(void) signal(SIGINT,SIG_IGN);
	(void) signal(SIGQUIT,SIG_IGN);
	(void) wait(&status);
	gettty();
	setftty();
	(void) signal(SIGINT,done1);
#ifdef WIZARD
	if(wizard) (void) signal(SIGQUIT,SIG_DFL);
#endif /* WIZARD */
	if(wt) getret();
	docrt();
	return(0);
}
Пример #6
0
void
outrip(void)
{
	char            buf[BUFSZ];

	cls();
	curs(1, 8);
	puts(riptop);
	(void) strcpy(buf, plname);
	buf[16] = 0;
	center(6, buf);
	(void) snprintf(buf, sizeof(buf), "%ld AU", u.ugold);
	center(7, buf);
	(void) snprintf(buf, sizeof(buf), "killed by%s",
		       !strncmp(killer, "the ", 4) ? "" :
		       !strcmp(killer, "starvation") ? "" :
		       strchr(vowels, *killer) ? " an" : " a");
	center(8, buf);
	(void) strlcpy(buf, killer, sizeof(buf));
	{
		int             i1;
		if ((i1 = strlen(buf)) > 16) {
			int             i, i0;
			i0 = i1 = 0;
			for (i = 0; i <= 16; i++)
				if (buf[i] == ' ')
					i0 = i, i1 = i + 1;
			if (!i0)
				i0 = i1 = 16;
			buf[i1 + 16] = 0;
			buf[i0] = 0;
		}
		center(9, buf);
		center(10, buf + i1);
	}
	(void) snprintf(buf, sizeof(buf), "%4d", getyear());
	center(11, buf);
	puts(ripbot);
	getret();
}
Пример #7
0
static void chdirx(const char *dir, bool wr)
{

#ifdef SECURE
    if (dir		       // User specified directory?
#ifdef HACKDIR
	&& strcmp(dir, HACKDIR)	// and not the default?
#endif
	) {
	(void) setuid(getuid());	// Ron Wessels
	(void) setregid(getgid(), getgid());
    }
#endif

#ifdef HACKDIR
    if (dir == NULL)
	dir = HACKDIR;
#endif

    if (dir && chdir(dir) < 0) {
	perror(dir);
	error("Cannot chdir to %s.", dir);
    }
    // warn the player if he cannot write the record file
    // perhaps we should also test whether . is writable
    // unfortunately the access systemcall is worthless
    if (wr) {
	int fd;

	if (dir == NULL)
	    dir = ".";
	if ((fd = open(RECORD, O_RDWR)) < 0) {
	    printf("Warning: cannot write %s/%s", dir, RECORD);
	    getret();
	} else
	    (void) close(fd);
    }
}
Пример #8
0
bool
child(bool wt)
{
	int status;
	int f;

	f = fork();
	if (f == 0) {		/* child */
		settty(NULL);	/* also calls end_screen() */
		/* revoke */
		setgid(getgid());
#ifdef CHDIR
		chdir(getenv("HOME"));
#endif /* CHDIR */
		return (1);
	}
	if (f == -1) {		/* cannot fork */
		pline("Fork failed. Try again.");
		return (0);
	}
	/* fork succeeded; wait for child to exit */
	signal(SIGINT, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);
	wait(&status);
	gettty();
	setftty();
	signal(SIGINT, done1);
#ifdef WIZARD
	if (wizard)
		signal(SIGQUIT, SIG_DFL);
#endif /* WIZARD */
	if (wt)
		getret();
	docrt();
	return (0);
}
Пример #9
0
/* Be careful not to call panic from here! */
void
done(const char *st1)
{

#ifdef WIZARD
	if(wizard && *st1 == 'd'){
		u.uswldtim = 0;
		if(u.uhpmax < 0) u.uhpmax = 100;	/* arbitrary */
		u.uhp = u.uhpmax;
		pline("For some reason you are still alive.");
		flags.move = 0;
		if(multi > 0) multi = 0; else multi = -1;
		flags.botl = 1;
		return;
	}
#endif /* WIZARD */
	signal(SIGINT, done_intr);
	signal(SIGQUIT, done_intr);
	signal(SIGHUP, done_hangup);
	if(*st1 == 'q' && u.uhp < 1){
		st1 = "died";
		killer = "quit while already on Charon's boat";
	}
	if(*st1 == 's') killer = "starvation"; else
	if(*st1 == 'd' && st1[1] == 'r') killer = "drowning"; else
	if(*st1 == 'p') killer = "panic"; else
	if(*st1 == 't') killer = "trickery"; else
	if(!index("bcd", *st1)) killer = st1;
	paybill();
	clearlocks();
	if(flags.toplin == 1) more();
	if(index("bcds", *st1)){
#ifdef WIZARD
	    if(!wizard)
#endif /* WIZARD */
		savebones();
		if(!flags.notombstone)
			outrip();
	}
	if(*st1 == 'c') killer = st1;		/* after outrip() */
	settty(NULL);				/* does a clear_screen() */
	if(!done_stopprint)
		printf("Goodbye %s %s...\n\n", pl_character, plname);
	{ long int tmp;
	  tmp = u.ugold - u.ugold0;
	  if(tmp < 0)
		tmp = 0;
	  if(*st1 == 'd' || *st1 == 'b')
		tmp -= tmp/10;
	  u.urexp += tmp;
	  u.urexp += 50 * maxdlevel;
	  if(maxdlevel > 20)
		u.urexp += 1000*((maxdlevel > 30) ? 10 : maxdlevel - 20);
	}
	if(*st1 == 'e') {
		struct monst *mtmp;
		struct obj *otmp;
		int i;
		unsigned worthlessct = 0;
		boolean has_amulet = FALSE;

		killer = st1;
		keepdogs();
		mtmp = mydogs;
		if(mtmp) {
			if(!done_stopprint) printf("You");
			while(mtmp) {
				if(!done_stopprint)
					printf(" and %s", monnam(mtmp));
				if(mtmp->mtame)
					u.urexp += mtmp->mhp;
				mtmp = mtmp->nmon;
			}
			if(!done_stopprint)
		    printf("\nescaped from the dungeon with %ld points,\n",
			u.urexp);
		} else
		if(!done_stopprint)
		  printf("You escaped from the dungeon with %ld points,\n",
		    u.urexp);
		for(otmp = invent; otmp; otmp = otmp->nobj) {
			if(otmp->olet == GEM_SYM){
				i = otmp->quan*objects[otmp->otyp].g_val;
				if(i == 0) {
					worthlessct += otmp->quan;
					continue;
				}
				u.urexp += i;
				if(!done_stopprint)
				  printf("\t%s (worth %d Zorkmids),\n",
				    doname(otmp), i);
			} else if(otmp->olet == AMULET_SYM) {
				i = (otmp->spe < 0) ? 2 : 5000;
				u.urexp += i;
				if(!done_stopprint)
				  printf("\t%s (worth %d Zorkmids),\n",
				    doname(otmp), i);
				if(otmp->spe >= 0) {
					has_amulet = TRUE;
					killer = "escaped (with amulet)";
				}
			}
		}
		if(worthlessct) if(!done_stopprint)
		  printf("\t%u worthless piece%s of coloured glass,\n",
		  worthlessct, plur(worthlessct));
		if(has_amulet) u.urexp *= 2;
	} else
		if(!done_stopprint)
		  printf("You %s on dungeon level %d with %ld points,\n",
		    st1, dlevel, u.urexp);
	if(!done_stopprint)
	  printf("and %ld piece%s of gold, after %ld move%s.\n",
	    u.ugold, plur(u.ugold), moves, plur(moves));
	if(!done_stopprint)
  printf("You were level %u with a maximum of %d hit points when you %s.\n",
	    u.ulevel, u.uhpmax, st1);
	if(*st1 == 'e' && !done_stopprint){
		getret();	/* all those pieces of coloured glass ... */
		cls();
	}
#ifdef WIZARD
	if(!wizard)
#endif /* WIZARD */
		topten();
	if(done_stopprint) printf("\n\n");
	exit(0);
}
Пример #10
0
void
getlock(void)
{
	int             i = 0, fd;

	(void) fflush(stdout);

	/* we ignore QUIT and INT at this point */
	if (link(HLOCK, LLOCK) == -1) {
		int             errnosv = errno;

		perror(HLOCK);
		printf("Cannot link %s to %s\n", LLOCK, HLOCK);
		switch (errnosv) {
		case ENOENT:
			printf("Perhaps there is no (empty) file %s ?\n", HLOCK);
			break;
		case EACCES:
			printf("It seems you don't have write permission here.\n");
			break;
		case EEXIST:
			printf("(Try again or rm %s.)\n", LLOCK);
			break;
		default:
			printf("I don't know what is wrong.");
		}
		getret();
		error("%s", "");
		/* NOTREACHED */
	}
	regularize(lock);
	glo(0);
	if (locknum > 25)
		locknum = 25;

	do {
		if (locknum)
			lock[0] = 'a' + i++;

		if ((fd = open(lock, O_RDONLY)) == -1) {
			if (errno == ENOENT)
				goto gotlock;	/* no such file */
			perror(lock);
			(void) unlink(LLOCK);
			error("Cannot open %s", lock);
		}
		if (veryold(fd))/* if true, this closes fd and unlinks lock */
			goto gotlock;
		(void) close(fd);
	} while (i < locknum);

	(void) unlink(LLOCK);
	error(locknum ? "Too many hacks running now."
	      : "There is a game in progress under your name.");
gotlock:
	fd = creat(lock, FMASK);
	if (unlink(LLOCK) == -1)
		error("Cannot unlink %s.", LLOCK);
	if (fd == -1) {
		error("cannot creat lock file.");
	} else {
		if (write(fd, &hackpid, sizeof(hackpid))
		    != sizeof(hackpid)) {
			error("cannot write lock");
		}
		if (close(fd) == -1) {
			error("cannot close lock");
		}
	}
}
Пример #11
0
static void
parseoptions(char *opts, bool from_env)
{
	char *op, *op2;
	unsigned num;
	boolean negated;

	if ((op = strchr(opts, ',')) != NULL) {
		*op++ = 0;
		parseoptions(op, from_env);
	}
	if ((op = strchr(opts, ' ')) != NULL) {
		op2 = op;
		while (*op++)
			if (*op != ' ')
				*op2++ = *op;
	}
	if (!*opts)
		return;
	negated = FALSE;
	while ((*opts == '!') || !strncmp(opts, "no", 2)) {
		if (*opts == '!')
			opts++;
		else
			opts += 2;
		negated = !negated;
	}

	if (!strncmp(opts, "standout", 8)) {
		flags.standout = !negated;
		return;
	}

	if (!strncmp(opts, "null", 3)) {
		flags.nonull = negated;
		return;
	}

	if (!strncmp(opts, "tombstone", 4)) {
		flags.notombstone = negated;
		return;
	}

	if (!strncmp(opts, "news", 4)) {
		flags.nonews = negated;
		return;
	}

	if (!strncmp(opts, "time", 4)) {
		flags.time = !negated;
		flags.botl = 1;
		return;
	}

	if (!strncmp(opts, "restonspace", 4)) {
		flags.no_rest_on_space = negated;
		return;
	}

	if (!strncmp(opts, "fixinv", 4)) {
		if (from_env)
			flags.invlet_constant = !negated;
		else
			pline("The fixinvlet option must be in HACKOPTIONS.");
		return;
	}

	if (!strncmp(opts, "male", 4)) {
		flags.female = negated;
		return;
	}
	if (!strncmp(opts, "female", 6)) {
		flags.female = !negated;
		return;
	}

	/* name:string */
	if (!strncmp(opts, "name", 4)) {
		if (!from_env) {
			pline("The playername can be set only from HACKOPTIONS.");
			return;
		}
		op = strchr(opts, ':');
		if (!op)
			goto bad;
		strncpy(plname, op + 1, sizeof(plname) - 1);
		return;
	}

	/* endgame:5t[op] 5a[round] o[wn] */
	if (!strncmp(opts, "endgame", 3)) {
		op = strchr(opts, ':');
		if (!op)
			goto bad;
		op++;
		while (*op) {
			num = 1;
			if (digit(*op)) {
				num = atoi(op);
				while (digit(*op))
					op++;
			} else if (*op == '!') {
				negated = !negated;
				op++;
			}
			switch (*op) {
			case 't':
				flags.end_top = num;
				break;
			case 'a':
				flags.end_around = num;
				break;
			case 'o':
				flags.end_own = !negated;
				break;
			default:
				goto bad;
			}
			while (letter(*++op))
				; /* nothing */
			if (*op == '/')
				op++;
		}
		return;
	}
bad:
	if (!from_env) {
		if (!strncmp(opts, "help", 4)) {
			pline("%s%s%s",
			    "To set options use `HACKOPTIONS=\"<options>\"' in your environment, or ",
			    "give the command 'o' followed by the line `<options>' while playing. ",
			    "Here <options> is a list of <option>s separated by commas.");
			pline("%s%s%s",
			    "Simple (boolean) options are rest_on_space, news, time, ",
			    "null, tombstone, (fe)male. ",
			    "These can be negated by prefixing them with '!' or \"no\".");
			pline("%s",
			    "A string option is name, as in HACKOPTIONS=\"name:Merlin-W\".");
			pline("%s%s%s",
			    "A compound option is endgame; it is followed by a description of what ",
			    "parts of the scorelist you want to see. You might for example say: ",
			    "`endgame:own scores/5 top scores/4 around my score'.");
			return;
		}
		pline("Bad option: %s.", opts);
		pline("Type `o help<cr>' for help.");
		return;
	}
	puts("Bad syntax in HACKOPTIONS.");
	puts("Use for example:");
	puts("HACKOPTIONS=\"!restonspace,notombstone,endgame:own/5 topscorers/4 around me\"");
	getret();
}
Пример #12
0
void
u_init(void)
{
	int i;
	char exper = 'y', pc;

	if (flags.female)	/* should have been set in HACKOPTIONS */
		strlcpy(roles[4], "Cave-woman", sizeof(roles[4]));
	for (i = 0; i < NR_OF_ROLES; i++)
		rolesyms[i] = roles[i][0];
	rolesyms[i] = 0;

	if ((pc = pl_character[0]) != '\0') {
		if ('a' <= pc && pc <= 'z')
			pc += 'A' - 'a';
		if ((i = role_index(pc)) >= 0)
			goto got_suffix;	/* implies experienced */
		printf("\nUnknown role: %c\n", pc);
		pl_character[0] = pc = 0;
	}

	printf("\nAre you an experienced player? [ny] ");

	while (!strchr("ynYN \n\004", (exper = readchar())))
		bell();
	if (exper == '\004')	/* Give him an opportunity to get out */
		end_of_input();
	printf("%c\n", exper);	/* echo */
	if (strchr("Nn \n", exper)) {
		exper = 0;
		goto beginner;
	}

	printf("\nTell me what kind of character you are:\n");
	printf("Are you");
	for (i = 0; i < NR_OF_ROLES; i++) {
		printf(" a %s", roles[i]);
		if (i == 2)	/* %% */
			printf(",\n\t");
		else if (i < NR_OF_ROLES - 2)
			printf(",");
		else if (i == NR_OF_ROLES - 2)
			printf(" or");
	}
	printf("? [%s] ", rolesyms);

	while ((pc = readchar()) != '\0') {
		if ('a' <= pc && pc <= 'z')
			pc += 'A' - 'a';
		if ((i = role_index(pc)) >= 0) {
			printf("%c\n", pc);	/* echo */
			fflush(stdout);		/* should be seen */
			break;
		}
		if (pc == '\n')
			break;
		if (pc == '\004')	/* Give him the opportunity to get out */
			end_of_input();
		bell();
	}
	if (pc == '\n')
		pc = 0;

beginner:
	if (!pc) {
		printf("\nI'll choose a character for you.\n");
		i = rn2(NR_OF_ROLES);
		pc = rolesyms[i];
		printf("This game you will be a%s %s.\n",
		       exper ? "n experienced" : "",
		       roles[i]);
		getret();
		/* give him some feedback in case mklev takes much time */
		putchar('\n');
		fflush(stdout);
	}
	if (exper)
		roles[i][0] = pc;

got_suffix:

	strncpy(pl_character, roles[i], PL_CSIZ - 1);
	pl_character[PL_CSIZ - 1] = 0;
	flags.beginner = 1;
	u = zerou;
	u.usym = '@';
	u.ulevel = 1;
	init_uhunger();
#ifdef QUEST
	u.uhorizon = 6;
#endif /* QUEST */
	uarm = uarm2 = uarmh = uarms = uarmg = uwep = uball = uchain =
		uleft = uright = 0;

	switch (pc) {
	case 'c':
	case 'C':
		Cave_man[2].trquan = 12 + rnd(9) * rnd(9);
		u.uhp = u.uhpmax = 16;
		u.ustr = u.ustrmax = 18;
		ini_inv(Cave_man);
		break;
	case 't':
	case 'T':
		Tourist[3].trquan = 20 + rnd(20);
		u.ugold = u.ugold0 = rnd(1000);
		u.uhp = u.uhpmax = 10;
		u.ustr = u.ustrmax = 8;
		ini_inv(Tourist);
		if (!rn2(25))
			ini_inv(Tinopener);
		break;
	case 'w':
	case 'W':
		for (i = 1; i <= 4; i++)
			if (!rn2(5))
				Wizard[i].trquan += rn2(3) - 1;
		u.uhp = u.uhpmax = 15;
		u.ustr = u.ustrmax = 16;
		ini_inv(Wizard);
		break;
	case 's':
	case 'S':
		Fast = INTRINSIC;
		Stealth = INTRINSIC;
		u.uhp = u.uhpmax = 12;
		u.ustr = u.ustrmax = 10;
		ini_inv(Speleologist);
		if (!rn2(10))
			ini_inv(Tinopener);
		break;
	case 'k':
	case 'K':
		u.uhp = u.uhpmax = 12;
		u.ustr = u.ustrmax = 10;
		ini_inv(Knight);
		break;
	case 'f':
	case 'F':
		u.uhp = u.uhpmax = 14;
		u.ustr = u.ustrmax = 17;
		ini_inv(Fighter);
		break;
	default:		/* impossible */
		u.uhp = u.uhpmax = 12;
		u.ustr = u.ustrmax = 16;
	}
	find_ac();
	if (!rn2(20)) {
		int d1 = rn2(7) - 2;	/* biased variation */
		u.ustr += d1;
		u.ustrmax += d1;
	}

#ifdef WIZARD
	if (wizard)
		wiz_inv();
#endif /* WIZARD */

	/* make sure he can carry all he has - especially for T's */
	while (inv_weight() > 0 && u.ustr < 118)
		u.ustr++, u.ustrmax++;
}
Пример #13
0
void
tty_player_selection()
{
    char pbuf[QBUFSZ];
    char pick, pc;
    int i, linecount;

    linecount = wins[BASE_WINDOW]->cury+1;
    if ((pc = highc(pl_character[0])) != 0) {
	if(index(pl_classes, pc) != (char*) 0)
	    goto got_suffix;
	tty_putstr(BASE_WINDOW, 0, "");
	Sprintf(pbuf, "Unknown role: %c", pc);
	tty_putstr(BASE_WINDOW, 0, pbuf);
	linecount += 2;
	pl_character[0] = pc = 0;
    }

#define PICK_PROMPT "Shall I pick a character for you? [Y, N, or Q(quit)] "
    tty_putstr(BASE_WINDOW, 0, "");
    tty_putstr(BASE_WINDOW, 0, PICK_PROMPT);

    while(!index("yYnNqQ", (pick = readchar())) && !index(quitchars, pick))
	tty_nhbell();

    pick = index(quitchars, pick) ? 'Y' : highc(pick);

    tty_putsym(BASE_WINDOW, (int)strlen(PICK_PROMPT)+1, linecount, pick); /* echo */

    if (pick == 'Q') {
	clearlocks();
	tty_exit_nhwindows(NULL);
	terminate(0);
    }

    if (pick == 'Y') {
	tty_putstr(BASE_WINDOW, 0, "");
	goto beginner;
    }

    tty_curs(BASE_WINDOW, 1, linecount+2);
    tty_putstr(BASE_WINDOW, 0, "What kind of character are you:");
    tty_putstr(BASE_WINDOW, 0, "");
    Sprintf(pbuf, " 	 %s,", An(roles[0]));
    for(i = 1; roles[i]; i++) {
	Sprintf(eos(pbuf), " %s", an(roles[i]));
	if((((i + 1) % 4) == 0) && roles[i+1]) {
	    Strcat(pbuf, ",");
	    tty_putstr(BASE_WINDOW, 0, pbuf);
	    linecount++;
	    Strcpy(pbuf, "        ");
	}
	else if(roles[i+1] && roles[i+2])	Strcat(pbuf, ",");
	if(roles[i+1] && !roles[i+2])	Strcat(pbuf, " or");
    }
    Strcat(pbuf ,"?");
    tty_putstr(BASE_WINDOW, 0, pbuf);
    Strcpy(pbuf, "         [");
    for(i = 0; roles[i]; i++)
	Sprintf(eos(pbuf), "%c,", pl_classes[i]);
    Strcat(pbuf, " or Q] ");
    tty_putstr(BASE_WINDOW, 0, pbuf);
    linecount += 5;

    while ((pc = readchar()) != 0) {
	if ((pc = highc(pc)) == 'Q') {
	    clearlocks();
	    tty_exit_nhwindows(NULL);
	    terminate(0);
	}
	if(index(pl_classes, pc) != (char *) 0) {
	    tty_putsym(BASE_WINDOW, (int)strlen(pbuf)+1, linecount, pc); /* echo */
	    tty_putstr(BASE_WINDOW, 0, "");
	    tty_display_nhwindow(BASE_WINDOW, TRUE);
	    break;
	}
	if(pc == '\n') {
	    pc = 0;
	    break;
	}
	tty_nhbell();
    }

beginner:
    if(!pc) {
	i = rn2((int)strlen(pl_classes));
	pc = pl_classes[i];
	tty_putstr(BASE_WINDOW, 0, "");
	Sprintf(pbuf, "This game you will be %s.", an(roles[i]));
	tty_putstr(BASE_WINDOW, 0, pbuf);
	tty_putstr(BASE_WINDOW, 0, "");
	tty_display_nhwindow(BASE_WINDOW, TRUE);
	getret();
    }
got_suffix:

    tty_clear_nhwindow(BASE_WINDOW);
    pl_character[0] = pc;
    return;
}