view arogue7/command.c @ 306:057c5114e244

Super-Rogue: fix some out-of-range constants. Constants K_ARROW etc., for causes of death other than monsters, are in the 240-255 range. They were often passed to functions taking char, which is usually signed, making the values out of range. The function declarations have been changed to unsigned char, which is also the type used by the scoreboard code.
author John "Elwin" Edwards
date Sat, 17 Apr 2021 15:41:12 -0400
parents e52a8a7ad4c5
children 32bc72dcbf4f
line wrap: on
line source

/*
 * command.c  -  Read and execute the user commands
 *
 * Advanced Rogue
 * Copyright (C) 1984, 1985, 1986 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.
 */

/*
 * Read and execute the user commands
 *
 */

#include "curses.h"
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include "mach_dep.h"
#include "rogue.h"
#ifdef PC7300
#include "sys/window.h"
extern struct uwdata wdata;
#endif

void display(void);
void help(void);
void identify(char ch);
void d_level(void);
void u_level(void);
void shell(void);
void nameit(void);
void namemonst(void);
void count_gold(void);

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

void
command(void)
{
    unsigned char ch;
    struct linked_list *item;
    unsigned char countch, direction, newcount = FALSE;
    int segment = 1;
    int monst_limit, monst_current;

    monst_limit = monst_current = 1;
    while (playing) {
	/*
	 * Let the daemons start up, but only do them once a round
	 * (round = 10 segments).
	 */
	if (segment >= 10) {
	    do_daemons(BEFORE);
	    do_fuses(BEFORE);
	}

	after = TRUE;
	do {
	    /* One more tick of the clock. */
	    if (segment >= 10 && after && (++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);
	    }

	    /*
	     * Don't bother with these updates unless the player's going
	     * to do something.
	     */
	    if (player.t_action == A_NIL && player.t_no_move <= 1) {
		look(after, FALSE);
		lastscore = purse;
		wmove(cw, hero.y, hero.x);
		if (!((running || count) && jump)) {
		    status(FALSE);
		}
	    }

	    /* Draw the screen */
	    if (!((running || count) && jump)) {
		wmove(cw, hero.y, hero.x);
		draw(cw);
	    }

	    after = TRUE;

	    /*
	     * Read command or continue run
	     */
	    if (--player.t_no_move <= 0) {
		take = 0;		/* Nothing here to start with */
		player.t_no_move = 0;	/* Be sure we don't go too negative */
		if (!running) door_stop = FALSE;

		/* Was the player being held? */
		if (player.t_action == A_FREEZE) {
		    player.t_action = A_NIL;
		    msg("You can move again.");
		}

		if (player.t_action != A_NIL) ch = (char) player.t_action;
		else if (running) {
		    char scratch;

		    /* If in a corridor or maze, if we are at a turn with
		     * only one way to go, turn that way.
		     */
		    scratch = CCHAR( winat(hero.y, hero.x) );
		    if ((scratch==PASSAGE||scratch==DOOR||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("");
		}

		/*
		 * 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 C_SEARCH: case '.':
			    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 && player.t_action == A_NIL)
		    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 A_PICKUP:
			player.t_action = A_NIL;
			if (add_pack(NULL, FALSE, NULL)) {
			    char tch;

			    tch = CCHAR( mvwinch(stdscr, hero.y, hero.x) );
			    if (tch != FLOOR && tch != PASSAGE) {
			        player.t_action = A_PICKUP; /*get more */
			        player.t_no_move += 2 * movement(&player);
			    }
			}
		    when A_ATTACK:
			/* Is our attackee still there? */
			if (isalpha(winat(player.t_newpos.y,
					  player.t_newpos.x))) {
			    /* Our friend is still here */
			    player.t_action = A_NIL;
			    fight(&player.t_newpos, cur_weapon, FALSE);
			}
			else {	/* Our monster has moved */
			    player.t_action = A_NIL;
			}
		    when A_THROW:
			if (player.t_action == A_NIL) {
			    item = get_item(pack, "throw", ALL, FALSE, FALSE);
			    if (item != NULL && get_dir(&player.t_newpos)) {
				player.t_action = A_THROW;
				player.t_using = item;
				player.t_no_move = 2 * movement(&player);
			    }
			    else
				after = FALSE;
			}
			else {
			    missile(player.t_newpos.y, player.t_newpos.x, 
				    player.t_using, &player);
			    player.t_action = A_NIL;
			    player.t_using = 0;
			}
		    when 'Q' : after = FALSE; quit(0);
		    when 'i' : after = FALSE; inventory(pack, ALL);
		    when 'I' : after = FALSE; picky_inven();
		    when C_DROP : player.t_action = C_DROP; drop(NULL);
		    when 'P' :
			if (levtype != POSTLEV) {
			    /* We charge 2 movement units per item */
			    player.t_no_move =
				2 * grab(hero.y, hero.x) * movement(&player);
			}
			else {
			    /* Let's quote the wise guy a price */
			    buy_it();
			    after = FALSE;
			}
		    when C_COUNT : count_gold();
		    when C_QUAFF : quaff(-1, 0, 0, TRUE);
		    when C_READ : read_scroll(-1, 0, TRUE);
		    when C_EAT : eat();
		    when C_WIELD : wield();
		    when C_WEAR : wear();
		    when C_TAKEOFF : take_off();
		    when 'o' : option();
		    when CTRL('N') : nameit();
		    when '=' : after = FALSE; display();
		    when 'm' : nameitem(NULL, TRUE);
		    when '>' : after = FALSE; d_level();
		    when '<' : after = FALSE; u_level();
		    when '?' : after = FALSE; help();
		    when '/' : after = FALSE; identify(0);
		    when C_USE : use_mm(-1);
		    when CTRL('T') :
			if (player.t_action == A_NIL) {
			    if (get_dir(&player.t_newpos)) {
				player.t_action = CTRL('T');
				player.t_no_move = 2 * movement(&player);
			    }
			    else
				after = FALSE;
			}
			else {
			    steal();
			    player.t_action = A_NIL;
			}
		    when C_DIP : dip_it();
		    when 'G' :
			if (player.t_action == A_NIL) {
			    player.t_action = 'G';
			    player.t_no_move = movement(&player);
			}
			else {
			    gsense();
			    player.t_action = A_NIL;
			}
		    when C_SETTRAP : set_trap(&player, hero.y, hero.x);
		    when C_SEARCH :
			if (player.t_action == A_NIL) {
			    player.t_action = C_SEARCH;
			    player.t_no_move = 5 * movement(&player);
			}
			else {
			    search(FALSE, FALSE);
			    player.t_action = A_NIL;
			}
		    when C_ZAP : if (!player_zap(0, FALSE))
				    after=FALSE;
		    when C_PRAY : pray();
		    when C_CHANT : chant();
		    when C_CAST : cast();
		    when 'a' :
			if (player.t_action == A_NIL) {
			    if (get_dir(&player.t_newpos)) {
				player.t_action = 'a';
				player.t_no_move = 2 * movement(&player);
			    }
			    else
				after = FALSE;
			}
			else {
			    affect();
			    player.t_action = A_NIL;
			}
		    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();
#ifdef PC7300
			    endhardwin();
#endif
			    exit(0);
			}
		    when '.' :
			player.t_no_move = movement(&player);  /* Rest */
			player.t_action = A_NIL;
		    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') : msg("food left: %d\tfood level: %d", 
						    food_left, foodlev);
			    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('G') :
			    {
				item=get_item(pack,"charge",STICK,FALSE,FALSE);
				if (item != NULL) {
				    (OBJPTR(item))->o_charges=10000;
				}
			    }
			    when CTRL('H') :
			    {
				register int i;
				register struct object *obj;

				for (i = 0; i < 9; i++)
				    raise_level();
				/*
				 * 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);
				    (OBJPTR(item))->o_flags |= (ISKNOW|ISPROT);
				}
				/*
				 * And his suit of armor
				 */
				if (player.t_ctype != C_MONK) {
				    item = spec_item(ARMOR, PLATE_ARMOR, 10, 0);
				    obj = OBJPTR(item);
				    if (player.t_ctype == C_THIEF)
				        obj->o_which = STUDDED_LEATHER;
				    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;
			}
		}

		/*
		 * If he ran into something to take, let him pick it up.
		 * unless it's a trading post
		 */
		if (auto_pickup && take != 0 && levtype != POSTLEV) {
		    /* get ready to pick it up */
		    player.t_action = A_PICKUP;
		    player.t_no_move += 2 * movement(&player);
		}
	    }

	    /* If he was fighting, let's stop (for now) */
	    if (player.t_quiet < 0) player.t_quiet = 0;

	    if (!running)
		door_stop = FALSE;

	    if (after && segment >= 10) {
		/*
		 * Kick off the rest if the daemons and fuses
		 */

		/* 
		 * If player is infested, take off a hit point 
		 */
		if (on(player, HASINFEST)) {
		    if ((pstats.s_hpt -= infest_dam) <= 0) death(D_INFESTATION);
		}

		/*
		 * The eye of Vecna is a constant drain on the player
		 */
		if (cur_relic[EYE_VECNA]) {
		    if ((--pstats.s_hpt) <= 0) death(D_RELIC);
		}

		/* 
		 * 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);
	    }
	} while (after == FALSE);

	/* Make the monsters go */
	if (--monst_current <= 0)
	    monst_current = monst_limit = runners(monst_limit);

#ifdef NEEDLOOK
	/* Shall we take a look? */
	if (player.t_no_move <= 1 &&
	    !((running || count) && jump))
	    look(FALSE, FALSE);
#endif

	if (++segment > 10) segment = 1;
	t_free_list(monst_dead);
    }
}

