[net.sources.games] For rogue 5.3 lovers, part 4 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:
#	random.c #	ring.c #	room.c #	save.c #	score.c #	throw.c #	trap.c 
echo shar: extracting random.c
cat - << \SHAR_EOF > random.c
#include <stdio.h>

static int dgrs[5] = {0, 7, 15, 31, 63};
static int seps[5] = {0, 3, 1, 3, 1};

static long rntb[32] = {
	         3, 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 
	0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, 0x7449e56b,
	0xbeb1dbb0, 0xab5c5918, 0x946554fd, 0x8c2e680f, 0xeb3d799f,
	0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88, 0xe369735d,
	0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, 
	0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e,
	0x8999220b, 0x27fb47b9 };

static long *fptr = &rntb[4];
static long *rptr = &rntb[1];
static long *state = &rntb[1];
static int rand_type = 3;
static int rand_deg = 31;
static int rand_sep = 3;
static long *end_ptr = &rntb[32];

srandom(x)
unsigned x;
{
	register int i, j;

	if (rand_type == 0) {
		state[0] = x;
	} else {
		j = 1;
		state[0] = x;
		for (i = 1; i < rand_deg; i++) {
			state[i] = 1103515245*state[i - 1] + 12345;
		}
		fptr = &state[rand_sep];
		rptr = &state[0];
		for (i = 0; i < 10*rand_deg; i++) {
			random();
		}
	}
}

char *
initstate(seed, arg_state, n)
unsigned seed;
char *arg_state;
int n;
{
	register char *ostate = (char *)(&state[-1]);

	if (rand_type == 0) {
		state[-1] = rand_type;
	} else {
		state[-1] = 5 * (rptr - state) + rand_type;
	}
	if (n < 32) {
		rand_type = 0;
		rand_deg = 0;
		rand_sep = 0;
	} else {
		if (n < 64) {
			rand_type = 1;
			rand_deg = 7;
			rand_sep = 3;
		} else {
			if (n < 128) {
				rand_type = 2;
				rand_deg = 15;
				rand_sep = 1;
			} else {
				if (n < 256) {
					rand_type = 3;
					rand_deg = 31;
					rand_sep = 3;
				} else {
					rand_type = 4;
					rand_deg = 63;
					rand_sep = 1;
				}
			}
		}
	}
	state = &(((long *)arg_state)[1]);
	end_ptr = &state[rand_deg];
	srandom(seed);
	if (rand_type == 0) {
		state[-1] = rand_type;
	} else {
		state[-1] = 5 * (rptr - state) + rand_type;
	}
	return(ostate);
}

char *
setstate(arg_state)
char *arg_state;
{
	register long *new_state = (long *) arg_state;
	register int type = new_state[0] % 5;
	register int rear = new_state[0] / 5;
	char *ostate = (char *)(&state[-1]);

	if (rand_type == 0) {
		state[-1] = rand_type;
	} else {
		state[-1] = 5 * (rptr - state) + rand_type;
	}
	switch(type) {
	case 0:
	case 1:
	case 2:
	case 3:
	case 4:
		rand_type = type;
		rand_deg = dgrs[type];
		rand_sep = seps[type];
		break;

	}
	state = &new_state[1];
	if (rand_type != 0) {
		rptr = &state[rear];
		fptr = &state[(rear + rand_sep)%rand_deg];
	}
	end_ptr = &state[rand_deg];
	return(ostate);
}

long
random()
{
	long i;
	
	if (rand_type == 0) {
		i = state[0] = (state[0]*1103515245 + 12345) & 0x7fffffff;
	} else {
		*fptr += *rptr;
		i = (*fptr >> 1) & 0x7fffffff;
		if (++fptr >= end_ptr) {
			fptr = state;
			++rptr;
		} else {
			if (++rptr >= end_ptr) {
				rptr = state;
			}
		}
	}
	return(i);
}

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

	if (x > y) {
		y = t;
		y = x;
		x = t;
	}
	r = (int) random();
	r = (r % ((y-x)+1)) + x;
	return(r);
}

rand_percent(percentage)
register int percentage;
{
	return(get_rand(1, 100) <= percentage);
}

coin_toss()
{
	long random();

	return(((random() & 01) ? 1 : 0));
}
SHAR_EOF
echo shar: extracting ring.c
cat - << \SHAR_EOF > ring.c
/*
 * ring.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 "object.h"
#include "move.h"
#include "room.h"

char *left_or_right = "left or right hand?";
char *no_ring = "there's no ring on that hand";
short stealthy, r_rings, add_strength, e_rings, regeneration, ring_exp;
short auto_search;
boolean r_teleport, r_see_invisible, sustain_strength, maintain_armor;

extern char *curse_message;
extern boolean wizard;

put_on_ring()
{
	short ch;
	char description[DCOLS];
	object *ring, *get_letter_object();

	if (r_rings == 2) {
		message("wearing two rings already", 0);
		return;
	}
	if ((ch = get_pack_letter("put on what?", RING)) == CANCEL) {
		return;
	}
	if (!(ring = get_letter_object(ch))) {
		message("no such item.", 0);
		return;
	}
	if (!(ring->what_is & RING)) {
		message("that's not a ring", 0);
		return;
	}
	if (ring->in_use_flags & (ON_LEFT_HAND | ON_RIGHT_HAND)) {
		message("that ring is already being worn", 0);
		return;
	}
	if (r_rings == 1) {
		ch = (rogue.left_ring ? 'r' : 'l');
	} else {
		message(left_or_right, 0);
		do {
			ch = rgetchar();
		} while ((ch != CANCEL) && (ch != 'l') && (ch != 'r') && (ch != '\n') &&
			 	(ch != '\r'));
	}
	if ((ch != 'l') && (ch != 'r')) {
		check_message();
		return;
	}
	if (((ch == 'l') && rogue.left_ring)||((ch == 'r') && rogue.right_ring)) {
		check_message();
		message("there's already a ring on that hand", 0);
		return;
	}
	if (ch == 'l') {
		do_put_on(ring, 1);
	} else {
		do_put_on(ring, 0);
	}
	ring_stats(1);
	check_message();
	get_description(ring, description);
	message(description, 0);
	register_move();
}

/*
 * Do not call ring_stats() from within do_put_on().  It will cause
 * serious problems when do_put_on() is called from read_pack() in restore().
 */

do_put_on(ring, on_left)
object *ring;
boolean on_left;
{
	if (on_left) {
		ring->in_use_flags |= ON_LEFT_HAND;
		rogue.left_ring = ring;
	} else {
		ring->in_use_flags |= ON_RIGHT_HAND;
		rogue.right_ring = ring;
	}
}

