view arogue5/command.c @ 315:ad2570b5b21f

Advanced Rogue 5, 7: fix some trading post messages. When attempting to buy an unaffordable object, messages were often of the form "You can't afford that a scroll of hold monster !", because the object description (stored in curpurch) was the same text used in inventory displays. This has been worked around by inspecting the contents of curpurch and using different message templates.
author John "Elwin" Edwards
date Sun, 24 Oct 2021 20:26:21 -0400
parents 32bc72dcbf4f
children c03d0b87211c
line wrap: on
line source

/*
 * Read and execute the user commands
 *
 * Advanced Rogue
 * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
 * All rights reserved.
 *
 * Based on "Rogue: Exploring the Dungeons of Doom"
 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
 * All rights reserved.
 *
 * See the file LICENSE.TXT for full copyright and licensing information.
 */

#include "curses.h"
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>
#include <signal.h>
#include "rogue.h"
#include "mach_dep.h"

void help(void);
void identify(void);
void d_level(void);
void u_level(void);
void shell(void);
void call(bool mark);

/*
 * command:
 *	Process the user commands
 */

void
command(void)
{
    register char ch;
    register int ntimes = 1;			/* Number of player moves */
    static char countch, direction, newcount = FALSE;
    struct linked_list *item;
    bool an_after = FALSE;

    if (on(player, ISHASTE)) {
	ntimes++;
	turns--;	/* correct for later */
    }
    if (on(player, ISSLOW) || on(player, ISDANCE)) {
	if (player.t_turn != TRUE) {
	    ntimes--;
	    turns++;
	    an_after = TRUE;
	}
	player.t_turn ^= TRUE;
    }

    /*
     * Let the daemons start up
     */
    do_daemons(BEFORE);
    do_fuses(BEFORE);
    while (ntimes-- > 0)
    {	
	/* One more tick of the clock. */
	if ((++turns % DAYLENGTH) == 0) {
	    daytime ^= TRUE;
	    if (levtype == OUTSIDE) {
		if (daytime) msg("The sun rises above the horizon");
		else msg("The sun sinks below the horizon");
	    }
	    light(&hero);
	}

	look(after, FALSE);
	if (!running) door_stop = FALSE;
	lastscore = purse;
	wmove(cw, hero.y, hero.x);
	if (!((running || count) && jump)) {
	    status(FALSE);
	    wmove(cw, hero.y, hero.x);
	    draw(cw);			/* Draw screen */
	}
	take = 0;
	after = TRUE;
	/*
	 * Read command or continue run
	 */
	if (!no_command)
	{
	    if (running) {
		/* If in a corridor or maze, if we are at a turn with only one
		 * way to go, turn that way.
		 */
		if ((winat(hero.y, hero.x) == PASSAGE || levtype == MAZELEV) &&
		    off(player, ISHUH) && (off(player, ISBLIND))) {
		    int y, x;
		    if (getdelta(runch, &y, &x) == TRUE) {
			corr_move(y, x);
		    }
		}
	        ch = runch;
	    }
	    else if (count) ch = countch;
	    else
	    {
		ch = readchar();
		if (mpos != 0 && !running)	/* Erase message if its there */
		    msg("");
	    }
	}
	else ch = '.';
	if (no_command)
	{
	    if (--no_command == 0)
		msg("You can move again.");
	}
	else
	{
	    /*
	     * check for prefixes
	     */
	    if (isdigit(ch))
	    {
		count = 0;
		newcount = TRUE;
		while (isdigit(ch))
		{
		    count = count * 10 + (ch - '0');
		    if (count > 255)
			count = 255;
		    ch = readchar();
		}
		countch = ch;
		/*
		 * turn off count for commands which don't make sense
		 * to repeat
		 */
		switch (ch) {
		    case 'h': case 'j': case 'k': case 'l':
		    case 'y': case 'u': case 'b': case 'n':
		    case 'H': case 'J': case 'K': case 'L':
		    case 'Y': case 'U': case 'B': case 'N':
		    case 'q': case 'r': case 's': case 'f':
		    case 't': case 'C': case 'I': case '.':
		    case 'z': case 'p':
			break;
		    default:
			count = 0;
		}
	    }

	    /* Save current direction */
	    if (!running) /* If running, it is already saved */
	    switch (ch) {
		case 'h': case 'j': case 'k': case 'l':
		case 'y': case 'u': case 'b': case 'n':
		case 'H': case 'J': case 'K': case 'L':
		case 'Y': case 'U': case 'B': case 'N':
		    runch = tolower(ch);
	    }

	    /* Perform the action */
	    switch (ch) {
		case 'f':
		    if (!on(player, ISBLIND))
		    {
			door_stop = TRUE;
			firstmove = TRUE;
		    }
		    if (count && !newcount)
			ch = direction;
		    else
			ch = readchar();
		    switch (ch)
		    {
			case 'h': case 'j': case 'k': case 'l':
			case 'y': case 'u': case 'b': case 'n':
			    ch = toupper(ch);
		    }
		    direction = ch;
	    }
	    newcount = FALSE;
	    /*
	     * execute a command
	     */
	    if (count && !running)
		count--;
	    switch (ch)
	    {
		case '!' : shell();
		when 'h' : do_move(0, -1);
		when 'j' : do_move(1, 0);
		when 'k' : do_move(-1, 0);
		when 'l' : do_move(0, 1);
		when 'y' : do_move(-1, -1);
		when 'u' : do_move(-1, 1);
		when 'b' : do_move(1, -1);
		when 'n' : do_move(1, 1);
		when 'H' : do_run('h');
		when 'J' : do_run('j');
		when 'K' : do_run('k');
		when 'L' : do_run('l');
		when 'Y' : do_run('y');
		when 'U' : do_run('u');
		when 'B' : do_run('b');
		when 'N' : do_run('n');
		when 't':
		    if((item=get_item(pack,"throw", ALL)) != NULL && get_dir())
			missile(delta.y, delta.x, item, &player);
		    else
			after = FALSE;
		when 'Q' : after = FALSE; quit(-1);
		when 'i' : after = FALSE; inventory(pack, ALL);
		when 'I' : after = FALSE; picky_inven();
		when 'd' : drop(NULL);
		when 'P' : grab(hero.y, hero.x);
		when 'q' : quaff(-1, 0, TRUE);
		when 'r' : read_scroll(-1, 0, TRUE);
		when 'e' : eat();
		when 'w' : wield();
		when 'W' : wear();
		when 'T' : take_off();
		when 'o' : option();
		when 'c' : call(FALSE);
		when 'm' : call(TRUE);
		when '>' : after = FALSE; d_level();
		when '<' : after = FALSE; u_level();
		when '?' : after = FALSE; help();
		when '/' : after = FALSE; identify();
		when CTRL('U') : use_mm(-1);
		when CTRL('T') :
		    if (get_dir()) steal();
		    else after = FALSE;
		when 'D' : dip_it();
		when 'G' : gsense();
		when '^' : set_trap(&player, hero.y, hero.x);
		when 's' : search(FALSE, FALSE);
		when 'z' : if (!do_zap(TRUE, 0, FALSE))
				after=FALSE;
		when 'p' : pray();
		when 'C' : cast();
		when 'a' :
		    if (get_dir())
			affect();
		    else after = FALSE;
		when 'v' : after = FALSE;
			   msg("Advanced Rogue Version %s.",
				release);
		when CTRL('L') : after = FALSE; clearok(curscr, TRUE);
				touchwin(cw); /* MMMMMMMMMM */
		when CTRL('R') : after = FALSE; msg(huh);
		when 'S' : 
		    after = FALSE;
		    if (save_game())
		    {
			wclear(cw);
			draw(cw);
			endwin();
			printf("\n");
			exit(0);
		    }
		when '.' : ;			/* Rest command */
		when ' ' : after = FALSE;	/* Do Nothing */
#ifdef WIZARD
		when CTRL('P') :
		    after = FALSE;
		    if (wizard)
		    {
			wizard = FALSE;
			trader = 0;
			msg("Not wizard any more");
		    }
		    else
		    {
			if (waswizard || passwd())
			{
			    msg("Welcome, oh mighty wizard.");
			    wizard = waswizard = TRUE;
			}
			else
			    msg("Sorry");
		    }
#endif
		when ESCAPE :	/* Escape */
		    door_stop = FALSE;
		    count = 0;
		    after = FALSE;
		when '#':
		    if (levtype == POSTLEV)		/* buy something */
			buy_it();
		    after = FALSE;
		when '$':
		    if (levtype == POSTLEV)		/* price something */
			price_it();
		    after = FALSE;
		when '%':
		    if (levtype == POSTLEV)		/* sell something */
			sell_it();
		    after = FALSE;
		otherwise :
		    after = FALSE;
#ifdef WIZARD
		    if (wizard) switch (ch)
		    {
			case 'M' : create_obj(TRUE, 0, 0);
			when CTRL('W') : wanderer();
			when CTRL('I') : inventory(lvl_obj, ALL);
			when CTRL('Z') : whatis(NULL);
			when CTRL('D') : level++; new_level(NORMLEV);
			when CTRL('F') : overlay(stdscr,cw);
			when CTRL('X') : overlay(mw,cw);
			when CTRL('J') : teleport();
			when CTRL('E') : sprintf(outstring,"food left: %d\tfood level: %d", 
						food_left, foodlev);
				       msg(outstring);
			when CTRL('A') : activity();
			when CTRL('C') : 
			{
			    int tlev;
			    prbuf[0] = '\0';
			    msg("Which level? ");
			    if(get_str(prbuf, msgw) == NORM) {
				tlev = atoi(prbuf);
				if(tlev < 1) {
				    mpos = 0;
				    msg("Illegal level.");
				}
				else if (tlev > 199) {
					levtype = MAZELEV;
					level = tlev - 200 + 1;
				}
				else if (tlev > 99) {
					levtype = POSTLEV;
					level = tlev - 100 + 1;
				} 
				else {
					levtype = NORMLEV;
					level = tlev;
				}
				new_level(levtype);
			    }
			}
			when CTRL('N') :
			{
			    if ((item=get_item(pack, "charge", STICK)) != NULL){
				(OBJPTR(item))->o_charges=10000;
			    }
			}
			when CTRL('H') :
			{
			    register int i;
			    register struct object *obj;

			    for (i = 0; i < 9; i++)
				raise_level(TRUE);
			    /*
			     * Give the rogue a sword 
			     */
			    if(cur_weapon==NULL || cur_weapon->o_type!=RELIC) {
				item = spec_item(WEAPON, TWOSWORD, 5, 5);
				add_pack(item, TRUE, NULL);
				cur_weapon = OBJPTR(item);
				cur_weapon->o_flags |= (ISKNOW | ISPROT);
			    }
			    /*
			     * And his suit of armor
			     */
			    if (player.t_ctype == C_THIEF)
				item = spec_item(ARMOR, STUDDED_LEATHER, 10, 0);
			    else
				item = spec_item(ARMOR, PLATE_ARMOR, 7, 0);
			    obj = OBJPTR(item);
			    obj->o_flags |= (ISKNOW | ISPROT);
			    obj->o_weight = armors[PLATE_ARMOR].a_wght;
			    cur_armor = obj;
			    add_pack(item, TRUE, NULL);
			    purse += 20000;
			}
			otherwise :
			    msg("Illegal command '%s'.", unctrl(ch));
			    count = 0;
		    }
		    else
#endif
		    {
			msg("Illegal command '%s'.", unctrl(ch));
			count = 0;
			after = FALSE;
		    }
	    }
	    /*
	     * turn off flags if no longer needed
	     */
	    if (!running)
		door_stop = FALSE;
	}
	/*
	 * If he ran into something to take, let him pick it up.
	 * unless its a trading post
	 */
	if (auto_pickup && take != 0 && levtype != POSTLEV)
	    pick_up(take);
	if (!running)
	    door_stop = FALSE;

	/* If after is true, mark an_after as true so that if
	 * we are hasted, the first "after" will be noted.
	 * if after is FALSE then stay in this loop
	 */
	if (after) an_after = TRUE;
	else ntimes++;
    }

    /*
     * Kick off the rest if the daemons and fuses
     */
    if (an_after)
    {
	/* 
	 * If player is infested, take off a hit point 
	 */
	if (on(player, HASINFEST)) {
	    if ((pstats.s_hpt -= infest_dam) <= 0) death(D_INFESTATION);
	}
	/* 
	 * if player has body rot then take off five hits 
	 */
	if (on(player, DOROT)) {
	     if ((pstats.s_hpt -= 5) <= 0) death(D_ROT);
	}
	do_daemons(AFTER);
	do_fuses(AFTER);
	if (!((running || count) && jump)) look(FALSE, FALSE);


    }
    t_free_list(monst_dead);
}