/*
 * display
 * 	tell the player what is at a certain coordinates assuming
 *	it can be seen.
 */
void
display(void)
{
    coord c;
    struct linked_list *item;
    struct thing *tp;
    int what;

    msg("What do you want to display (* for help)?");
    c = get_coordinates();
    mpos = 0;
    if (!cansee(c.y, c.x)) {
	msg("You can't see what is there.");
	return;
    }
    what = mvwinch(cw, c.y, c.x);
    if (isalpha(what)) {
	item = find_mons(c.y, c.x);
	tp = THINGPTR(item);
	msg("%s", monster_name(tp));
	return;
    }
    if ((item = find_obj(c.y, c.x)) != NULL) {
	msg("%s", inv_name(OBJPTR(item), FALSE));
	return;
    }
    identify(what);
}

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

void
quit(int sig)
{
    /*
     * Reset the signal in case we got here via an interrupt
     */
    if (signal(SIGINT, quit) != quit)
	mpos = 0;
    msg("Really quit? <yes or no> ");
    draw(cw);
    prbuf[0] = '\0';
    if ((get_str(prbuf, msgw) == NORM) && strcmp(prbuf, "yes") == 0) {
	clear();
	move(lines-1, 0);
	draw(stdscr);
	writelog(pstats.s_exp + (long) purse, CHICKEN, 0);
	score(pstats.s_exp + (long) purse, CHICKEN, 0);
#ifdef PC7300
	endhardwin();
#endif
	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 && mvwinch(cw, y, x) == mch)
			mp->t_oldch = ch; /* Will change when monst moves */
		    else mvwaddch(cw, y, x, ch);

		    count = 0;
		    running = FALSE;

		    /* Stop what we were doing */
		    player.t_no_move = movement(&player);
		    player.t_action = A_NIL;
		    player.t_using = NULL;

		    if (fight_flush) md_flushinp();
		    msg(tr_name(tp->tr_type));
	    }
	    else if (ch == SECRETDOOR) {
		if (door_chime == TRUE || (!is_thief && rnd(100) < 20)) {
		    struct room *rp;
		    coord cp;

		    /* 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;
		    /*
		     * if its the entrance to a treasure room, wake it up
		     */
		    cp.y = y;
		    cp.x = x;
		    rp = roomin(&cp);
		    if (rp->r_flags & ISTREAS)
			wake_room(rp);

		    /* Make sure we don't shoot into the room */
		    if (door_chime == FALSE) {
			count = 0;
			running = FALSE;

			/* Stop what we were doing */
			player.t_no_move = movement(&player);
			player.t_action = A_NIL;
			player.t_using = NULL;
		    }
		}
	    }
	}
}


/*
 * 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(msgw, 0, 0);
	while (strp->h_ch) {
	    if (strp->h_ch == helpch) {
		msg("%s%s", unctrl(strp->h_ch), strp->h_desc);
		return;
	    }
	    strp++;
	}
#ifdef WIZARD
	if (wizard) {
	    while (wizp->h_ch) {
		if (wizp->h_ch == helpch) {
		    msg("%s%s", unctrl(wizp->h_ch), wizp->h_desc);
		    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(' ');
	    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(' ');
		wclear(hw);
		cnt = 0;
	    }
	}
    }
#endif
    wmove(hw, lines-1, 0);
    wprintw(hw, spacemsg);
    draw(hw);
    wait_for(' ');
    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(char ch)
{
    register char *str;

    if (ch == 0) {
	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";