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

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:
#	main.c #	message.c #	monster.c #	monster.h #	room.h #	move.c #	move.h #	special_hit.c 
echo shar: extracting main.c
cat - << \SHAR_EOF > main.c
/*
 * main.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 "room.h"

extern short party_room;

main(argc, argv)
int argc;
char *argv[];
{
	if (init(argc, argv)) {		/* restored game */
		goto PL;
	}

	for (;;) {
		clear_level();
		make_level();
		put_objects();
		put_stairs();
		add_traps();
		put_monsters();
		put_player(party_room);
		print_stats(STAT_ALL);
PL:		
		play_level();
		free_stuff(&level_objects);
		free_stuff(&level_monsters);
	}
}
SHAR_EOF
echo shar: extracting message.c
cat - << \SHAR_EOF > message.c
/*
 * message.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"

char message_line[DCOLS] = "";
short message_col = 0;
boolean message_cleared = 1;
char hunger_str[8] = "";

extern boolean cant_int, did_int, interrupted, save_is_interactive;
extern short add_strength;
extern short current_level;

message(msg, intrpt)
char *msg;
boolean intrpt;
{
	if (!save_is_interactive) {
		return;
	}
	if (intrpt) {
		interrupted = 1;
		slurp();
	}
	cant_int = 1;

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

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

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

check_message()
{
	if (message_cleared) {
		return;
	}
	move(MIN_ROW-1, 0);
	clrtoeol();
	refresh();
	message_cleared = 1;
}

get_input_line(prompt, insert, buf, if_cancelled, add_blank, do_echo)
char *prompt, *buf, *insert;
char *if_cancelled;
boolean add_blank;
boolean do_echo;
{
	short ch;
	short i = 0, n;

	message(prompt, 0);
	n = strlen(prompt);

	if (insert[0]) {
		mvaddstr(0, n + 1, insert);
		strcpy(buf, insert);
		i = strlen(insert);
		move(0, (n + i + 1));
		refresh();
	}

	while (((ch = rgetchar()) != '\r') && (ch != '\n') && (ch != CANCEL)) {
		if ((ch >= ' ') && (ch <= '~') && (i < MAX_TITLE_LENGTH-2)) {
			if ((ch != ' ') || (i > 0)) {
				buf[i++] = ch;
				if (do_echo) {
					addch(ch);
				}
			}
		}
		if ((ch == '\b') && (i > 0)) {
			if (do_echo) {
				mvaddch(0, i + n, ' ');
				move(MIN_ROW-1, i+n);
			}
			i--;
		}
		refresh();
	}
	check_message();
	if (add_blank) {
		buf[i++] = ' ';
	} else {
		while ((i > 0) && (buf[i-1] == ' ')) {
			i--;
		}
	}

	buf[i] = 0;

	if ((ch == CANCEL) || (i == 0) || ((i == 1) && add_blank)) {
		if (if_cancelled) {
			message(if_cancelled, 0);
		}
		return(0);
	}
	return(i);
}

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

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

	for (i = 0; i < n; i++) {
		getchar();
	}
}

rgetchar()
{
	register ch;

	for(;;) {
		ch = getchar();

		switch(ch) {
		case '\022':
			wrefresh(curscr);
			break;
		case '\032':
			printf(CL);
			fflush(stdout);
			tstp();
			break;
		case 'X':
			save_screen();
			break;
		default:
			return(ch);
		}
	}
}
/*
Level: 99 Gold: 999999 Hp: 999(999) Str: 99(99) Arm: 99 Exp: 21/10000000 Hungry
0    5    1    5    2    5    3    5    4    5    5    5    6    5    7    5
*/

print_stats(stat_mask)
register stat_mask;
{
	char buf[16];
	boolean label;
	int row = DROWS - 1;

	label = (stat_mask & STAT_LABEL) ? 1 : 0;

	if (stat_mask & STAT_LEVEL) {
		if (label) {
			mvaddstr(row, 0, "Level: ");
		}
		/* max level taken care of in make_level() */
		sprintf(buf, "%d", current_level);
		mvaddstr(row, 7, buf);
		pad(buf, 2);
	}
	if (stat_mask & STAT_GOLD) {
		if (label) {
			if (rogue.gold > MAX_GOLD) {
				rogue.gold = MAX_GOLD;
			}
			mvaddstr(row, 10, "Gold: ");
		}
		sprintf(buf, "%d", rogue.gold);
		mvaddstr(row, 16, buf);
		pad(buf, 6);
	}
	if (stat_mask & STAT_HP) {
		if (label) {
			mvaddstr(row, 23, "Hp: ");
			if (rogue.hp_max > MAX_HP) {
				rogue.hp_current -= (rogue.hp_max - MAX_HP);
				rogue.hp_max = MAX_HP;
			}
		}
		sprintf(buf, "%d(%d)", rogue.hp_current, rogue.hp_max);
		mvaddstr(row, 27, buf);
		pad(buf, 8);
	}
	if (stat_mask & STAT_STRENGTH) {
		if (label) {
			mvaddstr(row, 36, "Str: ");
		}
		if (rogue.strength_max > MAX_STRENGTH) {
			rogue.strength_current -= (rogue.strength_max - MAX_STRENGTH);
			rogue.strength_max = MAX_STRENGTH;
		}
		sprintf(buf, "%d(%d)", (rogue.strength_current + add_strength),
			rogue.strength_max);
		mvaddstr(row, 41, buf);
		pad(buf, 6);
	}
	if (stat_mask & STAT_ARMOR) {
		if (label) {
			mvaddstr(row, 48, "Arm: ");
		}
		if (rogue.armor->damage_enchantment > MAX_ARMOR) {
			rogue.armor->damage_enchantment = MAX_ARMOR;
		}
		sprintf(buf, "%d", get_armor_class(rogue.armor));
		mvaddstr(row, 53, buf);
		pad(buf, 2);
	}
	if (stat_mask & STAT_EXP) {
		if (label) {
			mvaddstr(row, 56, "Exp: ");
		}
		/*  Max exp taken care of in add_exp() */
		sprintf(buf, "%d/%D", rogue.exp, rogue.exp_points);
		mvaddstr(row, 61, buf);
		pad(buf, 11);
	}
	if (stat_mask & STAT_HUNGER) {
		mvaddstr(row, 73, hunger_str);
		clrtoeol();
	}
	refresh();
}

