[net.sources.games] For rogue 5.3 lovers, part 1 of 4

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

This is an excellent imitation of rogue 5.3, a clone, if you will.  This
is the same program I distributed a year or two ago, but with innumerable
significant improvements and much greater completeness and robustness.
For those of you who would have this posted instead to mod.sources; I
definately consider this program to be different enough to be considered
a new program.

#!/bin/sh-----cut here-----cut here-----cut here-----cut here-----
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	Makefile #	hit.c #	init.c #	inventory.c #	level.c #	zap.c 
echo shar: extracting Makefile
cat - << \SHAR_EOF > Makefile
ROGUE_OBJS = hit.o init.o inventory.o level.o main.o \
    message.o monster.o move.o object.o pack.o play.o random.o ring.o \
    room.o save.o score.o special_hit.o throw.o trap.o use.o zap.o

CC = cc

CFLAGS = -c

rogue: $(ROGUE_OBJS)
	$(CC) $(ROGUE_OBJS) -lcurses -ltermlib -o rogue

hit.o: hit.c object.h move.h monster.h room.h
	$(CC) $(CFLAGS) hit.c

init.o: init.c object.h room.h
	$(CC) $(CFLAGS) init.c

inventory.o: inventory.c object.h move.h
	$(CC) $(CFLAGS) inventory.c

level.o: level.c move.h object.h room.h
	$(CC) $(CFLAGS) level.c

main.o: main.c object.h room.h
	$(CC) $(CFLAGS) main.c

message.o: message.c object.h move.h room.h
	$(CC) $(CFLAGS) message.c

monster.o: monster.c monster.h object.h room.h move.h
	$(CC) $(CFLAGS) monster.c

move.o: move.c object.h room.h move.h monster.h
	$(CC) $(CFLAGS) move.c

object.o: object.c object.h monster.h room.h
	$(CC) $(CFLAGS) object.c

pack.o: pack.c move.h object.h room.h
	$(CC) $(CFLAGS) pack.c

play.o: play.c object.h move.h
	$(CC) $(CFLAGS) play.c

random.o: random.c
	$(CC) $(CFLAGS) random.c

ring.o: ring.c object.h move.h room.h
	$(CC) $(CFLAGS) ring.c

room.o: room.c room.h object.h move.h
	$(CC) $(CFLAGS) room.c

save.o: save.c room.h object.h room.h
	$(CC) $(CFLAGS) save.c

score.o: score.c object.h monster.h room.h
	$(CC) $(CFLAGS) score.c

special_hit.o: special_hit.c object.h move.h monster.h room.h
	$(CC) $(CFLAGS) special_hit.c

throw.o: throw.c object.h move.h monster.h
	$(CC) $(CFLAGS) throw.c

trap.o: trap.c room.h object.h move.h monster.h
	$(CC) $(CFLAGS) trap.c

use.o: use.c object.h move.h monster.h room.h
	$(CC) $(CFLAGS) use.c

zap.o: zap.c object.h move.h monster.h
	$(CC) $(CFLAGS) zap.c
SHAR_EOF
echo shar: extracting hit.c
cat - << \SHAR_EOF > hit.c
/*
 * hit.c
 *
 * This source herein may be modified and/or distributed by anybody who
 * so desires, with the following restrictions:
 *    1.)  This notice shall not be removed.
 *    2.)  Credit shall not be taken for the creation of this source.
 *    3.)  This code is not to be traded, sold, or used for personal
 *         gain or profit.
 *
 */

#include <curses.h>
#include "object.h"
#include "move.h"
#include "monster.h"
#include "room.h"

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

extern short halluc, blind, current_level;
extern short add_strength, ring_exp, r_rings;
extern boolean being_held, interrupted, wizard;

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

	if (fight_monster && (monster != fight_monster)) {
		fight_monster = 0;
	}
	monster->trow = NO_ROOM;
	if (current_level >= (AMULET_LEVEL * 2)) {
		hit_chance = 100;
	} else {
		hit_chance = monster->m_hit_chance;
		hit_chance -= (((2 * rogue.exp) + (2 * ring_exp)) - r_rings);
	}
	if (wizard) {
		hit_chance /= 2;
	}
	if (!fight_monster) {
		interrupted = 1;
	}
	mn = monster_name(monster);

	if (other) {
		hit_chance -= ((rogue.exp + ring_exp) - r_rings);
	}

	if (!rand_percent(hit_chance)) {
		if (!fight_monster) {
			sprintf(hit_message + strlen(hit_message),
			"the %s misses", (other ? other : mn));
			message(hit_message, 1);
			hit_message[0] = 0;
		}
		return;
	}
	if (!fight_monster) {
		sprintf(hit_message + strlen(hit_message), "the %s hit",
			(other ? other : mn));
		message(hit_message, 1);
		hit_message[0] = 0;
	}
	if (!(monster->m_flags & STATIONARY)) {
		damage = get_damage(monster->m_damage, 1);
		if (other) {
			if (flame) {
				if ((damage -= get_armor_class(rogue.armor)) < 0) {
					damage = 1;
				}
			}
		}
		if (current_level >= (AMULET_LEVEL * 2)) {
			minus = (float) ((AMULET_LEVEL * 2) - current_level);
		} else {
			minus = (float) get_armor_class(rogue.armor) * 3.00;
			minus = minus/100.00 * (float) damage;
		}
		damage -= (short) minus;
	} else {
		damage = monster->stationary_damage++;
	}
	if (wizard) {
		damage /= 3;
	}
	if (damage > 0) {
		rogue_damage(damage, monster);
	}
	if (monster->m_flags & SPECIAL_HIT) {
		special_hit(monster);
	}
}

