[comp.sources.games] v01i012: rogue - a rogue 5.3 clone, Part02/05

games-request@tekred.TEK.COM (05/11/87)

Submitted by: Tim Stoehr <tims@zues.TEK.COM>
Comp.sources.games: Volume 1, Issue 12
Archive-name: rogue/Part02

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 5)."
# Contents:  curses.c machdep.c object.c throw.c
# Wrapped by billr@tekred on Mon May 11 12:19:17 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f curses.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"curses.c\"
else
echo shar: Extracting \"curses.c\" \(11545 characters\)
sed "s/^X//" >curses.c <<'END_OF_curses.c'
X/*
X * curses.c
X *
X * This source herein may be modified and/or distributed by anybody who
X * so desires, with the following restrictions:
X *    1.)  No portion of this notice shall be removed.
X *    2.)  Credit shall not be taken for the creation of this source.
X *    3.)  This code is not to be traded, sold, or used for personal
X *         gain or profit.
X *
X */
X
X#ifdef CURSES
X
X/* The following is a curses emulation package suitable for the rogue program
X * in which it is included.  No other suitability is claimed or suspected.
X * Only those routines currently needed by this rogue program are included.
X * This is being provided for those systems that don't have a suitable
X * curses package and want to run this rogue program.
X *
X * Compile the entire program with -DCURSES to incorporate this package.
X *
X * The following is NOT supported:
X *   "%D", "%B", "%n", or "%>" inside a cursor motion (cm) termcap string.
X *   Terminals in which the cursor motion addresses the row differently from
X *       the column, as in ":cm=\E%2,%3" or ":cm=\EY%+x;%+y"
X *   Termcap database stored in the TERMCAP environ variable as returned
X *       from md_getenv().  Only the termcap file name can be stored there.
X *       See the comments for md_getenv() in machdep.c.
X *   Terminals without non-destructive backspace.  Backspace (^H) is used
X *       for cursor motion regardless of any termcap entries.
X *   The ":tc=" termcap entry is ignored.
X *
X * Suggestions:
X *   Use line-feed as your termcap "do" entry: ":do=^J", ":do=\012" or
X *      ":do=\n"  This will help cursor motion optimization.  If line-feed
X *      won't work, then a short escape sequence will do.  Same goes for "up"
X */
X
X#include <stdio.h>
X#include "rogue.h"
X
Xboolean tc_tname();
X
X#define BS 010
X#define LF 012
X#define CR 015
X#define ESC '\033'
X#define TAB '\011'
X
X#define ST_MASK 0x80
X#define BUFLEN 256
X
Xchar terminal[DROWS][DCOLS];
Xchar buffer[DROWS][DCOLS];
Xchar *tc_file;
X
Xchar cm_esc[16], cm_sep[16], cm_end[16];
Xboolean cm_reverse = 0;
Xboolean cm_two = 0;
Xboolean cm_three = 0;
Xboolean cm_char = 0;
Xshort cm_inc = 0;
X
Xboolean screen_dirty;
Xboolean lines_dirty[DROWS];
Xboolean buf_stand_out = 0;
Xboolean term_stand_out = 0;
X
Xint LINES = DROWS, COLS = DCOLS;
XWINDOW scr_buf;
XWINDOW *curscr = &scr_buf;
X
Xchar *CL = (char *) 0;
Xchar *CM = (char *) 0;
Xchar *UC = (char *) 0;
Xchar *DO = (char *) 0;
Xchar *VS = "";
Xchar *VE = "";
Xchar *TI = "";
Xchar *TE = "";
Xchar *SO = "";
Xchar *SE = "";
X
Xshort cur_row, cur_col;
X
Xinitscr()
X{
X	clear();
X	get_term_info();
X	printf("%s%s", TI, VS);
X}
X
Xendwin()
X{
X	printf("%s%s", TE, VE);
X	md_cbreak_no_echo_nonl(0);
X}
X
Xmove(row, col)
Xshort row, col;
X{
X	curscr->_cury = row;
X	curscr->_curx = col;
X	screen_dirty = 1;
X}
X
Xmvaddstr(row, col, str)
Xshort row, col;
Xchar *str;
X{
X	move(row, col);
X	addstr(str);
X}
X
Xaddstr(str)
Xchar *str;
X{
X	while (*str) {
X		addch((int) *str++);
X	}
X}
X
Xaddch(ch)
Xregister int ch;
X{
X	short row, col;
X
X	row = curscr->_cury;
X	col = curscr->_curx++;
X
X	if (buf_stand_out) {
X		ch |= ST_MASK;
X	}
X	buffer[row][col] = (char) ch;
X	lines_dirty[row] = 1;
X	screen_dirty = 1;
X}
X
Xmvaddch(row, col, ch)
Xshort row, col;
Xint ch;
X{
X	move(row, col);
X	addch(ch);
X}
X
Xrefresh()
X{
X	register i, j, line;
X	short old_row, old_col, first_row;
X
X	if (screen_dirty) {
X
X		old_row = curscr->_cury;
X		old_col = curscr->_curx;
X		first_row = cur_row;
X
X		for (i = 0; i < DROWS; i++) {
X			line = (first_row + i) % DROWS;
X			if (lines_dirty[line]) {
X				for (j = 0; j < DCOLS; j++) {
X					if (buffer[line][j] != terminal[line][j]) {
X						put_char_at(line, j, buffer[line][j]);
X					}
X				}
X				lines_dirty[line] = 0;
X			}
X		}
X		put_cursor(old_row, old_col);
X		screen_dirty = 0;
X		fflush(stdout);
X	}
X}
X
Xwrefresh(scr)
XWINDOW *scr;
X{
X	short i, col;
X
X	printf("%s", CL);
X	cur_row = cur_col = 0;
X
X	for (i = 0; i < DROWS; i++) {
X		col = 0;
X		while (col < DCOLS) {
X			while ((col < DCOLS) && (buffer[i][col] == ' ')) {
X				col++;
X			}
X			if (col < DCOLS) {
X				put_cursor(i, col);
X			}
X			while ((col < DCOLS) && (buffer[i][col] != ' ')) {
X				put_st_char((int) buffer[i][col]);
X				cur_col++;
X				col++;
X			}
X		}
X	}
X	put_cursor(curscr->_cury, curscr->_curx);
X	fflush(stdout);
X	scr = scr;		/* make lint happy */
X}
X
Xmvinch(row, col)
Xshort row, col;
X{
X	move(row, col);
X	return((int) buffer[row][col]);
X}
X
Xclear()
X{
X	printf("%s", CL);
X	fflush(stdout);
X	cur_row = cur_col = 0;
X	move(0, 0);
X	clear_buffers();
X}
X
Xclrtoeol()
X{
X	short row, col;
X
X	row = curscr->_cury;
X
X	for (col = curscr->_curx; col < DCOLS; col++) {
X		buffer[row][col] = ' ';
X	}
X	lines_dirty[row] = 1;
X}
X
Xstandout()
X{
X	buf_stand_out = 1;
X}
X
Xstandend()
X{
X	buf_stand_out = 0;
X}
X
Xcrmode()
X{
X	md_cbreak_no_echo_nonl(1);
X}
X
Xnoecho()
X{
X	/* crmode() takes care of this */
X}
X
Xnonl()
X{
X	/* crmode() takes care of this */
X}
X
Xclear_buffers()
X{
X	register i, j;
X
X	screen_dirty = 0;
X
X	for (i = 0; i < DROWS; i++) {
X		lines_dirty[i] = 0;
X		for (j = 0; j < DCOLS; j++) {
X			terminal[i][j] = ' ';
X			buffer[i][j] = ' ';
X		}
X	}
X}
X
Xput_char_at(row, col, ch)
Xregister row, col, ch;
X{
X	put_cursor(row, col);
X	put_st_char(ch);
X	terminal[row][col] = (char) ch;
X	cur_col++;
X}
X
Xput_cursor(row, col)
Xregister row, col;
X{
X	register i, rdif, cdif;
X	short ch, t;
X
X	rdif = (row > cur_row) ? row - cur_row : cur_row - row;
X	cdif = (col > cur_col) ? col - cur_col : cur_col - col;
X
X	if (((row > cur_row) && DO) || ((cur_row > row) && UC)) {
X		if ((rdif < 4) && (cdif < 4)) {
X			for (i = 0; i < rdif; i++) {
X				printf("%s", ((row < cur_row) ? UC : DO));
X			}
X			cur_row = row;
X			if (col == cur_col) {
X				return;
X			}
X		}
X	}
X	if (row == cur_row) {
X		if (cdif <= 6) {
X		for (i = 0; i < cdif; i++) {
X				ch = (col < cur_col) ? BS :
X						terminal[row][cur_col + i];
X				put_st_char((int) ch);
X			}
X			cur_row = row;
X			cur_col = col;
X			return;
X		}
X	}
X	cur_row = row;
X	cur_col = col;
X
X	row += cm_inc;
X	col += cm_inc;
X
X	if (cm_reverse) {
X		t = row;
X		row = col;
X		col = t;
X	}
X	if (cm_two) {
X		printf("%s%02d%s%02d%s", cm_esc, row, cm_sep, col, cm_end);
X	} else if (cm_three) {
X		printf("%s%03d%s%03d%s", cm_esc, row, cm_sep, col, cm_end);
X	} else if (cm_char) {
X		printf("%s%c%s%c%s", cm_esc, row, cm_sep, col, cm_end);
X	} else {
X		printf("%s%d%s%d%s", cm_esc, row, cm_sep, col, cm_end);
X	}
X}
X
Xput_st_char(ch)
Xregister ch;
X{
X	if ((ch & ST_MASK) && (!term_stand_out)) {
X		ch &= ~ST_MASK;
X		printf("%s%c", SO, ch);
X		term_stand_out = 1;
X	} else if ((!(ch & ST_MASK)) && term_stand_out) {
X		printf("%s%c", SE, ch);
X		term_stand_out = 0;
X	} else {
X		ch &= ~ST_MASK;
X		putchar(ch);
X	}
X}
X
Xget_term_info()
X{
X	FILE *fp;
X	char *term, *tcf;
X	char buf[BUFLEN];
X
X	if (tcf = md_getenv("TERMCAP")) {
X		if (strlen(tcf) > 40) {
X			clean_up("TERMCAP file name too long");
X		}
X		tc_file = tcf;
X	} else {
X		if (!(tc_file = md_gdtcf())) {
X			clean_up("I need a termcap file");
X		}
X	}
X
X	if (!(term = md_getenv("TERM"))) {
X		clean_up("Cannot find TERM variable in environ");
X	}
X	if ((fp = fopen(tc_file, "r")) == NULL) {
X		sprintf(buf, "Cannot open TERMCAP file: %s", tc_file);
X		clean_up(buf);
X	}
X
X	if (!tc_tname(fp, term, buf)) {
X		sprintf(buf, "Cannot find TERM type: %s in TERMCAP file: %s", term,
X			tc_file);
X		clean_up(buf);
X	}
X	tc_gtdata(fp, buf);
X	fclose(fp);
X}
X
Xboolean
Xtc_tname(fp, term, buf)
XFILE *fp;
Xchar *term;
Xchar *buf;
X{
X	short i, j;
X	boolean found = 0;
X	char *fg;
X
X	while (!found) {
X		i = 0;
X		fg = fgets(buf, BUFLEN, fp);
X		if (fg != NULL) {
X			if (	(buf[0] != '#') && (buf[0] != ' ') && (buf[0] != TAB) &&
X					(buf[0] != CR) && (buf[0] != LF)) {
X				while (buf[i] && (!found)) {
X					j = 0;
X					while (buf[i] == term[j]) {
X						i++;
X						j++;
X					}
X					if ((!term[j]) && ((buf[i] == '|') || (buf[i] == ':'))) {
X						found = 1;
X					} else {
X						while (buf[i] && (buf[i] != '|') && (buf[i] != ':')) {
X							i++;
X						}
X						if (buf[i]) {
X							i++;
X						}
X					}
X				}
X			}
X		} else {
X			break;
X		}
X	}
X	return(found);
X}
X
Xtc_gtdata(fp, buf)
XFILE *fp;
Xchar *buf;
X{
X	short i;
X	boolean first = 1;
X
X	do {
X		if (!first) {
X			if ((buf[0] != TAB) && (buf[0] != ' ')) {
X				break;
X			}
X		}
X		first = 0;
X		i = 0;
X		while (buf[i]) {
X			while (buf[i] && (buf[i] != ':')) {
X				i++;
X			}
X			if (buf[i] == ':') {
X				if (!strncmp(buf + i, ":cl=", 4)) {
X					tc_gets(buf + i, &CL);
X				} else if (!strncmp(buf + i, ":cm=", 4)) {
X					tc_gets(buf + i, &CM);
X				} else if (!strncmp(buf + i, ":up=", 4)) {
X					tc_gets(buf + i, &UC);
X				} else if (!strncmp(buf + i, ":do=", 4)) {
X					tc_gets(buf + i, &DO);
X				} else if (!strncmp(buf + i, ":vs=", 4)) {
X					tc_gets(buf + i, &VS);
X				} else if (!strncmp(buf + i, ":ve=", 4)) {
X					tc_gets(buf + i, &VE);
X				} else if (!strncmp(buf + i, ":ti=", 4)) {
X					tc_gets(buf + i, &TI);
X				} else if (!strncmp(buf + i, ":te=", 4)) {
X					tc_gets(buf + i, &TE);
X				} else if (!strncmp(buf + i, ":vs=", 4)) {
X					tc_gets(buf + i, &VS);
X				} else if (!strncmp(buf + i, ":ve=", 4)) {
X					tc_gets(buf + i, &VE);
X				} else if (!strncmp(buf + i, ":so=", 4)) {
X					tc_gets(buf + i, &SO);
X				} else if (!strncmp(buf + i, ":se=", 4)) {
X					tc_gets(buf + i, &SE);
X				} else if (!strncmp(buf + i, ":li#", 4)) {
X					tc_gnum(buf + i, &LINES);
X				} else if (!strncmp(buf + i, ":co#", 4)) {
X					tc_gnum(buf + i, &COLS);
X				}
X				i++;
X			}
X		}
X	} while (fgets(buf, BUFLEN, fp) != NULL);
X
X	if ((!CM) || (!CL)) {
X		clean_up("Terminal and termcap must have cm and cl");
X	}
X	tc_cmget();
X}
X
Xtc_gets(ibuf, tcstr)
Xchar *ibuf;
Xchar **tcstr;
X{
X	short i, j, k, n;
X	char obuf[BUFLEN];
X
X	i = 4;
X	j = 0;
X
X	while (ibuf[i] && is_digit(ibuf[i])) {
X		i++;
X	}
X
X	while (ibuf[i] && (ibuf[i] != ':')) {
X		if (ibuf[i] == '\\') {
X			i++;
X			switch(ibuf[i]) {
X			case 'E':
X				obuf[j] = ESC;
X				i++;
X				break;
X			case 'n':
X				obuf[j] = LF;
X				i++;
X				break;
X			case 'r':
X				obuf[j] = CR;
X				i++;
X				break;
X			case 'b':
X				obuf[j] = BS;
X				i++;
X				break;
X			case 't':
X				obuf[j] = TAB;
X				i++;
X				break;
X			case '0':
X			case '1':
X			case '2':
X			case '3':
X			case '4':
X			case '5':
X			case '6':
X			case '7':
X			case '8':
X			case '9':
X				n = 0;
X				k = 0;
X				while (k < 3 && ibuf[i] && is_digit(ibuf[i])) {
X					n = (8 * n) + (ibuf[i] - '0');
X					i++;
X					k++;
X				}
X				obuf[j] = (char) n;
X				break;
X			default:
X				obuf[j] = ibuf[i];
X				i++;
X			}
X		} else if (ibuf[i] == '^') {
X			obuf[j] = ibuf[i+1] - 64;
X			i += 2;
X		} else {
X			obuf[j] = ibuf[i++];
X		}
X		j++;
X	}
X	obuf[j] = 0;
X	if (!(*tcstr = md_malloc(j + 1))) {
X		clean_up("cannot alloc() memory");
X	}
X	strcpy(*tcstr, obuf);
X}
X
Xtc_gnum(ibuf, n)
Xchar *ibuf;
Xint *n;
X{
X	short i;
X	int r = 0;
X
X	i = 4;
X
X	while (is_digit(ibuf[i])) {
X		r = (r * 10) + (ibuf[i] - '0');
X		i++;
X	}
X	*n = r;
X}
X
Xtstp()
X{
X	endwin();
X	md_tstp();
X
X	start_window();
X	printf("%s%s", TI, VS);
X	wrefresh(curscr);
X	md_slurp();
X}
X
Xtc_cmget()
X{
X	short i = 0, j = 0, rc_spec = 0;
X
X	while (CM[i] && (CM[i] != '%') && (j < 15)) {
X		cm_esc[j++] = CM[i++];
X	}
X	cm_esc[j] = 0;
X
X	while (CM[i] && (rc_spec < 2)) {
X		if (CM[i] == '%') {
X			i++;
X			switch(CM[i]) {
X			case 'd':
X				rc_spec++;
X				break;
X			case 'i':
X				cm_inc = 1;
X				break;
X			case '2':
X				cm_two = 1;
X				rc_spec++;
X				break;
X			case '3':
X				cm_three = 1;
X				rc_spec++;
X				break;
X			case '.':
X				cm_char = 1;
X				rc_spec++;
X				break;
X			case 'r':
X				cm_reverse = 1;
X				break;
X			case '+':
X				i++;
X				cm_inc = CM[i];
X				cm_char = 1;
X				rc_spec++;
X				break;
X			}
X			i++;
X		} else {
X			j = 0;
X			while (CM[i] && (CM[i] != '%')) {
X				cm_sep[j++] = CM[i++];
X			}
X			cm_sep[j] = 0;
X		}
X	}
X
X	j = 0;
X	if (rc_spec == 2) {
X		while (CM[i] && (j < 15)) {
X			cm_end[j++] = CM[i++];
X		}
X	}
X	cm_end[j] = 0;
X}
X
X#endif CURSES
END_OF_curses.c
if test 11545 -ne `wc -c <curses.c`; then
    echo shar: \"curses.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f machdep.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"machdep.c\"
