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

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

#!/bin/sh-----cut here-----cut here-----cut here-----cut here-----
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	object.c #	object.h #	pack.c #	play.c #	use.c 
echo shar: extracting object.c
cat - << \SHAR_EOF > object.c
/*
 * object.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 "monster.h"
#include "room.h"

object level_objects;
unsigned short dungeon[DROWS][DCOLS];
short foods = 0;
short party_counter;
object *free_list = (object *) 0;
char *fruit = "slime-mold ";

fighter rogue = {
	0, 0,		/* armor, weapon */
	0, 0,		/* rings */
	INIT_HP,	/* Hp current */
	INIT_HP,	/* Hp max */
	16, 16,		/* Str */
	{0},		/* pack */
	0,			/* gold */
	1, 0,		/* exp, exp_points */
	0, 0,		/* row, col */
	'@',		/* char */
	1250		/* 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},
 {80, "plaid \0                          ", "of levitation ", 0},
{150, "burgundy \0                       ", "of haste self ", 0},
{145, "beige \0                          ", "of see invisible ", 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},
{180, "                                   ", "of magic mapping ",0}
};

struct identify id_weapons[WEAPONS] = {
	{150, "short bow ", "", 0},
	  {8, "darts ", "", 0},
	 {15, "arrows ", "", 0},
	 {27, "daggers ", "", 0},
	 {35, "shurikens ", "", 0},
	{360, "mace ", "", 0},
	{470, "long sword ", "", 0},
	{580, "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 confuse monster ",0},
	  {8, "                                 ", "of invisibility ",0},
	 {55, "                                 ", "of polymorph ",0},
	  {2, "                                 ", "of haste monster ",0},
	 {25, "                                 ", "of sleep ",0},
	 {20, "                                 ", "of magic missile ",0},
	 {20, "                                 ", "of cancellation ",0},
	  {0, "                                 ", "of do nothing ",0}
};

struct identify id_rings[RINGS] = {
	 {250, "                                 ", "of stealth ",0},
	 {100, "                                 ", "of teleportation ", 0},
	 {255, "                                 ", "of regeneration ",0},
	 {295, "                                 ", "of slow digestion ",0},
	 {200, "                                 ", "of add strength ",0},
	 {250, "                                 ", "of sustain strength ",0},
	 {250, "                                 ", "of dexterity ",0},
	  {25, "                                 ", "of adornment ",0},
	 {300, "                                 ", "of see invisible ",0},
	 {290, "                                 ", "of maintain armor ",0},
	 {270, "                                 ", "of searching ",0},
};

extern short current_level, max_level;
extern short party_room;
extern char *error_file;
extern boolean is_wood[];

put_objects()
{
	short i, n;
	object *obj, *get_rand_object();

	if (current_level < max_level) {
		return;
	}
	n = coin_toss() ? get_rand(2, 4) : get_rand(3, 5);
	while (rand_percent(33)) {
		n++;
	}
	if (current_level == party_counter) {
		make_party();
		party_counter = next_party();
	}
	for (i = 0; i < n; i++) {
		obj = get_rand_object();
		put_object_rand_location(obj);
	}
	put_gold();
}

put_gold()
{
	short i, j;
	short row,col;
	unsigned short is_maze, is_room;

	for (i = 0; i < MAXROOMS; i++) {
		is_maze = (rooms[i].is_room & R_MAZE);
		is_room = (rooms[i].is_room & R_ROOM);

		if (!(is_room || is_maze)) {
			continue;
		}
		if (is_maze || rand_percent(GOLD_PERCENT)) {
			for (j = 0; j < 50; 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 ((dungeon[row][col] == FLOOR) ||
					(dungeon[row][col] == TUNNEL)) {
					put_gold_at(row, col, is_maze);
					break;
				}
			}
		}
	}
}

put_gold_at(row, col, is_maze)
short row, col;
boolean is_maze;
{
	object *obj;
	object *alloc_object(), *add_to_pack();

	obj = alloc_object();
	obj->row = row; obj->col = col;
	obj->what_is = GOLD;
	obj->quantity = get_rand((2 * current_level), (16 * current_level));
	if (is_maze) {
		obj->quantity += obj->quantity / 2;
	}
	dungeon[row][col] |= OBJECT;
	add_to_pack(obj, &level_objects, 0);
}

put_object_at(obj, row, col)
object *obj;
{
	object *add_to_pack();

	obj->row = row;
	obj->col = col;
	dungeon[row][col] |= OBJECT;
	add_to_pack(obj, &level_objects, 0);
}

object *
object_at(pack, row, col)
register object *pack;
short row, col;
{
	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_object(obj);
	}
}

free_free_list()
{
	object *obj;

	while (free_list) {
		obj = free_list;
		free_list = free_list->next_object;
		free_object(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:
		if (obj->which_kind == RATION) {
			retstring = "food ";
		} else {
			retstring = fruit;
		}
		break;
	case WAND:
		retstring = is_wood[obj->which_kind] ? "staff " : "wand ";
		break;
	case WEAPON:
		switch(obj->which_kind) {
		case DART:
			retstring=obj->quantity > 1 ? "darts " : "dart ";
			break;
		case ARROW:
			retstring=obj->quantity > 1 ? "arrows " : "arrow ";
			break;
		case DAGGER:
			retstring=obj->quantity > 1 ? "daggers " : "dagger ";
			break;
		case SHURIKEN:
			retstring=obj->quantity > 1?"shurikens ":"shuriken ";
			break;
		default:
			retstring = id_weapons[obj->which_kind].title;
		}
		break;
	case ARMOR:
		retstring = "armor ";
		break;
	case RING:
			retstring = "ring ";
		break;
	case AMULET:
		retstring = "amulet ";
		break;
	default:
		retstring = "unknown ";
		break;
	}
	return(retstring);
}

object *
get_rand_object()
{
	object *obj, *alloc_object();
	unsigned short get_rand_what_is();

	obj = alloc_object();

	if (foods < (current_level / 3)) {
		obj->what_is = FOOD;
		foods++;
	} else {
		obj->what_is = get_rand_what_is();
	}
	switch(obj->what_is) {
	case SCROLL:
		get_rand_scroll(obj);
		break;
	case POTION:
		get_rand_potion(obj);
		break;
	case WEAPON:
		get_rand_weapon(obj, 1);
		break;
	case ARMOR:
		get_rand_armor(obj);
		break;
	case WAND:
		get_rand_wand(obj);
		break;
	case FOOD:
		get_food(obj, 0);
		break;
	case RING:
		get_rand_ring(obj, 1);
		break;
	}
	return(obj);
}

unsigned short
get_rand_what_is()
{
	short percent;
	unsigned short what_is;

	percent = get_rand(1, 91);

	if (percent <= 30) {
		what_is = SCROLL;
	} else if (percent <= 60) {
		what_is = POTION;
	} else if (percent <= 64) {
		what_is = WAND;
	} else if (percent <= 74) {
		what_is = WEAPON;
	} else if (percent <= 83) {
		what_is = ARMOR;
	} else if (percent <= 88) {
		what_is = FOOD;
	} else {
		what_is = RING;
	}
	return(what_is);
}

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

	percent = get_rand(0, 85);

	obj->what_is = SCROLL;

	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 <= 50) {
		obj->which_kind = SLEEP;
	} else if (percent <= 55) {
		obj->which_kind = SCARE_MONSTER;
	} else if (percent <= 64) {
		obj->which_kind = REMOVE_CURSE;
	} else if (percent <= 69) {
		obj->which_kind = ENCHANT_ARMOR;
	} else if (percent <= 74) {
		obj->which_kind = ENCHANT_WEAPON;
	} else if (percent <= 80) {
		obj->which_kind = AGGRAVATE_MONSTER;
	} else {
		obj->which_kind = MAGIC_MAPPING;
	}
}

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

	percent = get_rand(1, 118);

	obj->what_is = POTION;

	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 if (percent <= 105) {
		obj->which_kind = POISON;
	} else if (percent <= 110) {
		obj->which_kind = LEVITATION;
	} else if (percent <= 114) {
		obj->which_kind = HASTE_SELF;
	} else {
		obj->which_kind = SEE_INVISIBLE;
	}
}

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

	obj->what_is = WEAPON;
	if (assign_wk) {
		obj->which_kind = get_rand(0, (WEAPONS - 1));
	}
	if ((obj->which_kind == ARROW) || (obj->which_kind == DAGGER) ||
		(obj->which_kind == SHURIKEN) | (obj->which_kind == DART)) {
		obj->quantity = get_rand(3, 15);
		obj->quiver = get_rand(0, 126);
	} else {
		obj->quantity = 1;
	}
	obj->to_hit_enchantment = obj->damage_enchantment = 0;

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

	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 (coin_toss()) {
				obj->to_hit_enchantment += increment;
			} else {
				obj->damage_enchantment += increment;
			}
		}
	}
	switch(obj->which_kind) {
	case BOW:
	case DART:
		obj->damage = "1d1";
		break;
	case ARROW:
		obj->damage = "1d2";
		break;
	case DAGGER:
		obj->damage = "1d3";
		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->what_is = ARMOR;
	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_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->what_is = WAND;
	obj->which_kind = get_rand(0, (WANDS - 1));
	if (obj->which_kind == MAGIC_MISSILE) {
		obj->class = get_rand(6, 12);
	} else if (obj->which_kind == CANCELLATION) {
		obj->class = get_rand(5, 9);
	} else {
		obj->class = get_rand(3, 6);
	}
}

get_food(obj, force_ration)
object *obj;
boolean force_ration;
{
	obj->what_is = FOOD;

	if (force_ration || rand_percent(80)) {
		obj->which_kind = RATION;
	} else {
		obj->which_kind = FRUIT;
	}
}

put_stairs()
{
	short row, col;

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

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

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

	if (free_list) {
		obj = free_list;
		free_list = free_list->next_object;
	} else if (!(obj = (object *) malloc(sizeof(object)))) {
			free_free_list();
			message("cannot allocate object, saving game", 0);
			save_into_file(error_file);
	}
	obj->quantity = 1;
	obj->ichar = 'L';
	obj->picked_up = obj->is_cursed = 0;
	obj->in_use_flags = NOT_USED;
	obj->identified = UNIDENTIFIED;
	obj->damage = "1d1";
	return(obj);
}

free_object(obj)
object *obj;
{
	obj->next_object = free_list;
	free_list = obj;
}

make_party()
{
	short n;

	party_room = get_rand_room();
	n = rand_percent(99) ? fill_party_room_with_objects(party_room) : 11;
	if (rand_percent(99)) {
		fill_party_room_with_monsters(party_room, n);
	}
}

show_objects()
{
	object *obj;
	short mc, rc, row, col;
	object *monster, *object_at();

	obj = level_objects.next_object;

	while (obj) {
		row = obj->row;
		col = obj->col;

		rc = get_mask_char(obj->what_is);

		if (dungeon[row][col] & MONSTER) {
			if (monster = object_at(&level_monsters, row, col)) {
				monster->trail_char = rc;
			}
		}
		mc = mvinch(row, col);
		if (((mc < 'A') || (mc > 'Z')) &&
			((row != rogue.row) || (col != rogue.col))) {
			mvaddch(row, col, rc);
		}
		obj = obj->next_object;
	}

	monster = level_monsters.next_object;

	while (monster) {
		if (monster->m_flags & IMITATES) {
			mvaddch(monster->row, monster->col, monster->disguise);
		}
		monster = monster->next_monster;
	}
}

put_amulet()
{
	object *obj, *alloc_object();

	obj = alloc_object();
	obj->what_is = AMULET;
	put_object_rand_location(obj);
}

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

	get_rand_row_col(&row, &col, (FLOOR | TUNNEL));
	put_object_at(obj, row, col);

}

create_object_for_wizard()
{
	short ch, max, wk;
	object *obj, *alloc_object(), *add_to_pack();
	char buf[80];

	if (get_pack_count(0) >= MAX_PACK_COUNT) {
		message("pack full", 0);
		return;
	}
	message("type of object?", 0);

	while (!index("!?:)]=/,\033", (ch = rgetchar()))) {
		sound_bell();
	}
	check_message();

	if (ch == '\033') {
		return;
	}
	obj = alloc_object();

	switch(ch) {
	case '!':
		obj->what_is = POTION;
		max = POTIONS - 1;
		break;
	case '?':
		obj->what_is = SCROLL;
		max = SCROLLS - 1;
		break;
	case ',':
		obj->what_is = AMULET;
		break;
	case ':':
		get_food(obj, 0);
		break;
	case ')':
		get_rand_weapon(obj, 0);
		max = WEAPONS - 1;
		break;
	case ']':
		get_rand_armor(obj);
		max = ARMORS - 1;
		break;
	case '/':
		get_rand_wand(obj);
		max = WANDS - 1;
		break;
	case '=':
		max = RINGS - 1;
		obj->what_is = RING;
		break;
	}
	if ((ch != ',') && (ch != ':')) {
GIL:
		if (get_input_line("which kind?", "", buf, "", 0, 1)) {
			wk = get_number(buf);
			if ((wk >= 0) && (wk <= max)) {
				obj->which_kind = (unsigned char) wk;
				if (obj->what_is == RING) {
					get_rand_ring(obj, 0);
				}
			} else {
				sound_bell();
				goto GIL;
			}
		} else {
			free_object(obj);
			return;
		}
	}
	get_description(obj, buf);
	message(buf, 0);
	add_to_pack(obj, &rogue.pack, 1);
}

next_party()
{
	int n;

	n = current_level;
	while (n % PARTY_TIME) {
		n++;
	}
	return(get_rand((n + 1), (n + PARTY_TIME)));
}
SHAR_EOF
echo shar: extracting object.h
cat - << \SHAR_EOF > object.h
/*
 * object.h
 *
 * 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.
 *
 */