rogue_hit(monster, force_hit)
register object *monster;
boolean force_hit;
{
	short damage, hit_chance;
	char *monster_name();

	if (monster) {
		if (check_imitator(monster)) {
			return;
		}
		hit_chance = force_hit ? 100 : get_hit_chance(rogue.weapon);

		if (wizard) {
			hit_chance *= 2;
		}
		if (!rand_percent(hit_chance)) {
			if (!fight_monster) {
				strcpy(hit_message, "you miss  ");
			}
			goto RET;
		}
		damage = get_weapon_damage(rogue.weapon);
		if (wizard) {
			damage *= 3;
		}
		if (monster_damage(monster, damage)) {	/* still alive? */
			if (!fight_monster) {
				strcpy(hit_message, "you hit  ");
			}
		}
RET:	check_gold_seeker(monster);
		wake_up(monster);
	}
}

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

get_damage(ds, r)
char *ds;
boolean r;
{
	register 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 to_hit, damage;
	register i = 0;

	if ((!obj) || (obj->what_is != WEAPON)) {
		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 i = 0;
	register total = 0;

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

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

damage_for_strength()
{
	short strength;

	strength = rogue.strength_current + add_strength;

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

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

	monster->hp_to_kill -= damage;

	if (monster->hp_to_kill <= 0) {
		row = monster->row;
		col = monster->col;
		dungeon[row][col] &= ~MONSTER;
		mvaddch(row, col, get_dungeon_char(row, col));

		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, 1);
		remove_from_pack(monster, &level_monsters);

		if (monster->m_flags & HOLDS) {
			being_held = 0;
		}
		free_object(monster);
		return(0);
	}
	return(1);
}

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

	while (!is_direction(ch = rgetchar())) {
		sound_bell();
		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, 0);

	c = mvinch(row, col);
	if (((c < 'A') || (c > 'Z')) ||
		(!can_move(rogue.row, rogue.col, row, col))) {
		message("I see no monster there", 0);
		return;
	}
	if (!(fight_monster = object_at(&level_monsters, row, col))) {
		return;
	}
	if (!(fight_monster->m_flags & STATIONARY)) {
		possible_damage = ((get_damage(fight_monster->m_damage, 0) * 2) / 3);
	} else {
		possible_damage = fight_monster->stationary_damage - 1;
	}
	while (fight_monster) {
		single_move_rogue(ch, 0);
		if (((!to_the_death) && (rogue.hp_current <= possible_damage)) ||
			interrupted || (!(dungeon[row][col] & MONSTER))) {
			fight_monster = 0;
		} else {
			monster = object_at(&level_monsters, row, col);
			if (monster != fight_monster) {
				fight_monster = 0;
			}
		}
	}
}