else
echo shar: Extracting \"machdep.c\" \(15393 characters\)
sed "s/^X//" >machdep.c <<'END_OF_machdep.c'
X/*
X * machdep.c
X *
X * This source herein may be modified and/or distributed by anybody who
X * so desires, with the following restrictions:
X *    1.)  No portion of this notice shall be removed.
X *    2.)  Credit shall not be taken for the creation of this source.
X *    3.)  This code is not to be traded, sold, or used for personal
X *         gain or profit.
X *
X */
X
X/* Included in this file are all system dependent routines.  Extensive use
X * of #ifdef's will be used to compile the appropriate code on each system:
X *
X *    UNIX:        all UNIX systems.
X *    UNIX_BSD4_2: UNIX BSD 4.2 and later, UTEK, (4.1 BSD too?)
X *    UNIX_SYS5:   UNIX system 5
X *    UNIX_V7:     UNIX version 7
X *
X * All UNIX code should be included between the single "#ifdef UNIX" at the
X * top of this file, and the "#endif UNIX" at the bottom.
X * 
X * To change a routine to include a new UNIX system, simply #ifdef the
X * existing routine, as in the following example:
X *
X *   To make a routine compatible with UNIX system 5, change the first
X *   function to the second:
X *
X *      md_function()
X *      {
X *         code;
X *      }
X *
X *      md_function()
X *      {
X *      #ifdef UNIX_SYS5
X *         sys5code;
X *      #else
X *         code;
X *      #endif
X *      }
X *
X * Appropriate variations of this are of course acceptible.
X * The use of "#elseif" is discouraged because of non-portability.
X * If the correct #define doesn't exist, "UNIX_SYS5" in this case, make it up
X * and insert it in the list at the top of the file.  Alter the CFLAGS
X * in you Makefile appropriately.
X *
X */
X
X#ifdef UNIX
X
X#include <stdio.h>
X#include <sgtty.h>
X#include <sys/file.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/time.h>
X#include <signal.h>
X#include "rogue.h"
X
X/* md_slurp:
X *
X * This routine throws away all keyboard input that has not
X * yet been read.  It is used to get rid of input that the user may have
X * typed-ahead.
X *
X * This function is not necessary, so it may be stubbed.  The might cause
X * message-line output to flash by because the game has continued to read
X * input without waiting for the user to read the message.  Not such a
X * big deal.
X */
X
Xmd_slurp()
X{
X#ifdef UNIX_BSD4_2
X	long ln;
X	int i, n;
X	ioctl(0, FIONREAD, &ln);
X	n = (int) (stdin->_cnt + ln);
X
X	for (i = 0; i < n; i++) {
X		(void) getchar();
X	}
X#endif UNIX_BSD4_2
X}
X
X/* md_control_keyboard():
X *
X * This routine is much like md_cbreak_no_echo_nonl() above.  It sets up the
X * keyboard for appropriate input.  Specifically, it prevents the tty driver
X * from stealing characters.  For example, ^Y is needed as a command
X * character, but the tty driver intercepts it for another purpose.  Any
X * such behavior should be stopped.  This routine could be avoided if
X * we used RAW mode instead of CBREAK.  But RAW mode does not allow the
X * generation of keyboard signals, which the program uses.
X *
X * The parameter 'mode' when true, indicates that the keyboard should
X * be set up to play rogue.  When false, it should be restored if
X * necessary.
X *
X * This routine is not strictly necessary and may be stubbed.  This may
X * cause certain command characters to be unavailable.
X */
X
Xmd_control_keybord(mode)
Xshort mode;
X{
X	static boolean called_before = 0;
X	static struct ltchars ltc_orig;
X	static struct tchars tc_orig;
X	struct ltchars ltc_temp;
X	struct tchars tc_temp;
X
X	if (!called_before) {
X		called_before = 1;
X		ioctl(0, TIOCGETC, &tc_orig);
X		ioctl(0, TIOCGLTC, &ltc_orig);
X	}
X	ltc_temp = ltc_orig;
X	tc_temp = tc_orig;
X
X	if (!mode) {
X#ifdef UNIX_BSD4_2
X		ltc_temp.t_suspc = ltc_temp.t_dsuspc = -1;
X#endif UNIX_BSD4_2
X		ltc_temp.t_rprntc = ltc_temp.t_flushc = -1;
X		ltc_temp.t_werasc = ltc_temp.t_lnextc = -1;
X		tc_temp.t_startc = tc_temp.t_stopc = -1;
X	}
X	ioctl(0, TIOCSETC, &tc_temp);
X	ioctl(0, TIOCSLTC, &ltc_temp);
X}
X
X/* md_heed_signals():
X *
X * This routine tells the program to call particular routines when
X * certain interrupts/events occur:
X *
X *      SIGINT: call onintr() to interrupt fight with monster or long rest.
X *      SIGQUIT: call byebye() to check for game termination.
X *      SIGHUP: call error_save() to save game when terminal hangs up.
X *
X *		On VMS, SIGINT and SIGQUIT correspond to ^C and ^Y.
X *
X * This routine is not strictly necessary and can be stubbed.  This will
X * mean that the game cannot be interrupted properly with keyboard
X * input, this is not usually critical.
X */
X
Xmd_heed_signals()
X{
X	signal(SIGINT, onintr);
X	signal(SIGQUIT, byebye);
X	signal(SIGHUP, error_save);
X}
X
X/* md_ignore_signals():
X *
X * This routine tells the program to completely ignore the events mentioned
X * in md_heed_signals() above.  The event handlers will later be turned on
X * by a future call to md_heed_signals(), so md_heed_signals() and
X * md_ignore_signals() need to work together.
X *
X * This function should be implemented or the user risks interrupting
X * critical sections of code, which could cause score file, or saved-game
X * file, corruption.
X */
X
Xmd_ignore_signals()
X{
X	signal(SIGQUIT, SIG_IGN);
X	signal(SIGINT, SIG_IGN);
X	signal(SIGHUP, SIG_IGN);
X}
X
X/* md_get_file_id():
X *
X * This function returns an integer that uniquely identifies the specified
X * file.  It need not check for the file's existence.  In UNIX, the inode
X * number is used.
X *
X * This function need not be implemented.  To stub the routine, just make
X * it return 0.  This will make the game less able to prevent users from
X * modifying saved-game files.  This is probably no big deal.
X */
X
Xint
Xmd_get_file_id(fname)
Xchar *fname;
X{
X	struct stat sbuf;
X
X	if (stat(fname, &sbuf)) {
X		return(-1);
X	}
X	return((int) sbuf.st_ino);
X}
X
X/* md_link_count():
X *
X * This routine returns the number of hard links to the specified file.
X *
X * This function is not strictly necessary.  On systems without hard links
X * this routine can be stubbed by just returning 1.
X */
X
Xint
Xmd_link_count(fname)
Xchar *fname;
X{
X	struct stat sbuf;
X
X	stat(fname, &sbuf);
X	return((int) sbuf.st_nlink);
X}
X
X/* md_gct(): (Get Current Time)
X *
X * This function returns the current year, month(1-12), day(1-31), hour(0-23),
X * minute(0-59), and second(0-59).  This is used for identifying the time
X * at which a game is saved.
X *
X * This function is not strictly necessary.  It can be stubbed by returing
X * zeros instead of the correct year, month, etc.  If your operating
X * system doesn't provide all of the time units requested here, then you
X * can provide only those that it does, and return zeros for the others.
X * If you cannot provide good time values, then users may be able to copy
X * saved-game files and play them.  
X */
X
Xmd_gct(rt_buf)
Xstruct rogue_time *rt_buf;
X{
X	struct timeval tv;
X	struct timezone tzp;
X	struct tm *t;
X	long seconds;
X
X	gettimeofday(&tv, &tzp);
X	seconds = (long) tv.tv_sec;
X	t = localtime(&seconds);
X
X	rt_buf->year = t->tm_year;
X	rt_buf->month = t->tm_mon + 1;
X	rt_buf->day = t->tm_mday;
X	rt_buf->hour = t->tm_hour;
X	rt_buf->minute = t->tm_min;
X	rt_buf->second = t->tm_sec;
X}
X
X/* md_gfmt: (Get File Modification Time)
X *
X * This routine returns a file's date of last modification in the same format
X * as md_gct() above.
X *
X * This function is not strictly necessary.  It is used to see if saved-game
X * files have been modified since they were saved.  If you have stubbed the
X * routine md_gct() above by returning constant values, then you may do
X * exactly the same here.
X * Or if md_gct() is implemented correctly, but your system does not provide
X * file modification dates, you may return some date far in the past so
X * that the program will never know that a saved-game file being modified.  
X * You may also do this if you wish to be able to restore games from
X * saved-games that have been modified.
X */
X
Xmd_gfmt(fname, rt_buf)
Xchar *fname;
Xstruct rogue_time *rt_buf;
X{
X	struct stat sbuf;
X	long seconds;
X	struct tm *t;
X
X	stat(fname, &sbuf);
X	seconds = (long) sbuf.st_mtime;
X	t = localtime(&seconds);
X
X	rt_buf->year = t->tm_year;
X	rt_buf->month = t->tm_mon + 1;
X	rt_buf->day = t->tm_mday;
X	rt_buf->hour = t->tm_hour;
X	rt_buf->minute = t->tm_min;
X	rt_buf->second = t->tm_sec;
X}
X
X/* md_df: (Delete File)
X *
X * This function deletes the specified file, and returns true (1) if the
X * operation was successful.  This is used to delete saved-game files
X * after restoring games from them.
X *
X * Again, this function is not strictly necessary, and can be stubbed
X * by simply returning 1.  In this case, saved-game files will not be
X * deleted and can be replayed.
X */
X
Xboolean
Xmd_df(fname)
Xchar *fname;
X{
X	if (unlink(fname)) {
X		return(0);
X	}
X	return(1);
X}
X
X/* md_gln: (Get login name)
X *
X * This routine returns the login name of the user.  This string is
X * used mainly for identifying users in score files.
X *
X * A dummy string may be returned if you are unable to implement this
X * function, but then the score file would only have one name in it.
X */
X
Xchar *
Xmd_gln()
X{
X	char *getlogin();
X	char *t;
X
X	t = getlogin();
X	return(t);
X}
X
X/* md_sleep:
X *
X * This routine causes the game to pause for the specified number of
X * seconds.
X *
X * This routine is not necessary at all, and can be stubbed with no ill
X * effects.
X */
X
Xmd_sleep(nsecs)
Xint nsecs;
X{
X	(void) sleep(nsecs);
X}
X
X/* md_getenv()
X *
X * This routine gets certain values from the user's environment.  These
X * values are strings, and each string is identified by a name.  The names
X * of the values needed, and their use, is as follows:
X *
X *   TERMCAP
X *     The name of the users's termcap file, NOT the termcap entries
X *     themselves.  This is used ONLY if the program is compiled with
X *     CURSES defined (-DCURSES).  Even in this case, the program need
X *     not find a string for TERMCAP.  If it does not, it will use the
X *     default termcap file as returned by md_gdtcf();
X *   TERM
X *     The name of the users's terminal.  This is used ONLY if the program
X *     is compiled with CURSES defined (-DCURSES).  In this case, the string
X *     value for TERM must be found, or the routines in curses.c cannot
X *     function, and the program will quit.
X *   ROGUEOPTS
X *     A string containing the various game options.  This need not be
X *     defined.
X *   HOME
X *     The user's home directory.  This is only used when the user specifies
X *     '~' as the first character of a saved-game file.  This string need
X *     not be defined.
X *
X * If your system does not provide a means of searching for these values,
X * you will have to do it yourself.  None of the values above really need
X * to be defined except TERM when the program is compiled with CURSES
X * defined.  In this case, as a bare minimum, you can check the 'name'
X * parameter, and if it is "TERM" find the terminal name and return that,
X * else return zero.  If the program is not compiled with CURSES, you can
X * get by with simply always returning zero.  Returning zero indicates
X * that their is no defined value for the given string.
X */
X
Xchar *
Xmd_getenv(name)
Xchar *name;
X{
X	char *value;
X	char *getenv();
X
X	value = getenv(name);
X
X	return(value);
X}
X
X/* md_malloc()
X *
X * This routine allocates, and returns a pointer to, the specified number
X * of bytes.  This routines absolutely MUST be implemented for your
X * particular system or the program will not run at all.  Return zero
X * when no more memory can be allocated.
X */
X
Xchar *
Xmd_malloc(n)
Xint n;
X{
X	char *malloc();
X	char *t;
X
X	t = malloc(n);
X	return(t);
X}
X
X/* md_gseed() (Get Seed)
X *
X * This function returns a seed for the random number generator (RNG).  This
X * seed causes the RNG to begin generating numbers at some point in it's
X * sequence.  Without a random seed, the RNG will generate the same set
X * of numbers, and every game will start out exactly the same way.  A good
X * number to use is the process id, given by getpid() on most UNIX systems.
X *
X * You need to find some single random integer, such as:
X *   process id.
X *   current time (minutes + seconds) returned from md_gct(), if implemented.
X *   
X * It will not help to return "get_rand()" or "rand()" or the return value of
X * any pseudo-RNG.  If you cannot a random number, you can just return 1,
X * but this means you games will ALWAYS start the same way, and will play
X * exactly the same way given the same input.
X */
X
Xmd_gseed()
X{
X	return(getpid());
X}
X
X/* md_exit():
X *
X * This function causes the program to discontinue execution and exit.
X * This function must be implemented or the program will continue to
X * hang when it should quit.
X */
X
Xmd_exit(status)
Xint status;
X{
X	exit(status);
X}
X
X/* If you have a viable curses/termlib library, then use it and don't bother
X * implementing the routines below.  And don't compile with -DCURSES.
X */
X
X#ifdef CURSES
X
X/* md_cbreak_no_echo_nonl:
X *
X * This routine sets up some terminal characteristics.  The tty-driver
X * must be told to:
X *   1.)  Not echo input.
X *   2.)  Transmit input characters immediately upon typing. (cbreak mode)
X *   3.)  Move the cursor down one line, without changing column, and
X *        without generating a carriage-return, when it
X *        sees a line-feed.  This is only necessary if line-feed is ever
X *        used in the termcap 'do' (cursor down) entry, in which case,
X *        your system should must have a way of accomplishing this.
X *
X * When the parameter 'on' is true, the terminal is set up as specified
X * above.  When this parameter is false, the terminal is restored to the
X * original state.
X *
X * Raw mode should not to be used.  Keyboard signals/events/interrupts should
X * be sent, although they are not strictly necessary.  See notes in
X * md_heed_signals().
X *
X * This function must be implemented for rogue to run properly if the
X * program is compiled with CURSES defined to use the enclosed curses
X * emulation package.  If you are not using this, then this routine is
X * totally unnecessary.
X * 
X * Notice that information is saved between calls.  This is used to
X * restore the terminal to an initial saved state.
X *
X */
X
Xmd_cbreak_no_echo_nonl(on)
Xboolean on;
X{
X	static struct sgttyb tty_buf;
X	static int tty_save_flags;
X
X	if (on) {
X		ioctl(0, TIOCGETP, &tty_buf);
X		tty_save_flags = tty_buf.sg_flags;
X		tty_buf.sg_flags |= CBREAK;
X		tty_buf.sg_flags &= ~(ECHO | CRMOD);	/* CRMOD: see note above */
X		ioctl(0, TIOCSETP, &tty_buf);
X	} else {
X		tty_buf.sg_flags = tty_save_flags;
X		ioctl(0, TIOCSETP, &tty_buf);
X	}
X}
X
X/* md_gdtcf(): (Get Default Termcap File)
X *
X * This function is called ONLY when the program is compiled with CURSES
X * defined.  If you use your system's curses/termlib library, this function
X * won't be called.  On most UNIX systems, "/etc/termcap" suffices.
X *
X * If their is no such termcap file, then return 0, but in that case, you
X * must have a TERMCAP file returned from md_getenv("TERMCAP").  The latter
X * will override the value returned from md_gdtcf().  If the program is
X * compiled with CURSES defined, and md_gdtcf() returns 0, and
X * md_getenv("TERMCAP") returns 0, the program will have no terminal
X * capability information and will quit.
X */
X
Xchar *
Xmd_gdtcf()
X{
X	return("/etc/termcap");
X}
X
X/* md_tstp():
X *
X * This function puts the game to sleep and returns to the shell.  This
X * only applies to UNIX 4.2 and 4.3.  For other systems, the routine should
X * be provided as a do-nothing routine.  md_tstp() will only be referenced
X * in the code when compiled with CURSES defined.
X *
X */
X
Xmd_tstp()
X{
X#ifdef UNIX_BSD4_2
X	kill(0, SIGTSTP);
X#endif UNIX_BSD4_2
X}
X
X#endif CURSES
X
X#endif UNIX
END_OF_machdep.c
if test 15393 -ne `wc -c <machdep.c`; then
    echo shar: \"machdep.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f object.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"object.c\"
