[net.sources.games] rogue 5.3 clone source, shell archive enclosed.

tims@zeus.UUCP (Tim Stoehr) (02/26/86)

I recently posted an article asking if anyone would like the source
to a rogue 5.3 look-alike that I wrote.  There was sufficient response
to post it.  I wrote this code out of disgust for the inexcusable number
of bugs that rogue 5.3 is famous for.  I wrote this to eliminate the
bugs as well as to get rid of some other things I didn't care for.
Except for the list of differences below, this game plays remarkably
like 5.3.

Major differences from 5.3

  1.)  No traps or hidden doors/passages.
  2.)  Save game not implemented.
  3.)  ROGUEOPTS not implemented.
  4.)  You cannot throw anything besides weapons.
  5.)  All unidentified scrolls/potions will identify themselves after use.
  6.)  There is only one scroll of identify and it works on anything.
  7.)  Some of the wands are different.
  8.)  ALL rooms, except when blind, light up when you enter, and darken
       when you leave.
  9.)  It's more winnable, you can change the monster characteristics and
       magic-items-per-level numbers to make it more or less difficult.

I would welcome any comments/questions/suggestions.
Mail to tektronix!zeus!tims

#!/bin/sh-----cut here-----cut here-----cut here-----cut here-----
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	macros.h #	monster.h #	move.h #	object.h #	room.h #	door_course.c #	hit.c #	init.c #	inventory.c #	level.c #	main.c #	message.c #	monster.c #	move.c #	object.c #	pack.c #	play.c #	random.c #	room.c #	score.c #	special_hit.c #	throw.c #	use.c #	zap.c 
echo shar: extracting macros.h
cat - << \SHAR_EOF > macros.h
#define swap(x,y) {int t; t = x; x = y; y = t;}
#define two_sort(x,y) if (x > y) {int t; t = x; x = y; y = t;}
#define swap_string(x,y) {char *t; t = x; x = y; y = t;}
SHAR_EOF
echo shar: extracting monster.h
cat - << \SHAR_EOF > monster.h
#define MONSTERS 26

#define HASTED ((unsigned short)001)
#define SLOWED ((unsigned short)002)
#define IS_INVIS ((unsigned short)004)
#define IS_ASLEEP ((unsigned short)010)
#define WAKENS ((unsigned short)020)
#define WANDERS ((unsigned short)040)
#define FLIES ((unsigned short)0100)
#define FLITS ((unsigned short)0200)
#define CAN_GO ((unsigned short)0400)

#define MAXMONSTER 26

#define WAKE_PERCENT 45
#define FLIT_PERCENT 33
#define PARTY_WAKE_PERCENT 75

#define XEROC1 16	/* levels xeroc appears at */
#define XEROC2 25

#define HYPOTHERMIA 1
#define STARVATION 2
#define QUIT 3
#define WIN 4
SHAR_EOF
echo shar: extracting move.h
cat - << \SHAR_EOF > move.h
#define UP 0
#define UPRIGHT 1
#define RIGHT 2
#define RIGHTDOWN 3
#define DOWN 4
#define DOWNLEFT 5
#define LEFT 6
#define LEFTUP 7

#define ROW1 7
#define ROW2 15

#define COL1 26
#define COL2 52

#define MOVED 0
#define MOVE_FAILED -1
#define STOPPED_ON_SOMETHING -2
#define CANCEL '\033'
#define LIST '*'

#define HUNGRY 300
#define WEAK 120
#define FAINT 20
#define STARVE 0

#define MIN_ROW 1
SHAR_EOF
echo shar: extracting object.h
cat - << \SHAR_EOF > object.h
#define BLANK ((unsigned short) 0)
#define ARMOR ((unsigned short) 01)
#define WEAPON ((unsigned short) 02)
#define SCROLL ((unsigned short) 04)
#define POTION ((unsigned short) 010)
#define GOLD ((unsigned short) 020)
#define FOOD ((unsigned short) 040)
#define WAND ((unsigned short) 0100)
#define STAIRS ((unsigned short) 0200)
#define AMULET ((unsigned short) 0400)
#define MONSTER ((unsigned short) 01000)
#define HORWALL ((unsigned short) 02000)
#define VERTWALL ((unsigned short) 04000)
#define DOOR ((unsigned short) 010000)
#define FLOOR ((unsigned short) 020000)
#define TUNNEL ((unsigned short) 040000)
#define UNUSED ((unsigned short) 0100000)
#define IS_OBJECT ((unsigned short) 0777)  /* all object masks or'd together */
#define CAN_PICK_UP ((unsigned short) 0577)

#define LEATHER 0
#define RING 1
#define SCALE 2
#define CHAIN 3
#define BANDED 4
#define SPLINT 5
#define PLATE 6
#define ARMORS 7

#define BOW 0
#define ARROW 1
#define SHURIKEN 2
#define MACE 3
#define LONG_SWORD 4
#define TWO_HANDED_SWORD 5
#define WEAPONS 6

#define MAX_PACK_COUNT 24

#define PROTECT_ARMOR 0
#define HOLD_MONSTER 1
#define ENCHANT_WEAPON 2
#define ENCHANT_ARMOR 3
#define IDENTIFY 4
#define TELEPORT 5
#define SLEEP 6
#define SCARE_MONSTER 7
#define REMOVE_CURSE 8
#define CREATE_MONSTER 9
#define AGGRAVATE_MONSTER 10
#define SCROLLS 11

#define INCREASE_STRENGTH 0
#define RESTORE_STRENGTH 1
#define HEALING 2
#define EXTRA_HEALING 3
#define POISON 4
#define RAISE_LEVEL 5
#define BLINDNESS 6
#define HALLUCINATION 7
#define DETECT_MONSTER 8
#define DETECT_OBJECTS 9
#define CONFUSION 10
#define POTIONS 11

#define TELEPORT_AWAY 0
#define SLOW_MONSTER 1
#define KILL_MONSTER 2
#define INVISIBILITY 3
#define POLYMORPH 4
#define HASTE_MONSTER 5
#define PUT_TO_SLEEP 6
#define DO_NOTHING 7
#define WANDS 8

#define UNIDENTIFIED ((unsigned char) 0)	/* MUST BE ZERO! */
#define IDENTIFIED ((unsigned char) 01)
#define CALLED ((unsigned char) 02)

#define SROWS 24
#define SCOLS 80
#define MAX_TITLE_LENGTH 30
#define MORE "-more-"
#define MAXSYLLABLES 40
#define MAXMETALS 15

#define GOLD_PERCENT 46

struct identify {
	short value;
	char *title;
	char *real;
	unsigned char id_status;
};

struct object {				/* comment is monster meaning */
	unsigned short m_flags;		/* monster flags */
	char *damage;			/* damage it does */
	short quantity;			/* hit points to kill */
	char ichar;			/* 'A' is for aquatar */
	short kill_exp;			/* exp for killing it */
	char is_protected;		/* level starts */
	char is_cursed;			/* level ends */
	char class;			/* chance of hitting you */
	char identified;		/* F%d/Arwarn/Og/If/Mc/Xc */
	unsigned char which_kind;	/* item carry/drop % */
	char row, col;			/* current row,col */
	char damage_enchantment;	/* fly-trap,medusa,etc */
	char quiver;			/* monster slowed toggle */
	char trow, tcol;		/* target row, col */
	char to_hit_enchantment;
	unsigned short what_is;
	char picked_up;
	struct object *next_object;	/* next monster */
};

typedef struct object object;

struct fighter {
	object *armor;
	object *weapon;
	short hp_current;
	short hp_max;
	char strength_current;
	char strength_max;
	object pack;
	int gold;
	char exp;
	int exp_points;
	short row, col;
	char fchar;
	short moves_left;
};

typedef struct fighter fighter;

struct door {
	char other_room;
	char other_row,
	     other_col;
};

typedef struct door door;

struct room {
	char bottom_row, right_col, left_col, top_row;
	char width, height;
	door doors[4];
	char is_room;
};

typedef struct room room;

extern fighter rogue;
extern room rooms[];
unsigned extern short screen[SROWS][SCOLS];
extern object level_objects;

extern struct identify id_scrolls[];
extern struct identify id_potions[];
extern struct identify id_wands[];
extern struct identify id_weapons[];
extern struct identify id_armors[];

extern object monster_tab[];
extern object level_monsters;
SHAR_EOF
echo shar: extracting room.h
cat - << \SHAR_EOF > room.h
#define MAXROOMS 9

#define NO_ROOM -1		/* these two only for doors[] */
#define DEAD_END -2

#define PASSAGE -3		/* current_room value */

#define SCOREFILE "/usr1/tims/SCORE_FILE"

#define AMULET_LEVEL 26
SHAR_EOF
echo shar: extracting door_course.c
cat - << \SHAR_EOF > door_course.c
#include "object.h"
#include "monster.h"
#include "room.h"
#include "move.h"

door_course(monster, entering, row, col)
object *monster;
short entering, row, col;
{
	short trow, tcol, i, j, rn;
	short rrow, ccol;

	monster->row = row;
	monster->col = col;

	if (monster_can_see(monster, rogue.row, rogue.col)) {
		monster->trow = -1;
		return;
	}
	rn = get_room_number(row, col);

	if (entering) {		/* entering room */
		for (i = 0; i < MAXROOMS; i++) {
			if (!rooms[i].is_room || (i == rn)) continue;
			for (j = 0; j < 4; j++) {
				if (rooms[i].doors[j].other_room == rn) {
				monster->trow = rooms[i].doors[j].other_row;
				monster->tcol = rooms[i].doors[j].other_col;
				if ((monster->trow == row) &&
				    (monster->tcol == col)) {
					continue;
				}
				return;
				}
			}
		}
	} else {		/* exiting room */
		rrow = row;
		ccol = col;
		if (get_other_room(rn, &rrow, &ccol)) {
			monster->trow = rrow;
			monster->tcol = ccol;
		} else {
			monster->trow = -1;
		}
	}
}

get_other_room(rn, row, col)
short rn, *row, *col;
{
	short d = -1;

	if ((screen[*row][(*col)-1]&HORWALL)&&(screen[*row][(*col)+1]&HORWALL)){
		if (screen[(*row)+1][*col] & FLOOR) {
			d = UP/2;
		} else {
			d = DOWN/2;
		}
	} else {
		if (screen[*row][(*col)+1] & FLOOR) {
			d = LEFT/2;
		} else {
			d = RIGHT/2;
		}
	}
	if ((d != -1) && (rooms[rn].doors[d].other_room > 0)) {
		*row = rooms[rn].doors[d].other_row;
		*col = rooms[rn].doors[d].other_col;
		return(1);
	}
	return(0);
}
SHAR_EOF
echo shar: extracting hit.c
cat - << \SHAR_EOF > hit.c
#include <curses.h>
#include "object.h"
#include "move.h"
#include "monster.h"

object *fight_monster = 0;
short detect_monster;
char hit_message[80] = "";

extern short halluc, blind, being_held, interrupted;

monster_hit(monster, other)
register object *monster;
char *other;
{
	short damage, hit_chance;
	char *mn, *monster_name();
	float minus;

	if (fight_monster && (monster != fight_monster)) {
		fight_monster = 0;
	}
	monster->trow = -1;
	hit_chance = monster->class;
	hit_chance -= (rogue.exp + rogue.exp);
	if (hit_chance < 0) hit_chance = 0;

	if (!fight_monster) {
		interrupted = 1;
	}

	mn = monster_name(monster);

	if (!rand_percent(hit_chance)) {
		if (!fight_monster) {
			sprintf(hit_message + strlen(hit_message),
			"the %s misses", (other ? other : mn));
			message(hit_message, 0);
			hit_message[0] = 0;
		}
		return;
	}
	if (!fight_monster) {
		sprintf(hit_message + strlen(hit_message), "the %s hit", (other ? other : mn));
		message(hit_message, 0);
		hit_message[0] = 0;
	}

	if (monster->ichar != 'F') {
		damage = get_damage(monster->damage, 1);
		minus = (float) get_armor_class(rogue.armor) * 3.00;
		minus = minus/100.00 * (float) damage;
		damage -= (short) minus;
	} else {
		damage = monster->identified++;
	}
	if (damage > 0) {
		rogue_damage(damage, monster);
	}
	special_hit(monster);
}

rogue_hit(monster)
register object *monster;
{
	short damage, hit_chance;
	char mbuf[80], *monster_name();
	float minus;
	short cx;

	if (check_xeroc(monster)) {
		return;
	}
	hit_chance = get_hit_chance(rogue.weapon);

	if (!rand_percent(hit_chance)) {
		if (!fight_monster) {
			strcpy(hit_message, "you miss  ");
		}
		goto RET;
	}
	damage = get_weapon_damage(rogue.weapon);

	if (monster_damage(monster, damage)) {	/* still alive? */
		if (!fight_monster) {
			strcpy(hit_message, "you hit  ");
		}
	}
RET:	check_orc(monster);
	wake_up(monster);
}

rogue_damage(d, monster)
short d;
object *monster;
{
	if (d >= rogue.hp_current) {
		rogue.hp_current = 0;
		print_stats();
		killed_by(monster, 0);
	}
	rogue.hp_current -= d;
	print_stats();
}

get_damage(ds, r)
char *ds;
{
	register short i = 0, j, n, d, total = 0;

	while (ds[i]) {
		n = get_number(ds+i);
		while (ds[i++] != 'd') ;
		d = get_number(ds+i);
		while ((ds[i] != '/') && ds[i]) i++;

		for (j = 0; j < n; j++) {
			if (r) {
				total += get_rand(1, d);
			} else {
				total += d;
			}
		}
		if (ds[i] == '/') {
			i++;
		}
	}
	return(total);
}

get_w_damage(obj)
object *obj;
{
	char new_damage[12];
	register short to_hit, damage;
	register short i = 0;

	if (!obj) {
		return(-1);
	}
	to_hit = get_number(obj->damage) + obj->to_hit_enchantment;
	while (obj->damage[i++] != 'd') ;
	damage = get_number(obj->damage + i) + obj->damage_enchantment;

	sprintf(new_damage, "%dd%d", to_hit, damage);

	return(get_damage(new_damage, 1));
}

get_number(s)
register char *s;
{
	register short i = 0;
	register short total = 0;

	while ((s[i] >= '0') && (s[i] <= '9')) {
		total = (10 * total) + (s[i] - '0');
		i++;
	}
	return(total);
}

to_hit(obj)
object *obj;
{
	short tohit = 0;
	short i = 0;

	if (!obj) {
		return(1);
	}
	return(get_number(obj->damage) + obj->to_hit_enchantment);
}

damage_for_strength(s)
{
	if (s <= 6) {
		return(s-5);
	}
	if (s <= 14) {
		return(1);
	}
	if (s <= 17) {
		return(3);
	}
	if (s <= 18) {
		return(4);
	}
	if (s <= 20) {
		return(5);
	}
	if (s <= 21) {
		return(6);
	}
	if (s <= 30) {
		return(7);
	}
	return(8);
}

monster_damage(monster, damage)
object *monster;
{
	char *mn, *monster_name();
	short row, col;

	monster->quantity -= damage;

	if (monster->quantity <= 0) {
		row = monster->row;
		col = monster->col;
		remove_mask(row, col, MONSTER);
		mvaddch(row, col, get_room_char(screen[row][col]));
		refresh();

		fight_monster = 0;
		cough_up(monster);
		mn = monster_name(monster);
		sprintf(hit_message+strlen(hit_message), "defeated the %s", mn);
		message(hit_message, 1);
		hit_message[0] = 0;
		add_exp(monster->kill_exp);
		print_stats();
		remove_from_pack(monster, &level_monsters);

		if (monster->ichar == 'F') {
			being_held = 0;
		}
		free(monster);
		return(0);
	}
	return(1);
}

fight(to_the_death)
short to_the_death;
{
	short ch;
	short row, col;
	short first_miss = 1;
	short possible_damage;
	object *object_at();

	while (!is_direction(ch = getchar())) {
		putchar(7);
		fflush(stdout);
		if (first_miss) {
			message("direction?", 0);
			first_miss = 0;
		}
	}
	check_message();
	if (ch == CANCEL) {
		return;
	}
	row = rogue.row; col = rogue.col;
	get_dir_rc(ch, &row, &col);

	if (!(screen[row][col] & MONSTER) || blind || hiding_xeroc(row, col)) {
NM:		message("I see no monster there", 0);
		return;
	}
	fight_monster = object_at(&level_monsters, row, col);
	if ((fight_monster->m_flags & IS_INVIS) && !detect_monster) {
		goto NM;
	}

	possible_damage = ((get_damage(fight_monster->damage, 0) * 2) / 3);

	while (fight_monster) {
		single_move_rogue(ch, 0);
		if (!to_the_death && rogue.hp_current <= possible_damage) {
			fight_monster = 0;
		}
		if (!(screen[row][col] & MONSTER) || interrupted) {
			fight_monster = 0;
		}
	}
}

get_dir_rc(dir, row, col)
short dir;
short *row, *col;
{
	switch(dir) {
	case 'h':
		if (*col > 0) {
			(*col)--;
		}
		break;
	case 'j':
		if (*row < (LINES-2)) {
			(*row)++;
		}
		break;
	case 'k':
		if (*row > MIN_ROW) {
			(*row)--;
		}
		break;
	case 'l':
		if (*col < (COLS-1)) {
			(*col)++;
		}
		break;
	case 'y':
		if ((*row > MIN_ROW) && (*col > 0)) {
			(*row)--;
			(*col)--;
		}
		break;
	case 'u':
		if ((*row > MIN_ROW) && (*col < (COLS-1))) {
			(*row)--;
			(*col)++;
		}
		break;
	case 'n':
		if ((*row < (LINES-2)) && (*col < (COLS-1))) {
			(*row)++;
			(*col)++;
		}
		break;
	case 'b':
		if ((*row < (LINES-2)) && (*col > 0)) {
			(*row)++;
			(*col)--;
		}
		break;
	}
}

get_hit_chance(weapon)
object *weapon;
{
	short hit_chance;

	hit_chance = 40;
	hit_chance += 3 * to_hit(weapon);
	hit_chance += (rogue.exp + rogue.exp);
	if (hit_chance > 100) hit_chance = 100;
	return(hit_chance);
}

get_weapon_damage(weapon)
object *weapon;
{
	short damage;

	damage = get_w_damage(weapon);
	damage += damage_for_strength(rogue.strength_current);
	damage += ((rogue.exp + 1) / 2);
	return(damage);
}
SHAR_EOF
echo shar: extracting init.c
cat - << \SHAR_EOF > init.c
#include <curses.h>
#include "object.h"
#include "room.h"
#include <sgtty.h>
#include <signal.h>

char *player_name;
short cant_int = 0, did_int = 0;

extern char ichars[];
extern short party_room;

init()
{
	char *getlogin();
	short i;
	int tstp(), byebye(), onintr();

	if (!(player_name = getlogin())) {
		fprintf(stderr, "Hey!  Who are you?");
		exit(1);
	}
	printf("Hello %s, just a moment while I dig the dungeon...",
	player_name);
	fflush(stdout);

	initscr();
	for (i = 0; i < 26; i++) {
		ichars[i] = 0;
	}
	start_window();
	signal(SIGTSTP, tstp);
	signal(SIGINT, onintr);
	signal(SIGQUIT, byebye);
	if ((LINES < 24) || (COLS < 80)) {
		clean_up("must be played on 24 x 80 screen");
	}
	LINES = SROWS;

	srandom(getpid());
	shuffle_colors();
	mix_metals();
	make_scroll_titles();

	level_objects.next_object = 0;
	level_monsters.next_object = 0;
	player_init();
}