get_dir_rc(dir, row, col, allow_off_screen)
short dir;
short *row, *col;
short allow_off_screen;
{
	switch(dir) {
	case 'h':
		if (allow_off_screen || (*col > 0)) {
			(*col)--;
		}
		break;
	case 'j':
		if (allow_off_screen || (*row < (DROWS-2))) {
			(*row)++;
		}
		break;
	case 'k':
		if (allow_off_screen || (*row > MIN_ROW)) {
			(*row)--;
		}
		break;
	case 'l':
		if (allow_off_screen || (*col < (DCOLS-1))) {
			(*col)++;
		}
		break;
	case 'y':
		if (allow_off_screen || ((*row > MIN_ROW) && (*col > 0))) {
			(*row)--;
			(*col)--;
		}
		break;
	case 'u':
		if (allow_off_screen || ((*row > MIN_ROW) && (*col < (DCOLS-1)))) {
			(*row)--;
			(*col)++;
		}
		break;
	case 'n':
		if (allow_off_screen || ((*row < (DROWS-2)) && (*col < (DCOLS-1)))) {
			(*row)++;
			(*col)++;
		}
		break;
	case 'b':
		if (allow_off_screen || ((*row < (DROWS-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 += (((2 * rogue.exp) + (2 * ring_exp)) - r_rings);
	return(hit_chance);
}

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

	damage = get_w_damage(weapon);
	damage += damage_for_strength();
	damage += ((((rogue.exp + ring_exp) - r_rings) + 1) / 2);
	return(damage);
}
SHAR_EOF
echo shar: extracting init.c
cat - << \SHAR_EOF > init.c
/*
 * init.c
 *
 * This source herein may be modified and/or distributed by anybody who
 * so desires, with the following restrictions:
 *    1.)  This notice shall not be removed.
 *    2.)  Credit shall not be taken for the creation of this source.
 *    3.)  This code is not to be traded, sold, or used for personal
 *         gain or profit.
 *
 */

#include <curses.h>
#include "object.h"
#include "room.h"
#include <sgtty.h>
#include <signal.h>

char login_name[30];
char *nick_name = "";
char *restore_file = 0;
boolean cant_int = 0, did_int = 0, score_only, init_curses = 0;
boolean save_is_interactive = 1;
boolean ask_quit = 1, show_skull = 1;
char *error_file = "rogue.save.after.error";
char *byebye_string = "Okay, bye bye!";

extern char *fruit;
extern char *save_file;
extern short party_room, party_counter;
extern boolean jump;

init(argc, argv)
int argc;
char *argv[];
{
	char *getlogin(), *pn;

	process_args(argc, argv);
	process_opts();

	if (!(pn = getlogin())) {
		clean_up("Hey!  Who are you?");
	}
	strcpy(login_name, pn);

	if (!score_only && !restore_file) {
		printf("Hello %s, just a moment while I dig the dungeon...",
		(nick_name[0]) ? nick_name : login_name);
		fflush(stdout);
	}

	initscr();
	if ((LINES < DROWS) || (COLS < DCOLS)) {
		clean_up("must be played on 24 x 80 screen");
	}
	start_window();
	init_curses = 1;

	heed_signals();

	if (score_only) {
		put_scores(0, 0);
	}
	srandom(getpid());
	if (restore_file) {
		restore(restore_file);
		return(1);
	}
	shuffle_colors();
	get_wand_and_ring_materials();
	make_scroll_titles();

	level_objects.next_object = 0;
	level_monsters.next_monster = 0;
	player_init();
	party_counter = get_rand(1, PARTY_TIME);
	ring_stats(0);
	return(0);
}

player_init()
{
	object *alloc_object(), *obj, *add_to_pack();

	rogue.pack.next_object = 0;

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

	obj = alloc_object();		/* initial armor */
	obj->what_is = ARMOR;
	obj->which_kind = RINGMAIL;
	obj->class = RINGMAIL+2;
	obj->is_protected = 0;
	obj->damage_enchantment = 1;
	add_to_pack(obj, &rogue.pack, 1);
	do_wear(obj);

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

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

	obj = alloc_object();
	obj->what_is = WEAPON;
	obj->which_kind = ARROW;
	obj->quantity = get_rand(25, 35);
	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;
{
	if (save_is_interactive) {
		if (init_curses) {
			move(DROWS-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()
{
	if (ask_quit) {
		quit(1);
	} else {
		clean_up(byebye_string);
	}
}

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

error_save()
{
	save_is_interactive = 0;
	save_into_file(error_file);
	clean_up("");
}

edchars(mode)
short mode;
{
	static boolean 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;
		tc_temp.t_startc = tc_temp.t_stopc = -1;
	}
	ioctl(0, TIOCSETC, &tc_temp);
	ioctl(0, TIOCSLTC, &ltc_temp);
}

process_args(argc, argv)
int argc;
char *argv[];
{
	short i, j;

	for (i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			for (j = 1; argv[i][j]; j++) {
				switch(argv[i][j]) {
				case 's':
					score_only = 1;
					break;
				}
			}
		} else {
			restore_file = argv[i];
		}
	}
}

process_opts()
{
	char *getenv(), *eptr;

	if (eptr = getenv("ROGUEOPTS")) {
		for (;;) {
			while ((*eptr) == ' ') {
				eptr++;
			}
			if (!(*eptr)) {
				break;
			}
			if (!strncmp(eptr, "fruit=", 6)) {
				eptr += 6;
				env_get_value(&fruit, eptr, 1);
			} else if (!strncmp(eptr, "file=", 5)) {
				eptr += 5;
				env_get_value(&save_file, eptr, 0);
			} else if (!strncmp(eptr, "nojump", 6)) {
				jump = 0;
			} else if (!strncmp(eptr, "name=", 5)) {
				eptr += 5;
				env_get_value(&nick_name, eptr, 0);
			} else if (!strncmp(eptr, "noaskquit", 9)) {
				ask_quit = 0;
			} else if (!strncmp(eptr, "noskull", 5) ||
					!strncmp(eptr,"notomb", 6)) {
				show_skull = 0;
			}
			while ((*eptr) && (*eptr != ',')) {
				eptr++;
			}
			if (!(*(eptr++))) {
				break;
			}
		}
	}
}

env_get_value(s, e, add_blank)
char **s, *e;
boolean add_blank;
{
	short i = 0;
	char *malloc(), *t;

	t = e;

	while ((*e) && (*e != ',')) {
		if (*e == ':') {
			*e = ';';		/* ':' reserved for score file purposes */
		}
		e++;
		if (++i >= 30) {
			break;
		}
	}
	if (!(*s = malloc(i + (add_blank ? 2 : 1)))) {
		clean_up("cannot malloc() memory");
	}
	strncpy(*s, t, i);
	if (add_blank) {
		(*s)[i++] = ' ';
	}
	(*s)[i] = '\0';
}

ignore_signals()
{
	signal(SIGQUIT, SIG_IGN);
	signal(SIGINT, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
}

heed_signals()
{
	int byebye(), onintr(), error_save();

	signal(SIGINT, onintr);
	signal(SIGQUIT, byebye);
	signal(SIGHUP, error_save);
}
SHAR_EOF
echo shar: extracting inventory.c
cat - << \SHAR_EOF > inventory.c
/*
 * inventory.c
 *
 * This source herein may be modified and/or distributed by anybody who
 * so desires, with the following restrictions:
 *    1.)  This notice shall not be removed.
 *    2.)  Credit shall not be taken for the creation of this source.
 *    3.)  This code is not to be traded, sold, or used for personal
 *         gain or profit.
 *
 */

#include <curses.h>
#include "object.h"
#include "move.h"

#define swap_string(x,y) {t = x; x = y; y = t;}

boolean is_wood[WANDS];

char *wand_materials[WAND_MATERIALS] = {
	"steel ",
	"bronze ",
	"gold ",
	"silver ",
	"copper ",
	"nickel ",
	"cobalt ",
	"tin ",
	"iron ",
	"magnesium ",
	"chrome ",
	"carbon ",
	"platinum ",
	"silicon ",
	"titanium ",

	"teak ",
	"oak ",
	"cherry ",
	"birch ",
	"pine ",
	"cedar ",
	"redwood ",
	"balsa ",
	"ivory ",
	"walnut ",
	"maple ",
	"mahogany ",
	"elm ",
	"palm ",
	"wooden "
};

char *gems[GEMS] = {
	"diamond ",
	"stibotantalite ",
	"lapi-lazuli ",
	"ruby ",
	"emerald ",
	"sapphire ",
	"amethyst ",
	"quartz ",
	"tiger-eye ",
	"opal ",
	"agate ",
	"turquoise ",
	"pearl ",
	"garnet "
};

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 "
};

extern boolean wizard;

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

	obj = pack->next_object;

	if (!obj) {
		message("your pack is empty", 0);
		return;
	}
	while (obj) {
		if (obj->what_is & mask) {
			descriptions[i][0] = ' ';
			descriptions[i][1] = obj->ichar;
			descriptions[i][2] = ((obj->what_is & ARMOR) && obj->is_protected)
				? '}' : ')';
			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 = DCOLS - (maxlen + 2);

	for (row = 0; ((row < i) && (row < DROWS)); row++) {
		if (row > 0) {
			for (j = col; j < DCOLS; 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;
	char *t;

	for (i = 0; i <= 32; 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];
	short i;

	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) {
		if (obj->which_kind == RATION) {
			if (obj->quantity > 1) {
				sprintf(description, "%d rations of ", obj->quantity);
			} else {
				strcpy(description, "some ");
			}
		} else {
			strcpy(description, "a ");
		}
		strcat(description, item_name);
		goto ANA;
	}
	id_table = get_id_table(obj);

	if (wizard) {
		goto ID;
	}
	if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) {
		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:
		case RING:
			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));
			break;
		}
		break;
	case CALLED:
CALL:	switch(obj->what_is) {
		case SCROLL:
		case POTION:
		case WAND:
		case RING:
			strcat(description, item_name);
			strcat(description, "called ");
			strcat(description, id_table[obj->which_kind].title);
			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 RING:
			if (wizard || obj->identified) {
				if ((obj->which_kind == DEXTERITY) ||
					(obj->which_kind == ADD_STRENGTH)) {
					sprintf(more_info, "%s%d ", ((obj->class > 0) ? "+" : ""),
						obj->class);
					strcat(description, more_info);
				}
			}
			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);
			if (wizard || 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);
			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));
			break;
		}
		break;
	}
ANA:
	if (!strncmp(description, "a ", 2)) {
		if (is_vowel(description[2])) {
			for (i = strlen(description) + 1; i > 1; i--) {
				description[i] = description[i-1];
			}
			description[1] = 'n';
		}
	}
	if (obj->in_use_flags & BEING_WIELDED) {
		strcat(description, "in hand");
	} else if (obj->in_use_flags & BEING_WORN) {
		strcat(description, "being worn");
	} else if (obj->in_use_flags & ON_LEFT_HAND) {
		strcat(description, "on left hand");
	} else if (obj->in_use_flags & ON_RIGHT_HAND) {
		strcat(description, "on right hand");
	}
}

get_wand_and_ring_materials()
{
	short i, j;
	boolean used[WAND_MATERIALS];

	for (i = 0; i < WAND_MATERIALS; i++) {
		used[i] = 0;
	}
	for (i = 0; i < WANDS; i++) {
		do {
			j = get_rand(0, WAND_MATERIALS-1);
		} while (used[j]);
		used[j] = 1;
		strcpy(id_wands[i].title, wand_materials[j]);
		is_wood[i] = (j > MAX_METAL);
	}
	for (i = 0; i < GEMS; i++) {
		used[i] = 0;
	}
	for (i = 0; i < RINGS; i++) {
		do {
			j = get_rand(0, GEMS-1);
		} while (used[j]);
		used[j] = 1;
		strcpy(id_rings[i].title, gems[j]);
	}
}

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

	ch = ichar ? ichar : get_pack_letter("inventory what?", ALL_OBJECTS);

	if (ch == CANCEL) {
		return;
	}
	if (!(obj = get_letter_object(ch))) {
		message("no such item.", 0);
		return;
	}
	description[0] = ch;
	description[1] = ((obj->what_is & ARMOR) && obj->is_protected) ? '}' : ')';
	description[2] = ' ';
	description[3] = 0;
	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);
	case POTION:
		return(id_potions);
	case WAND:
		return(id_wands);
	case RING:
		return(id_rings);
	case WEAPON:
		return(id_weapons);
	case ARMOR:
		return(id_armors);
	}
	return((struct identify *) 0);
}