/*
 * quit:
 *	Have player make certain, then exit.
 */

void
quit(int sig)
{
    NOOP(sig);

    /*
     * Reset the signal in case we got here via an interrupt
     */
    if (signal(SIGINT, &quit) != &quit)
	mpos = 0;
    msg("Really quit? ");
    draw(cw);
    if (readchar() == 'y')
    {
	clear();
	move(LINES-1, 0);
	draw(stdscr);
	writelog(pstats.s_exp + (long) purse, CHICKEN, 0);
	score(pstats.s_exp + (long) purse, CHICKEN, 0);
	exit(0);
    }
    else
    {
	signal(SIGINT, quit);
	wmove(cw, 0, 0);
	wclrtoeol(cw);
	status(FALSE);
	draw(cw);
	mpos = 0;
	count = 0;
	running = FALSE;
    }
}

/*
 * bugkill:
 *	killed by a program bug instead of voluntarily.
 */

void
bugkill(int sig)
{
    signal(sig, quit);	/* If we get it again, give up */
    death(D_SIGNAL);	/* Killed by a bug */
}


/*
 * search:
 *	Player gropes about him to find hidden things.
 */

void
search(bool is_thief, bool door_chime)
{
    register int x, y;
    register char ch,	/* The trap or door character */
		 sch,	/* Trap or door character (as seen on screen) */
		 mch;	/* Monster, if a monster is on the trap or door */
    register struct linked_list *item;
    register struct thing *mp; /* Status on surrounding monster */

    /*
     * Look all around the hero, if there is something hidden there,
     * give him a chance to find it.  If its found, display it.
     */
    if (on(player, ISBLIND))
	return;
    for (x = hero.x - 1; x <= hero.x + 1; x++)
	for (y = hero.y - 1; y <= hero.y + 1; y++)
	{
	    if (y==hero.y && x==hero.x)
		continue;

	    /* Mch and ch will be the same unless there is a monster here */
	    mch = CCHAR( winat(y, x) );
	    ch = CCHAR( mvwinch(stdscr, y, x) );
	    sch = CCHAR( mvwinch(cw, y, x) );	/* What's on the screen */

	    if (door_chime == FALSE && isatrap(ch)) {
		    register struct trap *tp;

		    /* Is there a monster on the trap? */
		    if (mch != ch && (item = find_mons(y, x)) != NULL) {
			mp = THINGPTR(item);
			if (sch == mch) sch = mp->t_oldch;
		    }
		    else mp = NULL;

		    /* 
		     * is this one found already?
		     */
		    if (isatrap(sch)) 
			continue;	/* give him chance for other traps */
		    tp = trap_at(y, x);
		    /* 
		     * if the thief set it then don't display it.
		     * if its not a thief he has 50/50 shot
		     */
		    if((tp->tr_flags&ISTHIEFSET) || (!is_thief && rnd(100)>50))
			continue;	/* give him chance for other traps */
		    tp->tr_flags |= ISFOUND;

		    /* Let's update the screen */
		    if (mp != NULL && CCHAR(mvwinch(cw, y, x)) == mch)
			mp->t_oldch = ch; /* Will change when monst moves */
		    else mvwaddch(cw, y, x, ch);

		    count = 0;
		    running = FALSE;
		    msg(tr_name(tp->tr_type));
	    }
	    else if (ch == SECRETDOOR) {
		if (door_chime == TRUE || (!is_thief && rnd(100) < 20)) {
		    /* Is there a monster on the door? */
		    if (mch != ch && (item = find_mons(y, x)) != NULL) {
			mp = THINGPTR(item);

			/* Screen will change when monster moves */
			if (sch == mch) mp->t_oldch = ch;
		    }
		    mvaddch(y, x, DOOR);
		    count = 0;
		}
	    }
	}
}