player_init()
{
	object *get_an_object(), *obj;

	rogue.pack.next_object = 0;

	obj = get_an_object();
	get_food(obj);
	add_to_pack(obj, &rogue.pack, 1);

	obj = get_an_object();		/* initial armor */
	obj->what_is = ARMOR;
	obj->which_kind = RING;
	obj->class = RING+2;
	obj->is_cursed = obj->is_protected = 0;
	obj->damage_enchantment = 1;
	obj->identified = 1;
	add_to_pack(obj, &rogue.pack, 1);
	rogue.armor = obj;

	obj = get_an_object();		/* initial weapons */
	obj->what_is = WEAPON;
	obj->which_kind = MACE;
	get_weapon_thd(obj);
	obj->is_cursed = 0;
	obj->damage = "2d3";
	obj->to_hit_enchantment = obj->damage_enchantment = 1;
	obj->identified = 1;
	add_to_pack(obj, &rogue.pack, 1);
	rogue.weapon = obj;

	obj = get_an_object();
	obj->what_is = WEAPON;
	obj->which_kind = BOW;
	get_weapon_thd(obj);
	obj->is_cursed = 0;
	obj->damage = "1d2";
	obj->to_hit_enchantment = 1;
	obj->damage_enchantment = 0;
	obj->identified = 1;
	add_to_pack(obj, &rogue.pack, 1);

	obj = get_an_object();
	obj->what_is = WEAPON;
	obj->which_kind = ARROW;
	obj->quantity = get_rand(25, 35);
	get_weapon_thd(obj);
	obj->is_cursed = 0;
	obj->damage = "1d2";
	obj->to_hit_enchantment = 0;
	obj->damage_enchantment = 0;
	obj->identified = 1;
	add_to_pack(obj, &rogue.pack, 1);
}

clean_up(estr)
char *estr;
{
	move(LINES-1, 0);
	refresh();
	stop_window();
	printf("\n%s\n", estr);
	exit(0);
}

start_window()
{
	crmode();
	noecho();
	nonl();
	edchars(0);
}

stop_window()
{
	endwin();
	edchars(1);
}

byebye()
{
	clean_up("Okay, bye bye!");
}

onintr()
{
	if (cant_int) {
		did_int = 1;
	} else {
		signal(SIGINT, SIG_IGN);
		check_message();
		message("interrupt", 1);
		signal(SIGINT, onintr);
	}
}

edchars(mode)
short mode;
{
	static short called_before = 0;
	static struct ltchars ltc_orig;
	static struct tchars tc_orig;
	struct ltchars ltc_temp;
	struct tchars tc_temp;

	if (!called_before) {
		called_before = 1;
		ioctl(0, TIOCGETC, &tc_orig);
		ioctl(0, TIOCGLTC, &ltc_orig);
	}
	ltc_temp = ltc_orig;
	tc_temp = tc_orig;

	if (!mode) {
		ltc_temp.t_suspc = ltc_temp.t_dsuspc = ltc_temp.t_rprntc =
		ltc_temp.t_flushc = ltc_temp.t_werasc = ltc_temp.t_lnextc = -1;
	}

	ioctl(0, TIOCSETC, &tc_temp);
	ioctl(0, TIOCSLTC, &ltc_temp);
}
SHAR_EOF
echo shar: extracting inventory.c
cat - << \SHAR_EOF > inventory.c
#include <curses.h>
#include "object.h"
#include "macros.h"
#include "move.h"

char *metals[MAXMETALS] = {
	"steel ",
	"bronze ",
	"gold ",
	"silver ",
	"copper ",
	"nickel ",
	"cobalt ",
	"tin ",
	"iron ",
	"magnesium ",
	"chrome ",
	"carbon ",
	"platinum ",
	"silicon ",
	"titanium "
};

char *syllables[MAXSYLLABLES] = {
	"blech ",
	"foo ",
	"barf ",
	"rech ",
	"bar ",
	"blech ",
	"quo ",
	"bloto ",
	"woh ",
	"caca ",
	"blorp ",
	"erp ",
	"festr ",
	"rot ",
	"slie ",
	"snorf ",
	"iky ",
	"yuky ",
	"ooze ",
	"ah ",
	"bahl ",
	"zep ",
	"druhl ",
	"flem ",
	"behil ",
	"arek ",
	"mep ",
	"zihr ",
	"grit ",
	"kona ",
	"kini ",
	"ichi ",
	"niah ",
	"ogr ",
	"ooh ",
	"ighr ",
	"coph ",
	"swerr ",
	"mihln ",
	"poxi "
};

inventory(pack, mask)
object *pack;
unsigned short mask;
{
	object *obj;
	short i = 0, j, maxlen = 0, n;
	char descriptions[MAX_PACK_COUNT+1][SCOLS];
	short row, col;

	obj = pack->next_object;
	while (obj) {
		if (obj->what_is & mask) {
			descriptions[i][0] = ' ';
			descriptions[i][1] = obj->ichar;
			descriptions[i][2] = ')';
			descriptions[i][3] = ' ';
			get_description(obj, descriptions[i]+4);
			if ((n = strlen(descriptions[i])) > maxlen) {
				maxlen = n;
			}
		i++;
		}
		obj = obj->next_object;
	}
	strcpy(descriptions[i++], " --press space to continue--");
	if (maxlen < 27) maxlen = 27;
	col = COLS - (maxlen + 2);

	for (row = 0; ((row < i) && (row < SROWS)); row++) {
		if (row > 0) {
			for (j = col; j < COLS; j++) {
				descriptions[row-1][j-col] = mvinch(row, j);
			}
			descriptions[row-1][j-col] = 0;
		}
		mvaddstr(row, col, descriptions[row]);
		clrtoeol();
	}
	refresh();
	wait_for_ack(0);

	move(0, 0);
	clrtoeol();

	for (j = 1; j < i; j++) {
		mvaddstr(j, col, descriptions[j-1]);
	}
}

shuffle_colors()
{
	short i, j, k;

	for (i = 0; i <= POTIONS; i++) {
		j = get_rand(0, (POTIONS - 1));
		k = get_rand(0, (POTIONS - 1));
		swap_string(id_potions[j].title, id_potions[k].title);
	}
}

make_scroll_titles()
{
	short i, j, n;
	short sylls, s;

	for (i = 0; i < SCROLLS; i++) {
		sylls = get_rand(2, 5);
		strcpy(id_scrolls[i].title, "'");

		for (j = 0; j < sylls; j++) {
			s = get_rand(1, (MAXSYLLABLES-1));
			strcat(id_scrolls[i].title, syllables[s]);
		}
		n = strlen(id_scrolls[i].title);
		strcpy(id_scrolls[i].title+(n-1), "' ");
	}
}

get_description(obj, description)
object *obj;
char *description;
{
	char *name_of(), *item_name;
	struct identify *id_table, *get_id_table();
	char more_info[32];

	if (obj->what_is == AMULET) {
		strcpy(description, "the amulet of Yendor ");
		return;
	}
	item_name = name_of(obj);

	if (obj->what_is == GOLD) {
		sprintf(description, "%d pieces of gold", obj->quantity);
		return;
	}

	if (obj->what_is != ARMOR) {
		if (obj->quantity == 1) {
			strcpy(description, "a ");
		} else {
			sprintf(description, "%d ", obj->quantity);
		}
	}
	if (obj->what_is == FOOD) {
		strcat(description, item_name);
		strcat(description, "of food ");
		return;
	}
	id_table = get_id_table(obj);

	if (obj->what_is & (WEAPON | ARMOR | WAND)) goto CHECK;

	switch(id_table[obj->which_kind].id_status) {
	case UNIDENTIFIED:
CHECK:		switch(obj->what_is) {
		case SCROLL:
			strcat(description, item_name);
			strcat(description, "entitled: ");
			strcat(description, id_table[obj->which_kind].title);
			break;
		case POTION:
			strcat(description, id_table[obj->which_kind].title);
			strcat(description, item_name);
			break;
		case WAND:
			if (obj->identified ||
			(id_table[obj->which_kind].id_status == IDENTIFIED)) {
				goto ID;
			}
			if (id_table[obj->which_kind].id_status == CALLED) {
				goto CALL;
			}
			strcat(description, id_table[obj->which_kind].title);
			strcat(description, item_name);
			break;
		case ARMOR:
			if (obj->identified) {
				goto ID;
			}
			strcpy(description, id_table[obj->which_kind].title);
			break;
		case WEAPON:
			if (obj->identified) {
				goto ID;
			}
			strcat(description, name_of(obj));
			if (obj == rogue.weapon) {
				strcat(description, "in hand");
			}
			break;
		}
		break;
	case CALLED:
CALL:		switch(obj->what_is) {
		case SCROLL:
		case POTION:
		case WAND:
			strcat(description, item_name);
			strcat(description, "called ");
			strcat(description, id_table[obj->which_kind].title);
			goto MI;
			break;
		}
		break;
	case IDENTIFIED:
ID:		switch(obj->what_is) {
		case SCROLL:
		case POTION:
			strcat(description, item_name);
			strcat(description, id_table[obj->which_kind].real);
			break;
		case WAND:
			strcat(description, item_name);
			strcat(description, id_table[obj->which_kind].real);
MI:			if (obj->identified) {
				sprintf(more_info, "[%d]", obj->class);
				strcat(description, more_info);
			}
			break;
		case ARMOR:
			sprintf(description, "%s%d ",
			((obj->damage_enchantment >= 0) ? "+" : ""),
			obj->damage_enchantment);
			strcat(description, id_table[obj->which_kind].title);
			sprintf(more_info, "[%d] ", get_armor_class(obj));
			strcat(description, more_info);
			if (obj == rogue.armor) {
				strcat(description, "being worn");
			}
			break;
		case WEAPON:
			sprintf(description+strlen(description), "%s%d,%s%d ",
			((obj->to_hit_enchantment >= 0) ? "+" : ""),
			obj->to_hit_enchantment,
			((obj->damage_enchantment >= 0) ? "+" : ""),
			obj->damage_enchantment);
			strcat(description, name_of(obj));
			if (obj == rogue.weapon) {
				strcat(description, "in hand");
			}
			break;
		}
		break;
	}
}

mix_metals()
{
	short i, j, k;

	for (i = 0; i <= MAXMETALS; i++) {
		j = get_rand(0, MAXMETALS-1);
		k = get_rand(0, MAXMETALS-1);
		swap_string(metals[j], metals[k]);
	}
	for (i = 0; i < WANDS; i++) {
		strcpy(id_wands[i].title, metals[i]);
	}
}

single_inventory()
{
	short ch;
	char description[SCOLS];
	object *obj, *get_letter_object();

	ch = get_pack_letter("inventory what? ", IS_OBJECT);

	if (ch == CANCEL) {
		return;
	}
	if (!(obj = get_letter_object(ch))) {
		message("No such item.", 0);
		return;
	}
	strcpy(description, "x) ");
	description[0] = ch;
	get_description(obj, description+3);
	message(description, 0);
}

struct identify *get_id_table(obj)
object *obj;
{
	switch(obj->what_is) {
	case SCROLL:
		return(id_scrolls);
		break;
	case POTION:
		return(id_potions);
		break;
	case WAND:
		return(id_wands);
		break;
	case WEAPON:
		return(id_weapons);
		break;
	case ARMOR:
		return(id_armors);
		break;
	}
}
SHAR_EOF
echo shar: extracting level.c
cat - << \SHAR_EOF > level.c
#include <curses.h>
#include "move.h"
#include "object.h"
#include "room.h"
#include "macros.h"

short current_level = 0, max_level = 1;
extern short current_room;
char *hunger_str = "";
short party_room;
extern short being_held;
extern short detect_monster, has_amulet;

int level_points[] = {
	      10,
	      20,
	      40,
	      80,
	     160,
	     320,
	     640,
	    1300,
	    2600,
	    5200,
	   10000,
	   20000,
	   40000,
	   80000,
	  160000,
	  320000,
	 1000000,
	10000000
};

make_level()
{
	short i;
	short must_exist1, must_exist2;

	party_room = -1;

	if (current_level < 126) {
		current_level++;
	}
	if (current_level > max_level) max_level = current_level;

	if (rand_percent(50)) {
		must_exist1 = 1;
		must_exist2 = 7;
	} else {
		must_exist1 = 3;
		must_exist2 = 5;
	}

	for (i = 0; i < MAXROOMS; i++) {
		make_room(i, must_exist1, must_exist2, 4);
	}

	try_rooms(0, 1, 2);
	try_rooms(0, 3, 6);
	try_rooms(2, 5, 8);
	try_rooms(6, 7, 8);

	for (i = 0; i < (MAXROOMS); i++) {
		connect_rooms(i, i+1, must_exist1, must_exist2, 4);
		if (i < (MAXROOMS-3)) {
			connect_rooms(i, i+3, must_exist1, must_exist2, 4);
		}
	}
	add_dead_ends();

	if (!has_amulet && (current_level >= AMULET_LEVEL)) {
		put_amulet();
	}
}

make_room(n, r1, r2, r3)
{
	short left_col, right_col, top_row, bottom_row;
	short width, height;
	short row_offset, col_offset;
	short i, j;
	short ch;

	switch(n) {
	case 0:
		left_col = 0;
		right_col = COL1-1;
		top_row = MIN_ROW;
		bottom_row = ROW1-1;
		break;
	case 1:
		left_col = COL1+1;
		right_col = COL2-1;
		top_row = MIN_ROW;
		bottom_row = ROW1-1;
		break;
	case 2:
		left_col = COL2+1;
		right_col = COLS-1;
		top_row = MIN_ROW;
		bottom_row = ROW1-1;
		break;
	case 3:
		left_col = 0;
		right_col = COL1-1;
		top_row = ROW1+1;
		bottom_row = ROW2-1;
		break;
	case 4:
		left_col = COL1+1;
		right_col = COL2-1;
		top_row = ROW1+1;
		bottom_row = ROW2-1;
		break;
	case 5:
		left_col = COL2+1;
		right_col = COLS-1;
		top_row = ROW1+1;
		bottom_row = ROW2-1;
		break;
	case 6:
		left_col = 0;
		right_col = COL1-1;
		top_row = ROW2+1;
		bottom_row = LINES - 2;
		break;
	case 7:
		left_col = COL1+1;
		right_col = COL2-1;
		top_row = ROW2+1;
		bottom_row = LINES - 2;
		break;
	case 8:
		left_col = COL2+1;
		right_col = COLS-1;
		top_row = ROW2+1;
		bottom_row = LINES - 2;
		break;
	}

	if ((n != r1) && (n != r2) && (n != r3) && rand_percent(45)) {
		goto END;
	}
	height = get_rand(4, (bottom_row-top_row+1));
	width = get_rand(7, (right_col-left_col-2));

	row_offset = get_rand(0, ((bottom_row-top_row)-height+1));
	col_offset = get_rand(0, ((right_col-left_col)-width+1));

	top_row += row_offset;
	bottom_row = top_row + height - 1;

	left_col += col_offset;
	right_col = left_col + width - 1;

	rooms[n].is_room = 1;

	for (i = top_row; i <= bottom_row; i++) {
		for (j = left_col; j <= right_col; j++) {
			if ((i == top_row) || (i == bottom_row)) {
				ch = HORWALL;
			} else if (((i != top_row) && (i != bottom_row)) &&
			((j == left_col) || (j == right_col))) {
				ch = VERTWALL;
			} else {
				ch = FLOOR;
			}
			add_mask(i, j, ch);
		}
	}
END:	rooms[n].top_row = top_row;
	rooms[n].bottom_row = bottom_row;
	rooms[n].left_col = left_col;
	rooms[n].right_col = right_col;
	rooms[n].height = height;
	rooms[n].width = width;
}

connect_rooms(room1, room2, m1, m2, m3)
{
	if ((room1 != m1) && (room1 != m2) && (room1 != m3) && (room2 != m1) &&
	    (room2 != m2) && (room2 != m3)) {
		if (rand_percent(80)) {
			return;
		}
	}

	if (adjascent(room1, room2)) {
		do_connect(room1, room2);
	}
}

do_connect(room1, room2)
{
	short row1, col1, row2, col2, dir;

	if ((rooms[room1].left_col > rooms[room2].right_col) &&
	(on_same_row(room1, room2))) {
		put_door(room1, LEFT, &row1, &col1);
		put_door(room2, RIGHT, &row2, &col2);
		dir = LEFT;
	} else if ((rooms[room2].left_col > rooms[room1].right_col) &&
	(on_same_row(room1, room2))) {
		put_door(room1, RIGHT, &row1, &col1);
		put_door(room2, LEFT, &row2, &col2);
		dir = RIGHT;
	} else if ((rooms[room1].top_row > rooms[room2].bottom_row) &&
	(on_same_col(room1, room2))) {
		put_door(room1, UP, &row1, &col1);
		put_door(room2, DOWN, &row2, &col2);
		dir = UP;
	} else if ((rooms[room2].top_row > rooms[room1].bottom_row) &&
	(on_same_col(room1, room2))) {
		put_door(room1, DOWN, &row1, &col1);
		put_door(room2, UP, &row2, &col2);
		dir = DOWN;
	} else {
		return;
	}
	draw_simple_passage(row1, col1, row2, col2, dir);
	if (rand_percent(10)) {
		draw_simple_passage(row1, col1, row2, col2, dir);
	}
	rooms[room1].doors[dir/2].other_room = room2;
	rooms[room1].doors[dir/2].other_row = row2;
	rooms[room1].doors[dir/2].other_col = col2;

	rooms[room2].doors[(((dir+4)%8)/2)].other_room = room1;
	rooms[room2].doors[(((dir+4)%8)/2)].other_row = row1;
	rooms[room2].doors[(((dir+4)%8)/2)].other_col = col1;
}

clear_level()
{
	int i, j;

	for (i = 0; i < MAXROOMS; i++) {
		rooms[i].is_room = 0;
		for (j = 0; j < 4; j++) {
			rooms[i].doors[j].other_room = NO_ROOM;
		}
	}
	for (i = 0; i < SROWS; i++) {
		for (j = 0; j < SCOLS; j++) {
			screen[i][j] = BLANK;
		}
	}
	detect_monster = 0;
	being_held = 0;
}

print_stats()
{
	char mbuf[100];

	sprintf(mbuf, "Level: %d  Gold: %3d  Hp: %2d(%d)  Str: %2d(%d)  Arm: %2d  Exp: %d/%d %s", current_level, rogue.gold, rogue.hp_current, rogue.hp_max, rogue.strength_current, rogue.strength_max, get_armor_class(rogue.armor), rogue.exp, rogue.exp_points, hunger_str);
	mvaddstr(LINES-1, 0, mbuf);
	clrtoeol();
	refresh();
}