else
echo shar: Extracting \"object.c\" \(16345 characters\)
sed "s/^X//" >object.c <<'END_OF_object.c'
X/*
X * object.c
X *
X * This source herein may be modified and/or distributed by anybody who
X * so desires, with the following restrictions:
X *    1.)  No portion of this notice shall be removed.
X *    2.)  Credit shall not be taken for the creation of this source.
X *    3.)  This code is not to be traded, sold, or used for personal
X *         gain or profit.
X *
X */
X
X#ifndef CURSES
X#include <curses.h>
X#endif CURSES
X#include "rogue.h"
X
Xobject level_objects;
Xunsigned short dungeon[DROWS][DCOLS];
Xshort foods = 0;
Xshort party_counter;
Xobject *free_list = (object *) 0;
Xchar *fruit = "slime-mold ";
X
Xfighter rogue = {
X	0, 0,		/* armor, weapon */
X	0, 0,		/* rings */
X	INIT_HP,	/* Hp current */
X	INIT_HP,	/* Hp max */
X	16, 16,		/* Str */
X	{0},		/* pack */
X	0,			/* gold */
X	1, 0,		/* exp, exp_points */
X	0, 0,		/* row, col */
X	'@',		/* char */
X	1250		/* moves */
X};
X
Xstruct id id_potions[POTIONS] = {
X{100, "blue \0                           ", "of increase strength ", 0},
X{250, "red \0                            ", "of restore strength ", 0},
X{100, "green \0                          ", "of healing ", 0},
X{200, "grey \0                           ", "of extra healing ", 0},
X {10, "brown \0                          ", "of poison ", 0},
X{300, "clear \0                          ", "of raise level ", 0},
X {10, "pink \0                           ", "of blindness ", 0},
X {25, "white \0                          ", "of hallucination ", 0},
X{100, "purple \0                         ", "of detect monster ", 0},
X{100, "black \0                          ", "of detect things ", 0},
X {10, "yellow \0                         ", "of confusion ", 0},
X {80, "plaid \0                          ", "of levitation ", 0},
X{150, "burgundy \0                       ", "of haste self ", 0},
X{145, "beige \0                          ", "of see invisible ", 0}
X};
X
Xstruct id id_scrolls[SCROLLS] = {
X{505, "                                   ", "of protect armor ", 0},
X{200, "                                   ", "of hold monster ", 0},
X{235, "                                   ", "of enchant weapon ", 0},
X{235, "                                   ", "of enchant armor ", 0},
X{175, "                                   ", "of identify ", 0},
X{190, "                                   ", "of teleportation ", 0},
X {25, "                                   ", "of sleep ", 0},
X{610, "                                   ", "of scare monster ", 0},
X{210, "                                   ", "of remove curse ", 0},
X{100, "                                   ", "of create monster ",0},
X {25, "                                   ", "of aggravate monster ",0},
X{180, "                                   ", "of magic mapping ",0}
X};
X
Xstruct id id_weapons[WEAPONS] = {
X	{150, "short bow ", "", 0},
X	  {8, "darts ", "", 0},
X	 {15, "arrows ", "", 0},
X	 {27, "daggers ", "", 0},
X	 {35, "shurikens ", "", 0},
X	{360, "mace ", "", 0},
X	{470, "long sword ", "", 0},
X	{580, "two-handed sword ", "", 0}
X};
X
Xstruct id id_armors[ARMORS] = {
X	{300, "leather armor ", "", (UNIDENTIFIED)},
X	{300, "ring mail ", "", (UNIDENTIFIED)},
X	{400, "scale mail ", "", (UNIDENTIFIED)},
X	{500, "chain mail ", "", (UNIDENTIFIED)},
X	{600, "banded mail ", "", (UNIDENTIFIED)},
X	{600, "splint mail ", "", (UNIDENTIFIED)},
X	{700, "plate mail ", "", (UNIDENTIFIED)}
X};
X
Xstruct id id_wands[WANDS] = {
X	 {25, "                                 ", "of teleport away ",0},
X	 {50, "                                 ", "of slow monster ", 0},
X	 {45, "                                 ", "of confuse monster ",0},
X	  {8, "                                 ", "of invisibility ",0},
X	 {55, "                                 ", "of polymorph ",0},
X	  {2, "                                 ", "of haste monster ",0},
X	 {25, "                                 ", "of sleep ",0},
X	 {20, "                                 ", "of magic missile ",0},
X	 {20, "                                 ", "of cancellation ",0},
X	  {0, "                                 ", "of do nothing ",0}
X};
X
Xstruct id id_rings[RINGS] = {
X	 {250, "                                 ", "of stealth ",0},
X	 {100, "                                 ", "of teleportation ", 0},
X	 {255, "                                 ", "of regeneration ",0},
X	 {295, "                                 ", "of slow digestion ",0},
X	 {200, "                                 ", "of add strength ",0},
X	 {250, "                                 ", "of sustain strength ",0},
X	 {250, "                                 ", "of dexterity ",0},
X	  {25, "                                 ", "of adornment ",0},
X	 {300, "                                 ", "of see invisible ",0},
X	 {290, "                                 ", "of maintain armor ",0},
X	 {270, "                                 ", "of searching ",0},
X};
X
Xextern short cur_level, max_level;
Xextern short party_room;
Xextern char *error_file;
Xextern boolean is_wood[];
X
Xput_objects()
X{
X	short i, n;
X	object *obj;
X
X	if (cur_level < max_level) {
X		return;
X	}
X	n = coin_toss() ? get_rand(2, 4) : get_rand(3, 5);
X	while (rand_percent(33)) {
X		n++;
X	}
X	if (cur_level == party_counter) {
X		make_party();
X		party_counter = next_party();
X	}
X	for (i = 0; i < n; i++) {
X		obj = gr_object();
X		rand_place(obj);
X	}
X	put_gold();
X}
X
Xput_gold()
X{
X	short i, j;
X	short row,col;
X	boolean is_maze, is_room;
X
X	for (i = 0; i < MAXROOMS; i++) {
X		is_maze = (rooms[i].is_room & R_MAZE) ? 1 : 0;
X		is_room = (rooms[i].is_room & R_ROOM) ? 1 : 0;
X
X		if (!(is_room || is_maze)) {
X			continue;
X		}
X		if (is_maze || rand_percent(GOLD_PERCENT)) {
X			for (j = 0; j < 50; j++) {
X				row = get_rand(rooms[i].top_row+1,
X				rooms[i].bottom_row-1);
X				col = get_rand(rooms[i].left_col+1,
X				rooms[i].right_col-1);
X				if ((dungeon[row][col] == FLOOR) ||
X					(dungeon[row][col] == TUNNEL)) {
X					plant_gold(row, col, is_maze);
X					break;
X				}
X			}
X		}
X	}
X}
X
Xplant_gold(row, col, is_maze)
Xshort row, col;
Xboolean is_maze;
X{
X	object *obj;
X
X	obj = alloc_object();
X	obj->row = row; obj->col = col;
X	obj->what_is = GOLD;
X	obj->quantity = get_rand((2 * cur_level), (16 * cur_level));
X	if (is_maze) {
X		obj->quantity += obj->quantity / 2;
X	}
X	dungeon[row][col] |= OBJECT;
X	(void) add_to_pack(obj, &level_objects, 0);
X}
X
Xplace_at(obj, row, col)
Xobject *obj;
X{
X	obj->row = row;
X	obj->col = col;
X	dungeon[row][col] |= OBJECT;
X	(void) add_to_pack(obj, &level_objects, 0);
X}
X
Xobject *
Xobject_at(pack, row, col)
Xregister object *pack;
Xshort row, col;
X{
X	object *obj;
X
X	obj = pack->next_object;
X
X	while (obj && ((obj->row != row) || (obj->col != col))) {
X		obj = obj->next_object;
X	}
X	return(obj);
X}
X
Xobject *
Xget_letter_object(ch)
X{
X	object *obj;
X
X	obj = rogue.pack.next_object;
X
X	while (obj && (obj->ichar != ch)) {
X		obj = obj->next_object;
X	}
X	return(obj);
X}
X
Xfree_stuff(objlist)
Xobject *objlist;
X{
X	object *obj;
X
X	while (objlist->next_object) {
X		obj = objlist->next_object;
X		objlist->next_object =
X			objlist->next_object->next_object;
X		free_object(obj);
X	}
X}
X
Xfree_free_list()
X{
X	object *obj;
X
X	while (free_list) {
X		obj = free_list;
X		free_list = free_list->next_object;
X		free_object(obj);
X	}
X}
X
Xchar *
Xname_of(obj)
Xobject *obj;
X{
X	char *retstring;
X
X	switch(obj->what_is) {
X	case SCROLL:
X		retstring = obj->quantity > 1 ? "scrolls " : "scroll ";
X		break;
X	case POTION:
X		retstring = obj->quantity > 1 ? "potions " : "potion ";
X		break;
X	case FOOD:
X		if (obj->which_kind == RATION) {
X			retstring = "food ";
X		} else {
X			retstring = fruit;
X		}
X		break;
X	case WAND:
X		retstring = is_wood[obj->which_kind] ? "staff " : "wand ";
X		break;
X	case WEAPON:
X		switch(obj->which_kind) {
X		case DART:
X			retstring=obj->quantity > 1 ? "darts " : "dart ";
X			break;
X		case ARROW:
X			retstring=obj->quantity > 1 ? "arrows " : "arrow ";
X			break;
X		case DAGGER:
X			retstring=obj->quantity > 1 ? "daggers " : "dagger ";
X			break;
X		case SHURIKEN:
X			retstring=obj->quantity > 1?"shurikens ":"shuriken ";
X			break;
X		default:
X			retstring = id_weapons[obj->which_kind].title;
X		}
X		break;
X	case ARMOR:
X		retstring = "armor ";
X		break;
X	case RING:
X			retstring = "ring ";
X		break;
X	case AMULET:
X		retstring = "amulet ";
X		break;
X	default:
X		retstring = "unknown ";
X		break;
X	}
X	return(retstring);
X}
X
Xobject *
Xgr_object()
X{
X	object *obj;
X
X	obj = alloc_object();
X
X	if (foods < (cur_level / 3)) {
X		obj->what_is = FOOD;
X		foods++;
X	} else {
X		obj->what_is = gr_what_is();
X	}
X	switch(obj->what_is) {
X	case SCROLL:
X		gr_scroll(obj);
X		break;
X	case POTION:
X		gr_potion(obj);
X		break;
X	case WEAPON:
X		gr_weapon(obj, 1);
X		break;
X	case ARMOR:
X		gr_armor(obj);
X		break;
X	case WAND:
X		gr_wand(obj);
X		break;
X	case FOOD:
X		get_food(obj, 0);
X		break;
X	case RING:
X		gr_ring(obj, 1);
X		break;
X	}
X	return(obj);
X}
X
Xunsigned short
Xgr_what_is()
X{
X	short percent;
X	unsigned short what_is;
X
X	percent = get_rand(1, 91);
X
X	if (percent <= 30) {
X		what_is = SCROLL;
X	} else if (percent <= 60) {
X		what_is = POTION;
X	} else if (percent <= 64) {
X		what_is = WAND;
X	} else if (percent <= 74) {
X		what_is = WEAPON;
X	} else if (percent <= 83) {
X		what_is = ARMOR;
X	} else if (percent <= 88) {
X		what_is = FOOD;
X	} else {
X		what_is = RING;
X	}
X	return(what_is);
X}
X
Xgr_scroll(obj)
Xobject *obj;
X{
X	short percent;
X
X	percent = get_rand(0, 85);
X
X	obj->what_is = SCROLL;
X
X	if (percent <= 5) {
X		obj->which_kind = PROTECT_ARMOR;
X	} else if (percent <= 11) {
X		obj->which_kind = HOLD_MONSTER;
X	} else if (percent <= 20) {
X		obj->which_kind = CREATE_MONSTER;
X	} else if (percent <= 35) {
X		obj->which_kind = IDENTIFY;
X	} else if (percent <= 43) {
X		obj->which_kind = TELEPORT;
X	} else if (percent <= 50) {
X		obj->which_kind = SLEEP;
X	} else if (percent <= 55) {
X		obj->which_kind = SCARE_MONSTER;
X	} else if (percent <= 64) {
X		obj->which_kind = REMOVE_CURSE;
X	} else if (percent <= 69) {
X		obj->which_kind = ENCH_ARMOR;
X	} else if (percent <= 74) {
X		obj->which_kind = ENCH_WEAPON;
X	} else if (percent <= 80) {
X		obj->which_kind = AGGRAVATE_MONSTER;
X	} else {
X		obj->which_kind = MAGIC_MAPPING;
X	}
X}
X
Xgr_potion(obj)
Xobject *obj;
X{
X	short percent;
X
X	percent = get_rand(1, 118);
X
X	obj->what_is = POTION;
X
X	if (percent <= 5) {
X		obj->which_kind = RAISE_LEVEL;
X	} else if (percent <= 15) {
X		obj->which_kind = DETECT_OBJECTS;
X	} else if (percent <= 25) {
X		obj->which_kind = DETECT_MONSTER;
X	} else if (percent <= 35) {
X		obj->which_kind = INCREASE_STRENGTH;
X	} else if (percent <= 45) {
X		obj->which_kind = RESTORE_STRENGTH;
X	} else if (percent <= 55) {
X		obj->which_kind = HEALING;
X	} else if (percent <= 65) {
X		obj->which_kind = EXTRA_HEALING;
X	} else if (percent <= 75) {
X		obj->which_kind = BLINDNESS;
X	} else if (percent <= 85) {
X		obj->which_kind = HALLUCINATION;
X	} else if (percent <= 95) {
X		obj->which_kind = CONFUSION;
X	} else if (percent <= 105) {
X		obj->which_kind = POISON;
X	} else if (percent <= 110) {
X		obj->which_kind = LEVITATION;
X	} else if (percent <= 114) {
X		obj->which_kind = HASTE_SELF;
X	} else {
X		obj->which_kind = SEE_INVISIBLE;
X	}
X}
X
Xgr_weapon(obj, assign_wk)
Xobject *obj;
Xint assign_wk;
X{
X	short percent;
X	short i;
X	short blessing, increment;
X
X	obj->what_is = WEAPON;
X	if (assign_wk) {
X		obj->which_kind = get_rand(0, (WEAPONS - 1));
X	}
X	if ((obj->which_kind == ARROW) || (obj->which_kind == DAGGER) ||
X		(obj->which_kind == SHURIKEN) | (obj->which_kind == DART)) {
X		obj->quantity = get_rand(3, 15);
X		obj->quiver = get_rand(0, 126);
X	} else {
X		obj->quantity = 1;
X	}
X	obj->hit_enchant = obj->d_enchant = 0;
X
X	percent = get_rand(1, 96);
X	blessing = get_rand(1, 3);
X
X	if (percent <= 16) {
X		increment = 1;
X	} else if (percent <= 32) {
X		increment = -1;
X		obj->is_cursed = 1;
X	}
X	if (percent <= 32) {
X		for (i = 0; i < blessing; i++) {
X			if (coin_toss()) {
X				obj->hit_enchant += increment;
X			} else {
X				obj->d_enchant += increment;
X			}
X		}
X	}
X	switch(obj->which_kind) {
X	case BOW:
X	case DART:
X		obj->damage = "1d1";
X		break;
X	case ARROW:
X		obj->damage = "1d2";
X		break;
X	case DAGGER:
X		obj->damage = "1d3";
X		break;
X	case SHURIKEN:
X		obj->damage = "1d4";
X		break;
X	case MACE:
X		obj->damage = "2d3";
X		break;
X	case LONG_SWORD:
X		obj->damage = "3d4";
X		break;
X	case TWO_HANDED_SWORD:
X		obj->damage = "4d5";
X		break;
X	}
X}
X
Xgr_armor(obj)
Xobject *obj;
X{
X	short percent;
X	short blessing;
X
X	obj->what_is = ARMOR;
X	obj->which_kind = get_rand(0, (ARMORS - 1));
X	obj->class = obj->which_kind + 2;
X	if ((obj->which_kind == PLATE) || (obj->which_kind == SPLINT)) {
X		obj->class--;
X	}
X	obj->is_protected = 0;
X	obj->d_enchant = 0;
X
X	percent = get_rand(1, 100);
X	blessing = get_rand(1, 3);
X
X	if (percent <= 16) {
X		obj->is_cursed = 1;
X		obj->d_enchant -= blessing;
X	} else if (percent <= 33) {
X		obj->d_enchant += blessing;
X	}
X}
X
Xgr_wand(obj)
Xobject *obj;
X{
X	obj->what_is = WAND;
X	obj->which_kind = get_rand(0, (WANDS - 1));
X	if (obj->which_kind == MAGIC_MISSILE) {
X		obj->class = get_rand(6, 12);
X	} else if (obj->which_kind == CANCELLATION) {
X		obj->class = get_rand(5, 9);
X	} else {
X		obj->class = get_rand(3, 6);
X	}
X}
X
Xget_food(obj, force_ration)
Xobject *obj;
Xboolean force_ration;
X{
X	obj->what_is = FOOD;
X
X	if (force_ration || rand_percent(80)) {
X		obj->which_kind = RATION;
X	} else {
X		obj->which_kind = FRUIT;
X	}
X}
X
Xput_stairs()
X{
X	short row, col;
X
X	gr_row_col(&row, &col, (FLOOR | TUNNEL));
X	dungeon[row][col] |= STAIRS;
X}
X
Xget_armor_class(obj)
Xobject *obj;
X{
X	if (obj) {
X		return(obj->class + obj->d_enchant);
X	}
X	return(0);
X}
X
Xobject *
Xalloc_object()
X{
X	object *obj;
X
X	if (free_list) {
X		obj = free_list;
X		free_list = free_list->next_object;
X	} else if (!(obj = (object *) md_malloc(sizeof(object)))) {
X			free_free_list();
X			message("cannot allocate object, saving game", 0);
X			save_into_file(error_file);
X	}
X	obj->quantity = 1;
X	obj->ichar = 'L';
X	obj->picked_up = obj->is_cursed = 0;
X	obj->in_use_flags = NOT_USED;
X	obj->identified = UNIDENTIFIED;
X	obj->damage = "1d1";
X	return(obj);
X}
X
Xfree_object(obj)
Xobject *obj;
X{
X	obj->next_object = free_list;
X	free_list = obj;
X}
X
Xmake_party()
X{
X	short n;
X
X	party_room = gr_room();
X
X	n = rand_percent(99) ? party_objects(party_room) : 11;
X	if (rand_percent(99)) {
X		party_monsters(party_room, n);
X	}
X}
X
Xshow_objects()
X{
X	object *obj;
X	short mc, rc, row, col;
X	object *monster;
X
X	obj = level_objects.next_object;
X
X	while (obj) {
X		row = obj->row;
X		col = obj->col;
X
X		rc = get_mask_char(obj->what_is);
X
X		if (dungeon[row][col] & MONSTER) {
X			if (monster = object_at(&level_monsters, row, col)) {
X				monster->trail_char = rc;
X			}
X		}
X		mc = mvinch(row, col);
X		if (((mc < 'A') || (mc > 'Z')) &&
X			((row != rogue.row) || (col != rogue.col))) {
X			mvaddch(row, col, rc);
X		}
X		obj = obj->next_object;
X	}
X
X	monster = level_monsters.next_object;
X
X	while (monster) {
X		if (monster->m_flags & IMITATES) {
X			mvaddch(monster->row, monster->col, (int) monster->disguise);
X		}
X		monster = monster->next_monster;
X	}
X}
X
Xput_amulet()
X{
X	object *obj;
X
X	obj = alloc_object();
X	obj->what_is = AMULET;
X	rand_place(obj);
X}
X
Xrand_place(obj)
Xobject *obj;
X{
X	short row, col;
X
X	gr_row_col(&row, &col, (FLOOR | TUNNEL));
X	place_at(obj, row, col);
X
X}
X
Xnew_object_for_wizard()
X{
X	short ch, max, wk;
X	object *obj;
X	char buf[80];
X
X	if (pack_count((object *) 0) >= MAX_PACK_COUNT) {
X		message("pack full", 0);
X		return;
X	}
X	message("type of object?", 0);
X
X	while (r_index("!?:)]=/,\033", (ch = rgetchar()), 0) == -1) {
X		sound_bell();
X	}
X	check_message();
X
X	if (ch == '\033') {
X		return;
X	}
X	obj = alloc_object();
X
X	switch(ch) {
X	case '!':
X		obj->what_is = POTION;
X		max = POTIONS - 1;
X		break;
X	case '?':
X		obj->what_is = SCROLL;
X		max = SCROLLS - 1;
X		break;
X	case ',':
X		obj->what_is = AMULET;
X		break;
X	case ':':
X		get_food(obj, 0);
X		break;
X	case ')':
X		gr_weapon(obj, 0);
X		max = WEAPONS - 1;
X		break;
X	case ']':
X		gr_armor(obj);
X		max = ARMORS - 1;
X		break;
X	case '/':
X		gr_wand(obj);
X		max = WANDS - 1;
X		break;
X	case '=':
X		max = RINGS - 1;
X		obj->what_is = RING;
X		break;
X	}
X	if ((ch != ',') && (ch != ':')) {
XGIL:
X		if (get_input_line("which kind?", "", buf, "", 0, 1)) {
X			wk = get_number(buf);
X			if ((wk >= 0) && (wk <= max)) {
X				obj->which_kind = (unsigned short) wk;
X				if (obj->what_is == RING) {
X					gr_ring(obj, 0);
X				}
X			} else {
X				sound_bell();
X				goto GIL;
X			}
X		} else {
X			free_object(obj);
X			return;
X		}
X	}
X	get_desc(obj, buf);
X	message(buf, 0);
X	(void) add_to_pack(obj, &rogue.pack, 1);
X}
X
Xnext_party()
X{
X	int n;
X
X	n = cur_level;
X	while (n % PARTY_TIME) {
X		n++;
X	}
X	return(get_rand((n + 1), (n + PARTY_TIME)));
X}
END_OF_object.c
if test 16345 -ne `wc -c <object.c`; then
    echo shar: \"object.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f throw.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"throw.c\"