/*
 * help:
 *	Give single character help, or the whole mess if he wants it
 */

void
help(void)
{
    register struct h_list *strp = helpstr;
#ifdef WIZARD
    struct h_list *wizp = wiz_help;
#endif
    register char helpch;
    register int cnt;

    msg("Character you want help for (* for all): ");
    helpch = readchar();
    mpos = 0;
    /*
     * If its not a *, print the right help string
     * or an error if he typed a funny character.
     */
    if (helpch != '*') {
	wmove(cw, 0, 0);
	while (strp->h_ch) {
	    if (strp->h_ch == helpch) {
		sprintf(outstring,"%s%s", unctrl(strp->h_ch), strp->h_desc);
		msg(outstring);
		return;
	    }
	    strp++;
	}
#ifdef WIZARD
	if (wizard) {
	    while (wizp->h_ch) {
		if (wizp->h_ch == helpch) {
		    sprintf(outstring,"%s%s", unctrl(wizp->h_ch), wizp->h_desc);
		    msg(outstring);
		    return;
		}
		wizp++;
	    }
	}
#endif

	msg("Unknown character '%s'", unctrl(helpch));
	return;
    }
    /*
     * Here we print help for everything.
     * Then wait before we return to command mode
     */
    wclear(hw);
    cnt = 0;
    while (strp->h_ch) {
	mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(strp->h_ch));
	waddstr(hw, strp->h_desc);
	strp++;
	if (++cnt >= 46 && strp->h_ch) {
	    wmove(hw, LINES-1, 0);
	    wprintw(hw, morestr);
	    draw(hw);
	    wait_for(hw,' ');
	    wclear(hw);
	    cnt = 0;
	}
    }