add_mask(row, col, mask)
int row, col;
unsigned short mask;
{
	if (mask == DOOR) {
		remove_mask(row, col, HORWALL);
		remove_mask(row, col, VERTWALL);
	}
	screen[row][col] |= mask;
/*switch(mask) {
	case FLOOR:
		mvaddch(row, col, '.');
		break;
	case STAIRS:
		mvaddch(row, col, '%');
		break;
	case DOOR:
		mvaddch(row, col, '+');
		break;
	case VERTWALL:
		mvaddch(row, col, '|');
		break;
	case HORWALL:
		mvaddch(row, col, '-');
		break;
	case TUNNEL:
		mvaddch(row, col, '#');
		break;
}*/
}

remove_mask(row, col, mask)
{
	screen[row][col] &= (~mask);
}

adjascent(room1, room2)
{
	if ((!rooms[room1].is_room) || (!rooms[room2].is_room)) {
		return(0);
	}
	two_sort(room1, room2);
	return((on_same_col(room1,room2) || on_same_row(room1, room2))
	&& (((room2 - room1) == 1) || (((room2 - room1) == 3))));
}

put_door(rn, dir, row, col)
short *row, *col;
{
	switch(dir) {
	case UP:
	case DOWN:
		*row = ((dir == UP) ? rooms[rn].top_row :
				     rooms[rn].bottom_row);
		*col = get_rand(rooms[rn].left_col+1,
		rooms[rn].right_col-1);
		break;
	case RIGHT:
	case LEFT:
		*row = get_rand(rooms[rn].top_row+1,
		rooms[rn].bottom_row-1);
		*col = (dir == LEFT) ? rooms[rn].left_col :
				     rooms[rn].right_col;
		break;
	}
	add_mask(*row, *col, DOOR);
}

draw_simple_passage(row1, col1, row2, col2, dir)
{
	short i, middle;

	if ((dir == LEFT) || (dir == RIGHT)) {
		if (col2 < col1) {
			swap(row1, row2);
			swap(col1, col2);
		}
		middle = get_rand(col1+1, col2-1);
		for (i = col1+1; i != middle; i++) {
			add_mask(row1, i, TUNNEL);
		}
		for (i = row1; i != row2; i += (row1 > row2) ? -1 : 1) {
			add_mask(i, middle, TUNNEL);
		}
		for (i = middle; i != col2; i++) {
			add_mask(row2, i, TUNNEL);
		}
	} else {
		if (row2 < row1) {
			swap(row1, row2);
			swap(col1, col2);
		}
		middle = get_rand(row1+1, row2-1);
		for (i = row1+1; i != middle; i++) {
			add_mask(i, col1, TUNNEL);
		}
		for (i = col1; i != col2; i += (col1 > col2) ? -1 : 1) {
			add_mask(middle, i, TUNNEL);
		}
		for (i = middle; i != row2; i++) {
			add_mask(i, col2, TUNNEL);
		}
	}
}

on_same_row(room1, room2)
{
	return((room1 / 3) == (room2 / 3));
}

on_same_col(room1, room2)
{
	return((room1 % 3) == (room2 % 3));
}

add_dead_ends()
{
	short i, j;
	short start;
	short row, col, distance, dir;
	short found;
	short dead_end_percent;

	if (current_level <= 2) return;

	start = get_rand(0, (MAXROOMS-1));
	dead_end_percent = 12 + current_level + current_level;

	for (i = 0; i < MAXROOMS; i++) {
		j = ((start + i) % MAXROOMS);
		if (rooms[j].is_room) continue;
		if (!rand_percent(dead_end_percent)) continue;

		row = rooms[j].top_row + get_rand(0, 6);
		col = rooms[j].left_col + get_rand(0, 19);

		found = 0;
		while (!found) {
			distance = get_rand(8, 20);
			dir = get_rand(0, 3) * 2;

			for (j = 0; (j < distance) && !found; j++) {
				switch(dir) {
				case UP:
					if ((row - 1) >= MIN_ROW) {
						--row;
					}
					break;
				case RIGHT:
					if ((col + 1) < (COLS-1)) {
						++col;
					}
					break;
				case DOWN:
					if ((row + 1) < (LINES-2)) {
						++row;
					}
					break;
				case LEFT:
					if ((col - 1) > 0) {
						--col;
					}
					break;
				}
				if ((screen[row][col] & VERTWALL) ||
				(screen[row][col] & HORWALL) ||
				(screen[row][col] & DOOR)) {
					break_in(row, col, screen[row][col],
					dir);
					found = 1;
				} else {
					add_mask(row, col, TUNNEL);
				}
			}
		}
	}
}

break_in(row, col, ch, dir)
{
	short rn;
	short i, drow, dcol;

	if (ch == DOOR) {
		return;
	}
	rn = get_room_number(row, col);

	if (ch == VERTWALL) {
		if (col == rooms[rn].left_col) {
			if (rooms[rn].doors[LEFT/2].other_room != NO_ROOM) {
				drow = door_row(rn, LEFT);
				for (i = row; i != drow;
				i += (drow < row) ? -1 : 1) {
					add_mask(i, col-1, TUNNEL);
				}
			} else {
				rooms[rn].doors[LEFT/2].other_room = DEAD_END;
				add_mask(row, col, DOOR);
			}
		} else {
			if (rooms[rn].doors[RIGHT/2].other_room != NO_ROOM) {
				drow = door_row(rn, RIGHT);
				for (i = row; i != drow;
				i += (drow < row) ? -1 : 1) {
					add_mask(i, col+1, TUNNEL);
				}
			} else {
				rooms[rn].doors[RIGHT/2].other_room = DEAD_END;
				add_mask(row, col, DOOR);
			}
		}
	} else {		/* break in througt top or bottom --- */
		if (col == rooms[rn].left_col) {
			if (row == MIN_ROW) {
				add_mask(row+1, col-1, TUNNEL);
				break_in(row+1, col, VERTWALL, RIGHT);
			} else if (row == (LINES-2)) {
				add_mask(row-1, col-1, TUNNEL);
				break_in(row-1, col, VERTWALL, RIGHT);
			} else {
				if (row == rooms[rn].top_row) {
					if (dir == RIGHT) {
						add_mask(row-1, col-1, TUNNEL);
						add_mask(row-1, col, TUNNEL);
					}
					add_mask(row-1, col+1, TUNNEL);
					break_in(row, col+1, HORWALL, DOWN);
				} else {
					if (dir == RIGHT) {
						add_mask(row+1, col-1, TUNNEL);
						add_mask(row+1, col, TUNNEL);
					}
					add_mask(row+1, col+1, TUNNEL);
					break_in(row, col+1, HORWALL, UP);
				}
			}
			return;
		} else if (col == rooms[rn].right_col) {
			if (row == MIN_ROW) {
				add_mask(row+1, col+1, TUNNEL);
				break_in(row+1, col, VERTWALL, LEFT);
			} else if (row == (LINES-2)) {
				add_mask(row-1, col+1, TUNNEL);
				break_in(row-1, col, VERTWALL, LEFT);
			} else {
				if (row == rooms[rn].top_row) {
					if (dir == DOWN) {
						add_mask(row-1, col+1, TUNNEL);
						add_mask(row, col+1, TUNNEL);
					}
					add_mask(row+1, col+1, TUNNEL);
					break_in(row+1, col, VERTWALL, LEFT);
				} else {
					if (dir == UP) {
						add_mask(row+1, col+1, TUNNEL);
						add_mask(row, col+1, TUNNEL);
					}
					add_mask(row-1, col+1, TUNNEL);
					break_in(row-1, col, VERTWALL, LEFT);
				}
			}
			return;
		}
		if (row == rooms[rn].top_row) {
			if (rooms[rn].doors[UP/2].other_room != NO_ROOM) {
				dcol = door_col(rn, UP);
				for (i = col; i != dcol;
				i += (dcol < col) ? -1 : 1) {
					add_mask(row-1, i, TUNNEL);
				}
			} else {
				rooms[rn].doors[UP/2].other_room = DEAD_END;
				add_mask(row, col, DOOR);
			}
		} else {
			if (rooms[rn].doors[DOWN/2].other_room != NO_ROOM) {
				dcol = door_col(rn, DOWN);
				for (i = col; i != dcol;
				i += (dcol < col) ? -1 : 1) {
					add_mask(row+1, i, TUNNEL);
				}
			} else {
				rooms[rn].doors[DOWN/2].other_room = DEAD_END;
				add_mask(row, col, DOOR);
			}
		}
	}
	return(0);
}

door_row(rn, dir)
{
	short i, col, row;

	if (rooms[rn].doors[dir/2].other_room == NO_ROOM) {
		return(-1);
	}

	row = rooms[rn].top_row;

	switch(dir) {
	case LEFT:
		col = rooms[rn].left_col;
		for (i = row; !(screen[i][col] & DOOR); i++) ;
		break;
	case RIGHT:
		col = rooms[rn].right_col;
		for (i = row; !(screen[i][col] & DOOR); i++) ;
		break;
	}
	return(i);
}

door_col(rn, dir)
{
	short i, col, row;

	if (rooms[rn].doors[dir/2].other_room == NO_ROOM) {
		return(-1);
	}

	col = rooms[rn].left_col;

	switch(dir) {
	case UP:
		row = rooms[rn].top_row;
		for (i = col; !(screen[row][i] & DOOR); i++) ;
		break;
	case DOWN:
		row = rooms[rn].bottom_row;
		for (i = col; !(screen[row][i] & DOOR); i++) ;
		break;
	}
	return(i);
}

put_player()
{
	for (;;) {
		get_rand_row_col(&rogue.row, &rogue.col, (FLOOR | IS_OBJECT));

		current_room = get_room_number(rogue.row, rogue.col);

		if (current_room != party_room) {
			break;
		}
	}
}

check_down()
{
	if (screen[rogue.row][rogue.col] & STAIRS) {
		return(1);
	}
	message("I see no way down", 0);
	return(0);
}

check_up()
{
	if (!(screen[rogue.row][rogue.col] & STAIRS)) {
		message("I see no way up", 0);
		return(0);
	}
	if (!has_amulet) {
		message("your way is magically blocked", 0);
		return(0);
	}
	if (current_level == 1) {
		win();
	} else {
		current_level -= 2;
		return(1);
	}
}

add_exp(e)
{
	char mbuf[40];
	short new_exp;
	short i, hp;

	rogue.exp_points += e;

	if (rogue.exp_points >= level_points[rogue.exp-1]) {
		new_exp = get_exp_level(rogue.exp_points);
		for (i = rogue.exp+1; i <= new_exp; i++) {
			sprintf(mbuf, "welcome to level %d", i);
			message(mbuf, 0);
			hp = get_rand(3, 10);
			rogue.hp_current += hp;
			rogue.hp_max += hp;
			print_stats();
		}
		rogue.exp = new_exp;
	}
	print_stats();
}

get_exp_level(e)
{
	short i;

	for (i = 0; i < 50; i++) {
		if (level_points[i] > e) {
			break;
		}
	}
	return(i+1);
}

try_rooms(r1, r2, r3)
{
	if (rooms[r1].is_room && !rooms[r2].is_room && rooms[r3].is_room) {
		if (rand_percent(75)) {
			do_connect(r1, r3);
		}
	}
}
SHAR_EOF
echo shar: extracting main.c
cat - << \SHAR_EOF > main.c
#include <curses.h>
#include "object.h"

main()
{
	init();

	for (;;) {
		clear_level();
		make_level();
		put_objects();
		put_stairs();
		put_monsters();
		put_player();
		light_up_room();
		print_stats();
		play_level();
		free_stuff(&level_objects);
		free_stuff(&level_monsters);
		clear();
	}
}
SHAR_EOF
echo shar: extracting message.c
cat - << \SHAR_EOF > message.c
#include <curses.h>
#include "object.h"
#include "move.h"

char message_cleared = 1;
char message_line[SCOLS] = "";
short message_col;

extern short cant_int, did_int;

extern short interrupted;

message(msg, intrpt)
char *msg;
short intrpt;
{
	if (intrpt) {
		interrupted = 1;
	}
	cant_int = 1;
	slurp();

	if (!message_cleared) {
		mvaddstr(MIN_ROW-1, message_col, MORE);
		refresh();
		wait_for_ack(0);
		check_message();
	}
	strcpy(message_line, msg);
	mvaddstr(MIN_ROW-1, 0, msg);
	addch(' ');
	refresh();
	message_cleared = 0;
	message_col = strlen(msg);

	if (did_int) {
		onintr();
	}
	cant_int = 0;
}

remessage()
{
	if (message_line[0]) {
		message(message_line, 0);
	}
}

check_message()
{
	register i;

	if (message_cleared) {
		return;
	}
	move(MIN_ROW-1, 0);
	clrtoeol();
	move(rogue.row, rogue.col);
	refresh();
	message_cleared = 1;
}

get_input_line(buf, if_cancelled)
char *buf;
char *if_cancelled;
{
	short ch;
	short i = 0;

	message("call it:", 0);

	while (((ch = getchar()) != '\r') && (ch != CANCEL)) {
		if ((ch >= ' ') && (ch <= '~') && (i < MAX_TITLE_LENGTH-2)) {
			buf[i++] = ch;
			addch(ch);
		}
		if ((ch == '\b') && (i > 0)) {
			mvaddch(0, --i + 9, ' ');
			move(MIN_ROW-1, i+9);
		}
		refresh();
	}
	check_message();
	if (ch == CANCEL) {
		if (if_cancelled) {
			message(if_cancelled, 0);
		}
		return(0);
	}
	buf[i++] = ' ';
	buf[i] = 0;
	return(1);
}

slurp()
{
	long ln;
	short i, n;

	do {
		ioctl(0, FIONREAD, &ln);
		n = stdin->_cnt + ln;

		for (i = 0; i < ln; i++) getchar();
	} while (ln > 0L);
}
SHAR_EOF
echo shar: extracting monster.c
cat - << \SHAR_EOF > monster.c
#include <curses.h>
#include "monster.h"
#include "object.h"
#include "room.h"
#include "move.h"

extern short current_level;
extern short current_room, party_room;
extern short detect_monster;
extern short blind, halluc;

char *monster_names[] = {
	"aquatar",
	"bat",
	"centaur",
	"dragon",
	"emu",
	"venus fly-trap",
	"griffin",
	"hobgoblin",
	"ice monster",
	"jabberwock",
	"kestrel",
	"leprechaun",
	"medusa",
	"nymph",
	"orc",
	"phantom",
	"quasit",
	"rattlesnake",
	"snake",
	"troll",
	"black unicorn",
	"vampire",
	"wraith",
	"xeroc",
	"yeti",
	"zombie"
};

object monster_tab[MONSTERS] = {
	{(IS_ASLEEP|WAKENS|WANDERS),"0d0",25,'A',20,9,18,100,0,0},
	{(IS_ASLEEP|WANDERS|FLITS),"1d3",10,'B',2,1,8,60,0,0},
	{(IS_ASLEEP|WANDERS),"3d3/2d5",30,'C',15,7,16,85,0,10},
	{(IS_ASLEEP|WAKENS),"4d5/3d9",128,'D',5000,21,126,100,0,90},
	{(IS_ASLEEP|WAKENS),"1d3",11,'E',2,1,7,65,0,0},
	{(0),"0d0",32,'F',91,12,126,80,0,0},
	{(IS_ASLEEP|WAKENS|WANDERS|FLIES),"5d4/4d5",92,'G',2000,20,126,85,0,10},
	{(IS_ASLEEP|WAKENS|WANDERS),"1d3/1d3",17,'H',3,1,10,67,0,0},
	{(IS_ASLEEP),"0d0",15,'I',5,2,11,68,0,0},
	{(IS_ASLEEP|WANDERS),"3d10/3d4",125,'J',3000,21,126,100,0,0},
	{(IS_ASLEEP|WAKENS|WANDERS|FLIES),"1d4",10,'K',2,1,6,60,0,0},
	{(IS_ASLEEP),"0d0",25,'L',18,6,16,75,0,0},
	{(IS_ASLEEP|WAKENS|WANDERS),"4d4/3d7",92,'M',250,18,126,85,0,25},
	{(IS_ASLEEP),"0d0",25,'N',37,10,19,75,0,100},
	{(IS_ASLEEP|WANDERS|WAKENS),"1d6",25,'O',5,4,13,70,0,10},
	{(IS_ASLEEP|IS_INVIS|WANDERS|FLITS),"5d4",76,'P',120,15,23,80,0,50},
	{(IS_ASLEEP|WAKENS|WANDERS),"3d5",30,'Q',20,8,17,78,0,20},
	{(IS_ASLEEP|WAKENS|WANDERS),"2d5",19,'R',10,3,12,70,0,0},
	{(IS_ASLEEP|WAKENS|WANDERS),"1d3",8,'S',2,1,9,50,0,0},
	{(IS_ASLEEP|WAKENS|WANDERS),"4d6",64,'T',125,13,22,75,0,33},
	{(IS_ASLEEP|WAKENS|WANDERS),"4d9",88,'U',200,17,26,85,0,33},
	{(IS_ASLEEP|WAKENS|WANDERS),"1d14",40,'V',350,19,126,85,0,18},
	{(IS_ASLEEP|WANDERS),"2d7",42,'W',55,14,23,75,0,0},
	{(IS_ASLEEP),"4d6",42,'X',110,XEROC1,XEROC2,75,0,0},
	{(IS_ASLEEP|WANDERS),"3d6",33,'Y',50,11,20,80,0,20},
	{(IS_ASLEEP|WAKENS|WANDERS),"1d7",20,'Z',8,5,14,69,0,0}
};

object level_monsters;

put_monsters()
{
	short i;
	short n;
	object *monster, *get_rand_monster();

	n = get_rand(3, 7);

	for (i = 0; i < n; i++) {
		monster = get_rand_monster();
		if ((monster->m_flags & WANDERS) && rand_percent(50)) {
			wake_up(monster);
		}
		put_monster_rand_location(monster);
		add_to_pack(monster, &level_monsters, 0);
	}
}

object *get_rand_monster()
{
	object *monster, *get_an_object();
	short mn;

	monster = get_an_object();

	for (;;) {
		mn = get_rand(0, MAXMONSTER-1);
		if ((current_level >= monster_tab[mn].is_protected) &&
		(current_level <= monster_tab[mn].is_cursed)) {
			break;
		}
	}
	*monster = monster_tab[mn];
	monster->what_is = MONSTER;
	if (monster->ichar == 'X') {
		monster->identified = get_rand_obj_char();
	}
	if (current_level > (AMULET_LEVEL + 2)) {
		monster->m_flags |= HASTED;
	}
	monster->trow = -1;
	return(monster);
}

move_monsters()
{
	object *monster;
	short flew;

	monster = level_monsters.next_object;

	while (monster) {
		if (monster->m_flags & HASTED) {
			mv_monster(monster, rogue.row, rogue.col);
		} else if (monster->m_flags & SLOWED) {
			monster->quiver = !monster->quiver;
			if (monster->quiver) {
				goto NM;
			}
		}
		flew = 0;
		if ((monster->m_flags & FLIES) &&
		     !monster_can_go(monster, rogue.row, rogue.col)) {
			flew = 1;
			mv_monster(monster, rogue.row, rogue.col);
		}
		if (!flew || !monster_can_go(monster, rogue.row, rogue.col)) {
			mv_monster(monster, rogue.row, rogue.col);
		}
NM:		monster = monster->next_object;
	}
}