#define boolean char

#define NOTHING		((unsigned short)     0)
#define OBJECT		((unsigned short)    01)
#define MONSTER		((unsigned short)    02)
#define STAIRS		((unsigned short)    04)
#define HORWALL		((unsigned short)   010)
#define VERTWALL	((unsigned short)   020)
#define DOOR		((unsigned short)   040)
#define FLOOR		((unsigned short)  0100)
#define TUNNEL		((unsigned short)  0200)
#define TRAP		((unsigned short)  0400)
#define HIDDEN		((unsigned short) 01000)

#define ARMOR		((unsigned short)   01)
#define WEAPON		((unsigned short)   02)
#define SCROLL		((unsigned short)   04)
#define POTION		((unsigned short)  010)
#define GOLD		((unsigned short)  020)
#define FOOD		((unsigned short)  040)
#define WAND		((unsigned short) 0100)
#define RING		((unsigned short) 0200)
#define AMULET		((unsigned short) 0400)
#define ALL_OBJECTS	((unsigned short) 0777)

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

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

#define MAX_PACK_COUNT 24

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

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

#define TELEPORT_AWAY 0
#define SLOW_MONSTER 1
#define CONFUSE_MONSTER 2
#define INVISIBILITY 3
#define POLYMORPH 4
#define HASTE_MONSTER 5
#define PUT_TO_SLEEP 6
#define MAGIC_MISSILE 7
#define CANCELLATION 8
#define DO_NOTHING 9
#define WANDS 10