inventory_armor_weapon(is_weapon)
boolean is_weapon;
{
	if (is_weapon) {
		if (rogue.weapon) {
			single_inventory(rogue.weapon->ichar);
		} else {
			message("not wielding anything");
		}
	} else {
		if (rogue.armor) {
			single_inventory(rogue.armor->ichar);
		} else {
			message("not wearing anything");
		}
	}
}
SHAR_EOF
echo shar: extracting level.c
cat - << \SHAR_EOF > level.c
/*
 * level.c
 *
 * This source herein may be modified and/or distributed by anybody who
 * so desires, with the following restrictions:
 *    1.)  This notice shall not be removed.
 *    2.)  Credit shall not be taken for the creation of this source.
 *    3.)  This code is not to be traded, sold, or used for personal
 *         gain or profit.
 *
 */

#include <curses.h>
#include "move.h"
#include "object.h"
#include "room.h"

#define swap(x,y) {t = x; x = y; y = t;}

short current_level = 0, max_level = 1;
char *new_level_message = 0;
short party_room = NO_ROOM;
short r_de;

long level_points[MAX_EXP_LEVEL] = {
		  10L,
		  20L,
		  40L,
		  80L,
		 160L,
		 320L,
		 640L,
		1300L,
		2600L,
		5200L,
	   10000L,
	   20000L,
	   40000L,
	   80000L,
	  160000L,
	  320000L,
	 1000000L,
	 3333333L,
	 6666666L,
	  MAX_EXP,
	99900000L
};

char random_rooms[MAXROOMS+1] = "\003\007\005\002\010\006\001\004\0";

extern boolean being_held, wizard, detect_monster;
extern boolean see_invisible;
extern short bear_trap, levitate, extra_hp, less_hp, current_room;
extern short party_counter;