fill_room_with_monsters(rn, n)
{
	short i;
	short row, col;
	object *monster, *get_rand_monster();

	n += n/2;

	for (i = 0; i < n; i++) {
		if (no_room_for_monster(rn)) break;
		do {
			row = get_rand(rooms[rn].top_row+1,
				       rooms[rn].bottom_row-1);
			col = get_rand(rooms[rn].left_col+1,
				       rooms[rn].right_col-1);
		} while (screen[row][col] & MONSTER);

		monster = get_rand_monster();
		put_monster_at(row, col, monster);
	}
}

get_monster_char_row_col(row, col)
{
	object *monster, *object_at();
	short retval;

	monster = object_at(&level_monsters, row, col);
	if ((!detect_monster && (monster->m_flags & IS_INVIS)) || blind) {
		retval = get_room_char((screen[row][col] & ~MONSTER),row,col);
		return(retval);
	}
	if ((monster->ichar == 'X') && monster->identified) {
		return(monster->identified);
	}
	return(monster->ichar);
}

get_monster_char(monster)
object *monster;
{
	short retval;

	if ((!detect_monster && (monster->m_flags & IS_INVIS)) || blind) {
		retval = get_room_char((screen[monster->row][monster->col] & ~MONSTER), monster->row, monster->col);
		return(retval);
	}
	if ((monster->ichar == 'X') && monster->identified) {
		return(monster->identified);
	}
	return(monster->ichar);
}

mv_monster(monster, row, col)
register object *monster;
short row, col;
{
	short i, n;
	char tried[6];

	if (monster->m_flags & IS_ASLEEP) {
		if ((monster->m_flags & WAKENS) &&
		     rogue_is_around(monster->row, monster->col) &&
		     rand_percent(WAKE_PERCENT)) {
			wake_up(monster);
		}
		return;
	}
	if ((monster->m_flags & FLITS) && flit(monster)) {
		return;
	}
	if ((monster->ichar == 'F') &&
	    !monster_can_go(monster, rogue.row, rogue.col)) {
		return;
	}
	if ((monster->ichar == 'I') && monster->identified) {
		return;
	}
	if ((monster->ichar == 'M') && m_confuse(monster)) {
		return;
	}
	if (monster_can_go(monster, rogue.row, rogue.col)) {
		monster_hit(monster, 0);
		return;
	}
	if ((monster->ichar == 'D') && flame_broil(monster)) {
		return;
	}
	if ((monster->ichar == 'O') && orc_gold(monster)) {
		return;
	}
	if ((monster->trow == monster->row) &&
		   (monster->tcol == monster->col)) {
		monster->trow = -1;
	} else if (monster->trow != -1) {
		row = monster->trow;
		col = monster->tcol;
	}
	if (monster->row > row) {
		row = monster->row - 1;
	} else if (monster->row < row) {
		row = monster->row + 1;
	}
	if ((screen[row][monster->col] & DOOR) &&
	     mtry(monster, row, monster->col)) {
		return;
	}
	if (monster->col > col) {
		col = monster->col - 1;
	} else if (monster->col < col) {
		col = monster->col + 1;
	}
	if ((screen[monster->row][col] & DOOR) &&
	     mtry(monster, monster->row, col)) {
		return;
	}
	if (mtry(monster, row, col)) {
		return;
	}
	for (i = 0; i <= 5; i++) tried[i] = 0;

	for (i = 0; i < 6; i++) {
NEXT_TRY:	n = get_rand(0, 5);
		switch(n) {
		case 0:
			if (!tried[n] && mtry(monster, row, monster->col-1)) {
				return;
			}
			break;
		case 1:
			if (!tried[n] && mtry(monster, row, monster->col)) {
				return;
			}
			break;
		case 2:
			if (!tried[n] && mtry(monster, row, monster->col+1)) {
				return;
			}
			break;
		case 3:
			if (!tried[n] && mtry(monster, monster->row-1, col)) {
				return;
			}
			break;
		case 4:
			if (!tried[n] && mtry(monster, monster->row, col)) {
				return;
			}
			break;
		case 5:
			if (!tried[n] && mtry(monster, monster->row+1, col)) {
				return;
			}
			break;
		}
		if (!tried[n]) {
			tried[n] = 1;
		} else {
			goto NEXT_TRY;
		}
	}
}

mtry(monster, row, col)
register object *monster;
register short row, col;
{
	if (monster_can_go(monster, row, col)) {
		move_monster_to(monster, row, col);
		return(1);
	}
	return(0);
}

move_monster_to(monster, row, col)
register object *monster;
register short row, col;
{
	short c;

	add_mask(row, col, MONSTER);
	remove_mask(monster->row, monster->col, MONSTER);

	c = mvinch(monster->row, monster->col);

	if ((c >= 'A') && (c <= 'Z')) {
		mvaddch(monster->row, monster->col,
		get_room_char(screen[monster->row][monster->col],
		monster->row, monster->col));
	}
	if (!blind && (detect_monster || can_see(row, col))) {
		if ((!(monster->m_flags & IS_INVIS) || detect_monster)) {
			mvaddch(row, col, get_monster_char(monster));
		}
	}
	if ((screen[row][col] & DOOR) &&
	    (get_room_number(row, col) != current_room) &&
	    (screen[monster->row][monster->col] == FLOOR)) {
		if (!blind)
			mvaddch(monster->row, monster->col, ' ');
	}
	if (screen[row][col] & DOOR) {
			door_course(monster,
			(screen[monster->row][monster->col] & TUNNEL),
			row, col);
	} else {
		monster->row = row;
		monster->col = col;
	}
}

monster_can_go(monster, row, col)
register object *monster;
register short row, col;
{
	object *obj, *object_at();
	short dr, dc;

	dr = monster->row - row;	/* check if move distance > 1 */
	if ((dr >= 2) || (dr <= -2)) return(0);
	dc = monster->col - col;
	if ((dc >= 2) || (dc <= -2)) return(0);

	if ((!screen[monster->row][col]) || (!screen[row][monster->col])) {
		return(0);
	}

	if ((!is_passable(row, col)) || (screen[row][col] & MONSTER)) {
		return(0);
	}
	if ((monster->row!=row)&&(monster->col!=col)&&((screen[row][col]&DOOR)
	|| (screen[monster->row][monster->col]&DOOR))) {
		return(0);
	}
	if (!(monster->m_flags & FLITS) && !(monster->m_flags & CAN_GO) &&
	     (monster->trow == -1)) {
	if ((monster->row < rogue.row) && (row < monster->row)) return(0);
	if ((monster->row > rogue.row) && (row > monster->row)) return(0);
	if ((monster->col < rogue.col) && (col < monster->col)) return(0);
	if ((monster->col > rogue.col) && (col > monster->col)) return(0);
	}

	if (screen[row][col] & SCROLL) {
		obj = object_at(&level_objects, row, col);
		if (obj->which_kind == SCARE_MONSTER) {
			return(0);
		}
	}

	return(1);
}

wake_up(monster)
object *monster;
{
	monster->m_flags &= (~IS_ASLEEP);
}

wake_room(rn, entering, row, col)
{
	object *monster;
	short wake_percent;

	wake_percent = (rn == party_room) ? PARTY_WAKE_PERCENT : WAKE_PERCENT;

	monster = level_monsters.next_object;

	while (monster) {
		if (((monster->m_flags & WAKENS) || (rn == party_room)) &&
		   (rn == get_room_number(monster->row, monster->col))) {
			if ((monster->ichar != 'X') && (rn == party_room)) {
				monster->m_flags |= WAKENS;
			}
			if (entering) {
				monster->trow = -1;
			} else {
				monster->trow = row;
				monster->tcol = col;
			}
			if (rand_percent(wake_percent) &&
			   (monster->m_flags & WAKENS)) {
				if (monster->ichar != 'X') {
					wake_up(monster);
				}
			}
		}
		monster = monster->next_object;
	}
}

char *monster_name(monster)
object *monster;
{
	short ch;

	if (blind || ((monster->m_flags & IS_INVIS) && !detect_monster)) {
		return("something");
	}
	if (halluc) {
		ch = get_rand('A', 'Z') - 'A';
		return(monster_names[ch]);
	}
	ch = monster->ichar - 'A';
	return(monster_names[ch]);
}

rogue_is_around(row, col)
{
	short rdif, cdif, retval;

	rdif = row - rogue.row;
	cdif = col - rogue.col;

	retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
	return(retval);
}

start_wanderer()
{
	object *monster, *get_rand_monster();
	short row, col, i;
ANOTHER:
	monster = get_rand_monster();
	if ((!(monster->m_flags & WAKENS)) &&
	    (!(monster->m_flags & WANDERS))) {
		free(monster);
		goto ANOTHER;
	}
	wake_up(monster);

	for (i = 0; i < 12; i++) {
		get_rand_row_col(&row, &col, (FLOOR | TUNNEL | IS_OBJECT));
		if (!can_see(row, col)) {
			put_monster_at(row, col, monster);
			return;
		}
	}
}

show_monsters()
{
	object *monster;

	if (blind) return;

	monster = level_monsters.next_object;

	while (monster) {
		mvaddch(monster->row, monster->col, monster->ichar);
		if (monster->ichar == 'X') {
			monster->identified = 0;
		}
		monster = monster->next_object;
	}
}

create_monster()
{
	short row, col;
	short i, j, inc1, inc2;
	short found = 0;
	object *monster;

	inc1 = get_rand(0, 1) ? 1 : -1;
	inc2 = get_rand(0, 1) ? 1 : -1;

	for (i = inc1; i != (2 * -inc1); i -= inc1) {
		for (j = inc2; j != (2 * -inc2); j -= inc2) {
			if (!i && !j) continue;
			row = rogue.row + i;
			col = rogue.col + j;
			if ((row < MIN_ROW) || (row > (LINES-2)) ||
			    (col < 0) || (col > (COLS-1))) {
				continue;
			}
			if ((!(screen[row][col] & MONSTER)) &&
			      (screen[row][col] & (FLOOR|TUNNEL|STAIRS))) {
				found = 1;
				goto FOUND;
			}
		}
	}
FOUND:
	if (found) {
		monster = get_rand_monster();
		put_monster_at(row, col, monster);
		mvaddch(row, col, get_monster_char(monster));
		if (monster->m_flags & WANDERS) {
			wake_up(monster);
		}
	} else {
		message("you hear a faint cry of anguish in the distance",0);
	}
}

put_monster_at(row, col, monster)
object *monster;
{
		monster->row = row; monster->col = col;
		add_mask(row, col, MONSTER);
		add_to_pack(monster, &level_monsters, 0);
}

can_see(row, col)
{
	short retval;

	retval = !blind && ((get_room_number(row, col) == current_room) ||
	   (rogue_is_around(row, col)));

	return(retval);
}

flit(monster)
object *monster;
{
	short inc1, inc2;
	short i, j, row, col;

	if (!rand_percent(FLIT_PERCENT)) {
		return(0);
	}
	inc1 = get_rand(0, 1) ? 1 : -1;
	inc2 = get_rand(0, 1) ? 1 : -1;

	if (rand_percent(10)) {
		return(1);
	}
	for (i = inc1; i != (2*(0-inc1)); i+=(0-inc1)) {
		for (j = inc2; j != (2*(0-inc2)); j+=(0-inc2)) {

			row = monster->row + i;
			col = monster->col + j;
			if ((row == rogue.row) && (col == rogue.col)) {
				continue;
			}

			if (mtry(monster, row, col)) {
				return(1);
			}
		}
	}
	return(1);
}

put_monster_rand_location(monster)
object *monster;
{
	short row, col;

	get_rand_row_col(&row, &col, (FLOOR | TUNNEL | IS_OBJECT));
	add_mask(row, col, MONSTER);
	monster->row = row;
	monster->col = col;

}

get_rand_obj_char()
{
	short r;
	char *rs = "%!?]/):*";

	r = get_rand(0, 7);

	return(rs[r]);
}

no_room_for_monster(rn)
{
	short i, j;

	for (i = rooms[rn].left_col+1; i < rooms[rn].right_col; i++) {
		for (j = rooms[rn].top_row+1; j < rooms[rn].bottom_row; j++) {
			if (!(screen[i][j] & MONSTER)) {
				return(0);
			}
		}
	}
	return(1);
}

aggravate()
{
	struct object *monster;

	message("you hear a high pitched humming noise");

	monster = level_monsters.next_object;

	while (monster) {
		wake_up(monster);
		if (monster->ichar == 'X') {
			monster->identified = 0;
		}
		monster = monster->next_object;
	}
}

monster_can_see(monster, row, col)
object *monster;
{
	short rn, rdif, cdif, retval;

	rn = get_room_number(row, col);

	if ((rn != NO_ROOM) && (rn ==
	    get_room_number(monster->row, monster->col))) {
		return(1);
	}
	rdif = row - monster->row;
	cdif = col - monster->col;

	retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
	return(retval);
}

mv_aquatars()
{
	object *monster;

	monster = level_monsters.next_object;

	while (monster) {
		if (monster->ichar == 'A') {
			mv_monster(monster, rogue.row, rogue.col);
		}
		monster = monster->next_object;
	}
}
SHAR_EOF
echo shar: extracting move.c
cat - << \SHAR_EOF > move.c
#include <curses.h>
#include "object.h"
#include "room.h"
#include "move.h"
#include "monster.h"

extern short current_room, halluc, detect_monster, blind, being_held;
extern short confused, interrupted, has_amulet;
extern char *hunger_str;

single_move_rogue(dirch, pickup)
{
	short row, col;
	object *obj, *object_at(), *pick_up();
	char description[SCOLS];
	short n, status;

	row = rogue.row;
	col = rogue.col;

	if (being_held) {
		get_dir_rc(dirch, &row, &col);

		if (!(screen[row][col] & MONSTER)) {
			message("you are being held", 1);
			return(MOVE_FAILED);
		}
	}
	row = rogue.row;
	col = rogue.col;

	if (confused) {
		dirch = get_rand_dir();
	}

	switch(dirch) {
	case 'h':
		col--;
		break;
	case 'j':
		row++;
		break;
	case 'k':
		row--;
		break;
	case 'l':
		col++;
		break;
	case 'b':
		col--;
		row++;
		break;
	case 'y':
		col--;
		row--;
		break;
	case 'u':
		col++;
		row--;
		break;
	case 'n':
		col++;
		row++;
		break;
	}
	if (screen[row][col] & MONSTER) {
		rogue_hit(object_at(&level_monsters, row, col));
		register_move();
		return(MOVE_FAILED);
	}
	if (!can_move(rogue.row, rogue.col, row, col)) {
		return(MOVE_FAILED);
	}
	if (screen[row][col] & DOOR) {
		if (current_room == PASSAGE) {
			current_room = get_room_number(row, col);
			light_up_room();
			wake_room(current_room, 1, row, col);
		} else {
			light_passage(row, col);
		}
	} else if ((screen[rogue.row][rogue.col] & DOOR) &&
		   (screen[row][col] & TUNNEL)) {
		light_passage(row, col);
		wake_room(current_room, 0, row, col);
		darken_room(current_room);
		current_room = PASSAGE;
	} else if (screen[row][col] & TUNNEL) {
			light_passage(row, col);
	}
	mvaddch(rogue.row, rogue.col,
	get_room_char(screen[rogue.row][rogue.col], rogue.row, rogue.col));
	mvaddch(row, col, rogue.fchar);
	rogue.row = row; rogue.col = col;
	if (screen[row][col] & CAN_PICK_UP) {
		if (pickup) {
			if (obj = pick_up(row, col, &status)) {
				get_description(obj, description);
				if (obj->what_is == GOLD) {
					free(obj);
					goto NOT_IN_PACK;
				}
			} else if (!status) {
				goto MVED;
			} else {
				goto MOVE_ON;
			}
		} else {
MOVE_ON:		obj = object_at(&level_objects, row, col);
			strcpy(description, "moved onto ");
			get_description(obj, description+11);
			goto NOT_IN_PACK;
		}
		n = strlen(description);
		description[n] = '(';
		description[n+1] = obj->ichar;
		description[n+2] = ')';
		description[n+3] = 0;
NOT_IN_PACK:	message(description, 1);
		register_move();
		return(STOPPED_ON_SOMETHING);
	}
	if ((screen[row][col] & DOOR) || (screen[row][col] & STAIRS)) {
		register_move();
		return(STOPPED_ON_SOMETHING);
	}
MVED:	if (register_move()) {			/* fainted from hunger */
		return(STOPPED_ON_SOMETHING);
	}
	return((confused ? STOPPED_ON_SOMETHING : MOVED));
}

multiple_move_rogue(dirch)
{
	short row, col;
	short m;

	switch(dirch) {
	case '':
	case '\012':
	case '':
	case '':
	case '\031':
	case '\025':
	case '\016':
	case '\002':
		do {
			row = rogue.row;
			col = rogue.col;
			if (((m = single_move_rogue((dirch + 96), 1)) ==
			MOVE_FAILED) || (m == STOPPED_ON_SOMETHING) ||
			interrupted) {
				break;
			}
		} while (!next_to_something(row, col));
		break;
	case 'H':
	case 'J':
	case 'K':
	case 'L':
	case 'B':
	case 'Y':
	case 'U':
	case 'N':
		while (!interrupted &&
			single_move_rogue((dirch + 32), 1) == MOVED) ;
		break;
	}
}

is_passable(row, col)
{
	if ((row < MIN_ROW) || (row > (LINES - 2)) || (col < 0) ||
	    (col > (COLS-1))) {
		return(0);
	}
	return(screen[row][col] & (FLOOR | TUNNEL | DOOR | STAIRS));
}

next_to_something(drow, dcol)
{
	short i, j, i_end, j_end, row, col;
	short pass_count = 0;

	if (confused) {
		return(1);
	}
	if (blind) {
		return(0);
	}
	i_end = (rogue.row < (LINES-2)) ? 1 : 0;
	j_end = (rogue.col < (COLS-1)) ? 1 : 0;

	for (i = ((rogue.row > MIN_ROW) ? -1 : 0); i <= i_end; i++) {
		for (j = ((rogue.col > 0) ? -1 : 0); j <= j_end; j++) {
			if ((i == 0) && (j == 0)) continue;
			if (((rogue.row+i)==drow)&&((rogue.col+j)==dcol)) {
				continue;
			}
			if(screen[rogue.row+i][rogue.col+j]&(MONSTER|IS_OBJECT))return(1);
			if ((((i - j) == 1) || ((i - j) == -1)) &&
			(screen[rogue.row+i][rogue.col+j] & TUNNEL)) {
				if (++pass_count > 1) {
					return(1);
				}
			}
			row = rogue.row+i; col = rogue.col+j;
			if ((screen[row][col] & DOOR)||(is_object(row,col))) {
				if (i == 0 || j == 0) {
					return(1);
				}
			}
		}
	}
	return(0);
}

can_move(row1, col1, row2, col2) 
{
	if (!is_passable(row2, col2)) {
		return(0);
	}
	if ((row1 != row2) && (col1 != col2)) {
		if ((screen[row1][col1]&DOOR)||(screen[row2][col2]&DOOR)) {
			return(0);
		}
		if ((!screen[row1][col2]) || (!screen[row2][col1])) {
			return(0);
		}
	}
	return(1);
}

is_object(row, col)
{
	return(screen[row][col] & IS_OBJECT);
}