#define STEALTH 0
#define R_TELEPORT 1
#define REGENERATION 2
#define SLOW_DIGEST 3
#define ADD_STRENGTH 4
#define SUSTAIN_STRENGTH 5
#define DEXTERITY 6
#define ADORNMENT 7
#define R_SEE_INVISIBLE 8
#define MAINTAIN_ARMOR 9
#define SEARCHING 10
#define RINGS 11

#define RATION 0
#define FRUIT 1

#define NOT_USED		((unsigned short)   0)
#define BEING_WIELDED	((unsigned short)  01)
#define BEING_WORN		((unsigned short)  02)
#define ON_LEFT_HAND	((unsigned short)  04)
#define ON_RIGHT_HAND	((unsigned short) 010)
#define ON_EITHER_HAND	((unsigned short) 014)
#define BEING_USED		((unsigned short) 017)

#define NO_TRAP -1
#define TRAP_DOOR 0
#define BEAR_TRAP 1
#define TELEPORT_TRAP 2
#define POISON_DART_TRAP 3
#define SLEEPING_GAS_TRAP 4
#define RUST_TRAP 5
#define TRAPS 6

#define STEALTH_FACTOR 3
#define R_TELEPORT_PERCENT 8

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

#define DROWS 24
#define DCOLS 80
#define MAX_TITLE_LENGTH 30
#define MORE "-more-"
#define MAXSYLLABLES 40
#define MAX_METAL 14
#define WAND_MATERIALS 30
#define GEMS 14