remove_ring()
{
	boolean left = 0, right = 0;
	short ch;
	char buf[DCOLS];
	object *ring;

	if (r_rings == 0) {
		inventory_rings();
	} else if (rogue.left_ring && !rogue.right_ring) {
		left = 1;
	} else if (!rogue.left_ring && rogue.right_ring) {
		right = 1;
	} else {
		message(left_or_right, 0);
		do {
			ch = rgetchar();
		} while ((ch != CANCEL) && (ch != 'l') && (ch != 'r') &&
			(ch != '\n') && (ch != '\r'));
		left = (ch == 'l');
		right = (ch == 'r');
		check_message();
	}
	if (left || right) {
		if (left) {
			if (rogue.left_ring) {
				ring = rogue.left_ring;
			} else {
				message(no_ring, 0);
			}
		} else {
			if (rogue.right_ring) {
				ring = rogue.right_ring;
			} else {
				message(no_ring, 0);
			}
		}
		if (ring->is_cursed) {
			message(curse_message, 0);
		} else {
			un_put_on(ring);
			strcpy(buf, "removed ");
			get_description(ring, buf + 8);
			message(buf, 0);
			register_move();
		}
	}
}

un_put_on(ring)
object *ring;
{
	if (ring && (ring->in_use_flags & ON_LEFT_HAND)) {
		ring->in_use_flags &= (~ON_LEFT_HAND);
		rogue.left_ring = 0;
	} else if (ring && (ring->in_use_flags & ON_RIGHT_HAND)) {
		ring->in_use_flags &= (~ON_RIGHT_HAND);
		rogue.right_ring = 0;
	}
	ring_stats(1);
}

get_rand_ring(ring, assign_wk)
object *ring;
boolean assign_wk;
{
	ring->what_is = RING;
	if (assign_wk) {
		ring->which_kind = get_rand(0, (RINGS - 1));
	}
	ring->class = 0;

	switch(ring->which_kind) {
	/*
	case STEALTH:
		break;
	case SLOW_DIGEST:
		break;
	case REGENERATION:
		break;
	case R_SEE_INVISIBLE:
		break;
	case SUSTAIN_STRENGTH:
		break;
	case R_MAINTAIN_ARMOR:
		break;
	case SEARCHING:
		break;
	*/
	case R_TELEPORT:
		ring->is_cursed = 1;
		break;
	case ADD_STRENGTH:
	case DEXTERITY:
		while ((ring->class = (get_rand(0, 4) - 2)) == 0) ;
		ring->is_cursed = (ring->class < 0);
		break;
	case ADORNMENT:
		ring->is_cursed = coin_toss();
		break;
	}
}

inventory_rings()
{
	char buf[DCOLS];

	if (r_rings == 0) {
		message("not wearing any rings", 0);
	} else {
		if (rogue.left_ring) {
			get_description(rogue.left_ring, buf);
			message(buf, 0);
		}
		if (rogue.right_ring) {
			get_description(rogue.right_ring, buf);
			message(buf, 0);
		}
	}
	if (wizard) {
		sprintf(buf, "ste %d, r_r %d, e_r %d, r_t %d, s_s %d, a_s %d, reg %d, r_e %d, s_i %d, m_a %d, aus %d",
			stealthy, r_rings, e_rings, r_teleport, sustain_strength,
			add_strength, regeneration, ring_exp, r_see_invisible,
			maintain_armor, auto_search);
		message(buf, 0);
	}
}

ring_stats(pr)
boolean pr;
{
	short i;
	object *ring;

	stealthy = 0;
	r_rings = 0;
	e_rings = 0;
	r_teleport = 0;
	sustain_strength = 0;
	add_strength = 0;
	regeneration = 0;
	ring_exp = 0;
	r_see_invisible = 0;
	maintain_armor = 0;
	auto_search = 0;

	for (i = 0; i < 2; i++) {
		if (!(ring = ((i == 0) ? rogue.left_ring : rogue.right_ring))) {
			continue;
		}
		r_rings++;
		e_rings++;
		switch(ring->which_kind) {
		case STEALTH:
			stealthy++;
			break;
		case R_TELEPORT:
			r_teleport = 1;
			break;
		case REGENERATION:
			regeneration++;
			break;
		case SLOW_DIGEST:
			e_rings -= 2;
			break;
		case ADD_STRENGTH:
			add_strength += ring->class;
			break;
		case SUSTAIN_STRENGTH:
			sustain_strength = 1;
			break;
		case DEXTERITY:
			ring_exp += ring->class;
			break;
		case ADORNMENT:
			break;
		case R_SEE_INVISIBLE:
			r_see_invisible = 1;
			break;
		case MAINTAIN_ARMOR:
			maintain_armor = 1;
			break;
		case SEARCHING:
			auto_search += 2;
			break;
		}
	}
	if (pr) {
		print_stats(STAT_STRENGTH);
		relight();
	}
}
SHAR_EOF
echo shar: extracting room.c
cat - << \SHAR_EOF > room.c
/*
 * room.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 "room.h"
#include "object.h"
#include "move.h"
#include "monster.h"

short current_room;
room rooms[MAXROOMS];
boolean rooms_visited[MAXROOMS];

extern short blind;
extern boolean detect_monster;

light_up_room()
{
	short i, j;

	if (!blind) {
		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++) {
				if (dungeon[i][j] & MONSTER) {
					object *monster, *object_at();

					if (monster = object_at(&level_monsters, i, j)) {
						dungeon[monster->row][monster->col] &= (~MONSTER);
						monster->trail_char =
							get_dungeon_char(monster->row, monster->col);
						dungeon[monster->row][monster->col] |= MONSTER;
					}
				}
				mvaddch(i, j, get_dungeon_char(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 < (DROWS-2)) ? 1 : 0;
	j_end = (col < (DCOLS-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 (can_move(row, col, row+i, col+j)) {
				mvaddch(row+i, col+j, get_dungeon_char(row+i, col+j));
			}
		}
	}
}

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

	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 (blind) {
				mvaddch(i, j, ' ');
			} else {
				if (!(dungeon[i][j] & (OBJECT | STAIRS)) &&
					!(detect_monster && (dungeon[i][j] & MONSTER))) {
					if (!imitating(i, j)) {
						mvaddch(i, j, ' ');
					}
					if ((dungeon[i][j] & TRAP) && (!(dungeon[i][j] & HIDDEN))) {
						mvaddch(i, j, '^');
					}
				}
			}
		}
	}
}

get_dungeon_char(row, col)
register row, col;
{
	register unsigned short mask = dungeon[row][col];

	if (mask & MONSTER) {
		return(get_monster_char_row_col(row, col));
	}
	if (mask & OBJECT) {
		object *obj, *object_at();

		obj = object_at(&level_objects, row, col);
		return(get_mask_char(obj->what_is));
	}
	if (mask & (TUNNEL | STAIRS | HORWALL | VERTWALL | FLOOR | DOOR)) {
		if ((mask & (TUNNEL| STAIRS)) && (!(mask & HIDDEN))) {
			return(((mask & STAIRS) ? '%' : '#'));
		}
		if (mask & HORWALL) {
			return('-');
		}
		if (mask & VERTWALL) {
			return('|');
		}
		if (mask & FLOOR) {
			if (mask & TRAP) {
				if (!(dungeon[row][col] & HIDDEN)) {
					return('^');
				}
			}
			return('.');
		}
		if (mask & DOOR) {
			if (mask & HIDDEN) {
				if (((col > 0) && (dungeon[row][col-1] & HORWALL)) ||
					((col < (DCOLS-1)) && (dungeon[row][col+1] & HORWALL))) {
					return('-');
				} else {
					return('|');
				}
			} else {
				return('+');
			}
		}
	}
	return(' ');
}

get_mask_char(mask)
register unsigned short mask;
{
		switch(mask) {
		case SCROLL:
			return('?');
		case POTION:
			return('!');
		case GOLD:
			return('*');
		case FOOD:
			return(':');
		case WAND:
			return('/');
		case ARMOR:
			return(']');
		case WEAPON:
			return(')');
		case RING:
			return('=');
		case AMULET:
			return(',');
		default:
			return('~');	/* unknown, something is wrong */
		}
}