move_onto()
{
	short ch;
	short first_miss = 1;

	while (!is_direction(ch = getchar())) {
		putchar(7);
		fflush(stdout);
		if (first_miss) {
			message("direction? ", 0);
			first_miss = 0;
		}
	}
	check_message();
	if (ch != CANCEL) {
		single_move_rogue(ch, 0);
	}
}

is_direction(c)
{
	return( (c == 'h') ||
		(c == 'j') ||
		(c == 'k') ||
		(c == 'l') ||
		(c == 'b') ||
		(c == 'y') ||
		(c == 'u') ||
		(c == 'n') ||
		(c == CANCEL)
		);
}

is_pack_letter(c)
{
	return(((c >= 'a') && (c <= 'z')) || (c == CANCEL) || (c == LIST));
}

check_hunger()
{
	short i, n;
	short fainted = 0;

	if (rogue.moves_left == HUNGRY) {
		hunger_str = "hungry";
		message(hunger_str, 0);
		print_stats();
	}
	if (rogue.moves_left == WEAK) {
		hunger_str = "weak";
		message(hunger_str, 0);
		print_stats();
	}
	if ((rogue.moves_left) <= FAINT) {
		if (rogue.moves_left == FAINT) {
			hunger_str = "faint";
			message(hunger_str, 1);
			print_stats();
		}
		n = get_rand(0, (FAINT - rogue.moves_left));
		if (n > 0) {
			fainted = 1;
			if (rand_percent(40)) rogue.moves_left++;
			message("you faint", 1);
			for (i = 0; i < n; i++) {
				if (rand_percent(50)) {
					move_monsters();
				}
			}
			message("you can move again", 1);
		}
	}
	if (rogue.moves_left <= STARVE) {
		killed_by(0, STARVATION);
	}
	rogue.moves_left--;
	return(fainted);
}

register_move()
{
	static short moves = 0;
	short fainted;

	if ((rogue.moves_left <= HUNGRY) || !has_amulet) {
		fainted = check_hunger();
	} else {
		fainted = 0;
	}

	move_monsters();

	if (++moves >= 80) {
		moves = 0;
		start_wanderer();
	}
	if (halluc) {
		if (!(--halluc)) {
			unhallucinate();
		} else {
			hallucinate();
		}
	}
	if (blind) {
		if (!(--blind)) {
			unblind();
		}
	}
	if (confused) {
		if (!(--confused)) {
			unconfuse();
		}
	}
	heal();

	return(fainted);
}

rest(count)
{
	int i;

	for (i = 0; i < count; i++) {
		if (interrupted) break;
		register_move();
	}
}

get_rand_dir()
{
	short d;

	d = get_rand(1, 8);

	switch(d) {
		case 1:
			return('j');
		case 2:
			return('k');
		case 3:
			return('l');
		case 4:
			return('h');
		case 5:
			return('y');
		case 6:
			return('u');
		case 7:
			return('b');
		case 8:
			return('n');
	}
}

heal()
{
	static short exp = -1, n, c = 0;

	if (rogue.exp != exp) {
		exp = rogue.exp;

		switch(exp) {
		case 1:
			n = 20;
			break;
		case 2:
			n = 18;
			break;
		case 3:
			n = 17;
			break;
		case 4:
			n = 14;
			break;
		case 5:
			n = 13;
			break;
		case 6:
			n = 10;
			break;
		case 7:
			n = 9;
			break;
		case 8:
			n = 8;
			break;
		case 9:
			n = 7;
			break;
		case 10:
			n = 4;
			break;
		case 11:
			n = 3;
			break;
		case 12:
		default:
			n = 2;
		}
	}
	if (rogue.hp_current == rogue.hp_max) {
		c = 0;
		return;
	}

	if (++c >= n) {
		c = 0;
		rogue.hp_current++;
		if (rogue.hp_current < rogue.hp_max) {
			if (rand_percent(50)) {
				rogue.hp_current++;
			}
		}
		print_stats();
	}
}
SHAR_EOF
echo shar: extracting object.c
cat - << \SHAR_EOF > object.c
#include <curses.h>
#include "object.h"
#include "room.h"

object level_objects;
unsigned short screen[SROWS][SCOLS];

extern short current_level, max_level;
extern short party_room;

short has_amulet = 0;
short foods = 0;

fighter rogue = {
	0, 0,		/* armor, weapon */
	12, 12,		/* Hp */
	16, 16,		/* Str */
	{0},		/* pack */
	0,		/* gold */
	1, 0,		/* exp, exp_points */
	0, 0,		/* row, col */
	'@',		/* char */
	1200		/* moves */
};

struct identify id_potions[POTIONS] = {
{100, "blue \0                           ", "of increase strength ",0},
{250, "red \0                            ", "of restore strength ",0},
{100, "green \0                          ", "of healing ",0},
{200, "grey \0                           ", "of extra healing ",0},
 {10, "brown \0                          ", "of poison ",0},
{300, "clear \0                          ", "of raise level ",0},
 {10, "pink \0                           ", "of blindness ",0},
 {25, "white \0                          ", "of hallucination ",0},
{100, "purple \0                         ", "of detect monster ",0},
{100, "black \0                          ", "of detect things ",0},
 {10, "yellow \0                         ", "of confusion ",0}
};

struct identify id_scrolls[SCROLLS] = {
{505, "                                   ", "of protect armor ", 0},
{200, "                                   ", "of hold monster ", 0},
{235, "                                   ", "of enchant weapon ", 0},
{235, "                                   ", "of enchant armor ", 0},
{175, "                                   ", "of identify ", 0},
{190, "                                   ", "of teleportation ", 0},
 {25, "                                   ", "of sleep ", 0},
{610, "                                   ", "of scare monster ", 0},
{210, "                                   ", "of remove curse ", 0},
{100, "                                   ", "of create monster ",0},
 {25, "                                   ", "of aggravate monster ",0}
};

struct identify id_weapons[WEAPONS] = {
	{150, "short bow ", "", 0},
	 {15, "arrows ", "", 0},
	 {35, "shurikens ", "", 0},
	{370, "mace ", "", 0},
	{480, "long sword ", "", 0},
	{590, "two-handed sword ", "", 0}
};

struct identify id_armors[ARMORS] = {
	{300, "leather armor ", "", (UNIDENTIFIED)},
	{300, "ring mail ", "", (UNIDENTIFIED)},
	{400, "scale mail ", "", (UNIDENTIFIED)},
	{500, "chain mail ", "", (UNIDENTIFIED)},
	{600, "banded mail ", "", (UNIDENTIFIED)},
	{600, "splint mail ", "", (UNIDENTIFIED)},
	{700, "plate mail ", "", (UNIDENTIFIED)}
};

struct identify id_wands[WANDS] = {
	 {25, "                                 ", "of teleport away ",0},
	 {50, "                                 ", "of slow monster ", 0},
	 {45, "                                 ", "of kill monster ",0},
	  {8, "                                 ", "of invisibility ",0},
	 {55, "                                 ", "of polymorph ",0},
	  {2, "                                 ", "of haste monster ",0},
	 {25, "                                 ", "of put to sleep ",0},
	  {0, "                                 ", "of do nothing ",0}
};

put_objects()
{
	short row, col, i, n;
	char *malloc();
	object *obj, *get_rand_object();

	if (current_level < max_level) return;

	n = get_rand(2, 4);
	if (rand_percent(35)) n++;

	if (rand_percent(50)) {
		strcpy(id_weapons[SHURIKEN].title, "daggers ");
	}
	if (rand_percent(5)) {
		make_party();
	}
	for (i = 0; i < n; i++) {
		obj = get_rand_object();
		put_object_rand_location(obj);
		add_to_pack(obj, &level_objects, 0);
	}
	put_gold();
}

put_gold()
{
	short i, j;
	short row,col;
	object *obj, *get_an_object();

	for (i = 0; i < MAXROOMS; i++) {
		if (rooms[i].is_room && rand_percent(GOLD_PERCENT)) {
			for (j = 0; j < 25; j++) {
				row = get_rand(rooms[i].top_row+1,
				rooms[i].bottom_row-1);
				col = get_rand(rooms[i].left_col+1,
				rooms[i].right_col-1);
				if ((screen[row][col] == FLOOR) ||
				    (screen[row][col] == PASSAGE)) {
					put_gold_at(row, col);
					break;
				}
			}
		continue;
		}
	}
}

put_gold_at(row, col)
{
	object *obj;

	obj = get_an_object();
	obj->row = row; obj->col = col;
	obj->what_is = GOLD;
	obj->quantity = get_rand((2*current_level), (16*current_level));
	add_mask(row, col, GOLD);
	add_to_pack(obj, &level_objects, 0);
}

put_object_at(obj, row, col)
object *obj;
{
	obj->row = row;
	obj->col = col;
	add_mask(row, col, obj->what_is);
	add_to_pack(obj, &level_objects, 0);
}

object *object_at(pack, row, col)
object *pack;
{
	object *obj;

	obj = pack->next_object;

	while (obj && (obj->row != row) || (obj->col != col)) {
		obj = obj->next_object;
	}
	return(obj);
}

object *get_letter_object(ch)
{
	object *obj;

	obj = rogue.pack.next_object;

	while (obj && (obj->ichar != ch)) {
		obj = obj->next_object;
	}
	return(obj);
}

free_stuff(objlist)
object *objlist;
{
	object *obj;

	while (objlist->next_object) {
		obj = objlist->next_object;
		objlist->next_object =
			objlist->next_object->next_object;
		free(obj);
	}
}

char *name_of(obj)
object *obj;
{
	char *retstring;

	switch(obj->what_is) {
	case SCROLL:
		retstring = obj->quantity > 1 ? "scrolls " : "scroll ";
		break;
	case POTION:
		retstring = obj->quantity > 1 ? "potions " : "potion ";
		break;
	case FOOD:
		retstring = obj->quantity > 1 ? "rations " : "ration ";
		break;
	case WAND:
		retstring = "wand ";
		break;
	case WEAPON:
		switch(obj->which_kind) {
		case ARROW:
			retstring=obj->quantity > 1 ? "arrows " : "arrow ";
			break;
		case SHURIKEN:
			if (id_weapons[SHURIKEN].title[0] == 'd') {
			retstring=obj->quantity > 1 ? "daggers " : "dagger ";
			} else {
			retstring=obj->quantity > 1?"shurikens ":"shuriken ";
			}
			break;
		default:
			retstring = id_weapons[obj->which_kind].title;
		}
		break;
	default:
		retstring = "unknown ";
		break;
	}
	return(retstring);
}

object *get_rand_object()
{
	object *obj, *get_an_object();

	obj = get_an_object();

	if (foods < (current_level/2)) {
		obj->what_is = FOOD;
	} else {
		obj->what_is = get_rand_what_is();
	}
	obj->identified = 0;

	switch(obj->what_is) {
	case SCROLL:
		get_rand_scroll(obj);
		break;
	case POTION:
		get_rand_potion(obj);
		break;
	case WEAPON:
		get_rand_weapon(obj);
		break;
	case ARMOR:
		get_rand_armor(obj);
		break;
	case WAND:
		get_rand_wand(obj);
		break;
	case FOOD:
		foods++;
		get_food(obj);
		break;
	}
	return(obj);
}

get_rand_what_is()
{
	short percent;
	short what_is;

	percent = get_rand(1, 92);

	if (percent <= 30) {
		what_is = SCROLL;
	} else if (percent <= 60) {
		what_is = POTION;
	} else if (percent <= 65) {
		what_is = WAND;
	} else if (percent <= 75) {
		what_is = WEAPON;
	} else if (percent <= 85) {
		what_is = ARMOR;
	} else {
		what_is = FOOD;
	}
	return(what_is);
}

get_rand_scroll(obj)
object *obj;
{
	short percent;

	percent = get_rand(0, 82);

	if (percent <= 5) {
		obj->which_kind = PROTECT_ARMOR;
	} else if (percent <= 11) {
		obj->which_kind = HOLD_MONSTER;
	} else if (percent <= 20) {
		obj->which_kind = CREATE_MONSTER;
	} else if (percent <= 35) {
		obj->which_kind = IDENTIFY;
	} else if (percent <= 43) {
		obj->which_kind = TELEPORT;
	} else if (percent <= 52) {
		obj->which_kind = SLEEP;
	} else if (percent <= 57) {
		obj->which_kind = SCARE_MONSTER;
	} else if (percent <= 66) {
		obj->which_kind = REMOVE_CURSE;
	} else if (percent <= 71) {
		obj->which_kind = ENCHANT_ARMOR;
	} else if (percent <= 76) {
		obj->which_kind = ENCHANT_WEAPON;
	} else {
		obj->which_kind = AGGRAVATE_MONSTER;
	}
}

get_rand_potion(obj)
object *obj;
{
	short percent;

	percent = get_rand(1, 105);

	if (percent <= 5) {
		obj->which_kind = RAISE_LEVEL;
	} else if (percent <= 15) {
		obj->which_kind = DETECT_OBJECTS;
	} else if (percent <= 25) {
		obj->which_kind = DETECT_MONSTER;
	} else if (percent <= 35) {
		obj->which_kind = INCREASE_STRENGTH;
	} else if (percent <= 45) {
		obj->which_kind = RESTORE_STRENGTH;
	} else if (percent <= 55) {
		obj->which_kind = HEALING;
	} else if (percent <= 65) {
		obj->which_kind = EXTRA_HEALING;
	} else if (percent <= 75) {
		obj->which_kind = BLINDNESS;
	} else if (percent <= 85) {
		obj->which_kind = HALLUCINATION;
	} else if (percent <= 95) {
		obj->which_kind = CONFUSION;
	} else {
		obj->which_kind = POISON;
	}
}

get_rand_weapon(obj)
object *obj;
{
	short percent;
	short i;
	short blessing, cursed, increment;

	obj->which_kind = get_rand(0, (WEAPONS-1));

	if ((obj->which_kind == ARROW) || (obj->which_kind == SHURIKEN)) {
		obj->quantity = get_rand(3, 15);
		obj->quiver = get_rand(0, 126);
	} else {
		obj->quantity = 1;
	}
	obj->identified = 0;
	obj->to_hit_enchantment = obj->damage_enchantment = 0;
	get_weapon_thd(obj);

	/* notice, long swords are ALWAYS cursed or blessed */

	percent = get_rand(1, ((obj->which_kind == LONG_SWORD) ? 32 : 96));
	blessing = get_rand(1, 3);
	obj->is_cursed = 0;

	if (percent <= 16) {
		increment = 1;
	} else if (percent <= 32) {
		increment = -1;
		obj->is_cursed = 1;
	}
	if (percent <= 32) {
		for (i = 0; i < blessing; i++) {
			if (rand_percent(50)) {
				obj->to_hit_enchantment += increment;
			} else {
				obj->damage_enchantment += increment;
			}
		}
	}
	switch(obj->which_kind) {
	case BOW:
		obj->damage = "1d2";
		break;
	case ARROW:
		obj->damage = "1d2";
		break;
	case SHURIKEN:
		obj->damage = "1d4";
		break;
	case MACE:
		obj->damage = "2d3";
		break;
	case LONG_SWORD:
		obj->damage = "3d4";
		break;
	case TWO_HANDED_SWORD:
		obj->damage = "4d5";
		break;
	}
}

get_rand_armor(obj)
object *obj;
{
	short percent;
	short blessing;

	obj->which_kind = get_rand(0, (ARMORS-1));
	obj->class = obj->which_kind + 2;
	if ((obj->which_kind == PLATE) || (obj->which_kind == SPLINT)) {
		obj->class--;
	}
	obj->is_cursed = 0;
	obj->is_protected = 0;
	obj->damage_enchantment = 0;

	percent = get_rand(1, 100);
	blessing = get_rand(1, 3);

	if (percent <= 16) {
		obj->is_cursed = 1;
		obj->damage_enchantment -= blessing;
	} else if (percent <= 33) {
		obj->damage_enchantment += blessing;
	}
}

get_rand_wand(obj)
object *obj;
{
	obj->which_kind = get_rand(0, (WANDS-1));
	obj->class = get_rand(3, 7);
}

get_food(obj)
object *obj;
{
	obj->which_kind = obj->what_is = FOOD;
}

put_stairs()
{
	short row, col;

	get_rand_row_col(&row, &col, (FLOOR | TUNNEL));
	screen[row][col] = STAIRS;
}

get_weapon_thd(obj)
object *obj;
{
	switch(obj->which_kind) {
	case BOW:
		break;
	case ARROW:
		break;
	case SHURIKEN:
		break;
	case MACE:
		break;
	case LONG_SWORD:
		break;
	case TWO_HANDED_SWORD:
		break;
	}
}

get_armor_class(obj)
object *obj;
{
	if (obj) {
		return(obj->class + obj->damage_enchantment);
	}
	return(0);
}

object *get_an_object()
{
	object *obj;
	char *malloc();

	if (!(obj = (object *) malloc(sizeof(object)))) {
		clean_up("Cannot allocate item");
	}
	obj->quantity = 1;
	obj->ichar = 'L';
	obj->picked_up = 0;		/* not picked up yet */
	return(obj);
}

make_party()
{
	object *obj;
	short n;

	party_room = get_rand_room();
	n = fill_room_with_objects(party_room);
	fill_room_with_monsters(party_room, n);
}

show_objects()
{
	object *obj;

	obj = level_objects.next_object;

	while (obj) {
		mvaddch(obj->row, obj->col, get_room_char(obj->what_is));
		obj = obj->next_object;
	}
}

put_amulet()
{
	short row, col;
	object *obj, *get_an_object();

	obj = get_an_object();
	obj->what_is = AMULET;
	put_object_rand_location(obj);
	add_to_pack(obj, &level_objects, 0);
}

put_object_rand_location(obj)
object *obj;
{
	short row, col;

	get_rand_row_col(&row, &col, (FLOOR | TUNNEL));
	add_mask(row, col, obj->what_is);
	obj->row = row;
	obj->col = col;

}
SHAR_EOF
echo shar: extracting pack.c
cat - << \SHAR_EOF > pack.c
#include <curses.h>
#include "move.h"
#include "object.h"

char *CURSE_MESSAGE = "you can't, it appears to be cursed";
char ichars[26];

extern short has_amulet;

object *add_to_pack(obj, pack, condense)
object *obj, *pack;
{
	object *op, *check_duplicate();

	if (condense) {
		if (op = check_duplicate(obj, pack)) {
			free(obj);
			return(op);
		} else {
			obj->ichar = next_avail_ichar();
		}
	}

	if (pack->next_object == 0) {
		pack->next_object = obj;
	} else {
		op = pack->next_object;

		while (op->next_object) {
			op = op->next_object;
		}
		op->next_object = obj;
	}
	obj->next_object = 0;
	return(obj);
}

remove_from_pack(obj, pack)
object *obj, *pack;
{
	while (pack->next_object != obj) {
		pack = pack->next_object;
	}
	pack->next_object = pack->next_object->next_object;
}