#define GOLD_PERCENT 46

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

/*
 The following #defines provide more meaningful names for some of the
 struct object fields that are used for monsters.  This, since each monster
 and object (scrolls, potions, etc) are represented by a struct object.
*/

#define m_damage damage
#define hp_to_kill quantity
#define m_char ichar
#define first_level is_protected
#define last_level is_cursed
#define m_hit_chance class
#define stationary_damage identified
#define drop_percent which_kind
#define trail_char damage_enchantment
#define slowed_toggle quiver
#define moves_confused to_hit_enchantment
#define nap_length picked_up
#define disguise what_is
#define next_monster next_object

struct object {				/* comment is monster meaning */
	unsigned long m_flags;	/* monster flags */
	char *damage;			/* damage it does */
	short quantity;			/* hit points to kill */
	char ichar;				/* 'A' is for aquatar */
	short kill_exp;			/* exp for killing it */
	boolean is_protected;	/* level starts */
	boolean is_cursed;		/* level ends */
	char class;				/* chance of hitting you */
	short identified;		/* 'F' damage, 1,2,3... */
	unsigned char which_kind; /* item carry/drop % */
	char o_row, o_col, o;	/* o is how many times stuck at o_row, o_col */
	char row, col;			/* current row, col */
	char damage_enchantment;/* room char when detect_monster */
	char quiver;			/* monster slowed toggle */
	char trow, tcol;		/* target row, col */
	char to_hit_enchantment;/* how many moves is confused */
	unsigned short what_is;	/* imitator's charactor (?!%: */
	boolean picked_up;		/* sleep from wand of sleep */
	unsigned short in_use_flags;
	struct object *next_object;	/* next monster */
};

typedef struct object object;

#define INIT_HP 12

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

typedef struct fighter fighter;

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

typedef struct door door;

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