get_rand_row_col(row, col, mask)
short *row, *col;
unsigned short mask;
{
	short rn;

	do {
		*row = get_rand(MIN_ROW, DROWS-2);
		*col = get_rand(0, DCOLS-1);
		rn = get_room_number(*row, *col);
	} while ((rn == NO_ROOM) ||
		(!(dungeon[*row][*col] & mask)) ||
		(dungeon[*row][*col] & (~mask)) ||
		(!(rooms[rn].is_room & (R_ROOM | R_MAZE))));
}

get_rand_room()
{
	short i;

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

	return(i);
}

fill_party_room_with_objects(rn)
{
	short i, j, nf = 0;
	object *obj, *get_rand_object();
	short n, N, row, col;
	boolean found;

	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++) {
		for (j = found = 0; ((!found) && (j < 250)); j++) {
			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);
			if ((dungeon[row][col] == FLOOR) || (dungeon[row][col] == TUNNEL)) {
				found = 1;
			}
		}
		if (found) {
			obj = get_rand_object();
			put_object_at(obj, row, col);
			nf++;
		}
	}
	return(nf);
}

get_room_number(row, col)
register 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(DROWS-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);
}

is_all_connected()
{
	short i, starting_room;

	for (i = 0; i < MAXROOMS; i++) {
		rooms_visited[i] = 0;
		if (rooms[i].is_room & (R_ROOM | R_MAZE)) {
			starting_room = i;
		}
	}

	visit_rooms(starting_room);

	for (i = 0; i < MAXROOMS; i++) {
		if ((rooms[i].is_room & (R_ROOM | R_MAZE)) && (!rooms_visited[i])) {
			return(0);
		}
	}
	return(1);
}

visit_rooms(rn)
int rn;
{
	short i;
	short other_rn;

	rooms_visited[rn] = 1;

	for (i = 0; i < 4; i++) {
		other_rn = rooms[rn].doors[i].other_room;
		if ((other_rn >= 0) && (!rooms_visited[other_rn])) {
			visit_rooms(other_rn);
		}
	}
}

draw_magic_map()
{
	short i, j, ch, och;
	unsigned short mask = (HORWALL | VERTWALL | DOOR | TUNNEL | TRAP | STAIRS |
			MONSTER);
	unsigned short s;

	for (i = 0; i < DROWS; i++) {
		for (j = 0; j < DCOLS; j++) {
			s = dungeon[i][j];
			if (s & mask) {
				if (((ch = mvinch(i, j)) == ' ') ||
					((ch >= 'A') && (ch <= 'Z')) || (s & (TRAP | HIDDEN))) {
					och = ch;
					dungeon[i][j] &= (~HIDDEN);
					if (s & HORWALL) {
						ch = '-';
					} else if (s & VERTWALL) {
						ch = '|';
					} else if (s & DOOR) {
						ch = '+';
					} else if (s & TRAP) {
						ch = '^';
					} else if (s & STAIRS) {
						ch = '%';
					} else if (s & TUNNEL) {
						ch = '#';
					} else {
						continue;
					}
					if ((!(s & MONSTER)) || (och == ' ')) {
						addch(ch);
					}
					if (s & MONSTER) {
						object *monster, *object_at();

						if (monster = object_at(&level_monsters, i, j)) {
							monster->trail_char = ch;
						}
					}
				}
			}
		}
	}
}