object *pick_up(row, col, status)
short *status;
{
	object *obj, *object_at(), *add_to_pack();

	obj = object_at(&level_objects, row, col);
	*status = 1;

	if ((obj->what_is == SCROLL) && (obj->which_kind == SCARE_MONSTER) &&
	    (obj->picked_up > 0)) {
		message("the scroll turns to dust as you pick it up", 1);
		remove_from_pack(obj, &level_objects);
		remove_mask(row, col, SCROLL);
		free(obj);
		*status = 0;
		if (id_scrolls[SCARE_MONSTER].id_status == UNIDENTIFIED) {
			id_scrolls[SCARE_MONSTER].id_status = IDENTIFIED;
		}
		return(0);
	}
	if (obj->what_is == GOLD) {
		rogue.gold += obj->quantity;
		remove_mask(row, col, GOLD);
		remove_from_pack(obj, &level_objects);
		print_stats();
		return(obj);	/* obj will be free()ed in single_move() */
	}
	if (get_pack_count(obj) >= MAX_PACK_COUNT) {
		message("Pack too full", 1);
		return(0);
	}
	if (obj->what_is == AMULET) {
		has_amulet = 1;
	}

	remove_mask(row, col, obj->what_is);
	remove_from_pack(obj, &level_objects);
	obj = add_to_pack(obj, &rogue.pack, 1);
	obj->picked_up++;
	return(obj);
}

drop()
{
	object *obj, *get_letter_object(), *new;
	short ch;
	object *get_an_object();
	char description[SCOLS];

	if (screen[rogue.row][rogue.col] & IS_OBJECT) {
		message("There's already something there", 0);
		return;
	}
	if (!rogue.pack.next_object) {
		message("You have nothing to drop", 0);
		return;
	}
	ch = get_pack_letter("drop what? ", IS_OBJECT);

	if (ch == CANCEL) {
		return;
	}
	if (!(obj = get_letter_object(ch))) {
		message("No such item.", 0);
		return;
	}
	if (obj == rogue.weapon) {
		if (obj->is_cursed) {
			message(CURSE_MESSAGE, 0);
			return;
		}
		rogue.weapon = 0;
	} else if (obj == rogue.armor) {
		if (obj->is_cursed) {
			message(CURSE_MESSAGE, 0);
			return;
		}
		rogue.armor = 0;
		print_stats();
	}
	obj->row = rogue.row;
	obj->col = rogue.col;

	if ((obj->quantity > 1) && (obj->what_is != WEAPON)) {
		obj->quantity--;
		new = get_an_object();
		*new = *obj;
		new->quantity = 1;
		obj = new;
		goto ADD;
	}
	if (obj->what_is == AMULET) {
		has_amulet = 0;
	}
	make_avail_ichar(obj->ichar);
	remove_from_pack(obj, &rogue.pack);
ADD:	add_to_pack(obj, &level_objects, 0);
	add_mask(rogue.row, rogue.col, obj->what_is);
	strcpy(description, "dropped ");
	get_description(obj, description+8);
	message(description, 0);
	register_move();
}

object *check_duplicate(obj, pack)
object *obj, *pack;
{
	object *op;

	if (!(obj->what_is & (WEAPON | FOOD | SCROLL | POTION))) {
		return(0);
	}
	op = pack->next_object;

	while (op) {
		if ((op->what_is == obj->what_is) && 
		    (op->which_kind == obj->which_kind)) {

			if ((obj->what_is != WEAPON) ||
			((obj->what_is == WEAPON) &&
			((obj->which_kind == ARROW) ||
			(obj->which_kind == SHURIKEN)) &&
			(obj->quiver == op->quiver))) {
				op->quantity += obj->quantity;
				return(op);
			}
		}
		op = op->next_object;
	}
	return(0);
}

next_avail_ichar()
{
	short i;

	for (i = 'a'; i < 'z'; i++) {
		if (!ichars[i-'a']) {
			ichars[i-'a'] = 1;
			return(i);
		}
	}
	return(0);
}

make_avail_ichar(ch)
{
	ichars[ch - 'a'] = 0;
}

wait_for_ack(prompt)
{
	if (prompt) {
		printf("%s ", MORE);
		fflush(stdout);
	}
	while (getchar() != ' ') ;
}

get_pack_letter(prompt, mask)
char *prompt;
unsigned short mask;
{
	short first_miss = 1;
	short ch;

	while (!is_pack_letter(ch = getchar())) {
		putchar(7);
		fflush(stdout);
		if (first_miss) {
WHICH:			message(prompt, 0);
			first_miss = 0;
		}
	}
	if (ch == LIST) {
		check_message();
		inventory(&rogue.pack, mask);
		goto WHICH;
	}
	check_message();
	return(ch);
}

take_off()
{
	char description[SCOLS];
	object *obj;

	if (rogue.armor) {
		if (rogue.armor->is_cursed) {
			message(CURSE_MESSAGE, 0);
		} else {
			mv_aquatars();
			obj = rogue.armor;
			rogue.armor = 0;
			strcpy(description, "was wearing ");
			get_description(obj, description+12);
			message(description, 0);
			print_stats();
			register_move();
		}
	} else {
		message("not wearing any", 0);
	}
}

wear()
{
	short ch;
	register object *obj;
	char description[SCOLS];

	if (rogue.armor) {
		message("your already wearing some", 0);
		return;
	}
	ch = get_pack_letter("wear what? ", ARMOR);

	if (ch == CANCEL) {
		return;
	}
	if (!(obj = get_letter_object(ch))) {
		message("No such item.", 0);
		return;
	}
	if (obj->what_is != ARMOR) {
		message("You can't wear that", 0);
		return;
	}
	rogue.armor = obj;
	obj->identified = 1;
	get_description(obj, description);
	message(description, 0);
	print_stats();
	register_move();
}

wield()
{
	short ch;
	register object *obj;
	char description[SCOLS];

	if (rogue.weapon && rogue.weapon->is_cursed) {
		message(CURSE_MESSAGE, 0);
		return;
	}
	ch = get_pack_letter("wield what? ", WEAPON);

	if (ch == CANCEL) {
		return;
	}
	if (!(obj = get_letter_object(ch))) {
		message("No such item.", 0);
		return;
	}
	if (obj->what_is != WEAPON) {
		message("You can't wield that", 0);
		return;
	}
	if (obj == rogue.weapon) {
		message("in use", 0);
	} else {
		rogue.weapon = obj;
		get_description(obj, description);
		message(description, 0);
		register_move();
	}
}

call_it()
{
	short ch;
	register object *obj;
	struct identify *id_table, *get_id_table();
	char buf[MAX_TITLE_LENGTH+2];

	ch = get_pack_letter("call what? ", (SCROLL | POTION | WAND));

	if (ch == CANCEL) {
		return;
	}
	if (!(obj = get_letter_object(ch))) {
		message("No such item.", 0);
		return;
	}
	if (!(obj->what_is & (SCROLL | POTION | WAND))) {
		message("surely you already know what that's called", 0);
		return;
	}
	id_table = get_id_table(obj);

	if (get_input_line(buf, id_table[obj->which_kind].title)) {
		id_table[obj->which_kind].id_status = CALLED;
		strcpy(id_table[obj->which_kind].title, buf);
	}
}

get_pack_count(new_obj)
object *new_obj;
{
	object *obj;
	short count = 0;

	if (!(obj = rogue.pack.next_object)) {
		return(0);
	}
	while (obj) {
		if (obj->what_is != WEAPON) {
			count += obj->quantity;
		} else {
			if ((new_obj->what_is != WEAPON) ||
			    ((obj->which_kind != ARROW) &&
			    (obj->which_kind != SHURIKEN)) ||
			    (new_obj->which_kind != obj->which_kind) ||
			    (obj->quiver != new_obj->quiver)) {
				count++;
			}
		}
		obj = obj->next_object;
	}
	return(count);
}
SHAR_EOF
echo shar: extracting play.c
cat - << \SHAR_EOF > play.c
#include <curses.h>
#include "object.h"
#include "move.h"

short interrupted = 0;
extern short party_room, detect_monster;
extern char hit_message[];

play_level()
{
	short ch;
	int count = 0;

	for (;;) {
		interrupted = 0;
		if (hit_message[0]) {
			message(hit_message);
			hit_message[0] = 0;
		}
		move(rogue.row, rogue.col);
		refresh();
		ch = getchar();
		check_message();
CH:
		switch(ch) {
		case '.':
			rest((count > 0) ? count : 1);
			break;
		case 'i':
			inventory(&rogue.pack, IS_OBJECT);
			break;
		/*case 'p':
			inventory(&level_objects, IS_OBJECT);
			break;*/
		case 'f':
			fight(0);
			break;
		case 'F':
			fight(1);
			break;
		case 'h':
		case 'j':
		case 'k':
		case 'l':
		case 'y':
		case 'u':
		case 'n':
		case 'b':
			single_move_rogue(ch, 1);
			break;
		case 'H':
		case 'J':
		case 'K':
		case 'L':
		case 'B':
		case 'Y':
		case 'U':
		case 'N':
		case '':
		case '\012':		/* ^J */
		case '':
		case '':
		case '\031':
		case '\025':
		case '\016':
		case '\002':
			multiple_move_rogue(ch);
			break;
		case 'e':
			eat();
			break;
		case 'q':
			quaff();
			break;
		case 'r':
			read_scroll();
			break;
		case 'm':
			move_onto();
			break;
		case 'd':
			drop();
			break;
		case '':
			remessage();
			break;
		case '>':
			if (check_down()) {
				return;
			}
			break;
		case '<':
			if (check_up()) {
				return;
			}
			break;
		case 'I':
			single_inventory();
			break;
		case '':
			wrefresh(curscr);
			break;
		case 'T':
			take_off();
			break;
		case 'W':
		case 'P':
			wear();
			break;
		case 'w':
			wield();
			break;
		case 'c':
			call_it();
			break;
		case 'z':
			zapp();
			break;
		case 't':
			throw();
			break;
		case '\032':
			tstp();
			break;
		case '!':
			shell();
			break;
		case 'v':
			message("i_rogue: Version 1.0. (stoehr was here)", 0);
			break;
		case 'Q':
			quit();
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			count = 0;
			do {
				count = (10 * count) + (ch - '0');
				ch = getchar();
			} while ((ch >= '0') && (ch <= '9'));
			goto CH;
			break;
		case ' ':
			break;
		default:
			message("unknown command");
			break;
		}
	}
}
SHAR_EOF
echo shar: extracting random.c
cat - << \SHAR_EOF > random.c
#include "macros.h"

get_rand(x, y)
int x, y;
{
	long r, random();
	int s;

	two_sort(x, y);

	r = random();
	r = (r % ((y-x)+1)) + x;
	s = (int) r;
	return(s);
}

rand_percent(percentage)
{
	return(get_rand(1, 100) <= percentage);
}
SHAR_EOF
echo shar: extracting room.c
cat - << \SHAR_EOF > room.c
#include <curses.h>
#include "room.h"
#include "object.h"
#include "move.h"

short current_room;
room rooms[MAXROOMS];
extern short detect_monster;
extern short blind;

light_up_room()
{
	short i, j;

	if (blind) return;
	for (i = rooms[current_room].top_row;
	i <= rooms[current_room].bottom_row; i++) {
		for (j = rooms[current_room].left_col;
		j <= rooms[current_room].right_col; j++) {
			mvaddch(i, j, get_room_char(screen[i][j], i, j));
		}
	}
	mvaddch(rogue.row, rogue.col, rogue.fchar);
}

light_passage(row, col)
{
	short i, j, i_end, j_end;

	if (blind) return;

	i_end = (row < (LINES-2)) ? 1 : 0;
	j_end = (col < (COLS-1)) ? 1 : 0;

	for (i = ((row > MIN_ROW) ? -1 : 0); i <= i_end; i++) {
		for (j = ((col > 0) ? -1 : 0); j <= j_end; j++) {
			if (is_passable(row+i, col+j)) {
				mvaddch(row+i, col+j,
				get_room_char(screen[row+i][col+j],
				row+i, col+j));
			}
		}
	}
}

darken_room(rn)
short rn;
{
	short i, j;

	if (blind) return;

	for (i = rooms[rn].top_row + 1;
	i < rooms[rn].bottom_row; i++) {
		for (j = rooms[rn].left_col + 1;
		j < rooms[rn].right_col; j++) {
			if (!is_object(i, j) &&
			   !(detect_monster && (screen[i][j] & MONSTER))) {
				if (!hiding_xeroc(i, j)) {
					mvaddch(i, j, ' ');
				}
			}
		}
	}
}

get_room_char(mask, row, col)
register short mask;
register short row, col;
{
	if (mask & MONSTER) {
		return(get_monster_char_row_col(row, col));
	}
	if (mask & SCROLL) {
		return('?');
	}
	if (mask & POTION) {
		return('!');
	}
	if (mask & FOOD) {
		return(':');
	}
	if (mask & WAND) {
		return('/');
	}
	if (mask & ARMOR) {
		return(']');
	}
	if (mask & WEAPON) {
		return(')');
	}
	if (mask & GOLD) {
		return('*');
	}
	if (mask & TUNNEL) {
		return('#');
	}
	if (mask & HORWALL) {
		return('-');
	}
	if (mask & VERTWALL) {
		return('|');
	}
	if (mask & AMULET) {
		return(',');
	}
	if (mask & FLOOR) {
		return('.');
	}
	if (mask & DOOR) {
		return('+');
	}
	if (mask & STAIRS) {
		return('%');
	}
	return(' ');
}

get_rand_row_col(row, col, mask)
short *row, *col;
unsigned short mask;
{
	short rn;
AGAIN:
	do {
		*row = get_rand(MIN_ROW, SROWS-2);
		*col = get_rand(0, SCOLS-1);
		rn = get_room_number(*row, *col);
	} while (!(screen[*row][*col] & mask) || (rn == NO_ROOM));
	if (screen[*row][*col] & (~mask)) goto AGAIN;
}

get_rand_room()
{
	short i;

	do {
		i = get_rand(0, MAXROOMS-1);
	} while (!rooms[i].is_room);

	return(i);
}

fill_room_with_objects(rn)
{
	short i;
	object *obj, *get_rand_object();
	short n, N, row, col;

	N = ((rooms[rn].bottom_row - rooms[rn].top_row) - 1) *
	    ((rooms[rn].right_col - rooms[rn].left_col) - 1);
	n =  get_rand(5, 10);
	if (n > N) n = N - 2;

	for (i = 0; i < n; i++) {
		do {
			row = get_rand(rooms[rn].top_row+1,
				       rooms[rn].bottom_row-1);
			col = get_rand(rooms[rn].left_col+1,
				       rooms[rn].right_col-1);
		} while (screen[row][col] != FLOOR);

		obj = get_rand_object();
		put_object_at(obj, row, col);
	}
	return(n);
}

get_room_number(row, col)
{
	short i;

	for (i = 0; i < MAXROOMS; i++) {
		if ((row >= rooms[i].top_row)&&(row <= rooms[i].bottom_row) &&
		    (col >= rooms[i].left_col)&&(col <= rooms[i].right_col)) {
			return(i);
		}
	}
	return(NO_ROOM);
}

shell()
{
	char *getenv(), *rindex();
	char *sh;
	int status;

	move(LINES-1, 0);
	refresh();
	stop_window();
	putchar('\n');

	if (!(sh = getenv("SHELL"))) {
		sh = "/bin/sh";
	}

	if (!fork()) {
		if (setreuid(-1, getuid()) < 0) exit(1);
		execl(sh, rindex(sh, '/') + 1, 0);
		exit(0);
	}
	wait(&status);
	start_window();
	wrefresh(curscr);
}
SHAR_EOF
echo shar: extracting score.c
cat - << \SHAR_EOF > score.c
#include <signal.h>
#include <curses.h>
#include "object.h"
#include "monster.h"
#include "room.h"
#include <sys/file.h>

extern char *player_name;
extern char *monster_names[];
extern short has_amulet, max_level;

killed_by(monster, other)
object *monster;
short other;
{
	char buf[80];
	short i;

	signal(SIGINT, SIG_IGN);

	if (other != QUIT) {
		rogue.gold = ((rogue.gold * 9) / 10);
	}

	if (other) {
		switch(other) {
		case HYPOTHERMIA:
			strcpy(buf, "died of hypothermia");
			break;
		case STARVATION:
			strcpy(buf, "died of starvation");
			break;
		case QUIT:
			strcpy(buf, "quit");
			break;
		}
	} else {
		strcpy(buf, "Killed by ");
		if (is_vowel(monster_names[monster->ichar - 'A'])) {
			strcat(buf, "an ");
		} else {
			strcat(buf, "a ");
		}
		strcat(buf, monster_names[monster->ichar - 'A']);
	}
	strcat(buf, " with ");
	sprintf(buf+strlen(buf), "%d gold", rogue.gold);
	message(buf, 0);
	message("");
	score(monster, other);
}

win()
{
	rogue.armor = 0;	/* disarm and relax */
	rogue.weapon = 0;

	clear();
	mvaddstr(10, 11, "@   @  @@@   @   @      @  @  @   @@@   @   @   @");
	mvaddstr(11, 11, " @ @  @   @  @   @      @  @  @  @   @  @@  @   @");
	mvaddstr(12, 11, "  @   @   @  @   @      @  @  @  @   @  @ @ @   @");
	mvaddstr(13, 11, "  @   @   @  @   @      @  @  @  @   @  @  @@");
	mvaddstr(14, 11, "  @    @@@    @@@        @@ @@    @@@   @   @   @");
	mvaddstr(17, 11, "Congratulations,  you have  been admitted  to  the");
	mvaddstr(18, 11, "Fighter's Guild.   You return home,  sell all your");
	mvaddstr(19, 11, "treasures at great profit and retire into comfort.");
	message("");
	message("");
	id_all();
	sell_pack();
	score((object *) 0, WIN);
}

quit()
{
	message("really quit?", 1);
	if (getchar() != 'y') {
		check_message();
		return;
	}
	check_message();

	killed_by(0, QUIT);
}

score(monster, other)
object *monster;
{
	int fd;

	while (access(SCOREFILE, W_OK) || access(SCOREFILE, R_OK)) {
		umask(0);
		if ((fd = creat(SCOREFILE, 0666)) < 0) {
			message("cannot find/read/write score file");
			message(SCOREFILE);
			message("I'll wait, you go off and try to fix it");
			message("hit space when finished fixing the problem");
			wait_for_ack(0);
		} else {
			close(fd);
		}
	}
	put_scores(monster, other);
}

put_scores(monster, other)
object *monster;
{
	short i, j, n, rank = 10, x, dont_insert = 0;
	char scores[10][82];
	int fd, s;

	fd = open(SCOREFILE, O_RDWR, 0);

	for (i = 0; i < 10; i++) {
L:		if (((n = read(fd, scores[i], 80)) < 80) && (n != 0)) {
			message("error in score file format");
			message("");
			clean_up("sorry, score file is out of order");
		} else if (n == 0) {
			break;
		}
		if (!ncmp(scores[i]+16, player_name)) {
			x = 7;
			while (scores[i][x] == ' ') x++;
			s = get_number(scores[i] + x);
			if (s <= rogue.gold) {
				goto L;
			} else {
				dont_insert = 1;
			}
		}
	}
	if (dont_insert) goto DI;

	for (j = 0; j < i; j++) {
		if (rank > 9) {

			x = 7;
			while (scores[j][x] == ' ') x++;
			s = get_number(scores[j] + x);

			if (s <= rogue.gold) {
				rank = j;
			}
		}
	}
	if (i == 0) {
		rank = 0;
	} else if ((i < 10) && (rank > 9)) {
		rank = i;
	}
	if (rank <= 9) {
		insert_score(scores, rank, i, monster, other);

		if (i < 10) {
			i++;
		}
	}
	lseek(fd, 0, 0);
DI:
	clear();
	mvaddstr(3, 30, "Top  Ten  Rogueists");
	mvaddstr(8, 0, "Rank\tScore\tName");