typedef struct room room;

struct trap {
	short trap_type;
	short trap_row, trap_col;
};

typedef struct trap trap;

extern fighter rogue;
extern room rooms[];
extern trap traps[];
extern unsigned short dungeon[DROWS][DCOLS];
extern object level_objects;

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

extern object monster_tab[];
extern object level_monsters;
SHAR_EOF
echo shar: extracting pack.c
cat - << \SHAR_EOF > pack.c
/*
 * pack.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"

char *curse_message = "you can't, it appears to be cursed";

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

	if (condense) {
		if (op = check_duplicate(obj, pack)) {
			free_object(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) {
		message("the scroll turns to dust as you pick it up", 0);
		dungeon[row][col] &= (~OBJECT);
		vanish(obj, 0, &level_objects);
		*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;
		dungeon[row][col] &= ~(OBJECT);
		remove_from_pack(obj, &level_objects);
		print_stats(STAT_GOLD);
		return(obj);	/* obj will be free_object()ed in single_move() */
	}
	if (get_pack_count(obj) >= MAX_PACK_COUNT) {
		message("pack too full", 1);
		return(0);
	}
	dungeon[row][col] &= ~(OBJECT);
	remove_from_pack(obj, &level_objects);
	obj = add_to_pack(obj, &rogue.pack, 1);
	obj->picked_up = 1;
	return(obj);
}

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

	if (dungeon[rogue.row][rogue.col] & (OBJECT | STAIRS | TRAP)) {
		message("there's already something there", 0);
		return;
	}
	if (!rogue.pack.next_object) {
		message("you have nothing to drop", 0);
		return;
	}
	if ((ch = get_pack_letter("drop what?", ALL_OBJECTS)) == CANCEL) {
		return;
	}
	if (!(obj = get_letter_object(ch))) {
		message("no such item.", 0);
		return;
	}
	if (obj->in_use_flags & BEING_WIELDED) {
		if (obj->is_cursed) {
			message(curse_message, 0);
			return;
		}
		unwield(rogue.weapon);
	} else if (obj->in_use_flags & BEING_WORN) {
		if (obj->is_cursed) {
			message(curse_message, 0);
			return;
		}
		mv_aquatars();
		unwear(rogue.armor);
		print_stats(STAT_ARMOR);
	} else if (obj->in_use_flags & ON_EITHER_HAND) {
		if (obj->is_cursed) {
			message(curse_message, 0);
			return;
		}
		un_put_on(obj);
	}
	obj->row = rogue.row;
	obj->col = rogue.col;

	if ((obj->quantity > 1) && (obj->what_is != WEAPON)) {
		obj->quantity--;
		new = alloc_object();
		*new = *obj;
		new->quantity = 1;
		obj = new;
	} else {
		obj->ichar = 'L';
		remove_from_pack(obj, &rogue.pack);
	}
	put_object_at(obj, rogue.row, rogue.col);
	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);
	}
	if ((obj->what_is == FOOD) && (obj->which_kind == FRUIT)) {
		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 == DAGGER) ||
			(obj->which_kind == DART) ||
			(obj->which_kind == SHURIKEN)) &&
			(obj->quiver == op->quiver))) {
				op->quantity += obj->quantity;
				return(op);
			}
		}
		op = op->next_object;
	}
	return(0);
}

next_avail_ichar()
{
	register object *obj;
	register i;
	boolean ichars[26];

	for (i = 0; i < 26; i++) {
		ichars[i] = 0;
	}
	obj = rogue.pack.next_object;
	while (obj) {
		ichars[(obj->ichar - 'a')] = 1;
		obj = obj->next_object;
	}
	for (i = 0; i < 26; i++) {
		if (!ichars[i]) {
			return(i + 'a');
		}
	}
	return('?');
}

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

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

	if (!mask_in_pack(&rogue.pack, mask)) {
		message("nothing appropriate", 0);
		return(CANCEL);
	}
	for (;;) {

		message(prompt, 0);

		for (;;) {
			ch = rgetchar();
			if (!is_pack_letter(&ch, &mask)) {
				sound_bell();
			} else {
				break;
			}
		}

		if (ch == LIST) {
			check_message();
			inventory(&rogue.pack, mask);
		} else {
			break;
		}
		mask = tmask;
	}
	check_message();
	return(ch);
}

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

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

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

	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;
	}
	obj->identified = 1;
	strcpy(description, "wearing ");
	get_description(obj, description + 8);
	message(description, 0);
	do_wear(obj);
	print_stats(STAT_ARMOR);
	register_move();
}

unwear(obj)
object *obj;
{
	if (obj) {
		obj->in_use_flags &= (~BEING_WORN);
	}
	rogue.armor = (object *) 0;
}