make_level()
{
	short i, j;
	short must_exist1, must_exist2, must_exist3;
	boolean big_room;

	if (current_level < LAST_DUNGEON) {
		current_level++;
	}
	if (current_level > max_level) {
		max_level = current_level;
	}
	must_exist1 = get_rand(0, 5);

	switch(must_exist1) {
	case 0:
		must_exist1 = 0;
		must_exist2 = 1;
		must_exist3 = 2;
		break;
	case 1:
		must_exist1 = 3;
		must_exist2 = 4;
		must_exist3 = 5;
		break;
	case 2:
		must_exist1 = 6;
		must_exist2 = 7;
		must_exist3 = 8;
		break;
	case 3:
		must_exist1 = 0;
		must_exist2 = 3;
		must_exist3 = 6;
		break;
	case 4:
		must_exist1 = 1;
		must_exist2 = 4;
		must_exist3 = 7;
		break;
	case 5:
		must_exist1 = 2;
		must_exist2 = 5;
		must_exist3 = 8;
		break;
	}
	big_room = ((current_level == party_counter) && rand_percent(1));
	if (big_room) {
		make_room(BIG_ROOM, 0, 0, 0);
	} else {
		for (i = 0; i < MAXROOMS; i++) {
			make_room(i, must_exist1, must_exist2, must_exist3);
		}
	}
	if (!big_room) {
		add_mazes();

		shuffle_random_rooms();

		for (j = 0; j < MAXROOMS; j++) {

			i = random_rooms[j];

			if (i < (MAXROOMS-1)) {
				connect_rooms(i, i+1);
			}
			if (i < (MAXROOMS-3)) {
				connect_rooms(i, i+3);
			}
			if (i < (MAXROOMS-2)) {
				if (rooms[i+1].is_room & R_NOTHING) {
					if (connect_rooms(i, i+2)) {
						rooms[i+1].is_room = R_CROSS;
					}
				}
			}
			if (i < (MAXROOMS-6)) {
				if (rooms[i+3].is_room & R_NOTHING) {
					if (connect_rooms(i, i+6)) {
						rooms[i+3].is_room = R_CROSS;
					}
				}
			}
			if (is_all_connected()) {
				break;
			}
		}
		fill_out_level();
	}
	if (!has_amulet() && (current_level >= AMULET_LEVEL)) {
		put_amulet();
	}
}

make_room(rn, r1, r2, r3)
short rn, 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(rn) {
	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 = DCOLS-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 = DCOLS-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 = DROWS - 2;
		break;
	case 7:
		left_col = COL1+1;
		right_col = COL2-1;
		top_row = ROW2+1;
		bottom_row = DROWS - 2;
		break;
	case 8:
		left_col = COL2+1;
		right_col = DCOLS-1;
		top_row = ROW2+1;
		bottom_row = DROWS - 2;
		break;
	case BIG_ROOM:
		top_row = get_rand(MIN_ROW, MIN_ROW+5);
		bottom_row = get_rand(DROWS-7, DROWS-2);
		left_col = get_rand(0, 10);;
		right_col = get_rand(DCOLS-11, DCOLS-1);
		rn = 0;
		goto B;
	}
	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;

	if ((rn != r1) && (rn != r2) && (rn != r3) && rand_percent(40)) {
		goto END;
	}
B:
	rooms[rn].is_room = R_ROOM;

	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;
			}
			dungeon[i][j] = ch;
		}
	}
END:
	rooms[rn].top_row = top_row;
	rooms[rn].bottom_row = bottom_row;
	rooms[rn].left_col = left_col;
	rooms[rn].right_col = right_col;
}

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

	if ((!(rooms[room1].is_room & (R_ROOM | R_MAZE))) ||
		(!(rooms[room2].is_room & (R_ROOM | R_MAZE)))) {
		return(0);
	}
	if (on_same_row(room1, room2) &&
		(rooms[room1].left_col > rooms[room2].right_col)) {
		put_door(&rooms[room1], LEFT, &row1, &col1);
		put_door(&rooms[room2], RIGHT, &row2, &col2);
		dir = LEFT;
	} else if (on_same_row(room1, room2) &&
		(rooms[room2].left_col > rooms[room1].right_col)) {
		put_door(&rooms[room1], RIGHT, &row1, &col1);
		put_door(&rooms[room2], LEFT, &row2, &col2);
		dir = RIGHT;
	} else if (on_same_col(room1, room2) &&
		(rooms[room1].top_row > rooms[room2].bottom_row)) {
		put_door(&rooms[room1], UP, &row1, &col1);
		put_door(&rooms[room2], DOWN, &row2, &col2);
		dir = UP;
	} else if (on_same_col(room1, room2) &&
		(rooms[room2].top_row > rooms[room1].bottom_row)) {
		put_door(&rooms[room1], DOWN, &row1, &col1);
		put_door(&rooms[room2], UP, &row2, &col2);
		dir = DOWN;
	} else {
		return(0);
	}

	do {
		draw_simple_passage(row1, col1, row2, col2, dir);
	} while (rand_percent(4));

	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)%DIRS)/2)].other_room = room1;
	rooms[room2].doors[(((dir+4)%DIRS)/2)].other_row = row1;
	rooms[room2].doors[(((dir+4)%DIRS)/2)].other_col = col1;
	return(1);
}

clear_level()
{
	short i, j;

	for (i = 0; i < MAXROOMS; i++) {
		rooms[i].is_room = R_NOTHING;
		for (j = 0; j < 4; j++) {
			rooms[i].doors[j].other_room = NO_ROOM;
		}
	}

	for (i = 0; i < MAX_TRAPS; i++) {
		traps[i].trap_type = NO_TRAP;
	}
	for (i = 0; i < DROWS; i++) {
		for (j = 0; j < DCOLS; j++) {
			dungeon[i][j] = NOTHING;
		}
	}
	detect_monster = see_invisible = 0;
	being_held = bear_trap = 0;
	party_room = NO_ROOM;
	clear();
}