pad(s, n)
char *s;
short n;
{
	short i;

	for (i = strlen(s); i < n; i++) {
		addch(' ');
	}
}

save_screen()
{
	FILE *fp;
	short i, j, row, col;
	char buf[DCOLS+2];
	boolean found_non_blank;

	row = curscr->_cury;
	col = curscr->_curx;

	if (fp = fopen("rogue.screen", "w")) {
		for (i = 0; i < DROWS; i++) {
			found_non_blank = 0;
			for (j = (DCOLS - 1); j >= 0; j--) {
				buf[j] = mvinch(i, j);
				if (!found_non_blank) {
					if ((buf[j] != ' ') || (j == 0)) {
						buf[j + ((j == 0) ? 0 : 1)] = 0;
						found_non_blank = 1;
					}
				}
			}
			fputs(buf, fp);
			putc('\n', fp);
		}
		fclose(fp);
	} else {
		sound_bell();
	}
	move(row, col);
	refresh();
}

sound_bell()
{
	putchar(7);
	fflush(stdout);
}
SHAR_EOF
echo shar: extracting monster.c
cat - << \SHAR_EOF > monster.c
/*
 * monster.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 "object.h"
#include "room.h"
#include "move.h"

object level_monsters;
boolean monster_disappeared;

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

object monster_tab[MONSTERS] = {
	{(ASLEEP|WAKENS|WANDERS|RUSTS),"0d0",25,'A',20,9,18,100,0,0,0,0,0},
	{(ASLEEP|WANDERS|FLITS),"1d3",10,'B',2,1,8,60,0,0,0,0,0},
	{(ASLEEP|WANDERS),"3d3/2d5",32,'C',15,7,16,85,0,10,0,0,0},
	{(ASLEEP|WAKENS|FLAMES),"4d6/4d9",145,'D',5000,21,126,100,0,90,0,0,0},
	{(ASLEEP|WAKENS),"1d3",11,'E',2,1,7,65,0,0,0,0,0},
	{(HOLDS|STATIONARY),"5d5",73,'F',91,12,126,80,0,0,0,0,0},
	{(ASLEEP|WAKENS|WANDERS|FLIES),"5d5/5d5",115,'G',
			2000,20,126,85,0,10,0,0,0},
	{(ASLEEP|WAKENS|WANDERS),"1d3/1d2",15,'H',3,1,10,67,0,0,0,0,0},
	{(ASLEEP|FREEZES),"0d0",15,'I',5,2,11,68,0,0,0,0,0},
	{(ASLEEP|WANDERS),"3d10/4d5",132,'J',3000,21,126,100,0,0,0,0,0},
	{(ASLEEP|WAKENS|WANDERS|FLIES),"1d4",10,'K',2,1,6,60,0,0,0,0,0},
	{(ASLEEP|STEALS_GOLD),"0d0",25,'L',21,6,16,75,0,0,0,0,0},
	{(ASLEEP|WAKENS|WANDERS|CONFUSES),"4d4/3d7",97,'M',
			250,18,126,85,0,25,0,0,0},
	{(ASLEEP|STEALS_ITEM),"0d0",25,'N',39,10,19,75,0,100,0,0,0},
	{(ASLEEP|WANDERS|WAKENS|SEEKS_GOLD),"1d6",25,'O',5,4,13,70,0,10,0,0,0},
	{(ASLEEP|INVISIBLE|WANDERS|FLITS),"5d4",76,'P',120,15,24,80,0,50,0,0,0},
	{(ASLEEP|WAKENS|WANDERS),"3d5",30,'Q',20,8,17,78,0,20,0,0,0},
	{(ASLEEP|WAKENS|WANDERS|STINGS),"2d5",19,'R',10,3,12,70,0,0,0,0,0},
	{(ASLEEP|WAKENS|WANDERS),"1d3",8,'S',2,1,9,50,0,0,0,0,0},
	{(ASLEEP|WAKENS|WANDERS),"4d6/1d4",75,'T',125,13,22,75,0,33,0,0,0},
	{(ASLEEP|WAKENS|WANDERS),"4d10",90,'U',
			200,17,26,85,0,33,0,0,0},
	{(ASLEEP|WAKENS|WANDERS|DRAINS_LIFE),"1d14/1d4",55,'V',
			350,19,126,85,0,18,0,0,0},
	{(ASLEEP|WANDERS|DRAINS_LEVEL),"2d8",45,'W',55,14,23,75,0,0,0,0,0},
	{(ASLEEP|IMITATES),"4d6",42,'X',110,16,25,75,0,0,0,0,0},
	{(ASLEEP|WANDERS),"3d6",35,'Y',50,11,20,80,0,20,0,0,0},
	{(ASLEEP|WAKENS|WANDERS),"1d7",21,'Z',8,5,14,69,0,0,0,0,0}
};

extern short current_level;
extern short current_room, party_room;
extern short blind, halluc, haste_self;
extern boolean detect_monster, see_invisible, r_see_invisible;
extern short stealthy;

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

	n = get_rand(4, 6);

	for (i = 0; i < n; i++) {
		monster = get_rand_monster((object *) 0, 0);
		if ((monster->m_flags & WANDERS) && coin_toss()) {
			wake_up(monster);
		}
		get_rand_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
		put_monster_at(row, col, monster);
	}
}

object *
get_rand_monster(monster, mn)
register object *monster;
register mn;
{
	object *alloc_object();

	if (!monster) {

		monster = alloc_object();

		for (;;) {
			mn = get_rand(0, MONSTERS-1);
			if ((current_level >= monster_tab[mn].first_level) &&
			(current_level <= monster_tab[mn].last_level)) {
				break;
			}
		}
	}
	*monster = monster_tab[mn];
	if (monster->m_flags & IMITATES) {
		monster->disguise = get_rand_obj_char();
	}
	if (current_level > (AMULET_LEVEL + 2)) {
		monster->m_flags |= HASTED;
	}
	monster->trow = NO_ROOM;
	return(monster);
}

move_monsters()
{
	register object *monster, *next_monster;
	boolean flew;

	if (haste_self % 2) {
		return;
	}

	monster = level_monsters.next_monster;

	while (monster) {
		next_monster = monster->next_monster;
		if (monster->m_flags & HASTED) {
			monster_disappeared = 0;
			mv_monster(monster, rogue.row, rogue.col);
			if (monster_disappeared) {
				goto NM;
			}
		} else if (monster->m_flags & SLOWED) {
			monster->slowed_toggle = !monster->slowed_toggle;
			if (monster->slowed_toggle) {
				goto NM;
			}
		}
		if ((monster->m_flags & CONFUSED) && confused_move(monster)) {
			goto NM;
		}
		flew = 0;
		if ((monster->m_flags & FLIES) && !(monster->m_flags & NAPPING) &&
			 !monster_can_go(monster, rogue.row, rogue.col)) {
			flew = 1;
			mv_monster(monster, rogue.row, rogue.col);
		}
		if (!(flew && monster_can_go(monster, rogue.row, rogue.col))) {
			mv_monster(monster, rogue.row, rogue.col);
		}
NM:		monster = next_monster;
	}
}

fill_party_room_with_monsters(rn, n)
int rn, n;
{
	short i, j;
	short row, col;
	object *monster, *get_rand_monster();
	boolean found;

	n += n;

	for (i = 0; i < MONSTERS; i++) {
		monster_tab[i].first_level -= (current_level % 3);
	}
	for (i = 0; i < n; i++) {
		if (no_room_for_monster(rn)) {
			break;
		}
		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] & MONSTER)) &&
				(dungeon[row][col] & (FLOOR | TUNNEL))) {
				found = 1;
			}
		}
		if (found) {
			monster = get_rand_monster((object *) 0, 0);
			if (!(monster->m_flags & IMITATES)) {
				monster->m_flags |= WAKENS;
			}
			put_monster_at(row, col, monster);
		}
	}
	for (i = 0; i < MONSTERS; i++) {
		monster_tab[i].first_level += (current_level % 3);
	}
}

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

	if (monster = object_at(&level_monsters, row, col)) {
		if ((!(detect_monster || see_invisible || r_see_invisible) &&
			(monster->m_flags & INVISIBLE)) || blind) {
			retval = monster->trail_char;
			return(retval);
		}
		if (monster->m_flags & IMITATES) {
			return(monster->disguise);
		}
		return(monster->m_char);
	}
}

get_monster_char(monster)
object *monster;
{
	if ((!(detect_monster || see_invisible || r_see_invisible) &&
		(monster->m_flags & INVISIBLE))
		|| blind) {
		return(monster->trail_char);
	}
	if (monster->m_flags & IMITATES) {
		return(monster->disguise);
	}
	return(monster->m_char);
}

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

	if (monster->m_flags & ASLEEP) {
		if (monster->m_flags & NAPPING) {
			if (--monster->nap_length <= 0) {
				monster->m_flags &= (~(NAPPING | ASLEEP));
			}
			return;
		}
		if ((monster->m_flags & WAKENS) &&
			 rogue_is_around(monster->row, monster->col) &&
			 rand_percent(((stealthy > 0) ?
			 	(WAKE_PERCENT / (STEALTH_FACTOR + stealthy)) :
				WAKE_PERCENT))) {
			wake_up(monster);
		}
		return;
	} else if (monster->m_flags & ALREADY_MOVED) {
		monster->m_flags &= (~ALREADY_MOVED);
		return;
	}
	if ((monster->m_flags & FLITS) && flit(monster)) {
		return;
	}
	if ((monster->m_flags & STATIONARY) &&
		(!monster_can_go(monster, rogue.row, rogue.col))) {
		return;
	}
	if (monster->m_flags & FREEZING_ROGUE) {
		return;
	}
	if ((monster->m_flags & CONFUSES) && m_confuse(monster)) {
		return;
	}
	if (monster_can_go(monster, rogue.row, rogue.col)) {
		monster_hit(monster, 0, 0);
		return;
	}
	if ((monster->m_flags & FLAMES) && flame_broil(monster)) {
		return;
	}
	if ((monster->m_flags & SEEKS_GOLD) && seek_gold(monster)) {
		return;
	}
	if ((monster->trow == monster->row) &&
		   (monster->tcol == monster->col)) {
		monster->trow = NO_ROOM;
	} else if (monster->trow != NO_ROOM) {
		row = monster->trow;
		col = monster->tcol;
	}
	if (monster->row > row) {
		row = monster->row - 1;
	} else if (monster->row < row) {
		row = monster->row + 1;
	}
	if ((dungeon[row][monster->col] & DOOR) &&
		 mtry(monster, row, monster->col)) {
		return;
	}
	if (monster->col > col) {
		col = monster->col - 1;
	} else if (monster->col < col) {
		col = monster->col + 1;
	}
	if ((dungeon[monster->row][col] & DOOR) &&
		 mtry(monster, monster->row, col)) {
		return;
	}
	if (mtry(monster, row, col)) {
		return;
	}

	for (i = 0; i <= 5; i++) tried[i] = 0;

	for (i = 0; i < 6; i++) {
NEXT_TRY:	n = get_rand(0, 5);
		switch(n) {
		case 0:
			if (!tried[n] && mtry(monster, row, monster->col-1)) {
				goto O;
			}
			break;
		case 1:
			if (!tried[n] && mtry(monster, row, monster->col)) {
				goto O;
			}
			break;
		case 2:
			if (!tried[n] && mtry(monster, row, monster->col+1)) {
				goto O;
			}
			break;
		case 3:
			if (!tried[n] && mtry(monster, monster->row-1, col)) {
				goto O;
			}
			break;
		case 4:
			if (!tried[n] && mtry(monster, monster->row, col)) {
				goto O;
			}
			break;
		case 5:
			if (!tried[n] && mtry(monster, monster->row+1, col)) {
				goto O;
			}
			break;
		}
		if (!tried[n]) {
			tried[n] = 1;
		} else {
			goto NEXT_TRY;
		}
	}
O:
	if ((monster->row == monster->o_row) && (monster->col == monster->o_col)) {
		if (++(monster->o) > 4) {
			if ((monster->trow == NO_ROOM) &&
					(!monster_can_see(monster, rogue.row, rogue.col))) {
				monster->trow = get_rand(1, (DROWS - 2));
				monster->tcol = get_rand(0, (DCOLS - 1));
			} else {
				monster->trow = NO_ROOM;
				monster->o = 0;
			}
		}
	} else {
		monster->o_row = monster->row;
		monster->o_col = monster->col;
		monster->o = 0;
	}
}

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

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

	mrow = monster->row;
	mcol = monster->col;

	dungeon[mrow][mcol] &= ~MONSTER;
	dungeon[row][col] |= MONSTER;

	c = mvinch(mrow, mcol);

	if ((c >= 'A') && (c <= 'Z')) {
		if (!detect_monster) {
			mvaddch(mrow, mcol, monster->trail_char);
		} else {
			if (rogue_can_see(mrow, mcol)) {
				mvaddch(mrow, mcol, monster->trail_char);
			} else {
				if (monster->trail_char == '.') {
					monster->trail_char = ' ';
				}
				mvaddch(mrow, mcol, monster->trail_char);
			}
		}
	}
	monster->trail_char = mvinch(row, col);
	if (!blind && (detect_monster || rogue_can_see(row, col))) {
		if ((!(monster->m_flags & INVISIBLE) ||
			(detect_monster || see_invisible || r_see_invisible))) {
			mvaddch(row, col, get_monster_char(monster));
		}
	}
	if ((dungeon[row][col] & DOOR) &&
		(get_room_number(row, col) != current_room) &&
		(dungeon[mrow][mcol] == FLOOR) && !blind) {
			mvaddch(mrow, mcol, ' ');
	}
	if (dungeon[row][col] & DOOR) {
			door_course(monster, (dungeon[mrow][mcol] & TUNNEL), row, col);
	} else {
		monster->row = row;
		monster->col = col;
	}
}

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

	dr = monster->row - row;	/* check if move distance > 1 */
	if ((dr >= 2) || (dr <= -2)) {
		return(0);
	}
	dc = monster->col - col;
	if ((dc >= 2) || (dc <= -2)) {
		return(0);
	}
	if ((!dungeon[monster->row][col]) || (!dungeon[row][monster->col])) {
		return(0);
	}
	if ((!is_passable(row, col)) || (dungeon[row][col] & MONSTER)) {
		return(0);
	}
	if ((monster->row!=row)&&(monster->col!=col)&&((dungeon[row][col]&DOOR) ||
		(dungeon[monster->row][monster->col]&DOOR))) {
		return(0);
	}
	if (!(monster->m_flags & (FLITS | CONFUSED | CAN_FLIT)) &&
		(monster->trow == NO_ROOM)) {
		if ((monster->row < rogue.row) && (row < monster->row)) return(0);
		if ((monster->row > rogue.row) && (row > monster->row)) return(0);
		if ((monster->col < rogue.col) && (col < monster->col)) return(0);
		if ((monster->col > rogue.col) && (col > monster->col)) return(0);
	}
	if (dungeon[row][col] & OBJECT) {
		obj = object_at(&level_objects, row, col);
		if ((obj->what_is == SCROLL) && (obj->which_kind == SCARE_MONSTER)) {
			return(0);
		}
	}
	return(1);
}