#ifdef WIZARD
    if (wizard) {
	while (wizp->h_ch) {
	    mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(wizp->h_ch));
	    waddstr(hw, wizp->h_desc);
	    wizp++;
	    if (++cnt >= 46 && wizp->h_ch) {
		wmove(hw, LINES-1, 0);
		wprintw(hw, morestr);
		draw(hw);
		wait_for(hw,' ');
		wclear(hw);
		cnt = 0;
	    }
	}
    }
#endif
    wmove(hw, LINES-1, 0);
    wprintw(hw, spacemsg);
    draw(hw);
    wait_for(hw,' ');
    wclear(hw);
    draw(hw);
    wmove(cw, 0, 0);
    wclrtoeol(cw);
    status(FALSE);
    touchwin(cw);
}
/*
 * identify:
 *	Tell the player what a certain thing is.
 */

void
identify(void)
{
    register char ch;
    const char *str;

    msg("What do you want identified? ");
    ch = readchar();
    mpos = 0;
    if (ch == ESCAPE)
    {
	msg("");
	return;
    }
    if (isalpha(ch))
	str = monsters[id_monst(ch)].m_name;
    else switch(ch)
    {
	case '|':
	case '-':
	    str = (levtype == OUTSIDE) ? "boundary of sector"
				       : "wall of a room";
	when GOLD:	str = "gold";
	when STAIRS :	str = (levtype == OUTSIDE) ? "entrance to a dungeon"
						   : "passage leading down";
	when DOOR:	str = "door";
	when FLOOR:	str = (levtype == OUTSIDE) ? "meadow" : "room floor";
	when VPLAYER:	str = "the hero of the game ---> you";
	when IPLAYER:	str = "you (but invisible)";
	when PASSAGE:	str = "passage";
	when POST:	str = "trading post";
	when POOL:	str = (levtype == OUTSIDE) ? "lake"
						   : "a shimmering pool";
	when TRAPDOOR:	str = "trapdoor";
	when ARROWTRAP:	str = "arrow trap";
	when SLEEPTRAP:	str = "sleeping gas trap";
	when BEARTRAP:	str = "bear trap";
	when TELTRAP:	str = "teleport trap";
	when DARTTRAP:	str = "dart trap";
	when MAZETRAP:	str = "entrance to a maze";
	when FOREST:	str = "forest";
	when POTION:	str = "potion";
	when SCROLL:	str = "scroll";
	when FOOD:	str = "food";
	when WEAPON:	str = "weapon";
	when ' ' :	str = "solid rock";
	when ARMOR:	str = "armor";
	when MM:	str = "miscellaneous magic";
	when RING:	str = "ring";
	when STICK:	str = "wand or staff";
	when SECRETDOOR:str = "secret door";
	when RELIC:	str = "artifact";
	otherwise:	str = "unknown character";
    }
    sprintf(outstring,"'%s' : %s", unctrl(ch), str);
    msg(outstring);
}