	signal(SIGQUIT, SIG_IGN);
	signal(SIGINT, SIG_IGN);
	signal(SIGHUP, SIG_IGN);

	for (j = 0; j < i; j++) {
		if (j == rank) {
			standout();
		}
		if (j == 9) {
			scores[j][0] = '1';
			scores[j][1] = '0';
		} else {
			scores[j][0] = ' ';
			scores[j][1] = j + '1';
		}
		mvaddstr(j+10, 0, scores[j]);
		if (rank < 10) {
			write(fd, scores[j], 80);
		}
		if (j == rank) {
			standend();
		}
	}
	refresh();
	close(fd);
	clean_up("");
}

insert_score(scores, rank, n, monster, other)
char scores[][82];
short rank, n;
object *monster;
{
	short i, k;
	char buf[82];

	for (i = (n - 1); i >= rank; i--) {
		if (i < 9) {
			strcpy(scores[i+1], scores[i]);
		}
	}
	sprintf(buf, "%2d      %5d   %s: ", rank+1, rogue.gold, player_name);

	if (other) {
		switch(other) {
		case HYPOTHERMIA:
			strcat(buf, "died of hypothermia");
			break;
		case STARVATION:
			strcat(buf, "died of starvation");
			break;
		case QUIT:
			strcat(buf, "quit");
			break;
		case WIN:
			strcat(buf, "a total winner");
			break;
		}
	} else {
		strcat(buf, "killed by ");
		if (is_vowel(monster_names[monster->ichar - 'A'])) {
			strcat(buf, "an ");
		} else {
			strcat(buf, "a ");
		}
		strcat(buf, monster_names[monster->ichar - 'A']);
	}
	sprintf(buf+strlen(buf), " on level %d ",  max_level);
	if ((other != WIN) && has_amulet) {
		strcat(buf, "with amulet");
	}
	for (i = strlen(buf); i < 79; i++) {
		buf[i] = ' ';
	}
	buf[79] = 0;
	strcpy(scores[rank], buf);
}

is_vowel(ch)
short ch;
{
	return( (ch == 'a') ||
		(ch == 'e') ||
		(ch == 'i') ||
		(ch == 'o') ||
		(ch == 'u') );
}

sell_pack()
{
	object *obj;
	short row = 2, val;
	char buf[80];

	obj = rogue.pack.next_object;

	clear();

	while (obj) {
		mvaddstr(1, 0, "Value      Item");
		if (obj->what_is == FOOD) {
			goto NEXT;
		}
		obj->identified = 1;
		val = get_value(obj);
		rogue.gold += val;

		if (row < SROWS) {
			sprintf(buf, "%5d      ", val);
			get_description(obj, buf+11);
			mvaddstr(row++, 0, buf);
		}
NEXT:		obj = obj->next_object;
	}
	refresh();
	message("");
}

get_value(obj)
object *obj;
{
	short wc;
	int val;

	wc = obj->which_kind;

	switch(obj->what_is) {
	case WEAPON:
		val = id_weapons[wc].value;
		if ((wc == ARROW) || (wc == SHURIKEN)) {
			val *= obj->quantity;
		}
		val += (obj->damage_enchantment * 85);
		val += (obj->to_hit_enchantment * 85);
		break;
	case ARMOR:
		val = id_armors[wc].value;
		val += (obj->damage_enchantment * 75);
		if (obj->is_protected) {
			val += 200;
		}
		break;
	case WAND:
		val = id_wands[wc].value * obj->class;
		break;
	case SCROLL:
		val = id_scrolls[wc].value * obj->quantity;
		break;
	case POTION:
		val = id_potions[wc].value * obj->quantity;
		break;
	case AMULET:
		val = 5000;
		break;
	}
	if (val <= 0) {
		val = 10;
	}
	return(val);
}

id_all()
{
	short i;

	for (i = 0; i < SCROLLS; i++) {
		id_scrolls[i].id_status = IDENTIFIED;
	}
	for (i = 0; i < WEAPONS; i++) {
		id_weapons[i].id_status = IDENTIFIED;
	}
	for (i = 0; i < ARMORS; i++) {
		id_armors[i].id_status = IDENTIFIED;
	}
	for (i = 0; i < WANDS; i++) {
		id_wands[i].id_status = IDENTIFIED;
	}
	for (i = 0; i < POTIONS; i++) {
		id_potions[i].id_status = IDENTIFIED;
	}
}

ncmp(s1, s2)
char *s1, *s2;
{
	short i = 0;
	int r;

	while(s1[i] != ':') i++;
	s1[i] = 0;
	r = strcmp(s1, s2);
	s1[i] = ':';
	return(r);
}
SHAR_EOF
echo shar: extracting special_hit.c
cat - << \SHAR_EOF > special_hit.c
#include <curses.h>
#include "object.h"
#include "move.h"
#include "monster.h"

short being_held;

extern short current_level, max_level, has_amulet, detect_monster;
extern int level_points[];

special_hit(monster)
object *monster;
{
	switch(monster->ichar) {
	case 'A':
		rust(monster);
		break;
	case 'F':
		being_held = 1;
		break;
	case 'I':
		freeze(monster);
		break;
	case 'L':
		steal_gold(monster);
		break;
	case 'N':
		steal_item(monster);
		break;
	case 'R':
		sting(monster);
		break;
	case 'V':
		drain_life();
		break;
	case 'W':
		drain_level();
		break;
	}
}

rust(monster)
object *monster;
{
	if (!rogue.armor || (get_armor_class(rogue.armor) <= 1) ||
	    (rogue.armor->which_kind == LEATHER)) {
		return;
	}
	if (rogue.armor->is_protected) {
		if (!monster->identified) {
			message("the rust vanishes instantly", 0);
			monster->identified = 1;
		}
	} else {
		rogue.armor->damage_enchantment--;
		message("your armor weakens", 0);
		print_stats();
	}
}

freeze(monster)
object *monster;
{
	short freeze_percent = 99;
	short i, n;

	if (rand_percent(12)) return;

	freeze_percent -= (rogue.strength_current+(rogue.strength_current/2));
	freeze_percent -= rogue.exp * 4;
	freeze_percent -= (get_armor_class(rogue.armor) * 5);
	freeze_percent -= (rogue.hp_max / 3);

	if (freeze_percent > 10) {
		monster->identified = 1;
		message("you are frozen", 1);

		n = get_rand(5, 9);
		for (i = 0; i < n; i++) {
			move_monsters();
		}
		if (rand_percent(freeze_percent)) {
			for (i = 0; i < 50; i++) {
				move_monsters();
			}
			killed_by((object *)0, HYPOTHERMIA);
		}
		message("you can move again", 1);
		monster->identified = 0;
	}
}

steal_gold(monster)
object *monster;
{
	int amount;

	if (rand_percent(15)) return;

	if (rogue.gold > 50) {
		amount = rogue.gold > 1000 ? get_rand(8, 15) : get_rand(2, 5);
		amount = rogue.gold / amount;
	} else {
		amount = rogue.gold/2;
	}
	amount += (get_rand(0, 2) - 1) * (rogue.exp + current_level);
	if ((amount <= 0) && (rogue.gold > 0)) {
		amount = rogue.gold;
	}

	if (amount > 0) {
		rogue.gold -= amount;
		message("your purse feels lighter", 0);
		print_stats();
	}
	disappear(monster);
}

steal_item(monster)
object *monster;
{
	object *obj;
	short i, n, has_something = 0;
	char description[80];

	if (rand_percent(15)) return;

	obj = rogue.pack.next_object;

	if (!obj) {
		goto DSPR;
	}
	while (obj) {
		if ((obj != rogue.armor) && (obj != rogue.weapon)) {
			has_something = 1;
			break;
		}
		obj = obj->next_object;
	}
	if (!has_something) goto DSPR;

	n = get_rand(0, MAX_PACK_COUNT);
	obj = rogue.pack.next_object;

	for (i = 0; i <= n; i++) {
		obj = obj->next_object;
		while (!obj || (obj == rogue.weapon) || (obj == rogue.armor)) {
			if (!obj) {
				obj = rogue.pack.next_object;
			} else {
				obj = obj->next_object;
			}
		}
	}
	strcpy(description, "she stole ");
	get_description(obj, description+10);
	message(description, 0);

	if (obj->what_is == AMULET) {
		has_amulet = 0;
	}
	vanish(obj, 0);
DSPR:	disappear(monster);
}

disappear(monster)
object *monster;
{
	short row, col;

	row = monster->row;
	col = monster->col;

	remove_mask(row, col, MONSTER);
	if (can_see(row, col)) {
		mvaddch(row, col, get_room_char(screen[row][col], row, col));
	}
	remove_from_pack(monster, &level_monsters);
	free(monster);
}

cough_up(monster)
object *monster;
{
	object *obj, *get_an_object(),*get_rand_object();
	short row, col, i, j, n;

	if (current_level < max_level) {
		return;
	}

	switch(monster->ichar) {
	case 'L':
		obj = get_an_object();
		obj->what_is = GOLD;
		obj->quantity = get_rand(9, 599);
		break;
	default:
		if (rand_percent(monster->which_kind)) {
			obj = get_rand_object();
			break;
		}
		return;
	}
	row = monster->row;
	col = monster->col;

	for (n = 0; n <= 5; n++) {
		for (i = -n; i <= n; i++) {
			if (try_to_cough(row+n, col+i, obj)) {
				return;
			}
			if (try_to_cough(row-n, col+i, obj)) {
				return;
			}
		}
		for (i = -n; i <= n; i++) {
			if (try_to_cough(row+i, col-n, obj)) {
				return;
			}
			if (try_to_cough(row+i, col+n, obj)) {
				return;
			}
		}
	}
	free(obj);
}

try_to_cough(row, col, obj)
short row, col;
object *obj;
{
	if ((row<MIN_ROW)||(row>(LINES-2))||(col<0)||(col>(COLS-1))) {
		return(0);
	}
	if ((!(screen[row][col] & IS_OBJECT)) &&
	    (screen[row][col] & (TUNNEL|FLOOR|DOOR)) &&
	    !(screen[row][col] & MONSTER)) {
		put_object_at(obj, row, col);
		mvaddch(row, col, get_room_char(screen[row][col], row, col));
		refresh();
		return(1);
	}
	return(0);
}

orc_gold(monster)
object *monster;
{
	short i, j, row, col, rn, s;

	if (monster->identified) {
		return(0);
	}
	if ((rn = get_room_number(monster->row, monster->col)) < 0) {
		return(0);
	}
	for (i = rooms[rn].top_row+1;
	i < rooms[rn].bottom_row; i++) {
		for (j = rooms[rn].left_col+1;
		j < rooms[rn].right_col; j++) {
			if ((screen[i][j] & GOLD) &&
			   !(screen[i][j] & MONSTER)) {
				monster->m_flags |= CAN_GO;
				s = monster_can_go(monster, i, j);
				monster->m_flags &= (~CAN_GO);
				if (s) {
					move_monster_to(monster, i, j);
					monster->m_flags |= IS_ASLEEP;
					monster->m_flags &= (~WAKENS);
					monster->identified = 1;
					return(1);
				}
				monster->identified = 1;
				monster->m_flags |= CAN_GO;
				mv_monster(monster, i, j);
				monster->m_flags &= (~CAN_GO);
				monster->identified = 0;
				return(1);
			}
		}
	}
	return(0);
}

check_orc(monster)
object *monster;
{
	if (monster->ichar == 'O') {
		monster->identified = 1;
	}
}

check_xeroc(monster)
object *monster;
{
	char *monster_name();
	char msg[80];

	if ((monster->ichar == 'X') && monster->identified) {
		wake_up(monster);
		monster->identified = 0;
		mvaddch(monster->row, monster->col,
		get_room_char(screen[monster->row][monster->col],
		monster->row, monster->col));
		check_message();
		sprintf(msg, "wait, that's a %s!", monster_name(monster));
		message(msg, 1);
		return(1);
	}
	return(0);
}

hiding_xeroc(row, col)
register short row, col;
{
	object *object_at(), *monster;

	if ((current_level < XEROC1) || (current_level > XEROC2) ||
	    !(screen[row][col] & MONSTER)) {
		return(0);
	}
	monster = object_at(&level_monsters, row, col);

	if ((monster->ichar == 'X') && monster->identified) {
		return(1);
	}
	return(0);
}

sting(monster)
object *monster;
{
	short ac, sting_chance = 35;
	char msg[80], *monster_name();

	if (rogue.strength_current < 5) return;

	ac = get_armor_class(rogue.armor);

	sting_chance += (6 * (6 - ac));

	if (rogue.exp > 8) {
		sting_chance -= (6 * (rogue.exp - 8));
	}

	if (sting_chance > 100) {
		sting_chance = 100;
	} else if (sting_chance <= 0) {
		sting_chance = 1;
	}
	if (rand_percent(sting_chance)) {
		sprintf(msg, "the %s's bite has weakened you",
		monster_name(monster));
		message(msg, 0);
		rogue.strength_current--;
		print_stats();
	}
}

drain_level()
{
	if (!rand_percent(20) || (rogue.exp <= 7)) {
		return;
	}
	rogue.exp_points = level_points[rogue.exp-2] - get_rand(10, 50);
	rogue.exp -= 2;
	add_exp(1);
}

drain_life()
{
	if (!rand_percent(25) || (rogue.hp_max<=30) || (rogue.hp_current<10)) {
		return;
	}
	message("you feel weaker", 0);
	rogue.hp_max--;
	rogue.hp_current--;
	if (rand_percent(50)) {
		if (rogue.strength_current >= 5) {
			rogue.strength_current--;
			if (rand_percent(50)) {
				rogue.strength_max--;
			}
		}
	}
	print_stats();
}

m_confuse(monster)
object *monster;
{
	char msg[80];
	char *monster_name();

	if (monster->identified) {
		return(0);
	}
	if (!can_see(monster->row, monster->col)) {
		return(0);
	}
	if (rand_percent(45)) {
		monster->identified = 1;
		return(0);
	}
	if (rand_percent(55)) {
		monster->identified = 1;
		sprintf(msg, "the gaze of the %s has confused you",
		monster_name(monster));
		message(msg, 1);
		confuse();
		return(1);
	}
	return(0);
}

flame_broil(monster)
object *monster;
{
	short row, col;

	if (!can_see(monster->row, monster->col)) {
		return(0);
	}
	if (rand_percent(50)) {
		return(0);
	}
	if (!rogue_is_around(monster->row, monster->col)) {

		row = monster->row; col = monster->col;
		get_closer(&row, &col, rogue.row, rogue.col);
		standout();
		do {
			mvaddch(row, col, '*');
			refresh();
			get_closer(&row, &col, rogue.row, rogue.col);
		} while ((row != rogue.row) || (col != rogue.col));
		standend();
		row = monster->row; col = monster->col;
		get_closer(&row, &col, rogue.row, rogue.col);
		do {
			mvaddch(row, col, get_room_char(screen[row][col],
				row, col));
			refresh();
			get_closer(&row, &col, rogue.row, rogue.col);
		} while ((row != rogue.row) || (col != rogue.col));
	}
	monster_hit(monster, "flame");
	return(1);
}

get_closer(row, col, trow, tcol)
short *row, *col;
short trow, tcol;
{
	if (*row < trow) {
		(*row)++;
	} else if (*row > trow) {
		(*row)--;
	}
	if (*col < tcol) {
		(*col)++;
	} else if (*col > tcol) {
		(*col)--;
	}
}
SHAR_EOF
echo shar: extracting throw.c
cat - << \SHAR_EOF > throw.c
#include <curses.h>
#include "object.h"
#include "move.h"
#include "monster.h"

extern short current_room;
extern char *CURSE_MESSAGE;
extern char hit_message[];

throw()
{
	short wch;
	short first_miss = 1, f = 1;
	object *weapon, *get_letter_object();
	short dir, row, col;
	object *monster, *get_thrown_at_monster();

	while (!is_direction(dir = getchar())) {
		putchar(7);
		fflush(stdout);
		if (first_miss) {
			message("direction? ", 0);
			first_miss = 0;
		}
	}
	if (dir == CANCEL) {
		check_message();
		return;
	}
	if ((wch = get_pack_letter("throw what?", WEAPON)) == CANCEL) {
		check_message();
		return;
	}
	check_message();

	if (!(weapon = get_letter_object(wch))) {
		message("no such item.", 0);
		return;
	}
	if (weapon->what_is != WEAPON) {
		wch = get_rand(0, 2);

		switch(wch) {
		case 0:
			message("if you don't want it, drop it!", 0);
			break;
		case 1:
			message("throwing that would do noone any good", 0);
			break;
		case 2:
			message("why would you want to throw that?", 0);
			break;
		}
		return;
	}
	if ((weapon == rogue.weapon) && (weapon->is_cursed)) {
		message(CURSE_MESSAGE, 0);
		return;
	}
	row = rogue.row; col = rogue.col;
	monster = get_thrown_at_monster(dir, &row, &col);
	mvaddch(rogue.row, rogue.col, rogue.fchar);
	refresh();

	if (can_see(row, col) && ((row != rogue.row) || (col != rogue.col))) {
		mvaddch(row, col, get_room_char(screen[row][col], row, col));
	}
	if (monster) {
		wake_up(monster);
		check_orc(monster);

		if (!throw_at_monster(monster, weapon)) {
			f = flop_weapon(weapon, row, col);
		}
	} else {
		f = flop_weapon(weapon, row, col);
	}
	vanish(weapon, 1);
}

throw_at_monster(monster, weapon)
object *monster, *weapon;
{
	short damage, hit_chance;
	char *name_of();
	short t;

	hit_chance = get_hit_chance(weapon);
	t = weapon->quantity;
	weapon->quantity = 1;
	sprintf(hit_message, "the %s", name_of(weapon));
	weapon->quantity = t;

	if (!rand_percent(hit_chance)) {
		strcat(hit_message, "misses  ");
		return(0);
	}
	strcat(hit_message, "hit  ");
	damage = get_weapon_damage(weapon);
	if (((weapon->which_kind == ARROW) && (rogue.weapon &&
	   (rogue.weapon->which_kind == BOW))) ||
	   ((weapon->which_kind == SHURIKEN) && (rogue.weapon == weapon))) {
		damage += get_weapon_damage(rogue.weapon);
		damage = ((damage * 2) / 3);
	}
	monster_damage(monster, damage);
	return(1);
}

object *get_thrown_at_monster(dir, row, col)
short dir;
short *row, *col;
{
	object *object_at();
	short orow, ocol;
	short i;

	orow = *row; ocol = *col;

	for (i = 0; i < 24; i++) {
		get_dir_rc(dir, row, col);
		if ((screen[*row][*col] == BLANK) ||
		     (screen[*row][*col] & (HORWALL | VERTWALL))) {
			*row = orow;
			*col = ocol;
			return(0);
		}
		if ((i != 0) && can_see(orow, ocol)) {
			mvaddch(orow, ocol, get_room_char(screen[orow][ocol],
				orow, ocol));
		}
		if (can_see(*row, *col)) {
			if (!(screen[*row][*col] & MONSTER)) {
				mvaddch(*row, *col, ')');
			}
			refresh();
		}
		orow = *row; ocol = *col;
		if (screen[*row][*col] & MONSTER) {
			if (!hiding_xeroc(*row, *col)) {
				return(object_at(&level_monsters, *row, *col));
			}
		}
		if (screen[*row][*col] & TUNNEL) {
			i += 2;
		}
	}
	return(0);
}