wake_up(monster)
object *monster;
{
	if (!(monster->m_flags & NAPPING)) {
		monster->m_flags &= (~(ASLEEP | IMITATES | WAKENS));
	}
}

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

	wake_percent = (rn == party_room) ? PARTY_WAKE_PERCENT : WAKE_PERCENT;
	if (stealthy > 0) {
		wake_percent /= (STEALTH_FACTOR + stealthy);
	}

	monster = level_monsters.next_monster;

	while (monster) {
		in_room = (rn == get_room_number(monster->row, monster->col));
		if (in_room) {
			if (entering) {
				monster->trow = NO_ROOM;
			} else {
				monster->trow = row;
				monster->tcol = col;
			}
		}
		if ((monster->m_flags & WAKENS) &&
			(rn == get_room_number(monster->row, monster->col))) {
			if (rand_percent(wake_percent)) {
				wake_up(monster);
			}
		}
		monster = monster->next_monster;
	}
}

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

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

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

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

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

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

	for (i = 0; i < 10; i++) {
		get_rand_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
		if (!rogue_can_see(row, col)) {
			put_monster_at(row, col, monster);
			return;
		}
	}
	free_object(monster);
}

show_monsters()
{
	object *monster;

	detect_monster = 1;

	if (blind) {
		return;
	}
	monster = level_monsters.next_monster;

	while (monster) {
		mvaddch(monster->row, monster->col, monster->m_char);
		if (monster->m_flags & IMITATES) {
			monster->m_flags &= (~IMITATES);
			monster->m_flags |= WAKENS;
		}
		monster = monster->next_monster;
	}
}

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

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

	for (i = 0; i < 9; i++) {
		rand_around(i, &row, &col);
		if (((row == rogue.row) && (col = rogue.col)) ||
				(row < MIN_ROW) || (row > (DROWS-2)) ||
				(col < 0) || (col > (DCOLS-1))) {
			continue;
		}
		if ((!(dungeon[row][col] & MONSTER)) &&
			  (dungeon[row][col] & (FLOOR|TUNNEL|STAIRS|DOOR))) {
			found = 1;
			break;
		}
	}
	if (found) {
		monster = get_rand_monster((object *) 0, 0);
		put_monster_at(row, col, monster);
		mvaddch(row, col, get_monster_char(monster));
		if (monster->m_flags & (WANDERS | WAKENS)) {
			wake_up(monster);
		}
	} else {
		message("you hear a faint cry of anguish in the distance", 0);
	}
}