/*
 * d_level:
 *	He wants to go down a level
 */

void
d_level(void)
{
    bool no_phase=FALSE;


    /* If we are at a top-level trading post, we probably can't go down */
    if (levtype == POSTLEV && level == 0 && rnd(100) < 80) {
	msg("I see no way down.");
	return;
    }

    if (winat(hero.y, hero.x) != STAIRS) {
	if (off(player, CANINWALL) ||	/* Must use stairs if can't phase */
	    (levtype == OUTSIDE && rnd(100) < 90)) {
	    msg("I see no way down.");
	    return;
	}

	/* Is there any dungeon left below? */
	if (level >= nfloors) {
	    msg("There is only solid rock below.");
	    return;
	}

	extinguish(unphase);	/* Using phase to go down gets rid of it */
	no_phase = TRUE;
    }

    /* Is this the bottom? */
    if (level >= nfloors) {
	msg("The stairway only goes up.");
	return;
    }

    level++;
    new_level(NORMLEV);
    if (no_phase) unphase();
}

/*
 * u_level:
 *	He wants to go up a level
 */

void
u_level(void)
{
    bool no_phase = FALSE;
    register struct linked_list *item;
    struct thing *tp;
    struct object *obj;

    if (winat(hero.y, hero.x) != STAIRS) {
	if (off(player, CANINWALL)) {	/* Must use stairs if can't phase */
	    msg("I see no way up.");
	    return;
	}

	extinguish(unphase);
	no_phase = TRUE;
    }

    if (level == 0) {
	msg("The stairway only goes down.");
	return;
    }

    /*
     * does he have the item he was quested to get?
     */
    if (level == 1) {
	for (item = pack; item != NULL; item = next(item)) {
	    obj = OBJPTR(item);
	    if (obj->o_type == RELIC && obj->o_which == quest_item)
		total_winner();
	}
    }
    /*
     * check to see if he trapped a UNIQUE, If he did then put it back
     * in the monster table for next time
     */
    for (item = tlist; item != NULL; item = next(item)) {
	tp = THINGPTR(item);
	if (on(*tp, ISUNIQUE)) 
	    monsters[tp->t_index].m_normal = TRUE;
    }
    t_free_list(tlist);	/* Monsters that fell below are long gone! */

    if (levtype != POSTLEV) level--;
    if (level > 0) new_level(NORMLEV);
    else {
	level = -1;	/* Indicate that we are new to the outside */
	new_level(OUTSIDE); 	/* Leaving the dungeon */
	msg("You emerge into the %s", daytime ? "light" : "night");
    }

    if (no_phase) unphase();
}