flop_weapon(weapon, row, col)
object *weapon;
short row, col;
{
	object *new_weapon, *get_an_object();
	short i, j, r, c, found = 0, inc1, inc2;
	char msg[80];

	inc1 = get_rand(0, 1) ? 1 : -1;
	inc2 = get_rand(0, 1) ? 1 : -1;

	r = row;
	c = col;

	if ((screen[r][c] & ~(FLOOR | TUNNEL | DOOR)) ||
	    ((row == rogue.row) && (col == rogue.col))) {
		for (i = inc1; i != (2 * -inc1); i -= inc1) {
			for (j = inc2; j != (2 * -inc2); j -= inc2) {
				r = row + i;
				c = col + j;

				if ((r > (LINES-2)) || (r < MIN_ROW) ||
				    (c > (COLS-1)) || (c < 0)) {
					continue;
				}
				if (!screen[r][c]) continue;
				if ((screen[r][c] & ~(FLOOR|TUNNEL|DOOR))
				|| ((r == rogue.row) && (c == rogue.col))) {
					continue;
				}
				found = 1;
				goto FOUND;
			}
		}
	} else {
		found = 1;
	}
FOUND:  if (found) {
		new_weapon = get_an_object();
		*new_weapon = *weapon;
		new_weapon->quantity = 1;
		new_weapon->row = r;
		new_weapon->col = c;
		add_mask(r, c, WEAPON);
		add_to_pack(new_weapon, &level_objects, 0);
		if (can_see(r, c)) {
			mvaddch(r, c, get_room_char(screen[r][c], r, c));
		}
	} else {
		short t;

		t = weapon->quantity;
		weapon->quantity = 1;
		sprintf(msg, "the %svanishes as it hits the ground",
		name_of(weapon));
		weapon->quantity = t;
		message(msg, 0);
	}
	return(found);
}
SHAR_EOF
echo shar: extracting use.c
cat - << \SHAR_EOF > use.c
#include <curses.h>
#include "object.h"
#include "move.h"
#include "monster.h"
#include "room.h"

short halluc = 0;
short blind = 0;
short confused = 0;
short detect_monster = 0;

extern short being_held;

char *strange_feeling = "you have a strange feeling for a moment, then it passes";

extern char *hunger_str;
extern short current_room;
extern int level_points[];

quaff()
{
	short ch, i;
	object *obj, *get_letter_object();
	char msg[SCOLS];

	ch = get_pack_letter("quaff what? ", POTION);

	if (ch == CANCEL) {
		return;
	}
	if (!(obj = get_letter_object(ch))) {
		message("no such item.", 0);
		return;
	}
	if (obj->what_is != POTION) {
		message("you can't drink that", 0);
		return;
	}
	switch(obj->which_kind) {
		case INCREASE_STRENGTH:
			message("you feel stronger now, what bulging muscles!",
			0);
			rogue.strength_current++;
			if (rogue.strength_current > rogue.strength_max) {
				rogue.strength_max = rogue.strength_current;
			}
			break;
		case RESTORE_STRENGTH:
			rogue.strength_current = rogue.strength_max;
			message("this tastes great, you feel warm all over", 0);
			break;
		case HEALING:
			message("you begin to feel better", 0);
			potion_heal(0);
			break;
		case EXTRA_HEALING:
			message("you begin to feel much better", 0);
			potion_heal(1);
			break;
		case POISON:
			rogue.strength_current -= get_rand(1, 3);
			if (rogue.strength_current < 0) {
				rogue.strength_current = 0;
			}
			message("you feel very sick now", 0);
			if (halluc) {
				unhallucinate();
			}
			break;
		case RAISE_LEVEL:
			add_exp((level_points[rogue.exp-1]-rogue.exp_points)+1);
			break;
		case BLINDNESS:
			go_blind();
			break;
		case HALLUCINATION:
			message("oh wow, everything seems so cosmic", 0);
			halluc += get_rand(500, 800);
			break;
		case DETECT_MONSTER:
			if (level_monsters.next_object) {
				show_monsters();
			} else {
				message(strange_feeling, 0);
			}
			detect_monster = 1;
			break;
		case DETECT_OBJECTS:
			if (level_objects.next_object) {
				if (!blind) {
					show_objects();
				}
			} else {
				message(strange_feeling, 0);
			}
			break;
		case CONFUSION:
			message((halluc ? "what a trippy feeling" :
			"you feel confused"), 0);
			confuse();
			break;
	}
	print_stats();
	if (id_potions[obj->which_kind].id_status != CALLED) {
		id_potions[obj->which_kind].id_status = IDENTIFIED;
	}
	vanish(obj, 1);
}

read_scroll()
{
	short ch;
	object *obj, *get_letter_object();
	char msg[SCOLS];
	char *get_ench_color();

	ch = get_pack_letter("read what? ", SCROLL);

	if (ch == CANCEL) {
		return;
	}
	if (!(obj = get_letter_object(ch))) {
		message("no such item.", 0);
		return;
	}
	if (obj->what_is != SCROLL) {
		message("you can't read that", 0);
		return;
	}
	switch(obj->which_kind) {
		case SCARE_MONSTER:
			message("you hear a maniacal laughter in the distance",
			0);
			break;
		case HOLD_MONSTER:
			hold_monster();
			break;
		case ENCHANT_WEAPON:
			if (rogue.weapon) {
				sprintf(msg, "your %sglows %sfor a moment",
				id_weapons[rogue.weapon->which_kind].title,
				get_ench_color());
				message(msg, 0);
				if (get_rand(0, 1) == 1) {
					rogue.weapon->to_hit_enchantment++;
				} else {
					rogue.weapon->damage_enchantment++;
				}
				rogue.weapon->is_cursed = 0;
			} else {
				message("your hands tingle", 0);
			}
			break;
		case ENCHANT_ARMOR:
			if (rogue.armor) {
				sprintf(msg, "your armor glows %sfor a moment",
				get_ench_color());
				message(msg, 0);
				rogue.armor->damage_enchantment++;
				rogue.armor->is_cursed = 0;
				print_stats();
			} else {
				message("your skin crawls", 0);
			}
			break;
		case IDENTIFY:
			message("this is a scroll of identify", 0);
			message("what would you like to identify?", 0);
			obj->identified = 1;
			id_scrolls[obj->which_kind].id_status = IDENTIFIED;
			identify();
			break;
		case TELEPORT:
			teleport();
			break;
		case SLEEP:
			sleep_scroll();
			break;
		case PROTECT_ARMOR:
			if (rogue.armor) {
				message( "your armor is covered by a shimmering gold shield", 0);
				rogue.armor->is_protected = 1;
			} else {
				message("your acne seems to have disappeared",
				0);
			}
			break;
		case REMOVE_CURSE:
			message(
			"you feel as though someone is watching over you", 0);
			if (rogue.armor) {
				rogue.armor->is_cursed = 0;
			}
			if (rogue.weapon) {
				rogue.weapon->is_cursed = 0;
			}
			break;
		case CREATE_MONSTER:
			create_monster();
			break;
		case AGGRAVATE_MONSTER:
			aggravate();
			break;
	}
	if (id_scrolls[obj->which_kind].id_status != CALLED) {
		id_scrolls[obj->which_kind].id_status = IDENTIFIED;
	}
	vanish(obj, 1);
}

vanish(obj, rm)
object *obj;
short rm;
{
	if (obj->quantity > 1) {
		obj->quantity--;
	} else {
		remove_from_pack(obj, &rogue.pack);
		make_avail_ichar(obj->ichar);
		free(obj);
	}
	if (rm) {
		register_move();
	}
}

potion_heal(extra)
{
	float ratio;
	short add;

	ratio = ((float)rogue.hp_current) / rogue.hp_max;

	if (ratio >= 0.90) {
		rogue.hp_max += (extra + 1);
		rogue.hp_current = rogue.hp_max;
	} else {
		if (ratio < 30.00) {
			ratio = 30.00;
		}
		if (extra) {
			ratio += ratio;
		}
		add = (short)(ratio*((float)rogue.hp_max-rogue.hp_current));
		rogue.hp_current += add;
		if (rogue.hp_current > rogue.hp_max) {
			rogue.hp_current = rogue.hp_max;
		}
	}
	if (blind) {
		unblind();
	}
	if (confused && extra) {
		unconfuse();
	}
	if (confused) {
		confused = ((confused - 9) / 2);
		if (confused <= 0) {
			unconfuse();
		}
	}
	if (halluc && extra) {
		unhallucinate();
	} else if (halluc) {
		halluc = (halluc/2) + 1;
	}
}

identify()
{
	short ch;
	object *obj, *get_letter_object();
	struct identify *id_table, *get_id_table();
	char description[SCOLS];
AGAIN:
	ch = get_pack_letter("identify what? ", IS_OBJECT);

	if (ch == CANCEL) {
		return;
	}
	if (!(obj = get_letter_object(ch))) {
		message("no such item, try again", 0);
		message("", 0);
		check_message();
		goto AGAIN;
	}
	obj->identified = 1;
	if (obj->what_is & (SCROLL | POTION | WEAPON | ARMOR | WAND)) {
		id_table = get_id_table(obj);
		id_table[obj->which_kind].id_status = IDENTIFIED;
	}
	get_description(obj, description);
	message(description, 0);
}

eat()
{
	short ch;
	short moves;
	object *obj, *get_letter_object();
	char msg[SCOLS];

	ch = get_pack_letter("eat what? ", FOOD);

	if (ch == CANCEL) {
		return;
	}
	if (!(obj = get_letter_object(ch))) {
		message("no such item.", 0);
		return;
	}
	if (obj->what_is != FOOD) {
		message("you can't eat that", 0);
		return;
	}
	moves = get_rand(800, 1000);

	if (moves >= 900) {
		message("yum, that tasted good", 0);
	} else {
		message("yuk, that food tasted awful", 0);
		add_exp(3);
	}
	rogue.moves_left /= 2;
	rogue.moves_left += moves;
	hunger_str = "";
	print_stats();

	vanish(obj, 1);
}

hold_monster()
{
	short i, j;
	short mcount = 0;
	object *monster, *object_at();
	short row, col;

	for (i = -2; i <= 2; i++) {
		for (j = -2; j <= 2; j++) {
			row = rogue.row + i;
			col = rogue.col + j;
			if ((row < MIN_ROW) || (row > (LINES-2)) || (col < 0) ||
			     (col > (COLS-1))) {
				continue;
			}
			if (screen[row][col] & MONSTER) {
				monster = object_at(&level_monsters, row, col);
				monster->m_flags |= IS_ASLEEP;
				monster->m_flags &= (~WAKENS);
				mcount++;
			}
		}
	}
	if (mcount == 0) {
		message("you feel a strange sense of loss", 0);
	} else if (mcount == 1) {
		message("the monster freezes", 0);
	} else {
		message("the monsters around you freeze", 0);
	}
}

teleport()
{
	if (current_room >= 0) {
		darken_room(current_room);
	} else {
		mvaddch(rogue.row, rogue.col,
		get_room_char(screen[rogue.row][rogue.col], rogue.row,
		rogue.col));
	}
	put_player();
	light_up_room();
	being_held = 0;
}

hallucinate()
{
	object *obj;
	short ch;

	if (blind) return;

	obj = level_objects.next_object;

	while (obj) {
		move(obj->row, obj->col);
		ch = inch();
		if (((ch < 'A') || (ch > 'Z')) &&
		    ((obj->row != rogue.row) || (obj->col != rogue.col)))
		if ((ch != ' ')&&(ch != '.')&&(ch != '#')&&(ch != '+')) {
			mvaddch(obj->row, obj->col, get_rand_obj_char());
		}
		obj = obj->next_object;
	}
	obj = level_monsters.next_object;

	while (obj) {
		move(obj->row, obj->col);
		ch = inch();
		if ((ch >= 'A') && (ch <= 'Z')) {
			mvaddch(obj->row,obj->col,get_rand('A','Z'));
		}
		obj = obj->next_object;
	}
}

unhallucinate()
{
	halluc = 0;
	if (current_room == PASSAGE) {
		light_passage(rogue.row, rogue.col);
	} else {
		light_up_room();
	}
	message("everything looks SO boring now", 0);
}

unblind()
{
	blind = 0;
	message("the veil of darkness lifts", 0);
	if (current_room == PASSAGE) {
		light_passage(rogue.row, rogue.col);
	} else {
		light_up_room();
	}
	blind = 0;
	if (detect_monster) {
		show_monsters();
	}
	if (halluc) {
		hallucinate();
	}
}

sleep_scroll()
{
	short i;

	message("you fall asleep", 0);
	sleep(1);
	i = get_rand(4, 10);

	while (i--) {
		move_monsters();
	}
	sleep(1);
	message("you can move again", 0);
}

go_blind()
{
	short i, j;

	if (!blind) {
		message("a cloak of darkness falls around you", 0);
	}
	blind += get_rand(500, 800);

	if (current_room >= 0) {
		for (i = rooms[current_room].top_row + 1;
		     i < rooms[current_room].bottom_row; i++) {
			for (j = rooms[current_room].left_col + 1;
			     j < rooms[current_room].right_col; j++) {
				mvaddch(i, j, ' ');
			}
		}
	}
	mvaddch(rogue.row, rogue.col, rogue.fchar);
	refresh();
}

char *get_ench_color()
{
	if (halluc) {
		return(id_potions[get_rand(0, POTIONS-1)].title);
	}
	return("blue ");
}

confuse()
{
	confused = get_rand(12, 22);
}

unconfuse()
{
	char msg[80];

	confused = 0;
	sprintf(msg, "you feel less %s now", (halluc ? "trippy" : "confused"));
	message(msg, 0);
}
SHAR_EOF
echo shar: extracting zap.c
cat - << \SHAR_EOF > zap.c
#include <curses.h>
#include "object.h"
#include "move.h"
#include "monster.h"

extern short current_room, being_held, current_level;

zapp()
{
	short wch;
	short first_miss = 1;
	object *wand, *get_letter_object();
	short dir, row, col;
	object *monster, *get_zapped_monster();

	while (!is_direction(dir = getchar())) {
		putchar(7);
		fflush(stdout);
		if (first_miss) {
			message("direction? ", 0);
			first_miss = 0;
		}
	}
	if (dir == CANCEL) {
		check_message();
		return;
	}
	if ((wch = get_pack_letter("zap with what?", WAND)) == CANCEL) {
		check_message();
		return;
	}
	check_message();

	if (!(wand = get_letter_object(wch))) {
		message("no such item.", 0);
		return;
	}
	if (wand->what_is != WAND) {
		message("you can't zap with that", 0);
		return;
	}
	if (wand->class <= 0) {
		message("nothing happens", 0);
		goto RM;
	} else {
		wand->class--;
	}
	row = rogue.row; col = rogue.col;
	monster = get_zapped_monster(dir, &row, &col);
	if (monster != 0) {
		wake_up(monster);
		zap_monster(monster, wand->which_kind);
	}
RM:	register_move();
}

object *get_zapped_monster(dir, row, col)
short dir;
short *row, *col;
{
	object *object_at();
	short orow, ocol;
	short i;

	for (;;) {
		orow = *row; ocol = *col;
		get_dir_rc(dir, row, col);
		if (((*row == orow) && (*col == ocol)) ||
		   (screen[*row][*col] & (HORWALL | VERTWALL)) ||
		   (screen[*row][*col] == BLANK)) {
			return(0);
		}
		if (screen[*row][*col] & MONSTER) {
			if (!hiding_xeroc(*row, *col)) {
				return(object_at(&level_monsters, *row, *col));
			}
		}
	}
}

zap_monster(monster, kind)
object *monster;
short kind;
{
	short row, col;
	struct object *nm;

	row = monster->row;
	col = monster->col;
	nm = monster->next_object;

	switch(kind) {
	case SLOW_MONSTER:
		if (monster->m_flags & HASTED) {
			monster->m_flags &= (~HASTED);
		} else {
			monster->quiver = 0;
			monster->m_flags |= SLOWED;
		}
		break;
	case HASTE_MONSTER:
		if (monster->m_flags & SLOWED) {
			monster->m_flags &= (~SLOWED);
		} else {
			monster->m_flags |= HASTED;
		}
		break;
	case TELEPORT_AWAY:
		teleport_away(monster);
		break;
	case KILL_MONSTER:
		rogue.exp_points -= monster->kill_exp;
		monster_damage(monster, monster->quantity);
		break;
	case INVISIBILITY:
		monster->m_flags |= IS_INVIS;
		mvaddch(row, col, get_monster_char(monster));
		break;
	case POLYMORPH:
		if (monster->ichar == 'F') {
			being_held = 0;
		}
MA:		*monster = monster_tab[get_rand(0, MONSTERS-1)];
		if ((monster->ichar == 'X') && ((current_level < XEROC1) ||
		    (current_level > XEROC2))) {
			goto MA;
		}
		monster->what_is = MONSTER;
		monster->row = row; monster->col = col;
		monster->next_object = nm;
		wake_up(monster);
		if (can_see(row, col)) {
			mvaddch(row, col, get_monster_char(monster));
		}
		break;
	case PUT_TO_SLEEP:
		monster->m_flags |= IS_ASLEEP;
		monster->m_flags &= (~WAKENS);
		break;
	case DO_NOTHING:
		message("nothing happens", 0);
		break;
	}
}

teleport_away(monster)
object *monster;
{
	short row, col;

	if (monster->ichar == 'F') {
		being_held = 0;
	}
	get_rand_row_col(&row, &col, (FLOOR | TUNNEL | IS_OBJECT));
	remove_mask(monster->row, monster->col, MONSTER);
	mvaddch(monster->row, monster->col,
	get_room_char(screen[monster->row][monster->col], monster->row,
	monster->col));

	monster->row = row; monster->col = col;
	add_mask(row, col, MONSTER);

	if (can_see(row, col)) {
		mvaddch(row, col, get_monster_char(monster));
	}
}
SHAR_EOF

todd@bucsd.UUCP (Todd Cooper) (03/01/86)

Please note:
This works no 42BSD, but *NOT* SYSV -- I am working on the SYSV port.


-- 
---------------------------
Todd Cooper

UUCP:	...!harvard!bu-cs!todd ...!harvard!think!festiv!todd
CSNET:	todd@bu-cs
BITNET:	cscpyqc@bostonu
USNail:	29 Gordon Street #201, Brighton, MA 02135

jcz@ncsu.UUCP (John A. Toebes, VIII) (03/03/86)

I am working on porting it to the Amiga.

jcz@ncsu.UUCP (John A. Toebes, VIII) (03/03/86)

Oops, stopped too early.  I am in the process of porting the code to the
Amiga.  It is an excellent job of writing the code, I believe that the 
termcap/window stuff from Hack can readily step in in the shoes of the curses
stuff.

John A. Toebes, VIII
120-H Northington Place
Cary NC 27511
(919) 469-4210
   ...mcnc!ncsu!jcz