put_monster_at(row, col, monster)
object *monster;
{
	object *add_to_pack();

	monster->row = row;
	monster->col = col;
	dungeon[row][col] |= MONSTER;
	monster->trail_char = mvinch(row, col);
	add_to_pack(monster, &level_monsters, 0);
	aim_monster(monster);
}

aim_monster(monster)
object *monster;
{
	short i, rn, d, r;

	rn = get_room_number(monster->row, monster->col);
	r = get_rand(0, 12);

	for (i = 0; i < 4; i++) {
		d = (r + i) % 4;
		if (rooms[rn].doors[d].other_room != NO_ROOM) {
			monster->trow = rooms[rn].doors[d].door_row;
			monster->tcol = rooms[rn].doors[d].door_col;
			break;
		}
	}
}

rogue_can_see(row, col)
register row, col;
{
	register retval;

	retval = !blind &&
			(((get_room_number(row, col) == current_room) &&
					!(rooms[current_room].is_room & R_MAZE)) ||
			rogue_is_around(row, col));

	return(retval);
}

confused_move(monster)
object *monster;
{
	short i, row, col;

	if (!(monster->m_flags & ASLEEP)) {
		if (--monster->moves_confused <= 0) {
			monster->m_flags &= (~CONFUSED);
		}
		if (monster->m_flags & STATIONARY) {
			return(coin_toss() ? 1 : 0);
		} else if (rand_percent(15)) {
			return(1);
		}
		row = monster->row;
		col = monster->col;

		for (i = 0; i < 9; i++) {
			rand_around(i, &row, &col);
			if ((row == rogue.row) && (col == rogue.col)) {
				return(0);
			}
			if (mtry(monster, row, col)) {
				return(1);
			}
		}
	}
	return(0);
}

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

	if (!rand_percent(FLIT_PERCENT)) {
		return(0);
	}
	if (rand_percent(10)) {
		return(1);
	}
	row = monster->row;
	col = monster->col;

	for (i = 0; i < 9; i++) {
		rand_around(i, &row, &col);
		if ((row == rogue.row) && (col == rogue.col)) {
			continue;
		}
		if (mtry(monster, row, col)) {
			return(1);
		}
	}
	return(1);
}

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

	get_rand_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
	put_monster_at(row, col, MONSTER);

}

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

	r = get_rand(0, 7);

	return(rs[r]);
}