do_wear(obj)
object *obj;
{
	rogue.armor = obj;
	obj->in_use_flags |= BEING_WORN;
	obj->identified = 1;
}

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

	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 & (ARMOR | RING)) {
		sprintf(description, "you can't wield %s",
			((obj->what_is == ARMOR) ? "armor" : "rings"));
		message(description, 0);
		return;
	}
	if (obj->in_use_flags & BEING_WIELDED) {
		message("in use", 0);
	} else {
		unwield(rogue.weapon);
		strcpy(description, "wielding ");
		get_description(obj, description + 9);
		message(description, 0);
		do_wield(obj);
		register_move();
	}
}

do_wield(obj)
object *obj;
{
	rogue.weapon = obj;
	obj->in_use_flags |= BEING_WIELDED;
}

unwield(obj)
object *obj;
{
	if (obj) {
		obj->in_use_flags &= (~BEING_WIELDED);
	}
	rogue.weapon = (object *) 0;
}

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 | RING));

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

	if (get_input_line("call it:","",buf,id_table[obj->which_kind].title,1,1)) {
		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;

	obj = rogue.pack.next_object;

	while (obj) {
		if (obj->what_is != WEAPON) {
			count += obj->quantity;
		} else if (!new_obj) {
			count++;
		} else if ((new_obj->what_is != WEAPON) ||
			((obj->which_kind != ARROW) &&
			(obj->which_kind != DAGGER) &&
			(obj->which_kind != DART) &&
			(obj->which_kind != SHURIKEN)) ||
			(new_obj->which_kind != obj->which_kind) ||
			(obj->quiver != new_obj->quiver)) {
			count++;
		}
		obj = obj->next_object;
	}
	return(count);
}

mask_in_pack(pack, mask)
object *pack;
unsigned short mask;
{
	while (pack->next_object) {
		pack = pack->next_object;
		if (pack->what_is & mask) {
			return(1);
		}
	}
	return(0);
}

is_pack_letter(c, mask)
short *c;
unsigned short *mask;
{
	if (((*c == '?') || (*c == '!') || (*c == ':') || (*c == '=') ||
		(*c == ')') || (*c == ']') || (*c == '/') || (*c == ','))) {
		switch(*c) {
		case '?':
			*mask = SCROLL;
			break;
		case '!':
			*mask = POTION;
			break;
		case ':':
			*mask = FOOD;
			break;
		case ')':
			*mask = WEAPON;
			break;
		case ']':
			*mask = ARMOR;
			break;
		case '/':
			*mask = WAND;
			break;
		case '=':
			*mask = RING;
			break;
		case ',':
			*mask = AMULET;
			break;
		}
		*c = LIST;
		return(1);
	}
	return(((*c >= 'a') && (*c <= 'z')) || (*c == CANCEL) || (*c == LIST));
}