door_course(monster, entering, row, col)
object *monster;
short entering, row, col;
{
	short i, j, k, rn;
	short r, rr;

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

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

	if (entering) {		/* entering room */
		/* look for door to some other room */
		r = get_rand(0, MAXROOMS-1);
		for (i = 0; i < MAXROOMS; i++) {
			rr = (r + i) % MAXROOMS;
			if ((!(rooms[rr].is_room & (R_ROOM | R_MAZE))) || (rr == rn)) {
				continue;
			}
			for (k = 0; k < 4; k++) {
				if (rooms[rr].doors[k].other_room == rn) {
					monster->trow = rooms[rr].doors[k].other_row;
					monster->tcol = rooms[rr].doors[k].other_col;
					if ((monster->trow == row) &&
						(monster->tcol == col)) {
						continue;
					}
					return;
				}
			}
		}
		/* look for door to dead end */
		for (i = rooms[rn].top_row; i <= rooms[rn].bottom_row; i++) {
			for (j = rooms[rn].left_col; j <= rooms[rn].right_col; j++) {
				if ((i != monster->row) && (j != monster->col) &&
					(dungeon[i][j] & DOOR)) {
					monster->trow = i;
					monster->tcol = j;
					return;
				}
			}
		}
		/* return monster to room that he came from */
		for (i = 0; i < MAXROOMS; i++) {
			for (j = 0; j < 4; j++) {
				if (rooms[i].doors[j].other_room == rn) {
					for (k = 0; k < 4; k++) {
						if (rooms[rn].doors[k].other_room == i) {
							monster->trow = rooms[rn].doors[k].other_row;
							monster->tcol = rooms[rn].doors[k].other_col;
							return;
						}
					}
				}
			}
		}
		/* no place to send monster */
		monster->trow = -1;
	} else {		/* exiting room */
		if (!get_other_room(rn, &row, &col)) {
			monster->trow = NO_ROOM;
		} else {
			monster->trow = row;
			monster->tcol = col;
		}
	}
}

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

	if (*row == rooms[rn].top_row) {
		d = UP/2;
	} else if (*row == rooms[rn].bottom_row) {
		d = DOWN/2;
	} else if (*col == rooms[rn].left_col) {
		d = LEFT/2;
	} else if (*col == rooms[rn].right_col) {
		d = RIGHT/2;
	}
	if ((d != -1) && (rooms[rn].doors[d].other_room >= 0)) {
		*row = rooms[rn].doors[d].other_row;
		*col = rooms[rn].doors[d].other_col;
		return(1);
	}
	return(0);
}
SHAR_EOF
echo shar: extracting save.c
cat - << \SHAR_EOF > save.c
/*
 * save.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 <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include "object.h"
#include "room.h"

short write_failed = 0;
char *save_file = "";

extern boolean detect_monster;
extern short current_level, max_level;
extern char hunger_str[];
extern char login_name[];
extern short party_room;
extern short party_counter;
extern short foods;
extern boolean is_wood[];
extern short current_room;
extern boolean being_held;
extern short bear_trap;
extern short halluc;
extern short blind;
extern short confused;
extern short levitate;
extern short haste_self;
extern boolean see_invisible;
extern boolean detect_monster;
extern boolean wizard;
extern boolean score_only;
extern short m_moves;

extern boolean message_cleared;

save_game()
{
	char fname[64];

	if (!get_input_line("file name?", save_file, fname, "game not saved",
		0, 1)) {
		return;
	}
	check_message();
	message(fname, 0);
	save_into_file(fname);
}

save_into_file(save_file)
char *save_file;
{
	FILE *fp;
	int i;
	struct stat sbuf;
	struct timeval tv;
	struct timezone tzp;
	char name_buffer[80];
	char *getenv(), *hptr;

	if (save_file[0] == '~') {
		if (hptr = getenv("HOME")) {
			strcpy(name_buffer, hptr);
			strcat(name_buffer, save_file+1);
			save_file = name_buffer;
		}
	}
	if (((fp = fopen(save_file, "w")) == NULL) || stat(save_file, &sbuf)) {
		message("problem accessing the save file", 0);
		return;
	}
	ignore_signals();
	write_failed = 0;
	xxx(1);
	r_write(fp, &detect_monster, sizeof(detect_monster));
	r_write(fp, &current_level, sizeof(current_level));
	r_write(fp, &max_level, sizeof(max_level));
	write_string(hunger_str, fp);
	write_string(login_name, fp);
	r_write(fp, &party_room, sizeof(party_room));
	r_write(fp, &party_counter, sizeof(party_counter));
	write_pack(&level_monsters, fp);
	write_pack(&level_objects, fp);
	r_write(fp, &sbuf.st_ino, sizeof(ino_t));
	rw_dungeon(fp, 1);
	r_write(fp, &foods, sizeof(foods));
	r_write(fp, &rogue, sizeof(struct fighter));
	write_pack(&rogue.pack, fp);
	rw_id(id_potions, fp, POTIONS, 1);
	rw_id(id_scrolls, fp, SCROLLS, 1);
	rw_id(id_wands, fp, WANDS, 1);
	rw_id(id_rings, fp, RINGS, 1);
	r_write(fp, traps, (MAX_TRAPS * sizeof(trap)));
	r_write(fp, is_wood, (WANDS * sizeof(boolean)));
	r_write(fp, &current_room, sizeof(current_room));
	rw_rooms(fp, 1);
	r_write(fp, &being_held, sizeof(being_held));
	r_write(fp, &bear_trap, sizeof(bear_trap));
	r_write(fp, &halluc, sizeof(halluc));
	r_write(fp, &blind, sizeof(blind));
	r_write(fp, &confused, sizeof(confused));
	r_write(fp, &levitate, sizeof(levitate));
	r_write(fp, &haste_self, sizeof(haste_self));
	r_write(fp, &see_invisible, sizeof(see_invisible));
	r_write(fp, &detect_monster, sizeof(detect_monster));
	r_write(fp, &wizard, sizeof(wizard));
	r_write(fp, &score_only, sizeof(score_only));
	r_write(fp, &m_moves, sizeof(m_moves));
	gettimeofday(&tv, &tzp); tv.tv_sec += 10;
	r_write(fp, &tv.tv_sec, sizeof(long));
	fclose(fp);

	if (write_failed) {
		unlink(save_file);
	} else {
		clean_up("");
	}
}

restore(fname)
char *fname;
{
	FILE *fp;
	short i;
	struct stat sbuf;
	ino_t inode;
	long seconds;
	char buf[4];

	if (stat(fname, &sbuf) || ((fp = fopen(fname, "r")) == NULL)) {
		clean_up("cannot open file", 0);
	}
	if (sbuf.st_nlink > 1) {
		clean_up("file has link");
	}
	xxx(1);
	r_read(fp, &detect_monster, sizeof(detect_monster));
	r_read(fp, &current_level, sizeof(current_level));
	r_read(fp, &max_level, sizeof(max_level));
	read_string(hunger_str, fp);
	{
		char buf[40];

		strcpy(buf, login_name);
		read_string(login_name, fp);
		if (strcmp(buf, login_name)) {
			clean_up("you're not the original player");
		}
	}
	r_read(fp, &party_room, sizeof(party_room));
	r_read(fp, &party_counter, sizeof(party_counter));
	read_pack(&level_monsters, fp, 0);
	read_pack(&level_objects, fp, 0);
	r_read(fp, &inode, sizeof(ino_t));
	if (sbuf.st_ino != inode) {
		clean_up("sorry, saved game is not in the same file");
	}
	rw_dungeon(fp, 0);
	r_read(fp, &foods, sizeof(foods));
	r_read(fp, &rogue, sizeof(struct fighter));
	read_pack(&rogue.pack, fp, 1);
	rw_id(id_potions, fp, POTIONS, 0);
	rw_id(id_scrolls, fp, SCROLLS, 0);
	rw_id(id_wands, fp, WANDS, 0);
	rw_id(id_rings, fp, RINGS, 0);
	r_read(fp, traps, (MAX_TRAPS * sizeof(trap)));
	r_read(fp, is_wood, (WANDS * sizeof(boolean)));
	r_read(fp, &current_room, sizeof(current_room));
	rw_rooms(fp, 0);
	r_read(fp, &being_held, sizeof(being_held));
	r_read(fp, &bear_trap, sizeof(bear_trap));
	r_read(fp, &halluc, sizeof(halluc));
	r_read(fp, &blind, sizeof(blind));
	r_read(fp, &confused, sizeof(confused));
	r_read(fp, &levitate, sizeof(levitate));
	r_read(fp, &haste_self, sizeof(haste_self));
	r_read(fp, &see_invisible, sizeof(see_invisible));
	r_read(fp, &detect_monster, sizeof(detect_monster));
	r_read(fp, &wizard, sizeof(wizard));
	r_read(fp, &score_only, sizeof(score_only));
	r_read(fp, &m_moves, sizeof(m_moves));
	r_read(fp, &seconds, sizeof(long));

	if (fread(buf, 1, 1, fp) > 0) {
		clear();
		clean_up("extra characters in file");
	}
	if (seconds < sbuf.st_mtime) {
		clear();
		clean_up("sorry, file has been touched");
	}
	if ((!wizard) && unlink(fname)) {
		clean_up("cannot unlink file");
	}
	message_cleared = 0;
	ring_stats(0);
	fclose(fp);
}

write_pack(pack, fp)
object *pack;
FILE *fp;
{
	struct object t;

	while (pack = pack->next_object) {
		r_write(fp, pack, sizeof(struct object));
	}
	t.ichar = t.what_is = 0;
	r_write(fp, &t, sizeof(struct object));
}

read_pack(pack, fp, is_rogue)
object *pack;
FILE *fp;
boolean is_rogue;
{
	struct object read_obj, *new_obj;
	object *alloc_object();

	for (;;) {
		r_read(fp, &read_obj, sizeof(struct object));
		if (read_obj.ichar == 0) {
			pack->next_object = (object *) 0;
			break;
		}
		new_obj = alloc_object();
		*new_obj = read_obj;
		if (is_rogue) {
			if (new_obj->in_use_flags & BEING_WORN) {
					do_wear(new_obj);
			} else if (new_obj->in_use_flags & BEING_WIELDED) {
					do_wield(new_obj);
			} else if (new_obj->in_use_flags & (ON_EITHER_HAND)) {
				do_put_on(new_obj,
					((new_obj->in_use_flags & ON_LEFT_HAND) ? 1 : 0));
			}
		}
		pack->next_object = new_obj;
		pack = new_obj;
	}
}

rw_dungeon(fp, rw)
FILE *fp;
boolean rw;
{
	short i, j;
	char ch;

	for (i = 0; i < DROWS; i++) {
		if (rw) {
			r_write(fp, dungeon[i], (DCOLS * sizeof(dungeon[0][0])));
			for (j = 0; j < DCOLS; j++) {
				ch = mvinch(i, j);
				r_write(fp, &ch, 1);
			}
		} else {
			r_read(fp, dungeon[i], (DCOLS * sizeof(dungeon[0][0])));
			for (j = 0; j < DCOLS; j++) {
				r_read(fp, &ch, 1);
				mvaddch(i, j, ch);
			}
		}
	}
}

rw_id(id_table, fp, n, wr)
struct identify id_table[];
FILE *fp;
int n;
boolean wr;
{
	short i;

	for (i = 0; i < n; i++) {
		if (wr) {
			r_write(fp, &(id_table[i].value), sizeof(short));
			r_write(fp, &(id_table[i].id_status), sizeof(unsigned char));
			write_string(id_table[i].title, fp);
		} else {
			r_read(fp, &(id_table[i].value), sizeof(short));
			r_read(fp, &(id_table[i].id_status), sizeof(unsigned char));
			read_string(id_table[i].title, fp);
		}
	}
}

write_string(s, fp)
char *s;
FILE *fp;
{
	short n;

	n = strlen(s) + 1;
	xxxx(s, n);
	r_write(fp, &n, sizeof(short));
	r_write(fp, s, n);
}

read_string(s, fp)
char *s;
FILE *fp;
{
	short n;

	r_read(fp, &n, sizeof(short));
	r_read(fp, s, n);
	xxxx(s, n);
}

rw_rooms(fp, rw)
FILE *fp;
boolean rw;
{
	short i;

	for (i = 0; i < MAXROOMS; i++) {
		rw ? r_write(fp, (rooms + i), sizeof(struct room)) :
			r_read(fp, (rooms + i), sizeof(struct room));
	}
}

r_read(fp, buf, n)
FILE *fp;
char *buf;
int n;
{
	if (fread(buf, 1, n, fp) != n) {
		clean_up("read() failed, don't know why");
	}
}

r_write(fp, buf, n)
FILE *fp;
char *buf;
int n;
{
	if (!write_failed) {
		if (fwrite(buf, 1, n, fp) != n) {
			message("write() failed, don't know why", 0);
			sound_bell();
			write_failed = 1;
		}
	}
}
SHAR_EOF
echo shar: extracting score.c
cat - << \SHAR_EOF > score.c
/*
 * score.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 <signal.h>
#include <curses.h>
#include "object.h"
#include "monster.h"
#include "room.h"
#include <sys/file.h>

char *score_file = SCORE_FILE;

extern char login_name[];
extern char *monster_names[];
extern short max_level, message_cleared;
extern boolean score_only, show_skull;
extern char *byebye_string, *nick_name;

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

	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 POISON_DART:
			strcpy(buf, "killed by a dart");
			break;
		case QUIT:
			strcpy(buf, "quit");
			break;
		}
	} else {
		strcpy(buf, "Killed by ");
		if (is_vowel(monster_names[monster->m_char - 'A'][0])) {
			strcat(buf, "an ");
		} else {
			strcat(buf, "a ");
		}
		strcat(buf, monster_names[monster->m_char - 'A']);
	}
	strcat(buf, " with ");
	sprintf(buf+strlen(buf), "%d gold", rogue.gold);
	if ((!other) && show_skull) {
		clear();
		mvaddstr(4, 32, "__---------__");
		mvaddstr(5, 30, "_~             ~_");
		mvaddstr(6, 29, "/                 \\");
		mvaddstr(7, 28, "~                   ~");
		mvaddstr(8, 27, "/                     \\");
		mvaddstr(9, 27, "|    XXXX     XXXX    |");
		mvaddstr(10, 27, "|    XXXX     XXXX    |");
		mvaddstr(11, 27, "|    XXX       XXX    |");
		mvaddstr(12, 28, "\\         @         /");
		mvaddstr(13, 29, "--\\     @@@     /--");
		mvaddstr(14, 30, "| |    @@@    | |");
		mvaddstr(15, 30, "| |           | |");
		mvaddstr(16, 30, "| vvVvvvvvvvVvv |");
		mvaddstr(17, 30, "|  ^^^^^^^^^^^  |");
		mvaddstr(18, 31, "\\_           _/");
		mvaddstr(19, 33, "~---------~");
		center(21, (nick_name[0] ? nick_name : login_name));
		center(22, buf);
		if (message_cleared) {
			message("", 0);
		}
	} else {
		message(buf, 0);
	}
	message("", 0);
	put_scores(monster, other);
}

win()
{
	unwield(rogue.weapon);		/* disarm and relax */
	unwear(rogue.armor);
	un_put_on(rogue.left_ring);
	un_put_on(rogue.right_ring);

	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, "Fighters' Guild.   You return home,  sell all your");
	mvaddstr(19, 11, "treasures at great profit and retire into comfort.");
	message("", 0);
	message("", 0);
	id_all();
	sell_pack();
	put_scores((object *) 0, WIN);
}