no_room_for_monster(rn)
int 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 (!(dungeon[i][j] & MONSTER)) {
				return(0);
			}
		}
	}
	return(1);
}

aggravate()
{
	struct object *monster;

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

	monster = level_monsters.next_monster;

	while (monster) {
		wake_up(monster);
		monster->m_flags &= (~IMITATES);
		monster = monster->next_monster;
		if (rogue_can_see(monster->row, monster->col)) {
			mvaddch(monster->row, monster->col, monster->m_char);
		}
	}
}

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

	rn = get_room_number(row, col);

	if (	(rn != NO_ROOM) &&
			(rn == get_room_number(monster->row, monster->col)) &&
			!(rooms[rn].is_room & R_MAZE)) {
		return(1);
	}
	rdif = row - monster->row;
	cdif = col - monster->col;

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

mv_aquatars()
{
	object *monster;

	monster = level_monsters.next_monster;

	while (monster) {
		if ((monster->m_char == 'A') &&
			monster_can_go(monster, rogue.row, rogue.col)) {
			mv_monster(monster, rogue.row, rogue.col);
			monster->m_flags |= ALREADY_MOVED;
		}
		monster = monster->next_monster;
	}
}
SHAR_EOF
echo shar: extracting monster.h
cat - << \SHAR_EOF > monster.h
/*
 * monster.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 MONSTERS 26

#define HASTED					01L
#define SLOWED					02L
#define INVISIBLE				04L
#define ASLEEP				   010L
#define WAKENS				   020L
#define WANDERS				   040L
#define FLIES				  0100L
#define FLITS				  0200L
#define CAN_FLIT			  0400L		/* can, but usually doesn't, flit */
#define CONFUSED	 		 01000L
#define RUSTS				 02000L
#define HOLDS				 04000L
#define FREEZES				010000L
#define STEALS_GOLD			020000L
#define STEALS_ITEM			040000L
#define STINGS			   0100000L
#define DRAINS_LIFE		   0200000L
#define DRAINS_LEVEL	   0400000L
#define SEEKS_GOLD		  01000000L
#define FREEZING_ROGUE	  02000000L
#define RUST_VANISHED	  04000000L
#define CONFUSES		 010000000L
#define IMITATES		 020000000L
#define FLAMES			 040000000L
#define STATIONARY		0100000000L		/* damage will be 1,2,3,... */
#define NAPPING			0200000000L		/* can't wake up for a while */
#define ALREADY_MOVED	0400000000L

#define SPECIAL_HIT		(RUSTS|HOLDS|FREEZES|STEALS_GOLD|STEALS_ITEM|STINGS|DRAINS_LIFE|DRAINS_LEVEL)

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

#define HYPOTHERMIA 1
#define STARVATION 2
#define POISON_DART 3
#define QUIT 4
#define WIN 5
SHAR_EOF
echo shar: extracting room.h
cat - << \SHAR_EOF > room.h
/*
 * room.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 MAXROOMS 9
#define BIG_ROOM 10

#define NO_ROOM -1

#define PASSAGE -3		/* current_room value */

#define SCORE_FILE "SCORE_FILE"

#define AMULET_LEVEL 26

#define R_NOTHING ((unsigned short)  01)
#define R_ROOM ((unsigned short)     02)
#define R_MAZE ((unsigned short)     04)
#define R_DEADEND ((unsigned short) 010)
#define R_CROSS ((unsigned short)   020)

#define MAX_EXP_LEVEL 21
#define MAX_EXP 10000000L
#define MAX_GOLD 900000
#define MAX_ARMOR 99
#define MAX_HP 800
#define MAX_STRENGTH 99
#define LAST_DUNGEON 99

#define STAT_LEVEL 01
#define STAT_GOLD 02
#define STAT_HP 04
#define STAT_STRENGTH 010
#define STAT_ARMOR 020
#define STAT_EXP 040
#define STAT_HUNGER 0100
#define STAT_LABEL 0200
#define STAT_ALL 0377

#define PARTY_TIME 10	/* one party somewhere in each 10 level span */

#define MAX_TRAPS 10	/* maximum traps per level */

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

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

short m_moves = 0;
boolean jump = 1;
char *you_can_move_again = "you can move again";