has_amulet()
{
	return(mask_in_pack(&rogue.pack, AMULET));
}
SHAR_EOF
echo shar: extracting play.c
cat - << \SHAR_EOF > play.c
/*
 * play.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"

boolean interrupted = 0;
char *unknown_command = "unknown command";

extern short party_room, bear_trap;
extern char hit_message[];
extern boolean wizard, trap_door;

play_level()
{
	short ch;
	int count;

	for (;;) {
		interrupted = 0;
		if (hit_message[0]) {
			message(hit_message, 1);
			hit_message[0] = 0;
		}
		if (trap_door) {
			trap_door = 0;
			return;
		}
		move(rogue.row, rogue.col);
		refresh();

		ch = rgetchar();
		check_message();
		count = 0;
CH:
		switch(ch) {
		case '.':
			rest((count > 0) ? count : 1);
			break;
		case 's':
			search(((count > 0) ? count : 1), 0);
			break;
		case 'i':
			inventory(&rogue.pack, ALL_OBJECTS);
			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 'P':
			put_on_ring();
			break;
		case 'R':
			remove_ring();
			break;
		case '\020':
			remessage();
			break;
		case '\027':
			wizardize();
			break;
		case '>':
			if (check_down()) {
				return;
			}
			break;
		case '<':
			if (check_up()) {
				return;
			}
			break;
		case ')':
		case ']':
			inventory_armor_weapon(ch == ')');
			break;
		case '=':
			inventory_rings();
			break;
		case '^':
			identify_trap();
			break;
		case 'I':
			single_inventory(0);
			break;
		case 'T':
			take_off();
			break;
		case 'W':
			wear();
			break;
		case 'w':
			wield();
			break;
		case 'c':
			call_it();
			break;
		case 'z':
			zapp();
			break;
		case 't':
			throw();
			break;
		case '!':
			shell();
			break;
		case 'v':
			message("rogue-clone: Version II. (Tim Stoehr was here), tektronix!zeus!tims", 0);
			break;
		case 'Q':
			quit(0);
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			move(rogue.row, rogue.col);
			refresh();
			do {
				if (count < 100) {
					count = (10 * count) + (ch - '0');
				}
				ch = rgetchar();
			} while ((ch >= '0') && (ch <= '9'));
			if (ch != CANCEL) {
				goto CH;
			}
			break;
		case ' ':
			break;
		case '\011':
			if (wizard) {
				inventory(&level_objects, ALL_OBJECTS);
			} else {
				message(unknown_command, 0);
			}
			break;
		case '\023':
			if (wizard) {
				draw_magic_map();
			} else {
				message(unknown_command, 0);
			}
			break;
		case '\024':
			if (wizard) {
				show_traps();
			} else {
				message(unknown_command, 0);
			}
			break;
		case '\017':
			if (wizard) {
				show_objects();
			} else {
				message(unknown_command, 0);
			}
			break;
		case '\001':
			show_average_hp();
			break;
		case '\003':
			if (wizard) {
				create_object_for_wizard();
			} else {
				message(unknown_command, 0);
			}
			break;
		case '\015':
			if (wizard) {
				show_monsters();
			} else {
				message(unknown_command, 0);
			}
			break;
		case 'S':
			save_game();
			break;
		default:
			message(unknown_command, 0);
			break;
		}
	}
}
SHAR_EOF
echo shar: extracting use.c
cat - << \SHAR_EOF > use.c
/*
 * use.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"

short halluc = 0;
short blind = 0;
short confused = 0;
short levitate = 0;
short haste_self = 0;
boolean see_invisible = 0;
short extra_hp = 0;
boolean detect_monster = 0;
char *strange_feeling = "you have a strange feeling for a moment, then it passes";

extern short bear_trap;
extern char hunger_str[];
extern short current_room;
extern long level_points[];
extern boolean being_held;
extern char *fruit, *you_can_move_again;
extern boolean sustain_strength;

quaff()
{
	short ch;
	char buf[80];
	object *obj, *get_letter_object();

	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:
			if (!sustain_strength) {
				rogue.strength_current -= get_rand(1, 3);
				if (rogue.strength_current < 1) {
					rogue.strength_current = 1;
				}
			}
			message("you feel very sick now", 0);
			if (halluc) {
				unhallucinate();
			}
			break;
		case RAISE_LEVEL:
			rogue.exp_points = level_points[rogue.exp - 1];
			add_exp(1, 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:
			show_monsters();
			if (!(level_monsters.next_monster)) {
				message(strange_feeling, 0);
			}
			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;
		case LEVITATION:
			message("you start to float in the air", 0);
			levitate += get_rand(15, 30);
			being_held = bear_trap = 0;
			break;
		case HASTE_SELF:
			message("you feel yourself moving much faster", 0);
			haste_self += get_rand(11, 21);
			if (!(haste_self % 2)) {
				haste_self++;
			}
			break;
		case SEE_INVISIBLE:
			sprintf(buf, "hmm, this potion tastes like %sjuice", fruit);
			message(buf, 0);
			if (blind) {
				unblind();
			}
			see_invisible = 1;
			relight();
			break;
	}
	print_stats((STAT_STRENGTH | STAT_HP));
	if (id_potions[obj->which_kind].id_status != CALLED) {
		id_potions[obj->which_kind].id_status = IDENTIFIED;
	}
	vanish(obj, 1, &rogue.pack);
}

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

	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) {
				if (rogue.weapon->what_is == WEAPON) {
					sprintf(msg, "your %sglow%s %sfor a moment",
					name_of(rogue.weapon),
					((rogue.weapon->quantity <= 1) ? "s" : ""),
					get_ench_color());
					message(msg, 0);
					if (coin_toss()) {
						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(STAT_ARMOR);
			} else {
				message("your skin crawls", 0);
			}
			break;
		case IDENTIFY:
			message("this is a scroll of identify", 0);
			obj->identified = 1;
			id_scrolls[obj->which_kind].id_status = IDENTIFIED;
			identify();
			break;
		case TELEPORT:
			teleport();
			break;
		case SLEEP:
			message("you fall asleep", 0);
			take_a_nap();
			break;
		case PROTECT_ARMOR:
			if (rogue.armor) {
				message( "your armor is covered by a shimmering gold shield",0);
				rogue.armor->is_protected = 1;
				rogue.armor->is_cursed = 0;
			} else {
				message("your acne seems to have disappeared",
				0);
			}
			break;
		case REMOVE_CURSE:
				message((!halluc) ?
					"you feel as though someone is watching over you" :
					"you feel in touch with the universal oneness", 0);
			uncurse_all();
			break;
		case CREATE_MONSTER:
			create_monster();
			break;
		case AGGRAVATE_MONSTER:
			aggravate();
			break;
		case MAGIC_MAPPING:
			message("this scroll seems to have a map on it", 0);
			draw_magic_map();
			break;
	}
	if (id_scrolls[obj->which_kind].id_status != CALLED) {
		id_scrolls[obj->which_kind].id_status = IDENTIFIED;
	}
	vanish(obj, (obj->which_kind != SLEEP), &rogue.pack);
}

/* vanish() does NOT handle a quiver of weapons with more than one
   arrow (or whatever) in the quiver.  It will only decrement the count.
*/