quit(from_intrpt)
boolean from_intrpt;
{
	char buf[128];
	short i, orow, ocol, mc;

	ignore_signals();

	if (from_intrpt) {

		orow = curscr->_cury;
		ocol = curscr->_curx;
		mc = message_cleared;

		for (i = 0; i < DCOLS; i++) {
			buf[i] = mvinch(0, i);
		}
	}
	check_message();
	message("really quit?", 1);
	if (rgetchar() != 'y') {
		heed_signals();
		check_message();
		if (from_intrpt) {
			for (i = 0; i < DCOLS; i++) {
				mvaddch(0, i, buf[i]);
			}
			message_cleared = mc;
			move(orow, ocol);
			refresh();
		}
		return;
	}
	if (from_intrpt) {
		clean_up(byebye_string);
	}
	check_message();
	killed_by(0, QUIT);
}

put_scores(monster, other)
object *monster;
short other;
{
	short i, j, n, rank = 10, x;
	char scores[10][82];
	char nick_names[10][30];
	char buf[100];
	FILE *fp;
	int s;
	long xxx();
	boolean dont_insert = 0, failed = 0;
	char *mode = "r+w";

	while ((fp = fopen(score_file, mode)) == NULL) {
		if (!failed) {
			mode = "w";
		} else {
			message("cannot read/write/create score file", 0);
			goto M;
		}
		failed = 1;
	}
	xxx(1);

	for (i = 0; i < 10; i++) {
L:		if (((n = fread(scores[i], 1, 80, fp)) < 80) && (n != 0)) {
			message("error in score file format", 0);
M:			message("", 0);
			clean_up("sorry, score file is out of order");
		} else if (n == 0) {
			break;
		} else {
			xxxx(scores[i], 80);
			if ((n = fread(nick_names[i], 1, 30, fp)) != 30) {
				goto M;
			}
			xxxx(nick_names[i], 30);
		}
		if (score_only) {
			continue;
		}
		if (!name_cmp(scores[i]+15, login_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 || score_only) 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, nick_names, nick_name, rank, i, monster,
			other);

		if (i < 10) {
			i++;
		}
	}
	rewind(fp);
DI:
	clear();
	mvaddstr(3, 30, "Top  Ten  Rogueists");
	mvaddstr(8, 0, "Rank   Score   Name");

	ignore_signals();

	xxx(1);

	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';
		}
		nick_namize(buf, scores[j], nick_names[j]);
		mvaddstr(j+10, 0, buf);
		if (rank < 10) {
			xxxx(scores[j], 80);
			fwrite(scores[j], 1, 80, fp);
			xxxx(nick_names[j], 30);
			fwrite(nick_names[j], 1, 30, fp);
		}
		if (j == rank) {
			standend();
		}
	}
	refresh();
	fclose(fp);
	message("", 0);
	if (score_only) {
		message("", 0);
	}
	clean_up("");
}

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

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

	if (other) {
		switch(other) {
		case HYPOTHERMIA:
			strcat(buf, "died of hypothermia");
			break;
		case STARVATION:
			strcat(buf, "died of starvation");
			break;
		case POISON_DART:
			strcat(buf, "killed by a dart");
			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->m_char - 'A'][0])) {
			strcat(buf, "an ");
		} else {
			strcat(buf, "a ");
		}
		strcat(buf, monster_names[monster->m_char - '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);
	strcpy(nick_names[rank], n_name);
}

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 < DROWS) {
			sprintf(buf, "%5d      ", val);
			get_description(obj, buf+11);
			mvaddstr(row++, 0, buf);
		}