extern short current_room, halluc, blind, levitate;
extern short current_level, max_level;
extern short bear_trap, haste_self, confused;
extern short e_rings, regeneration, auto_search;
extern char hunger_str[];
extern boolean being_held, interrupted, r_teleport;

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

	row = rogue.row;
	col = rogue.col;
	if (confused) {
		dirch = get_rand_dir();
	}
	get_dir_rc(dirch, &row, &col, 1);

	if (!can_move(rogue.row, rogue.col, row, col)) {
		return(MOVE_FAILED);
	}
	if (being_held || bear_trap) {
		if (!(dungeon[row][col] & MONSTER)) {
			if (being_held) {
				message("you are being held", 1);
			} else {
				message("you are still stuck in the bear trap", 0);
				register_move();
			}
			return(MOVE_FAILED);
		}
	}
	if (r_teleport) {
		if (rand_percent(R_TELEPORT_PERCENT)) {
			teleport();
			return(STOPPED_ON_SOMETHING);
		}
	}
	if (dungeon[row][col] & MONSTER) {
		rogue_hit(object_at(&level_monsters, row, col), 0);
		register_move();
		return(MOVE_FAILED);
	}
	if (dungeon[row][col] & DOOR) {
		if (current_room == PASSAGE) {
			current_room = get_room_number(row, col);
			light_up_room();
			wake_room(current_room, 1, row, col);
		} else {
			light_passage(row, col);
		}
	} else if ((dungeon[rogue.row][rogue.col] & DOOR) &&
		   (dungeon[row][col] & TUNNEL)) {
		light_passage(row, col);
		wake_room(current_room, 0, rogue.row, rogue.col);
		darken_room(current_room);
		current_room = PASSAGE;
	} else if (dungeon[row][col] & TUNNEL) {
			light_passage(row, col);
	}
	mvaddch(rogue.row, rogue.col, get_dungeon_char(rogue.row, rogue.col));
	mvaddch(row, col, rogue.fchar);

	if (!jump) {
		refresh();
	}
	rogue.row = row;
	rogue.col = col;
	if (dungeon[row][col] & OBJECT) {
		if (levitate && pickup) {
			return(STOPPED_ON_SOMETHING);
		}
		if (pickup && !levitate) {
			if (obj = pick_up(row, col, &status)) {
				get_description(obj, description);
				if (obj->what_is == GOLD) {
					free_object(obj);
					goto NOT_IN_PACK;
				}
			} else if (!status) {
				goto MVED;
			} else {
				goto MOVE_ON;
			}
		} else {
MOVE_ON:
			obj = object_at(&level_objects, row, col);
			strcpy(description, "moved onto ");
			get_description(obj, description+11);
			goto NOT_IN_PACK;
		}
		n = strlen(description);
		description[n] = '(';
		description[n+1] = obj->ichar;
		description[n+2] = ')';
		description[n+3] = 0;
NOT_IN_PACK:
		message(description, 1);
		register_move();
		return(STOPPED_ON_SOMETHING);
	}
	if (dungeon[row][col] & (DOOR | STAIRS | TRAP)) {
		if ((!levitate) && (dungeon[row][col] & TRAP)) {
			trap_rogue(row, col);
		}
		register_move();
		return(STOPPED_ON_SOMETHING);
	}
MVED:	if (register_move()) {			/* fainted from hunger */
			return(STOPPED_ON_SOMETHING);
	}
	return((confused ? STOPPED_ON_SOMETHING : MOVED));
}

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

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

is_passable(row, col)
register row, col;
{
	if ((row < MIN_ROW) || (row > (DROWS - 2)) || (col < 0) ||
		(col > (DCOLS-1))) {
		return(0);
	}
	if (dungeon[row][col] & HIDDEN) {
		return((dungeon[row][col] & TRAP) ? 1 : 0);
	}
	return(dungeon[row][col] & (FLOOR | TUNNEL | DOOR | STAIRS | TRAP));
}

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

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

	for (i = ((rogue.row > MIN_ROW) ? -1 : 0); i <= i_end; i++) {
		for (j = ((rogue.col > 0) ? -1 : 0); j <= j_end; j++) {
			if ((i == 0) && (j == 0)) {
				continue;
			}
			if (((rogue.row+i) == drow) && ((rogue.col+j) == dcol)) {
				continue;
			}
			row = rogue.row + i;
			col = rogue.col + j;
			s = dungeon[row][col];
			if (s & HIDDEN) {
				continue;
			}
			/* If the rogue used to be right up, left, down, or right of
			 * row,col, and now isn't, then don't stop */
			if (s & (MONSTER | OBJECT | STAIRS)) {
				if (((row == drow) || (col == dcol)) &&
					(!((row == rogue.row) || (col == rogue.col)))) {
					continue;
				}
				return(1);
			}
			if (s & TRAP) {
				if (!(s & HIDDEN)) {
					if (((row == drow) || (col == dcol)) &&
						(!((row == rogue.row) || (col == rogue.col)))) {
						continue;
					}
					return(1);
				}
			}
			if ((((i - j) == 1) || ((i - j) == -1)) && (s & TUNNEL)) {
				if (++pass_count > 1) {
					return(1);
				}
			}
			if ((s & DOOR) && ((i == 0) || (j == 0))) {
					return(1);
			}
		}
	}
	return(0);
}

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

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

	while (!is_direction(ch = rgetchar())) {
		sound_bell();
		if (first_miss) {
			message("direction? ", 0);
			first_miss = 0;
		}
	}
	check_message();
	if (ch != CANCEL) {
		single_move_rogue(ch, 0);
	}
}

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

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

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

	switch(e_rings) {
	/*case -2:
		Subtract 0, i.e. do nothing.
		break;*/
	case -1:
		rogue.moves_left -= (rogue.moves_left % 2);
		break;
	case 0:
		rogue.moves_left--;
		break;
	case 1:
		rogue.moves_left--;
		check_hunger(1);
		rogue.moves_left -= (rogue.moves_left % 2);
		break;
	case 2:
		rogue.moves_left--;
		check_hunger(1);
		rogue.moves_left--;
		break;
	}
	return(fainted);
}

