summaryrefslogtreecommitdiffstats
path: root/rogue
diff options
context:
space:
mode:
authorcgd <cgd@NetBSD.org>1993-03-21 09:45:37 +0000
committercgd <cgd@NetBSD.org>1993-03-21 09:45:37 +0000
commit77e3814f0c0e3dea4d0032e25666f77e6f83bfff (patch)
tree7eddfcbf3dd12089e71dc3fafb0a106c5c5766c7 /rogue
parente81d63576b2e46ab90da7d75fa155ea57ee4d32e (diff)
downloadbsdgames-darwin-77e3814f0c0e3dea4d0032e25666f77e6f83bfff.tar.gz
bsdgames-darwin-77e3814f0c0e3dea4d0032e25666f77e6f83bfff.tar.zst
bsdgames-darwin-77e3814f0c0e3dea4d0032e25666f77e6f83bfff.zip
initial import of 386bsd-0.1 sources
Diffstat (limited to 'rogue')
-rw-r--r--rogue/CHANGES53
-rw-r--r--rogue/Makefile13
-rw-r--r--rogue/curses.c694
-rw-r--r--rogue/hit.c456
-rw-r--r--rogue/init.c338
-rw-r--r--rogue/inventory.c774
-rw-r--r--rogue/level.c881
-rw-r--r--rogue/machdep.c681
-rw-r--r--rogue/main.c85
-rw-r--r--rogue/message.c379
-rw-r--r--rogue/monster.c867
-rw-r--r--rogue/move.c647
-rw-r--r--rogue/object.c783
-rw-r--r--rogue/pack.c570
-rw-r--r--rogue/pathnames.h38
-rw-r--r--rogue/play.c298
-rw-r--r--rogue/random.c140
-rw-r--r--rogue/ring.c336
-rw-r--r--rogue/rogue.6113
-rw-r--r--rogue/rogue.h490
-rw-r--r--rogue/room.c649
-rw-r--r--rogue/save.c426
-rw-r--r--rogue/score.c581
-rw-r--r--rogue/spec_hit.c534
-rw-r--r--rogue/throw.c322
-rw-r--r--rogue/trap.c283
-rw-r--r--rogue/use.c618
-rw-r--r--rogue/zap.c405
28 files changed, 12454 insertions, 0 deletions
diff --git a/rogue/CHANGES b/rogue/CHANGES
new file mode 100644
index 00000000..73a71353
--- /dev/null
+++ b/rogue/CHANGES
@@ -0,0 +1,53 @@
+From: tektronix!zeus.TEK.COM!tims@ucbvax.Berkeley.EDU
+Date: 30 Nov 87 15:08:15 PST (Mon)
+To: okeeffe.Berkeley.EDU!mckusick@ucbvax.Berkeley.EDU (Kirk McKusick)
+Subject: Re: Public domain rogue
+Return-Path: tektronix!zeus.TEK.COM!tims@ucbvax.Berkeley.EDU
+
+Here is a list of discrepencies from the documentation you sent me:
+
+The -d option not implemented.
+The -r option not implemented, use "rogue save_file" instead.
+Strength is between 1 and 99, not 3 and 32.
+The D command is not implemented.
+Only scrolls,potions,wands,and rings may be "call"ed something.
+The ^P command may be used to go 4 messages back, instead of just 1.
+The @ comand is not implemented.
+There are no dark rooms.
+ROGUEOPTS of flush,terse,seefloor,askme,inventory are ignored.
+ 'askquit' is added to prevent ^\ from terminating the game accidentally.
+ If 'noaskquit' is
+ found in the ROGUEOPTS string, the the ^\ kills the game, otherwise,
+ the player is asked if he really wants to quit. In either case, no
+ score file processing is attempted.
+The score is keyed to winning scores, and no player may appear twice.
+
+
+
+
+
+
+Other differences from "standard" rogue 5.3. This list covers externally
+visible differences only.
+
+There should be NO bugs with any severe consequences. Absolutely NO
+ game-stopping, or game-winning bugs should be present.
+Traps fail occasionally, that is, they sometimes are sprung but miss.
+The ^A command prints out some stuff you're probably not interested in.
+The '&' command silently saves your screen into the file 'rogue.screen'
+Any inventory selection command that takes '*' as a request to list all
+ appropriate items, can take one of "=?:)]!/" to list only rings,
+ scrolls, or whatever.
+Scrolls and potions, once used, become identified. All other objects become
+ identified only by scroll of identification.
+There is only one scroll of identification, and it works on any item.
+ROGUEOPTS
+ Only the following are implemented:
+ file,jump,name,askquit,tombstone,passgo
+ "askquit" is used to prevent accidental termination of the game via ^\
+You may drop objects in doorways.
+Prints a picture of a skull, not a tombstone, upon death.
+The save/restore game function is faster and machine-independent, but sometimes
+ requires modification when new variables are added to the source.
+The potion of detect monster lasts for the whole level.
+Their is no wand of light.
diff --git a/rogue/Makefile b/rogue/Makefile
new file mode 100644
index 00000000..312a6115
--- /dev/null
+++ b/rogue/Makefile
@@ -0,0 +1,13 @@
+# @(#)Makefile 5.7 (Berkeley) 5/11/90
+
+PROG= rogue
+CFLAGS+=-DUNIX -DUNIX_BSD4_2 -fwritable-strings
+SRCS= curses.c hit.c init.c inventory.c level.c machdep.c main.c \
+ message.c monster.c move.c object.c pack.c play.c random.c ring.c \
+ room.c save.c score.c spec_hit.c throw.c trap.c use.c zap.c
+DPADD= ${LIBCURSES} ${LIBTERM}
+LDADD= -lcurses -ltermlib
+HIDEGAME=hidegame
+MAN6= rogue.0
+
+.include <bsd.prog.mk>
diff --git a/rogue/curses.c b/rogue/curses.c
new file mode 100644
index 00000000..fc609383
--- /dev/null
+++ b/rogue/curses.c
@@ -0,0 +1,694 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)curses.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * curses.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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.
+ *
+ */
+
+#ifdef CURSES
+
+/* The following is a curses emulation package suitable for the rogue program
+ * in which it is included. No other suitability is claimed or suspected.
+ * Only those routines currently needed by this rogue program are included.
+ * This is being provided for those systems that don't have a suitable
+ * curses package and want to run this rogue program.
+ *
+ * Compile the entire program with -DCURSES to incorporate this package.
+ *
+ * The following is NOT supported:
+ * "%D", "%B", "%n", or "%>" inside a cursor motion (cm) termcap string.
+ * Terminals in which the cursor motion addresses the row differently from
+ * the column, as in ":cm=\E%2,%3" or ":cm=\EY%+x;%+y"
+ * Termcap database stored in the TERMCAP environ variable as returned
+ * from md_getenv(). Only the termcap file name can be stored there.
+ * See the comments for md_getenv() in machdep.c.
+ * Terminals without non-destructive backspace. Backspace (^H) is used
+ * for cursor motion regardless of any termcap entries.
+ * The ":tc=" termcap entry is ignored.
+ *
+ * Suggestions:
+ * Use line-feed as your termcap "do" entry: ":do=^J", ":do=\012" or
+ * ":do=\n" This will help cursor motion optimization. If line-feed
+ * won't work, then a short escape sequence will do.
+ */
+
+#include <stdio.h>
+#include "rogue.h"
+
+boolean tc_tname();
+
+#define BS 010
+#define LF 012
+#define CR 015
+#define ESC '\033'
+#define TAB '\011'
+
+#define ST_MASK 0x80
+#define BUFLEN 256
+
+char terminal[DROWS][DCOLS];
+char buffer[DROWS][DCOLS];
+char *tc_file;
+
+char cm_esc[16];
+char cm_sep[16];
+char cm_end[16];
+boolean cm_reverse = 0;
+boolean cm_two = 0;
+boolean cm_three = 0;
+boolean cm_char = 0;
+short cm_inc = 0;
+
+boolean screen_dirty;
+boolean lines_dirty[DROWS];
+boolean buf_stand_out = 0;
+boolean term_stand_out = 0;
+
+int LINES = DROWS;
+int COLS = DCOLS;
+WINDOW scr_buf;
+WINDOW *curscr = &scr_buf;
+
+char *CL = (char *) 0;
+char *CM = (char *) 0;
+char *UC = (char *) 0; /* UP */
+char *DO = (char *) 0;
+char *VS = "";
+char *VE = "";
+char *TI = "";
+char *TE = "";
+char *SO = "";
+char *SE = "";
+
+short cur_row;
+short cur_col;
+
+initscr()
+{
+ clear();
+ get_term_info();
+ printf("%s%s", TI, VS);
+}
+
+endwin()
+{
+ printf("%s%s", TE, VE);
+ md_cbreak_no_echo_nonl(0);
+}
+
+move(row, col)
+short row, col;
+{
+ curscr->_cury = row;
+ curscr->_curx = col;
+ screen_dirty = 1;
+}
+
+mvaddstr(row, col, str)
+short row, col;
+char *str;
+{
+ move(row, col);
+ addstr(str);
+}
+
+addstr(str)
+char *str;
+{
+ while (*str) {
+ addch((int) *str++);
+ }
+}
+
+addch(ch)
+register int ch;
+{
+ short row, col;
+
+ row = curscr->_cury;
+ col = curscr->_curx++;
+
+ if (buf_stand_out) {
+ ch |= ST_MASK;
+ }
+ buffer[row][col] = (char) ch;
+ lines_dirty[row] = 1;
+ screen_dirty = 1;
+}
+
+mvaddch(row, col, ch)
+short row, col;
+int ch;
+{
+ move(row, col);
+ addch(ch);
+}
+
+refresh()
+{
+ register i, j, line;
+ short old_row, old_col, first_row;
+
+ if (screen_dirty) {
+
+ old_row = curscr->_cury;
+ old_col = curscr->_curx;
+ first_row = cur_row;
+
+ for (i = 0; i < DROWS; i++) {
+ line = (first_row + i) % DROWS;
+ if (lines_dirty[line]) {
+ for (j = 0; j < DCOLS; j++) {
+ if (buffer[line][j] != terminal[line][j]) {
+ put_char_at(line, j, buffer[line][j]);
+ }
+ }
+ lines_dirty[line] = 0;
+ }
+ }
+ put_cursor(old_row, old_col);
+ screen_dirty = 0;
+ fflush(stdout);
+ }
+}
+
+wrefresh(scr)
+WINDOW *scr;
+{
+ short i, col;
+
+ printf("%s", CL);
+ cur_row = cur_col = 0;
+
+ for (i = 0; i < DROWS; i++) {
+ col = 0;
+ while (col < DCOLS) {
+ while ((col < DCOLS) && (buffer[i][col] == ' ')) {
+ col++;
+ }
+ if (col < DCOLS) {
+ put_cursor(i, col);
+ }
+ while ((col < DCOLS) && (buffer[i][col] != ' ')) {
+ put_st_char((int) buffer[i][col]);
+ cur_col++;
+ col++;
+ }
+ }
+ }
+ put_cursor(curscr->_cury, curscr->_curx);
+ fflush(stdout);
+ scr = scr; /* make lint happy */
+}
+
+mvinch(row, col)
+short row, col;
+{
+ move(row, col);
+ return((int) buffer[row][col]);
+}
+
+clear()
+{
+ printf("%s", CL);
+ fflush(stdout);
+ cur_row = cur_col = 0;
+ move(0, 0);
+ clear_buffers();
+}
+
+clrtoeol()
+{
+ short row, col;
+
+ row = curscr->_cury;
+
+ for (col = curscr->_curx; col < DCOLS; col++) {
+ buffer[row][col] = ' ';
+ }
+ lines_dirty[row] = 1;
+}
+
+standout()
+{
+ buf_stand_out = 1;
+}
+
+standend()
+{
+ buf_stand_out = 0;
+}
+
+crmode()
+{
+ md_cbreak_no_echo_nonl(1);
+}
+
+noecho()
+{
+ /* crmode() takes care of this */
+}
+
+nonl()
+{
+ /* crmode() takes care of this */
+}
+
+clear_buffers()
+{
+ register i, j;
+
+ screen_dirty = 0;
+
+ for (i = 0; i < DROWS; i++) {
+ lines_dirty[i] = 0;
+ for (j = 0; j < DCOLS; j++) {
+ terminal[i][j] = ' ';
+ buffer[i][j] = ' ';
+ }
+ }
+}
+
+put_char_at(row, col, ch)
+register row, col, ch;
+{
+ put_cursor(row, col);
+ put_st_char(ch);
+ terminal[row][col] = (char) ch;
+ cur_col++;
+}
+
+put_cursor(row, col)
+register row, col;
+{
+ register i, rdif, cdif;
+ short ch, t;
+
+ rdif = (row > cur_row) ? row - cur_row : cur_row - row;
+ cdif = (col > cur_col) ? col - cur_col : cur_col - col;
+
+ if (((row > cur_row) && DO) || ((cur_row > row) && UC)) {
+ if ((rdif < 4) && (cdif < 4)) {
+ for (i = 0; i < rdif; i++) {
+ printf("%s", ((row < cur_row) ? UC : DO));
+ }
+ cur_row = row;
+ if (col == cur_col) {
+ return;
+ }
+ }
+ }
+ if (row == cur_row) {
+ if (cdif <= 6) {
+ for (i = 0; i < cdif; i++) {
+ ch = (col < cur_col) ? BS :
+ terminal[row][cur_col + i];
+ put_st_char((int) ch);
+ }
+ cur_row = row;
+ cur_col = col;
+ return;
+ }
+ }
+ cur_row = row;
+ cur_col = col;
+
+ row += cm_inc;
+ col += cm_inc;
+
+ if (cm_reverse) {
+ t = row;
+ row = col;
+ col = t;
+ }
+ if (cm_two) {
+ printf("%s%02d%s%02d%s", cm_esc, row, cm_sep, col, cm_end);
+ } else if (cm_three) {
+ printf("%s%03d%s%03d%s", cm_esc, row, cm_sep, col, cm_end);
+ } else if (cm_char) {
+ printf("%s%c%s%c%s", cm_esc, row, cm_sep, col, cm_end);
+ } else {
+ printf("%s%d%s%d%s", cm_esc, row, cm_sep, col, cm_end);
+ }
+}
+
+put_st_char(ch)
+register ch;
+{
+ if ((ch & ST_MASK) && (!term_stand_out)) {
+ ch &= ~ST_MASK;
+ printf("%s%c", SO, ch);
+ term_stand_out = 1;
+ } else if ((!(ch & ST_MASK)) && term_stand_out) {
+ printf("%s%c", SE, ch);
+ term_stand_out = 0;
+ } else {
+ ch &= ~ST_MASK;
+ putchar(ch);
+ }
+}
+
+get_term_info()
+{
+ FILE *fp;
+ char *term, *tcf;
+ char buf[BUFLEN];
+
+ if (tcf = md_getenv("TERMCAP")) {
+ if (strlen(tcf) > 40) {
+ clean_up("TERMCAP file name too long");
+ }
+ tc_file = tcf;
+ } else {
+ if (!(tc_file = md_gdtcf())) {
+ clean_up("I need a termcap file");
+ }
+ }
+
+ if (!(term = md_getenv("TERM"))) {
+ clean_up("Cannot find TERM variable in environ");
+ }
+ if ((fp = fopen(tc_file, "r")) == NULL) {
+ sprintf(buf, "Cannot open TERMCAP file: %s", tc_file);
+ clean_up(buf);
+ }
+
+ if (!tc_tname(fp, term, buf)) {
+ sprintf(buf, "Cannot find TERM type: %s in TERMCAP file: %s", term,
+ tc_file);
+ clean_up(buf);
+ }
+ tc_gtdata(fp, buf);
+ fclose(fp);
+}
+
+boolean
+tc_tname(fp, term, buf)
+FILE *fp;
+char *term;
+char *buf;
+{
+ short i, j;
+ boolean found = 0;
+ char *fg;
+
+ while (!found) {
+ i = 0;
+ fg = fgets(buf, BUFLEN, fp);
+ if (fg != NULL) {
+ if ( (buf[0] != '#') && (buf[0] != ' ') && (buf[0] != TAB) &&
+ (buf[0] != CR) && (buf[0] != LF)) {
+ while (buf[i] && (!found)) {
+ j = 0;
+ while (buf[i] == term[j]) {
+ i++;
+ j++;
+ }
+ if ((!term[j]) && ((buf[i] == '|') || (buf[i] == ':'))) {
+ found = 1;
+ } else {
+ while (buf[i] && (buf[i] != '|') && (buf[i] != ':')) {
+ i++;
+ }
+ if (buf[i]) {
+ i++;
+ }
+ }
+ }
+ }
+ } else {
+ break;
+ }
+ }
+ return(found);
+}
+
+tc_gtdata(fp, buf)
+FILE *fp;
+char *buf;
+{
+ short i;
+ boolean first = 1;
+
+ do {
+ if (!first) {
+ if ((buf[0] != TAB) && (buf[0] != ' ')) {
+ break;
+ }
+ }
+ first = 0;
+ i = 0;
+ while (buf[i]) {
+ while (buf[i] && (buf[i] != ':')) {
+ i++;
+ }
+ if (buf[i] == ':') {
+ if (!strncmp(buf + i, ":cl=", 4)) {
+ tc_gets(buf + i, &CL);
+ } else if (!strncmp(buf + i, ":cm=", 4)) {
+ tc_gets(buf + i, &CM);
+ } else if (!strncmp(buf + i, ":up=", 4)) {
+ tc_gets(buf + i, &UC);
+ } else if (!strncmp(buf + i, ":do=", 4)) {
+ tc_gets(buf + i, &DO);
+ } else if (!strncmp(buf + i, ":vs=", 4)) {
+ tc_gets(buf + i, &VS);
+ } else if (!strncmp(buf + i, ":ve=", 4)) {
+ tc_gets(buf + i, &VE);
+ } else if (!strncmp(buf + i, ":ti=", 4)) {
+ tc_gets(buf + i, &TI);
+ } else if (!strncmp(buf + i, ":te=", 4)) {
+ tc_gets(buf + i, &TE);
+ } else if (!strncmp(buf + i, ":vs=", 4)) {
+ tc_gets(buf + i, &VS);
+ } else if (!strncmp(buf + i, ":ve=", 4)) {
+ tc_gets(buf + i, &VE);
+ } else if (!strncmp(buf + i, ":so=", 4)) {
+ tc_gets(buf + i, &SO);
+ } else if (!strncmp(buf + i, ":se=", 4)) {
+ tc_gets(buf + i, &SE);
+ } else if (!strncmp(buf + i, ":li#", 4)) {
+ tc_gnum(buf + i, &LINES);
+ } else if (!strncmp(buf + i, ":co#", 4)) {
+ tc_gnum(buf + i, &COLS);
+ }
+ i++;
+ }
+ }
+ } while (fgets(buf, BUFLEN, fp) != NULL);
+
+ if ((!CM) || (!CL)) {
+ clean_up("Terminal and termcap must have cm and cl");
+ }
+ tc_cmget();
+}
+
+tc_gets(ibuf, tcstr)
+char *ibuf;
+char **tcstr;
+{
+ short i, j, k, n;
+ char obuf[BUFLEN];
+
+ i = 4;
+ j = 0;
+
+ while (ibuf[i] && is_digit(ibuf[i])) {
+ i++;
+ }
+
+ while (ibuf[i] && (ibuf[i] != ':')) {
+ if (ibuf[i] == '\\') {
+ i++;
+ switch(ibuf[i]) {
+ case 'E':
+ obuf[j] = ESC;
+ i++;
+ break;
+ case 'n':
+ obuf[j] = LF;
+ i++;
+ break;
+ case 'r':
+ obuf[j] = CR;
+ i++;
+ break;
+ case 'b':
+ obuf[j] = BS;
+ i++;
+ break;
+ case 't':
+ obuf[j] = TAB;
+ i++;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ n = 0;
+ k = 0;
+ while (k < 3 && ibuf[i] && is_digit(ibuf[i])) {
+ n = (8 * n) + (ibuf[i] - '0');
+ i++;
+ k++;
+ }
+ obuf[j] = (char) n;
+ break;
+ default:
+ obuf[j] = ibuf[i];
+ i++;
+ }
+ } else if (ibuf[i] == '^') {
+ obuf[j] = ibuf[i+1] - 64;
+ i += 2;
+ } else {
+ obuf[j] = ibuf[i++];
+ }
+ j++;
+ }
+ obuf[j] = 0;
+ if (!(*tcstr = md_malloc(j + 1))) {
+ clean_up("cannot alloc() memory");
+ }
+ (void) strcpy(*tcstr, obuf);
+}
+
+tc_gnum(ibuf, n)
+char *ibuf;
+int *n;
+{
+ short i;
+ int r = 0;
+
+ i = 4;
+
+ while (is_digit(ibuf[i])) {
+ r = (r * 10) + (ibuf[i] - '0');
+ i++;
+ }
+ *n = r;
+}
+
+tstp()
+{
+ endwin();
+ md_tstp();
+
+ start_window();
+ printf("%s%s", TI, VS);
+ wrefresh(curscr);
+ md_slurp();
+}
+
+tc_cmget()
+{
+ short i = 0, j = 0, rc_spec = 0;
+
+ while (CM[i] && (CM[i] != '%') && (j < 15)) {
+ cm_esc[j++] = CM[i++];
+ }
+ cm_esc[j] = 0;
+
+ while (CM[i] && (rc_spec < 2)) {
+ if (CM[i] == '%') {
+ i++;
+ switch(CM[i]) {
+ case 'd':
+ rc_spec++;
+ break;
+ case 'i':
+ cm_inc = 1;
+ break;
+ case '2':
+ cm_two = 1;
+ rc_spec++;
+ break;
+ case '3':
+ cm_three = 1;
+ rc_spec++;
+ break;
+ case '.':
+ cm_char = 1;
+ rc_spec++;
+ break;
+ case 'r':
+ cm_reverse = 1;
+ break;
+ case '+':
+ i++;
+ cm_inc = CM[i];
+ cm_char = 1;
+ rc_spec++;
+ break;
+ }
+ i++;
+ } else {
+ j = 0;
+ while (CM[i] && (CM[i] != '%')) {
+ cm_sep[j++] = CM[i++];
+ }
+ cm_sep[j] = 0;
+ }
+ }
+
+ j = 0;
+ if (rc_spec == 2) {
+ while (CM[i] && (j < 15)) {
+ cm_end[j++] = CM[i++];
+ }
+ }
+ cm_end[j] = 0;
+}
+
+#endif
diff --git a/rogue/hit.c b/rogue/hit.c
new file mode 100644
index 00000000..b83e6c59
--- /dev/null
+++ b/rogue/hit.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)hit.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * hit.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.h"
+
+object *fight_monster = 0;
+char hit_message[80] = "";
+
+extern short halluc, blind, cur_level;
+extern short add_strength, ring_exp, r_rings;
+extern boolean being_held, interrupted, wizard, con_mon;
+
+mon_hit(monster)
+register object *monster;
+{
+ short damage, hit_chance;
+ char *mn;
+ float minus;
+
+ if (fight_monster && (monster != fight_monster)) {
+ fight_monster = 0;
+ }
+ monster->trow = NO_ROOM;
+ if (cur_level >= (AMULET_LEVEL * 2)) {
+ hit_chance = 100;
+ } else {
+ hit_chance = monster->m_hit_chance;
+ hit_chance -= (((2 * rogue.exp) + (2 * ring_exp)) - r_rings);
+ }
+ if (wizard) {
+ hit_chance /= 2;
+ }
+ if (!fight_monster) {
+ interrupted = 1;
+ }
+ mn = mon_name(monster);
+
+ if (!rand_percent(hit_chance)) {
+ if (!fight_monster) {
+ sprintf(hit_message + strlen(hit_message), "the %s misses", mn);
+ message(hit_message, 1);
+ hit_message[0] = 0;
+ }
+ return;
+ }
+ if (!fight_monster) {
+ sprintf(hit_message + strlen(hit_message), "the %s hit", mn);
+ message(hit_message, 1);
+ hit_message[0] = 0;
+ }
+ if (!(monster->m_flags & STATIONARY)) {
+ damage = get_damage(monster->m_damage, 1);
+ if (cur_level >= (AMULET_LEVEL * 2)) {
+ minus = (float) ((AMULET_LEVEL * 2) - cur_level);
+ } else {
+ minus = (float) get_armor_class(rogue.armor) * 3.00;
+ minus = minus/100.00 * (float) damage;
+ }
+ damage -= (short) minus;
+ } else {
+ damage = monster->stationary_damage++;
+ }
+ if (wizard) {
+ damage /= 3;
+ }
+ if (damage > 0) {
+ rogue_damage(damage, monster, 0);
+ }
+ if (monster->m_flags & SPECIAL_HIT) {
+ special_hit(monster);
+ }
+}
+
+rogue_hit(monster, force_hit)
+register object *monster;
+boolean force_hit;
+{
+ short damage, hit_chance;
+
+ if (monster) {
+ if (check_imitator(monster)) {
+ return;
+ }
+ hit_chance = force_hit ? 100 : get_hit_chance(rogue.weapon);
+
+ if (wizard) {
+ hit_chance *= 2;
+ }
+ if (!rand_percent(hit_chance)) {
+ if (!fight_monster) {
+ (void) strcpy(hit_message, "you miss ");
+ }
+ goto RET;
+ }
+ damage = get_weapon_damage(rogue.weapon);
+ if (wizard) {
+ damage *= 3;
+ }
+ if (con_mon) {
+ s_con_mon(monster);
+ }
+ if (mon_damage(monster, damage)) { /* still alive? */
+ if (!fight_monster) {
+ (void) strcpy(hit_message, "you hit ");
+ }
+ }
+RET: check_gold_seeker(monster);
+ wake_up(monster);
+ }
+}
+
+rogue_damage(d, monster, other)
+short d;
+object *monster;
+short other;
+{
+ if (d >= rogue.hp_current) {
+ rogue.hp_current = 0;
+ print_stats(STAT_HP);
+ killed_by(monster, other);
+ }
+ if (d > 0) {
+ rogue.hp_current -= d;
+ print_stats(STAT_HP);
+ }
+}
+
+get_damage(ds, r)
+char *ds;
+boolean r;
+{
+ register i = 0, j, n, d, total = 0;
+
+ while (ds[i]) {
+ n = get_number(ds+i);
+ while (ds[i++] != 'd') ;
+ d = get_number(ds+i);
+ while ((ds[i] != '/') && ds[i]) i++;
+
+ for (j = 0; j < n; j++) {
+ if (r) {
+ total += get_rand(1, d);
+ } else {
+ total += d;
+ }
+ }
+ if (ds[i] == '/') {
+ i++;
+ }
+ }
+ return(total);
+}
+
+get_w_damage(obj)
+object *obj;
+{
+ char new_damage[12];
+ register to_hit, damage;
+ register i = 0;
+
+ if ((!obj) || (obj->what_is != WEAPON)) {
+ return(-1);
+ }
+ to_hit = get_number(obj->damage) + obj->hit_enchant;
+ while (obj->damage[i++] != 'd') ;
+ damage = get_number(obj->damage + i) + obj->d_enchant;
+
+ sprintf(new_damage, "%dd%d", to_hit, damage);
+
+ return(get_damage(new_damage, 1));
+}
+
+get_number(s)
+register char *s;
+{
+ register i = 0;
+ register total = 0;
+
+ while ((s[i] >= '0') && (s[i] <= '9')) {
+ total = (10 * total) + (s[i] - '0');
+ i++;
+ }
+ return(total);
+}
+
+long
+lget_number(s)
+char *s;
+{
+ short i = 0;
+ long total = 0;
+
+ while ((s[i] >= '0') && (s[i] <= '9')) {
+ total = (10 * total) + (s[i] - '0');
+ i++;
+ }
+ return(total);
+}
+
+to_hit(obj)
+object *obj;
+{
+ if (!obj) {
+ return(1);
+ }
+ return(get_number(obj->damage) + obj->hit_enchant);
+}
+
+damage_for_strength()
+{
+ short strength;
+
+ strength = rogue.str_current + add_strength;
+
+ if (strength <= 6) {
+ return(strength-5);
+ }
+ if (strength <= 14) {
+ return(1);
+ }
+ if (strength <= 17) {
+ return(3);
+ }
+ if (strength <= 18) {
+ return(4);
+ }
+ if (strength <= 20) {
+ return(5);
+ }
+ if (strength <= 21) {
+ return(6);
+ }
+ if (strength <= 30) {
+ return(7);
+ }
+ return(8);
+}
+
+mon_damage(monster, damage)
+object *monster;
+short damage;
+{
+ char *mn;
+ short row, col;
+
+ monster->hp_to_kill -= damage;
+
+ if (monster->hp_to_kill <= 0) {
+ row = monster->row;
+ col = monster->col;
+ dungeon[row][col] &= ~MONSTER;
+ mvaddch(row, col, (int) get_dungeon_char(row, col));
+
+ fight_monster = 0;
+ cough_up(monster);
+ mn = mon_name(monster);
+ sprintf(hit_message+strlen(hit_message), "defeated the %s", mn);
+ message(hit_message, 1);
+ hit_message[0] = 0;
+ add_exp(monster->kill_exp, 1);
+ take_from_pack(monster, &level_monsters);
+
+ if (monster->m_flags & HOLDS) {
+ being_held = 0;
+ }
+ free_object(monster);
+ return(0);
+ }
+ return(1);
+}
+
+fight(to_the_death)
+boolean to_the_death;
+{
+ short ch, c, d;
+ short row, col;
+ boolean first_miss = 1;
+ short possible_damage;
+ object *monster;
+
+ while (!is_direction(ch = rgetchar(), &d)) {
+ sound_bell();
+ if (first_miss) {
+ message("direction?", 0);
+ first_miss = 0;
+ }
+ }
+ check_message();
+ if (ch == CANCEL) {
+ return;
+ }
+ row = rogue.row; col = rogue.col;
+ get_dir_rc(d, &row, &col, 0);
+
+ c = mvinch(row, col);
+ if (((c < 'A') || (c > 'Z')) ||
+ (!can_move(rogue.row, rogue.col, row, col))) {
+ message("I see no monster there", 0);
+ return;
+ }
+ if (!(fight_monster = object_at(&level_monsters, row, col))) {
+ return;
+ }
+ if (!(fight_monster->m_flags & STATIONARY)) {
+ possible_damage = ((get_damage(fight_monster->m_damage, 0) * 2) / 3);
+ } else {
+ possible_damage = fight_monster->stationary_damage - 1;
+ }
+ while (fight_monster) {
+ (void) one_move_rogue(ch, 0);
+ if (((!to_the_death) && (rogue.hp_current <= possible_damage)) ||
+ interrupted || (!(dungeon[row][col] & MONSTER))) {
+ fight_monster = 0;
+ } else {
+ monster = object_at(&level_monsters, row, col);
+ if (monster != fight_monster) {
+ fight_monster = 0;
+ }
+ }
+ }
+}
+
+get_dir_rc(dir, row, col, allow_off_screen)
+short dir;
+short *row, *col;
+short allow_off_screen;
+{
+ switch(dir) {
+ case LEFT:
+ if (allow_off_screen || (*col > 0)) {
+ (*col)--;
+ }
+ break;
+ case DOWN:
+ if (allow_off_screen || (*row < (DROWS-2))) {
+ (*row)++;
+ }
+ break;
+ case UPWARD:
+ if (allow_off_screen || (*row > MIN_ROW)) {
+ (*row)--;
+ }
+ break;
+ case RIGHT:
+ if (allow_off_screen || (*col < (DCOLS-1))) {
+ (*col)++;
+ }
+ break;
+ case UPLEFT:
+ if (allow_off_screen || ((*row > MIN_ROW) && (*col > 0))) {
+ (*row)--;
+ (*col)--;
+ }
+ break;
+ case UPRIGHT:
+ if (allow_off_screen || ((*row > MIN_ROW) && (*col < (DCOLS-1)))) {
+ (*row)--;
+ (*col)++;
+ }
+ break;
+ case DOWNRIGHT:
+ if (allow_off_screen || ((*row < (DROWS-2)) && (*col < (DCOLS-1)))) {
+ (*row)++;
+ (*col)++;
+ }
+ break;
+ case DOWNLEFT:
+ if (allow_off_screen || ((*row < (DROWS-2)) && (*col > 0))) {
+ (*row)++;
+ (*col)--;
+ }
+ break;
+ }
+}
+
+get_hit_chance(weapon)
+object *weapon;
+{
+ short hit_chance;
+
+ hit_chance = 40;
+ hit_chance += 3 * to_hit(weapon);
+ hit_chance += (((2 * rogue.exp) + (2 * ring_exp)) - r_rings);
+ return(hit_chance);
+}
+
+get_weapon_damage(weapon)
+object *weapon;
+{
+ short damage;
+
+ damage = get_w_damage(weapon);
+ damage += damage_for_strength();
+ damage += ((((rogue.exp + ring_exp) - r_rings) + 1) / 2);
+ return(damage);
+}
+
+s_con_mon(monster)
+object *monster;
+{
+ if (con_mon) {
+ monster->m_flags |= CONFUSED;
+ monster->moves_confused += get_rand(12, 22);
+ message("the monster appears confused", 0);
+ con_mon = 0;
+ }
+}
diff --git a/rogue/init.c b/rogue/init.c
new file mode 100644
index 00000000..fe6d9b1b
--- /dev/null
+++ b/rogue/init.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)init.c 5.4 (Berkeley) 2/28/91";
+#endif /* not lint */
+
+/*
+ * init.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 <stdio.h>
+#include "rogue.h"
+
+char login_name[MAX_OPT_LEN];
+char *nick_name = (char *) 0;
+char *rest_file = 0;
+boolean cant_int = 0;
+boolean did_int = 0;
+boolean score_only;
+boolean init_curses = 0;
+boolean save_is_interactive = 1;
+boolean ask_quit = 1;
+boolean no_skull = 0;
+boolean passgo = 0;
+char *error_file = "rogue.esave";
+char *byebye_string = "Okay, bye bye!";
+
+extern char *fruit;
+extern char *save_file;
+extern short party_room;
+extern boolean jump;
+
+init(argc, argv)
+int argc;
+char *argv[];
+{
+ char *pn;
+ int seed;
+
+ pn = md_gln();
+ if ((!pn) || (strlen(pn) >= MAX_OPT_LEN)) {
+ clean_up("Hey! Who are you?");
+ }
+ (void) strcpy(login_name, pn);
+
+ do_args(argc, argv);
+ do_opts();
+
+ if (!score_only && !rest_file) {
+ printf("Hello %s, just a moment while I dig the dungeon...",
+ nick_name);
+ fflush(stdout);
+ }
+
+ initscr();
+ if ((LINES < DROWS) || (COLS < DCOLS)) {
+ clean_up("must be played on 24 x 80 screen");
+ }
+ start_window();
+ init_curses = 1;
+
+ md_heed_signals();
+
+ if (score_only) {
+ put_scores((object *) 0, 0);
+ }
+ seed = md_gseed();
+ (void) srrandom(seed);
+ if (rest_file) {
+ restore(rest_file);
+ return(1);
+ }
+ mix_colors();
+ get_wand_and_ring_materials();
+ make_scroll_titles();
+
+ level_objects.next_object = (object *) 0;
+ level_monsters.next_monster = (object *) 0;
+ player_init();
+ ring_stats(0);
+ return(0);
+}
+
+player_init()
+{
+ object *obj;
+
+ rogue.pack.next_object = (object *) 0;
+
+ obj = alloc_object();
+ get_food(obj, 1);
+ (void) add_to_pack(obj, &rogue.pack, 1);
+
+ obj = alloc_object(); /* initial armor */
+ obj->what_is = ARMOR;
+ obj->which_kind = RINGMAIL;
+ obj->class = RINGMAIL+2;
+ obj->is_protected = 0;
+ obj->d_enchant = 1;
+ (void) add_to_pack(obj, &rogue.pack, 1);
+ do_wear(obj);
+
+ obj = alloc_object(); /* initial weapons */
+ obj->what_is = WEAPON;
+ obj->which_kind = MACE;
+ obj->damage = "2d3";
+ obj->hit_enchant = obj->d_enchant = 1;
+ obj->identified = 1;
+ (void) add_to_pack(obj, &rogue.pack, 1);
+ do_wield(obj);
+
+ obj = alloc_object();
+ obj->what_is = WEAPON;
+ obj->which_kind = BOW;
+ obj->damage = "1d2";
+ obj->hit_enchant = 1;
+ obj->d_enchant = 0;
+ obj->identified = 1;
+ (void) add_to_pack(obj, &rogue.pack, 1);
+
+ obj = alloc_object();
+ obj->what_is = WEAPON;
+ obj->which_kind = ARROW;
+ obj->quantity = get_rand(25, 35);
+ obj->damage = "1d2";
+ obj->hit_enchant = 0;
+ obj->d_enchant = 0;
+ obj->identified = 1;
+ (void) add_to_pack(obj, &rogue.pack, 1);
+}
+
+clean_up(estr)
+char *estr;
+{
+ if (save_is_interactive) {
+ if (init_curses) {
+ move(DROWS-1, 0);
+ refresh();
+ stop_window();
+ }
+ printf("\n%s\n", estr);
+ }
+ md_exit(0);
+}
+
+start_window()
+{
+ crmode();
+ noecho();
+#ifndef BAD_NONL
+ nonl();
+#endif
+ md_control_keybord(0);
+}
+
+stop_window()
+{
+ endwin();
+ md_control_keybord(1);
+}
+
+void
+byebye()
+{
+ md_ignore_signals();
+ if (ask_quit) {
+ quit(1);
+ } else {
+ clean_up(byebye_string);
+ }
+ md_heed_signals();
+}
+
+void
+onintr()
+{
+ md_ignore_signals();
+ if (cant_int) {
+ did_int = 1;
+ } else {
+ check_message();
+ message("interrupt", 1);
+ }
+ md_heed_signals();
+}
+
+void
+error_save()
+{
+ save_is_interactive = 0;
+ save_into_file(error_file);
+ clean_up("");
+}
+
+do_args(argc, argv)
+int argc;
+char *argv[];
+{
+ short i, j;
+
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ for (j = 1; argv[i][j]; j++) {
+ switch(argv[i][j]) {
+ case 's':
+ score_only = 1;
+ break;
+ }
+ }
+ } else {
+ rest_file = argv[i];
+ }
+ }
+}
+
+do_opts()
+{
+ char *eptr;
+
+ if (eptr = md_getenv("ROGUEOPTS")) {
+ for (;;) {
+ while ((*eptr) == ' ') {
+ eptr++;
+ }
+ if (!(*eptr)) {
+ break;
+ }
+ if (!strncmp(eptr, "fruit=", 6)) {
+ eptr += 6;
+ env_get_value(&fruit, eptr, 1);
+ } else if (!strncmp(eptr, "file=", 5)) {
+ eptr += 5;
+ env_get_value(&save_file, eptr, 0);
+ } else if (!strncmp(eptr, "jump", 4)) {
+ jump = 1;
+ } else if (!strncmp(eptr, "name=", 5)) {
+ eptr += 5;
+ env_get_value(&nick_name, eptr, 0);
+ } else if (!strncmp(eptr, "noaskquit", 9)) {
+ ask_quit = 0;
+ } else if (!strncmp(eptr, "noskull", 5) ||
+ !strncmp(eptr,"notomb", 6)) {
+ no_skull = 1;
+ } else if (!strncmp(eptr, "passgo", 5)) {
+ passgo = 1;
+ }
+ while ((*eptr) && (*eptr != ',')) {
+ eptr++;
+ }
+ if (!(*(eptr++))) {
+ break;
+ }
+ }
+ }
+ /* If some strings have not been set through ROGUEOPTS, assign defaults
+ * to them so that the options editor has data to work with.
+ */
+ init_str(&nick_name, login_name);
+ init_str(&save_file, "rogue.save");
+ init_str(&fruit, "slime-mold");
+}
+
+env_get_value(s, e, add_blank)
+char **s, *e;
+boolean add_blank;
+{
+ short i = 0;
+ char *t;
+
+ t = e;
+
+ while ((*e) && (*e != ',')) {
+ if (*e == ':') {
+ *e = ';'; /* ':' reserved for score file purposes */
+ }
+ e++;
+ if (++i >= MAX_OPT_LEN) {
+ break;
+ }
+ }
+ *s = md_malloc(MAX_OPT_LEN + 2);
+ (void) strncpy(*s, t, i);
+ if (add_blank) {
+ (*s)[i++] = ' ';
+ }
+ (*s)[i] = '\0';
+}
+
+init_str(str, dflt)
+char **str, *dflt;
+{
+ if (!(*str)) {
+ *str = md_malloc(MAX_OPT_LEN + 2);
+ (void) strcpy(*str, dflt);
+ }
+}
diff --git a/rogue/inventory.c b/rogue/inventory.c
new file mode 100644
index 00000000..cc06eeb8
--- /dev/null
+++ b/rogue/inventory.c
@@ -0,0 +1,774 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)inventory.c 5.4 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * inventory.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.h"
+
+boolean is_wood[WANDS];
+char *press_space = " --press space to continue--";
+
+char *wand_materials[WAND_MATERIALS] = {
+ "steel ",
+ "bronze ",
+ "gold ",
+ "silver ",
+ "copper ",
+ "nickel ",
+ "cobalt ",
+ "tin ",
+ "iron ",
+ "magnesium ",
+ "chrome ",
+ "carbon ",
+ "platinum ",
+ "silicon ",
+ "titanium ",
+
+ "teak ",
+ "oak ",
+ "cherry ",
+ "birch ",
+ "pine ",
+ "cedar ",
+ "redwood ",
+ "balsa ",
+ "ivory ",
+ "walnut ",
+ "maple ",
+ "mahogany ",
+ "elm ",
+ "palm ",
+ "wooden "
+};
+
+char *gems[GEMS] = {
+ "diamond ",
+ "stibotantalite ",
+ "lapi-lazuli ",
+ "ruby ",
+ "emerald ",
+ "sapphire ",
+ "amethyst ",
+ "quartz ",
+ "tiger-eye ",
+ "opal ",
+ "agate ",
+ "turquoise ",
+ "pearl ",
+ "garnet "
+};
+
+char *syllables[MAXSYLLABLES] = {
+ "blech ",
+ "foo ",
+ "barf ",
+ "rech ",
+ "bar ",
+ "blech ",
+ "quo ",
+ "bloto ",
+ "oh ",
+ "caca ",
+ "blorp ",
+ "erp ",
+ "festr ",
+ "rot ",
+ "slie ",
+ "snorf ",
+ "iky ",
+ "yuky ",
+ "ooze ",
+ "ah ",
+ "bahl ",
+ "zep ",
+ "druhl ",
+ "flem ",
+ "behil ",
+ "arek ",
+ "mep ",
+ "zihr ",
+ "grit ",
+ "kona ",
+ "kini ",
+ "ichi ",
+ "tims ",
+ "ogr ",
+ "oo ",
+ "ighr ",
+ "coph ",
+ "swerr ",
+ "mihln ",
+ "poxi "
+};
+
+#define COMS 48
+
+struct id_com_s {
+ short com_char;
+ char *com_desc;
+};
+
+struct id_com_s com_id_tab[COMS] = {
+ '?', "? prints help",
+ 'r', "r read scroll",
+ '/', "/ identify object",
+ 'e', "e eat food",
+ 'h', "h left ",
+ 'w', "w wield a weapon",
+ 'j', "j down",
+ 'W', "W wear armor",
+ 'k', "k up",
+ 'T', "T take armor off",
+ 'l', "l right",
+ 'P', "P put on ring",
+ 'y', "y up & left",
+ 'R', "R remove ring",
+ 'u', "u up & right",
+ 'd', "d drop object",
+ 'b', "b down & left",
+ 'c', "c call object",
+ 'n', "n down & right",
+ NULL, "<SHIFT><dir>: run that way",
+ ')', ") print current weapon",
+ NULL, "<CTRL><dir>: run till adjacent",
+ ']', "] print current armor",
+ 'f', "f<dir> fight till death or near death",
+ '=', "= print current rings",
+ 't', "t<dir> throw something",
+ '\001', "^A print Hp-raise average",
+ 'm', "m<dir> move onto without picking up",
+ 'z', "z<dir> zap a wand in a direction",
+ 'o', "o examine/set options",
+ '^', "^<dir> identify trap type",
+ '\022', "^R redraw screen",
+ '&', "& save screen into 'rogue.screen'",
+ 's', "s search for trap/secret door",
+ '\020', "^P repeat last message",
+ '>', "> go down a staircase",
+ '\033', "^[ cancel command",
+ '<', "< go up a staircase",
+ 'S', "S save game",
+ '.', ". rest for a turn",
+ 'Q', "Q quit",
+ ',', ", pick something up",
+ '!', "! shell escape",
+ 'i', "i inventory",
+ 'F', "F<dir> fight till either of you dies",
+ 'I', "I inventory single item",
+ 'v', "v print version number",
+ 'q', "q quaff potion"
+};
+
+extern boolean wizard;
+extern char *m_names[], *more;
+
+inventory(pack, mask)
+object *pack;
+unsigned short mask;
+{
+ object *obj;
+ short i = 0, j, maxlen = 0, n;
+ char descs[MAX_PACK_COUNT+1][DCOLS];
+ short row, col;
+
+ obj = pack->next_object;
+
+ if (!obj) {
+ message("your pack is empty", 0);
+ return;
+ }
+ while (obj) {
+ if (obj->what_is & mask) {
+ descs[i][0] = ' ';
+ descs[i][1] = obj->ichar;
+ descs[i][2] = ((obj->what_is & ARMOR) && obj->is_protected)
+ ? '}' : ')';
+ descs[i][3] = ' ';
+ get_desc(obj, descs[i]+4);
+ if ((n = strlen(descs[i])) > maxlen) {
+ maxlen = n;
+ }
+ i++;
+ }
+ obj = obj->next_object;
+ }
+ (void) strcpy(descs[i++], press_space);
+ if (maxlen < 27) maxlen = 27;
+ col = DCOLS - (maxlen + 2);
+
+ for (row = 0; ((row < i) && (row < DROWS)); row++) {
+ if (row > 0) {
+ for (j = col; j < DCOLS; j++) {
+ descs[row-1][j-col] = mvinch(row, j);
+ }
+ descs[row-1][j-col] = 0;
+ }
+ mvaddstr(row, col, descs[row]);
+ clrtoeol();
+ }
+ refresh();
+ wait_for_ack();
+
+ move(0, 0);
+ clrtoeol();
+
+ for (j = 1; ((j < i) && (j < DROWS)); j++) {
+ mvaddstr(j, col, descs[j-1]);
+ }
+}
+
+id_com()
+{
+ int ch = 0;
+ short i, j, k;
+
+ while (ch != CANCEL) {
+ check_message();
+ message("Character you want help for (* for all):", 0);
+
+ refresh();
+ ch = getchar();
+
+ switch(ch) {
+ case LIST:
+ {
+ char save[(((COMS / 2) + (COMS % 2)) + 1)][DCOLS];
+ short rows = (((COMS / 2) + (COMS % 2)) + 1);
+ boolean need_two_screens;
+
+ if (rows > LINES) {
+ need_two_screens = 1;
+ rows = LINES;
+ }
+ k = 0;
+
+ for (i = 0; i < rows; i++) {
+ for (j = 0; j < DCOLS; j++) {
+ save[i][j] = mvinch(i, j);
+ }
+ }
+MORE:
+ for (i = 0; i < rows; i++) {
+ move(i, 0);
+ clrtoeol();
+ }
+ for (i = 0; i < (rows-1); i++) {
+ if (i < (LINES-1)) {
+ if (((i + i) < COMS) && ((i+i+k) < COMS)) {
+ mvaddstr(i, 0, com_id_tab[i+i+k].com_desc);
+ }
+ if (((i + i + 1) < COMS) && ((i+i+k+1) < COMS)) {
+ mvaddstr(i, (DCOLS/2),
+ com_id_tab[i+i+k+1].com_desc);
+ }
+ }
+ }
+ mvaddstr(rows - 1, 0, need_two_screens ? more : press_space);
+ refresh();
+ wait_for_ack();
+
+ if (need_two_screens) {
+ k += ((rows-1) * 2);
+ need_two_screens = 0;
+ goto MORE;
+ }
+ for (i = 0; i < rows; i++) {
+ move(i, 0);
+ for (j = 0; j < DCOLS; j++) {
+ addch(save[i][j]);
+ }
+ }
+ }
+ break;
+ default:
+ if (!pr_com_id(ch)) {
+ if (!pr_motion_char(ch)) {
+ check_message();
+ message("unknown character", 0);
+ }
+ }
+ ch = CANCEL;
+ break;
+ }
+ }
+}
+
+pr_com_id(ch)
+int ch;
+{
+ int i;
+
+ if (!get_com_id(&i, ch)) {
+ return(0);
+ }
+ check_message();
+ message(com_id_tab[i].com_desc, 0);
+ return(1);
+}
+
+get_com_id(index, ch)
+int *index;
+short ch;
+{
+ short i;
+
+ for (i = 0; i < COMS; i++) {
+ if (com_id_tab[i].com_char == ch) {
+ *index = i;
+ return(1);
+ }
+ }
+ return(0);
+}
+
+pr_motion_char(ch)
+int ch;
+{
+ if ( (ch == 'J') ||
+ (ch == 'K') ||
+ (ch == 'L') ||
+ (ch == 'H') ||
+ (ch == 'Y') ||
+ (ch == 'U') ||
+ (ch == 'N') ||
+ (ch == 'B') ||
+ (ch == '\012') ||
+ (ch == '\013') ||
+ (ch == '\010') ||
+ (ch == '\014') ||
+ (ch == '\025') ||
+ (ch == '\031') ||
+ (ch == '\016') ||
+ (ch == '\002')) {
+ char until[18], buf[DCOLS];
+ int n;
+
+ if (ch <= '\031') {
+ ch += 96;
+ (void) strcpy(until, "until adjascent");
+ } else {
+ ch += 32;
+ until[0] = '\0';
+ }
+ (void) get_com_id(&n, ch);
+ sprintf(buf, "run %s %s", com_id_tab[n].com_desc + 8, until);
+ check_message();
+ message(buf, 0);
+ return(1);
+ } else {
+ return(0);
+ }
+}
+
+mix_colors()
+{
+ short i, j, k;
+ char *t;
+
+ for (i = 0; i <= 32; i++) {
+ j = get_rand(0, (POTIONS - 1));
+ k = get_rand(0, (POTIONS - 1));
+ t = id_potions[j].title;
+ id_potions[j].title = id_potions[k].title;
+ id_potions[k].title = t;
+ }
+}
+
+make_scroll_titles()
+{
+ short i, j, n;
+ short sylls, s;
+
+ for (i = 0; i < SCROLS; i++) {
+ sylls = get_rand(2, 5);
+ (void) strcpy(id_scrolls[i].title, "'");
+
+ for (j = 0; j < sylls; j++) {
+ s = get_rand(1, (MAXSYLLABLES-1));
+ (void) strcat(id_scrolls[i].title, syllables[s]);
+ }
+ n = strlen(id_scrolls[i].title);
+ (void) strcpy(id_scrolls[i].title+(n-1), "' ");
+ }
+}
+
+get_desc(obj, desc)
+object *obj;
+char *desc;
+{
+ char *item_name;
+ struct id *id_table;
+ char more_info[32];
+ short i;
+
+ if (obj->what_is == AMULET) {
+ (void) strcpy(desc, "the amulet of Yendor ");
+ return;
+ }
+ item_name = name_of(obj);
+
+ if (obj->what_is == GOLD) {
+ sprintf(desc, "%d pieces of gold", obj->quantity);
+ return;
+ }
+
+ if (obj->what_is != ARMOR) {
+ if (obj->quantity == 1) {
+ (void) strcpy(desc, "a ");
+ } else {
+ sprintf(desc, "%d ", obj->quantity);
+ }
+ }
+ if (obj->what_is == FOOD) {
+ if (obj->which_kind == RATION) {
+ if (obj->quantity > 1) {
+ sprintf(desc, "%d rations of ", obj->quantity);
+ } else {
+ (void) strcpy(desc, "some ");
+ }
+ } else {
+ (void) strcpy(desc, "a ");
+ }
+ (void) strcat(desc, item_name);
+ goto ANA;
+ }
+ id_table = get_id_table(obj);
+
+ if (wizard) {
+ goto ID;
+ }
+ if (obj->what_is & (WEAPON | ARMOR | WAND | RING)) {
+ goto CHECK;
+ }
+
+ switch(id_table[obj->which_kind].id_status) {
+ case UNIDENTIFIED:
+CHECK:
+ switch(obj->what_is) {
+ case SCROL:
+ (void) strcat(desc, item_name);
+ (void) strcat(desc, "entitled: ");
+ (void) strcat(desc, id_table[obj->which_kind].title);
+ break;
+ case POTION:
+ (void) strcat(desc, id_table[obj->which_kind].title);
+ (void) strcat(desc, item_name);
+ break;
+ case WAND:
+ case RING:
+ if (obj->identified ||
+ (id_table[obj->which_kind].id_status == IDENTIFIED)) {
+ goto ID;
+ }
+ if (id_table[obj->which_kind].id_status == CALLED) {
+ goto CALL;
+ }
+ (void) strcat(desc, id_table[obj->which_kind].title);
+ (void) strcat(desc, item_name);
+ break;
+ case ARMOR:
+ if (obj->identified) {
+ goto ID;
+ }
+ (void) strcpy(desc, id_table[obj->which_kind].title);
+ break;
+ case WEAPON:
+ if (obj->identified) {
+ goto ID;
+ }
+ (void) strcat(desc, name_of(obj));
+ break;
+ }
+ break;
+ case CALLED:
+CALL: switch(obj->what_is) {
+ case SCROL:
+ case POTION:
+ case WAND:
+ case RING:
+ (void) strcat(desc, item_name);
+ (void) strcat(desc, "called ");
+ (void) strcat(desc, id_table[obj->which_kind].title);
+ break;
+ }
+ break;
+ case IDENTIFIED:
+ID: switch(obj->what_is) {
+ case SCROL:
+ case POTION:
+ (void) strcat(desc, item_name);
+ (void) strcat(desc, id_table[obj->which_kind].real);
+ break;
+ case RING:
+ if (wizard || obj->identified) {
+ if ((obj->which_kind == DEXTERITY) ||
+ (obj->which_kind == ADD_STRENGTH)) {
+ sprintf(more_info, "%s%d ", ((obj->class > 0) ? "+" : ""),
+ obj->class);
+ (void) strcat(desc, more_info);
+ }
+ }
+ (void) strcat(desc, item_name);
+ (void) strcat(desc, id_table[obj->which_kind].real);
+ break;
+ case WAND:
+ (void) strcat(desc, item_name);
+ (void) strcat(desc, id_table[obj->which_kind].real);
+ if (wizard || obj->identified) {
+ sprintf(more_info, "[%d]", obj->class);
+ (void) strcat(desc, more_info);
+ }
+ break;
+ case ARMOR:
+ sprintf(desc, "%s%d ", ((obj->d_enchant >= 0) ? "+" : ""),
+ obj->d_enchant);
+ (void) strcat(desc, id_table[obj->which_kind].title);
+ sprintf(more_info, "[%d] ", get_armor_class(obj));
+ (void) strcat(desc, more_info);
+ break;
+ case WEAPON:
+ sprintf(desc+strlen(desc), "%s%d,%s%d ",
+ ((obj->hit_enchant >= 0) ? "+" : ""), obj->hit_enchant,
+ ((obj->d_enchant >= 0) ? "+" : ""), obj->d_enchant);
+ (void) strcat(desc, name_of(obj));
+ break;
+ }
+ break;
+ }
+ANA:
+ if (!strncmp(desc, "a ", 2)) {
+ if (is_vowel(desc[2])) {
+ for (i = strlen(desc) + 1; i > 1; i--) {
+ desc[i] = desc[i-1];
+ }
+ desc[1] = 'n';
+ }
+ }
+ if (obj->in_use_flags & BEING_WIELDED) {
+ (void) strcat(desc, "in hand");
+ } else if (obj->in_use_flags & BEING_WORN) {
+ (void) strcat(desc, "being worn");
+ } else if (obj->in_use_flags & ON_LEFT_HAND) {
+ (void) strcat(desc, "on left hand");
+ } else if (obj->in_use_flags & ON_RIGHT_HAND) {
+ (void) strcat(desc, "on right hand");
+ }
+}
+
+get_wand_and_ring_materials()
+{
+ short i, j;
+ boolean used[WAND_MATERIALS];
+
+ for (i = 0; i < WAND_MATERIALS; i++) {
+ used[i] = 0;
+ }
+ for (i = 0; i < WANDS; i++) {
+ do {
+ j = get_rand(0, WAND_MATERIALS-1);
+ } while (used[j]);
+ used[j] = 1;
+ (void) strcpy(id_wands[i].title, wand_materials[j]);
+ is_wood[i] = (j > MAX_METAL);
+ }
+ for (i = 0; i < GEMS; i++) {
+ used[i] = 0;
+ }
+ for (i = 0; i < RINGS; i++) {
+ do {
+ j = get_rand(0, GEMS-1);
+ } while (used[j]);
+ used[j] = 1;
+ (void) strcpy(id_rings[i].title, gems[j]);
+ }
+}
+
+single_inv(ichar)
+short ichar;
+{
+ short ch;
+ char desc[DCOLS];
+ object *obj;
+
+ ch = ichar ? ichar : pack_letter("inventory what?", ALL_OBJECTS);
+
+ if (ch == CANCEL) {
+ return;
+ }
+ if (!(obj = get_letter_object(ch))) {
+ message("no such item.", 0);
+ return;
+ }
+ desc[0] = ch;
+ desc[1] = ((obj->what_is & ARMOR) && obj->is_protected) ? '}' : ')';
+ desc[2] = ' ';
+ desc[3] = 0;
+ get_desc(obj, desc+3);
+ message(desc, 0);
+}
+
+struct id *
+get_id_table(obj)
+object *obj;
+{
+ switch(obj->what_is) {
+ case SCROL:
+ return(id_scrolls);
+ case POTION:
+ return(id_potions);
+ case WAND:
+ return(id_wands);
+ case RING:
+ return(id_rings);
+ case WEAPON:
+ return(id_weapons);
+ case ARMOR:
+ return(id_armors);
+ }
+ return((struct id *) 0);
+}
+
+inv_armor_weapon(is_weapon)
+boolean is_weapon;
+{
+ if (is_weapon) {
+ if (rogue.weapon) {
+ single_inv(rogue.weapon->ichar);
+ } else {
+ message("not wielding anything", 0);
+ }
+ } else {
+ if (rogue.armor) {
+ single_inv(rogue.armor->ichar);
+ } else {
+ message("not wearing anything", 0);
+ }
+ }
+}
+
+id_type()
+{
+ char *id;
+ int ch;
+ char buf[DCOLS];
+
+ message("what do you want identified?", 0);
+
+ ch = rgetchar();
+
+ if ((ch >= 'A') && (ch <= 'Z')) {
+ id = m_names[ch-'A'];
+ } else if (ch < 32) {
+ check_message();
+ return;
+ } else {
+ switch(ch) {
+ case '@':
+ id = "you";
+ break;
+ case '%':
+ id = "staircase";
+ break;
+ case '^':
+ id = "trap";
+ break;
+ case '+':
+ id = "door";
+ break;
+ case '-':
+ case '|':
+ id = "wall of a room";
+ break;
+ case '.':
+ id = "floor";
+ break;
+ case '#':
+ id = "passage";
+ break;
+ case ' ':
+ id = "solid rock";
+ break;
+ case '=':
+ id = "ring";
+ break;
+ case '?':
+ id = "scroll";
+ break;
+ case '!':
+ id = "potion";
+ break;
+ case '/':
+ id = "wand or staff";
+ break;
+ case ')':
+ id = "weapon";
+ break;
+ case ']':
+ id = "armor";
+ break;
+ case '*':
+ id = "gold";
+ break;
+ case ':':
+ id = "food";
+ break;
+ case ',':
+ id = "the Amulet of Yendor";
+ break;
+ default:
+ id = "unknown character";
+ break;
+ }
+ }
+ check_message();
+ sprintf(buf, "'%c': %s", ch, id);
+ message(buf, 0);
+}
diff --git a/rogue/level.c b/rogue/level.c
new file mode 100644
index 00000000..e04db8f7
--- /dev/null
+++ b/rogue/level.c
@@ -0,0 +1,881 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)level.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * level.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.h"
+
+#define swap(x,y) {t = x; x = y; y = t;}
+
+short cur_level = 0;
+short max_level = 1;
+short cur_room;
+char *new_level_message = 0;
+short party_room = NO_ROOM;
+short r_de;
+
+long level_points[MAX_EXP_LEVEL] = {
+ 10L,
+ 20L,
+ 40L,
+ 80L,
+ 160L,
+ 320L,
+ 640L,
+ 1300L,
+ 2600L,
+ 5200L,
+ 10000L,
+ 20000L,
+ 40000L,
+ 80000L,
+ 160000L,
+ 320000L,
+ 1000000L,
+ 3333333L,
+ 6666666L,
+ MAX_EXP,
+ 99900000L
+};
+
+short random_rooms[MAXROOMS] = {3, 7, 5, 2, 0, 6, 1, 4, 8};
+
+extern boolean being_held, wizard, detect_monster;
+extern boolean see_invisible;
+extern short bear_trap, levitate, extra_hp, less_hp, cur_room;
+
+make_level()
+{
+ short i, j;
+ short must_1, must_2, must_3;
+ boolean big_room;
+
+ if (cur_level < LAST_DUNGEON) {
+ cur_level++;
+ }
+ if (cur_level > max_level) {
+ max_level = cur_level;
+ }
+ must_1 = get_rand(0, 5);
+
+ switch(must_1) {
+ case 0:
+ must_1 = 0;
+ must_2 = 1;
+ must_3 = 2;
+ break;
+ case 1:
+ must_1 = 3;
+ must_2 = 4;
+ must_3 = 5;
+ break;
+ case 2:
+ must_1 = 6;
+ must_2 = 7;
+ must_3 = 8;
+ break;
+ case 3:
+ must_1 = 0;
+ must_2 = 3;
+ must_3 = 6;
+ break;
+ case 4:
+ must_1 = 1;
+ must_2 = 4;
+ must_3 = 7;
+ break;
+ case 5:
+ must_1 = 2;
+ must_2 = 5;
+ must_3 = 8;
+ break;
+ }
+ if (rand_percent(8)) {
+ party_room = 0;
+ }
+ big_room = ((party_room != NO_ROOM) && rand_percent(1));
+ if (big_room) {
+ make_room(BIG_ROOM, 0, 0, 0);
+ } else {
+ for (i = 0; i < MAXROOMS; i++) {
+ make_room(i, must_1, must_2, must_3);
+ }
+ }
+ if (!big_room) {
+ add_mazes();
+
+ mix_random_rooms();
+
+ for (j = 0; j < MAXROOMS; j++) {
+
+ i = random_rooms[j];
+
+ if (i < (MAXROOMS-1)) {
+ (void) connect_rooms(i, i+1);
+ }
+ if (i < (MAXROOMS-3)) {
+ (void) connect_rooms(i, i+3);
+ }
+ if (i < (MAXROOMS-2)) {
+ if (rooms[i+1].is_room & R_NOTHING) {
+ if (connect_rooms(i, i+2)) {
+ rooms[i+1].is_room = R_CROSS;
+ }
+ }
+ }
+ if (i < (MAXROOMS-6)) {
+ if (rooms[i+3].is_room & R_NOTHING) {
+ if (connect_rooms(i, i+6)) {
+ rooms[i+3].is_room = R_CROSS;
+ }
+ }
+ }
+ if (is_all_connected()) {
+ break;
+ }
+ }
+ fill_out_level();
+ }
+ if (!has_amulet() && (cur_level >= AMULET_LEVEL)) {
+ put_amulet();
+ }
+}
+
+make_room(rn, r1, r2, r3)
+short rn, r1, r2, r3;
+{
+ short left_col, right_col, top_row, bottom_row;
+ short width, height;
+ short row_offset, col_offset;
+ short i, j, ch;
+
+ switch(rn) {
+ case 0:
+ left_col = 0;
+ right_col = COL1-1;
+ top_row = MIN_ROW;
+ bottom_row = ROW1-1;
+ break;
+ case 1:
+ left_col = COL1+1;
+ right_col = COL2-1;
+ top_row = MIN_ROW;
+ bottom_row = ROW1-1;
+ break;
+ case 2:
+ left_col = COL2+1;
+ right_col = DCOLS-1;
+ top_row = MIN_ROW;
+ bottom_row = ROW1-1;
+ break;
+ case 3:
+ left_col = 0;
+ right_col = COL1-1;
+ top_row = ROW1+1;
+ bottom_row = ROW2-1;
+ break;
+ case 4:
+ left_col = COL1+1;
+ right_col = COL2-1;
+ top_row = ROW1+1;
+ bottom_row = ROW2-1;
+ break;
+ case 5:
+ left_col = COL2+1;
+ right_col = DCOLS-1;
+ top_row = ROW1+1;
+ bottom_row = ROW2-1;
+ break;
+ case 6:
+ left_col = 0;
+ right_col = COL1-1;
+ top_row = ROW2+1;
+ bottom_row = DROWS - 2;
+ break;
+ case 7:
+ left_col = COL1+1;
+ right_col = COL2-1;
+ top_row = ROW2+1;
+ bottom_row = DROWS - 2;
+ break;
+ case 8:
+ left_col = COL2+1;
+ right_col = DCOLS-1;
+ top_row = ROW2+1;
+ bottom_row = DROWS - 2;
+ break;
+ case BIG_ROOM:
+ top_row = get_rand(MIN_ROW, MIN_ROW+5);
+ bottom_row = get_rand(DROWS-7, DROWS-2);
+ left_col = get_rand(0, 10);;
+ right_col = get_rand(DCOLS-11, DCOLS-1);
+ rn = 0;
+ goto B;
+ }
+ height = get_rand(4, (bottom_row - top_row + 1));
+ width = get_rand(7, (right_col - left_col - 2));
+
+ row_offset = get_rand(0, ((bottom_row - top_row) - height + 1));
+ col_offset = get_rand(0, ((right_col - left_col) - width + 1));
+
+ top_row += row_offset;
+ bottom_row = top_row + height - 1;
+
+ left_col += col_offset;
+ right_col = left_col + width - 1;
+
+ if ((rn != r1) && (rn != r2) && (rn != r3) && rand_percent(40)) {
+ goto END;
+ }
+B:
+ rooms[rn].is_room = R_ROOM;
+
+ for (i = top_row; i <= bottom_row; i++) {
+ for (j = left_col; j <= right_col; j++) {
+ if ((i == top_row) || (i == bottom_row)) {
+ ch = HORWALL;
+ } else if ( ((i != top_row) && (i != bottom_row)) &&
+ ((j == left_col) || (j == right_col))) {
+ ch = VERTWALL;
+ } else {
+ ch = FLOOR;
+ }
+ dungeon[i][j] = ch;
+ }
+ }
+END:
+ rooms[rn].top_row = top_row;
+ rooms[rn].bottom_row = bottom_row;
+ rooms[rn].left_col = left_col;
+ rooms[rn].right_col = right_col;
+}
+
+connect_rooms(room1, room2)
+short room1, room2;
+{
+ short row1, col1, row2, col2, dir;
+
+ if ((!(rooms[room1].is_room & (R_ROOM | R_MAZE))) ||
+ (!(rooms[room2].is_room & (R_ROOM | R_MAZE)))) {
+ return(0);
+ }
+ if (same_row(room1, room2) &&
+ (rooms[room1].left_col > rooms[room2].right_col)) {
+ put_door(&rooms[room1], LEFT, &row1, &col1);
+ put_door(&rooms[room2], RIGHT, &row2, &col2);
+ dir = LEFT;
+ } else if (same_row(room1, room2) &&
+ (rooms[room2].left_col > rooms[room1].right_col)) {
+ put_door(&rooms[room1], RIGHT, &row1, &col1);
+ put_door(&rooms[room2], LEFT, &row2, &col2);
+ dir = RIGHT;
+ } else if (same_col(room1, room2) &&
+ (rooms[room1].top_row > rooms[room2].bottom_row)) {
+ put_door(&rooms[room1], UPWARD, &row1, &col1);
+ put_door(&rooms[room2], DOWN, &row2, &col2);
+ dir = UPWARD;
+ } else if (same_col(room1, room2) &&
+ (rooms[room2].top_row > rooms[room1].bottom_row)) {
+ put_door(&rooms[room1], DOWN, &row1, &col1);
+ put_door(&rooms[room2], UPWARD, &row2, &col2);
+ dir = DOWN;
+ } else {
+ return(0);
+ }
+
+ do {
+ draw_simple_passage(row1, col1, row2, col2, dir);
+ } while (rand_percent(4));
+
+ rooms[room1].doors[dir/2].oth_room = room2;
+ rooms[room1].doors[dir/2].oth_row = row2;
+ rooms[room1].doors[dir/2].oth_col = col2;
+
+ rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_room = room1;
+ rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_row = row1;
+ rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_col = col1;
+ return(1);
+}
+
+clear_level()
+{
+ short i, j;
+
+ for (i = 0; i < MAXROOMS; i++) {
+ rooms[i].is_room = R_NOTHING;
+ for (j = 0; j < 4; j++) {
+ rooms[i].doors[j].oth_room = NO_ROOM;
+ }
+ }
+
+ for (i = 0; i < MAX_TRAPS; i++) {
+ traps[i].trap_type = NO_TRAP;
+ }
+ for (i = 0; i < DROWS; i++) {
+ for (j = 0; j < DCOLS; j++) {
+ dungeon[i][j] = NOTHING;
+ }
+ }
+ detect_monster = see_invisible = 0;
+ being_held = bear_trap = 0;
+ party_room = NO_ROOM;
+ rogue.row = rogue.col = -1;
+ clear();
+}
+
+put_door(rm, dir, row, col)
+room *rm;
+short dir;
+short *row, *col;
+{
+ short wall_width;
+
+ wall_width = (rm->is_room & R_MAZE) ? 0 : 1;
+
+ switch(dir) {
+ case UPWARD:
+ case DOWN:
+ *row = ((dir == UPWARD) ? rm->top_row : rm->bottom_row);
+ do {
+ *col = get_rand(rm->left_col+wall_width,
+ rm->right_col-wall_width);
+ } while (!(dungeon[*row][*col] & (HORWALL | TUNNEL)));
+ break;
+ case RIGHT:
+ case LEFT:
+ *col = (dir == LEFT) ? rm->left_col : rm->right_col;
+ do {
+ *row = get_rand(rm->top_row+wall_width,
+ rm->bottom_row-wall_width);
+ } while (!(dungeon[*row][*col] & (VERTWALL | TUNNEL)));
+ break;
+ }
+ if (rm->is_room & R_ROOM) {
+ dungeon[*row][*col] = DOOR;
+ }
+ if ((cur_level > 2) && rand_percent(HIDE_PERCENT)) {
+ dungeon[*row][*col] |= HIDDEN;
+ }
+ rm->doors[dir/2].door_row = *row;
+ rm->doors[dir/2].door_col = *col;
+}
+
+draw_simple_passage(row1, col1, row2, col2, dir)
+short row1, col1, row2, col2, dir;
+{
+ short i, middle, t;
+
+ if ((dir == LEFT) || (dir == RIGHT)) {
+ if (col1 > col2) {
+ swap(row1, row2);
+ swap(col1, col2);
+ }
+ middle = get_rand(col1+1, col2-1);
+ for (i = col1+1; i != middle; i++) {
+ dungeon[row1][i] = TUNNEL;
+ }
+ for (i = row1; i != row2; i += (row1 > row2) ? -1 : 1) {
+ dungeon[i][middle] = TUNNEL;
+ }
+ for (i = middle; i != col2; i++) {
+ dungeon[row2][i] = TUNNEL;
+ }
+ } else {
+ if (row1 > row2) {
+ swap(row1, row2);
+ swap(col1, col2);
+ }
+ middle = get_rand(row1+1, row2-1);
+ for (i = row1+1; i != middle; i++) {
+ dungeon[i][col1] = TUNNEL;
+ }
+ for (i = col1; i != col2; i += (col1 > col2) ? -1 : 1) {
+ dungeon[middle][i] = TUNNEL;
+ }
+ for (i = middle; i != row2; i++) {
+ dungeon[i][col2] = TUNNEL;
+ }
+ }
+ if (rand_percent(HIDE_PERCENT)) {
+ hide_boxed_passage(row1, col1, row2, col2, 1);
+ }
+}
+
+same_row(room1, room2)
+{
+ return((room1 / 3) == (room2 / 3));
+}
+
+same_col(room1, room2)
+{
+ return((room1 % 3) == (room2 % 3));
+}
+
+add_mazes()
+{
+ short i, j;
+ short start;
+ short maze_percent;
+
+ if (cur_level > 1) {
+ start = get_rand(0, (MAXROOMS-1));
+ maze_percent = (cur_level * 5) / 4;
+
+ if (cur_level > 15) {
+ maze_percent += cur_level;
+ }
+ for (i = 0; i < MAXROOMS; i++) {
+ j = ((start + i) % MAXROOMS);
+ if (rooms[j].is_room & R_NOTHING) {
+ if (rand_percent(maze_percent)) {
+ rooms[j].is_room = R_MAZE;
+ make_maze(get_rand(rooms[j].top_row+1, rooms[j].bottom_row-1),
+ get_rand(rooms[j].left_col+1, rooms[j].right_col-1),
+ rooms[j].top_row, rooms[j].bottom_row,
+ rooms[j].left_col, rooms[j].right_col);
+ hide_boxed_passage(rooms[j].top_row, rooms[j].left_col,
+ rooms[j].bottom_row, rooms[j].right_col,
+ get_rand(0, 2));
+ }
+ }
+ }
+ }
+}
+
+fill_out_level()
+{
+ short i, rn;
+
+ mix_random_rooms();
+
+ r_de = NO_ROOM;
+
+ for (i = 0; i < MAXROOMS; i++) {
+ rn = random_rooms[i];
+ if ((rooms[rn].is_room & R_NOTHING) ||
+ ((rooms[rn].is_room & R_CROSS) && coin_toss())) {
+ fill_it(rn, 1);
+ }
+ }
+ if (r_de != NO_ROOM) {
+ fill_it(r_de, 0);
+ }
+}
+
+fill_it(rn, do_rec_de)
+int rn;
+boolean do_rec_de;
+{
+ short i, tunnel_dir, door_dir, drow, dcol;
+ short target_room, rooms_found = 0;
+ short srow, scol, t;
+ static short offsets[4] = {-1, 1, 3, -3};
+ boolean did_this = 0;
+
+ for (i = 0; i < 10; i++) {
+ srow = get_rand(0, 3);
+ scol = get_rand(0, 3);
+ t = offsets[srow];
+ offsets[srow] = offsets[scol];
+ offsets[scol] = t;
+ }
+ for (i = 0; i < 4; i++) {
+
+ target_room = rn + offsets[i];
+
+ if (((target_room < 0) || (target_room >= MAXROOMS)) ||
+ (!(same_row(rn,target_room) || same_col(rn,target_room))) ||
+ (!(rooms[target_room].is_room & (R_ROOM | R_MAZE)))) {
+ continue;
+ }
+ if (same_row(rn, target_room)) {
+ tunnel_dir = (rooms[rn].left_col < rooms[target_room].left_col) ?
+ RIGHT : LEFT;
+ } else {
+ tunnel_dir = (rooms[rn].top_row < rooms[target_room].top_row) ?
+ DOWN : UPWARD;
+ }
+ door_dir = ((tunnel_dir + 4) % DIRS);
+ if (rooms[target_room].doors[door_dir/2].oth_room != NO_ROOM) {
+ continue;
+ }
+ if (((!do_rec_de) || did_this) ||
+ (!mask_room(rn, &srow, &scol, TUNNEL))) {
+ srow = (rooms[rn].top_row + rooms[rn].bottom_row) / 2;
+ scol = (rooms[rn].left_col + rooms[rn].right_col) / 2;
+ }
+ put_door(&rooms[target_room], door_dir, &drow, &dcol);
+ rooms_found++;
+ draw_simple_passage(srow, scol, drow, dcol, tunnel_dir);
+ rooms[rn].is_room = R_DEADEND;
+ dungeon[srow][scol] = TUNNEL;
+
+ if ((i < 3) && (!did_this)) {
+ did_this = 1;
+ if (coin_toss()) {
+ continue;
+ }
+ }
+ if ((rooms_found < 2) && do_rec_de) {
+ recursive_deadend(rn, offsets, srow, scol);
+ }
+ break;
+ }
+}
+
+recursive_deadend(rn, offsets, srow, scol)
+short rn;
+short *offsets;
+short srow, scol;
+{
+ short i, de;
+ short drow, dcol, tunnel_dir;
+
+ rooms[rn].is_room = R_DEADEND;
+ dungeon[srow][scol] = TUNNEL;
+
+ for (i = 0; i < 4; i++) {
+ de = rn + offsets[i];
+ if (((de < 0) || (de >= MAXROOMS)) ||
+ (!(same_row(rn, de) || same_col(rn, de)))) {
+ continue;
+ }
+ if (!(rooms[de].is_room & R_NOTHING)) {
+ continue;
+ }
+ drow = (rooms[de].top_row + rooms[de].bottom_row) / 2;
+ dcol = (rooms[de].left_col + rooms[de].right_col) / 2;
+ if (same_row(rn, de)) {
+ tunnel_dir = (rooms[rn].left_col < rooms[de].left_col) ?
+ RIGHT : LEFT;
+ } else {
+ tunnel_dir = (rooms[rn].top_row < rooms[de].top_row) ?
+ DOWN : UPWARD;
+ }
+ draw_simple_passage(srow, scol, drow, dcol, tunnel_dir);
+ r_de = de;
+ recursive_deadend(de, offsets, drow, dcol);
+ }
+}
+
+boolean
+mask_room(rn, row, col, mask)
+short rn;
+short *row, *col;
+unsigned short mask;
+{
+ short i, j;
+
+ for (i = rooms[rn].top_row; i <= rooms[rn].bottom_row; i++) {
+ for (j = rooms[rn].left_col; j <= rooms[rn].right_col; j++) {
+ if (dungeon[i][j] & mask) {
+ *row = i;
+ *col = j;
+ return(1);
+ }
+ }
+ }
+ return(0);
+}
+
+make_maze(r, c, tr, br, lc, rc)
+short r, c, tr, br, lc, rc;
+{
+ char dirs[4];
+ short i, t;
+
+ dirs[0] = UPWARD;
+ dirs[1] = DOWN;
+ dirs[2] = LEFT;
+ dirs[3] = RIGHT;
+
+ dungeon[r][c] = TUNNEL;
+
+ if (rand_percent(20)) {
+ for (i = 0; i < 10; i++) {
+ short t1, t2;
+
+ t1 = get_rand(0, 3);
+ t2 = get_rand(0, 3);
+
+ swap(dirs[t1], dirs[t2]);
+ }
+ }
+ for (i = 0; i < 4; i++) {
+ switch(dirs[i]) {
+ case UPWARD:
+ if (((r-1) >= tr) &&
+ (dungeon[r-1][c] != TUNNEL) &&
+ (dungeon[r-1][c-1] != TUNNEL) &&
+ (dungeon[r-1][c+1] != TUNNEL) &&
+ (dungeon[r-2][c] != TUNNEL)) {
+ make_maze((r-1), c, tr, br, lc, rc);
+ }
+ break;
+ case DOWN:
+ if (((r+1) <= br) &&
+ (dungeon[r+1][c] != TUNNEL) &&
+ (dungeon[r+1][c-1] != TUNNEL) &&
+ (dungeon[r+1][c+1] != TUNNEL) &&
+ (dungeon[r+2][c] != TUNNEL)) {
+ make_maze((r+1), c, tr, br, lc, rc);
+ }
+ break;
+ case LEFT:
+ if (((c-1) >= lc) &&
+ (dungeon[r][c-1] != TUNNEL) &&
+ (dungeon[r-1][c-1] != TUNNEL) &&
+ (dungeon[r+1][c-1] != TUNNEL) &&
+ (dungeon[r][c-2] != TUNNEL)) {
+ make_maze(r, (c-1), tr, br, lc, rc);
+ }
+ break;
+ case RIGHT:
+ if (((c+1) <= rc) &&
+ (dungeon[r][c+1] != TUNNEL) &&
+ (dungeon[r-1][c+1] != TUNNEL) &&
+ (dungeon[r+1][c+1] != TUNNEL) &&
+ (dungeon[r][c+2] != TUNNEL)) {
+ make_maze(r, (c+1), tr, br, lc, rc);
+ }
+ break;
+ }
+ }
+}
+
+hide_boxed_passage(row1, col1, row2, col2, n)
+short row1, col1, row2, col2, n;
+{
+ short i, j, t;
+ short row, col, row_cut, col_cut;
+ short h, w;
+
+ if (cur_level > 2) {
+ if (row1 > row2) {
+ swap(row1, row2);
+ }
+ if (col1 > col2) {
+ swap(col1, col2);
+ }
+ h = row2 - row1;
+ w = col2 - col1;
+
+ if ((w >= 5) || (h >= 5)) {
+ row_cut = ((h >= 2) ? 1 : 0);
+ col_cut = ((w >= 2) ? 1 : 0);
+
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < 10; j++) {
+ row = get_rand(row1 + row_cut, row2 - row_cut);
+ col = get_rand(col1 + col_cut, col2 - col_cut);
+ if (dungeon[row][col] == TUNNEL) {
+ dungeon[row][col] |= HIDDEN;
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+put_player(nr)
+short nr; /* try not to put in this room */
+{
+ short rn = nr, misses;
+ short row, col;
+
+ for (misses = 0; ((misses < 2) && (rn == nr)); misses++) {
+ gr_row_col(&row, &col, (FLOOR | TUNNEL | OBJECT | STAIRS));
+ rn = get_room_number(row, col);
+ }
+ rogue.row = row;
+ rogue.col = col;
+
+ if (dungeon[rogue.row][rogue.col] & TUNNEL) {
+ cur_room = PASSAGE;
+ } else {
+ cur_room = rn;
+ }
+ if (cur_room != PASSAGE) {
+ light_up_room(cur_room);
+ } else {
+ light_passage(rogue.row, rogue.col);
+ }
+ rn = get_room_number(rogue.row, rogue.col);
+ wake_room(rn, 1, rogue.row, rogue.col);
+ if (new_level_message) {
+ message(new_level_message, 0);
+ new_level_message = 0;
+ }
+ mvaddch(rogue.row, rogue.col, rogue.fchar);
+}
+
+drop_check()
+{
+ if (wizard) {
+ return(1);
+ }
+ if (dungeon[rogue.row][rogue.col] & STAIRS) {
+ if (levitate) {
+ message("you're floating in the air!", 0);
+ return(0);
+ }
+ return(1);
+ }
+ message("I see no way down", 0);
+ return(0);
+}
+
+check_up()
+{
+ if (!wizard) {
+ if (!(dungeon[rogue.row][rogue.col] & STAIRS)) {
+ message("I see no way up", 0);
+ return(0);
+ }
+ if (!has_amulet()) {
+ message("your way is magically blocked", 0);
+ return(0);
+ }
+ }
+ new_level_message = "you feel a wrenching sensation in your gut";
+ if (cur_level == 1) {
+ win();
+ } else {
+ cur_level -= 2;
+ return(1);
+ }
+ return(0);
+}
+
+add_exp(e, promotion)
+int e;
+boolean promotion;
+{
+ char mbuf[40];
+ short new_exp;
+ short i, hp;
+
+ rogue.exp_points += e;
+
+ if (rogue.exp_points >= level_points[rogue.exp-1]) {
+ new_exp = get_exp_level(rogue.exp_points);
+ if (rogue.exp_points > MAX_EXP) {
+ rogue.exp_points = MAX_EXP + 1;
+ }
+ for (i = rogue.exp+1; i <= new_exp; i++) {
+ sprintf(mbuf, "welcome to level %d", i);
+ message(mbuf, 0);
+ if (promotion) {
+ hp = hp_raise();
+ rogue.hp_current += hp;
+ rogue.hp_max += hp;
+ }
+ rogue.exp = i;
+ print_stats(STAT_HP | STAT_EXP);
+ }
+ } else {
+ print_stats(STAT_EXP);
+ }
+}
+
+get_exp_level(e)
+long e;
+{
+ short i;
+
+ for (i = 0; i < (MAX_EXP_LEVEL - 1); i++) {
+ if (level_points[i] > e) {
+ break;
+ }
+ }
+ return(i+1);
+}
+
+hp_raise()
+{
+ int hp;
+
+ hp = (wizard ? 10 : get_rand(3, 10));
+ return(hp);
+}
+
+show_average_hp()
+{
+ char mbuf[80];
+ float real_average;
+ float effective_average;
+
+ if (rogue.exp == 1) {
+ real_average = effective_average = 0.00;
+ } else {
+ real_average = (float)
+ ((rogue.hp_max - extra_hp - INIT_HP) + less_hp) / (rogue.exp - 1);
+ effective_average = (float) (rogue.hp_max - INIT_HP) / (rogue.exp - 1);
+
+ }
+ sprintf(mbuf, "R-Hp: %.2f, E-Hp: %.2f (!: %d, V: %d)", real_average,
+ effective_average, extra_hp, less_hp);
+ message(mbuf, 0);
+}
+
+mix_random_rooms()
+{
+ short i, t;
+ short x, y;
+
+ for (i = 0; i < (3 * MAXROOMS); i++) {
+ do {
+ x = get_rand(0, (MAXROOMS-1));
+ y = get_rand(0, (MAXROOMS-1));
+ } while (x == y);
+ swap(random_rooms[x], random_rooms[y]);
+ }
+}
diff --git a/rogue/machdep.c b/rogue/machdep.c
new file mode 100644
index 00000000..149c5160
--- /dev/null
+++ b/rogue/machdep.c
@@ -0,0 +1,681 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)machdep.c 5.7 (Berkeley) 2/28/91";
+#endif /* not lint */
+
+/*
+ * machdep.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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.
+ *
+ */
+
+/* Included in this file are all system dependent routines. Extensive use
+ * of #ifdef's will be used to compile the appropriate code on each system:
+ *
+ * UNIX: all UNIX systems.
+ * UNIX_BSD4_2: UNIX BSD 4.2 and later, UTEK, (4.1 BSD too?)
+ * UNIX_SYSV: UNIX system V
+ * UNIX_V7: UNIX version 7
+ *
+ * All UNIX code should be included between the single "#ifdef UNIX" at the
+ * top of this file, and the "#endif" at the bottom.
+ *
+ * To change a routine to include a new UNIX system, simply #ifdef the
+ * existing routine, as in the following example:
+ *
+ * To make a routine compatible with UNIX system 5, change the first
+ * function to the second:
+ *
+ * md_function()
+ * {
+ * code;
+ * }
+ *
+ * md_function()
+ * {
+ * #ifdef UNIX_SYSV
+ * sys5code;
+ * #else
+ * code;
+ * #endif
+ * }
+ *
+ * Appropriate variations of this are of course acceptible.
+ * The use of "#elseif" is discouraged because of non-portability.
+ * If the correct #define doesn't exist, "UNIX_SYSV" in this case, make it up
+ * and insert it in the list at the top of the file. Alter the CFLAGS
+ * in you Makefile appropriately.
+ *
+ */
+
+#ifdef UNIX
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <pwd.h>
+
+#ifdef UNIX_BSD4_2
+#include <sys/time.h>
+#include <sgtty.h>
+#endif
+
+#ifdef UNIX_SYSV
+#include <time.h>
+#include <termio.h>
+#endif
+
+#include <signal.h>
+#include "rogue.h"
+#include "pathnames.h"
+
+/* md_slurp:
+ *
+ * This routine throws away all keyboard input that has not
+ * yet been read. It is used to get rid of input that the user may have
+ * typed-ahead.
+ *
+ * This function is not necessary, so it may be stubbed. The might cause
+ * message-line output to flash by because the game has continued to read
+ * input without waiting for the user to read the message. Not such a
+ * big deal.
+ */
+
+md_slurp()
+{
+ (void)fpurge(stdin);
+}
+
+/* md_control_keyboard():
+ *
+ * This routine is much like md_cbreak_no_echo_nonl() below. It sets up the
+ * keyboard for appropriate input. Specifically, it prevents the tty driver
+ * from stealing characters. For example, ^Y is needed as a command
+ * character, but the tty driver intercepts it for another purpose. Any
+ * such behavior should be stopped. This routine could be avoided if
+ * we used RAW mode instead of CBREAK. But RAW mode does not allow the
+ * generation of keyboard signals, which the program uses.
+ *
+ * The parameter 'mode' when true, indicates that the keyboard should
+ * be set up to play rogue. When false, it should be restored if
+ * necessary.
+ *
+ * This routine is not strictly necessary and may be stubbed. This may
+ * cause certain command characters to be unavailable.
+ */
+
+md_control_keybord(mode)
+boolean mode;
+{
+ static boolean called_before = 0;
+#ifdef UNIX_BSD4_2
+ static struct ltchars ltc_orig;
+ static struct tchars tc_orig;
+ struct ltchars ltc_temp;
+ struct tchars tc_temp;
+#endif
+#ifdef UNIX_SYSV
+ static struct termio _oldtty;
+ struct termio _tty;
+#endif
+
+ if (!called_before) {
+ called_before = 1;
+#ifdef UNIX_BSD4_2
+ ioctl(0, TIOCGETC, &tc_orig);
+ ioctl(0, TIOCGLTC, &ltc_orig);
+#endif
+#ifdef UNIX_SYSV
+ ioctl(0, TCGETA, &_oldtty);
+#endif
+ }
+#ifdef UNIX_BSD4_2
+ ltc_temp = ltc_orig;
+ tc_temp = tc_orig;
+#endif
+#ifdef UNIX_SYSV
+ _tty = _oldtty;
+#endif
+
+ if (!mode) {
+#ifdef UNIX_BSD4_2
+ ltc_temp.t_suspc = ltc_temp.t_dsuspc = -1;
+ ltc_temp.t_rprntc = ltc_temp.t_flushc = -1;
+ ltc_temp.t_werasc = ltc_temp.t_lnextc = -1;
+ tc_temp.t_startc = tc_temp.t_stopc = -1;
+#endif
+#ifdef UNIX_SYSV
+ _tty.c_cc[VSWTCH] = CNSWTCH;
+#endif
+ }
+#ifdef UNIX_BSD4_2
+ ioctl(0, TIOCSETC, &tc_temp);
+ ioctl(0, TIOCSLTC, &ltc_temp);
+#endif
+#ifdef UNIX_SYSV
+ ioctl(0, TCSETA, &_tty);
+#endif
+}
+
+/* md_heed_signals():
+ *
+ * This routine tells the program to call particular routines when
+ * certain interrupts/events occur:
+ *
+ * SIGINT: call onintr() to interrupt fight with monster or long rest.
+ * SIGQUIT: call byebye() to check for game termination.
+ * SIGHUP: call error_save() to save game when terminal hangs up.
+ *
+ * On VMS, SIGINT and SIGQUIT correspond to ^C and ^Y.
+ *
+ * This routine is not strictly necessary and can be stubbed. This will
+ * mean that the game cannot be interrupted properly with keyboard
+ * input, this is not usually critical.
+ */
+
+md_heed_signals()
+{
+ signal(SIGINT, onintr);
+ signal(SIGQUIT, byebye);
+ signal(SIGHUP, error_save);
+}
+
+/* md_ignore_signals():
+ *
+ * This routine tells the program to completely ignore the events mentioned
+ * in md_heed_signals() above. The event handlers will later be turned on
+ * by a future call to md_heed_signals(), so md_heed_signals() and
+ * md_ignore_signals() need to work together.
+ *
+ * This function should be implemented or the user risks interrupting
+ * critical sections of code, which could cause score file, or saved-game
+ * file, corruption.
+ */
+
+md_ignore_signals()
+{
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+}
+
+/* md_get_file_id():
+ *
+ * This function returns an integer that uniquely identifies the specified
+ * file. It need not check for the file's existence. In UNIX, the inode
+ * number is used.
+ *
+ * This function is used to identify saved-game files.
+ */
+
+int
+md_get_file_id(fname)
+char *fname;
+{
+ struct stat sbuf;
+
+ if (stat(fname, &sbuf)) {
+ return(-1);
+ }
+ return((int) sbuf.st_ino);
+}
+
+/* md_link_count():
+ *
+ * This routine returns the number of hard links to the specified file.
+ *
+ * This function is not strictly necessary. On systems without hard links
+ * this routine can be stubbed by just returning 1.
+ */
+
+int
+md_link_count(fname)
+char *fname;
+{
+ struct stat sbuf;
+
+ stat(fname, &sbuf);
+ return((int) sbuf.st_nlink);
+}
+
+/* md_gct(): (Get Current Time)
+ *
+ * This function returns the current year, month(1-12), day(1-31), hour(0-23),
+ * minute(0-59), and second(0-59). This is used for identifying the time
+ * at which a game is saved.
+ *
+ * This function is not strictly necessary. It can be stubbed by returning
+ * zeros instead of the correct year, month, etc. If your operating
+ * system doesn't provide all of the time units requested here, then you
+ * can provide only those that it does, and return zeros for the others.
+ * If you cannot provide good time values, then users may be able to copy
+ * saved-game files and play them.
+ */
+
+md_gct(rt_buf)
+struct rogue_time *rt_buf;
+{
+ struct tm *t, *localtime();
+ long seconds;
+
+ time(&seconds);
+ t = localtime(&seconds);
+
+ rt_buf->year = t->tm_year;
+ rt_buf->month = t->tm_mon + 1;
+ rt_buf->day = t->tm_mday;
+ rt_buf->hour = t->tm_hour;
+ rt_buf->minute = t->tm_min;
+ rt_buf->second = t->tm_sec;
+}
+
+/* md_gfmt: (Get File Modification Time)
+ *
+ * This routine returns a file's date of last modification in the same format
+ * as md_gct() above.
+ *
+ * This function is not strictly necessary. It is used to see if saved-game
+ * files have been modified since they were saved. If you have stubbed the
+ * routine md_gct() above by returning constant values, then you may do
+ * exactly the same here.
+ * Or if md_gct() is implemented correctly, but your system does not provide
+ * file modification dates, you may return some date far in the past so
+ * that the program will never know that a saved-game file being modified.
+ * You may also do this if you wish to be able to restore games from
+ * saved-games that have been modified.
+ */
+
+md_gfmt(fname, rt_buf)
+char *fname;
+struct rogue_time *rt_buf;
+{
+ struct stat sbuf;
+ long seconds;
+ struct tm *t;
+
+ stat(fname, &sbuf);
+ seconds = (long) sbuf.st_mtime;
+ t = localtime(&seconds);
+
+ rt_buf->year = t->tm_year;
+ rt_buf->month = t->tm_mon + 1;
+ rt_buf->day = t->tm_mday;
+ rt_buf->hour = t->tm_hour;
+ rt_buf->minute = t->tm_min;
+ rt_buf->second = t->tm_sec;
+}
+
+/* md_df: (Delete File)
+ *
+ * This function deletes the specified file, and returns true (1) if the
+ * operation was successful. This is used to delete saved-game files
+ * after restoring games from them.
+ *
+ * Again, this function is not strictly necessary, and can be stubbed
+ * by simply returning 1. In this case, saved-game files will not be
+ * deleted and can be replayed.
+ */
+
+boolean
+md_df(fname)
+char *fname;
+{
+ if (unlink(fname)) {
+ return(0);
+ }
+ return(1);
+}
+
+/* md_gln: (Get login name)
+ *
+ * This routine returns the login name of the user. This string is
+ * used mainly for identifying users in score files.
+ *
+ * A dummy string may be returned if you are unable to implement this
+ * function, but then the score file would only have one name in it.
+ */
+
+char *
+md_gln()
+{
+ struct passwd *p;
+
+ if (!(p = getpwuid(getuid())))
+ return((char *)NULL);
+ return(p->pw_name);
+}
+
+/* md_sleep:
+ *
+ * This routine causes the game to pause for the specified number of
+ * seconds.
+ *
+ * This routine is not particularly necessary at all. It is used for
+ * delaying execution, which is useful to this program at some times.
+ */
+
+md_sleep(nsecs)
+int nsecs;
+{
+ (void) sleep(nsecs);
+}
+
+/* md_getenv()
+ *
+ * This routine gets certain values from the user's environment. These
+ * values are strings, and each string is identified by a name. The names
+ * of the values needed, and their use, is as follows:
+ *
+ * TERMCAP
+ * The name of the users's termcap file, NOT the termcap entries
+ * themselves. This is used ONLY if the program is compiled with
+ * CURSES defined (-DCURSES). Even in this case, the program need
+ * not find a string for TERMCAP. If it does not, it will use the
+ * default termcap file as returned by md_gdtcf();
+ * TERM
+ * The name of the users's terminal. This is used ONLY if the program
+ * is compiled with CURSES defined (-DCURSES). In this case, the string
+ * value for TERM must be found, or the routines in curses.c cannot
+ * function, and the program will quit.
+ * ROGUEOPTS
+ * A string containing the various game options. This need not be
+ * defined.
+ * HOME
+ * The user's home directory. This is only used when the user specifies
+ * '~' as the first character of a saved-game file. This string need
+ * not be defined.
+ * SHELL
+ * The user's favorite shell. If not found, "/bin/sh" is assumed.
+ *
+ * If your system does not provide a means of searching for these values,
+ * you will have to do it yourself. None of the values above really need
+ * to be defined except TERM when the program is compiled with CURSES
+ * defined. In this case, as a bare minimum, you can check the 'name'
+ * parameter, and if it is "TERM" find the terminal name and return that,
+ * else return zero. If the program is not compiled with CURSES, you can
+ * get by with simply always returning zero. Returning zero indicates
+ * that their is no defined value for the given string.
+ */
+
+char *
+md_getenv(name)
+char *name;
+{
+ char *value;
+ char *getenv();
+
+ value = getenv(name);
+
+ return(value);
+}
+
+/* md_malloc()
+ *
+ * This routine allocates, and returns a pointer to, the specified number
+ * of bytes. This routines absolutely MUST be implemented for your
+ * particular system or the program will not run at all. Return zero
+ * when no more memory can be allocated.
+ */
+
+char *
+md_malloc(n)
+int n;
+{
+ char *malloc();
+ char *t;
+
+ t = malloc(n);
+ return(t);
+}
+
+/* md_gseed() (Get Seed)
+ *
+ * This function returns a seed for the random number generator (RNG). This
+ * seed causes the RNG to begin generating numbers at some point in it's
+ * sequence. Without a random seed, the RNG will generate the same set
+ * of numbers, and every game will start out exactly the same way. A good
+ * number to use is the process id, given by getpid() on most UNIX systems.
+ *
+ * You need to find some single random integer, such as:
+ * process id.
+ * current time (minutes + seconds) returned from md_gct(), if implemented.
+ *
+ * It will not help to return "get_rand()" or "rand()" or the return value of
+ * any pseudo-RNG. If you don't have a random number, you can just return 1,
+ * but this means your games will ALWAYS start the same way, and will play
+ * exactly the same way given the same input.
+ */
+
+md_gseed()
+{
+ return(getpid());
+}
+
+/* md_exit():
+ *
+ * This function causes the program to discontinue execution and exit.
+ * This function must be implemented or the program will continue to
+ * hang when it should quit.
+ */
+
+md_exit(status)
+int status;
+{
+ exit(status);
+}
+
+/* md_lock():
+ *
+ * This function is intended to give the user exclusive access to the score
+ * file. It does so by "creat"ing a lock file, which can only be created
+ * if it does not already exist. The file is deleted when score file
+ * processing is finished. The lock file should be located in the same
+ * directory as the score file. These full path names should be defined for
+ * any particular site in rogue.h. The constants _PATH_SCOREFILE and
+ * _PATH_LOCKFILE define these file names.
+ *
+ * When the parameter 'l' is non-zero (true), a lock is requested. Otherwise
+ * the lock is released by removing the lock file.
+ */
+
+md_lock(l)
+boolean l;
+{
+ short tries;
+ char *lock_file = _PATH_LOCKFILE;
+
+ if (l) {
+ for (tries = 0; tries < 5; tries++) {
+ if (md_get_file_id(lock_file) == -1) {
+ if (creat(lock_file, 0444) != -1) {
+ break;
+ } else {
+ message("cannot lock score file", 0);
+ }
+ } else {
+ message("waiting to lock score file", 0);
+ }
+ sleep(2);
+ }
+ } else {
+ (void) unlink(lock_file);
+ }
+}
+
+/* md_shell():
+ *
+ * This function spawns a shell for the user to use. When this shell is
+ * terminated, the game continues. Since this program may often be run
+ * setuid to gain access to privileged files, care is taken that the shell
+ * is run with the user's REAL user id, and not the effective user id.
+ * The effective user id is restored after the shell completes.
+ */
+
+md_shell(shell)
+char *shell;
+{
+ long w[2];
+
+ if (!fork()) {
+ int uid;
+
+ uid = getuid();
+ setuid(uid);
+ execl(shell, shell, 0);
+ }
+ wait(w);
+}
+
+/* If you have a viable curses/termlib library, then use it and don't bother
+ * implementing the routines below. And don't compile with -DCURSES.
+ */
+
+#ifdef CURSES
+
+/* md_cbreak_no_echo_nonl:
+ *
+ * This routine sets up some terminal characteristics. The tty-driver
+ * must be told to:
+ * 1.) Not echo input.
+ * 2.) Transmit input characters immediately upon typing. (cbreak mode)
+ * 3.) Move the cursor down one line, without changing column, and
+ * without generating a carriage-return, when it
+ * sees a line-feed. This is only necessary if line-feed is ever
+ * used in the termcap 'do' (cursor down) entry, in which case,
+ * your system should must have a way of accomplishing this.
+ *
+ * When the parameter 'on' is true, the terminal is set up as specified
+ * above. When this parameter is false, the terminal is restored to the
+ * original state.
+ *
+ * Raw mode should not to be used. Keyboard signals/events/interrupts should
+ * be sent, although they are not strictly necessary. See notes in
+ * md_heed_signals().
+ *
+ * This function must be implemented for rogue to run properly if the
+ * program is compiled with CURSES defined to use the enclosed curses
+ * emulation package. If you are not using this, then this routine is
+ * totally unnecessary.
+ *
+ * Notice that information is saved between calls. This is used to
+ * restore the terminal to an initial saved state.
+ *
+ */
+
+md_cbreak_no_echo_nonl(on)
+boolean on;
+{
+#ifdef UNIX_BSD4_2
+ static struct sgttyb tty_buf;
+ static int tsave_flags;
+
+ if (on) {
+ ioctl(0, TIOCGETP, &tty_buf);
+ tsave_flags = tty_buf.sg_flags;
+ tty_buf.sg_flags |= CBREAK;
+ tty_buf.sg_flags &= ~(ECHO | CRMOD); /* CRMOD: see note 3 above */
+ ioctl(0, TIOCSETP, &tty_buf);
+ } else {
+ tty_buf.sg_flags = tsave_flags;
+ ioctl(0, TIOCSETP, &tty_buf);
+ }
+#endif
+#ifdef UNIX_SYSV
+ struct termio tty_buf;
+ static struct termio tty_save;
+
+ if (on) {
+ ioctl(0, TCGETA, &tty_buf);
+ tty_save = tty_buf;
+ tty_buf.c_lflag &= ~(ICANON | ECHO);
+ tty_buf.c_oflag &= ~ONLCR;
+ tty_buf.c_cc[4] = 1; /* MIN */
+ tty_buf.c_cc[5] = 2; /* TIME */
+ ioctl(0, TCSETAF, &tty_buf);
+ } else {
+ ioctl(0, TCSETAF, &tty_save);
+ }
+#endif
+}
+
+/* md_gdtcf(): (Get Default Termcap File)
+ *
+ * This function is called ONLY when the program is compiled with CURSES
+ * defined. If you use your system's curses/termlib library, this function
+ * won't be called. On most UNIX systems, "/etc/termcap" suffices.
+ *
+ * If their is no such termcap file, then return 0, but in that case, you
+ * must have a TERMCAP file returned from md_getenv("TERMCAP"). The latter
+ * will override the value returned from md_gdtcf(). If the program is
+ * compiled with CURSES defined, and md_gdtcf() returns 0, and
+ * md_getenv("TERMCAP") returns 0, the program will have no terminal
+ * capability information and will quit.
+ */
+
+char *
+md_gdtcf()
+{
+ return("/etc/termcap");
+}
+
+/* md_tstp():
+ *
+ * This function puts the game to sleep and returns to the shell. This
+ * only applies to UNIX 4.2 and 4.3. For other systems, the routine should
+ * be provided as a do-nothing routine. md_tstp() will only be referenced
+ * in the code when compiled with CURSES defined.
+ *
+ */
+
+md_tstp()
+{
+#ifdef UNIX_BSD4_2
+ kill(0, SIGTSTP);
+#endif
+}
+
+#endif
+
+#endif
diff --git a/rogue/main.c b/rogue/main.c
new file mode 100644
index 00000000..e27084e4
--- /dev/null
+++ b/rogue/main.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1988 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * main.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.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_mons();
+ put_player(party_room);
+ print_stats(STAT_ALL);
+PL:
+ play_level();
+ free_stuff(&level_objects);
+ free_stuff(&level_monsters);
+ }
+}
diff --git a/rogue/message.c b/rogue/message.c
new file mode 100644
index 00000000..5761c8eb
--- /dev/null
+++ b/rogue/message.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)message.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * message.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 <stdio.h>
+#include "rogue.h"
+
+char msgs[NMESSAGES][DCOLS] = {"", "", "", "", ""};
+short msg_col = 0, imsg = -1;
+boolean msg_cleared = 1, rmsg = 0;
+char hunger_str[8] = "";
+char *more = "-more-";
+
+extern boolean cant_int, did_int, interrupted, save_is_interactive;
+extern short add_strength;
+extern short cur_level;
+
+message(msg, intrpt)
+char *msg;
+boolean intrpt;
+{
+ cant_int = 1;
+
+ if (!save_is_interactive) {
+ return;
+ }
+ if (intrpt) {
+ interrupted = 1;
+ md_slurp();
+ }
+
+ if (!msg_cleared) {
+ mvaddstr(MIN_ROW-1, msg_col, more);
+ refresh();
+ wait_for_ack();
+ check_message();
+ }
+ if (!rmsg) {
+ imsg = (imsg + 1) % NMESSAGES;
+ (void) strcpy(msgs[imsg], msg);
+ }
+ mvaddstr(MIN_ROW-1, 0, msg);
+ addch(' ');
+ refresh();
+ msg_cleared = 0;
+ msg_col = strlen(msg);
+
+ cant_int = 0;
+
+ if (did_int) {
+ did_int = 0;
+ onintr();
+ }
+}
+
+remessage(c)
+short c;
+{
+ if (imsg != -1) {
+ check_message();
+ rmsg = 1;
+ while (c > imsg) {
+ c -= NMESSAGES;
+ }
+ message(msgs[((imsg - c) % NMESSAGES)], 0);
+ rmsg = 0;
+ move(rogue.row, rogue.col);
+ refresh();
+ }
+}
+
+check_message()
+{
+ if (msg_cleared) {
+ return;
+ }
+ move(MIN_ROW-1, 0);
+ clrtoeol();
+ refresh();
+ msg_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);
+ (void) 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);
+}
+
+rgetchar()
+{
+ register ch;
+
+ for(;;) {
+ ch = getchar();
+
+ switch(ch) {
+ case '\022':
+ wrefresh(curscr);
+ break;
+#ifdef UNIX_BSD4_2
+ case '\032':
+ printf(CL);
+ fflush(stdout);
+ tstp();
+ break;
+#endif
+ case '&':
+ 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", cur_level);
+ mvaddstr(row, 7, buf);
+ pad(buf, 2);
+ }
+ if (stat_mask & STAT_GOLD) {
+ if (label) {
+ mvaddstr(row, 10, "Gold: ");
+ }
+ if (rogue.gold > MAX_GOLD) {
+ rogue.gold = MAX_GOLD;
+ }
+ sprintf(buf, "%ld", 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.str_max > MAX_STRENGTH) {
+ rogue.str_current -= (rogue.str_max - MAX_STRENGTH);
+ rogue.str_max = MAX_STRENGTH;
+ }
+ sprintf(buf, "%d(%d)", (rogue.str_current + add_strength),
+ rogue.str_max);
+ mvaddstr(row, 41, buf);
+ pad(buf, 6);
+ }
+ if (stat_mask & STAT_ARMOR) {
+ if (label) {
+ mvaddstr(row, 48, "Arm: ");
+ }
+ if (rogue.armor && (rogue.armor->d_enchant > MAX_ARMOR)) {
+ rogue.armor->d_enchant = 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: ");
+ }
+ if (rogue.exp_points > MAX_EXP) {
+ rogue.exp_points = MAX_EXP;
+ }
+ if (rogue.exp > MAX_EXP_LEVEL) {
+ rogue.exp = MAX_EXP_LEVEL;
+ }
+ sprintf(buf, "%d/%ld", 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;
+ char buf[DCOLS+2];
+ boolean found_non_blank;
+
+ if ((fp = fopen("rogue.screen", "w")) != NULL) {
+ 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();
+ }
+}
+
+sound_bell()
+{
+ putchar(7);
+ fflush(stdout);
+}
+
+boolean
+is_digit(ch)
+short ch;
+{
+ return((ch >= '0') && (ch <= '9'));
+}
+
+r_index(str, ch, last)
+char *str;
+int ch;
+boolean last;
+{
+ int i = 0;
+
+ if (last) {
+ for (i = strlen(str) - 1; i >= 0; i--) {
+ if (str[i] == ch) {
+ return(i);
+ }
+ }
+ } else {
+ for (i = 0; str[i]; i++) {
+ if (str[i] == ch) {
+ return(i);
+ }
+ }
+ }
+ return(-1);
+}
diff --git a/rogue/monster.c b/rogue/monster.c
new file mode 100644
index 00000000..8cf39e25
--- /dev/null
+++ b/rogue/monster.c
@@ -0,0 +1,867 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)monster.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * monster.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.h"
+
+object level_monsters;
+boolean mon_disappeared;
+
+char *m_names[] = {
+ "aquator",
+ "bat",
+ "centaur",
+ "dragon",
+ "emu",
+ "venus fly-trap",
+ "griffin",
+ "hobgoblin",
+ "ice monster",
+ "jabberwock",
+ "kestrel",
+ "leprechaun",
+ "medusa",
+ "nymph",
+ "orc",
+ "phantom",
+ "quagga",
+ "rattlesnake",
+ "snake",
+ "troll",
+ "black unicorn",
+ "vampire",
+ "wraith",
+ "xeroc",
+ "yeti",
+ "zombie"
+};
+
+object mon_tab[MONSTERS] = {
+ {(ASLEEP|WAKENS|WANDERS|RUSTS),"0d0",25,'A',20,9,18,100,0,0,0,0,0},
+ {(ASLEEP|WANDERS|FLITS|FLIES),"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|DROPS_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 cur_level;
+extern short cur_room, party_room;
+extern short blind, halluc, haste_self;
+extern boolean detect_monster, see_invisible, r_see_invisible;
+extern short stealthy;
+
+put_mons()
+{
+ short i;
+ short n;
+ object *monster;
+ short row, col;
+
+ n = get_rand(4, 6);
+
+ for (i = 0; i < n; i++) {
+ monster = gr_monster((object *) 0, 0);
+ if ((monster->m_flags & WANDERS) && coin_toss()) {
+ wake_up(monster);
+ }
+ gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
+ put_m_at(row, col, monster);
+ }
+}
+
+object *
+gr_monster(monster, mn)
+register object *monster;
+register mn;
+{
+ if (!monster) {
+ monster = alloc_object();
+
+ for (;;) {
+ mn = get_rand(0, MONSTERS-1);
+ if ((cur_level >= mon_tab[mn].first_level) &&
+ (cur_level <= mon_tab[mn].last_level)) {
+ break;
+ }
+ }
+ }
+ *monster = mon_tab[mn];
+ if (monster->m_flags & IMITATES) {
+ monster->disguise = gr_obj_char();
+ }
+ if (cur_level > (AMULET_LEVEL + 2)) {
+ monster->m_flags |= HASTED;
+ }
+ monster->trow = NO_ROOM;
+ return(monster);
+}
+
+mv_mons()
+{
+ register object *monster, *next_monster;
+ boolean flew;
+
+ if (haste_self % 2) {
+ return;
+ }
+
+ monster = level_monsters.next_monster;
+
+ while (monster) {
+ next_monster = monster->next_monster;
+ mon_disappeared = 0;
+ if (monster->m_flags & HASTED) {
+ mv_1_monster(monster, rogue.row, rogue.col);
+ if (mon_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) && move_confused(monster)) {
+ goto NM;
+ }
+ flew = 0;
+ if ( (monster->m_flags & FLIES) &&
+ !(monster->m_flags & NAPPING) &&
+ !mon_can_go(monster, rogue.row, rogue.col)) {
+ flew = 1;
+ mv_1_monster(monster, rogue.row, rogue.col);
+ if (mon_disappeared) {
+ goto NM;
+ }
+ }
+ if (!(flew && mon_can_go(monster, rogue.row, rogue.col))) {
+ mv_1_monster(monster, rogue.row, rogue.col);
+ }
+NM: monster = next_monster;
+ }
+}
+
+party_monsters(rn, n)
+int rn, n;
+{
+ short i, j;
+ short row, col;
+ object *monster;
+ boolean found;
+
+ n += n;
+
+ for (i = 0; i < MONSTERS; i++) {
+ mon_tab[i].first_level -= (cur_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 = gr_monster((object *) 0, 0);
+ if (!(monster->m_flags & IMITATES)) {
+ monster->m_flags |= WAKENS;
+ }
+ put_m_at(row, col, monster);
+ }
+ }
+ for (i = 0; i < MONSTERS; i++) {
+ mon_tab[i].first_level += (cur_level % 3);
+ }
+}
+
+gmc_row_col(row, col)
+register row, col;
+{
+ register object *monster;
+
+ if (monster = object_at(&level_monsters, row, col)) {
+ 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);
+ } else {
+ return('&'); /* BUG if this ever happens */
+ }
+}
+
+gmc(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_1_monster(monster, row, col)
+register object *monster;
+short row, col;
+{
+ short i, n;
+ boolean tried[6];
+
+ 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) &&
+ (!mon_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 (mon_can_go(monster, rogue.row, rogue.col)) {
+ mon_hit(monster);
+ 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) &&
+ (!mon_sees(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 (mon_can_go(monster, row, col)) {
+ move_mon_to(monster, row, col);
+ return(1);
+ }
+ return(0);
+}
+
+move_mon_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, gmc(monster));
+ }
+ }
+ if ((dungeon[row][col] & DOOR) &&
+ (get_room_number(row, col) != cur_room) &&
+ (dungeon[mrow][mcol] == FLOOR) && !blind) {
+ mvaddch(mrow, mcol, ' ');
+ }
+ if (dungeon[row][col] & DOOR) {
+ dr_course(monster, ((dungeon[mrow][mcol] & TUNNEL) ? 1 : 0),
+ row, col);
+ } else {
+ monster->row = row;
+ monster->col = col;
+ }
+}
+
+mon_can_go(monster, row, col)
+register object *monster;
+register short row, col;
+{
+ object *obj;
+ 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 == SCROL) && (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 *
+mon_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(m_names[ch]);
+ }
+ ch = monster->m_char - 'A';
+ return(m_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);
+}
+
+wanderer()
+{
+ object *monster;
+ short row, col, i;
+ boolean found = 0;
+
+ for (i = 0; ((i < 15) && (!found)); i++) {
+ monster = gr_monster((object *) 0, 0);
+ if (!(monster->m_flags & (WAKENS | WANDERS))) {
+ free_object(monster);
+ } else {
+ found = 1;
+ }
+ }
+ if (found) {
+ found = 0;
+ wake_up(monster);
+ for (i = 0; ((i < 25) && (!found)); i++) {
+ gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
+ if (!rogue_can_see(row, col)) {
+ put_m_at(row, col, monster);
+ found = 1;
+ }
+ }
+ if (!found) {
+ 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;
+ 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 = gr_monster((object *) 0, 0);
+ put_m_at(row, col, monster);
+ mvaddch(row, col, gmc(monster));
+ if (monster->m_flags & (WANDERS | WAKENS)) {
+ wake_up(monster);
+ }
+ } else {
+ message("you hear a faint cry of anguish in the distance", 0);
+ }
+}
+
+put_m_at(row, col, monster)
+short row, col;
+object *monster;
+{
+ monster->row = row;
+ monster->col = col;
+ dungeon[row][col] |= MONSTER;
+ monster->trail_char = mvinch(row, col);
+ (void) 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].oth_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) == cur_room) &&
+ !(rooms[cur_room].is_room & R_MAZE)) ||
+ rogue_is_around(row, col));
+
+ return(retval);
+}
+
+move_confused(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 + ((monster->m_flags & FLIES) ? 20 : 0))) {
+ 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);
+}
+
+gr_obj_char()
+{
+ short r;
+ char *rs = "%!?]=/):*";
+
+ r = get_rand(0, 8);
+
+ 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()
+{
+ 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);
+ if (rogue_can_see(monster->row, monster->col)) {
+ mvaddch(monster->row, monster->col, monster->m_char);
+ }
+ monster = monster->next_monster;
+ }
+}
+
+boolean
+mon_sees(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') &&
+ mon_can_go(monster, rogue.row, rogue.col)) {
+ mv_1_monster(monster, rogue.row, rogue.col);
+ monster->m_flags |= ALREADY_MOVED;
+ }
+ monster = monster->next_monster;
+ }
+}
diff --git a/rogue/move.c b/rogue/move.c
new file mode 100644
index 00000000..d8da6022
--- /dev/null
+++ b/rogue/move.c
@@ -0,0 +1,647 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)move.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * move.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.h"
+
+short m_moves = 0;
+boolean jump = 0;
+char *you_can_move_again = "you can move again";
+
+extern short cur_room, halluc, blind, levitate;
+extern short cur_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, passgo;
+
+one_move_rogue(dirch, pickup)
+short dirch, pickup;
+{
+ short row, col;
+ object *obj;
+ char desc[DCOLS];
+ short n, status, d;
+
+ row = rogue.row;
+ col = rogue.col;
+
+ if (confused) {
+ dirch = gr_dir();
+ }
+ (void) is_direction(dirch, &d);
+ get_dir_rc(d, &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);
+ (void) reg_move();
+ }
+ return(MOVE_FAILED);
+ }
+ }
+ if (r_teleport) {
+ if (rand_percent(R_TELE_PERCENT)) {
+ tele();
+ return(STOPPED_ON_SOMETHING);
+ }
+ }
+ if (dungeon[row][col] & MONSTER) {
+ rogue_hit(object_at(&level_monsters, row, col), 0);
+ (void) reg_move();
+ return(MOVE_FAILED);
+ }
+ if (dungeon[row][col] & DOOR) {
+ if (cur_room == PASSAGE) {
+ cur_room = get_room_number(row, col);
+ light_up_room(cur_room);
+ wake_room(cur_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(cur_room, 0, rogue.row, rogue.col);
+ darken_room(cur_room);
+ cur_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_desc(obj, desc);
+ 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);
+ (void) strcpy(desc, "moved onto ");
+ get_desc(obj, desc+11);
+ goto NOT_IN_PACK;
+ }
+ n = strlen(desc);
+ desc[n] = '(';
+ desc[n+1] = obj->ichar;
+ desc[n+2] = ')';
+ desc[n+3] = 0;
+NOT_IN_PACK:
+ message(desc, 1);
+ (void) reg_move();
+ return(STOPPED_ON_SOMETHING);
+ }
+ if (dungeon[row][col] & (DOOR | STAIRS | TRAP)) {
+ if ((!levitate) && (dungeon[row][col] & TRAP)) {
+ trap_player(row, col);
+ }
+ (void) reg_move();
+ return(STOPPED_ON_SOMETHING);
+ }
+MVED: if (reg_move()) { /* fainted from hunger */
+ return(STOPPED_ON_SOMETHING);
+ }
+ return((confused ? STOPPED_ON_SOMETHING : MOVED));
+}
+
+multiple_move_rogue(dirch)
+short 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 = one_move_rogue((dirch + 96), 1)) == MOVE_FAILED) ||
+ (m == STOPPED_ON_SOMETHING) ||
+ interrupted) {
+ break;
+ }
+ } while (!next_to_something(row, col));
+ if ( (!interrupted) && passgo && (m == MOVE_FAILED) &&
+ (dungeon[rogue.row][rogue.col] & TUNNEL)) {
+ turn_passage(dirch + 96, 0);
+ }
+ break;
+ case 'H':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'B':
+ case 'Y':
+ case 'U':
+ case 'N':
+ while ((!interrupted) && (one_move_rogue((dirch + 32), 1) == MOVED)) ;
+
+ if ( (!interrupted) && passgo &&
+ (dungeon[rogue.row][rogue.col] & TUNNEL)) {
+ turn_passage(dirch + 32, 1);
+ }
+ 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, d;
+ boolean first_miss = 1;
+
+ while (!is_direction(ch = rgetchar(), &d)) {
+ sound_bell();
+ if (first_miss) {
+ message("direction? ", 0);
+ first_miss = 0;
+ }
+ }
+ check_message();
+ if (ch != CANCEL) {
+ (void) one_move_rogue(ch, 0);
+ }
+}
+
+boolean
+is_direction(c, d)
+short c;
+short *d;
+{
+ switch(c) {
+ case 'h':
+ *d = LEFT;
+ break;
+ case 'j':
+ *d = DOWN;
+ break;
+ case 'k':
+ *d = UPWARD;
+ break;
+ case 'l':
+ *d = RIGHT;
+ break;
+ case 'b':
+ *d = DOWNLEFT;
+ break;
+ case 'y':
+ *d = UPLEFT;
+ break;
+ case 'u':
+ *d = UPRIGHT;
+ break;
+ case 'n':
+ *d = DOWNRIGHT;
+ break;
+ case CANCEL:
+ break;
+ default:
+ return(0);
+ }
+ return(1);
+}
+
+boolean
+check_hunger(msg_only)
+boolean msg_only;
+{
+ register short i, n;
+ boolean fainted = 0;
+
+ if (rogue.moves_left == HUNGRY) {
+ (void) strcpy(hunger_str, "hungry");
+ message(hunger_str, 0);
+ print_stats(STAT_HUNGER);
+ }
+ if (rogue.moves_left == WEAK) {
+ (void) strcpy(hunger_str, "weak");
+ message(hunger_str, 1);
+ print_stats(STAT_HUNGER);
+ }
+ if (rogue.moves_left <= FAINT) {
+ if (rogue.moves_left == FAINT) {
+ (void) 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()) {
+ mv_mons();
+ }
+ }
+ message(you_can_move_again, 1);
+ }
+ }
+ if (msg_only) {
+ return(fainted);
+ }
+ if (rogue.moves_left <= STARVE) {
+ killed_by((object *) 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--;
+ (void) check_hunger(1);
+ rogue.moves_left -= (rogue.moves_left % 2);
+ break;
+ case 2:
+ rogue.moves_left--;
+ (void) check_hunger(1);
+ rogue.moves_left--;
+ break;
+ }
+ return(fainted);
+}
+
+boolean
+reg_move()
+{
+ boolean fainted;
+
+ if ((rogue.moves_left <= HUNGRY) || (cur_level >= max_level)) {
+ fainted = check_hunger(0);
+ } else {
+ fainted = 0;
+ }
+
+ mv_mons();
+
+ if (++m_moves >= 120) {
+ m_moves = 0;
+ 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_player(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;
+ }
+ (void) reg_move();
+ }
+}
+
+gr_dir()
+{
+ short d;
+
+ d = get_rand(1, 8);
+
+ switch(d) {
+ case 1:
+ d = 'j';
+ break;
+ case 2:
+ d = 'k';
+ break;
+ case 3:
+ d = 'l';
+ break;
+ case 4:
+ d = 'h';
+ break;
+ case 5:
+ d = 'y';
+ break;
+ case 6:
+ d = 'u';
+ break;
+ case 7:
+ d = 'b';
+ break;
+ case 8:
+ d = 'n';
+ break;
+ }
+ return(d);
+}
+
+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);
+ }
+}
+
+static boolean
+can_turn(nrow, ncol)
+short nrow, ncol;
+{
+ if ((dungeon[nrow][ncol] & TUNNEL) && is_passable(nrow, ncol)) {
+ return(1);
+ }
+ return(0);
+}
+
+turn_passage(dir, fast)
+short dir;
+boolean fast;
+{
+ short crow = rogue.row, ccol = rogue.col, turns = 0;
+ short ndir;
+
+ if ((dir != 'h') && can_turn(crow, ccol + 1)) {
+ turns++;
+ ndir = 'l';
+ }
+ if ((dir != 'l') && can_turn(crow, ccol - 1)) {
+ turns++;
+ ndir = 'h';
+ }
+ if ((dir != 'k') && can_turn(crow + 1, ccol)) {
+ turns++;
+ ndir = 'j';
+ }
+ if ((dir != 'j') && can_turn(crow - 1, ccol)) {
+ turns++;
+ ndir = 'k';
+ }
+ if (turns == 1) {
+ multiple_move_rogue(ndir - (fast ? 32 : 96));
+ }
+}
diff --git a/rogue/object.c b/rogue/object.c
new file mode 100644
index 00000000..032cdd3e
--- /dev/null
+++ b/rogue/object.c
@@ -0,0 +1,783 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)object.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * object.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.h"
+
+object level_objects;
+unsigned short dungeon[DROWS][DCOLS];
+short foods = 0;
+object *free_list = (object *) 0;
+char *fruit = (char *) 0;
+
+fighter rogue = {
+ INIT_AW, /* armor, weapon */
+ INIT_RINGS, /* rings */
+ INIT_HP, /* Hp current,max */
+ INIT_STR, /* Str current,max */
+ INIT_PACK, /* pack */
+ INIT_GOLD, /* gold */
+ INIT_EXP, /* exp level,points */
+ 0, 0, /* row, col */
+ INIT_CHAR, /* char */
+ INIT_MOVES /* moves */
+};
+
+struct id id_potions[POTIONS] = {
+{100, "blue \0 ", "of increase strength ", 0},
+{250, "red \0 ", "of restore strength ", 0},
+{100, "green \0 ", "of healing ", 0},
+{200, "grey \0 ", "of extra healing ", 0},
+ {10, "brown \0 ", "of poison ", 0},
+{300, "clear \0 ", "of raise level ", 0},
+ {10, "pink \0 ", "of blindness ", 0},
+ {25, "white \0 ", "of hallucination ", 0},
+{100, "purple \0 ", "of detect monster ", 0},
+{100, "black \0 ", "of detect things ", 0},
+ {10, "yellow \0 ", "of confusion ", 0},
+ {80, "plaid \0 ", "of levitation ", 0},
+{150, "burgundy \0 ", "of haste self ", 0},
+{145, "beige \0 ", "of see invisible ", 0}
+};
+
+struct id id_scrolls[SCROLS] = {
+{505, " ", "of protect armor ", 0},
+{200, " ", "of hold monster ", 0},
+{235, " ", "of enchant weapon ", 0},
+{235, " ", "of enchant armor ", 0},
+{175, " ", "of identify ", 0},
+{190, " ", "of teleportation ", 0},
+ {25, " ", "of sleep ", 0},
+{610, " ", "of scare monster ", 0},
+{210, " ", "of remove curse ", 0},
+ {80, " ", "of create monster ",0},
+ {25, " ", "of aggravate monster ",0},
+{180, " ", "of magic mapping ", 0},
+ {90, " ", "of confuse monster ", 0}
+};
+
+struct id id_weapons[WEAPONS] = {
+ {150, "short bow ", "", 0},
+ {8, "darts ", "", 0},
+ {15, "arrows ", "", 0},
+ {27, "daggers ", "", 0},
+ {35, "shurikens ", "", 0},
+ {360, "mace ", "", 0},
+ {470, "long sword ", "", 0},
+ {580, "two-handed sword ", "", 0}
+};
+
+struct id id_armors[ARMORS] = {
+ {300, "leather armor ", "", (UNIDENTIFIED)},
+ {300, "ring mail ", "", (UNIDENTIFIED)},
+ {400, "scale mail ", "", (UNIDENTIFIED)},
+ {500, "chain mail ", "", (UNIDENTIFIED)},
+ {600, "banded mail ", "", (UNIDENTIFIED)},
+ {600, "splint mail ", "", (UNIDENTIFIED)},
+ {700, "plate mail ", "", (UNIDENTIFIED)}
+};
+
+struct id id_wands[WANDS] = {
+ {25, " ", "of teleport away ",0},
+ {50, " ", "of slow monster ", 0},
+ {8, " ", "of invisibility ",0},
+ {55, " ", "of polymorph ",0},
+ {2, " ", "of haste monster ",0},
+ {20, " ", "of magic missile ",0},
+ {20, " ", "of cancellation ",0},
+ {0, " ", "of do nothing ",0},
+ {35, " ", "of drain life ",0},
+ {20, " ", "of cold ",0},
+ {20, " ", "of fire ",0}
+};
+
+struct id id_rings[RINGS] = {
+ {250, " ", "of stealth ",0},
+ {100, " ", "of teleportation ", 0},
+ {255, " ", "of regeneration ",0},
+ {295, " ", "of slow digestion ",0},
+ {200, " ", "of add strength ",0},
+ {250, " ", "of sustain strength ",0},
+ {250, " ", "of dexterity ",0},
+ {25, " ", "of adornment ",0},
+ {300, " ", "of see invisible ",0},
+ {290, " ", "of maintain armor ",0},
+ {270, " ", "of searching ",0},
+};
+
+extern short cur_level, max_level;
+extern short party_room;
+extern char *error_file;
+extern boolean is_wood[];
+
+put_objects()
+{
+ short i, n;
+ object *obj;
+
+ if (cur_level < max_level) {
+ return;
+ }
+ n = coin_toss() ? get_rand(2, 4) : get_rand(3, 5);
+ while (rand_percent(33)) {
+ n++;
+ }
+ if (party_room != NO_ROOM) {
+ make_party();
+ }
+ for (i = 0; i < n; i++) {
+ obj = gr_object();
+ rand_place(obj);
+ }
+ put_gold();
+}
+
+put_gold()
+{
+ short i, j;
+ short row,col;
+ boolean is_maze, is_room;
+
+ for (i = 0; i < MAXROOMS; i++) {
+ is_maze = (rooms[i].is_room & R_MAZE) ? 1 : 0;
+ is_room = (rooms[i].is_room & R_ROOM) ? 1 : 0;
+
+ if (!(is_room || is_maze)) {
+ continue;
+ }
+ if (is_maze || rand_percent(GOLD_PERCENT)) {
+ for (j = 0; j < 50; j++) {
+ row = get_rand(rooms[i].top_row+1,
+ rooms[i].bottom_row-1);
+ col = get_rand(rooms[i].left_col+1,
+ rooms[i].right_col-1);
+ if ((dungeon[row][col] == FLOOR) ||
+ (dungeon[row][col] == TUNNEL)) {
+ plant_gold(row, col, is_maze);
+ break;
+ }
+ }
+ }
+ }
+}
+
+plant_gold(row, col, is_maze)
+short row, col;
+boolean is_maze;
+{
+ object *obj;
+
+ obj = alloc_object();
+ obj->row = row; obj->col = col;
+ obj->what_is = GOLD;
+ obj->quantity = get_rand((2 * cur_level), (16 * cur_level));
+ if (is_maze) {
+ obj->quantity += obj->quantity / 2;
+ }
+ dungeon[row][col] |= OBJECT;
+ (void) add_to_pack(obj, &level_objects, 0);
+}
+
+place_at(obj, row, col)
+object *obj;
+{
+ obj->row = row;
+ obj->col = col;
+ dungeon[row][col] |= OBJECT;
+ (void) add_to_pack(obj, &level_objects, 0);
+}
+
+object *
+object_at(pack, row, col)
+register object *pack;
+short row, col;
+{
+ object *obj = (object *) 0;
+
+ if (dungeon[row][col] & (MONSTER | OBJECT)) {
+ obj = pack->next_object;
+
+ while (obj && ((obj->row != row) || (obj->col != col))) {
+ obj = obj->next_object;
+ }
+ if (!obj) {
+ message("object_at(): inconsistent", 1);
+ }
+ }
+ return(obj);
+}
+
+object *
+get_letter_object(ch)
+{
+ object *obj;
+
+ obj = rogue.pack.next_object;
+
+ while (obj && (obj->ichar != ch)) {
+ obj = obj->next_object;
+ }
+ return(obj);
+}
+
+free_stuff(objlist)
+object *objlist;
+{
+ object *obj;
+
+ while (objlist->next_object) {
+ obj = objlist->next_object;
+ objlist->next_object =
+ objlist->next_object->next_object;
+ free_object(obj);
+ }
+}
+
+char *
+name_of(obj)
+object *obj;
+{
+ char *retstring;
+
+ switch(obj->what_is) {
+ case SCROL:
+ retstring = obj->quantity > 1 ? "scrolls " : "scroll ";
+ break;
+ case POTION:
+ retstring = obj->quantity > 1 ? "potions " : "potion ";
+ break;
+ case FOOD:
+ if (obj->which_kind == RATION) {
+ retstring = "food ";
+ } else {
+ retstring = fruit;
+ }
+ break;
+ case WAND:
+ retstring = is_wood[obj->which_kind] ? "staff " : "wand ";
+ break;
+ case WEAPON:
+ switch(obj->which_kind) {
+ case DART:
+ retstring=obj->quantity > 1 ? "darts " : "dart ";
+ break;
+ case ARROW:
+ retstring=obj->quantity > 1 ? "arrows " : "arrow ";
+ break;
+ case DAGGER:
+ retstring=obj->quantity > 1 ? "daggers " : "dagger ";
+ break;
+ case SHURIKEN:
+ retstring=obj->quantity > 1?"shurikens ":"shuriken ";
+ break;
+ default:
+ retstring = id_weapons[obj->which_kind].title;
+ }
+ break;
+ case ARMOR:
+ retstring = "armor ";
+ break;
+ case RING:
+ retstring = "ring ";
+ break;
+ case AMULET:
+ retstring = "amulet ";
+ break;
+ default:
+ retstring = "unknown ";
+ break;
+ }
+ return(retstring);
+}
+
+object *
+gr_object()
+{
+ object *obj;
+
+ obj = alloc_object();
+
+ if (foods < (cur_level / 3)) {
+ obj->what_is = FOOD;
+ foods++;
+ } else {
+ obj->what_is = gr_what_is();
+ }
+ switch(obj->what_is) {
+ case SCROL:
+ gr_scroll(obj);
+ break;
+ case POTION:
+ gr_potion(obj);
+ break;
+ case WEAPON:
+ gr_weapon(obj, 1);
+ break;
+ case ARMOR:
+ gr_armor(obj);
+ break;
+ case WAND:
+ gr_wand(obj);
+ break;
+ case FOOD:
+ get_food(obj, 0);
+ break;
+ case RING:
+ gr_ring(obj, 1);
+ break;
+ }
+ return(obj);
+}
+
+unsigned short
+gr_what_is()
+{
+ short percent;
+ unsigned short what_is;
+
+ percent = get_rand(1, 91);
+
+ if (percent <= 30) {
+ what_is = SCROL;
+ } else if (percent <= 60) {
+ what_is = POTION;
+ } else if (percent <= 64) {
+ what_is = WAND;
+ } else if (percent <= 74) {
+ what_is = WEAPON;
+ } else if (percent <= 83) {
+ what_is = ARMOR;
+ } else if (percent <= 88) {
+ what_is = FOOD;
+ } else {
+ what_is = RING;
+ }
+ return(what_is);
+}
+
+gr_scroll(obj)
+object *obj;
+{
+ short percent;
+
+ percent = get_rand(0, 91);
+
+ obj->what_is = SCROL;
+
+ if (percent <= 5) {
+ obj->which_kind = PROTECT_ARMOR;
+ } else if (percent <= 10) {
+ obj->which_kind = HOLD_MONSTER;
+ } else if (percent <= 20) {
+ obj->which_kind = CREATE_MONSTER;
+ } else if (percent <= 35) {
+ obj->which_kind = IDENTIFY;
+ } else if (percent <= 43) {
+ obj->which_kind = TELEPORT;
+ } else if (percent <= 50) {
+ obj->which_kind = SLEEP;
+ } else if (percent <= 55) {
+ obj->which_kind = SCARE_MONSTER;
+ } else if (percent <= 64) {
+ obj->which_kind = REMOVE_CURSE;
+ } else if (percent <= 69) {
+ obj->which_kind = ENCH_ARMOR;
+ } else if (percent <= 74) {
+ obj->which_kind = ENCH_WEAPON;
+ } else if (percent <= 80) {
+ obj->which_kind = AGGRAVATE_MONSTER;
+ } else if (percent <= 86) {
+ obj->which_kind = CON_MON;
+ } else {
+ obj->which_kind = MAGIC_MAPPING;
+ }
+}
+
+gr_potion(obj)
+object *obj;
+{
+ short percent;
+
+ percent = get_rand(1, 118);
+
+ obj->what_is = POTION;
+
+ if (percent <= 5) {
+ obj->which_kind = RAISE_LEVEL;
+ } else if (percent <= 15) {
+ obj->which_kind = DETECT_OBJECTS;
+ } else if (percent <= 25) {
+ obj->which_kind = DETECT_MONSTER;
+ } else if (percent <= 35) {
+ obj->which_kind = INCREASE_STRENGTH;
+ } else if (percent <= 45) {
+ obj->which_kind = RESTORE_STRENGTH;
+ } else if (percent <= 55) {
+ obj->which_kind = HEALING;
+ } else if (percent <= 65) {
+ obj->which_kind = EXTRA_HEALING;
+ } else if (percent <= 75) {
+ obj->which_kind = BLINDNESS;
+ } else if (percent <= 85) {
+ obj->which_kind = HALLUCINATION;
+ } else if (percent <= 95) {
+ obj->which_kind = CONFUSION;
+ } else if (percent <= 105) {
+ obj->which_kind = POISON;
+ } else if (percent <= 110) {
+ obj->which_kind = LEVITATION;
+ } else if (percent <= 114) {
+ obj->which_kind = HASTE_SELF;
+ } else {
+ obj->which_kind = SEE_INVISIBLE;
+ }
+}
+
+gr_weapon(obj, assign_wk)
+object *obj;
+int assign_wk;
+{
+ short percent;
+ short i;
+ short blessing, increment;
+
+ obj->what_is = WEAPON;
+ if (assign_wk) {
+ obj->which_kind = get_rand(0, (WEAPONS - 1));
+ }
+ if ((obj->which_kind == ARROW) || (obj->which_kind == DAGGER) ||
+ (obj->which_kind == SHURIKEN) | (obj->which_kind == DART)) {
+ obj->quantity = get_rand(3, 15);
+ obj->quiver = get_rand(0, 126);
+ } else {
+ obj->quantity = 1;
+ }
+ obj->hit_enchant = obj->d_enchant = 0;
+
+ percent = get_rand(1, 96);
+ blessing = get_rand(1, 3);
+
+ if (percent <= 16) {
+ increment = 1;
+ } else if (percent <= 32) {
+ increment = -1;
+ obj->is_cursed = 1;
+ }
+ if (percent <= 32) {
+ for (i = 0; i < blessing; i++) {
+ if (coin_toss()) {
+ obj->hit_enchant += increment;
+ } else {
+ obj->d_enchant += increment;
+ }
+ }
+ }
+ switch(obj->which_kind) {
+ case BOW:
+ case DART:
+ obj->damage = "1d1";
+ break;
+ case ARROW:
+ obj->damage = "1d2";
+ break;
+ case DAGGER:
+ obj->damage = "1d3";
+ break;
+ case SHURIKEN:
+ obj->damage = "1d4";
+ break;
+ case MACE:
+ obj->damage = "2d3";
+ break;
+ case LONG_SWORD:
+ obj->damage = "3d4";
+ break;
+ case TWO_HANDED_SWORD:
+ obj->damage = "4d5";
+ break;
+ }
+}
+
+gr_armor(obj)
+object *obj;
+{
+ short percent;
+ short blessing;
+
+ obj->what_is = ARMOR;
+ obj->which_kind = get_rand(0, (ARMORS - 1));
+ obj->class = obj->which_kind + 2;
+ if ((obj->which_kind == PLATE) || (obj->which_kind == SPLINT)) {
+ obj->class--;
+ }
+ obj->is_protected = 0;
+ obj->d_enchant = 0;
+
+ percent = get_rand(1, 100);
+ blessing = get_rand(1, 3);
+
+ if (percent <= 16) {
+ obj->is_cursed = 1;
+ obj->d_enchant -= blessing;
+ } else if (percent <= 33) {
+ obj->d_enchant += blessing;
+ }
+}
+
+gr_wand(obj)
+object *obj;
+{
+ obj->what_is = WAND;
+ obj->which_kind = get_rand(0, (WANDS - 1));
+ obj->class = get_rand(3, 7);
+}
+
+get_food(obj, force_ration)
+object *obj;
+boolean force_ration;
+{
+ obj->what_is = FOOD;
+
+ if (force_ration || rand_percent(80)) {
+ obj->which_kind = RATION;
+ } else {
+ obj->which_kind = FRUIT;
+ }
+}
+
+put_stairs()
+{
+ short row, col;
+
+ gr_row_col(&row, &col, (FLOOR | TUNNEL));
+ dungeon[row][col] |= STAIRS;
+}
+
+get_armor_class(obj)
+object *obj;
+{
+ if (obj) {
+ return(obj->class + obj->d_enchant);
+ }
+ return(0);
+}
+
+object *
+alloc_object()
+{
+ object *obj;
+
+ if (free_list) {
+ obj = free_list;
+ free_list = free_list->next_object;
+ } else if (!(obj = (object *) md_malloc(sizeof(object)))) {
+ message("cannot allocate object, saving game", 0);
+ save_into_file(error_file);
+ }
+ obj->quantity = 1;
+ obj->ichar = 'L';
+ obj->picked_up = obj->is_cursed = 0;
+ obj->in_use_flags = NOT_USED;
+ obj->identified = UNIDENTIFIED;
+ obj->damage = "1d1";
+ return(obj);
+}
+
+free_object(obj)
+object *obj;
+{
+ obj->next_object = free_list;
+ free_list = obj;
+}
+
+make_party()
+{
+ short n;
+
+ party_room = gr_room();
+
+ n = rand_percent(99) ? party_objects(party_room) : 11;
+ if (rand_percent(99)) {
+ party_monsters(party_room, n);
+ }
+}
+
+show_objects()
+{
+ object *obj;
+ short mc, rc, row, col;
+ object *monster;
+
+ obj = level_objects.next_object;
+
+ while (obj) {
+ row = obj->row;
+ col = obj->col;
+
+ rc = get_mask_char(obj->what_is);
+
+ if (dungeon[row][col] & MONSTER) {
+ if (monster = object_at(&level_monsters, row, col)) {
+ monster->trail_char = rc;
+ }
+ }
+ mc = mvinch(row, col);
+ if (((mc < 'A') || (mc > 'Z')) &&
+ ((row != rogue.row) || (col != rogue.col))) {
+ mvaddch(row, col, rc);
+ }
+ obj = obj->next_object;
+ }
+
+ monster = level_monsters.next_object;
+
+ while (monster) {
+ if (monster->m_flags & IMITATES) {
+ mvaddch(monster->row, monster->col, (int) monster->disguise);
+ }
+ monster = monster->next_monster;
+ }
+}
+
+put_amulet()
+{
+ object *obj;
+
+ obj = alloc_object();
+ obj->what_is = AMULET;
+ rand_place(obj);
+}
+
+rand_place(obj)
+object *obj;
+{
+ short row, col;
+
+ gr_row_col(&row, &col, (FLOOR | TUNNEL));
+ place_at(obj, row, col);
+}
+
+c_object_for_wizard()
+{
+ short ch, max, wk;
+ object *obj;
+ char buf[80];
+
+ if (pack_count((object *) 0) >= MAX_PACK_COUNT) {
+ message("pack full", 0);
+ return;
+ }
+ message("type of object?", 0);
+
+ while (r_index("!?:)]=/,\033", (ch = rgetchar()), 0) == -1) {
+ sound_bell();
+ }
+ check_message();
+
+ if (ch == '\033') {
+ return;
+ }
+ obj = alloc_object();
+
+ switch(ch) {
+ case '!':
+ obj->what_is = POTION;
+ max = POTIONS - 1;
+ break;
+ case '?':
+ obj->what_is = SCROL;
+ max = SCROLS - 1;
+ break;
+ case ',':
+ obj->what_is = AMULET;
+ break;
+ case ':':
+ get_food(obj, 0);
+ break;
+ case ')':
+ gr_weapon(obj, 0);
+ max = WEAPONS - 1;
+ break;
+ case ']':
+ gr_armor(obj);
+ max = ARMORS - 1;
+ break;
+ case '/':
+ gr_wand(obj);
+ max = WANDS - 1;
+ break;
+ case '=':
+ max = RINGS - 1;
+ obj->what_is = RING;
+ break;
+ }
+ if ((ch != ',') && (ch != ':')) {
+GIL:
+ if (get_input_line("which kind?", "", buf, "", 0, 1)) {
+ wk = get_number(buf);
+ if ((wk >= 0) && (wk <= max)) {
+ obj->which_kind = (unsigned short) wk;
+ if (obj->what_is == RING) {
+ gr_ring(obj, 0);
+ }
+ } else {
+ sound_bell();
+ goto GIL;
+ }
+ } else {
+ free_object(obj);
+ return;
+ }
+ }
+ get_desc(obj, buf);
+ message(buf, 0);
+ (void) add_to_pack(obj, &rogue.pack, 1);
+}
diff --git a/rogue/pack.c b/rogue/pack.c
new file mode 100644
index 00000000..f0d37f69
--- /dev/null
+++ b/rogue/pack.c
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)pack.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * pack.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.h"
+
+char *curse_message = "you can't, it appears to be cursed";
+
+extern short levitate;
+
+object *
+add_to_pack(obj, pack, condense)
+object *obj, *pack;
+{
+ object *op;
+
+ if (condense) {
+ if (op = check_duplicate(obj, pack)) {
+ free_object(obj);
+ return(op);
+ } else {
+ obj->ichar = next_avail_ichar();
+ }
+ }
+ if (pack->next_object == 0) {
+ pack->next_object = obj;
+ } else {
+ op = pack->next_object;
+
+ while (op->next_object) {
+ op = op->next_object;
+ }
+ op->next_object = obj;
+ }
+ obj->next_object = 0;
+ return(obj);
+}
+
+take_from_pack(obj, pack)
+object *obj, *pack;
+{
+ while (pack->next_object != obj) {
+ pack = pack->next_object;
+ }
+ pack->next_object = pack->next_object->next_object;
+}
+
+/* Note: *status is set to 0 if the rogue attempts to pick up a scroll
+ * of scare-monster and it turns to dust. *status is otherwise set to 1.
+ */
+
+object *
+pick_up(row, col, status)
+short *status;
+{
+ object *obj;
+
+ *status = 1;
+
+ if (levitate) {
+ message("you're floating in the air!", 0);
+ return((object *) 0);
+ }
+ obj = object_at(&level_objects, row, col);
+ if (!obj) {
+ message("pick_up(): inconsistent", 1);
+ return(obj);
+ }
+ if ( (obj->what_is == SCROL) &&
+ (obj->which_kind == SCARE_MONSTER) &&
+ obj->picked_up) {
+ message("the scroll turns to dust as you pick it up", 0);
+ dungeon[row][col] &= (~OBJECT);
+ vanish(obj, 0, &level_objects);
+ *status = 0;
+ if (id_scrolls[SCARE_MONSTER].id_status == UNIDENTIFIED) {
+ id_scrolls[SCARE_MONSTER].id_status = IDENTIFIED;
+ }
+ return((object *) 0);
+ }
+ if (obj->what_is == GOLD) {
+ rogue.gold += obj->quantity;
+ dungeon[row][col] &= ~(OBJECT);
+ take_from_pack(obj, &level_objects);
+ print_stats(STAT_GOLD);
+ return(obj); /* obj will be free_object()ed in caller */
+ }
+ if (pack_count(obj) >= MAX_PACK_COUNT) {
+ message("pack too full", 1);
+ return((object *) 0);
+ }
+ dungeon[row][col] &= ~(OBJECT);
+ take_from_pack(obj, &level_objects);
+ obj = add_to_pack(obj, &rogue.pack, 1);
+ obj->picked_up = 1;
+ return(obj);
+}
+
+drop()
+{
+ object *obj, *new;
+ short ch;
+ char desc[DCOLS];
+
+ if (dungeon[rogue.row][rogue.col] & (OBJECT | STAIRS | TRAP)) {
+ message("there's already something there", 0);
+ return;
+ }
+ if (!rogue.pack.next_object) {
+ message("you have nothing to drop", 0);
+ return;
+ }
+ if ((ch = pack_letter("drop what?", ALL_OBJECTS)) == CANCEL) {
+ return;
+ }
+ if (!(obj = get_letter_object(ch))) {
+ message("no such item.", 0);
+ return;
+ }
+ if (obj->in_use_flags & BEING_WIELDED) {
+ if (obj->is_cursed) {
+ message(curse_message, 0);
+ return;
+ }
+ unwield(rogue.weapon);
+ } else if (obj->in_use_flags & BEING_WORN) {
+ if (obj->is_cursed) {
+ message(curse_message, 0);
+ return;
+ }
+ mv_aquatars();
+ unwear(rogue.armor);
+ print_stats(STAT_ARMOR);
+ } else if (obj->in_use_flags & ON_EITHER_HAND) {
+ if (obj->is_cursed) {
+ message(curse_message, 0);
+ return;
+ }
+ un_put_on(obj);
+ }
+ obj->row = rogue.row;
+ obj->col = rogue.col;
+
+ if ((obj->quantity > 1) && (obj->what_is != WEAPON)) {
+ obj->quantity--;
+ new = alloc_object();
+ *new = *obj;
+ new->quantity = 1;
+ obj = new;
+ } else {
+ obj->ichar = 'L';
+ take_from_pack(obj, &rogue.pack);
+ }
+ place_at(obj, rogue.row, rogue.col);
+ (void) strcpy(desc, "dropped ");
+ get_desc(obj, desc+8);
+ message(desc, 0);
+ (void) reg_move();
+}
+
+object *
+check_duplicate(obj, pack)
+object *obj, *pack;
+{
+ object *op;
+
+ if (!(obj->what_is & (WEAPON | FOOD | SCROL | POTION))) {
+ return(0);
+ }
+ if ((obj->what_is == FOOD) && (obj->which_kind == FRUIT)) {
+ return(0);
+ }
+ op = pack->next_object;
+
+ while (op) {
+ if ((op->what_is == obj->what_is) &&
+ (op->which_kind == obj->which_kind)) {
+
+ if ((obj->what_is != WEAPON) ||
+ ((obj->what_is == WEAPON) &&
+ ((obj->which_kind == ARROW) ||
+ (obj->which_kind == DAGGER) ||
+ (obj->which_kind == DART) ||
+ (obj->which_kind == SHURIKEN)) &&
+ (obj->quiver == op->quiver))) {
+ op->quantity += obj->quantity;
+ return(op);
+ }
+ }
+ op = op->next_object;
+ }
+ return(0);
+}
+
+next_avail_ichar()
+{
+ register object *obj;
+ register i;
+ boolean ichars[26];
+
+ for (i = 0; i < 26; i++) {
+ ichars[i] = 0;
+ }
+ obj = rogue.pack.next_object;
+ while (obj) {
+ ichars[(obj->ichar - 'a')] = 1;
+ obj = obj->next_object;
+ }
+ for (i = 0; i < 26; i++) {
+ if (!ichars[i]) {
+ return(i + 'a');
+ }
+ }
+ return('?');
+}
+
+wait_for_ack()
+{
+ while (rgetchar() != ' ') ;
+}
+
+pack_letter(prompt, mask)
+char *prompt;
+unsigned short mask;
+{
+ short ch;
+ unsigned short tmask = mask;
+
+ if (!mask_pack(&rogue.pack, mask)) {
+ message("nothing appropriate", 0);
+ return(CANCEL);
+ }
+ for (;;) {
+
+ message(prompt, 0);
+
+ for (;;) {
+ ch = rgetchar();
+ if (!is_pack_letter(&ch, &mask)) {
+ sound_bell();
+ } else {
+ break;
+ }
+ }
+
+ if (ch == LIST) {
+ check_message();
+ inventory(&rogue.pack, mask);
+ } else {
+ break;
+ }
+ mask = tmask;
+ }
+ check_message();
+ return(ch);
+}
+
+take_off()
+{
+ char desc[DCOLS];
+ object *obj;
+
+ if (rogue.armor) {
+ if (rogue.armor->is_cursed) {
+ message(curse_message, 0);
+ } else {
+ mv_aquatars();
+ obj = rogue.armor;
+ unwear(rogue.armor);
+ (void) strcpy(desc, "was wearing ");
+ get_desc(obj, desc+12);
+ message(desc, 0);
+ print_stats(STAT_ARMOR);
+ (void) reg_move();
+ }
+ } else {
+ message("not wearing any", 0);
+ }
+}
+
+wear()
+{
+ short ch;
+ register object *obj;
+ char desc[DCOLS];
+
+ if (rogue.armor) {
+ message("your already wearing some", 0);
+ return;
+ }
+ ch = pack_letter("wear what?", ARMOR);
+
+ if (ch == CANCEL) {
+ return;
+ }
+ if (!(obj = get_letter_object(ch))) {
+ message("no such item.", 0);
+ return;
+ }
+ if (obj->what_is != ARMOR) {
+ message("you can't wear that", 0);
+ return;
+ }
+ obj->identified = 1;
+ (void) strcpy(desc, "wearing ");
+ get_desc(obj, desc + 8);
+ message(desc, 0);
+ do_wear(obj);
+ print_stats(STAT_ARMOR);
+ (void) reg_move();
+}
+
+unwear(obj)
+object *obj;
+{
+ if (obj) {
+ obj->in_use_flags &= (~BEING_WORN);
+ }
+ rogue.armor = (object *) 0;
+}
+
+do_wear(obj)
+object *obj;
+{
+ rogue.armor = obj;
+ obj->in_use_flags |= BEING_WORN;
+ obj->identified = 1;
+}
+
+wield()
+{
+ short ch;
+ register object *obj;
+ char desc[DCOLS];
+
+ if (rogue.weapon && rogue.weapon->is_cursed) {
+ message(curse_message, 0);
+ return;
+ }
+ ch = pack_letter("wield what?", WEAPON);
+
+ if (ch == CANCEL) {
+ return;
+ }
+ if (!(obj = get_letter_object(ch))) {
+ message("No such item.", 0);
+ return;
+ }
+ if (obj->what_is & (ARMOR | RING)) {
+ sprintf(desc, "you can't wield %s",
+ ((obj->what_is == ARMOR) ? "armor" : "rings"));
+ message(desc, 0);
+ return;
+ }
+ if (obj->in_use_flags & BEING_WIELDED) {
+ message("in use", 0);
+ } else {
+ unwield(rogue.weapon);
+ (void) strcpy(desc, "wielding ");
+ get_desc(obj, desc + 9);
+ message(desc, 0);
+ do_wield(obj);
+ (void) reg_move();
+ }
+}
+
+do_wield(obj)
+object *obj;
+{
+ rogue.weapon = obj;
+ obj->in_use_flags |= BEING_WIELDED;
+}
+
+unwield(obj)
+object *obj;
+{
+ if (obj) {
+ obj->in_use_flags &= (~BEING_WIELDED);
+ }
+ rogue.weapon = (object *) 0;
+}
+
+call_it()
+{
+ short ch;
+ register object *obj;
+ struct id *id_table;
+ char buf[MAX_TITLE_LENGTH+2];
+
+ ch = pack_letter("call what?", (SCROL | POTION | WAND | RING));
+
+ if (ch == CANCEL) {
+ return;
+ }
+ if (!(obj = get_letter_object(ch))) {
+ message("no such item.", 0);
+ return;
+ }
+ if (!(obj->what_is & (SCROL | POTION | WAND | RING))) {
+ message("surely you already know what that's called", 0);
+ return;
+ }
+ id_table = get_id_table(obj);
+
+ if (get_input_line("call it:","",buf,id_table[obj->which_kind].title,1,1)) {
+ id_table[obj->which_kind].id_status = CALLED;
+ (void) strcpy(id_table[obj->which_kind].title, buf);
+ }
+}
+
+pack_count(new_obj)
+object *new_obj;
+{
+ object *obj;
+ short count = 0;
+
+ obj = rogue.pack.next_object;
+
+ while (obj) {
+ if (obj->what_is != WEAPON) {
+ count += obj->quantity;
+ } else if (!new_obj) {
+ count++;
+ } else if ((new_obj->what_is != WEAPON) ||
+ ((obj->which_kind != ARROW) &&
+ (obj->which_kind != DAGGER) &&
+ (obj->which_kind != DART) &&
+ (obj->which_kind != SHURIKEN)) ||
+ (new_obj->which_kind != obj->which_kind) ||
+ (obj->quiver != new_obj->quiver)) {
+ count++;
+ }
+ obj = obj->next_object;
+ }
+ return(count);
+}
+
+boolean
+mask_pack(pack, mask)
+object *pack;
+unsigned short mask;
+{
+ while (pack->next_object) {
+ pack = pack->next_object;
+ if (pack->what_is & mask) {
+ return(1);
+ }
+ }
+ return(0);
+}
+
+is_pack_letter(c, mask)
+short *c;
+unsigned short *mask;
+{
+ if (((*c == '?') || (*c == '!') || (*c == ':') || (*c == '=') ||
+ (*c == ')') || (*c == ']') || (*c == '/') || (*c == ','))) {
+ switch(*c) {
+ case '?':
+ *mask = SCROL;
+ break;
+ case '!':
+ *mask = POTION;
+ break;
+ case ':':
+ *mask = FOOD;
+ break;
+ case ')':
+ *mask = WEAPON;
+ break;
+ case ']':
+ *mask = ARMOR;
+ break;
+ case '/':
+ *mask = WAND;
+ break;
+ case '=':
+ *mask = RING;
+ break;
+ case ',':
+ *mask = AMULET;
+ break;
+ }
+ *c = LIST;
+ return(1);
+ }
+ return(((*c >= 'a') && (*c <= 'z')) || (*c == CANCEL) || (*c == LIST));
+}
+
+has_amulet()
+{
+ return(mask_pack(&rogue.pack, AMULET));
+}
+
+kick_into_pack()
+{
+ object *obj;
+ char desc[DCOLS];
+ short n, stat;
+
+ if (!(dungeon[rogue.row][rogue.col] & OBJECT)) {
+ message("nothing here", 0);
+ } else {
+ if (obj = pick_up(rogue.row, rogue.col, &stat)) {
+ get_desc(obj, desc);
+ if (obj->what_is == GOLD) {
+ message(desc, 0);
+ free_object(obj);
+ } else {
+ n = strlen(desc);
+ desc[n] = '(';
+ desc[n+1] = obj->ichar;
+ desc[n+2] = ')';
+ desc[n+3] = 0;
+ message(desc, 0);
+ }
+ }
+ if (obj || (!stat)) {
+ (void) reg_move();
+ }
+ }
+}
diff --git a/rogue/pathnames.h b/rogue/pathnames.h
new file mode 100644
index 00000000..7be84041
--- /dev/null
+++ b/rogue/pathnames.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 5.1 (Berkeley) 6/1/90
+ */
+
+#define _PATH_SCOREFILE "/var/games/rogue.scores"
+#define _PATH_LOCKFILE "/var/games/rogue.lock"
+
diff --git a/rogue/play.c b/rogue/play.c
new file mode 100644
index 00000000..aaa6348c
--- /dev/null
+++ b/rogue/play.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)play.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * play.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.h"
+
+boolean interrupted = 0;
+char *unknown_command = "unknown command";
+
+extern short party_room, bear_trap;
+extern char hit_message[];
+extern boolean wizard, trap_door;
+
+play_level()
+{
+ short ch;
+ int count;
+
+ for (;;) {
+ interrupted = 0;
+ if (hit_message[0]) {
+ message(hit_message, 1);
+ hit_message[0] = 0;
+ }
+ if (trap_door) {
+ trap_door = 0;
+ return;
+ }
+ move(rogue.row, rogue.col);
+ refresh();
+
+ ch = rgetchar();
+CMCH:
+ check_message();
+ count = 0;
+CH:
+ switch(ch) {
+ case '.':
+ rest((count > 0) ? count : 1);
+ break;
+ case 's':
+ search(((count > 0) ? count : 1), 0);
+ break;
+ case 'i':
+ inventory(&rogue.pack, ALL_OBJECTS);
+ break;
+ case 'f':
+ fight(0);
+ break;
+ case 'F':
+ fight(1);
+ break;
+ case 'h':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'y':
+ case 'u':
+ case 'n':
+ case 'b':
+ (void) one_move_rogue(ch, 1);
+ break;
+ case 'H':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'B':
+ case 'Y':
+ case 'U':
+ case 'N':
+ case '\010':
+ case '\012':
+ case '\013':
+ case '\014':
+ case '\031':
+ case '\025':
+ case '\016':
+ case '\002':
+ multiple_move_rogue(ch);
+ break;
+ case 'e':
+ eat();
+ break;
+ case 'q':
+ quaff();
+ break;
+ case 'r':
+ read_scroll();
+ break;
+ case 'm':
+ move_onto();
+ break;
+ case ',':
+ kick_into_pack();
+ break;
+ case 'd':
+ drop();
+ break;
+ case 'P':
+ put_on_ring();
+ break;
+ case 'R':
+ remove_ring();
+ break;
+ case '\020':
+ do {
+ remessage(count++);
+ ch = rgetchar();
+ } while (ch == '\020');
+ goto CMCH;
+ break;
+ case '\027':
+ wizardize();
+ break;
+ case '>':
+ if (drop_check()) {
+ return;
+ }
+ break;
+ case '<':
+ if (check_up()) {
+ return;
+ }
+ break;
+ case ')':
+ case ']':
+ inv_armor_weapon(ch == ')');
+ break;
+ case '=':
+ inv_rings();
+ break;
+ case '^':
+ id_trap();
+ break;
+ case '/':
+ id_type();
+ break;
+ case '?':
+ id_com();
+ break;
+ case '!':
+ do_shell();
+ break;
+ case 'o':
+ edit_opts();
+ break;
+ case 'I':
+ single_inv(0);
+ break;
+ case 'T':
+ take_off();
+ break;
+ case 'W':
+ wear();
+ break;
+ case 'w':
+ wield();
+ break;
+ case 'c':
+ call_it();
+ break;
+ case 'z':
+ zapp();
+ break;
+ case 't':
+ throw();
+ break;
+ case 'v':
+ message("rogue-clone: Version III. (Tim Stoehr was here), tektronix!zeus!tims", 0);
+ break;
+ case 'Q':
+ quit(0);
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ move(rogue.row, rogue.col);
+ refresh();
+ do {
+ if (count < 100) {
+ count = (10 * count) + (ch - '0');
+ }
+ ch = rgetchar();
+ } while (is_digit(ch));
+ if (ch != CANCEL) {
+ goto CH;
+ }
+ break;
+ case ' ':
+ break;
+ case '\011':
+ if (wizard) {
+ inventory(&level_objects, ALL_OBJECTS);
+ } else {
+ message(unknown_command, 0);
+ }
+ break;
+ case '\023':
+ if (wizard) {
+ draw_magic_map();
+ } else {
+ message(unknown_command, 0);
+ }
+ break;
+ case '\024':
+ if (wizard) {
+ show_traps();
+ } else {
+ message(unknown_command, 0);
+ }
+ break;
+ case '\017':
+ if (wizard) {
+ show_objects();
+ } else {
+ message(unknown_command, 0);
+ }
+ break;
+ case '\001':
+ show_average_hp();
+ break;
+ case '\003':
+ if (wizard) {
+ c_object_for_wizard();
+ } else {
+ message(unknown_command, 0);
+ }
+ break;
+ case '\015':
+ if (wizard) {
+ show_monsters();
+ } else {
+ message(unknown_command, 0);
+ }
+ break;
+ case 'S':
+ save_game();
+ break;
+ default:
+ message(unknown_command, 0);
+ break;
+ }
+ }
+}
diff --git a/rogue/random.c b/rogue/random.c
new file mode 100644
index 00000000..bd829d6e
--- /dev/null
+++ b/rogue/random.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)random.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * random.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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.
+ *
+ */
+
+static long rntb[32] = {
+ 3, 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342,
+ 0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, 0x7449e56b,
+ 0xbeb1dbb0, 0xab5c5918, 0x946554fd, 0x8c2e680f, 0xeb3d799f,
+ 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88, 0xe369735d,
+ 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc,
+ 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e,
+ 0x8999220b, 0x27fb47b9
+};
+
+static long *fptr = &rntb[4];
+static long *rptr = &rntb[1];
+static long *state = &rntb[1];
+static int rand_type = 3;
+static int rand_deg = 31;
+static int rand_sep = 3;
+static long *end_ptr = &rntb[32];
+
+srrandom(x)
+int x;
+{
+ register int i;
+ long rrandom();
+
+ state[0] = (long) x;
+ if (rand_type != 0) {
+ for (i = 1; i < rand_deg; i++) {
+ state[i] = 1103515245 * state[i - 1] + 12345;
+ }
+ fptr = &state[rand_sep];
+ rptr = &state[0];
+ for (i = 0; i < 10 * rand_deg; i++) {
+ (void) rrandom();
+ }
+ }
+}
+
+long
+rrandom()
+{
+ long i;
+
+ if (rand_type == 0) {
+ i = state[0] = (state[0]*1103515245 + 12345) & 0x7fffffff;
+ } else {
+ *fptr += *rptr;
+ i = (*fptr >> 1) & 0x7fffffff;
+ if (++fptr >= end_ptr) {
+ fptr = state;
+ ++rptr;
+ } else {
+ if (++rptr >= end_ptr) {
+ rptr = state;
+ }
+ }
+ }
+ return(i);
+}
+
+get_rand(x, y)
+register int x, y;
+{
+ register int r, t;
+ long lr;
+
+ if (x > y) {
+ t = y;
+ y = x;
+ x = t;
+ }
+ lr = rrandom();
+ lr &= (long) 0x00003fff;
+ r = (int) lr;
+ r = (r % ((y - x) + 1)) + x;
+ return(r);
+}
+
+rand_percent(percentage)
+register int percentage;
+{
+ return(get_rand(1, 100) <= percentage);
+}
+
+coin_toss()
+{
+
+ return(((rrandom() & 01) ? 1 : 0));
+}
diff --git a/rogue/ring.c b/rogue/ring.c
new file mode 100644
index 00000000..1014000a
--- /dev/null
+++ b/rogue/ring.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ring.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * ring.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.h"
+
+char *left_or_right = "left or right hand?";
+char *no_ring = "there's no ring on that hand";
+short stealthy;
+short r_rings;
+short add_strength;
+short e_rings;
+short regeneration;
+short ring_exp;
+short auto_search;
+boolean r_teleport;
+boolean r_see_invisible;
+boolean sustain_strength;
+boolean maintain_armor;
+
+extern char *curse_message;
+extern boolean wizard;
+
+put_on_ring()
+{
+ short ch;
+ char desc[DCOLS];
+ object *ring;
+
+ if (r_rings == 2) {
+ message("wearing two rings already", 0);
+ return;
+ }
+ if ((ch = pack_letter("put on what?", RING)) == CANCEL) {
+ return;
+ }
+ if (!(ring = get_letter_object(ch))) {
+ message("no such item.", 0);
+ return;
+ }
+ if (!(ring->what_is & RING)) {
+ message("that's not a ring", 0);
+ return;
+ }
+ if (ring->in_use_flags & (ON_LEFT_HAND | ON_RIGHT_HAND)) {
+ message("that ring is already being worn", 0);
+ return;
+ }
+ if (r_rings == 1) {
+ ch = (rogue.left_ring ? 'r' : 'l');
+ } else {
+ message(left_or_right, 0);
+ do {
+ ch = rgetchar();
+ } while ((ch != CANCEL) && (ch != 'l') && (ch != 'r') && (ch != '\n') &&
+ (ch != '\r'));
+ }
+ if ((ch != 'l') && (ch != 'r')) {
+ check_message();
+ return;
+ }
+ if (((ch == 'l') && rogue.left_ring)||((ch == 'r') && rogue.right_ring)) {
+ check_message();
+ message("there's already a ring on that hand", 0);
+ return;
+ }
+ if (ch == 'l') {
+ do_put_on(ring, 1);
+ } else {
+ do_put_on(ring, 0);
+ }
+ ring_stats(1);
+ check_message();
+ get_desc(ring, desc);
+ message(desc, 0);
+ (void) reg_move();
+}
+
+/*
+ * Do not call ring_stats() from within do_put_on(). It will cause
+ * serious problems when do_put_on() is called from read_pack() in restore().
+ */
+
+do_put_on(ring, on_left)
+object *ring;
+boolean on_left;
+{
+ if (on_left) {
+ ring->in_use_flags |= ON_LEFT_HAND;
+ rogue.left_ring = ring;
+ } else {
+ ring->in_use_flags |= ON_RIGHT_HAND;
+ rogue.right_ring = ring;
+ }
+}
+
+remove_ring()
+{
+ boolean left = 0, right = 0;
+ short ch;
+ char buf[DCOLS];
+ object *ring;
+
+ if (r_rings == 0) {
+ inv_rings();
+ } else if (rogue.left_ring && !rogue.right_ring) {
+ left = 1;
+ } else if (!rogue.left_ring && rogue.right_ring) {
+ right = 1;
+ } else {
+ message(left_or_right, 0);
+ do {
+ ch = rgetchar();
+ } while ((ch != CANCEL) && (ch != 'l') && (ch != 'r') &&
+ (ch != '\n') && (ch != '\r'));
+ left = (ch == 'l');
+ right = (ch == 'r');
+ check_message();
+ }
+ if (left || right) {
+ if (left) {
+ if (rogue.left_ring) {
+ ring = rogue.left_ring;
+ } else {
+ message(no_ring, 0);
+ }
+ } else {
+ if (rogue.right_ring) {
+ ring = rogue.right_ring;
+ } else {
+ message(no_ring, 0);
+ }
+ }
+ if (ring->is_cursed) {
+ message(curse_message, 0);
+ } else {
+ un_put_on(ring);
+ (void) strcpy(buf, "removed ");
+ get_desc(ring, buf + 8);
+ message(buf, 0);
+ (void) reg_move();
+ }
+ }
+}
+
+un_put_on(ring)
+object *ring;
+{
+ if (ring && (ring->in_use_flags & ON_LEFT_HAND)) {
+ ring->in_use_flags &= (~ON_LEFT_HAND);
+ rogue.left_ring = 0;
+ } else if (ring && (ring->in_use_flags & ON_RIGHT_HAND)) {
+ ring->in_use_flags &= (~ON_RIGHT_HAND);
+ rogue.right_ring = 0;
+ }
+ ring_stats(1);
+}
+
+gr_ring(ring, assign_wk)
+object *ring;
+boolean assign_wk;
+{
+ ring->what_is = RING;
+ if (assign_wk) {
+ ring->which_kind = get_rand(0, (RINGS - 1));
+ }
+ ring->class = 0;
+
+ switch(ring->which_kind) {
+ /*
+ case STEALTH:
+ break;
+ case SLOW_DIGEST:
+ break;
+ case REGENERATION:
+ break;
+ case R_SEE_INVISIBLE:
+ break;
+ case SUSTAIN_STRENGTH:
+ break;
+ case R_MAINTAIN_ARMOR:
+ break;
+ case SEARCHING:
+ break;
+ */
+ case R_TELEPORT:
+ ring->is_cursed = 1;
+ break;
+ case ADD_STRENGTH:
+ case DEXTERITY:
+ while ((ring->class = (get_rand(0, 4) - 2)) == 0) ;
+ ring->is_cursed = (ring->class < 0);
+ break;
+ case ADORNMENT:
+ ring->is_cursed = coin_toss();
+ break;
+ }
+}
+
+inv_rings()
+{
+ char buf[DCOLS];
+
+ if (r_rings == 0) {
+ message("not wearing any rings", 0);
+ } else {
+ if (rogue.left_ring) {
+ get_desc(rogue.left_ring, buf);
+ message(buf, 0);
+ }
+ if (rogue.right_ring) {
+ get_desc(rogue.right_ring, buf);
+ message(buf, 0);
+ }
+ }
+ if (wizard) {
+ sprintf(buf, "ste %d, r_r %d, e_r %d, r_t %d, s_s %d, a_s %d, reg %d, r_e %d, s_i %d, m_a %d, aus %d",
+ stealthy, r_rings, e_rings, r_teleport, sustain_strength,
+ add_strength, regeneration, ring_exp, r_see_invisible,
+ maintain_armor, auto_search);
+ message(buf, 0);
+ }
+}
+
+ring_stats(pr)
+boolean pr;
+{
+ short i;
+ object *ring;
+
+ stealthy = 0;
+ r_rings = 0;
+ e_rings = 0;
+ r_teleport = 0;
+ sustain_strength = 0;
+ add_strength = 0;
+ regeneration = 0;
+ ring_exp = 0;
+ r_see_invisible = 0;
+ maintain_armor = 0;
+ auto_search = 0;
+
+ for (i = 0; i < 2; i++) {
+ if (!(ring = ((i == 0) ? rogue.left_ring : rogue.right_ring))) {
+ continue;
+ }
+ r_rings++;
+ e_rings++;
+ switch(ring->which_kind) {
+ case STEALTH:
+ stealthy++;
+ break;
+ case R_TELEPORT:
+ r_teleport = 1;
+ break;
+ case REGENERATION:
+ regeneration++;
+ break;
+ case SLOW_DIGEST:
+ e_rings -= 2;
+ break;
+ case ADD_STRENGTH:
+ add_strength += ring->class;
+ break;
+ case SUSTAIN_STRENGTH:
+ sustain_strength = 1;
+ break;
+ case DEXTERITY:
+ ring_exp += ring->class;
+ break;
+ case ADORNMENT:
+ break;
+ case R_SEE_INVISIBLE:
+ r_see_invisible = 1;
+ break;
+ case MAINTAIN_ARMOR:
+ maintain_armor = 1;
+ break;
+ case SEARCHING:
+ auto_search += 2;
+ break;
+ }
+ }
+ if (pr) {
+ print_stats(STAT_STRENGTH);
+ relight();
+ }
+}
diff --git a/rogue/rogue.6 b/rogue/rogue.6
new file mode 100644
index 00000000..bad531eb
--- /dev/null
+++ b/rogue/rogue.6
@@ -0,0 +1,113 @@
+.\" Copyright (c) 1988 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)rogue.6 6.5 (Berkeley) 6/23/90
+.\"
+.TH ROGUE 6 "June 23, 1990"
+.UC 4
+.SH NAME
+rogue \- Exploring The Dungeons of Doom
+.SH SYNOPSIS
+.B /usr/games/rogue
+[
+.B \-r
+]
+[
+.I save_file
+]
+[
+.B \-s
+]
+[
+.B \-d
+]
+.SH DESCRIPTION
+.PP
+.I Rogue
+is a computer fantasy game with a new twist. It is crt oriented and the
+object of the game is to survive the attacks of various monsters and get
+a lot of gold, rather than the puzzle solving orientation of most computer
+fantasy games.
+.PP
+To get started you really only need to know two commands. The command
+.B ?
+will give you a list of the available commands and the command
+.B /
+will identify the things you see on the screen.
+.PP
+To win the game (as opposed to merely playing to beat other people's high
+scores) you must locate the Amulet of Yendor which is somewhere below
+the 20th level of the dungeon and get it out. Nobody has achieved this
+yet and if somebody does, they will probably go down in history as a hero
+among heroes.
+.PP
+When the game ends, either by your death, when you quit, or if you (by
+some miracle) manage to win,
+.I rogue
+will give you a list of the top-ten scorers. The scoring is based entirely
+upon how much gold you get. There is a 10% penalty for getting yourself
+killed.
+.PP
+If
+.I save_file
+is specified,
+rogue will be restored from the specified saved game file.
+.PP
+The
+.B \-s
+option will print out the list of scores.
+.PP
+For more detailed directions, read the document
+.I "A Guide to the Dungeons of Doom."
+.SH AUTHORS
+Timothy Stoehr,
+Michael C. Toy,
+Kenneth C. R. C. Arnold,
+Glenn Wichman
+.SH FILES
+.DT
+.ta \w'/usr/games/lib/rogue_roll\ \ \ 'u
+/usr/games/lib/rogue_roll Score file
+.br
+\fB~\fP/rogue.save Default save file
+.SH SEE ALSO
+Michael C. Toy
+and
+Kenneth C. R. C. Arnold,
+.I "A guide to the Dungeons of Doom"
+.SH BUGS
+.PP
+Probably infinite, although none are known.
+However,
+that Ice Monsters sometimes transfix you permanently is
+.I not
+a bug.
+It's a feature.
diff --git a/rogue/rogue.h b/rogue/rogue.h
new file mode 100644
index 00000000..9e3d67d6
--- /dev/null
+++ b/rogue/rogue.h
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timoth C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)rogue.h 5.6 (Berkeley) 2/28/91
+ */
+
+/*
+ * rogue.h
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) This notice shall not be removed.
+ * 2.) Credit shall not be taken for the creation of this source.
+ * 3.) This code is not to be traded, sold, or used for personal
+ * gain or profit.
+ */
+
+#define boolean char
+
+#define NOTHING ((unsigned short) 0)
+#define OBJECT ((unsigned short) 01)
+#define MONSTER ((unsigned short) 02)
+#define STAIRS ((unsigned short) 04)
+#define HORWALL ((unsigned short) 010)
+#define VERTWALL ((unsigned short) 020)
+#define DOOR ((unsigned short) 040)
+#define FLOOR ((unsigned short) 0100)
+#define TUNNEL ((unsigned short) 0200)
+#define TRAP ((unsigned short) 0400)
+#define HIDDEN ((unsigned short) 01000)
+
+#define ARMOR ((unsigned short) 01)
+#define WEAPON ((unsigned short) 02)
+#define SCROL ((unsigned short) 04)
+#define POTION ((unsigned short) 010)
+#define GOLD ((unsigned short) 020)
+#define FOOD ((unsigned short) 040)
+#define WAND ((unsigned short) 0100)
+#define RING ((unsigned short) 0200)
+#define AMULET ((unsigned short) 0400)
+#define ALL_OBJECTS ((unsigned short) 0777)
+
+#define LEATHER 0
+#define RINGMAIL 1
+#define SCALE 2
+#define CHAIN 3
+#define BANDED 4
+#define SPLINT 5
+#define PLATE 6
+#define ARMORS 7
+
+#define BOW 0
+#define DART 1
+#define ARROW 2
+#define DAGGER 3
+#define SHURIKEN 4
+#define MACE 5
+#define LONG_SWORD 6
+#define TWO_HANDED_SWORD 7
+#define WEAPONS 8
+
+#define MAX_PACK_COUNT 24
+
+#define PROTECT_ARMOR 0
+#define HOLD_MONSTER 1
+#define ENCH_WEAPON 2
+#define ENCH_ARMOR 3
+#define IDENTIFY 4
+#define TELEPORT 5
+#define SLEEP 6
+#define SCARE_MONSTER 7
+#define REMOVE_CURSE 8
+#define CREATE_MONSTER 9
+#define AGGRAVATE_MONSTER 10
+#define MAGIC_MAPPING 11
+#define CON_MON 12
+#define SCROLS 13
+
+#define INCREASE_STRENGTH 0
+#define RESTORE_STRENGTH 1
+#define HEALING 2
+#define EXTRA_HEALING 3
+#define POISON 4
+#define RAISE_LEVEL 5
+#define BLINDNESS 6
+#define HALLUCINATION 7
+#define DETECT_MONSTER 8
+#define DETECT_OBJECTS 9
+#define CONFUSION 10
+#define LEVITATION 11
+#define HASTE_SELF 12
+#define SEE_INVISIBLE 13
+#define POTIONS 14
+
+#define TELE_AWAY 0
+#define SLOW_MONSTER 1
+#define INVISIBILITY 2
+#define POLYMORPH 3
+#define HASTE_MONSTER 4
+#define MAGIC_MISSILE 5
+#define CANCELLATION 6
+#define DO_NOTHING 7
+#define DRAIN_LIFE 8
+#define COLD 9
+#define FIRE 10
+#define WANDS 11
+
+#define STEALTH 0
+#define R_TELEPORT 1
+#define REGENERATION 2
+#define SLOW_DIGEST 3
+#define ADD_STRENGTH 4
+#define SUSTAIN_STRENGTH 5
+#define DEXTERITY 6
+#define ADORNMENT 7
+#define R_SEE_INVISIBLE 8
+#define MAINTAIN_ARMOR 9
+#define SEARCHING 10
+#define RINGS 11
+
+#define RATION 0
+#define FRUIT 1
+
+#define NOT_USED ((unsigned short) 0)
+#define BEING_WIELDED ((unsigned short) 01)
+#define BEING_WORN ((unsigned short) 02)
+#define ON_LEFT_HAND ((unsigned short) 04)
+#define ON_RIGHT_HAND ((unsigned short) 010)
+#define ON_EITHER_HAND ((unsigned short) 014)
+#define BEING_USED ((unsigned short) 017)
+
+#define NO_TRAP -1
+#define TRAP_DOOR 0
+#define BEAR_TRAP 1
+#define TELE_TRAP 2
+#define DART_TRAP 3
+#define SLEEPING_GAS_TRAP 4
+#define RUST_TRAP 5
+#define TRAPS 6
+
+#define STEALTH_FACTOR 3
+#define R_TELE_PERCENT 8
+
+#define UNIDENTIFIED ((unsigned short) 00) /* MUST BE ZERO! */
+#define IDENTIFIED ((unsigned short) 01)
+#define CALLED ((unsigned short) 02)
+
+#define DROWS 24
+#define DCOLS 80
+#define NMESSAGES 5
+#define MAX_TITLE_LENGTH 30
+#define MAXSYLLABLES 40
+#define MAX_METAL 14
+#define WAND_MATERIALS 30
+#define GEMS 14
+
+#define GOLD_PERCENT 46
+
+#define MAX_OPT_LEN 40
+
+struct id {
+ short value;
+ char *title;
+ char *real;
+ unsigned short id_status;
+};
+
+/* The following #defines provide more meaningful names for some of the
+ * struct object fields that are used for monsters. This, since each monster
+ * and object (scrolls, potions, etc) are represented by a struct object.
+ * Ideally, this should be handled by some kind of union structure.
+ */
+
+#define m_damage damage
+#define hp_to_kill quantity
+#define m_char ichar
+#define first_level is_protected
+#define last_level is_cursed
+#define m_hit_chance class
+#define stationary_damage identified
+#define drop_percent which_kind
+#define trail_char d_enchant
+#define slowed_toggle quiver
+#define moves_confused hit_enchant
+#define nap_length picked_up
+#define disguise what_is
+#define next_monster next_object
+
+struct obj { /* comment is monster meaning */
+ unsigned long m_flags; /* monster flags */
+ char *damage; /* damage it does */
+ short quantity; /* hit points to kill */
+ short ichar; /* 'A' is for aquatar */
+ short kill_exp; /* exp for killing it */
+ short is_protected; /* level starts */
+ short is_cursed; /* level ends */
+ short class; /* chance of hitting you */
+ short identified; /* 'F' damage, 1,2,3... */
+ unsigned short which_kind; /* item carry/drop % */
+ short o_row, o_col, o; /* o is how many times stuck at o_row, o_col */
+ short row, col; /* current row, col */
+ short d_enchant; /* room char when detect_monster */
+ short quiver; /* monster slowed toggle */
+ short trow, tcol; /* target row, col */
+ short hit_enchant; /* how many moves is confused */
+ unsigned short what_is; /* imitator's charactor (?!%: */
+ short picked_up; /* sleep from wand of sleep */
+ unsigned short in_use_flags;
+ struct obj *next_object; /* next monster */
+};
+
+typedef struct obj object;
+
+#define INIT_AW (object*)0,(object*)0
+#define INIT_RINGS (object*)0,(object*)0
+#define INIT_HP 12,12
+#define INIT_STR 16,16
+#define INIT_EXP 1,0
+#define INIT_PACK {0}
+#define INIT_GOLD 0
+#define INIT_CHAR '@'
+#define INIT_MOVES 1250
+
+struct fightr {
+ object *armor;
+ object *weapon;
+ object *left_ring, *right_ring;
+ short hp_current;
+ short hp_max;
+ short str_current;
+ short str_max;
+ object pack;
+ long gold;
+ short exp;
+ long exp_points;
+ short row, col;
+ short fchar;
+ short moves_left;
+};
+
+typedef struct fightr fighter;
+
+struct dr {
+ short oth_room;
+ short oth_row,
+ oth_col;
+ short door_row,
+ door_col;
+};
+
+typedef struct dr door;
+
+struct rm {
+ short bottom_row, right_col, left_col, top_row;
+ door doors[4];
+ unsigned short is_room;
+};
+
+typedef struct rm room;
+
+#define MAXROOMS 9
+#define BIG_ROOM 10
+
+#define NO_ROOM -1
+
+#define PASSAGE -3 /* cur_room value */
+
+#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 10000001L
+#define MAX_GOLD 999999
+#define MAX_ARMOR 99
+#define MAX_HP 999
+#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
+
+struct tr {
+ short trap_type;
+ short trap_row, trap_col;
+};
+
+typedef struct tr trap;
+
+extern fighter rogue;
+extern room rooms[];
+extern trap traps[];
+extern unsigned short dungeon[DROWS][DCOLS];
+extern object level_objects;
+
+extern struct id id_scrolls[];
+extern struct id id_potions[];
+extern struct id id_wands[];
+extern struct id id_rings[];
+extern struct id id_weapons[];
+extern struct id id_armors[];
+
+extern object mon_tab[];
+extern object level_monsters;
+
+#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 DROPS_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|DROPS_LEVEL)
+
+#define WAKE_PERCENT 45
+#define FLIT_PERCENT 40
+#define PARTY_WAKE_PERCENT 75
+
+#define HYPOTHERMIA 1
+#define STARVATION 2
+#define POISON_DART 3
+#define QUIT 4
+#define WIN 5
+#define KFIRE 6
+
+#define UPWARD 0
+#define UPRIGHT 1
+#define RIGHT 2
+#define DOWNRIGHT 3
+#define DOWN 4
+#define DOWNLEFT 5
+#define LEFT 6
+#define UPLEFT 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
+
+/* external routine declarations.
+ */
+char *strcpy();
+char *strncpy();
+char *strcat();
+
+char *mon_name();
+char *get_ench_color();
+char *name_of();
+char *md_gln();
+char *md_getenv();
+char *md_malloc();
+boolean is_direction();
+boolean mon_sees();
+boolean mask_pack();
+boolean mask_room();
+boolean is_digit();
+boolean check_hunger();
+boolean reg_move();
+boolean md_df();
+boolean has_been_touched();
+object *add_to_pack();
+object *alloc_object();
+object *get_letter_object();
+object *gr_monster();
+object *get_thrown_at_monster();
+object *get_zapped_monster();
+object *check_duplicate();
+object *gr_object();
+object *object_at();
+object *pick_up();
+struct id *get_id_table();
+unsigned short gr_what_is();
+long rrandom();
+long lget_number();
+long xxx();
+void byebye(), onintr(), error_save();
+
+struct rogue_time {
+ short year; /* >= 1987 */
+ short month; /* 1 - 12 */
+ short day; /* 1 - 31 */
+ short hour; /* 0 - 23 */
+ short minute; /* 0 - 59 */
+ short second; /* 0 - 59 */
+};
+
+#ifdef CURSES
+struct _win_st {
+ short _cury, _curx;
+ short _maxy, _maxx;
+};
+
+typedef struct _win_st WINDOW;
+
+extern int LINES, COLS;
+extern WINDOW *curscr;
+extern char *CL;
+
+char *md_gdtcf();
+
+#else
+#include <curses.h>
+#endif
diff --git a/rogue/room.c b/rogue/room.c
new file mode 100644
index 00000000..1154e51a
--- /dev/null
+++ b/rogue/room.c
@@ -0,0 +1,649 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)room.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * room.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.h"
+
+room rooms[MAXROOMS];
+boolean rooms_visited[MAXROOMS];
+
+extern short blind;
+extern boolean detect_monster, jump, passgo, no_skull, ask_quit;
+extern char *nick_name, *fruit, *save_file, *press_space;
+
+#define NOPTS 7
+
+struct option {
+ char *prompt;
+ boolean is_bool;
+ char **strval;
+ boolean *bval;
+} options[NOPTS] = {
+ {
+ "Show position only at end of run (\"jump\"): ",
+ 1, (char **) 0, &jump
+ },
+ {
+ "Follow turnings in passageways (\"passgo\"): ",
+ 1, (char **) 0, &passgo
+ },
+ {
+ "Don't print skull when killed (\"noskull\" or \"notombstone\"): ",
+ 1, (char **) 0, &no_skull
+ },
+ {
+ "Ask player before saying 'Okay, bye-bye!' (\"askquit\"): ",
+ 1, (char **) 0, &ask_quit
+ },
+ {
+ "Name (\"name\"): ",
+ 0, &nick_name
+ },
+ {
+ "Fruit (\"fruit\"): ",
+ 0, &fruit
+ },
+ {
+ "Save file (\"file\"): ",
+ 0, &save_file
+ }
+};
+
+light_up_room(rn)
+int rn;
+{
+ short i, j;
+
+ if (!blind) {
+ for (i = rooms[rn].top_row;
+ i <= rooms[rn].bottom_row; i++) {
+ for (j = rooms[rn].left_col;
+ j <= rooms[rn].right_col; j++) {
+ if (dungeon[i][j] & MONSTER) {
+ object *monster;
+
+ if (monster = object_at(&level_monsters, i, j)) {
+ dungeon[monster->row][monster->col] &= (~MONSTER);
+ monster->trail_char =
+ get_dungeon_char(monster->row, monster->col);
+ dungeon[monster->row][monster->col] |= MONSTER;
+ }
+ }
+ mvaddch(i, j, get_dungeon_char(i, j));
+ }
+ }
+ mvaddch(rogue.row, rogue.col, rogue.fchar);
+ }
+}
+
+light_passage(row, col)
+{
+ short i, j, i_end, j_end;
+
+ if (blind) {
+ return;
+ }
+ i_end = (row < (DROWS-2)) ? 1 : 0;
+ j_end = (col < (DCOLS-1)) ? 1 : 0;
+
+ for (i = ((row > MIN_ROW) ? -1 : 0); i <= i_end; i++) {
+ for (j = ((col > 0) ? -1 : 0); j <= j_end; j++) {
+ if (can_move(row, col, row+i, col+j)) {
+ mvaddch(row+i, col+j, get_dungeon_char(row+i, col+j));
+ }
+ }
+ }
+}
+
+darken_room(rn)
+short rn;
+{
+ short i, j;
+
+ for (i = rooms[rn].top_row + 1; i < rooms[rn].bottom_row; i++) {
+ for (j = rooms[rn].left_col + 1; j < rooms[rn].right_col; j++) {
+ if (blind) {
+ mvaddch(i, j, ' ');
+ } else {
+ if (!(dungeon[i][j] & (OBJECT | STAIRS)) &&
+ !(detect_monster && (dungeon[i][j] & MONSTER))) {
+ if (!imitating(i, j)) {
+ mvaddch(i, j, ' ');
+ }
+ if ((dungeon[i][j] & TRAP) && (!(dungeon[i][j] & HIDDEN))) {
+ mvaddch(i, j, '^');
+ }
+ }
+ }
+ }
+ }
+}
+
+get_dungeon_char(row, col)
+register row, col;
+{
+ register unsigned short mask = dungeon[row][col];
+
+ if (mask & MONSTER) {
+ return(gmc_row_col(row, col));
+ }
+ if (mask & OBJECT) {
+ object *obj;
+
+ obj = object_at(&level_objects, row, col);
+ return(get_mask_char(obj->what_is));
+ }
+ if (mask & (TUNNEL | STAIRS | HORWALL | VERTWALL | FLOOR | DOOR)) {
+ if ((mask & (TUNNEL| STAIRS)) && (!(mask & HIDDEN))) {
+ return(((mask & STAIRS) ? '%' : '#'));
+ }
+ if (mask & HORWALL) {
+ return('-');
+ }
+ if (mask & VERTWALL) {
+ return('|');
+ }
+ if (mask & FLOOR) {
+ if (mask & TRAP) {
+ if (!(dungeon[row][col] & HIDDEN)) {
+ return('^');
+ }
+ }
+ return('.');
+ }
+ if (mask & DOOR) {
+ if (mask & HIDDEN) {
+ if (((col > 0) && (dungeon[row][col-1] & HORWALL)) ||
+ ((col < (DCOLS-1)) && (dungeon[row][col+1] & HORWALL))) {
+ return('-');
+ } else {
+ return('|');
+ }
+ } else {
+ return('+');
+ }
+ }
+ }
+ return(' ');
+}
+
+get_mask_char(mask)
+register unsigned short mask;
+{
+ switch(mask) {
+ case SCROL:
+ return('?');
+ case POTION:
+ return('!');
+ case GOLD:
+ return('*');
+ case FOOD:
+ return(':');
+ case WAND:
+ return('/');
+ case ARMOR:
+ return(']');
+ case WEAPON:
+ return(')');
+ case RING:
+ return('=');
+ case AMULET:
+ return(',');
+ default:
+ return('~'); /* unknown, something is wrong */
+ }
+}
+
+gr_row_col(row, col, mask)
+short *row, *col;
+unsigned short mask;
+{
+ short rn;
+ short r, c;
+
+ do {
+ r = get_rand(MIN_ROW, DROWS-2);
+ c = get_rand(0, DCOLS-1);
+ rn = get_room_number(r, c);
+ } while ((rn == NO_ROOM) ||
+ (!(dungeon[r][c] & mask)) ||
+ (dungeon[r][c] & (~mask)) ||
+ (!(rooms[rn].is_room & (R_ROOM | R_MAZE))) ||
+ ((r == rogue.row) && (c == rogue.col)));
+
+ *row = r;
+ *col = c;
+}
+
+gr_room()
+{
+ short i;
+
+ do {
+ i = get_rand(0, MAXROOMS-1);
+ } while (!(rooms[i].is_room & (R_ROOM | R_MAZE)));
+
+ return(i);
+}
+
+party_objects(rn)
+{
+ short i, j, nf = 0;
+ object *obj;
+ short n, N, row, col;
+ boolean found;
+
+ N = ((rooms[rn].bottom_row - rooms[rn].top_row) - 1) *
+ ((rooms[rn].right_col - rooms[rn].left_col) - 1);
+ n = get_rand(5, 10);
+ if (n > N) {
+ n = N - 2;
+ }
+ for (i = 0; i < n; i++) {
+ for (j = found = 0; ((!found) && (j < 250)); j++) {
+ row = get_rand(rooms[rn].top_row+1,
+ rooms[rn].bottom_row-1);
+ col = get_rand(rooms[rn].left_col+1,
+ rooms[rn].right_col-1);
+ if ((dungeon[row][col] == FLOOR) || (dungeon[row][col] == TUNNEL)) {
+ found = 1;
+ }
+ }
+ if (found) {
+ obj = gr_object();
+ place_at(obj, row, col);
+ nf++;
+ }
+ }
+ return(nf);
+}
+
+get_room_number(row, col)
+register row, col;
+{
+ short i;
+
+ for (i = 0; i < MAXROOMS; i++) {
+ if ((row >= rooms[i].top_row) && (row <= rooms[i].bottom_row) &&
+ (col >= rooms[i].left_col) && (col <= rooms[i].right_col)) {
+ return(i);
+ }
+ }
+ return(NO_ROOM);
+}
+
+is_all_connected()
+{
+ short i, starting_room;
+
+ for (i = 0; i < MAXROOMS; i++) {
+ rooms_visited[i] = 0;
+ if (rooms[i].is_room & (R_ROOM | R_MAZE)) {
+ starting_room = i;
+ }
+ }
+
+ visit_rooms(starting_room);
+
+ for (i = 0; i < MAXROOMS; i++) {
+ if ((rooms[i].is_room & (R_ROOM | R_MAZE)) && (!rooms_visited[i])) {
+ return(0);
+ }
+ }
+ return(1);
+}
+
+visit_rooms(rn)
+int rn;
+{
+ short i;
+ short oth_rn;
+
+ rooms_visited[rn] = 1;
+
+ for (i = 0; i < 4; i++) {
+ oth_rn = rooms[rn].doors[i].oth_room;
+ if ((oth_rn >= 0) && (!rooms_visited[oth_rn])) {
+ visit_rooms(oth_rn);
+ }
+ }
+}
+
+draw_magic_map()
+{
+ short i, j, ch, och;
+ unsigned short mask = (HORWALL | VERTWALL | DOOR | TUNNEL | TRAP | STAIRS |
+ MONSTER);
+ unsigned short s;
+
+ for (i = 0; i < DROWS; i++) {
+ for (j = 0; j < DCOLS; j++) {
+ s = dungeon[i][j];
+ if (s & mask) {
+ if (((ch = mvinch(i, j)) == ' ') ||
+ ((ch >= 'A') && (ch <= 'Z')) || (s & (TRAP | HIDDEN))) {
+ och = ch;
+ dungeon[i][j] &= (~HIDDEN);
+ if (s & HORWALL) {
+ ch = '-';
+ } else if (s & VERTWALL) {
+ ch = '|';
+ } else if (s & DOOR) {
+ ch = '+';
+ } else if (s & TRAP) {
+ ch = '^';
+ } else if (s & STAIRS) {
+ ch = '%';
+ } else if (s & TUNNEL) {
+ ch = '#';
+ } else {
+ continue;
+ }
+ if ((!(s & MONSTER)) || (och == ' ')) {
+ addch(ch);
+ }
+ if (s & MONSTER) {
+ object *monster;
+
+ if (monster = object_at(&level_monsters, i, j)) {
+ monster->trail_char = ch;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+dr_course(monster, entering, row, col)
+object *monster;
+boolean entering;
+short row, col;
+{
+ short i, j, k, rn;
+ short r, rr;
+
+ monster->row = row;
+ monster->col = col;
+
+ if (mon_sees(monster, rogue.row, rogue.col)) {
+ monster->trow = NO_ROOM;
+ return;
+ }
+ rn = get_room_number(row, col);
+
+ if (entering) { /* entering room */
+ /* look for door to some other room */
+ r = get_rand(0, MAXROOMS-1);
+ for (i = 0; i < MAXROOMS; i++) {
+ rr = (r + i) % MAXROOMS;
+ if ((!(rooms[rr].is_room & (R_ROOM | R_MAZE))) || (rr == rn)) {
+ continue;
+ }
+ for (k = 0; k < 4; k++) {
+ if (rooms[rr].doors[k].oth_room == rn) {
+ monster->trow = rooms[rr].doors[k].oth_row;
+ monster->tcol = rooms[rr].doors[k].oth_col;
+ if ((monster->trow == row) &&
+ (monster->tcol == col)) {
+ continue;
+ }
+ return;
+ }
+ }
+ }
+ /* look for door to dead end */
+ for (i = rooms[rn].top_row; i <= rooms[rn].bottom_row; i++) {
+ for (j = rooms[rn].left_col; j <= rooms[rn].right_col; j++) {
+ if ((i != monster->row) && (j != monster->col) &&
+ (dungeon[i][j] & DOOR)) {
+ monster->trow = i;
+ monster->tcol = j;
+ return;
+ }
+ }
+ }
+ /* return monster to room that he came from */
+ for (i = 0; i < MAXROOMS; i++) {
+ for (j = 0; j < 4; j++) {
+ if (rooms[i].doors[j].oth_room == rn) {
+ for (k = 0; k < 4; k++) {
+ if (rooms[rn].doors[k].oth_room == i) {
+ monster->trow = rooms[rn].doors[k].oth_row;
+ monster->tcol = rooms[rn].doors[k].oth_col;
+ return;
+ }
+ }
+ }
+ }
+ }
+ /* no place to send monster */
+ monster->trow = NO_ROOM;
+ } else { /* exiting room */
+ if (!get_oth_room(rn, &row, &col)) {
+ monster->trow = NO_ROOM;
+ } else {
+ monster->trow = row;
+ monster->tcol = col;
+ }
+ }
+}
+
+get_oth_room(rn, row, col)
+short rn, *row, *col;
+{
+ short d = -1;
+
+ if (*row == rooms[rn].top_row) {
+ d = UPWARD/2;
+ } else if (*row == rooms[rn].bottom_row) {
+ d = DOWN/2;
+ } else if (*col == rooms[rn].left_col) {
+ d = LEFT/2;
+ } else if (*col == rooms[rn].right_col) {
+ d = RIGHT/2;
+ }
+ if ((d != -1) && (rooms[rn].doors[d].oth_room >= 0)) {
+ *row = rooms[rn].doors[d].oth_row;
+ *col = rooms[rn].doors[d].oth_col;
+ return(1);
+ }
+ return(0);
+}
+
+edit_opts()
+{
+ char save[NOPTS+1][DCOLS];
+ short i, j;
+ short ch;
+ boolean done = 0;
+ char buf[MAX_OPT_LEN + 2];
+
+ for (i = 0; i < NOPTS+1; i++) {
+ for (j = 0; j < DCOLS; j++) {
+ save[i][j] = mvinch(i, j);
+ }
+ if (i < NOPTS) {
+ opt_show(i);
+ }
+ }
+ opt_go(0);
+ i = 0;
+
+ while (!done) {
+ refresh();
+ ch = rgetchar();
+CH:
+ switch(ch) {
+ case '\033':
+ done = 1;
+ break;
+ case '\012':
+ case '\015':
+ if (i == (NOPTS - 1)) {
+ mvaddstr(NOPTS, 0, press_space);
+ refresh();
+ wait_for_ack();
+ done = 1;
+ } else {
+ i++;
+ opt_go(i);
+ }
+ break;
+ case '-':
+ if (i > 0) {
+ opt_go(--i);
+ } else {
+ sound_bell();
+ }
+ break;
+ case 't':
+ case 'T':
+ case 'f':
+ case 'F':
+ if (options[i].is_bool) {
+ *(options[i].bval) = (((ch == 't') || (ch == 'T')) ? 1 : 0);
+ opt_show(i);
+ opt_go(++i);
+ break;
+ }
+ default:
+ if (options[i].is_bool) {
+ sound_bell();
+ break;
+ }
+ j = 0;
+ if ((ch == '\010') || ((ch >= ' ') && (ch <= '~'))) {
+ opt_erase(i);
+ do {
+ if ((ch >= ' ') && (ch <= '~') && (j < MAX_OPT_LEN)) {
+ buf[j++] = ch;
+ buf[j] = '\0';
+ addch(ch);
+ } else if ((ch == '\010') && (j > 0)) {
+ buf[--j] = '\0';
+ move(i, j + strlen(options[i].prompt));
+ addch(' ');
+ move(i, j + strlen(options[i].prompt));
+ }
+ refresh();
+ ch = rgetchar();
+ } while ((ch != '\012') && (ch != '\015') && (ch != '\033'));
+ if (j != 0) {
+ (void) strcpy(*(options[i].strval), buf);
+ }
+ opt_show(i);
+ goto CH;
+ } else {
+ sound_bell();
+ }
+ break;
+ }
+ }
+
+ for (i = 0; i < NOPTS+1; i++) {
+ move(i, 0);
+ for (j = 0; j < DCOLS; j++) {
+ addch(save[i][j]);
+ }
+ }
+}
+
+opt_show(i)
+int i;
+{
+ char *s;
+ struct option *opt = &options[i];
+
+ opt_erase(i);
+
+ if (opt->is_bool) {
+ s = *(opt->bval) ? "True" : "False";
+ } else {
+ s = *(opt->strval);
+ }
+ addstr(s);
+}
+
+opt_erase(i)
+int i;
+{
+ struct option *opt = &options[i];
+
+ mvaddstr(i, 0, opt->prompt);
+ clrtoeol();
+}
+
+opt_go(i)
+int i;
+{
+ move(i, strlen(options[i].prompt));
+}
+
+do_shell()
+{
+#ifdef UNIX
+ char *sh;
+
+ md_ignore_signals();
+ if (!(sh = md_getenv("SHELL"))) {
+ sh = "/bin/sh";
+ }
+ move(LINES-1, 0);
+ refresh();
+ stop_window();
+ printf("\nCreating new shell...\n");
+ md_shell(sh);
+ start_window();
+ wrefresh(curscr);
+ md_heed_signals();
+#endif
+}
diff --git a/rogue/save.c b/rogue/save.c
new file mode 100644
index 00000000..54300e4e
--- /dev/null
+++ b/rogue/save.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)save.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * save.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 <stdio.h>
+#include "rogue.h"
+
+short write_failed = 0;
+char *save_file = (char *) 0;
+
+extern boolean detect_monster;
+extern short cur_level, max_level;
+extern char hunger_str[];
+extern char login_name[];
+extern short party_room;
+extern short foods;
+extern boolean is_wood[];
+extern short cur_room;
+extern boolean being_held;
+extern short bear_trap;
+extern short halluc;
+extern short blind;
+extern short confused;
+extern short levitate;
+extern short haste_self;
+extern boolean see_invisible;
+extern boolean detect_monster;
+extern boolean wizard;
+extern boolean score_only;
+extern short m_moves;
+
+extern boolean msg_cleared;
+
+save_game()
+{
+ char fname[64];
+
+ if (!get_input_line("file name?", save_file, fname, "game not saved",
+ 0, 1)) {
+ return;
+ }
+ check_message();
+ message(fname, 0);
+ save_into_file(fname);
+}
+
+save_into_file(sfile)
+char *sfile;
+{
+ FILE *fp;
+ int file_id;
+ char name_buffer[80];
+ char *hptr;
+ struct rogue_time rt_buf;
+
+ if (sfile[0] == '~') {
+ if (hptr = md_getenv("HOME")) {
+ (void) strcpy(name_buffer, hptr);
+ (void) strcat(name_buffer, sfile+1);
+ sfile = name_buffer;
+ }
+ }
+ if ( ((fp = fopen(sfile, "w")) == NULL) ||
+ ((file_id = md_get_file_id(sfile)) == -1)) {
+ message("problem accessing the save file", 0);
+ return;
+ }
+ md_ignore_signals();
+ write_failed = 0;
+ (void) xxx(1);
+ r_write(fp, (char *) &detect_monster, sizeof(detect_monster));
+ r_write(fp, (char *) &cur_level, sizeof(cur_level));
+ r_write(fp, (char *) &max_level, sizeof(max_level));
+ write_string(hunger_str, fp);
+ write_string(login_name, fp);
+ r_write(fp, (char *) &party_room, sizeof(party_room));
+ write_pack(&level_monsters, fp);
+ write_pack(&level_objects, fp);
+ r_write(fp, (char *) &file_id, sizeof(file_id));
+ rw_dungeon(fp, 1);
+ r_write(fp, (char *) &foods, sizeof(foods));
+ r_write(fp, (char *) &rogue, sizeof(fighter));
+ write_pack(&rogue.pack, fp);
+ rw_id(id_potions, fp, POTIONS, 1);
+ rw_id(id_scrolls, fp, SCROLS, 1);
+ rw_id(id_wands, fp, WANDS, 1);
+ rw_id(id_rings, fp, RINGS, 1);
+ r_write(fp, (char *) traps, (MAX_TRAPS * sizeof(trap)));
+ r_write(fp, (char *) is_wood, (WANDS * sizeof(boolean)));
+ r_write(fp, (char *) &cur_room, sizeof(cur_room));
+ rw_rooms(fp, 1);
+ r_write(fp, (char *) &being_held, sizeof(being_held));
+ r_write(fp, (char *) &bear_trap, sizeof(bear_trap));
+ r_write(fp, (char *) &halluc, sizeof(halluc));
+ r_write(fp, (char *) &blind, sizeof(blind));
+ r_write(fp, (char *) &confused, sizeof(confused));
+ r_write(fp, (char *) &levitate, sizeof(levitate));
+ r_write(fp, (char *) &haste_self, sizeof(haste_self));
+ r_write(fp, (char *) &see_invisible, sizeof(see_invisible));
+ r_write(fp, (char *) &detect_monster, sizeof(detect_monster));
+ r_write(fp, (char *) &wizard, sizeof(wizard));
+ r_write(fp, (char *) &score_only, sizeof(score_only));
+ r_write(fp, (char *) &m_moves, sizeof(m_moves));
+ md_gct(&rt_buf);
+ rt_buf.second += 10; /* allow for some processing time */
+ r_write(fp, (char *) &rt_buf, sizeof(rt_buf));
+ fclose(fp);
+
+ if (write_failed) {
+ (void) md_df(sfile); /* delete file */
+ } else {
+ clean_up("");
+ }
+}
+
+restore(fname)
+char *fname;
+{
+ FILE *fp;
+ struct rogue_time saved_time, mod_time;
+ char buf[4];
+ char tbuf[40];
+ int new_file_id, saved_file_id;
+
+ if ( ((new_file_id = md_get_file_id(fname)) == -1) ||
+ ((fp = fopen(fname, "r")) == NULL)) {
+ clean_up("cannot open file");
+ }
+ if (md_link_count(fname) > 1) {
+ clean_up("file has link");
+ }
+ (void) xxx(1);
+ r_read(fp, (char *) &detect_monster, sizeof(detect_monster));
+ r_read(fp, (char *) &cur_level, sizeof(cur_level));
+ r_read(fp, (char *) &max_level, sizeof(max_level));
+ read_string(hunger_str, fp);
+
+ (void) strcpy(tbuf, login_name);
+ read_string(login_name, fp);
+ if (strcmp(tbuf, login_name)) {
+ clean_up("you're not the original player");
+ }
+
+ r_read(fp, (char *) &party_room, sizeof(party_room));
+ read_pack(&level_monsters, fp, 0);
+ read_pack(&level_objects, fp, 0);
+ r_read(fp, (char *) &saved_file_id, sizeof(saved_file_id));
+ if (new_file_id != saved_file_id) {
+ clean_up("sorry, saved game is not in the same file");
+ }
+ rw_dungeon(fp, 0);
+ r_read(fp, (char *) &foods, sizeof(foods));
+ r_read(fp, (char *) &rogue, sizeof(fighter));
+ read_pack(&rogue.pack, fp, 1);
+ rw_id(id_potions, fp, POTIONS, 0);
+ rw_id(id_scrolls, fp, SCROLS, 0);
+ rw_id(id_wands, fp, WANDS, 0);
+ rw_id(id_rings, fp, RINGS, 0);
+ r_read(fp, (char *) traps, (MAX_TRAPS * sizeof(trap)));
+ r_read(fp, (char *) is_wood, (WANDS * sizeof(boolean)));
+ r_read(fp, (char *) &cur_room, sizeof(cur_room));
+ rw_rooms(fp, 0);
+ r_read(fp, (char *) &being_held, sizeof(being_held));
+ r_read(fp, (char *) &bear_trap, sizeof(bear_trap));
+ r_read(fp, (char *) &halluc, sizeof(halluc));
+ r_read(fp, (char *) &blind, sizeof(blind));
+ r_read(fp, (char *) &confused, sizeof(confused));
+ r_read(fp, (char *) &levitate, sizeof(levitate));
+ r_read(fp, (char *) &haste_self, sizeof(haste_self));
+ r_read(fp, (char *) &see_invisible, sizeof(see_invisible));
+ r_read(fp, (char *) &detect_monster, sizeof(detect_monster));
+ r_read(fp, (char *) &wizard, sizeof(wizard));
+ r_read(fp, (char *) &score_only, sizeof(score_only));
+ r_read(fp, (char *) &m_moves, sizeof(m_moves));
+ r_read(fp, (char *) &saved_time, sizeof(saved_time));
+
+ if (fread(buf, sizeof(char), 1, fp) > 0) {
+ clear();
+ clean_up("extra characters in file");
+ }
+
+ md_gfmt(fname, &mod_time); /* get file modification time */
+
+ if (has_been_touched(&saved_time, &mod_time)) {
+ clear();
+ clean_up("sorry, file has been touched");
+ }
+ if ((!wizard) && !md_df(fname)) {
+ clean_up("cannot delete file");
+ }
+ msg_cleared = 0;
+ ring_stats(0);
+ fclose(fp);
+}
+
+write_pack(pack, fp)
+object *pack;
+FILE *fp;
+{
+ object t;
+
+ while (pack = pack->next_object) {
+ r_write(fp, (char *) pack, sizeof(object));
+ }
+ t.ichar = t.what_is = 0;
+ r_write(fp, (char *) &t, sizeof(object));
+}
+
+read_pack(pack, fp, is_rogue)
+object *pack;
+FILE *fp;
+boolean is_rogue;
+{
+ object read_obj, *new_obj;
+
+ for (;;) {
+ r_read(fp, (char *) &read_obj, sizeof(object));
+ if (read_obj.ichar == 0) {
+ pack->next_object = (object *) 0;
+ break;
+ }
+ new_obj = alloc_object();
+ *new_obj = read_obj;
+ if (is_rogue) {
+ if (new_obj->in_use_flags & BEING_WORN) {
+ do_wear(new_obj);
+ } else if (new_obj->in_use_flags & BEING_WIELDED) {
+ do_wield(new_obj);
+ } else if (new_obj->in_use_flags & (ON_EITHER_HAND)) {
+ do_put_on(new_obj,
+ ((new_obj->in_use_flags & ON_LEFT_HAND) ? 1 : 0));
+ }
+ }
+ pack->next_object = new_obj;
+ pack = new_obj;
+ }
+}
+
+rw_dungeon(fp, rw)
+FILE *fp;
+boolean rw;
+{
+ short i, j;
+ char buf[DCOLS];
+
+ for (i = 0; i < DROWS; i++) {
+ if (rw) {
+ r_write(fp, (char *) dungeon[i], (DCOLS * sizeof(dungeon[0][0])));
+ for (j = 0; j < DCOLS; j++) {
+ buf[j] = mvinch(i, j);
+ }
+ r_write(fp, buf, DCOLS);
+ } else {
+ r_read(fp, (char *) dungeon[i], (DCOLS * sizeof(dungeon[0][0])));
+ r_read(fp, buf, DCOLS);
+ for (j = 0; j < DCOLS; j++) {
+ mvaddch(i, j, buf[j]);
+ }
+ }
+ }
+}
+
+rw_id(id_table, fp, n, wr)
+struct id id_table[];
+FILE *fp;
+int n;
+boolean wr;
+{
+ short i;
+
+ for (i = 0; i < n; i++) {
+ if (wr) {
+ r_write(fp, (char *) &(id_table[i].value), sizeof(short));
+ r_write(fp, (char *) &(id_table[i].id_status),
+ sizeof(unsigned short));
+ write_string(id_table[i].title, fp);
+ } else {
+ r_read(fp, (char *) &(id_table[i].value), sizeof(short));
+ r_read(fp, (char *) &(id_table[i].id_status),
+ sizeof(unsigned short));
+ read_string(id_table[i].title, fp);
+ }
+ }
+}
+
+write_string(s, fp)
+char *s;
+FILE *fp;
+{
+ short n;
+
+ n = strlen(s) + 1;
+ xxxx(s, n);
+ r_write(fp, (char *) &n, sizeof(short));
+ r_write(fp, s, n);
+}
+
+read_string(s, fp)
+char *s;
+FILE *fp;
+{
+ short n;
+
+ r_read(fp, (char *) &n, sizeof(short));
+ r_read(fp, s, n);
+ xxxx(s, n);
+}
+
+rw_rooms(fp, rw)
+FILE *fp;
+boolean rw;
+{
+ short i;
+
+ for (i = 0; i < MAXROOMS; i++) {
+ rw ? r_write(fp, (char *) (rooms + i), sizeof(room)) :
+ r_read(fp, (char *) (rooms + i), sizeof(room));
+ }
+}
+
+r_read(fp, buf, n)
+FILE *fp;
+char *buf;
+int n;
+{
+ if (fread(buf, sizeof(char), n, fp) != n) {
+ clean_up("read() failed, don't know why");
+ }
+}
+
+r_write(fp, buf, n)
+FILE *fp;
+char *buf;
+int n;
+{
+ if (!write_failed) {
+ if (fwrite(buf, sizeof(char), n, fp) != n) {
+ message("write() failed, don't know why", 0);
+ sound_bell();
+ write_failed = 1;
+ }
+ }
+}
+
+boolean
+has_been_touched(saved_time, mod_time)
+struct rogue_time *saved_time, *mod_time;
+{
+ if (saved_time->year < mod_time->year) {
+ return(1);
+ } else if (saved_time->year > mod_time->year) {
+ return(0);
+ }
+ if (saved_time->month < mod_time->month) {
+ return(1);
+ } else if (saved_time->month > mod_time->month) {
+ return(0);
+ }
+ if (saved_time->day < mod_time->day) {
+ return(1);
+ } else if (saved_time->day > mod_time->day) {
+ return(0);
+ }
+ if (saved_time->hour < mod_time->hour) {
+ return(1);
+ } else if (saved_time->hour > mod_time->hour) {
+ return(0);
+ }
+ if (saved_time->minute < mod_time->minute) {
+ return(1);
+ } else if (saved_time->minute > mod_time->minute) {
+ return(0);
+ }
+ if (saved_time->second < mod_time->second) {
+ return(1);
+ }
+ return(0);
+}
diff --git a/rogue/score.c b/rogue/score.c
new file mode 100644
index 00000000..6b1a06fd
--- /dev/null
+++ b/rogue/score.c
@@ -0,0 +1,581 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)score.c 5.5 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * score.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 <stdio.h>
+#include "rogue.h"
+#include "pathnames.h"
+
+extern char login_name[];
+extern char *m_names[];
+extern short max_level;
+extern boolean score_only, no_skull, msg_cleared;
+extern char *byebye_string, *nick_name;
+
+killed_by(monster, other)
+object *monster;
+short other;
+{
+ char buf[128];
+
+ md_ignore_signals();
+
+ if (other != QUIT) {
+ rogue.gold = ((rogue.gold * 9) / 10);
+ }
+
+ if (other) {
+ switch(other) {
+ case HYPOTHERMIA:
+ (void) strcpy(buf, "died of hypothermia");
+ break;
+ case STARVATION:
+ (void) strcpy(buf, "died of starvation");
+ break;
+ case POISON_DART:
+ (void) strcpy(buf, "killed by a dart");
+ break;
+ case QUIT:
+ (void) strcpy(buf, "quit");
+ break;
+ case KFIRE:
+ (void) strcpy(buf, "killed by fire");
+ break;
+ }
+ } else {
+ (void) strcpy(buf, "Killed by ");
+ if (is_vowel(m_names[monster->m_char - 'A'][0])) {
+ (void) strcat(buf, "an ");
+ } else {
+ (void) strcat(buf, "a ");
+ }
+ (void) strcat(buf, m_names[monster->m_char - 'A']);
+ }
+ (void) strcat(buf, " with ");
+ sprintf(buf+strlen(buf), "%ld gold", rogue.gold);
+ if ((!other) && (!no_skull)) {
+ clear();
+ mvaddstr(4, 32, "__---------__");
+ mvaddstr(5, 30, "_~ ~_");
+ mvaddstr(6, 29, "/ \\");
+ mvaddstr(7, 28, "~ ~");
+ mvaddstr(8, 27, "/ \\");
+ mvaddstr(9, 27, "| XXXX XXXX |");
+ mvaddstr(10, 27, "| XXXX XXXX |");
+ mvaddstr(11, 27, "| XXX XXX |");
+ mvaddstr(12, 28, "\\ @ /");
+ mvaddstr(13, 29, "--\\ @@@ /--");
+ mvaddstr(14, 30, "| | @@@ | |");
+ mvaddstr(15, 30, "| | | |");
+ mvaddstr(16, 30, "| vvVvvvvvvvVvv |");
+ mvaddstr(17, 30, "| ^^^^^^^^^^^ |");
+ mvaddstr(18, 31, "\\_ _/");
+ mvaddstr(19, 33, "~---------~");
+ center(21, nick_name);
+ center(22, buf);
+ } else {
+ message(buf, 0);
+ }
+ message("", 0);
+ put_scores(monster, other);
+}
+
+win()
+{
+ unwield(rogue.weapon); /* disarm and relax */
+ unwear(rogue.armor);
+ un_put_on(rogue.left_ring);
+ un_put_on(rogue.right_ring);
+
+ clear();
+ mvaddstr(10, 11, "@ @ @@@ @ @ @ @ @ @@@ @ @ @");
+ mvaddstr(11, 11, " @ @ @ @ @ @ @ @ @ @ @ @@ @ @");
+ mvaddstr(12, 11, " @ @ @ @ @ @ @ @ @ @ @ @ @ @");
+ mvaddstr(13, 11, " @ @ @ @ @ @ @ @ @ @ @ @@");
+ mvaddstr(14, 11, " @ @@@ @@@ @@ @@ @@@ @ @ @");
+ mvaddstr(17, 11, "Congratulations, you have been admitted to the");
+ mvaddstr(18, 11, "Fighters' Guild. You return home, sell all your");
+ mvaddstr(19, 11, "treasures at great profit and retire into comfort.");
+ message("", 0);
+ message("", 0);
+ id_all();
+ sell_pack();
+ put_scores((object *) 0, WIN);
+}
+
+quit(from_intrpt)
+boolean from_intrpt;
+{
+ char buf[128];
+ short i, orow, ocol;
+ boolean mc;
+
+ md_ignore_signals();
+
+ if (from_intrpt) {
+ orow = rogue.row;
+ ocol = rogue.col;
+
+ mc = msg_cleared;
+
+ for (i = 0; i < DCOLS; i++) {
+ buf[i] = mvinch(0, i);
+ }
+ }
+ check_message();
+ message("really quit?", 1);
+ if (rgetchar() != 'y') {
+ md_heed_signals();
+ check_message();
+ if (from_intrpt) {
+ for (i = 0; i < DCOLS; i++) {
+ mvaddch(0, i, buf[i]);
+ }
+ msg_cleared = mc;
+ move(orow, ocol);
+ refresh();
+ }
+ return;
+ }
+ if (from_intrpt) {
+ clean_up(byebye_string);
+ }
+ check_message();
+ killed_by((object *) 0, QUIT);
+}
+
+put_scores(monster, other)
+object *monster;
+short other;
+{
+ short i, n, rank = 10, x, ne = 0, found_player = -1;
+ char scores[10][82];
+ char n_names[10][30];
+ char buf[128];
+ FILE *fp;
+ long s;
+ boolean pause = score_only;
+
+ md_lock(1);
+
+ if ((fp = fopen(_PATH_SCOREFILE, "a+")) == NULL) {
+ message("cannot read/write/create score file", 0);
+ sf_error();
+ }
+ rewind(fp);
+ (void) xxx(1);
+
+ for (i = 0; i < 10; i++) {
+ if (((n = fread(scores[i], sizeof(char), 80, fp)) < 80) && (n != 0)) {
+ sf_error();
+ } else if (n != 0) {
+ xxxx(scores[i], 80);
+ if ((n = fread(n_names[i], sizeof(char), 30, fp)) < 30) {
+ sf_error();
+ }
+ xxxx(n_names[i], 30);
+ } else {
+ break;
+ }
+ ne++;
+ if ((!score_only) && (found_player == -1)) {
+ if (!name_cmp(scores[i]+15, login_name)) {
+ x = 5;
+ while (scores[i][x] == ' ') {
+ x++;
+ }
+ s = lget_number(scores[i] + x);
+ if (rogue.gold < s) {
+ score_only = 1;
+ } else {
+ found_player = i;
+ }
+ }
+ }
+ }
+ if (found_player != -1) {
+ ne--;
+ for (i = found_player; i < ne; i++) {
+ (void) strcpy(scores[i], scores[i+1]);
+ (void) strcpy(n_names[i], n_names[i+1]);
+ }
+ }
+ if (!score_only) {
+ for (i = 0; i < ne; i++) {
+ x = 5;
+ while (scores[i][x] == ' ') {
+ x++;
+ }
+ s = lget_number(scores[i] + x);
+
+ if (rogue.gold >= s) {
+ rank = i;
+ break;
+ }
+ }
+ if (ne == 0) {
+ rank = 0;
+ } else if ((ne < 10) && (rank == 10)) {
+ rank = ne;
+ }
+ if (rank < 10) {
+ insert_score(scores, n_names, nick_name, rank, ne, monster,
+ other);
+ if (ne < 10) {
+ ne++;
+ }
+ }
+ rewind(fp);
+ }
+
+ clear();
+ mvaddstr(3, 30, "Top Ten Rogueists");
+ mvaddstr(8, 0, "Rank Score Name");
+
+ md_ignore_signals();
+
+ (void) xxx(1);
+
+ for (i = 0; i < ne; i++) {
+ if (i == rank) {
+ standout();
+ }
+ if (i == 9) {
+ scores[i][0] = '1';
+ scores[i][1] = '0';
+ } else {
+ scores[i][0] = ' ';
+ scores[i][1] = i + '1';
+ }
+ nickize(buf, scores[i], n_names[i]);
+ mvaddstr(i+10, 0, buf);
+ if (rank < 10) {
+ xxxx(scores[i], 80);
+ fwrite(scores[i], sizeof(char), 80, fp);
+ xxxx(n_names[i], 30);
+ fwrite(n_names[i], sizeof(char), 30, fp);
+ }
+ if (i == rank) {
+ standend();
+ }
+ }
+ md_lock(0);
+ refresh();
+ fclose(fp);
+ message("", 0);
+ if (pause) {
+ message("", 0);
+ }
+ clean_up("");
+}
+
+insert_score(scores, n_names, n_name, rank, n, monster, other)
+char scores[][82];
+char n_names[][30];
+char *n_name;
+short rank, n;
+object *monster;
+{
+ short i;
+ char buf[128];
+
+ if (n > 0) {
+ for (i = n; i > rank; i--) {
+ if ((i < 10) && (i > 0)) {
+ (void) strcpy(scores[i], scores[i-1]);
+ (void) strcpy(n_names[i], n_names[i-1]);
+ }
+ }
+ }
+ sprintf(buf, "%2d %6d %s: ", rank+1, rogue.gold, login_name);
+
+ if (other) {
+ switch(other) {
+ case HYPOTHERMIA:
+ (void) strcat(buf, "died of hypothermia");
+ break;
+ case STARVATION:
+ (void) strcat(buf, "died of starvation");
+ break;
+ case POISON_DART:
+ (void) strcat(buf, "killed by a dart");
+ break;
+ case QUIT:
+ (void) strcat(buf, "quit");
+ break;
+ case WIN:
+ (void) strcat(buf, "a total winner");
+ break;
+ case KFIRE:
+ (void) strcpy(buf, "killed by fire");
+ break;
+ }
+ } else {
+ (void) strcat(buf, "killed by ");
+ if (is_vowel(m_names[monster->m_char - 'A'][0])) {
+ (void) strcat(buf, "an ");
+ } else {
+ (void) strcat(buf, "a ");
+ }
+ (void) strcat(buf, m_names[monster->m_char - 'A']);
+ }
+ sprintf(buf+strlen(buf), " on level %d ", max_level);
+ if ((other != WIN) && has_amulet()) {
+ (void) strcat(buf, "with amulet");
+ }
+ for (i = strlen(buf); i < 79; i++) {
+ buf[i] = ' ';
+ }
+ buf[79] = 0;
+ (void) strcpy(scores[rank], buf);
+ (void) strcpy(n_names[rank], n_name);
+}
+
+is_vowel(ch)
+short ch;
+{
+ return( (ch == 'a') ||
+ (ch == 'e') ||
+ (ch == 'i') ||
+ (ch == 'o') ||
+ (ch == 'u') );
+}
+
+sell_pack()
+{
+ object *obj;
+ short row = 2, val;
+ char buf[DCOLS];
+
+ obj = rogue.pack.next_object;
+
+ clear();
+ mvaddstr(1, 0, "Value Item");
+
+ while (obj) {
+ if (obj->what_is != FOOD) {
+ obj->identified = 1;
+ val = get_value(obj);
+ rogue.gold += val;
+
+ if (row < DROWS) {
+ sprintf(buf, "%5d ", val);
+ get_desc(obj, buf+11);
+ mvaddstr(row++, 0, buf);
+ }
+ }
+ obj = obj->next_object;
+ }
+ refresh();
+ if (rogue.gold > MAX_GOLD) {
+ rogue.gold = MAX_GOLD;
+ }
+ message("", 0);
+}
+
+get_value(obj)
+object *obj;
+{
+ short wc;
+ int val;
+
+ wc = obj->which_kind;
+
+ switch(obj->what_is) {
+ case WEAPON:
+ val = id_weapons[wc].value;
+ if ((wc == ARROW) || (wc == DAGGER) || (wc == SHURIKEN) ||
+ (wc == DART)) {
+ val *= obj->quantity;
+ }
+ val += (obj->d_enchant * 85);
+ val += (obj->hit_enchant * 85);
+ break;
+ case ARMOR:
+ val = id_armors[wc].value;
+ val += (obj->d_enchant * 75);
+ if (obj->is_protected) {
+ val += 200;
+ }
+ break;
+ case WAND:
+ val = id_wands[wc].value * (obj->class + 1);
+ break;
+ case SCROL:
+ val = id_scrolls[wc].value * obj->quantity;
+ break;
+ case POTION:
+ val = id_potions[wc].value * obj->quantity;
+ break;
+ case AMULET:
+ val = 5000;
+ break;
+ case RING:
+ val = id_rings[wc].value * (obj->class + 1);
+ break;
+ }
+ if (val <= 0) {
+ val = 10;
+ }
+ return(val);
+}
+
+id_all()
+{
+ short i;
+
+ for (i = 0; i < SCROLS; i++) {
+ id_scrolls[i].id_status = IDENTIFIED;
+ }
+ for (i = 0; i < WEAPONS; i++) {
+ id_weapons[i].id_status = IDENTIFIED;
+ }
+ for (i = 0; i < ARMORS; i++) {
+ id_armors[i].id_status = IDENTIFIED;
+ }
+ for (i = 0; i < WANDS; i++) {
+ id_wands[i].id_status = IDENTIFIED;
+ }
+ for (i = 0; i < POTIONS; i++) {
+ id_potions[i].id_status = IDENTIFIED;
+ }
+}
+
+name_cmp(s1, s2)
+char *s1, *s2;
+{
+ short i = 0;
+ int r;
+
+ while(s1[i] != ':') {
+ i++;
+ }
+ s1[i] = 0;
+ r = strcmp(s1, s2);
+ s1[i] = ':';
+ return(r);
+}
+
+xxxx(buf, n)
+char *buf;
+short n;
+{
+ short i;
+ unsigned char c;
+
+ for (i = 0; i < n; i++) {
+
+ /* It does not matter if accuracy is lost during this assignment */
+ c = (unsigned char) xxx(0);
+
+ buf[i] ^= c;
+ }
+}
+
+long
+xxx(st)
+boolean st;
+{
+ static long f, s;
+ long r;
+
+ if (st) {
+ f = 37;
+ s = 7;
+ return(0L);
+ }
+ r = ((f * s) + 9337) % 8887;
+ f = s;
+ s = r;
+ return(r);
+}
+
+nickize(buf, score, n_name)
+char *buf, *score, *n_name;
+{
+ short i = 15, j;
+
+ if (!n_name[0]) {
+ (void) strcpy(buf, score);
+ } else {
+ (void) strncpy(buf, score, 16);
+
+ while (score[i] != ':') {
+ i++;
+ }
+
+ (void) strcpy(buf+15, n_name);
+ j = strlen(buf);
+
+ while (score[i]) {
+ buf[j++] = score[i++];
+ }
+ buf[j] = 0;
+ buf[79] = 0;
+ }
+}
+
+center(row, buf)
+short row;
+char *buf;
+{
+ short margin;
+
+ margin = ((DCOLS - strlen(buf)) / 2);
+ mvaddstr(row, margin, buf);
+}
+
+sf_error()
+{
+ md_lock(0);
+ message("", 1);
+ clean_up("sorry, score file is out of order");
+}
diff --git a/rogue/spec_hit.c b/rogue/spec_hit.c
new file mode 100644
index 00000000..25bb5db4
--- /dev/null
+++ b/rogue/spec_hit.c
@@ -0,0 +1,534 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)spec_hit.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * special_hit.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.h"
+
+short less_hp = 0;
+boolean being_held;
+
+extern short cur_level, max_level, blind, levitate, ring_exp;
+extern long level_points[];
+extern boolean detect_monster, mon_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 & DROPS_LEVEL) {
+ drop_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->d_enchant--;
+ 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.str_current+(rogue.str_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++) {
+ mv_mons();
+ }
+ if (rand_percent(freeze_percent)) {
+ for (i = 0; i < 50; i++) {
+ mv_mons();
+ }
+ 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((cur_level * 10), (cur_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 desc[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;
+ }
+ }
+ }
+ (void) strcpy(desc, "she stole ");
+ if (obj->what_is != WEAPON) {
+ t = obj->quantity;
+ obj->quantity = 1;
+ }
+ get_desc(obj, desc+10);
+ message(desc, 0);
+
+ obj->quantity = ((obj->what_is != WEAPON) ? t : 1);
+
+ vanish(obj, 0, &rogue.pack);
+DSPR:
+ disappear(monster);
+}
+
+disappear(monster)
+object *monster;
+{
+ short row, col;
+
+ row = monster->row;
+ col = monster->col;
+
+ dungeon[row][col] &= ~MONSTER;
+ if (rogue_can_see(row, col)) {
+ mvaddch(row, col, get_dungeon_char(row, col));
+ }
+ take_from_pack(monster, &level_monsters);
+ free_object(monster);
+ mon_disappeared = 1;
+}
+
+cough_up(monster)
+object *monster;
+{
+ object *obj;
+ short row, col, i, n;
+
+ if (cur_level < max_level) {
+ return;
+ }
+
+ if (monster->m_flags & STEALS_GOLD) {
+ obj = alloc_object();
+ obj->what_is = GOLD;
+ obj->quantity = get_rand((cur_level * 15), (cur_level * 30));
+ } else {
+ if (!rand_percent((int) monster->drop_percent)) {
+ return;
+ }
+ obj = gr_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))) {
+ place_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 = mon_can_go(monster, i, j);
+ monster->m_flags &= (~CAN_FLIT);
+ if (s) {
+ move_mon_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_1_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) {
+ 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 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!", mon_name(monster));
+ message(msg, 1);
+ }
+ return(1);
+ }
+ return(0);
+}
+
+imitating(row, col)
+register short row, col;
+{
+ if (dungeon[row][col] & MONSTER) {
+ object *object_at(), *monster;
+
+ if (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];
+
+ if ((rogue.str_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",
+ mon_name(monster));
+ message(msg, 0);
+ rogue.str_current--;
+ print_stats(STAT_STRENGTH);
+ }
+}
+
+drop_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 = 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.str_current > 3) && (!sustain_strength)) {
+ rogue.str_current--;
+ if (coin_toss()) {
+ rogue.str_max--;
+ }
+ }
+ }
+ print_stats((STAT_STRENGTH | STAT_HP));
+}
+
+m_confuse(monster)
+object *monster;
+{
+ char msg[80];
+
+ 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", mon_name(monster));
+ message(msg, 1);
+ cnfs();
+ return(1);
+ }
+ return(0);
+}
+
+flame_broil(monster)
+object *monster;
+{
+ short row, col, dir;
+
+ if ((!mon_sees(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);
+ }
+ dir = get_dir(monster->row, monster->col, row, col);
+ bounce(FIRE, dir, monster->row, monster->col, 0);
+
+ return(1);
+}
+
+get_dir(srow, scol, drow, dcol)
+short srow, scol, drow, dcol;
+{
+ if (srow == drow) {
+ if (scol < dcol) {
+ return(RIGHT);
+ } else {
+ return(LEFT);
+ }
+ }
+ if (scol == dcol) {
+ if (srow < drow) {
+ return(DOWN);
+ } else {
+ return(UPWARD);
+ }
+ }
+ if ((srow > drow) && (scol > dcol)) {
+ return(UPLEFT);
+ }
+ if ((srow < drow) && (scol < dcol)) {
+ return(DOWNRIGHT);
+ }
+ if ((srow < drow) && (scol > dcol)) {
+ return(DOWNLEFT);
+ }
+ /*if ((srow > drow) && (scol < dcol)) {*/
+ return(UPRIGHT);
+ /*}*/
+}
diff --git a/rogue/throw.c b/rogue/throw.c
new file mode 100644
index 00000000..ccb688d6
--- /dev/null
+++ b/rogue/throw.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)throw.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * throw.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.h"
+
+extern short cur_room;
+extern char *curse_message;
+extern char hit_message[];
+
+throw()
+{
+ short wch, d;
+ boolean first_miss = 1;
+ object *weapon;
+ short dir, row, col;
+ object *monster;
+
+ while (!is_direction(dir = rgetchar(), &d)) {
+ sound_bell();
+ if (first_miss) {
+ message("direction? ", 0);
+ first_miss = 0;
+ }
+ }
+ check_message();
+ if (dir == CANCEL) {
+ return;
+ }
+ if ((wch = pack_letter("throw what?", WEAPON)) == CANCEL) {
+ return;
+ }
+ check_message();
+
+ if (!(weapon = get_letter_object(wch))) {
+ message("no such item.", 0);
+ return;
+ }
+ if ((weapon->in_use_flags & BEING_USED) && weapon->is_cursed) {
+ message(curse_message, 0);
+ return;
+ }
+ row = rogue.row; col = rogue.col;
+
+ if ((weapon->in_use_flags & BEING_WIELDED) && (weapon->quantity <= 1)) {
+ unwield(rogue.weapon);
+ } else if (weapon->in_use_flags & BEING_WORN) {
+ mv_aquatars();
+ unwear(rogue.armor);
+ print_stats(STAT_ARMOR);
+ } else if (weapon->in_use_flags & ON_EITHER_HAND) {
+ un_put_on(weapon);
+ }
+ monster = get_thrown_at_monster(weapon, d, &row, &col);
+ mvaddch(rogue.row, rogue.col, rogue.fchar);
+ refresh();
+
+ if (rogue_can_see(row, col) && ((row != rogue.row) || (col != rogue.col))){
+ mvaddch(row, col, get_dungeon_char(row, col));
+ }
+ if (monster) {
+ wake_up(monster);
+ check_gold_seeker(monster);
+
+ if (!throw_at_monster(monster, weapon)) {
+ flop_weapon(weapon, row, col);
+ }
+ } else {
+ flop_weapon(weapon, row, col);
+ }
+ vanish(weapon, 1, &rogue.pack);
+}
+
+throw_at_monster(monster, weapon)
+object *monster, *weapon;
+{
+ short damage, hit_chance;
+ short t;
+
+ hit_chance = get_hit_chance(weapon);
+ damage = get_weapon_damage(weapon);
+ if ((weapon->which_kind == ARROW) &&
+ (rogue.weapon && (rogue.weapon->which_kind == BOW))) {
+ damage += get_weapon_damage(rogue.weapon);
+ damage = ((damage * 2) / 3);
+ hit_chance += (hit_chance / 3);
+ } else if ((weapon->in_use_flags & BEING_WIELDED) &&
+ ((weapon->which_kind == DAGGER) ||
+ (weapon->which_kind == SHURIKEN) ||
+ (weapon->which_kind == DART))) {
+ damage = ((damage * 3) / 2);
+ hit_chance += (hit_chance / 3);
+ }
+ t = weapon->quantity;
+ weapon->quantity = 1;
+ sprintf(hit_message, "the %s", name_of(weapon));
+ weapon->quantity = t;
+
+ if (!rand_percent(hit_chance)) {
+ (void) strcat(hit_message, "misses ");
+ return(0);
+ }
+ s_con_mon(monster);
+ (void) strcat(hit_message, "hit ");
+ (void) mon_damage(monster, damage);
+ return(1);
+}
+
+object *
+get_thrown_at_monster(obj, dir, row, col)
+object *obj;
+short dir;
+short *row, *col;
+{
+ short orow, ocol;
+ short i, ch;
+
+ orow = *row; ocol = *col;
+
+ ch = get_mask_char(obj->what_is);
+
+ for (i = 0; i < 24; i++) {
+ get_dir_rc(dir, row, col, 0);
+ if ( (((*col <= 0) || (*col >= DCOLS-1)) ||
+ (dungeon[*row][*col] == NOTHING)) ||
+ ((dungeon[*row][*col] & (HORWALL | VERTWALL | HIDDEN)) &&
+ (!(dungeon[*row][*col] & TRAP)))) {
+ *row = orow;
+ *col = ocol;
+ return(0);
+ }
+ if ((i != 0) && rogue_can_see(orow, ocol)) {
+ mvaddch(orow, ocol, get_dungeon_char(orow, ocol));
+ }
+ if (rogue_can_see(*row, *col)) {
+ if (!(dungeon[*row][*col] & MONSTER)) {
+ mvaddch(*row, *col, ch);
+ }
+ refresh();
+ }
+ orow = *row; ocol = *col;
+ if (dungeon[*row][*col] & MONSTER) {
+ if (!imitating(*row, *col)) {
+ return(object_at(&level_monsters, *row, *col));
+ }
+ }
+ if (dungeon[*row][*col] & TUNNEL) {
+ i += 2;
+ }
+ }
+ return(0);
+}
+
+flop_weapon(weapon, row, col)
+object *weapon;
+short row, col;
+{
+ object *new_weapon, *monster;
+ short i = 0;
+ char msg[80];
+ boolean found = 0;
+ short mch, dch;
+ unsigned short mon;
+
+ while ((i < 9) && dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER)) {
+ rand_around(i++, &row, &col);
+ if ((row > (DROWS-2)) || (row < MIN_ROW) ||
+ (col > (DCOLS-1)) || (col < 0) || (!dungeon[row][col]) ||
+ (dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER))) {
+ continue;
+ }
+ found = 1;
+ break;
+ }
+
+ if (found || (i == 0)) {
+ new_weapon = alloc_object();
+ *new_weapon = *weapon;
+ new_weapon->in_use_flags = NOT_USED;
+ new_weapon->quantity = 1;
+ new_weapon->ichar = 'L';
+ place_at(new_weapon, row, col);
+ if (rogue_can_see(row, col) &&
+ ((row != rogue.row) || (col != rogue.col))) {
+ mon = dungeon[row][col] & MONSTER;
+ dungeon[row][col] &= (~MONSTER);
+ dch = get_dungeon_char(row, col);
+ if (mon) {
+ mch = mvinch(row, col);
+ if (monster = object_at(&level_monsters, row, col)) {
+ monster->trail_char = dch;
+ }
+ if ((mch < 'A') || (mch > 'Z')) {
+ mvaddch(row, col, dch);
+ }
+ } else {
+ mvaddch(row, col, dch);
+ }
+ dungeon[row][col] |= mon;
+ }
+ } else {
+ short t;
+
+ t = weapon->quantity;
+ weapon->quantity = 1;
+ sprintf(msg, "the %svanishes as it hits the ground",
+ name_of(weapon));
+ weapon->quantity = t;
+ message(msg, 0);
+ }
+}
+
+rand_around(i, r, c)
+short i, *r, *c;
+{
+ static char* pos = "\010\007\001\003\004\005\002\006\0";
+ static short row, col;
+ short j;
+
+ if (i == 0) {
+ short x, y, o, t;
+
+ row = *r;
+ col = *c;
+
+ o = get_rand(1, 8);
+
+ for (j = 0; j < 5; j++) {
+ x = get_rand(0, 8);
+ y = (x + o) % 9;
+ t = pos[x];
+ pos[x] = pos[y];
+ pos[y] = t;
+ }
+ }
+ switch((short)pos[i]) {
+ case 0:
+ *r = row + 1;
+ *c = col + 1;
+ break;
+ case 1:
+ *r = row + 1;
+ *c = col - 1;
+ break;
+ case 2:
+ *r = row - 1;
+ *c = col + 1;
+ break;
+ case 3:
+ *r = row - 1;
+ *c = col - 1;
+ break;
+ case 4:
+ *r = row;
+ *c = col + 1;
+ break;
+ case 5:
+ *r = row + 1;
+ *c = col;
+ break;
+ case 6:
+ *r = row;
+ *c = col;
+ break;
+ case 7:
+ *r = row - 1;
+ *c = col;
+ break;
+ case 8:
+ *r = row;
+ *c = col - 1;
+ break;
+ }
+}
diff --git a/rogue/trap.c b/rogue/trap.c
new file mode 100644
index 00000000..1f523ea2
--- /dev/null
+++ b/rogue/trap.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)trap.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * trap.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.h"
+
+trap traps[MAX_TRAPS];
+boolean trap_door = 0;
+short bear_trap = 0;
+
+char *trap_strings[TRAPS * 2] = {
+ "trap door",
+ "you fell down a trap",
+ "bear trap",
+ "you are caught in a bear trap",
+ "teleport trap",
+ "teleport",
+ "poison dart trap",
+ "a small dart just hit you in the shoulder",
+ "sleeping gas trap",
+ "a strange white mist envelops you and you fall asleep",
+ "rust trap",
+ "a gush of water hits you on the head"
+};
+
+extern short cur_level, party_room;
+extern char *new_level_message;
+extern boolean interrupted;
+extern short ring_exp;
+extern boolean sustain_strength;
+extern short blind;
+
+trap_at(row, col)
+register row, col;
+{
+ short i;
+
+ for (i = 0; ((i < MAX_TRAPS) && (traps[i].trap_type != NO_TRAP)); i++) {
+ if ((traps[i].trap_row == row) && (traps[i].trap_col == col)) {
+ return(traps[i].trap_type);
+ }
+ }
+ return(NO_TRAP);
+}
+
+trap_player(row, col)
+short row, col;
+{
+ short t;
+
+ if ((t = trap_at(row, col)) == NO_TRAP) {
+ return;
+ }
+ dungeon[row][col] &= (~HIDDEN);
+ if (rand_percent(rogue.exp + ring_exp)) {
+ message("the trap failed", 1);
+ return;
+ }
+ switch(t) {
+ case TRAP_DOOR:
+ trap_door = 1;
+ new_level_message = trap_strings[(t*2)+1];
+ break;
+ case BEAR_TRAP:
+ message(trap_strings[(t*2)+1], 1);
+ bear_trap = get_rand(4, 7);
+ break;
+ case TELE_TRAP:
+ mvaddch(rogue.row, rogue.col, '^');
+ tele();
+ break;
+ case DART_TRAP:
+ message(trap_strings[(t*2)+1], 1);
+ rogue.hp_current -= get_damage("1d6", 1);
+ if (rogue.hp_current <= 0) {
+ rogue.hp_current = 0;
+ }
+ if ((!sustain_strength) && rand_percent(40) &&
+ (rogue.str_current >= 3)) {
+ rogue.str_current--;
+ }
+ print_stats(STAT_HP | STAT_STRENGTH);
+ if (rogue.hp_current <= 0) {
+ killed_by((object *) 0, POISON_DART);
+ }
+ break;
+ case SLEEPING_GAS_TRAP:
+ message(trap_strings[(t*2)+1], 1);
+ take_a_nap();
+ break;
+ case RUST_TRAP:
+ message(trap_strings[(t*2)+1], 1);
+ rust((object *) 0);
+ break;
+ }
+}
+
+add_traps()
+{
+ short i, n, tries = 0;
+ short row, col;
+
+ if (cur_level <= 2) {
+ n = 0;
+ } else if (cur_level <= 7) {
+ n = get_rand(0, 2);
+ } else if (cur_level <= 11) {
+ n = get_rand(1, 2);
+ } else if (cur_level <= 16) {
+ n = get_rand(2, 3);
+ } else if (cur_level <= 21) {
+ n = get_rand(2, 4);
+ } else if (cur_level <= (AMULET_LEVEL + 2)) {
+ n = get_rand(3, 5);
+ } else {
+ n = get_rand(5, MAX_TRAPS);
+ }
+ for (i = 0; i < n; i++) {
+ traps[i].trap_type = get_rand(0, (TRAPS - 1));
+
+ if ((i == 0) && (party_room != NO_ROOM)) {
+ do {
+ row = get_rand((rooms[party_room].top_row+1),
+ (rooms[party_room].bottom_row-1));
+ col = get_rand((rooms[party_room].left_col+1),
+ (rooms[party_room].right_col-1));
+ tries++;
+ } while (((dungeon[row][col] & (OBJECT|STAIRS|TRAP|TUNNEL)) ||
+ (dungeon[row][col] == NOTHING)) && (tries < 15));
+ if (tries >= 15) {
+ gr_row_col(&row, &col, (FLOOR | MONSTER));
+ }
+ } else {
+ gr_row_col(&row, &col, (FLOOR | MONSTER));
+ }
+ traps[i].trap_row = row;
+ traps[i].trap_col = col;
+ dungeon[row][col] |= (TRAP | HIDDEN);
+ }
+}
+
+id_trap()
+{
+ short dir, row, col, d, t;
+
+ message("direction? ", 0);
+
+ while (!is_direction(dir = rgetchar(), &d)) {
+ sound_bell();
+ }
+ check_message();
+
+ if (dir == CANCEL) {
+ return;
+ }
+ row = rogue.row;
+ col = rogue.col;
+
+ get_dir_rc(d, &row, &col, 0);
+
+ if ((dungeon[row][col] & TRAP) && (!(dungeon[row][col] & HIDDEN))) {
+ t = trap_at(row, col);
+ message(trap_strings[t*2], 0);
+ } else {
+ message("no trap there", 0);
+ }
+}
+
+show_traps()
+{
+ short i, j;
+
+ for (i = 0; i < DROWS; i++) {
+ for (j = 0; j < DCOLS; j++) {
+ if (dungeon[i][j] & TRAP) {
+ mvaddch(i, j, '^');
+ }
+ }
+ }
+}
+
+search(n, is_auto)
+short n;
+boolean is_auto;
+{
+ short s, i, j, row, col, t;
+ short shown = 0, found = 0;
+ static boolean reg_search;
+
+ for (i = -1; i <= 1; i++) {
+ for (j = -1; j <= 1; j++) {
+ row = rogue.row + i;
+ col = rogue.col + j;
+ if ((row < MIN_ROW) || (row >= (DROWS-1)) ||
+ (col < 0) || (col >= DCOLS)) {
+ continue;
+ }
+ if (dungeon[row][col] & HIDDEN) {
+ found++;
+ }
+ }
+ }
+ for (s = 0; s < n; s++) {
+ for (i = -1; i <= 1; i++) {
+ for (j = -1; j <= 1; j++) {
+ row = rogue.row + i;
+ col = rogue.col + j ;
+ if ((row < MIN_ROW) || (row >= (DROWS-1)) ||
+ (col < 0) || (col >= DCOLS)) {
+ continue;
+ }
+ if (dungeon[row][col] & HIDDEN) {
+ if (rand_percent(17 + (rogue.exp + ring_exp))) {
+ dungeon[row][col] &= (~HIDDEN);
+ if ((!blind) && ((row != rogue.row) ||
+ (col != rogue.col))) {
+ mvaddch(row, col, get_dungeon_char(row, col));
+ }
+ shown++;
+ if (dungeon[row][col] & TRAP) {
+ t = trap_at(row, col);
+ message(trap_strings[t*2], 1);
+ }
+ }
+ }
+ if (((shown == found) && (found > 0)) || interrupted) {
+ return;
+ }
+ }
+ }
+ if ((!is_auto) && (reg_search = !reg_search)) {
+ (void) reg_move();
+ }
+ }
+}
diff --git a/rogue/use.c b/rogue/use.c
new file mode 100644
index 00000000..c4bc2240
--- /dev/null
+++ b/rogue/use.c
@@ -0,0 +1,618 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)use.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * use.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.h"
+
+short halluc = 0;
+short blind = 0;
+short confused = 0;
+short levitate = 0;
+short haste_self = 0;
+boolean see_invisible = 0;
+short extra_hp = 0;
+boolean detect_monster = 0;
+boolean con_mon = 0;
+char *strange_feeling = "you have a strange feeling for a moment, then it passes";
+
+extern short bear_trap;
+extern char hunger_str[];
+extern short cur_room;
+extern long level_points[];
+extern boolean being_held;
+extern char *fruit, *you_can_move_again;
+extern boolean sustain_strength;
+
+quaff()
+{
+ short ch;
+ char buf[80];
+ object *obj;
+
+ ch = pack_letter("quaff what?", POTION);
+
+ if (ch == CANCEL) {
+ return;
+ }
+ if (!(obj = get_letter_object(ch))) {
+ message("no such item.", 0);
+ return;
+ }
+ if (obj->what_is != POTION) {
+ message("you can't drink that", 0);
+ return;
+ }
+ switch(obj->which_kind) {
+ case INCREASE_STRENGTH:
+ message("you feel stronger now, what bulging muscles!",
+ 0);
+ rogue.str_current++;
+ if (rogue.str_current > rogue.str_max) {
+ rogue.str_max = rogue.str_current;
+ }
+ break;
+ case RESTORE_STRENGTH:
+ rogue.str_current = rogue.str_max;
+ message("this tastes great, you feel warm all over", 0);
+ break;
+ case HEALING:
+ message("you begin to feel better", 0);
+ potion_heal(0);
+ break;
+ case EXTRA_HEALING:
+ message("you begin to feel much better", 0);
+ potion_heal(1);
+ break;
+ case POISON:
+ if (!sustain_strength) {
+ rogue.str_current -= get_rand(1, 3);
+ if (rogue.str_current < 1) {
+ rogue.str_current = 1;
+ }
+ }
+ message("you feel very sick now", 0);
+ if (halluc) {
+ unhallucinate();
+ }
+ break;
+ case RAISE_LEVEL:
+ rogue.exp_points = level_points[rogue.exp - 1];
+ message("you suddenly feel much more skillful", 0);
+ add_exp(1, 1);
+ break;
+ case BLINDNESS:
+ go_blind();
+ break;
+ case HALLUCINATION:
+ message("oh wow, everything seems so cosmic", 0);
+ halluc += get_rand(500, 800);
+ break;
+ case DETECT_MONSTER:
+ show_monsters();
+ if (!(level_monsters.next_monster)) {
+ message(strange_feeling, 0);
+ }
+ break;
+ case DETECT_OBJECTS:
+ if (level_objects.next_object) {
+ if (!blind) {
+ show_objects();
+ }
+ } else {
+ message(strange_feeling, 0);
+ }
+ break;
+ case CONFUSION:
+ message((halluc ? "what a trippy feeling" :
+ "you feel confused"), 0);
+ cnfs();
+ break;
+ case LEVITATION:
+ message("you start to float in the air", 0);
+ levitate += get_rand(15, 30);
+ being_held = bear_trap = 0;
+ break;
+ case HASTE_SELF:
+ message("you feel yourself moving much faster", 0);
+ haste_self += get_rand(11, 21);
+ if (!(haste_self % 2)) {
+ haste_self++;
+ }
+ break;
+ case SEE_INVISIBLE:
+ sprintf(buf, "hmm, this potion tastes like %sjuice", fruit);
+ message(buf, 0);
+ if (blind) {
+ unblind();
+ }
+ see_invisible = 1;
+ relight();
+ break;
+ }
+ print_stats((STAT_STRENGTH | STAT_HP));
+ if (id_potions[obj->which_kind].id_status != CALLED) {
+ id_potions[obj->which_kind].id_status = IDENTIFIED;
+ }
+ vanish(obj, 1, &rogue.pack);
+}
+
+read_scroll()
+{
+ short ch;
+ object *obj;
+ char msg[DCOLS];
+
+ ch = pack_letter("read what?", SCROL);
+
+ if (ch == CANCEL) {
+ return;
+ }
+ if (!(obj = get_letter_object(ch))) {
+ message("no such item.", 0);
+ return;
+ }
+ if (obj->what_is != SCROL) {
+ message("you can't read that", 0);
+ return;
+ }
+ switch(obj->which_kind) {
+ case SCARE_MONSTER:
+ message("you hear a maniacal laughter in the distance",
+ 0);
+ break;
+ case HOLD_MONSTER:
+ hold_monster();
+ break;
+ case ENCH_WEAPON:
+ if (rogue.weapon) {
+ if (rogue.weapon->what_is == WEAPON) {
+ sprintf(msg, "your %sglow%s %sfor a moment",
+ name_of(rogue.weapon),
+ ((rogue.weapon->quantity <= 1) ? "s" : ""),
+ get_ench_color());
+ message(msg, 0);
+ if (coin_toss()) {
+ rogue.weapon->hit_enchant++;
+ } else {
+ rogue.weapon->d_enchant++;
+ }
+ }
+ rogue.weapon->is_cursed = 0;
+ } else {
+ message("your hands tingle", 0);
+ }
+ break;
+ case ENCH_ARMOR:
+ if (rogue.armor) {
+ sprintf(msg, "your armor glows %sfor a moment",
+ get_ench_color());
+ message(msg, 0);
+ rogue.armor->d_enchant++;
+ rogue.armor->is_cursed = 0;
+ print_stats(STAT_ARMOR);
+ } else {
+ message("your skin crawls", 0);
+ }
+ break;
+ case IDENTIFY:
+ message("this is a scroll of identify", 0);
+ obj->identified = 1;
+ id_scrolls[obj->which_kind].id_status = IDENTIFIED;
+ idntfy();
+ break;
+ case TELEPORT:
+ tele();
+ break;
+ case SLEEP:
+ message("you fall asleep", 0);
+ take_a_nap();
+ break;
+ case PROTECT_ARMOR:
+ if (rogue.armor) {
+ message( "your armor is covered by a shimmering gold shield",0);
+ rogue.armor->is_protected = 1;
+ rogue.armor->is_cursed = 0;
+ } else {
+ message("your acne seems to have disappeared", 0);
+ }
+ break;
+ case REMOVE_CURSE:
+ message((!halluc) ?
+ "you feel as though someone is watching over you" :
+ "you feel in touch with the universal oneness", 0);
+ uncurse_all();
+ break;
+ case CREATE_MONSTER:
+ create_monster();
+ break;
+ case AGGRAVATE_MONSTER:
+ aggravate();
+ break;
+ case MAGIC_MAPPING:
+ message("this scroll seems to have a map on it", 0);
+ draw_magic_map();
+ break;
+ case CON_MON:
+ con_mon = 1;
+ sprintf(msg, "your hands glow %sfor a moment", get_ench_color());
+ message(msg, 0);
+ break;
+ }
+ if (id_scrolls[obj->which_kind].id_status != CALLED) {
+ id_scrolls[obj->which_kind].id_status = IDENTIFIED;
+ }
+ vanish(obj, (obj->which_kind != SLEEP), &rogue.pack);
+}
+
+/* vanish() does NOT handle a quiver of weapons with more than one
+ * arrow (or whatever) in the quiver. It will only decrement the count.
+ */
+
+vanish(obj, rm, pack)
+object *obj;
+short rm;
+object *pack;
+{
+ if (obj->quantity > 1) {
+ obj->quantity--;
+ } else {
+ if (obj->in_use_flags & BEING_WIELDED) {
+ unwield(obj);
+ } else if (obj->in_use_flags & BEING_WORN) {
+ unwear(obj);
+ } else if (obj->in_use_flags & ON_EITHER_HAND) {
+ un_put_on(obj);
+ }
+ take_from_pack(obj, pack);
+ free_object(obj);
+ }
+ if (rm) {
+ (void) reg_move();
+ }
+}
+
+potion_heal(extra)
+{
+ float ratio;
+ short add;
+
+ rogue.hp_current += rogue.exp;
+
+ ratio = ((float)rogue.hp_current) / rogue.hp_max;
+
+ if (ratio >= 1.00) {
+ rogue.hp_max += (extra ? 2 : 1);
+ extra_hp += (extra ? 2 : 1);
+ rogue.hp_current = rogue.hp_max;
+ } else if (ratio >= 0.90) {
+ rogue.hp_max += (extra ? 1 : 0);
+ extra_hp += (extra ? 1 : 0);
+ rogue.hp_current = rogue.hp_max;
+ } else {
+ if (ratio < 0.33) {
+ ratio = 0.33;
+ }
+ if (extra) {
+ ratio += ratio;
+ }
+ add = (short)(ratio * ((float)rogue.hp_max - rogue.hp_current));
+ rogue.hp_current += add;
+ if (rogue.hp_current > rogue.hp_max) {
+ rogue.hp_current = rogue.hp_max;
+ }
+ }
+ if (blind) {
+ unblind();
+ }
+ if (confused && extra) {
+ unconfuse();
+ } else if (confused) {
+ confused = (confused / 2) + 1;
+ }
+ if (halluc && extra) {
+ unhallucinate();
+ } else if (halluc) {
+ halluc = (halluc / 2) + 1;
+ }
+}
+
+idntfy()
+{
+ short ch;
+ object *obj;
+ struct id *id_table;
+ char desc[DCOLS];
+AGAIN:
+ ch = pack_letter("what would you like to identify?", ALL_OBJECTS);
+
+ if (ch == CANCEL) {
+ return;
+ }
+ if (!(obj = get_letter_object(ch))) {
+ message("no such item, try again", 0);
+ message("", 0);
+ check_message();
+ goto AGAIN;
+ }
+ obj->identified = 1;
+ if (obj->what_is & (SCROL | POTION | WEAPON | ARMOR | WAND | RING)) {
+ id_table = get_id_table(obj);
+ id_table[obj->which_kind].id_status = IDENTIFIED;
+ }
+ get_desc(obj, desc);
+ message(desc, 0);
+}
+
+eat()
+{
+ short ch;
+ short moves;
+ object *obj;
+ char buf[70];
+
+ ch = pack_letter("eat what?", FOOD);
+
+ if (ch == CANCEL) {
+ return;
+ }
+ if (!(obj = get_letter_object(ch))) {
+ message("no such item.", 0);
+ return;
+ }
+ if (obj->what_is != FOOD) {
+ message("you can't eat that", 0);
+ return;
+ }
+ if ((obj->which_kind == FRUIT) || rand_percent(60)) {
+ moves = get_rand(950, 1150);
+ if (obj->which_kind == RATION) {
+ message("yum, that tasted good", 0);
+ } else {
+ sprintf(buf, "my, that was a yummy %s", fruit);
+ message(buf, 0);
+ }
+ } else {
+ moves = get_rand(750, 950);
+ message("yuk, that food tasted awful", 0);
+ add_exp(2, 1);
+ }
+ rogue.moves_left /= 3;
+ rogue.moves_left += moves;
+ hunger_str[0] = 0;
+ print_stats(STAT_HUNGER);
+
+ vanish(obj, 1, &rogue.pack);
+}
+
+hold_monster()
+{
+ short i, j;
+ short mcount = 0;
+ object *monster;
+ short row, col;
+
+ for (i = -2; i <= 2; i++) {
+ for (j = -2; j <= 2; j++) {
+ row = rogue.row + i;
+ col = rogue.col + j;
+ if ((row < MIN_ROW) || (row > (DROWS-2)) || (col < 0) ||
+ (col > (DCOLS-1))) {
+ continue;
+ }
+ if (dungeon[row][col] & MONSTER) {
+ monster = object_at(&level_monsters, row, col);
+ monster->m_flags |= ASLEEP;
+ monster->m_flags &= (~WAKENS);
+ mcount++;
+ }
+ }
+ }
+ if (mcount == 0) {
+ message("you feel a strange sense of loss", 0);
+ } else if (mcount == 1) {
+ message("the monster freezes", 0);
+ } else {
+ message("the monsters around you freeze", 0);
+ }
+}
+
+tele()
+{
+ mvaddch(rogue.row, rogue.col, get_dungeon_char(rogue.row, rogue.col));
+
+ if (cur_room >= 0) {
+ darken_room(cur_room);
+ }
+ put_player(get_room_number(rogue.row, rogue.col));
+ being_held = 0;
+ bear_trap = 0;
+}
+
+hallucinate()
+{
+ object *obj, *monster;
+ short ch;
+
+ if (blind) return;
+
+ obj = level_objects.next_object;
+
+ while (obj) {
+ ch = mvinch(obj->row, obj->col);
+ if (((ch < 'A') || (ch > 'Z')) &&
+ ((obj->row != rogue.row) || (obj->col != rogue.col)))
+ if ((ch != ' ') && (ch != '.') && (ch != '#') && (ch != '+')) {
+ addch(gr_obj_char());
+ }
+ obj = obj->next_object;
+ }
+ monster = level_monsters.next_monster;
+
+ while (monster) {
+ ch = mvinch(monster->row, monster->col);
+ if ((ch >= 'A') && (ch <= 'Z')) {
+ addch(get_rand('A', 'Z'));
+ }
+ monster = monster->next_monster;
+ }
+}
+
+unhallucinate()
+{
+ halluc = 0;
+ relight();
+ message("everything looks SO boring now", 1);
+}
+
+unblind()
+{
+ blind = 0;
+ message("the veil of darkness lifts", 1);
+ relight();
+ if (halluc) {
+ hallucinate();
+ }
+ if (detect_monster) {
+ show_monsters();
+ }
+}
+
+relight()
+{
+ if (cur_room == PASSAGE) {
+ light_passage(rogue.row, rogue.col);
+ } else {
+ light_up_room(cur_room);
+ }
+ mvaddch(rogue.row, rogue.col, rogue.fchar);
+}
+
+take_a_nap()
+{
+ short i;
+
+ i = get_rand(2, 5);
+ md_sleep(1);
+
+ while (i--) {
+ mv_mons();
+ }
+ md_sleep(1);
+ message(you_can_move_again, 0);
+}
+
+go_blind()
+{
+ short i, j;
+
+ if (!blind) {
+ message("a cloak of darkness falls around you", 0);
+ }
+ blind += get_rand(500, 800);
+
+ if (detect_monster) {
+ object *monster;
+
+ monster = level_monsters.next_monster;
+
+ while (monster) {
+ mvaddch(monster->row, monster->col, monster->trail_char);
+ monster = monster->next_monster;
+ }
+ }
+ if (cur_room >= 0) {
+ for (i = rooms[cur_room].top_row + 1;
+ i < rooms[cur_room].bottom_row; i++) {
+ for (j = rooms[cur_room].left_col + 1;
+ j < rooms[cur_room].right_col; j++) {
+ mvaddch(i, j, ' ');
+ }
+ }
+ }
+ mvaddch(rogue.row, rogue.col, rogue.fchar);
+}
+
+char *
+get_ench_color()
+{
+ if (halluc) {
+ return(id_potions[get_rand(0, POTIONS-1)].title);
+ } else if (con_mon) {
+ return("red ");
+ }
+ return("blue ");
+}
+
+cnfs()
+{
+ confused += get_rand(12, 22);
+}
+
+unconfuse()
+{
+ char msg[80];
+
+ confused = 0;
+ sprintf(msg, "you feel less %s now", (halluc ? "trippy" : "confused"));
+ message(msg, 1);
+}
+
+uncurse_all()
+{
+ object *obj;
+
+ obj = rogue.pack.next_object;
+
+ while (obj) {
+ obj->is_cursed = 0;
+ obj = obj->next_object;
+ }
+}
diff --git a/rogue/zap.c b/rogue/zap.c
new file mode 100644
index 00000000..ecc4e9e0
--- /dev/null
+++ b/rogue/zap.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Timothy C. Stoehr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)zap.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * zap.c
+ *
+ * This source herein may be modified and/or distributed by anybody who
+ * so desires, with the following restrictions:
+ * 1.) No portion of this notice shall 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 "rogue.h"
+
+boolean wizard = 0;
+
+extern boolean being_held, score_only, detect_monster;
+extern short cur_room;
+
+zapp()
+{
+ short wch;
+ boolean first_miss = 1;
+ object *wand;
+ short dir, d, row, col;
+ object *monster;
+
+ while (!is_direction(dir = rgetchar(), &d)) {
+ sound_bell();
+ if (first_miss) {
+ message("direction? ", 0);
+ first_miss = 0;
+ }
+ }
+ check_message();
+ if (dir == CANCEL) {
+ return;
+ }
+ if ((wch = pack_letter("zap with what?", WAND)) == CANCEL) {
+ return;
+ }
+ check_message();
+
+ if (!(wand = get_letter_object(wch))) {
+ message("no such item.", 0);
+ return;
+ }
+ if (wand->what_is != WAND) {
+ message("you can't zap with that", 0);
+ return;
+ }
+ if (wand->class <= 0) {
+ message("nothing happens", 0);
+ } else {
+ wand->class--;
+ row = rogue.row; col = rogue.col;
+ if ((wand->which_kind == COLD) || (wand->which_kind == FIRE)) {
+ bounce((short) wand->which_kind, d, row, col, 0);
+ } else {
+ monster = get_zapped_monster(d, &row, &col);
+ if (wand->which_kind == DRAIN_LIFE) {
+ wdrain_life(monster);
+ } else if (monster) {
+ wake_up(monster);
+ s_con_mon(monster);
+ zap_monster(monster, wand->which_kind);
+ relight();
+ }
+ }
+ }
+ (void) reg_move();
+}
+
+object *
+get_zapped_monster(dir, row, col)
+short dir;
+short *row, *col;
+{
+ short orow, ocol;
+
+ for (;;) {
+ orow = *row; ocol = *col;
+ get_dir_rc(dir, row, col, 0);
+ if (((*row == orow) && (*col == ocol)) ||
+ (dungeon[*row][*col] & (HORWALL | VERTWALL)) ||
+ (dungeon[*row][*col] == NOTHING)) {
+ return(0);
+ }
+ if (dungeon[*row][*col] & MONSTER) {
+ if (!imitating(*row, *col)) {
+ return(object_at(&level_monsters, *row, *col));
+ }
+ }
+ }
+}
+
+zap_monster(monster, kind)
+object *monster;
+unsigned short kind;
+{
+ short row, col;
+ object *nm;
+ short tc;
+
+ row = monster->row;
+ col = monster->col;
+
+ switch(kind) {
+ case SLOW_MONSTER:
+ if (monster->m_flags & HASTED) {
+ monster->m_flags &= (~HASTED);
+ } else {
+ monster->slowed_toggle = 0;
+ monster->m_flags |= SLOWED;
+ }
+ break;
+ case HASTE_MONSTER:
+ if (monster->m_flags & SLOWED) {
+ monster->m_flags &= (~SLOWED);
+ } else {
+ monster->m_flags |= HASTED;
+ }
+ break;
+ case TELE_AWAY:
+ tele_away(monster);
+ break;
+ case INVISIBILITY:
+ monster->m_flags |= INVISIBLE;
+ break;
+ case POLYMORPH:
+ if (monster->m_flags & HOLDS) {
+ being_held = 0;
+ }
+ nm = monster->next_monster;
+ tc = monster->trail_char;
+ (void) gr_monster(monster, get_rand(0, MONSTERS-1));
+ monster->row = row;
+ monster->col = col;
+ monster->next_monster = nm;
+ monster->trail_char = tc;
+ if (!(monster->m_flags & IMITATES)) {
+ wake_up(monster);
+ }
+ break;
+ case MAGIC_MISSILE:
+ rogue_hit(monster, 1);
+ break;
+ case CANCELLATION:
+ if (monster->m_flags & HOLDS) {
+ being_held = 0;
+ }
+ if (monster->m_flags & STEALS_ITEM) {
+ monster->drop_percent = 0;
+ }
+ monster->m_flags &= (~(FLIES | FLITS | SPECIAL_HIT | INVISIBLE |
+ FLAMES | IMITATES | CONFUSES | SEEKS_GOLD | HOLDS));
+ break;
+ case DO_NOTHING:
+ message("nothing happens", 0);
+ break;
+ }
+}
+
+tele_away(monster)
+object *monster;
+{
+ short row, col;
+
+ if (monster->m_flags & HOLDS) {
+ being_held = 0;
+ }
+ gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
+ mvaddch(monster->row, monster->col, monster->trail_char);
+ dungeon[monster->row][monster->col] &= ~MONSTER;
+ monster->row = row; monster->col = col;
+ dungeon[row][col] |= MONSTER;
+ monster->trail_char = mvinch(row, col);
+ if (detect_monster || rogue_can_see(row, col)) {
+ mvaddch(row, col, gmc(monster));
+ }
+}
+
+wizardize()
+{
+ char buf[100];
+
+ if (wizard) {
+ wizard = 0;
+ message("not wizard anymore", 0);
+ } else {
+ if (get_input_line("wizard's password:", "", buf, "", 0, 0)) {
+ (void) xxx(1);
+ xxxx(buf, strlen(buf));
+ if (!strncmp(buf, "\247\104\126\272\115\243\027", 7)) {
+ wizard = 1;
+ score_only = 1;
+ message("Welcome, mighty wizard!", 0);
+ } else {
+ message("sorry", 0);
+ }
+ }
+ }
+}
+
+wdrain_life(monster)
+object *monster;
+{
+ short hp;
+ object *lmon, *nm;
+
+ hp = rogue.hp_current / 3;
+ rogue.hp_current = (rogue.hp_current + 1) / 2;
+
+ if (cur_room >= 0) {
+ lmon = level_monsters.next_monster;
+ while (lmon) {
+ nm = lmon->next_monster;
+ if (get_room_number(lmon->row, lmon->col) == cur_room) {
+ wake_up(lmon);
+ (void) mon_damage(lmon, hp);
+ }
+ lmon = nm;
+ }
+ } else {
+ if (monster) {
+ wake_up(monster);
+ (void) mon_damage(monster, hp);
+ }
+ }
+ print_stats(STAT_HP);
+ relight();
+}
+
+bounce(ball, dir, row, col, r)
+short ball, dir, row, col, r;
+{
+ short orow, ocol;
+ char buf[DCOLS], *s;
+ short i, ch, new_dir = -1, damage;
+ static short btime;
+
+ if (++r == 1) {
+ btime = get_rand(3, 6);
+ } else if (r > btime) {
+ return;
+ }
+
+ if (ball == FIRE) {
+ s = "fire";
+ } else {
+ s = "ice";
+ }
+ if (r > 1) {
+ sprintf(buf, "the %s bounces", s);
+ message(buf, 0);
+ }
+ orow = row;
+ ocol = col;
+ do {
+ ch = mvinch(orow, ocol);
+ standout();
+ mvaddch(orow, ocol, ch);
+ get_dir_rc(dir, &orow, &ocol, 1);
+ } while (!( (ocol <= 0) ||
+ (ocol >= DCOLS-1) ||
+ (dungeon[orow][ocol] == NOTHING) ||
+ (dungeon[orow][ocol] & MONSTER) ||
+ (dungeon[orow][ocol] & (HORWALL | VERTWALL)) ||
+ ((orow == rogue.row) && (ocol == rogue.col))));
+ standend();
+ refresh();
+ do {
+ orow = row;
+ ocol = col;
+ ch = mvinch(row, col);
+ mvaddch(row, col, ch);
+ get_dir_rc(dir, &row, &col, 1);
+ } while (!( (col <= 0) ||
+ (col >= DCOLS-1) ||
+ (dungeon[row][col] == NOTHING) ||
+ (dungeon[row][col] & MONSTER) ||
+ (dungeon[row][col] & (HORWALL | VERTWALL)) ||
+ ((row == rogue.row) && (col == rogue.col))));
+
+ if (dungeon[row][col] & MONSTER) {
+ object *monster;
+
+ monster = object_at(&level_monsters, row, col);
+
+ wake_up(monster);
+ if (rand_percent(33)) {
+ sprintf(buf, "the %s misses the %s", s, mon_name(monster));
+ message(buf, 0);
+ goto ND;
+ }
+ if (ball == FIRE) {
+ if (!(monster->m_flags & RUSTS)) {
+ if (monster->m_flags & FREEZES) {
+ damage = monster->hp_to_kill;
+ } else if (monster->m_flags & FLAMES) {
+ damage = (monster->hp_to_kill / 10) + 1;
+ } else {
+ damage = get_rand((rogue.hp_current / 3), rogue.hp_max);
+ }
+ } else {
+ damage = (monster->hp_to_kill / 2) + 1;
+ }
+ sprintf(buf, "the %s hits the %s", s, mon_name(monster));
+ message(buf, 0);
+ (void) mon_damage(monster, damage);
+ } else {
+ damage = -1;
+ if (!(monster->m_flags & FREEZES)) {
+ if (rand_percent(33)) {
+ message("the monster is frozen", 0);
+ monster->m_flags |= (ASLEEP | NAPPING);
+ monster->nap_length = get_rand(3, 6);
+ } else {
+ damage = rogue.hp_current / 4;
+ }
+ } else {
+ damage = -2;
+ }
+ if (damage != -1) {
+ sprintf(buf, "the %s hits the %s", s, mon_name(monster));
+ message(buf, 0);
+ (void) mon_damage(monster, damage);
+ }
+ }
+ } else if ((row == rogue.row) && (col == rogue.col)) {
+ if (rand_percent(10 + (3 * get_armor_class(rogue.armor)))) {
+ sprintf(buf, "the %s misses", s);
+ message(buf, 0);
+ goto ND;
+ } else {
+ damage = get_rand(3, (3 * rogue.exp));
+ if (ball == FIRE) {
+ damage = (damage * 3) / 2;
+ damage -= get_armor_class(rogue.armor);
+ }
+ sprintf(buf, "the %s hits", s);
+ rogue_damage(damage, (object *) 0,
+ ((ball == FIRE) ? KFIRE : HYPOTHERMIA));
+ message(buf, 0);
+ }
+ } else {
+ short nrow, ncol;
+
+ND: for (i = 0; i < 10; i++) {
+ dir = get_rand(0, DIRS-1);
+ nrow = orow;
+ ncol = ocol;
+ get_dir_rc(dir, &nrow, &ncol, 1);
+ if (((ncol >= 0) && (ncol <= DCOLS-1)) &&
+ (dungeon[nrow][ncol] != NOTHING) &&
+ (!(dungeon[nrow][ncol] & (VERTWALL | HORWALL)))) {
+ new_dir = dir;
+ break;
+ }
+ }
+ if (new_dir != -1) {
+ bounce(ball, new_dir, orow, ocol, r);
+ }
+ }
+}