put_door(rm, dir, row, col)
room *rm;
short dir;
short *row, *col;
{
	short wall_width;

	wall_width = (rm->is_room & R_MAZE) ? 0 : 1;

	switch(dir) {
	case UP:
	case DOWN:
		*row = ((dir == UP) ? rm->top_row : rm->bottom_row);
		do {
			*col = get_rand(rm->left_col+wall_width,
				rm->right_col-wall_width);
		} while (!(dungeon[*row][*col] & (HORWALL | TUNNEL)));
		break;
	case RIGHT:
	case LEFT:
		*col = (dir == LEFT) ? rm->left_col : rm->right_col;
		do {
			*row = get_rand(rm->top_row+wall_width,
				rm->bottom_row-wall_width);
		} while (!(dungeon[*row][*col] & (VERTWALL | TUNNEL)));
		break;
	}
	if (rm->is_room & R_ROOM) {
		dungeon[*row][*col] = DOOR;
	}
	if ((current_level > 2) && rand_percent(HIDE_PERCENT)) {
		dungeon[*row][*col] |= HIDDEN;
	}
	rm->doors[dir/2].door_row = *row;
	rm->doors[dir/2].door_col = *col;
}

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

	if ((dir == LEFT) || (dir == RIGHT)) {
		if (col1 > col2) {
			swap(row1, row2);
			swap(col1, col2);
		}
		middle = get_rand(col1+1, col2-1);
		for (i = col1+1; i != middle; i++) {
			dungeon[row1][i] = TUNNEL;
		}
		for (i = row1; i != row2; i += (row1 > row2) ? -1 : 1) {
			dungeon[i][middle] = TUNNEL;
		}
		for (i = middle; i != col2; i++) {
			dungeon[row2][i] = TUNNEL;
		}
	} else {
		if (row1 > row2) {
			swap(row1, row2);
			swap(col1, col2);
		}
		middle = get_rand(row1+1, row2-1);
		for (i = row1+1; i != middle; i++) {
			dungeon[i][col1] = TUNNEL;
		}
		for (i = col1; i != col2; i += (col1 > col2) ? -1 : 1) {
			dungeon[middle][i] = TUNNEL;
		}
		for (i = middle; i != row2; i++) {
			dungeon[i][col2] = TUNNEL;
		}
	}
	if (rand_percent(HIDE_PERCENT)) {
		hide_boxed_passage(row1, col1, row2, col2, 1);
	}
}

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

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

add_mazes()
{
	short i, j;
	short start;
	short maze_percent;

	if (current_level > 1) {
		start = get_rand(0, (MAXROOMS-1));
		maze_percent = (current_level * 5) / 4;

		if (current_level > 15) {
			maze_percent += current_level;
		}
		for (i = 0; i < MAXROOMS; i++) {
			j = ((start + i) % MAXROOMS);
			if (rooms[j].is_room & R_NOTHING) {
				if (rand_percent(maze_percent)) {
				rooms[j].is_room = R_MAZE;
				make_maze(get_rand(rooms[j].top_row+1, rooms[j].bottom_row-1),
					get_rand(rooms[j].left_col+1, rooms[j].right_col-1),
					rooms[j].top_row, rooms[j].bottom_row,
					rooms[j].left_col, rooms[j].right_col);
				hide_boxed_passage(rooms[j].top_row, rooms[j].left_col,
					rooms[j].bottom_row, rooms[j].right_col,
					get_rand(0, 2));
				}
			}
		}
	}
}

fill_out_level()
{
	short i, rn;

	shuffle_random_rooms();

	r_de = NO_ROOM;

	for (i = 0; i < MAXROOMS; i++) {
		rn = random_rooms[i];
		if ((rooms[rn].is_room & R_NOTHING) ||
			((rooms[rn].is_room & R_CROSS) && coin_toss())) {
			fill_it(rn, 1);
		}
	}
	if (r_de != NO_ROOM) {
		fill_it(r_de, 0);
	}
}

fill_it(rn, do_rec_de)
int rn;
boolean do_rec_de;
{
	short i, j, tunnel_dir, door_dir, drow, dcol;
	short target_room, rooms_found = 0;
	short srow, scol, t;
	static short offsets[4] = {-1, 1, 3, -3};
	boolean did_this = 0;

	for (i = 0; i < 10; i++) {
		srow = get_rand(0, 3);
		scol = get_rand(0, 3);
		t = offsets[srow];
		offsets[srow] = offsets[scol];
		offsets[scol] = t;
	}
	for (i = 0; i < 4; i++) {

		target_room = rn + offsets[i];

		if (((target_room < 0) || (target_room >= MAXROOMS)) ||
			(!(on_same_row(rn,target_room) || on_same_col(rn,target_room))) ||
			(!(rooms[target_room].is_room & (R_ROOM | R_MAZE)))) {
			continue;
		}
		if (on_same_row(rn, target_room)) {
			tunnel_dir = (rooms[rn].left_col < rooms[target_room].left_col) ?
				RIGHT : LEFT;
		} else {
			tunnel_dir = (rooms[rn].top_row < rooms[target_room].top_row) ?
				DOWN : UP;
		}
		door_dir = ((tunnel_dir + 4) % DIRS);
		if (rooms[target_room].doors[door_dir/2].other_room != NO_ROOM) {
			continue;
		}
		if (((!do_rec_de) || did_this) ||
			(!mask_in_room(rn, &srow, &scol, TUNNEL))) {
			srow = (rooms[rn].top_row + rooms[rn].bottom_row) / 2;
			scol = (rooms[rn].left_col + rooms[rn].right_col) / 2;
		}
		put_door(&rooms[target_room], door_dir, &drow, &dcol);
		rooms_found++;
		draw_simple_passage(srow, scol, drow, dcol, tunnel_dir);
		rooms[rn].is_room = R_DEADEND;
		dungeon[srow][scol] = TUNNEL;

		if ((i < 3) && (!did_this)) {
			did_this = 1;
			if (coin_toss()) {
				continue;
			}
		}
		if ((rooms_found < 2) && do_rec_de) {
			recursive_deadend(rn, offsets, srow, scol);
		}
		break;
	}
}