register_move()
{
	boolean fainted, check_hunger();

	if ((rogue.moves_left <= HUNGRY) || (current_level >= max_level)) {
		fainted = check_hunger(0);
	} else {
		fainted = 0;
	}

	move_monsters();

	if (++m_moves >= 120) {
		m_moves = 0;
		start_wanderer();
	}
	if (halluc) {
		if (!(--halluc)) {
			unhallucinate();
		} else {
			hallucinate();
		}
	}
	if (blind) {
		if (!(--blind)) {
			unblind();
		}
	}
	if (confused) {
		if (!(--confused)) {
			unconfuse();
		}
	}
	if (bear_trap) {
		bear_trap--;
	}
	if (levitate) {
		if (!(--levitate)) {
			message("you float gently to the ground", 1);
			if (dungeon[rogue.row][rogue.col] & TRAP) {
				trap_rogue(rogue.row, rogue.col);
			}
		}
	}
	if (haste_self) {
		if (!(--haste_self)) {
			message("you feel yourself slowing down", 0);
		}
	}
	heal();
	if (auto_search > 0) {
		search(auto_search, auto_search);
	}
	return(fainted);
}

rest(count)
{
	int i;

	interrupted = 0;

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

get_rand_dir()
{
	short d;

	d = get_rand(1, 8);

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

heal()
{
	static short heal_exp = -1, n, c = 0;
	static boolean alt;

	if (rogue.hp_current == rogue.hp_max) {
		c = 0;
		return;
	}
	if (rogue.exp != heal_exp) {
		heal_exp = rogue.exp;

		switch(heal_exp) {
		case 1:
			n = 20;
			break;
		case 2:
			n = 18;
			break;
		case 3:
			n = 17;
			break;
		case 4:
			n = 14;
			break;
		case 5:
			n = 13;
			break;
		case 6:
			n = 10;
			break;
		case 7:
			n = 9;
			break;
		case 8:
			n = 8;
			break;
		case 9:
			n = 7;
			break;
		case 10:
			n = 4;
			break;
		case 11:
			n = 3;
			break;
		case 12:
		default:
			n = 2;
		}
	}
	if (++c >= n) {
		c = 0;
		rogue.hp_current++;
		if (alt = !alt) {
			rogue.hp_current++;
		}
		if ((rogue.hp_current += regeneration) > rogue.hp_max) {
			rogue.hp_current = rogue.hp_max;
		}
		print_stats(STAT_HP);
	}
}
SHAR_EOF
echo shar: extracting move.h
cat - << \SHAR_EOF > move.h
/*
 * move.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 UP 0
#define UPRIGHT 1
#define RIGHT 2
#define RIGHTDOWN 3
#define DOWN 4
#define DOWNLEFT 5
#define LEFT 6
#define LEFTUP 7
#define DIRS 8

#define ROW1 7
#define ROW2 15

#define COL1 26
#define COL2 52

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

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

#define MIN_ROW 1
SHAR_EOF
echo shar: extracting special_hit.c
cat - << \SHAR_EOF > special_hit.c
/*
 * special_hit.c
 *
 * This source herein may be modified and/or distributed by anybody who
 * so desires, with the following restrictions:
 *    1.)  This notice shall not be removed.
 *    2.)  Credit shall not be taken for the creation of this source.
 *    3.)  This code is not to be traded, sold, or used for personal
 *         gain or profit.
 *
 */

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

short being_held, less_hp = 0;
char *flame_name = "flame";

extern short current_level, max_level, blind, levitate, ring_exp;
extern long level_points[];
extern boolean detect_monster, monster_disappeared;
extern boolean sustain_strength, maintain_armor;
extern char *you_can_move_again;

special_hit(monster)
object *monster;
{
	if ((monster->m_flags & CONFUSED) && rand_percent(66)) {
		return;
	}
	if (monster->m_flags & RUSTS) {
		rust(monster);
	}
	if ((monster->m_flags & HOLDS) && !levitate) {
		being_held = 1;
	}
	if (monster->m_flags & FREEZES) {
		freeze(monster);
	}
	if (monster->m_flags & STINGS) {
		sting(monster);
	}
	if (monster->m_flags & DRAINS_LIFE) {
		drain_life();
	}
	if (monster->m_flags & DRAINS_LEVEL) {
		drain_level();
	}
	if (monster->m_flags & STEALS_GOLD) {
		steal_gold(monster);
	} else if (monster->m_flags & STEALS_ITEM) {
		steal_item(monster);
	}
}

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

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

	if (rand_percent(12)) {
		return;
	}
	freeze_percent -= (rogue.strength_current+(rogue.strength_current/2));
	freeze_percent -= ((rogue.exp + ring_exp) * 4);
	freeze_percent -= (get_armor_class(rogue.armor) * 5);
	freeze_percent -= (rogue.hp_max / 3);

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

		n = get_rand(4, 8);
		for (i = 0; i < n; i++) {
			move_monsters();
		}
		if (rand_percent(freeze_percent)) {
			for (i = 0; i < 50; i++) {
				move_monsters();
			}
			killed_by((object *)0, HYPOTHERMIA);
		}
		message(you_can_move_again, 1);
		monster->m_flags &= (~FREEZING_ROGUE);
	}
}

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

	if ((rogue.gold <= 0) || rand_percent(10)) {
		return;
	}

	amount = get_rand((current_level * 10), (current_level * 30));

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

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

	if (rand_percent(15)) {
		return;
	}
	obj = rogue.pack.next_object;

	if (!obj) {
		goto DSPR;
	}
	while (obj) {
		if (!(obj->in_use_flags & BEING_USED)) {
			has_something = 1;
			break;
		}
		obj = obj->next_object;
	}
	if (!has_something) {
		goto DSPR;
	}
	n = get_rand(0, MAX_PACK_COUNT);
	obj = rogue.pack.next_object;

	for (i = 0; i <= n; i++) {
		obj = obj->next_object;
		while ((!obj) || (obj->in_use_flags & BEING_USED)) {
			if (!obj) {
				obj = rogue.pack.next_object;
			} else {
				obj = obj->next_object;
			}
		}
	}
	strcpy(description, "she stole ");
	if (obj->what_is != WEAPON) {
		t = obj->quantity;
		obj->quantity = 1;
	}
	get_description(obj, description+10);
	message(description, 0);

	obj->quantity = ((obj->what_is != WEAPON) ? t : 1);

	vanish(obj, 0, &rogue.pack);