NEXT:		obj = obj->next_object;
	}
	refresh();
	if (rogue.gold > MAX_GOLD) {
		rogue.gold = MAX_GOLD;
	}
	message("", 0);
}

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 == DAGGER) || (wc == SHURIKEN) ||
			(wc == DART)) {
			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 + 1);
		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;
	}
}

name_cmp(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);
}

xxxx(buf, n)
unsigned char *buf;
short n;
{
	short i;
	unsigned char c;
	long xxx();

	for (i = 0; i < n; i++) {
		c = (unsigned char) xxx(0);
		buf[i] ^= c;
	}
}

long
xxx(st)
short st;
{
	static long f, s;
	long r;

	if (st) {
		f = 37;
		s = 7;
		return(0L);
	}
	r = ((f * s) + 9337) % 8887;
	f = s;
	s = r;
	return(r);
}

nick_namize(buf, score, n_name)
char *buf, *score, *n_name;
{
	short i = 15, j;

	if (!n_name[0]) {
		strcpy(buf, score);
		return;
	}
	strncpy(buf, score, 16);

	while (score[i] != ':') {
		i++;
	}

	strcpy(buf+15, n_name);
	j = strlen(buf);

	while (score[i]) {
		buf[j++] = score[i++];
	}
	buf[j] = 0;
	buf[79] = 0;
}