recursive_deadend(rn, offsets, srow, scol)
short rn;
short *offsets;
short srow, scol;
{
	short i, de;
	short drow, dcol, tunnel_dir;

	rooms[rn].is_room = R_DEADEND;
	dungeon[srow][scol] = TUNNEL;

	for (i = 0; i < 4; i++) {
		de = rn + offsets[i];
		if (((de < 0) || (de >= MAXROOMS)) ||
			(!(on_same_row(rn, de) || on_same_col(rn, de)))) {
			continue;
		}
		if (!(rooms[de].is_room & R_NOTHING)) {
			continue;
		}
		drow = (rooms[de].top_row + rooms[de].bottom_row) / 2;
		dcol = (rooms[de].left_col + rooms[de].right_col) / 2;
		if (on_same_row(rn, de)) {
			tunnel_dir = (rooms[rn].left_col < rooms[de].left_col) ?
				RIGHT : LEFT;
		} else {
			tunnel_dir = (rooms[rn].top_row < rooms[de].top_row) ?
				DOWN : UP;
		}
		draw_simple_passage(srow, scol, drow, dcol, tunnel_dir);
		r_de = de;
		recursive_deadend(de, offsets, drow, dcol);
	}
}

mask_in_room(rn, row, col, mask)
short rn;
short *row, *col;
unsigned short mask;
{
	short i, j;

	for (i = rooms[rn].top_row; i <= rooms[rn].bottom_row; i++) {
		for (j = rooms[rn].left_col; j <= rooms[rn].right_col; j++) {
			if (dungeon[i][j] & mask) {
				*row = i;
				*col = j;
				return(1);
			}
		}
	}
	return(0);
}

make_maze(r, c, tr, br, lc, rc)
short r, c, tr, br, lc, rc;
{
	char dirs[4];
	short i, t;

	dirs[0] = UP;
	dirs[1] = DOWN;
	dirs[2] = LEFT;
	dirs[3] = RIGHT;

	dungeon[r][c] = TUNNEL;

	for (i = 0; i < 10; i++) {
		short t1, t2;

		t1 = get_rand(0, 3);
		t2 = get_rand(0, 3);

		swap(dirs[t1], dirs[t2]);
	}
	for (i = 0; i < 4; i++) {
		switch(dirs[i]) {
		case UP:
			if (((r-1) >= tr) &&
				(dungeon[r-1][c] != TUNNEL) &&
				(dungeon[r-1][c-1] != TUNNEL) &&
				(dungeon[r-1][c+1] != TUNNEL) &&
				(dungeon[r-2][c] != TUNNEL)) {
				make_maze((r-1), c, tr, br, lc, rc);
			}
			break;
		case DOWN:
			if (((r+1) <= br) &&
				(dungeon[r+1][c] != TUNNEL) &&
				(dungeon[r+1][c-1] != TUNNEL) &&
				(dungeon[r+1][c+1] != TUNNEL) &&
				(dungeon[r+2][c] != TUNNEL)) {
				make_maze((r+1), c, tr, br, lc, rc);
			}
			break;
		case LEFT:
			if (((c-1) >= lc) &&
				(dungeon[r][c-1] != TUNNEL) &&
				(dungeon[r-1][c-1] != TUNNEL) &&
				(dungeon[r+1][c-1] != TUNNEL) &&
				(dungeon[r][c-2] != TUNNEL)) {
				make_maze(r, (c-1), tr, br, lc, rc);
			}
			break;
		case RIGHT:
			if (((c+1) <= rc) &&
				(dungeon[r][c+1] != TUNNEL) &&
				(dungeon[r-1][c+1] != TUNNEL) &&
				(dungeon[r+1][c+1] != TUNNEL) &&
				(dungeon[r][c+2] != TUNNEL)) {
				make_maze(r, (c+1), tr, br, lc, rc);
			}
			break;
		}
	}
}

hide_boxed_passage(row1, col1, row2, col2, n)
short row1, col1, row2, col2, n;
{
	short i, j, t;
	short row, col, row_cut, col_cut;
	short h, w;

	if (current_level > 2) {
		if (row1 > row2) {
			swap(row1, row2);
		}
		if (col1 > col2) {
			swap(col1, col2);
		}
		h = row2 - row1;
		w = col2 - col1;

		if ((w >= 5) || (h >= 5)) {
			row_cut = ((h >= 2) ? 1 : 0);
			col_cut = ((w >= 2) ? 1 : 0);

			for (i = 0; i < n; i++) {
				for (j = 0; j < 10; j++) {
					row = get_rand(row1 + row_cut, row2 - row_cut);
					col = get_rand(col1 + col_cut, col2 - col_cut);
					if (dungeon[row][col] == TUNNEL) {
						dungeon[row][col] |= HIDDEN;
						break;
					}
				}
			}
		}
	}
}

put_player(nr)
short nr;		/* try not to put in this room */
{
	short rn = nr, misses;

	for (misses = 0; ((misses < 2) && (rn == nr)); misses++) {
		get_rand_row_col(&rogue.row, &rogue.col, (FLOOR | TUNNEL |
			OBJECT | STAIRS));
		rn = get_room_number(rogue.row, rogue.col);
	}
	if (dungeon[rogue.row][rogue.col] & TUNNEL) {
		current_room = PASSAGE;
	} else {
		current_room = rn;
	}
	if (current_room != PASSAGE) {
		light_up_room();
	} else {
		light_passage(rogue.row, rogue.col);
	}
	wake_room(get_room_number(rogue.row, rogue.col), 1, rogue.row, rogue.col);
	if (new_level_message) {
		message(new_level_message, 0);
		new_level_message = 0;
	}
	mvaddch(rogue.row, rogue.col, rogue.fchar);
}

check_down()
{
	if (wizard) {
		return(1);
	}
	if (dungeon[rogue.row][rogue.col] & STAIRS) {
		if (levitate) {
			message("you're floating in the air!", 0);
			return(0);
		}
		return(1);
	}
	message("I see no way down", 0);
	return(0);
}

