From c1661bd854e32a714ed2ed3043143e98f11a9487 Mon Sep 17 00:00:00 2001 From: elly Date: Sat, 23 Aug 2014 10:27:03 -0400 Subject: [PATCH] Initial commit of rogue around 5.3 (?) --- changes. | 53 +++ curses.c | 694 ++++++++++++++++++++++++++++++++++++ hit.c | 456 ++++++++++++++++++++++++ init.c | 338 ++++++++++++++++++ inventor.c | 774 ++++++++++++++++++++++++++++++++++++++++ level.c | 881 ++++++++++++++++++++++++++++++++++++++++++++++ machdep.c | 674 +++++++++++++++++++++++++++++++++++ main.c | 85 +++++ makefile. | 13 + message.c | 379 ++++++++++++++++++++ monster.c | 867 +++++++++++++++++++++++++++++++++++++++++++++ move.c | 647 ++++++++++++++++++++++++++++++++++ obj. | 0 object.c | 783 ++++++++++++++++++++++++++++++++++++++++ pack.c | 571 ++++++++++++++++++++++++++++++ pathname.h | 36 ++ play.c | 298 ++++++++++++++++ random.c | 140 ++++++++ ring.c | 336 ++++++++++++++++++ rogue.6 | 113 ++++++ rogue.h | 490 ++++++++++++++++++++++++++ room.c | 649 ++++++++++++++++++++++++++++++++++ save.c | 426 ++++++++++++++++++++++ score.c | 582 ++++++++++++++++++++++++++++++ spec_hit.c | 534 ++++++++++++++++++++++++++++ tags. | 326 +++++++++++++++++ throw.c | 322 +++++++++++++++++ trap.c | 283 +++++++++++++++ usd_doc/makefile. | 10 + usd_doc/rogue.me | 835 +++++++++++++++++++++++++++++++++++++++++++ use.c | 618 ++++++++++++++++++++++++++++++++ zap.c | 405 +++++++++++++++++++++ 32 files changed, 13618 insertions(+) create mode 100755 changes. create mode 100755 curses.c create mode 100755 hit.c create mode 100755 init.c create mode 100755 inventor.c create mode 100755 level.c create mode 100755 machdep.c create mode 100755 main.c create mode 100755 makefile. create mode 100755 message.c create mode 100755 monster.c create mode 100755 move.c create mode 100755 obj. create mode 100755 object.c create mode 100755 pack.c create mode 100755 pathname.h create mode 100755 play.c create mode 100755 random.c create mode 100755 ring.c create mode 100755 rogue.6 create mode 100755 rogue.h create mode 100755 room.c create mode 100755 save.c create mode 100755 score.c create mode 100755 spec_hit.c create mode 100755 tags. create mode 100755 throw.c create mode 100755 trap.c create mode 100755 usd_doc/makefile. create mode 100755 usd_doc/rogue.me create mode 100755 use.c create mode 100755 zap.c diff --git a/changes. b/changes. new file mode 100755 index 0000000..73a7135 --- /dev/null +++ b/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/curses.c b/curses.c new file mode 100755 index 0000000..95fd11e --- /dev/null +++ b/curses.c @@ -0,0 +1,694 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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 +#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/hit.c b/hit.c new file mode 100755 index 0000000..d2a6d75 --- /dev/null +++ b/hit.c @@ -0,0 +1,456 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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/init.c b/init.c new file mode 100755 index 0000000..d040501 --- /dev/null +++ b/init.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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 +#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/inventor.c b/inventor.c new file mode 100755 index 0000000..8fa88a8 --- /dev/null +++ b/inventor.c @@ -0,0 +1,774 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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, ": run that way", + ')', ") print current weapon", + NULL, ": run till adjacent", + ']', "] print current armor", + 'f', "f fight till death or near death", + '=', "= print current rings", + 't', "t throw something", + '\001', "^A print Hp-raise average", + 'm', "m move onto without picking up", + 'z', "z zap a wand in a direction", + 'o', "o examine/set options", + '^', "^ 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 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/level.c b/level.c new file mode 100755 index 0000000..1e95f6d --- /dev/null +++ b/level.c @@ -0,0 +1,881 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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/machdep.c b/machdep.c new file mode 100755 index 0000000..d539eaa --- /dev/null +++ b/machdep.c @@ -0,0 +1,674 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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 +#include +#include +#include +#include + +#ifdef UNIX_BSD4_2 +#include +#include +#endif + +#ifdef UNIX_SYSV +#include +#include +#endif + +#include +#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, <c_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, <c_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 flock'ing the score file. The full path name of the + * score file should be defined for any particular site in rogue.h. The + * constants _PATH_SCOREFILE defines this file name. + * + * When the parameter 'l' is non-zero (true), a lock is requested. Otherwise + * the lock is released. + */ + +md_lock(l) +boolean l; +{ + static int fd; + short tries; + + if (l) { + if ((fd = open(_PATH_SCOREFILE, O_RDONLY)) < 1) { + message("cannot lock score file", 0); + return; + } + for (tries = 0; tries < 5; tries++) + if (!flock(fd, LOCK_EX|LOCK_NB)) + return; + } else { + (void)flock(fd, LOCK_NB); + (void)close(fd); + } +} + +/* 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/main.c b/main.c new file mode 100755 index 0000000..97e492c --- /dev/null +++ b/main.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1988, 1993 + * 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 copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 5/31/93"; +#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/makefile. b/makefile. new file mode 100755 index 0000000..9cf5389 --- /dev/null +++ b/makefile. @@ -0,0 +1,13 @@ +# @(#)Makefile 8.1 (Berkeley) 5/31/93 + +PROG= rogue +CFLAGS+=-DUNIX -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} ${LIBCOMPAT} +LDADD= -lcurses -ltermlib -lcompat +HIDEGAME=hidegame +MAN6= rogue.0 + +.include diff --git a/message.c b/message.c new file mode 100755 index 0000000..e77b7bf --- /dev/null +++ b/message.c @@ -0,0 +1,379 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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 +#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/monster.c b/monster.c new file mode 100755 index 0000000..bd73414 --- /dev/null +++ b/monster.c @@ -0,0 +1,867 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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/move.c b/move.c new file mode 100755 index 0000000..d35d5ad --- /dev/null +++ b/move.c @@ -0,0 +1,647 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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/obj. b/obj. new file mode 100755 index 0000000..e69de29 diff --git a/object.c b/object.c new file mode 100755 index 0000000..13dabe6 --- /dev/null +++ b/object.c @@ -0,0 +1,783 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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/pack.c b/pack.c new file mode 100755 index 0000000..7e26b6e --- /dev/null +++ b/pack.c @@ -0,0 +1,571 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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(); + mask = tmask; + 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/pathname.h b/pathname.h new file mode 100755 index 0000000..2d2b9c0 --- /dev/null +++ b/pathname.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 1990, 1993 + * 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 8.1 (Berkeley) 5/31/93 + */ + +#define _PATH_SCOREFILE "/var/games/rogue.scores" diff --git a/play.c b/play.c new file mode 100755 index 0000000..5b890f9 --- /dev/null +++ b/play.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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/random.c b/random.c new file mode 100755 index 0000000..39eb1dd --- /dev/null +++ b/random.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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/ring.c b/ring.c new file mode 100755 index 0000000..e343b2c --- /dev/null +++ b/ring.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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.6 b/rogue.6 new file mode 100755 index 0000000..4c46707 --- /dev/null +++ b/rogue.6 @@ -0,0 +1,113 @@ +.\" Copyright (c) 1988, 1993 +.\" 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 8.1 (Berkeley) 5/31/93 +.\" +.TH ROGUE 6 "May 31, 1993" +.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.h b/rogue.h new file mode 100755 index 0000000..2c694ec --- /dev/null +++ b/rogue.h @@ -0,0 +1,490 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93 + */ + +/* + * 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 +#endif diff --git a/room.c b/room.c new file mode 100755 index 0000000..a470c6c --- /dev/null +++ b/room.c @@ -0,0 +1,649 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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/save.c b/save.c new file mode 100755 index 0000000..76475bb --- /dev/null +++ b/save.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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 +#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/score.c b/score.c new file mode 100755 index 0000000..385a401 --- /dev/null +++ b/score.c @@ -0,0 +1,582 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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 +#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, "r+")) == NULL && + (fp = fopen(_PATH_SCOREFILE, "w+")) == 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/spec_hit.c b/spec_hit.c new file mode 100755 index 0000000..6a02cd4 --- /dev/null +++ b/spec_hit.c @@ -0,0 +1,534 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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/tags. b/tags. new file mode 100755 index 0000000..d787e8c --- /dev/null +++ b/tags. @@ -0,0 +1,326 @@ +Mmain main.c /^main(argc, argv)$/ +add_exp level.c /^add_exp(e, promotion)$/ +add_mazes level.c /^add_mazes()$/ +add_to_pack pack.c /^add_to_pack(obj, pack, condense)$/ +add_traps trap.c /^add_traps()$/ +addch curses.c /^addch(ch)$/ +addstr curses.c /^addstr(str)$/ +aggravate monster.c /^aggravate()$/ +aim_monster monster.c /^aim_monster(monster)$/ +alloc_object object.c /^alloc_object()$/ +bounce zap.c /^bounce(ball, dir, row, col, r)$/ +byebye init.c /^byebye()$/ +c_object_for_wizard object.c /^c_object_for_wizard()$/ +call_it pack.c /^call_it()$/ +can_move move.c /^can_move(row1, col1, row2, col2) $/ +can_turn move.c /^can_turn(nrow, ncol)$/ +center score.c /^center(row, buf)$/ +check_duplicate pack.c /^check_duplicate(obj, pack)$/ +check_gold_seeker spec_hit.c /^check_gold_seeker(monster)$/ +check_hunger move.c /^check_hunger(msg_only)$/ +check_imitator spec_hit.c /^check_imitator(monster)$/ +check_message message.c /^check_message()$/ +check_up level.c /^check_up()$/ +clean_up init.c /^clean_up(estr)$/ +clear curses.c /^clear()$/ +clear_buffers curses.c /^clear_buffers()$/ +clear_level level.c /^clear_level()$/ +clrtoeol curses.c /^clrtoeol()$/ +cnfs use.c /^cnfs()$/ +coin_toss random.c /^coin_toss()$/ +connect_rooms level.c /^connect_rooms(room1, room2)$/ +cough_up spec_hit.c /^cough_up(monster)$/ +create_monster monster.c /^create_monster()$/ +crmode curses.c /^crmode()$/ +damage_for_strength hit.c /^damage_for_strength()$/ +darken_room room.c /^darken_room(rn)$/ +disappear spec_hit.c /^disappear(monster)$/ +do_args init.c /^do_args(argc, argv)$/ +do_opts init.c /^do_opts()$/ +do_put_on ring.c /^do_put_on(ring, on_left)$/ +do_shell room.c /^do_shell()$/ +do_wear pack.c /^do_wear(obj)$/ +do_wield pack.c /^do_wield(obj)$/ +dr_course room.c /^dr_course(monster, entering, row, col)$/ +drain_life spec_hit.c /^drain_life()$/ +draw_magic_map room.c /^draw_magic_map()$/ +draw_simple_passage level.c /^draw_simple_passage(row1, col1, row2, col2, dir)$/ +drop pack.c /^drop()$/ +drop_check level.c /^drop_check()$/ +drop_level spec_hit.c /^drop_level()$/ +eat use.c /^eat()$/ +edit_opts room.c /^edit_opts()$/ +endwin curses.c /^endwin()$/ +env_get_value init.c /^env_get_value(s, e, add_blank)$/ +error_save init.c /^error_save()$/ +fight hit.c /^fight(to_the_death)$/ +fill_it level.c /^fill_it(rn, do_rec_de)$/ +fill_out_level level.c /^fill_out_level()$/ +flame_broil spec_hit.c /^flame_broil(monster)$/ +flit monster.c /^flit(monster)$/ +flop_weapon throw.c /^flop_weapon(weapon, row, col)$/ +free_object object.c /^free_object(obj)$/ +free_stuff object.c /^free_stuff(objlist)$/ +freeze spec_hit.c /^freeze(monster)$/ +get_armor_class object.c /^get_armor_class(obj)$/ +get_com_id inventory.c /^get_com_id(index, ch)$/ +get_damage hit.c /^get_damage(ds, r)$/ +get_desc inventory.c /^get_desc(obj, desc)$/ +get_dir spec_hit.c /^get_dir(srow, scol, drow, dcol)$/ +get_dir_rc hit.c /^get_dir_rc(dir, row, col, allow_off_screen)$/ +get_dungeon_char room.c /^get_dungeon_char(row, col)$/ +get_ench_color use.c /^get_ench_color()$/ +get_exp_level level.c /^get_exp_level(e)$/ +get_food object.c /^get_food(obj, force_ration)$/ +get_hit_chance hit.c /^get_hit_chance(weapon)$/ +get_id_table inventory.c /^get_id_table(obj)$/ +get_input_line message.c /^get_input_line(prompt, insert, buf, if_cancelled, / +get_letter_object object.c /^get_letter_object(ch)$/ +get_mask_char room.c /^get_mask_char(mask)$/ +get_number hit.c /^get_number(s)$/ +get_oth_room room.c /^get_oth_room(rn, row, col)$/ +get_rand random.c /^get_rand(x, y)$/ +get_room_number room.c /^get_room_number(row, col)$/ +get_term_info curses.c /^get_term_info()$/ +get_thrown_at_monster throw.c /^get_thrown_at_monster(obj, dir, row, col)$/ +get_value score.c /^get_value(obj)$/ +get_w_damage hit.c /^get_w_damage(obj)$/ +get_wand_and_ring_materials inventory.c /^get_wand_and_ring_materials()$/ +get_weapon_damage hit.c /^get_weapon_damage(weapon)$/ +get_zapped_monster zap.c /^get_zapped_monster(dir, row, col)$/ +gmc monster.c /^gmc(monster)$/ +gmc_row_col monster.c /^gmc_row_col(row, col)$/ +go_blind use.c /^go_blind()$/ +gold_at spec_hit.c /^gold_at(row, col)$/ +gr_armor object.c /^gr_armor(obj)$/ +gr_dir move.c /^gr_dir()$/ +gr_monster monster.c /^gr_monster(monster, mn)$/ +gr_obj_char monster.c /^gr_obj_char()$/ +gr_object object.c /^gr_object()$/ +gr_potion object.c /^gr_potion(obj)$/ +gr_ring ring.c /^gr_ring(ring, assign_wk)$/ +gr_room room.c /^gr_room()$/ +gr_row_col room.c /^gr_row_col(row, col, mask)$/ +gr_scroll object.c /^gr_scroll(obj)$/ +gr_wand object.c /^gr_wand(obj)$/ +gr_weapon object.c /^gr_weapon(obj, assign_wk)$/ +gr_what_is object.c /^gr_what_is()$/ +hallucinate use.c /^hallucinate()$/ +has_amulet pack.c /^has_amulet()$/ +has_been_touched save.c /^has_been_touched(saved_time, mod_time)$/ +heal move.c /^heal()$/ +hide_boxed_passage level.c /^hide_boxed_passage(row1, col1, row2, col2, n)$/ +hold_monster use.c /^hold_monster()$/ +hp_raise level.c /^hp_raise()$/ +id_all score.c /^id_all()$/ +id_com inventory.c /^id_com()$/ +id_trap trap.c /^id_trap()$/ +id_type inventory.c /^id_type()$/ +idntfy use.c /^idntfy()$/ +imitating spec_hit.c /^imitating(row, col)$/ +init init.c /^init(argc, argv)$/ +init_str init.c /^init_str(str, dflt)$/ +initscr curses.c /^initscr()$/ +insert_score score.c /^insert_score(scores, n_names, n_name, rank, n, mon/ +inv_armor_weapon inventory.c /^inv_armor_weapon(is_weapon)$/ +inv_rings ring.c /^inv_rings()$/ +inventory inventory.c /^inventory(pack, mask)$/ +is_all_connected room.c /^is_all_connected()$/ +is_digit message.c /^is_digit(ch)$/ +is_direction move.c /^is_direction(c, d)$/ +is_pack_letter pack.c /^is_pack_letter(c, mask)$/ +is_passable move.c /^is_passable(row, col)$/ +is_vowel score.c /^is_vowel(ch)$/ +kick_into_pack pack.c /^kick_into_pack()$/ +killed_by score.c /^killed_by(monster, other)$/ +lget_number hit.c /^lget_number(s)$/ +light_passage room.c /^light_passage(row, col)$/ +light_up_room room.c /^light_up_room(rn)$/ +m_confuse spec_hit.c /^m_confuse(monster)$/ +make_level level.c /^make_level()$/ +make_maze level.c /^make_maze(r, c, tr, br, lc, rc)$/ +make_party object.c /^make_party()$/ +make_room level.c /^make_room(rn, r1, r2, r3)$/ +make_scroll_titles inventory.c /^make_scroll_titles()$/ +mask_pack pack.c /^mask_pack(pack, mask)$/ +mask_room level.c /^mask_room(rn, row, col, mask)$/ +md_cbreak_no_echo_nonl machdep.c /^md_cbreak_no_echo_nonl(on)$/ +md_control_keybord machdep.c /^md_control_keybord(mode)$/ +md_df machdep.c /^md_df(fname)$/ +md_exit machdep.c /^md_exit(status)$/ +md_gct machdep.c /^md_gct(rt_buf)$/ +md_gdtcf machdep.c /^md_gdtcf()$/ +md_get_file_id machdep.c /^md_get_file_id(fname)$/ +md_getenv machdep.c /^md_getenv(name)$/ +md_gfmt machdep.c /^md_gfmt(fname, rt_buf)$/ +md_gln machdep.c /^md_gln()$/ +md_gseed machdep.c /^md_gseed()$/ +md_heed_signals machdep.c /^md_heed_signals()$/ +md_ignore_signals machdep.c /^md_ignore_signals()$/ +md_link_count machdep.c /^md_link_count(fname)$/ +md_lock machdep.c /^md_lock(l)$/ +md_malloc machdep.c /^md_malloc(n)$/ +md_shell machdep.c /^md_shell(shell)$/ +md_sleep machdep.c /^md_sleep(nsecs)$/ +md_slurp machdep.c /^md_slurp()$/ +md_tstp machdep.c /^md_tstp()$/ +message message.c /^message(msg, intrpt)$/ +mix_colors inventory.c /^mix_colors()$/ +mix_random_rooms level.c /^mix_random_rooms()$/ +mon_can_go monster.c /^mon_can_go(monster, row, col)$/ +mon_damage hit.c /^mon_damage(monster, damage)$/ +mon_hit hit.c /^mon_hit(monster)$/ +mon_name monster.c /^mon_name(monster)$/ +mon_sees monster.c /^mon_sees(monster, row, col)$/ +move curses.c /^move(row, col)$/ +move_confused monster.c /^move_confused(monster)$/ +move_mon_to monster.c /^move_mon_to(monster, row, col)$/ +move_onto move.c /^move_onto()$/ +mtry monster.c /^mtry(monster, row, col)$/ +multiple_move_rogue move.c /^multiple_move_rogue(dirch)$/ +mv_1_monster monster.c /^mv_1_monster(monster, row, col)$/ +mv_aquatars monster.c /^mv_aquatars()$/ +mv_mons monster.c /^mv_mons()$/ +mvaddch curses.c /^mvaddch(row, col, ch)$/ +mvaddstr curses.c /^mvaddstr(row, col, str)$/ +mvinch curses.c /^mvinch(row, col)$/ +name_cmp score.c /^name_cmp(s1, s2)$/ +name_of object.c /^name_of(obj)$/ +next_avail_ichar pack.c /^next_avail_ichar()$/ +next_to_something move.c /^next_to_something(drow, dcol)$/ +nickize score.c /^nickize(buf, score, n_name)$/ +no_room_for_monster monster.c /^no_room_for_monster(rn)$/ +noecho curses.c /^noecho()$/ +nonl curses.c /^nonl()$/ +object_at object.c /^object_at(pack, row, col)$/ +one_move_rogue move.c /^one_move_rogue(dirch, pickup)$/ +onintr init.c /^onintr()$/ +opt_erase room.c /^opt_erase(i)$/ +opt_go room.c /^opt_go(i)$/ +opt_show room.c /^opt_show(i)$/ +pack_count pack.c /^pack_count(new_obj)$/ +pack_letter pack.c /^pack_letter(prompt, mask)$/ +pad message.c /^pad(s, n)$/ +party_monsters monster.c /^party_monsters(rn, n)$/ +party_objects room.c /^party_objects(rn)$/ +pick_up pack.c /^pick_up(row, col, status)$/ +place_at object.c /^place_at(obj, row, col)$/ +plant_gold object.c /^plant_gold(row, col, is_maze)$/ +play_level play.c /^play_level()$/ +player_init init.c /^player_init()$/ +potion_heal use.c /^potion_heal(extra)$/ +pr_com_id inventory.c /^pr_com_id(ch)$/ +pr_motion_char inventory.c /^pr_motion_char(ch)$/ +print_stats message.c /^print_stats(stat_mask)$/ +put_amulet object.c /^put_amulet()$/ +put_char_at curses.c /^put_char_at(row, col, ch)$/ +put_cursor curses.c /^put_cursor(row, col)$/ +put_door level.c /^put_door(rm, dir, row, col)$/ +put_gold object.c /^put_gold()$/ +put_m_at monster.c /^put_m_at(row, col, monster)$/ +put_mons monster.c /^put_mons()$/ +put_objects object.c /^put_objects()$/ +put_on_ring ring.c /^put_on_ring()$/ +put_player level.c /^put_player(nr)$/ +put_scores score.c /^put_scores(monster, other)$/ +put_st_char curses.c /^put_st_char(ch)$/ +put_stairs object.c /^put_stairs()$/ +quaff use.c /^quaff()$/ +quit score.c /^quit(from_intrpt)$/ +r_index message.c /^r_index(str, ch, last)$/ +r_read save.c /^r_read(fp, buf, n)$/ +r_write save.c /^r_write(fp, buf, n)$/ +rand_around throw.c /^rand_around(i, r, c)$/ +rand_percent random.c /^rand_percent(percentage)$/ +rand_place object.c /^rand_place(obj)$/ +read_pack save.c /^read_pack(pack, fp, is_rogue)$/ +read_scroll use.c /^read_scroll()$/ +read_string save.c /^read_string(s, fp)$/ +recursive_deadend level.c /^recursive_deadend(rn, offsets, srow, scol)$/ +refresh curses.c /^refresh()$/ +reg_move move.c /^reg_move()$/ +relight use.c /^relight()$/ +remessage message.c /^remessage(c)$/ +remove_ring ring.c /^remove_ring()$/ +rest move.c /^rest(count)$/ +restore save.c /^restore(fname)$/ +rgetchar message.c /^rgetchar()$/ +ring_stats ring.c /^ring_stats(pr)$/ +rogue_can_see monster.c /^rogue_can_see(row, col)$/ +rogue_damage hit.c /^rogue_damage(d, monster, other)$/ +rogue_hit hit.c /^rogue_hit(monster, force_hit)$/ +rogue_is_around monster.c /^rogue_is_around(row, col)$/ +rrandom random.c /^rrandom()$/ +rust spec_hit.c /^rust(monster)$/ +rw_dungeon save.c /^rw_dungeon(fp, rw)$/ +rw_id save.c /^rw_id(id_table, fp, n, wr)$/ +rw_rooms save.c /^rw_rooms(fp, rw)$/ +s_con_mon hit.c /^s_con_mon(monster)$/ +same_col level.c /^same_col(room1, room2)$/ +same_row level.c /^same_row(room1, room2)$/ +save_game save.c /^save_game()$/ +save_into_file save.c /^save_into_file(sfile)$/ +save_screen message.c /^save_screen()$/ +search trap.c /^search(n, is_auto)$/ +seek_gold spec_hit.c /^seek_gold(monster)$/ +sell_pack score.c /^sell_pack()$/ +sf_error score.c /^sf_error()$/ +show_average_hp level.c /^show_average_hp()$/ +show_monsters monster.c /^show_monsters()$/ +show_objects object.c /^show_objects()$/ +show_traps trap.c /^show_traps()$/ +single_inv inventory.c /^single_inv(ichar)$/ +sound_bell message.c /^sound_bell()$/ +special_hit spec_hit.c /^special_hit(monster)$/ +srrandom random.c /^srrandom(x)$/ +standend curses.c /^standend()$/ +standout curses.c /^standout()$/ +start_window init.c /^start_window()$/ +steal_gold spec_hit.c /^steal_gold(monster)$/ +steal_item spec_hit.c /^steal_item(monster)$/ +sting spec_hit.c /^sting(monster)$/ +stop_window init.c /^stop_window()$/ +swap level.c /^#define swap(x,y) {t = x; x = y; y = t;}$/ +take_a_nap use.c /^take_a_nap()$/ +take_from_pack pack.c /^take_from_pack(obj, pack)$/ +take_off pack.c /^take_off()$/ +tc_cmget curses.c /^tc_cmget()$/ +tc_gets curses.c /^tc_gets(ibuf, tcstr)$/ +tc_gnum curses.c /^tc_gnum(ibuf, n)$/ +tc_gtdata curses.c /^tc_gtdata(fp, buf)$/ +tc_tname curses.c /^tc_tname(fp, term, buf)$/ +tele use.c /^tele()$/ +tele_away zap.c /^tele_away(monster)$/ +throw throw.c /^throw()$/ +throw_at_monster throw.c /^throw_at_monster(monster, weapon)$/ +to_hit hit.c /^to_hit(obj)$/ +trap_at trap.c /^trap_at(row, col)$/ +trap_player trap.c /^trap_player(row, col)$/ +try_to_cough spec_hit.c /^try_to_cough(row, col, obj)$/ +tstp curses.c /^tstp()$/ +turn_passage move.c /^turn_passage(dir, fast)$/ +un_put_on ring.c /^un_put_on(ring)$/ +unblind use.c /^unblind()$/ +unconfuse use.c /^unconfuse()$/ +uncurse_all use.c /^uncurse_all()$/ +unhallucinate use.c /^unhallucinate()$/ +unwear pack.c /^unwear(obj)$/ +unwield pack.c /^unwield(obj)$/ +vanish use.c /^vanish(obj, rm, pack)$/ +visit_rooms room.c /^visit_rooms(rn)$/ +wait_for_ack pack.c /^wait_for_ack()$/ +wake_room monster.c /^wake_room(rn, entering, row, col)$/ +wake_up monster.c /^wake_up(monster)$/ +wanderer monster.c /^wanderer()$/ +wdrain_life zap.c /^wdrain_life(monster)$/ +wear pack.c /^wear()$/ +wield pack.c /^wield()$/ +win score.c /^win()$/ +wizardize zap.c /^wizardize()$/ +wrefresh curses.c /^wrefresh(scr)$/ +write_pack save.c /^write_pack(pack, fp)$/ +write_string save.c /^write_string(s, fp)$/ +xxx score.c /^xxx(st)$/ +xxxx score.c /^xxxx(buf, n)$/ +zap_monster zap.c /^zap_monster(monster, kind)$/ +zapp zap.c /^zapp()$/ diff --git a/throw.c b/throw.c new file mode 100755 index 0000000..0af3117 --- /dev/null +++ b/throw.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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/trap.c b/trap.c new file mode 100755 index 0000000..518a321 --- /dev/null +++ b/trap.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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/usd_doc/makefile. b/usd_doc/makefile. new file mode 100755 index 0000000..3df0ddb --- /dev/null +++ b/usd_doc/makefile. @@ -0,0 +1,10 @@ +# @(#)Makefile 8.1 (Berkeley) 6/8/93 + +DIR= usd/30.rogue +SRCS= rogue.me +MACROS= -me + +paper.${PRINTER}: ${SRCS} + ${TBL} ${SRCS} | ${ROFF} > ${.TARGET} + +.include diff --git a/usd_doc/rogue.me b/usd_doc/rogue.me new file mode 100755 index 0000000..d65f280 --- /dev/null +++ b/usd_doc/rogue.me @@ -0,0 +1,835 @@ +.\" Copyright (c) 1986, 1993 +.\" 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.me 8.1 (Berkeley) 6/8/93 +.\" +.ds E \s-2\s0 +.ds R \s-2\s0 +.ds U \s-2UNIX\s0 +.ie t .ds _ \d\(mi\u +.el .ds _ _ +.de Cs +\&\\$3\*(lq\\$1\*(rq\\$2 +.. +.sp 5 +.ce 1000 +.ps +4 +.vs +4p +.b +A Guide to the Dungeons of Doom +.r +.vs +.ps +.sp 2 +.i +Michael C. Toy +Kenneth C. R. C. Arnold +.r +.sp 2 +Computer Systems Research Group +Department of Electrical Engineering and Computer Science +University of California +Berkeley, California 94720 +.sp 4 +.i ABSTRACT +.ce 0 +.(b I F +.bi Rogue +is a visual CRT based fantasy game +which runs under the \*U\(dg timesharing system. +.(f +\fR\(dg\*U is a trademark of Bell Laboratories\fP +.)f +This paper describes how to play rogue, +and gives a few hints +for those who might otherwise get lost in the Dungeons of Doom. +.)b +\".he '''\fBA Guide to the Dungeons of Doom\fP' +\" .fo ''- % -'' +.eh 'USD:30-%''A Guide to the Dungeons of Doom' +.oh 'A Guide to the Dungeons of Doom''USD:30-%' +.sh 1 Introduction +.pp +You have just finished your years as a student at the local fighter's guild. +After much practice and sweat you have finally completed your training +and are ready to embark upon a perilous adventure. +As a test of your skills, +the local guildmasters have sent you into the Dungeons of Doom. +Your task is to return with the Amulet of Yendor. +Your reward for the completion of this task +will be a full membership in the local guild. +In addition, +you are allowed to keep all the loot you bring back from the dungeons. +.pp +In preparation for your journey, +you are given an enchanted mace, +a bow, and a quiver of arrows +taken from a dragon's hoard in the far off Dark Mountains. +You are also outfitted with elf-crafted armor +and given enough food to reach the dungeons. +You say goodbye to family and friends for what may be the last time +and head up the road. +.pp +You set out on your way to the dungeons +and after several days of uneventful travel, +you see the ancient ruins +that mark the entrance to the Dungeons of Doom. +It is late at night, +so you make camp at the entrance +and spend the night sleeping under the open skies. +In the morning you gather your weapons, +put on your armor, +eat what is almost your last food, +and enter the dungeons. +.sh 1 "What is going on here?" +.pp +You have just begun a game of rogue. +Your goal is to grab as much treasure as you can, +find the Amulet of Yendor, +and get out of the Dungeons of Doom alive. +On the screen, +a map of where you have been +and what you have seen on the current dungeon level is kept. +As you explore more of the level, +it appears on the screen in front of you. +.pp +Rogue differs from most computer fantasy games in that it is screen oriented. +Commands are all one or two keystrokes\** +.(f +\** As opposed to pseudo English sentences. +.)f +and the results of your commands +are displayed graphically on the screen rather +than being explained in words.\** +.(f +\** A minimum screen size of 24 lines by 80 columns is required. +If the screen is larger, only the 24x80 section will be used +for the map. +.)f +.pp +Another major difference between rogue and other computer fantasy games +is that once you have solved all the puzzles in a standard fantasy game, +it has lost most of its excitement and it ceases to be fun. +Rogue, +on the other hand, +generates a new dungeon every time you play it +and even the author finds it an entertaining and exciting game. +.sh 1 "What do all those things on the screen mean?" +.pp +In order to understand what is going on in rogue +you have to first get some grasp of what rogue is doing with the screen. +The rogue screen is intended +to replace the \*(lqYou can see ...\*(rq descriptions +of standard fantasy games. +Figure 1 is a sample of what a rogue screen might look like. +.(z +.hl +.nf +.TS +center; +ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce. +- - - - - - - - - - - - +| . . . . . . . . . . + +| . . @ . . . . ] . . | +| . . . . B . . . . . | +| . . . . . . . . . . | +- - - - - + - - - - - - +.TE + + +.ce 1000 +Level: 1 Gold: 0 Hp: 12(12) Str: 16(16) Arm: 4 Exp: 1/0 + +Figure 1 +.ce +.hl +.)z +.sh 2 "The bottom line" +.pp +At the bottom line of the screen +are a few pieces of cryptic information +describing your current status. +Here is an explanation of what these things mean: +.ip Level \w'Level\ \ 'u +This number indicates how deep you have gone in the dungeon. +It starts at one and goes up as you go deeper into the dungeon. +.ip Gold \w'Level\ \ 'u +The number of gold pieces you have managed to find +and keep with you so far. +.ip Hp \w'Level\ \ 'u +Your current and maximum health points. +Health points indicate how much damage you can take before you die. +The more you get hit in a fight, +the lower they get. +You can regain health points by resting. +The number in parentheses +is the maximum number your health points can reach. +.ip Str \w'Level\ \ 'u +Your current strength and maximum ever strength. +This can be any integer less than or equal to 99, +or greater than or equal to 1. +The higher the number, +the stronger you are. +The number in the parentheses +is the maximum strength you have attained so far this game. +.ip Arm \w'Level\ \ 'u +Your current armor protection. +This number indicates how effective your armor is +in stopping blows from unfriendly creatures. +The higher this number is, +the more effective the armor. +.ip Exp \w'Level\ \ 'u +These two numbers give your current experience level +and experience points. +As you do things, +you gain experience points. +At certain experience point totals, +you gain an experience level. +The more experienced you are, +the better you are able to fight and to withstand magical attacks. +.sh 2 "The top line" +.pp +The top line of the screen is reserved +for printing messages that describe things +that are impossible to represent visually. +If you see a \*(lq--More--\*(rq on the top line, +this means that rogue wants to print another message on the screen, +but it wants to make certain +that you have read the one that is there first. +To read the next message, +just type a space. +.sh 2 "The rest of the screen" +.pp +The rest of the screen is the map of the level +as you have explored it so far. +Each symbol on the screen represents something. +Here is a list of what the various symbols mean: +.ip @ +This symbol represents you, the adventurer. +.ip "-\^|" +These symbols represent the walls of rooms. +.ip + +A door to/from a room. +.ip . +The floor of a room. +.ip # +The floor of a passage between rooms. +.ip * +A pile or pot of gold. +.ip ) +A weapon of some sort. +.ip ] +A piece of armor. +.ip ! +A flask containing a magic potion. +.ip ? +A piece of paper, usually a magic scroll. +.ip = +A ring with magic properties +.ip / +A magical staff or wand +.ip ^ +A trap, watch out for these. +.ip % +A staircase to other levels +.ip : +A piece of food. +.ip A-Z +The uppercase letters +represent the various inhabitants of the Dungeons of Doom. +Watch out, they can be nasty and vicious. +.sh 1 Commands +.pp +Commands are given to rogue by typing one or two characters. +Most commands can be preceded by a count to repeat them +(e.g. typing +.Cs 10s +will do ten searches). +Commands for which counts make no sense +have the count ignored. +To cancel a count or a prefix, +type \*E. +The list of commands is rather long, +but it can be read at any time during the game with the +.Cs ? +command. +Here it is for reference, +with a short explanation of each command. +.ip ? +The help command. +Asks for a character to give help on. +If you type a +.Cs * , +it will list all the commands, +otherwise it will explain what the character you typed does. +.ip / +This is the \*(lqWhat is that on the screen?\*(rq command. +A +.Cs / +followed by any character that you see on the level, +will tell you what that character is. +For instance, +typing +.Cs /@ +will tell you that the +.Cs @ +symbol represents you, the player. +.ip "h, H, ^H" +Move left. +You move one space to the left. +If you use upper case +.Cs h , +you will continue to move left until you run into something. +This works for all movement commands +(e.g. +.Cs L +means run in direction +.Cs l ) +If you use the \*(lqcontrol\*(rq +.Cs h , +you will continue moving in the specified direction +until you pass something interesting or run into a wall. +You should experiment with this, +since it is a very useful command, +but very difficult to describe. +This also works for all movement commands. +.ip j +Move down. +.ip k +Move up. +.ip l +Move right. +.ip y +Move diagonally up and left. +.ip u +Move diagonally up and right. +.ip b +Move diagonally down and left. +.ip n +Move diagonally down and right. +.ip t +Throw an object. +This is a prefix command. +When followed with a direction +it throws an object in the specified direction. +(e.g. type +.Cs th +to throw +something to the left.) +.ip f +Fight until someone dies. +When followed with a direction +this will force you to fight the creature in that direction +until either you or it bites the big one. +.ip m +Move onto something without picking it up. +This will move you one space in the direction you specify and, +if there is an object there you can pick up, +it won't do it. +.ip z +Zap prefix. +Point a staff or wand in a given direction +and fire it. +Even non-directional staves must be pointed in some direction +to be used. +.ip ^ +Identify trap command. +If a trap is on your map +and you can't remember what type it is, +you can get rogue to remind you +by getting next to it and typing +.Cs ^ +followed by the direction that would move you on top of it. +.ip s +Search for traps and secret doors. +Examine each space immediately adjacent to you +for the existence of a trap or secret door. +There is a large chance that even if there is something there, +you won't find it, +so you might have to search a while before you find something. +.ip > +Climb down a staircase to the next level. +Not surprisingly, this can only be done if you are standing on staircase. +.ip < +Climb up a staircase to the level above. +This can't be done without the Amulet of Yendor in your possession. +.ip "." +Rest. +This is the \*(lqdo nothing\*(rq command. +This is good for waiting and healing. +.ip , +Pick up something. +This picks up whatever you are currently standing on, +if you are standing on anything at all. +.ip i +Inventory. +List what you are carrying in your pack. +.ip I +Selective inventory. +Tells you what a single item in your pack is. +.ip q +Quaff one of the potions you are carrying. +.ip r +Read one of the scrolls in your pack. +.ip e +Eat food from your pack. +.ip w +Wield a weapon. +Take a weapon out of your pack and carry it for use in combat, +replacing the one you are currently using (if any). +.ip W +Wear armor. +You can only wear one suit of armor at a time. +This takes extra time. +.ip T +Take armor off. +You can't remove armor that is cursed. +This takes extra time. +.ip P +Put on a ring. +You can wear only two rings at a time +(one on each hand). +If you aren't wearing any rings, +this command will ask you which hand you want to wear it on, +otherwise, it will place it on the unused hand. +The program assumes that you wield your sword in your right hand. +.ip R +Remove a ring. +If you are only wearing one ring, +this command takes it off. +If you are wearing two, +it will ask you which one you wish to remove, +.ip d +Drop an object. +Take something out of your pack and leave it lying on the floor. +Only one object can occupy each space. +You cannot drop a cursed object at all +if you are wielding or wearing it. +.ip c +Call an object something. +If you have a type of object in your pack +which you wish to remember something about, +you can use the call command to give a name to that type of object. +This is usually used when you figure out what a +potion, scroll, ring, or staff is +after you pick it up but before it is truly identified. Each type of +scroll and potion will become identified after its first use. +.ip o +Examine and set options. +This command is further explained in the section on options. +.ip ^R +Redraws the screen. +Useful if spurious messages or transmission errors +have messed up the display. +.ip ^P +Print last message. +Useful when a message disappears before you can read it. +Consecutive repetitions of this command will reveal the last +five messages. +.ip \*E +Cancel a command, prefix, or count. +.ip ! +Escape to a shell for some commands. +.ip Q +Quit. +Leave the game. +.ip S +Save the current game in a file. +It will ask you whether you wish to use the default save file. +.i Caveat : +Rogue won't let you start up a copy of a saved game, +and it removes the save file as soon as you start up a restored game. +This is to prevent people from saving a game just before a dangerous position +and then restarting it if they die. +To restore a saved game, +give the file name as an argument to rogue. +As in +.ti +1i +.nf +% rogue \fIsave\*_file\fP +.ip v +Prints the program version number. +.ip ) +Print the weapon you are currently wielding +.ip ] +Print the armor you are currently wearing +.ip = +Print the rings you are currently wearing +.sh 1 Rooms +.pp +Rooms in the dungeons are lit as you enter them. +Upon leaving a room, +all monsters inside the room are erased from the screen. +In the darkness of a corridor, you can only see one space +in all directions around you. +.sh 1 Fighting +.pp +If you see a monster and you wish to fight it, +just attempt to run into it. +Many times a monster you find will mind its own business +unless you attack it. +It is often the case that discretion is the better part of valor. +.sh 1 "Objects you can find" +.pp +When you find something in the dungeon, +it is common to want to pick the object up. +This is accomplished in rogue by walking over the object +(unless you use the +.Cs m +prefix, see above). +If you are carrying too many things, +the program will tell you and it won't pick up the object, +otherwise it will add it to your pack +and tell you what you just picked up. +.pp +Many of the commands that operate on objects must prompt you +to find out which object you want to use. +If you change your mind and don't want to do that command after all, +just type an \*E and the command will be aborted. +.pp +Some objects, like armor and weapons, +are easily differentiated. +Others, like scrolls and potions, +are given labels which vary according to type. +During a game, +any two of the same kind of object +with the same label +are the same type. +However, +the labels will vary from game to game. +.pp +When you use one of these labeled objects, +if its effect may be obvious. Potions or scrolls will +become identified at this point, but not other items. +You may want to call these other items something +so you will recognize it later, +you can use the +.Cs call +command +(see above). +.sh 2 Weapons +.pp +Some weapons, +like arrows, +come in bunches, +but most come one at a time. +In order to use a weapon, +you must wield it. +To fire an arrow out of a bow, +you must first wield the bow, +then throw the arrow. +You can only wield one weapon at a time, +but you can't change weapons if the one +you are currently wielding is cursed. +The commands to use weapons are +.Cs w +(wield) +and +.Cs t +(throw). +.sh 2 Armor +.pp +There are various sorts of armor lying around in the dungeon. +Some of it is enchanted, +some is cursed, +and some is just normal. +Different armor types have different armor protection. +The higher the armor protection, +the more protection the armor affords against the blows of monsters. +Here is a list of the various armor types and their normal armor protection: +.(b +.TS +box center; +l r. +\ \ \fIType Protection\fP +None 0 +Leather armor 2 +Studded leather / Ring mail 3 +Scale mail 4 +Chain mail 5 +Banded mail / Splint mail 6 +Plate mail 7 +.TE +.)b +.lp +If a piece of armor is enchanted, +its armor protection will be higher than normal. +If a suit of armor is cursed, +its armor protection will be lower, +and you will not be able to remove it. +However, not all armor with a protection that is lower than normal is cursed. +.pp +The commands to use weapons are +.Cs W +(wear) +and +.Cs T +(take off). +.sh 2 Scrolls +.pp +Scrolls come with titles in an unknown tongue\**. +.(f +\** Actually, it's a dialect spoken only by the twenty-seven members +of a tribe in Outer Mongolia, +but you're not supposed to +.i know +that. +.)f +After you read a scroll, +it disappears from your pack. +The command to use a scroll is +.Cs r +(read). +.sh 2 Potions +.pp +Potions are labeled by the color of the liquid inside the flask. +They disappear after being quaffed. +The command to use a scroll is +.Cs q +(quaff). +.sh 2 "Staves and Wands" +.pp +Staves and wands do the same kinds of things. +Staves are identified by a type of wood; +wands by a type of metal or bone. +They are generally things you want to do to something +over a long distance, +so you must point them at what you wish to affect +to use them. +Some staves are not affected by the direction they are pointed, though. +Staves come with multiple magic charges, +the number being random, +and when they are used up, +the staff is just a piece of wood or metal. +.pp +The command to use a wand or staff is +.Cs z +(zap) +.sh 2 Rings +.pp +Rings are very useful items, +since they are relatively permanent magic, +unlike the usually fleeting effects of potions, scrolls, and staves. +Of course, +the bad rings are also more powerful. +Most rings also cause you to use up food more rapidly, +the rate varying with the type of ring. +Rings are differentiated by their stone settings. +The commands to use rings are +.Cs P +(put on) +and +.Cs R +(remove). +.sh 2 Food +.pp +Food is necessary to keep you going. +If you go too long without eating you will faint, +and eventually die of starvation. +The command to use food is +.Cs e +(eat). +.sh 1 Options +.pp +Due to variations in personal tastes +and conceptions of the way rogue should do things, +there are a set of options you can set +that cause rogue to behave in various different ways. +.sh 2 "Setting the options" +.pp +There are two ways to set the options. +The first is with the +.Cs o +command of rogue; +the second is with the +.Cs ROGUEOPTS +environment variable\**. +.(f +\** On Version 6 systems, +there is no equivalent of the ROGUEOPTS feature. +.br +.)f +.br +.sh 3 "Using the `o' command" +.pp +When you type +.Cs o +in rogue, +it clears the screen +and displays the current settings for all the options. +It then places the cursor by the value of the first option +and waits for you to type. +You can type a \*R +which means to go to the next option, +a +.Cs \- +which means to go to the previous option, +an \*E +which means to return to the game, +or you can give the option a value. +For boolean options this merely involves typing +.Cs t +for true or +.Cs f +for false. +For string options, +type the new value followed by a \*R. +.sh 3 "Using the ROGUEOPTS variable" +.pp +The ROGUEOPTS variable is a string +containing a comma separated list of initial values +for the various options. +Boolean variables can be turned on by listing their name +or turned off by putting a +.Cs no +in front of the name. +Thus to set up an environment variable so that +.b jump +is on, +.b passgo +is off, +and the +.b name +is set to \*(lqBlue Meanie\*(rq, +use the command +.nf +.ti +3n +% setenv ROGUEOPTS "jump,nopassgo,name=Blue Meanie"\** +.fi +.(f +\** +For those of you who use the Bourne shell sh (1), the commands would be +.in +3 +.nf +$ ROGUEOPTS="jump,nopassgo,name=Blue Meanie" +$ export ROGUEOPTS +.fi +.in +0 +.)f +.sh 2 "Option list" +.pp +Here is a list of the options +and an explanation of what each one is for. +The default value for each is enclosed in square brackets. +For character string options, +input over forty characters will be ignored. +.ip "\fBjump\fP [\fI\^nojump\^\fP]" +If this option is set, +running moves will not be displayed +until you reach the end of the move. +This saves considerable cpu and display time. +This option defaults to +.i jump +if you are using a slow terminal. +.ip "\fBpassgo\fP [\fI\^nopassgo\^\fP]" +Follow turnings in passageways. +If you run in a passage +and you run into stone or a wall, +rogue will see if it can turn to the right or left. +If it can only turn one way, +it will turn that way. +If it can turn either or neither, +it will stop. +This algorithm can sometimes lead to slightly confusing occurrences +which is why it defaults to \fInopassgo\fP. +.ip "\fBskull\fP [\fI\^skull\^\fP]" +Print out the skull at the end if you get killed. +This is nice but slow, so you can turn it off if you like. +.ip "\fBname\fP [account name]" +This is the name of your character. +It is used if you get on the top ten scorer's list. +.ip "\fBfruit\fP [\fI\^slime-mold\^\fP]" +This should hold the name of a fruit that you enjoy eating. +It is basically a whimsey that rogue uses in a couple of places. +.ip "\fBfile\fP [\fI\^~/rogue.save\^\fP]" +The default file name for saving the game. +If your phone is hung up by accident, +rogue will automatically save the game in this file. +The file name may start with the special character +.Cs ~ +which expands to be your home directory. +.sh 1 Scoring +.pp +Rogue maintains a list +of the top scoring people or scores on your machine. +If you score higher than someone else on this list, +or better your previous score on the list, +you will be inserted in the proper place +under your current name. +.pp +If you quit the game, you get out with all of your gold intact. +If, however, you get killed in the Dungeons of Doom, +your body is forwarded to your next-of-kin, +along with 90% of your gold; +ten percent of your gold is kept by the Dungeons' wizard as a fee\**. +.(f +\** The Dungeon's wizard is named Wally the Wonder Badger. +Invocations should be accompanied by a sizable donation. +.)f +This should make you consider whether you want to take one last hit +at that monster and possibly live, +or quit and thus stop with whatever you have. +If you quit, you do get all your gold, +but if you swing and live, you might find more. +.pp +If you just want to see what the current top players/games list is, +you can type +.ti +1i +.nf +% rogue \-s +.br +.sh 1 Acknowledgements +.pp +Rogue was originally conceived of by Glenn Wichman and Michael Toy. +Ken Arnold and Michael Toy then smoothed out the user interface, +and added jillions of new features. +We would like to thank +Bob Arnold, +Michelle Busch, +Andy Hatcher, +Kipp Hickman, +Mark Horton, +Daniel Jensen, +Bill Joy, +Joe Kalash, +Steve Maurer, +Marty McNary, +Jan Miller, +and +Scott Nelson +for their ideas and assistance; +and also the teeming multitudes +who graciously ignored work, school, and social life to play rogue +and send us bugs, complaints, suggestions, and just plain flames. +And also Mom. +.pp +The public domain version of rogue now distributed with Berkeley UNIX +was written by Timothy Stoehr. diff --git a/use.c b/use.c new file mode 100755 index 0000000..2588cff --- /dev/null +++ b/use.c @@ -0,0 +1,618 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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/zap.c b/zap.c new file mode 100755 index 0000000..b82d188 --- /dev/null +++ b/zap.c @@ -0,0 +1,405 @@ +/* + * Copyright (c) 1988, 1993 + * 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 8.1 (Berkeley) 5/31/93"; +#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); + } + } +}