DSPR:
	disappear(monster);
}

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

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

	dungeon[row][col] &= ~MONSTER;
	if (rogue_can_see(row, col)) {
		mvaddch(row, col, get_dungeon_char(row, col));
	}
	remove_from_pack(monster, &level_monsters);
	free_object(monster);
	monster_disappeared = 1;
}

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

	if (current_level < max_level) {
		return;
	}

	if (monster->m_flags & STEALS_GOLD) {
		obj = alloc_object();
		obj->what_is = GOLD;
		obj->quantity = get_rand((current_level * 15), (current_level * 30));
	} else {
		if (!rand_percent(monster->drop_percent)) {
			return;
		}
		obj = get_rand_object();
	}
	row = monster->row;
	col = monster->col;

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

try_to_cough(row, col, obj)
short row, col;
object *obj;
{
	if ((row < MIN_ROW) || (row > (DROWS-2)) || (col < 0) || (col>(DCOLS-1))) {
		return(0);
	}
	if ((!(dungeon[row][col] & (OBJECT | STAIRS | TRAP))) &&
		(dungeon[row][col] & (TUNNEL | FLOOR | DOOR))) {
		put_object_at(obj, row, col);
		if (((row != rogue.row) || (col != rogue.col)) &&
			(!(dungeon[row][col] & MONSTER))) {
			mvaddch(row, col, get_dungeon_char(row, col));
		}
		return(1);
	}
	return(0);
}

seek_gold(monster)
object *monster;
{
	short i, j, rn, s;

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

gold_at(row, col)
short row, col;
{
	if (dungeon[row][col] & OBJECT) {
		struct object *obj;

		if ((obj = object_at(&level_objects, row, col)) &&
				(obj->what_is == GOLD)) {
			return(1);
		}
	}
	return(0);
}

check_gold_seeker(monster)
object *monster;
{
	monster->m_flags &= (~SEEKS_GOLD);
}

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

	if (monster->m_flags & IMITATES) {
		wake_up(monster);
		if (!blind) {
			mvaddch(monster->row, monster->col,
					get_dungeon_char(monster->row, monster->col));
			check_message();
			sprintf(msg, "wait, that's a %s!", monster_name(monster));
			message(msg, 1);
		}
		return(1);
	}
	return(0);
}

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

	if (!(dungeon[row][col] & MONSTER)) {
		return(0);
	}
	monster = object_at(&level_monsters, row, col);
	if (monster->m_flags & IMITATES) {
		return(1);
	}
	return(0);
}

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

	if ((rogue.strength_current <= 3) || sustain_strength) {
		return;
	}
	sting_chance += (6 * (6 - get_armor_class(rogue.armor)));

	if ((rogue.exp + ring_exp) > 8) {
		sting_chance -= (6 * ((rogue.exp + ring_exp) - 8));
	}
	if (rand_percent(sting_chance)) {
		sprintf(msg, "the %s's bite has weakened you",
		monster_name(monster));
		message(msg, 0);
		rogue.strength_current--;
		print_stats(STAT_STRENGTH);
	}
}

drain_level()
{
	int hp;

	if (rand_percent(80) || (rogue.exp <= 5)) {
		return;
	}
	rogue.exp_points = level_points[rogue.exp-2] - get_rand(9, 29);
	rogue.exp -= 2;
	hp = get_rand_hp_raise();
	if ((rogue.hp_current -= hp) <= 0) {
		rogue.hp_current = 1;
	}
	if ((rogue.hp_max -= hp) <= 0) {
		rogue.hp_max = 1;
	}
	add_exp(1, 0);
}

drain_life()
{
	short n;

	if (rand_percent(60) || (rogue.hp_max <= 30) || (rogue.hp_current < 10)) {
		return;
	}
	n = get_rand(1, 3);		/* 1 Hp, 2 Str, 3 both */

	if ((n != 2) || (!sustain_strength)) {
		message("you feel weaker", 0);
	}
	if (n != 2) {
		rogue.hp_max--;
		rogue.hp_current--;
		less_hp++;
	}
	if (n != 1) {
		if ((rogue.strength_current > 3) && (!sustain_strength)) {
			rogue.strength_current--;
			if (coin_toss()) {
				rogue.strength_max--;
			}
		}
	}
	print_stats((STAT_STRENGTH | STAT_HP));
}

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

	if (!rogue_can_see(monster->row, monster->col)) {
		return(0);
	}
	if (rand_percent(45)) {
		monster->m_flags &= (~CONFUSES);	/* will not confuse the rogue */
		return(0);
	}
	if (rand_percent(55)) {
		monster->m_flags &= (~CONFUSES);
		sprintf(msg, "the gaze of the %s has confused you",
		monster_name(monster));
		message(msg, 1);
		confuse();
		return(1);
	}
	return(0);
}

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

	if ((!monster_can_see(monster, rogue.row, rogue.col)) || coin_toss()) {
		return(0);
	}
	row = rogue.row - monster->row;
	col = rogue.col - monster->col;
	if (row < 0) {
		row = -row;
	}
	if (col < 0) {
		col = -col;
	}
	if (((row != 0) && (col != 0) && (row != col)) ||
		((row > 7) || (col > 7))) {
		return(0);
	}
	if ((!blind) && (!rogue_is_around(monster->row, monster->col))) {
		row = monster->row;
		col = monster->col;
		get_closer(&row, &col, rogue.row, rogue.col);
		standout();
		do {
			mvaddch(row, col, '~');
			refresh();
			get_closer(&row, &col, rogue.row, rogue.col);
		} while ((row != rogue.row) || (col != rogue.col));
		standend();
		row = monster->row; col = monster->col;
		get_closer(&row, &col, rogue.row, rogue.col);
		do {
			mvaddch(row, col, get_dungeon_char(row, col));
			refresh();
			get_closer(&row, &col, rogue.row, rogue.col);
		} while ((row != rogue.row) || (col != rogue.col));
	}
	monster_hit(monster, flame_name, 1);
	return(1);
}

get_closer(row, col, trow, tcol)
short *row, *col;
short trow, tcol;
{
	if (*row < trow) {
		(*row)++;
	} else if (*row > trow) {
		(*row)--;
	}
	if (*col < tcol) {
		(*col)++;
	} else if (*col > tcol) {
		(*col)--;
	}
}
SHAR_EOF