/*
 * Let him escape for a while
 */

void
shell(void)
{
    /*
     * Set the terminal back to original mode
     */
    wclear(hw);
    wmove(hw, LINES-1, 0);
    draw(hw);
    endwin();
    in_shell = TRUE;
    fflush(stdout);
    
    md_shellescape();

    printf("%s", retstr);
    fflush(stdout);
    nonl();
    noecho();
    raw();
    keypad(cw,1);
    in_shell = FALSE;
    wait_for(hw,'\n');
    clearok(cw, TRUE);
    touchwin(cw);
    wmove(cw,0,0);
    draw(cw);
}

/*
 * allow a user to call a potion, scroll, or ring something
 */
void
call(bool mark)
{
    register struct object *obj;
    register struct linked_list *item;
    register char **guess = NULL, *elsewise = NULL;
    register bool *know;

    if (mark) item = get_item(pack, "mark", ALL);
    else item = get_item(pack, "call", CALLABLE);
    /*
     * Make certain that it is somethings that we want to wear
     */
    if (item == NULL)
	return;
    obj = OBJPTR(item);
    switch (obj->o_type)
    {
	case RING:
	    guess = r_guess;
	    know = r_know;
	    elsewise = (r_guess[obj->o_which] != NULL ?
			r_guess[obj->o_which] : r_stones[obj->o_which]);
	when POTION:
	    guess = p_guess;
	    know = p_know;
	    elsewise = (p_guess[obj->o_which] != NULL ?
			p_guess[obj->o_which] : p_colors[obj->o_which]);
	when SCROLL:
	    guess = s_guess;
	    know = s_know;
	    elsewise = (s_guess[obj->o_which] != NULL ?
			s_guess[obj->o_which] : s_names[obj->o_which]);
	when STICK:
	    guess = ws_guess;
	    know = ws_know;
	    elsewise = (ws_guess[obj->o_which] != NULL ?
			ws_guess[obj->o_which] : ws_made[obj->o_which]);