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

boyd@orstcs.UUCP (boyd) (03/02/86)

Would it be possible to re-post the last half of the ROGUE5.3 clone? Many
sites, including this one, are using the Notes system to peruse netnews. Notes
trucates individual postings to a maximum 64K. So the following files were
missing from the ROGUE posting:

	object.c, pack.c, play.c random.c, room.c, score.c, special_hit.c,
	throw.c, use.c, zap.c

Thank you. 

tims@zeus.UUCP (Tim Stoehr) (03/05/86)

> Would it be possible to re-post the last half of the ROGUE5.3 clone? Many
> sites, including this one, are using the Notes system to peruse netnews. Notes
> trucates individual postings to a maximum 64K. So the following files were
> missing from the ROGUE posting:
> 
> 	object.c, pack.c, play.c random.c, room.c, score.c, special_hit.c,
> 	throw.c, use.c, zap.c
> 
> Thank you. 

OK, here are the named files in a shell archive of about 59K bytes.

#!/bin/sh-----cut here-----cut here-----cut here-----cut here-----
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	object.c #	pack.c #	play.c #	random.c #	room.c #	score.c #	special_hit.c #	throw.c #	use.c #	zap.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
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
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 '\010':
		case '\012':
		case '\013':
		case '\014':
		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 '\020':
			remessage();
			break;
		case '>':
			if (check_down()) {
				return;
			}
			break;
		case '<':
			if (check_up()) {
				return;
			}
			break;
		case 'I':
			single_inventory();
			break;
		case '\022':
			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
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
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
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
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
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
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
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

frans@duvel.UUCP (03/07/86)

[sorry for posting to net.sources.games; but I don't know a better place]

From the previous article, I deducted that the rogue clone has been posted.
However, it has never made it to here (and most likely not to europe at all).

If you want to send it to me, please let me know. I'll ask the site closest
to me, to mail them me.

		Thanks.
-- 
Frans Meulenbroeks
	until May 1, 1986: Philips Microprocessor Development Systems
        		   ...!{seismo|philabs|decvax}!mcvax!philmds!frans

wasaunders@watdragon.UUCP (Alec Saunders) (03/14/86)

I have a problem. I can make the game, but for some reason it bombs on the
screen. Everything comes out all OVER the place. I had to change the library 
in the makefile to 'termcap' because we don't have the one originally 
specified .... could this be what's wrong? Termcap is what I've used
(succesfully!) with curses in the past.

-- 
Alec Saunders  wasaunders!watdragon!watnot!watmath!clyde!burl!ulysses
						     ...!cbosgd!ihnp4
					       ...!vt200!linus
"Parallel hair???? Who needs it!"