check_up()
{
	if (!wizard) {
		if (!(dungeon[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);
		}
	}
	new_level_message = "you feel a wrenching sensation in your gut";
	if (current_level == 1) {
		win();
	} else {
		current_level -= 2;
		return(1);
	}
	return(0);
}

add_exp(e, promotion)
int e;
boolean promotion;
{
	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);
		if (rogue.exp_points > MAX_EXP) {
			rogue.exp_points = MAX_EXP + 1;
		}
		for (i = rogue.exp+1; i <= new_exp; i++) {
			sprintf(mbuf, "welcome to level %d", i);
			message(mbuf, 0);
			if (promotion) {
				hp = get_rand_hp_raise();
				rogue.hp_current += hp;
				rogue.hp_max += hp;
			}
			rogue.exp = i;
			print_stats(STAT_HP | STAT_EXP);
		}
	} else {
		print_stats(STAT_EXP);
	}
}

get_exp_level(e)
long e;
{
	short i;

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

get_rand_hp_raise()
{
	int hp;

	hp = (wizard ? 10 : get_rand(2, 10));
	return(hp);
}

show_average_hp()
{
	char mbuf[80];
	float real_average;
	float effective_average;

	if (rogue.exp == 1) {
		real_average = effective_average = 0.00;
	} else {
		real_average = (float)
			((rogue.hp_max - extra_hp - INIT_HP) + less_hp) / (rogue.exp - 1);
		effective_average = (float) (rogue.hp_max - INIT_HP) / (rogue.exp - 1);

	}
	sprintf(mbuf, "R-Hp: %.2f, E-Hp: %.2f (!: %d, V: %d)", real_average,
		effective_average, extra_hp, less_hp);
	message(mbuf, 0);
}

shuffle_random_rooms()
{
	short i, t;
	short x, y;

	for (i = 0; i < (3 * MAXROOMS); i++) {
		do {
			x = get_rand(0, (MAXROOMS-1));
			y = get_rand(0, (MAXROOMS-1));
		} while (x == y);
		swap(random_rooms[x], random_rooms[y]);
	}
}
SHAR_EOF
echo shar: extracting zap.c
cat - << \SHAR_EOF > zap.c
/*
 * zap.c
 *
 * This source herein may be modified and/or distributed by anybody who
 * so desires, with the following restrictions:
 *    1.)  This notice shall not be removed.
 *    2.)  Credit shall not be taken for the creation of this source.
 *    3.)  This code is not to be traded, sold, or used for personal
 *         gain or profit.
 *
 */

#include <curses.h>
#include "object.h"
#include "move.h"
#include "monster.h"

boolean wizard = 0;

extern short current_room;
extern short being_held, score_only, blind;
extern boolean detect_monster;

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

	while (!is_direction(dir = rgetchar())) {
		sound_bell();
		if (first_miss) {
			message("direction? ", 0);
			first_miss = 0;
		}
	}
	check_message();
	if (dir == CANCEL) {
		return;
	}
	if ((wch = get_pack_letter("zap with what?", WAND)) == CANCEL) {
		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);
	} else {
		wand->class--;
		row = rogue.row; col = rogue.col;
		monster = get_zapped_monster(dir, &row, &col);
		if (monster) {
			wake_up(monster);
			zap_monster(monster, wand->which_kind);
			relight();
		}
	}
	register_move();
}

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

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

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

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

	switch(kind) {
	case SLOW_MONSTER:
		if (monster->m_flags & HASTED) {
			monster->m_flags &= (~HASTED);
		} else {
			monster->slowed_toggle = 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 CONFUSE_MONSTER:
		monster->m_flags |= CONFUSED;
		monster->moves_confused += get_rand(12, 22);
		break;
	case INVISIBILITY:
		monster->m_flags |= INVISIBLE;
		break;
	case POLYMORPH:
		if (monster->m_flags & HOLDS) {
			being_held = 0;
		}
		nm = monster->next_monster;
		tc = monster->trail_char;
		get_rand_monster(monster, get_rand(0, MONSTERS-1));
		monster->row = row;
		monster->col = col;
		monster->next_monster = nm;
		monster->trail_char = tc;
		if (!(monster->m_flags & IMITATES)) {
			wake_up(monster);
		}
		break;
	case PUT_TO_SLEEP:
		monster->m_flags |= (ASLEEP | NAPPING);
		monster->nap_length = get_rand(3, 6);
		break;
	case MAGIC_MISSILE:
		rogue_hit(monster, 1);
		break;
	case CANCELLATION:
		if (monster->m_flags & HOLDS) {
			being_held = 0;
		}
		if (monster->m_flags & STEALS_ITEM) {
			monster->drop_percent = 0;
		}
		monster->m_flags &= (~(FLIES | FLITS | SPECIAL_HIT | INVISIBLE |
			FLAMES | IMITATES | CONFUSES | SEEKS_GOLD | HOLDS));
		break;
	case DO_NOTHING:
		message("nothing happens", 0);
		break;
	}
}

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

	if (monster->m_flags & HOLDS) {
		being_held = 0;
	}
	get_rand_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
	dungeon[monster->row][monster->col] &= ~MONSTER;

	monster->row = row; monster->col = col;
	dungeon[row][col] |= MONSTER;
	monster->trail_char = mvinch(row, col);
}

wizardize()
{
	char buf[100];

	if (wizard) {
		wizard = 0;
		message("not wizard anymore", 0);
	} else {
		if (get_input_line("wizard's password:", "", buf, "", 0, 0)) {
			xxx(1);
			xxxx(buf, strlen(buf));
			if (!strncmp(buf, "\247\104\126\272\115\243\027", 7)) {
				wizard = score_only = 1;
				message("Welcome, mighty wizard!", 0);
			} else {
				message("sorry", 0);
			}
		}
	}
}
SHAR_EOF