vanish(obj, rm, pack)
object *obj;
short rm;
object *pack;
{
	if (obj->quantity > 1) {
		obj->quantity--;
	} else {
		if (obj->in_use_flags & BEING_WIELDED) {
			unwield(obj);
		} else if (obj->in_use_flags & BEING_WORN) {
			unwear(obj);
		} else if (obj->in_use_flags & ON_EITHER_HAND) {
			un_put_on(obj);
		}
		remove_from_pack(obj, pack);
		free_object(obj);
	}
	if (rm) {
		register_move();
	}
}

potion_heal(extra)
{
	float ratio;
	short add;

	rogue.hp_current += rogue.exp;

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

	if (ratio >= 1.00) {
		rogue.hp_max += (extra ? 2 : 1);
		extra_hp += (extra ? 2 : 1);
		rogue.hp_current = rogue.hp_max;
	} else if (ratio >= 0.90) {
		rogue.hp_max += (extra ? 1 : 0);
		extra_hp += (extra ? 1 : 0);
		rogue.hp_current = rogue.hp_max;
	} else {
		if (ratio < 0.33) {
			ratio = 0.33;
		}
		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();
	} else if (confused) {
		confused = (confused / 2) + 1;
	}
	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[DCOLS];
AGAIN:
	ch = get_pack_letter("what would you like to identify?", ALL_OBJECTS);

	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 | RING)) {
		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 buf[70];

	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;
	}
	if ((obj->which_kind == FRUIT) || rand_percent(60)) {
		moves = get_rand(900, 1100);
		if (obj->which_kind == RATION) {
			message("yum, that tasted good", 0);
		} else {
			sprintf(buf, "my, that was a yummy %s", fruit);
			message(buf, 0);
		}
	} else {
		moves = get_rand(700, 900);
		message("yuk, that food tasted awful", 0);
		add_exp(2, 1);
	}
	rogue.moves_left /= 3;
	rogue.moves_left += moves;
	hunger_str[0] = 0;
	print_stats(STAT_HUNGER);

	vanish(obj, 1, &rogue.pack);
}

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 > (DROWS-2)) || (col < 0) ||
				 (col > (DCOLS-1))) {
				continue;
			}
			if (dungeon[row][col] & MONSTER) {
				monster = object_at(&level_monsters, row, col);
				monster->m_flags |= 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()
{
	mvaddch(rogue.row, rogue.col, get_dungeon_char(rogue.row, rogue.col));

	if (current_room >= 0) {
		darken_room(current_room);
	}
	put_player(get_room_number(rogue.row, rogue.col));
	being_held = bear_trap = 0;
}

hallucinate()
{
	object *obj, *monster;
	short ch;

	if (blind) return;

	obj = level_objects.next_object;

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

	while (monster) {
		ch = mvinch(monster->row, monster->col);
		if ((ch >= 'A') && (ch <= 'Z')) {
			addch(get_rand('A', 'Z'));
		}
		monster = monster->next_monster;
	}
}

unhallucinate()
{
	halluc = 0;
	relight();
	message("everything looks SO boring now", 1);
}

unblind()
{
	blind = 0;
	message("the veil of darkness lifts", 1);
	relight();
	if (halluc) {
		hallucinate();
	}
	if (detect_monster) {
		show_monsters();
	}
}

relight()
{
	if (current_room == PASSAGE) {
		light_passage(rogue.row, rogue.col);
	} else {
		light_up_room();
	}
	mvaddch(rogue.row, rogue.col, rogue.fchar);
}

take_a_nap()
{
	short i;

	i = get_rand(2, 5);
	sleep(1);

	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 (detect_monster) {
		object *monster;

		monster = level_monsters.next_monster;

		while (monster) {
			mvaddch(monster->row, monster->col, monster->trail_char);
			monster = monster->next_monster;
		}
	}
	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);
}

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, 1);
}

uncurse_all()
{
	object *obj;

	obj = rogue.pack.next_object;

	while (obj) {
		obj->is_cursed = 0;
		obj = obj->next_object;
	}
}
SHAR_EOF