center(row, buf)
short row;
char *buf;
{
	short margin;

	margin = ((DCOLS - strlen(buf)) / 2);
	mvaddstr(row, margin, buf);
}
SHAR_EOF
echo shar: extracting throw.c
cat - << \SHAR_EOF > throw.c
/*
 * throw.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 "room.h"
#include "monster.h"

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

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

	while (!is_direction(dir = rgetchar())) {
		sound_bell();
		if (first_miss) {
			message("direction? ", 0);
			first_miss = 0;
		}
	}
	check_message();
	if (dir == CANCEL) {
		return;
	}
	if ((wch = get_pack_letter("throw what?", WEAPON)) == CANCEL) {
		return;
	}
	check_message();

	if (!(weapon = get_letter_object(wch))) {
		message("no such item.", 0);
		return;
	}
	if ((weapon->in_use_flags & BEING_USED) && weapon->is_cursed) {
		message(curse_message, 0);
		return;
	}
	row = rogue.row; col = rogue.col;

	if ((weapon->in_use_flags & BEING_WIELDED) && (weapon->quantity <= 1)) {
		unwield(rogue.weapon);
	} else if (weapon->in_use_flags & BEING_WORN) {
		mv_aquatars();
		unwear(rogue.armor);
		print_stats(STAT_ARMOR);
	} else if (weapon->in_use_flags & ON_EITHER_HAND) {
		un_put_on(weapon);
	}
	monster = get_thrown_at_monster(weapon, dir, &row, &col);
	mvaddch(rogue.row, rogue.col, rogue.fchar);
	refresh();

	if (rogue_can_see(row, col) && ((row != rogue.row) || (col != rogue.col))){
		mvaddch(row, col, get_dungeon_char(row, col));
	}
	if (monster) {
		wake_up(monster);
		check_gold_seeker(monster);

		if (!throw_at_monster(monster, weapon)) {
			flop_weapon(weapon, row, col);
		}
	} else {
		flop_weapon(weapon, row, col);
	}
	vanish(weapon, 1, &rogue.pack);
}

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

	hit_chance = get_hit_chance(weapon);
	damage = get_weapon_damage(weapon);
	if ((weapon->which_kind == ARROW) &&
		(rogue.weapon && (rogue.weapon->which_kind == BOW))) {
		damage += get_weapon_damage(rogue.weapon);
		damage = ((damage * 2) / 3);
		hit_chance += (hit_chance / 3);
	} else if ((weapon->in_use_flags & BEING_WIELDED) &&
		((weapon->which_kind == DAGGER) ||
		(weapon->which_kind == SHURIKEN) ||
		(weapon->which_kind == DART))) {
		damage = ((damage * 3) / 2);
		hit_chance += (hit_chance / 3);
	}
	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  ");
	monster_damage(monster, damage);
	return(1);
}

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

	orow = *row; ocol = *col;

	ch = get_mask_char(obj->what_is);

	for (i = 0; i < 24; i++) {
		get_dir_rc(dir, row, col, 0);
		if ((dungeon[*row][*col] == NOTHING) ||
				((dungeon[*row][*col] & (HORWALL | VERTWALL | HIDDEN)) &&
				(!(dungeon[*row][*col] & TRAP)))) {
			*row = orow;
			*col = ocol;
			return(0);
		}
		if ((i != 0) && rogue_can_see(orow, ocol)) {
			mvaddch(orow, ocol, get_dungeon_char(orow, ocol));
		}
		if (rogue_can_see(*row, *col)) {
			if (!(dungeon[*row][*col] & MONSTER)) {
				mvaddch(*row, *col, ch);
			}
			refresh();
		}
		orow = *row; ocol = *col;
		if (dungeon[*row][*col] & MONSTER) {
			if (!imitating(*row, *col)) {
				return(object_at(&level_monsters, *row, *col));
			}
		}
		if (dungeon[*row][*col] & TUNNEL) {
			i += 2;
		}
	}
	return(0);
}

flop_weapon(weapon, row, col)
object *weapon;
short row, col;
{
	object *new_weapon, *alloc_object(), *monster;
	short i = 0;
	char msg[80];
	boolean found = 0;
	short mch, dch;
	unsigned short mon;

	while ((i < 9) && dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER)) {
		rand_around(i++, &row, &col);
		if ((row > (DROWS-2)) || (row < MIN_ROW) ||
			(col > (DCOLS-1)) || (col < 0) || (!dungeon[row][col]) ||
			(dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER))) {
			continue;
		}
		found = 1;
		break;
	}

	if (found || (i == 0)) {
		new_weapon = alloc_object();
		*new_weapon = *weapon;
		new_weapon->in_use_flags = NOT_USED;
		new_weapon->quantity = 1;
		new_weapon->ichar = 'L';
		put_object_at(new_weapon, row, col);
		if (rogue_can_see(row, col) &&
				((row != rogue.row) || (col != rogue.col))) {
			mon = dungeon[row][col] & MONSTER;
			dungeon[row][col] &= (~MONSTER);
			dch = get_dungeon_char(row, col);
			if (mon) {
				mch = mvinch(row, col);
				if (monster = object_at(&level_monsters, row, col)) {
					monster->trail_char = dch;
				}
				if ((mch < 'A') || (mch > 'Z')) {
					mvaddch(row, col, dch);
				}
			} else {
				mvaddch(row, col, dch);
			}
			dungeon[row][col] |= mon;
		}
	} 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);
}

rand_around(i, r, c)
short i, *r, *c;
{
	static char* pos = "\010\007\001\003\004\005\002\006\0";
	static short row, col;
	short j;

	if (i == 0) {
		short x, y, o, t;

		row = *r;
		col = *c;

		o = get_rand(1, 8);

		for (j = 0; j < 5; j++) {
			x = get_rand(0, 8);
			y = (x + o) % 9;
			t = pos[x];
			pos[x] = pos[y];
			pos[y] = t;
		}
	}
	switch((short)pos[i]) {
	case 0:
		*r = row + 1;
		*c = col + 1;
		break;
	case 1:
		*r = row + 1;
		*c = col - 1;
		break;
	case 2:
		*r = row - 1;
		*c = col + 1;
		break;
	case 3:
		*r = row - 1;
		*c = col - 1;
		break;
	case 4:
		*r = row;
		*c = col + 1;
		break;
	case 5:
		*r = row + 1;
		*c = col;
		break;
	case 6:
		*r = row;
		*c = col;
		break;
	case 7:
		*r = row - 1;
		*c = col;
		break;
	case 8:
		*r = row;
		*c = col - 1;
		break;
	}
}
SHAR_EOF
echo shar: extracting trap.c
cat - << \SHAR_EOF > trap.c
/*
 * trap.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 "monster.h"
#include "move.h"
#include "object.h"
#include "room.h"

trap traps[MAX_TRAPS];
boolean trap_door = 0;
short bear_trap = 0;

char *trap_strings[TRAPS * 2] = {
	"trap door",
			"you fell down a trap",
	"bear trap",
			"you are caught in a bear trap",
	"teleport trap",
			"teleport",
	"poison dart trap",
			"a small dart just hit you in the shoulder",
	"sleeping gas trap",
			"a strange white mist envelops you and you fall asleep",
	"rust trap",
			"a gush of water hits you on the head"
};

extern short current_level, party_room;
extern char *new_level_message;
extern boolean interrupted;
extern short ring_exp;
extern boolean sustain_strength;
extern short blind;

trap_at(row, col)
register row, col;
{
	short i;

	for (i = 0; ((i < MAX_TRAPS) && (traps[i].trap_type != NO_TRAP)); i++) {
		if ((traps[i].trap_row == row) && (traps[i].trap_col == col)) {
			return(traps[i].trap_type);
		}
	}
	return(NO_TRAP);
}

trap_rogue(row, col)
short row, col;
{
	short t;

	if ((t = trap_at(row, col)) == NO_TRAP) {
		return;
	}
	dungeon[row][col] &= (~HIDDEN);
	if (rand_percent(rogue.exp + ring_exp)) {
		message("the trap failed", 1);
		return;
	}
	switch(t) {
	case TRAP_DOOR:
		trap_door = 1;
		new_level_message = trap_strings[(t*2)+1];
		break;
	case BEAR_TRAP:
		message(trap_strings[(t*2)+1], 1);
		bear_trap = get_rand(4, 7);
		break;
	case TELEPORT_TRAP:
		mvaddch(rogue.row, rogue.col, '^');
		teleport();
		break;
	case POISON_DART_TRAP:
		message(trap_strings[(t*2)+1], 1);
		rogue.hp_current -= get_damage("1d6", 1);
		if (rogue.hp_current <= 0) {
			rogue.hp_current = 0;
		}
		if ((!sustain_strength) && rand_percent(40) &&
			(rogue.strength_current >= 3)) {
			rogue.strength_current--;
		}
		print_stats(STAT_HP | STAT_STRENGTH);
		if (rogue.hp_current <= 0) {
			killed_by((object *) 0, POISON_DART);
		}
		break;
	case SLEEPING_GAS_TRAP:
		message(trap_strings[(t*2)+1], 1);
		take_a_nap();
		break;
	case RUST_TRAP:
		message(trap_strings[(t*2)+1], 1);
		rust((object *) 0);
		break;
	}
}

add_traps()
{
	short i, n, tries = 0;
	short row, col;

	if (current_level <= 2) {
		n = 0;
	} else if (current_level <= 7) {
		n = get_rand(0, 2);
	} else if (current_level <= 11) {
		n = get_rand(1, 2);
	} else if (current_level <= 16) {
		n = get_rand(2, 3);
	} else if (current_level <= 21) {
		n = get_rand(2, 4);
	} else if (current_level <= (AMULET_LEVEL + 2)) {
		n = get_rand(3, 5);
	} else {
		n = get_rand(5, MAX_TRAPS);
	}
	for (i = 0; i < n; i++) {
		traps[i].trap_type = get_rand(0, (TRAPS - 1));

		if ((i == 0) && (party_room != NO_ROOM)) {
			do {
				row = get_rand((rooms[party_room].top_row+1),
						(rooms[party_room].bottom_row-1));
				col = get_rand((rooms[party_room].left_col+1),
						(rooms[party_room].right_col-1));
				tries++;
			} while ((dungeon[row][col] | (OBJECT | STAIRS | TRAP)) &&
					(tries < 15));
			if (dungeon[row][col] & (OBJECT | STAIRS | TRAP)) {
				get_rand_row_col(&row, &col, (FLOOR | MONSTER));
			}
		} else {
			get_rand_row_col(&row, &col, (FLOOR | MONSTER));
		}
		traps[i].trap_row = row;
		traps[i].trap_col = col;
		dungeon[row][col] |= (TRAP | HIDDEN);
	}
}

identify_trap()
{
	short dir, row, col;
	short t;

	message("direction? ", 0);

	while (!is_direction(dir = rgetchar())) {
		sound_bell();
	}
	check_message();

	if (dir == CANCEL) {
		return;
	}
	row = rogue.row;
	col = rogue.col;

	get_dir_rc(dir, &row, &col, 0);

	if ((dungeon[row][col] & TRAP) && (!(dungeon[row][col] & HIDDEN))) {
		t = trap_at(row, col);
		message(trap_strings[t*2], 0);
	} else {
		message("no trap there", 0);
	}
}

show_traps()
{
	short i, j;

	for (i = 0; i < DROWS; i++) {
		for (j = 0; j < DCOLS; j++) {
			if (dungeon[i][j] & TRAP) {
				mvaddch(i, j, '^');
			}
		}
	}
}

search(n, is_auto)
short n;
boolean is_auto;
{
	short s, i, j, row, col, t;
	short shown = 0, found = 0;
	static boolean register_search;

	for (i = -1; i <= 1; i++) {
		for (j = -1; j <= 1; j++) {
			row = rogue.row + i;
			col = rogue.col + j;
			if ((row < MIN_ROW) || (row >= (DROWS-1)) ||
					(col < 0) || (col >= DCOLS)) {
				continue;
			}
			if (dungeon[row][col] & HIDDEN) {
				found++;
			}
		}
	}
	for (s = 0; s < n; s++) {
		for (i = -1; i <= 1; i++) {
			for (j = -1; j <= 1; j++) {
				row = rogue.row + i;
				col = rogue.col + j ;
				if ((row < MIN_ROW) || (row >= (DROWS-1)) ||
						(col < 0) || (col >= DCOLS)) {
					continue;
				}
				if (dungeon[row][col] & HIDDEN) {
					if (rand_percent(17 + (rogue.exp + ring_exp))) {
						dungeon[row][col] &= (~HIDDEN);
						if ((!blind) && ((row != rogue.row) ||
								(col != rogue.col))) {
							mvaddch(row, col, get_dungeon_char(row, col));
						}
						shown++;
						if (dungeon[row][col] & TRAP) {
							t = trap_at(row, col);
							message(trap_strings[t*2], 1);
						}
					}
				}
				if (((shown == found) && (found > 0)) || interrupted) {
					return;
				}
			}
		}
		if ((!is_auto) && (register_search = !register_search)) {
			register_move();
		}
	}
}
SHAR_EOF