else
echo shar: Extracting \"throw.c\" \(6032 characters\)
sed "s/^X//" >throw.c <<'END_OF_throw.c'
X/*
X * throw.c
X *
X * This source herein may be modified and/or distributed by anybody who
X * so desires, with the following restrictions:
X *    1.)  No portion of this notice shall be removed.
X *    2.)  Credit shall not be taken for the creation of this source.
X *    3.)  This code is not to be traded, sold, or used for personal
X *         gain or profit.
X *
X */
X
X#ifndef CURSES
X#include <curses.h>
X#endif CURSES
X#include "rogue.h"
X
Xextern short cur_room;
Xextern char *curse_message;
Xextern char hit_message[];
X
Xthrow()
X{
X	short wch;
X	boolean first_miss = 1;
X	object *weapon;
X	short dir, row, col;
X	object *monster;
X
X	while (!is_direction(dir = rgetchar())) {
X		sound_bell();
X		if (first_miss) {
X			message("direction? ", 0);
X			first_miss = 0;
X		}
X	}
X	check_message();
X	if (dir == CANCEL) {
X		return;
X	}
X	if ((wch = pack_letter("throw what?", WEAPON)) == CANCEL) {
X		return;
X	}
X	check_message();
X
X	if (!(weapon = get_letter_object(wch))) {
X		message("no such item.", 0);
X		return;
X	}
X	if ((weapon->in_use_flags & BEING_USED) && weapon->is_cursed) {
X		message(curse_message, 0);
X		return;
X	}
X	row = rogue.row; col = rogue.col;
X
X	if ((weapon->in_use_flags & BEING_WIELDED) && (weapon->quantity <= 1)) {
X		unwield(rogue.weapon);
X	} else if (weapon->in_use_flags & BEING_WORN) {
X		mv_aquatars();
X		unwear(rogue.armor);
X		print_stats(STAT_ARMOR);
X	} else if (weapon->in_use_flags & ON_EITHER_HAND) {
X		un_put_on(weapon);
X	}
X	monster = get_thrown_at_monster(weapon, dir, &row, &col);
X	mvaddch(rogue.row, rogue.col, rogue.fchar);
X	refresh();
X
X	if (rogue_can_see(row, col) && ((row != rogue.row) || (col != rogue.col))){
X		mvaddch(row, col, get_dungeon_char(row, col));
X	}
X	if (monster) {
X		wake_up(monster);
X		check_gold_seeker(monster);
X
X		if (!throw_at_monster(monster, weapon)) {
X			flop_weapon(weapon, row, col);
X		}
X	} else {
X		flop_weapon(weapon, row, col);
X	}
X	vanish(weapon, 1, &rogue.pack);
X}
X
Xthrow_at_monster(monster, weapon)
Xobject *monster, *weapon;
X{
X	short damage, hit_chance;
X	short t;
X
X	hit_chance = get_hit_chance(weapon);
X	damage = get_weapon_damage(weapon);
X	if ((weapon->which_kind == ARROW) &&
X		(rogue.weapon && (rogue.weapon->which_kind == BOW))) {
X		damage += get_weapon_damage(rogue.weapon);
X		damage = ((damage * 2) / 3);
X		hit_chance += (hit_chance / 3);
X	} else if ((weapon->in_use_flags & BEING_WIELDED) &&
X		((weapon->which_kind == DAGGER) ||
X		(weapon->which_kind == SHURIKEN) ||
X		(weapon->which_kind == DART))) {
X		damage = ((damage * 3) / 2);
X		hit_chance += (hit_chance / 3);
X	}
X	t = weapon->quantity;
X	weapon->quantity = 1;
X	sprintf(hit_message, "the %s", name_of(weapon));
X	weapon->quantity = t;
X
X	if (!rand_percent(hit_chance)) {
X		(void) strcat(hit_message, "misses  ");
X		return(0);
X	}
X	(void) strcat(hit_message, "hit  ");
X	if ((weapon->what_is == WAND) && rand_percent(75)) {
X		zap_monster(monster, weapon->which_kind);
X	} else {
X		(void) mon_damage(monster, damage);
X	}
X	return(1);
X}
X
Xobject *
Xget_thrown_at_monster(obj, dir, row, col)
Xobject *obj;
Xshort dir;
Xshort *row, *col;
X{
X	short orow, ocol;
X	short i, ch;
X
X	orow = *row; ocol = *col;
X
X	ch = get_mask_char(obj->what_is);
X
X	for (i = 0; i < 24; i++) {
X		get_dir_rc(dir, row, col, 0);
X		if ((dungeon[*row][*col] == NOTHING) ||
X				((dungeon[*row][*col] & (HORWALL | VERTWALL | HIDDEN)) &&
X				(!(dungeon[*row][*col] & TRAP)))) {
X			*row = orow;
X			*col = ocol;
X			return(0);
X		}
X		if ((i != 0) && rogue_can_see(orow, ocol)) {
X			mvaddch(orow, ocol, get_dungeon_char(orow, ocol));
X		}
X		if (rogue_can_see(*row, *col)) {
X			if (!(dungeon[*row][*col] & MONSTER)) {
X				mvaddch(*row, *col, ch);
X			}
X			refresh();
X		}
X		orow = *row; ocol = *col;
X		if (dungeon[*row][*col] & MONSTER) {
X			if (!imitating(*row, *col)) {
X				return(object_at(&level_monsters, *row, *col));
X			}
X		}
X		if (dungeon[*row][*col] & TUNNEL) {
X			i += 2;
X		}
X	}
X	return(0);
X}
X
Xflop_weapon(weapon, row, col)
Xobject *weapon;
Xshort row, col;
X{
X	object *new_weapon, *monster;
X	short i = 0;
X	char msg[80];
X	boolean found = 0;
X	short mch, dch;
X	unsigned short mon;
X
X	while ((i < 9) && dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER)) {
X		rand_around(i++, &row, &col);
X		if ((row > (DROWS-2)) || (row < MIN_ROW) ||
X			(col > (DCOLS-1)) || (col < 0) || (!dungeon[row][col]) ||
X			(dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER))) {
X			continue;
X		}
X		found = 1;
X		break;
X	}
X
X	if (found || (i == 0)) {
X		new_weapon = alloc_object();
X		*new_weapon = *weapon;
X		new_weapon->in_use_flags = NOT_USED;
X		new_weapon->quantity = 1;
X		new_weapon->ichar = 'L';
X		place_at(new_weapon, row, col);
X		if (rogue_can_see(row, col) &&
X				((row != rogue.row) || (col != rogue.col))) {
X			mon = dungeon[row][col] & MONSTER;
X			dungeon[row][col] &= (~MONSTER);
X			dch = get_dungeon_char(row, col);
X			if (mon) {
X				mch = mvinch(row, col);
X				if (monster = object_at(&level_monsters, row, col)) {
X					monster->trail_char = dch;
X				}
X				if ((mch < 'A') || (mch > 'Z')) {
X					mvaddch(row, col, dch);
X				}
X			} else {
X				mvaddch(row, col, dch);
X			}
X			dungeon[row][col] |= mon;
X		}
X	} else {
X		short t;
X
X		t = weapon->quantity;
X		weapon->quantity = 1;
X		sprintf(msg, "the %svanishes as it hits the ground",
X		name_of(weapon));
X		weapon->quantity = t;
X		message(msg, 0);
X	}
X}
X
Xrand_around(i, r, c)
Xshort i, *r, *c;
X{
X	static char* pos = "\010\007\001\003\004\005\002\006\0";
X	static short row, col;
X	short j;
X
X	if (i == 0) {
X		short x, y, o, t;
X
X		row = *r;
X		col = *c;
X
X		o = get_rand(1, 8);
X
X		for (j = 0; j < 5; j++) {
X			x = get_rand(0, 8);
X			y = (x + o) % 9;
X			t = pos[x];
X			pos[x] = pos[y];
X			pos[y] = t;
X		}
X	}
X	switch((short)pos[i]) {
X	case 0:
X		*r = row + 1;
X		*c = col + 1;
X		break;
X	case 1:
X		*r = row + 1;
X		*c = col - 1;
X		break;
X	case 2:
X		*r = row - 1;
X		*c = col + 1;
X		break;
X	case 3:
X		*r = row - 1;
X		*c = col - 1;
X		break;
X	case 4:
X		*r = row;
X		*c = col + 1;
X		break;
X	case 5:
X		*r = row + 1;
X		*c = col;
X		break;
X	case 6:
X		*r = row;
X		*c = col;
X		break;
X	case 7:
X		*r = row - 1;
X		*c = col;
X		break;
X	case 8:
X		*r = row;
X		*c = col - 1;
X		break;
X	}
X}
END_OF_throw.c
if test 6032 -ne `wc -c <throw.c`; then
    echo shar: \"throw.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 2 \(of 5\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 5 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive&S&S&get_