Rogue 3.6 reconstruction from http://rogue.rogueforge.net/rogue36/.
authorJoe Wreschnig <joe.wreschnig@gmail.com>
Thu, 4 Apr 2013 10:00:26 +0000 (12:00 +0200)
committerJoe Wreschnig <joe.wreschnig@gmail.com>
Thu, 4 Apr 2013 10:00:26 +0000 (12:00 +0200)
43 files changed:
LICENSE.TXT [new file with mode: 0644]
Makefile [new file with mode: 0644]
armor.c [new file with mode: 0644]
chase.c [new file with mode: 0644]
command.c [new file with mode: 0644]
daemon.c [new file with mode: 0644]
daemons.c [new file with mode: 0644]
fight.c [new file with mode: 0644]
init.c [new file with mode: 0644]
io.c [new file with mode: 0644]
list.c [new file with mode: 0644]
machdep.h [new file with mode: 0644]
main.c [new file with mode: 0644]
mdport.c [new file with mode: 0644]
misc.c [new file with mode: 0644]
monsters.c [new file with mode: 0644]
move.c [new file with mode: 0644]
newlevel.c [new file with mode: 0644]
options.c [new file with mode: 0644]
pack.c [new file with mode: 0644]
passages.c [new file with mode: 0644]
potions.c [new file with mode: 0644]
readme36.html [new file with mode: 0644]
rings.c [new file with mode: 0644]
rip.c [new file with mode: 0644]
rogue.6 [new file with mode: 0644]
rogue.h [new file with mode: 0644]
rogue.r [new file with mode: 0644]
rogue36.cat [new file with mode: 0644]
rogue36.doc [new file with mode: 0644]
rogue36.html [new file with mode: 0644]
rogue36.sln [new file with mode: 0644]
rogue36.vcproj [new file with mode: 0644]
rooms.c [new file with mode: 0644]
save.c [new file with mode: 0644]
scrolls.c [new file with mode: 0644]
state.c [new file with mode: 0644]
sticks.c [new file with mode: 0644]
things.c [new file with mode: 0644]
vers.c [new file with mode: 0644]
weapons.c [new file with mode: 0644]
wizard.c [new file with mode: 0644]
xcrypt.c [new file with mode: 0644]

diff --git a/LICENSE.TXT b/LICENSE.TXT
new file mode 100644 (file)
index 0000000..7993e9d
--- /dev/null
@@ -0,0 +1,92 @@
+Rogue: Exploring the Dungeons of Doom\r
+Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+All rights reserved.\r
+\r
+Redistribution and use in source and binary forms, with or without\r
+modification, are permitted provided that the following conditions\r
+are met:\r
+1. Redistributions of source code must retain the above copyright\r
+   notice, this list of conditions and the following disclaimer.\r
+2. Redistributions in binary form must reproduce the above copyright\r
+   notice, this list of conditions and the following disclaimer in the\r
+   documentation and/or other materials provided with the distribution.\r
+3. Neither the name(s) of the author(s) nor the names of other contributors\r
+   may be used to endorse or promote products derived from this software\r
+   without specific prior written permission.\r
+\r
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND\r
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE\r
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+SUCH DAMAGE.\r
+\r
+===========================================================================\r
+\r
+Portions of this software (save/restore game state) are based on the work \r
+of Nicholas J. Kisseberth. Used under license:\r
+\r
+Copyright (C) 1999, 2000, 2006 Nicholas J. Kisseberth\r
+\r
+Redistribution and use in source and binary forms, with or without\r
+modification, are permitted provided that the following conditions\r
+are met:\r
+1. Redistributions of source code must retain the above copyright\r
+   notice, this list of conditions and the following disclaimer.\r
+2. Redistributions in binary form must reproduce the above copyright\r
+   notice, this list of conditions and the following disclaimer in the\r
+   documentation and/or other materials provided with the distribution.\r
+3. Neither the name(s) of the author(s) nor the names of other contributors\r
+   may be used to endorse or promote products derived from this software\r
+   without specific prior written permission.\r
+\r
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND\r
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE\r
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+SUCH DAMAGE.\r
+\r
+===========================================================================\r
+\r
+Portions of this software (encryption) are based on the work \r
+of David Burren. Used under license:\r
+\r
+FreeSec: libcrypt\r
+\r
+Copyright (C) 1994 David Burren\r
+All rights reserved.\r
+\r
+Redistribution and use in source and binary forms, with or without\r
+modification, are permitted provided that the following conditions\r
+are met:\r
+1. Redistributions of source code must retain the above copyright\r
+   notice, this list of conditions and the following disclaimer.\r
+2. Redistributions in binary form must reproduce the above copyright\r
+   notice, this list of conditions and the following disclaimer in the\r
+   documentation and/or other materials provided with the distribution.\r
+3. Neither the name(s) of the author(s) nor the names of other contributors\r
+   may be used to endorse or promote products derived from this software\r
+   without specific prior written permission.\r
+\r
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND\r
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE\r
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+SUCH DAMAGE.\r
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..ef1d6b5
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,145 @@
+#\r
+# Makefile for rogue\r
+# %W% (Berkeley) %G%\r
+#\r
+# Rogue: Exploring the Dungeons of Doom\r
+# Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+# All rights reserved.\r
+#\r
+# See the file LICENSE.TXT for full copyright and licensing information.\r
+#\r
+\r
+DISTNAME=rogue3.6.3\r
+PROGRAM=rogue36\r
+\r
+O=o\r
+\r
+HDRS=  rogue.h machdep.h\r
+\r
+OBJS1 = vers.$(O) armor.$(O) chase.$(O) command.$(O) daemon.$(O) daemons.$(O) \\r
+        fight.$(O) init.$(O) io.$(O) list.$(O) main.$(O) mdport.$(O) \\r
+       misc.$(O) monsters.$(O) move.$(O) newlevel.$(O) options.$(O) \r
+OBJS2 =        pack.$(O) passages.$(O) potions.$(O) rings.$(O) rip.$(O) rooms.$(O) \\r
+       save.$(O) scrolls.$(O) state.$(O) sticks.$(O) things.$(O) \\r
+       weapons.$(O) wizard.$(O) xcrypt.$(O)\r
+OBJS  = $(OBJS1) $(OBJS2)\r
+\r
+CFILES= vers.c armor.c chase.c command.c daemon.c daemons.c fight.c \\r
+       init.c io.c list.c main.c mdport.c misc.c monsters.c move.c newlevel.c \\r
+       options.c pack.c passages.c potions.c rings.c rip.c rooms.c \\r
+       save.c scrolls.c state.c sticks.c things.c weapons.c wizard.c xcrypt.c\r
+\r
+\r
+MISC_C=\r
+DOCSRC= rogue.6 rogue.r\r
+DOCS  = $(PROGRAM).doc $(PROGRAM).cat $(PROGRAM).html readme36.html\r
+MISC  =        Makefile $(MISC_C) LICENSE.TXT $(PROGRAM).sln $(PROGRAM).vcproj $(DOCS)\\r
+       $(DOCSRC)\r
+\r
+CC    = gcc\r
+ROPTS =\r
+COPTS = -O3\r
+CFLAGS= $(COPTS) $(ROPTS)\r
+LIBS  = -lcurses\r
+RM    = rm -f\r
+LD    = $(CC)\r
+LDOUT = -o \r
+\r
+.SUFFIXES: .obj\r
+\r
+.c.obj:\r
+       $(CC) $(CFLAGS) /c $*.c\r
+\r
+$(PROGRAM)$(EXE): $(HDRS) $(OBJS)\r
+       $(LD) $(LDFLAGS) $(OBJS) $(LIBS) $(LDOUT)$@\r
+\r
+clean:\r
+       $(RM) $(OBJS1)\r
+       $(RM) $(OBJS2)\r
+       $(RM) core $(PROGRAM) $(PROGRAM).exe $(DISTNAME).tar $(DISTNAME).tar.gz \r
+       $(RM) $(DISTNAME).zip\r
+\r
+dist.src:\r
+       make clean\r
+       tar cf $(DISTNAME)-src.tar $(CFILES) $(HDRS) $(MISC) $(DOCS)\r
+       gzip -f $(DISTNAME)-src.tar\r
+\r
+dist.irix:\r
+       @$(MAKE) clean\r
+       @$(MAKE) CC=cc CFLAGS="-woff 1116 -O3" $(PROGRAM)\r
+#      tbl rogue.r | nroff -ms | colcrt - > $(PROGRAM).doc\r
+#      nroff -man rogue.6 | colcrt - > $(PROGRAM).cat\r
+       tar cf $(DISTNAME)-irix.tar $(PROGRAM) LICENSE.TXT $(DOCS)\r
+       gzip -f $(DISTNAME)-irix.tar\r
+\r
+dist.aix:\r
+       @$(MAKE) clean\r
+       @$(MAKE) CC=xlc CFLAGS="-qmaxmem=16768 -O3 -qstrict" $(PROGRAM)\r
+#      tbl rogue.r | nroff -ms | colcrt - > $(ROGUE).doc\r
+#      nroff -man rogue.6 | colcrt - > $(ROGUE).cat\r
+       tar cf $(DISTNAME)-aix.tar $(PROGRAM) LICENSE.TXT $(DOCS)\r
+       gzip -f $(DISTNAME)-aix.tar\r
+\r
+dist.linux:\r
+       @$(MAKE) clean\r
+       @$(MAKE) $(PROGRAM)\r
+#      groff -P-c -t -ms -Tascii rogue.r | sed -e 's/.\x08//g' > $(PROGRAM).doc\r
+#      groff -man rogue.6 | sed -e 's/.\x08//g' > $(PROGRAM).cat\r
+       tar cf $(DISTNAME)-linux.tar $(PROGRAM) LICENSE.TXT $(DOCS)\r
+       gzip -f $(DISTNAME)-linux.tar\r
+       \r
+dist.interix: \r
+       @$(MAKE) clean\r
+       @$(MAKE) COPTS="-ansi" $(PROGRAM)\r
+#      groff -P-b -P-u -t -ms -Tascii rogue.r > $(PROGRAM).doc\r
+#      groff -P-b -P-u -man -Tascii rogue.6 > $(PROGRAM).cat\r
+       tar cf $(DISTNAME)-interix.tar $(PROGRAM) LICENSE.TXT $(DOCS)\r
+       gzip -f $(DISTNAME)-interix.tar \r
+\r
+dist.cygwin:\r
+       @$(MAKE) --no-print-directory clean\r
+       @$(MAKE) COPTS="-I/usr/include/ncurses" --no-print-directory $(PROGRAM)\r
+#      groff -P-c -t -ms -Tascii rogue.r | sed -e 's/.\x08//g' > $(PROGRAM).doc\r
+#      groff -P-c -man -Tascii rogue.6 | sed -e 's/.\x08//g' > $(PROGRAM).cat\r
+       tar cf $(DISTNAME)-cygwin.tar $(PROGRAM).exe LICENSE.TXT $(DOCS)\r
+       gzip -f $(DISTNAME)-cygwin.tar\r
+\r
+#\r
+# Use MINGW32-MAKE to build this target\r
+#\r
+dist.mingw32:\r
+       @$(MAKE) --no-print-directory RM="cmd /c del" clean\r
+       @$(MAKE) --no-print-directory COPTS="-I../pdcurses" LIBS="../pdcurses/pdcurses.a" $(PROGRAM)\r
+       cmd /c del $(DISTNAME)-mingw32.zip\r
+       zip $(DISTNAME)-mingw32.zip $(PROGRAM).exe LICENSE.TXT $(DOCS)\r
+       \r
+#\r
+# Seperate doc targets for DJGPP prevent strange SIGSEGV in groff\r
+# in that environment.\r
+#\r
+doc.djgpp:\r
+       groff -t -ms -Tascii rogue.r | sed -e 's/.\x08//g' > $(PROGRAM).doc\r
+\r
+cat.djgpp:\r
+       groff -man -Tascii rogue.6 | sed -e 's/.\x08//g' > $(PROGRAM).cat\r
+\r
+dist.djgpp: \r
+       @$(MAKE) --no-print-directory clean\r
+       @$(MAKE) --no-print-directory LDFLAGS="-L$(DJDIR)/LIB" \\r
+               LIBS="-lpdcur" $(PROGRAM)\r
+#      @$(MAKE) --no-print-directory doc.djgpp\r
+#      @$(MAKE) --no-print-directory cat.djgpp\r
+       rm -f $(DISTNAME)-djgpp.zip\r
+       zip $(DISTNAME)-djgpp.zip $(PROGRAM) LICENSE.TXT $(DOCS)\r
+\r
+#\r
+# Use NMAKE to build this target\r
+#\r
+dist.win32:\r
+       @$(MAKE) /NOLOGO O="obj" RM="-del" clean\r
+       @$(MAKE) /NOLOGO O="obj" CC="@CL" LD="link" LDOUT="/OUT:" EXE=".exe"\\r
+           LIBS="/NODEFAULTLIB:LIBC ..\pdcurses\pdcurses.lib shell32.lib user32.lib Advapi32.lib" \\r
+           COPTS="-nologo -D_CRT_SECURE_NO_DEPRECATE -I..\pdcurses \\r
+           -Ox -wd4033 -wd4716" $(PROGRAM).exe\r
+       -del $(DISTNAME)-win32.zip\r
+       zip $(DISTNAME)-win32.zip $(PROGRAM).exe LICENSE.TXT $(DOCS)\r
diff --git a/armor.c b/armor.c
new file mode 100644 (file)
index 0000000..f4817b1
--- /dev/null
+++ b/armor.c
@@ -0,0 +1,90 @@
+/*\r
+ * This file contains misc functions for dealing with armor\r
+ * @(#)armor.c 3.9 (Berkeley) 6/15/81\r
+ * \r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include "rogue.h"\r
+\r
+/*\r
+ * wear:\r
+ *     The player wants to wear something, so let him/her put it on.\r
+ */\r
+\r
+wear()\r
+{\r
+    register struct linked_list *item;\r
+    register struct object *obj;\r
+\r
+    if (cur_armor != NULL)\r
+    {\r
+       addmsg("You are already wearing some");\r
+       if (!terse)\r
+           addmsg(".  You'll have to take it off first");\r
+       endmsg();\r
+       after = FALSE;\r
+       return;\r
+    }\r
+    if ((item = get_item("wear", ARMOR)) == NULL)\r
+       return;\r
+    obj = (struct object *) ldata(item);\r
+    if (obj->o_type != ARMOR)\r
+    {\r
+       msg("You can't wear that.");\r
+       return;\r
+    }\r
+    waste_time();\r
+    if (!terse)\r
+       addmsg("You are now w");\r
+    else\r
+       addmsg("W");\r
+    msg("earing %s.", a_names[obj->o_which]);\r
+    cur_armor = obj;\r
+    obj->o_flags |= ISKNOW;\r
+}\r
+\r
+/*\r
+ * take_off:\r
+ *     Get the armor off of the players back\r
+ */\r
+\r
+take_off()\r
+{\r
+    register struct object *obj;\r
+\r
+    if ((obj = cur_armor) == NULL)\r
+    {\r
+       if (terse)\r
+               msg("Not wearing armor");\r
+       else\r
+               msg("You aren't wearing any armor");\r
+       return;\r
+    }\r
+    if (!dropcheck(cur_armor))\r
+       return;\r
+    cur_armor = NULL;\r
+    if (terse)\r
+       addmsg("Was");\r
+    else\r
+       addmsg("You used to be ");\r
+    msg(" wearing %c) %s", pack_char(obj), inv_name(obj, TRUE));\r
+}\r
+\r
+/*\r
+ * waste_time:\r
+ *     Do nothing but let other things happen\r
+ */\r
+\r
+waste_time()\r
+{\r
+    do_daemons(BEFORE);\r
+    do_fuses(BEFORE);\r
+    do_daemons(AFTER);\r
+    do_fuses(AFTER);\r
+}\r
diff --git a/chase.c b/chase.c
new file mode 100644 (file)
index 0000000..1c5bb95
--- /dev/null
+++ b/chase.c
@@ -0,0 +1,323 @@
+/*\r
+ * Code for one object to chase another\r
+ *\r
+ * @(#)chase.c 3.17 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include "rogue.h"\r
+\r
+coord ch_ret;                          /* Where chasing takes you */\r
+\r
+/*\r
+ * runners:\r
+ *     Make all the running monsters move.\r
+ */\r
+\r
+runners()\r
+{\r
+    register struct linked_list *item;\r
+    register struct thing *tp;\r
+\r
+    for (item = mlist; item != NULL;)\r
+    {\r
+       tp = (struct thing *) ldata(item);\r
+        item = next(item);\r
+       if (off(*tp, ISHELD) && on(*tp, ISRUN))\r
+       {\r
+           if (off(*tp, ISSLOW) || tp->t_turn)\r
+               if (do_chase(tp) == -1)\r
+                    continue;\r
+           if (on(*tp, ISHASTE))\r
+               if (do_chase(tp) == -1)\r
+                    continue;\r
+           tp->t_turn ^= TRUE;\r
+       }\r
+    }\r
+}\r
+\r
+/*\r
+ * do_chase:\r
+ *     Make one thing chase another.\r
+ */\r
+\r
+do_chase(th)\r
+register struct thing *th;\r
+{\r
+    register struct room *rer, *ree;   /* room of chaser, room of chasee */\r
+    register int mindist = 32767, i, dist;\r
+    register bool stoprun = FALSE;     /* TRUE means we are there */\r
+    register char sch;\r
+    coord this;                                /* Temporary destination for chaser */\r
+\r
+    rer = roomin(&th->t_pos);  /* Find room of chaser */\r
+    ree = roomin(th->t_dest);  /* Find room of chasee */\r
+    /*\r
+     * We don't count doors as inside rooms for this routine\r
+     */\r
+    if (mvwinch(stdscr, th->t_pos.y, th->t_pos.x) == DOOR)\r
+       rer = NULL;\r
+    this = *th->t_dest;\r
+    /*\r
+     * If the object of our desire is in a different room, \r
+     * than we are and we ar not in a corridor, run to the\r
+     * door nearest to our goal.\r
+     */\r
+    if (rer != NULL && rer != ree)\r
+       for (i = 0; i < rer->r_nexits; i++)     /* loop through doors */\r
+       {\r
+           dist = DISTANCE(th->t_dest->y, th->t_dest->x,\r
+                           rer->r_exit[i].y, rer->r_exit[i].x);\r
+           if (dist < mindist)                 /* minimize distance */\r
+           {\r
+               this = rer->r_exit[i];\r
+               mindist = dist;\r
+           }\r
+       }\r
+    /*\r
+     * this now contains what we want to run to this time\r
+     * so we run to it.  If we hit it we either want to fight it\r
+     * or stop running\r
+     */\r
+    if (!chase(th, &this))\r
+    {\r
+       if (ce(this, hero))\r
+       {\r
+           return( attack(th) );\r
+       }\r
+       else if (th->t_type != 'F')\r
+           stoprun = TRUE;\r
+    }\r
+    else if (th->t_type == 'F')\r
+       return(0);\r
+    mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch);\r
+    sch = mvwinch(cw, ch_ret.y, ch_ret.x);\r
+    if (rer != NULL && (rer->r_flags & ISDARK) && sch == FLOOR\r
+       && DISTANCE(ch_ret.y, ch_ret.x, th->t_pos.y, th->t_pos.x) < 3\r
+       && off(player, ISBLIND))\r
+           th->t_oldch = ' ';\r
+    else\r
+       th->t_oldch = sch;\r
+\r
+    if (cansee(unc(ch_ret)) && !on(*th, ISINVIS))\r
+        mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type);\r
+    mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');\r
+    mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type);\r
+    th->t_pos = ch_ret;\r
+    /*\r
+     * And stop running if need be\r
+     */\r
+    if (stoprun && ce(th->t_pos, *(th->t_dest)))\r
+       th->t_flags &= ~ISRUN;\r
+\r
+    return(0);\r
+}\r
+\r
+/*\r
+ * runto:\r
+ *     Set a mosnter running after something\r
+ *     or stop it from running (for when it dies)\r
+ */\r
+\r
+runto(runner, spot)\r
+register coord *runner;\r
+coord *spot;\r
+{\r
+    register struct linked_list *item;\r
+    register struct thing *tp;\r
+\r
+    /*\r
+     * If we couldn't find him, something is funny\r
+     */\r
+    if ((item = find_mons(runner->y, runner->x)) == NULL)\r
+    {\r
+       msg("CHASER '%s'", unctrl(winat(runner->y, runner->x)));\r
+       return;\r
+    }\r
+    tp = (struct thing *) ldata(item);\r
+    /*\r
+     * Start the beastie running\r
+     */\r
+    tp->t_dest = spot;\r
+    tp->t_flags |= ISRUN;\r
+    tp->t_flags &= ~ISHELD;\r
+}\r
+\r
+/*\r
+ * chase:\r
+ *     Find the spot for the chaser(er) to move closer to the\r
+ *     chasee(ee).  Returns TRUE if we want to keep on chasing later\r
+ *     FALSE if we reach the goal.\r
+ */\r
+\r
+chase(tp, ee)\r
+struct thing *tp;\r
+coord *ee;\r
+{\r
+    register int x, y;\r
+    register int dist, thisdist;\r
+    register struct linked_list *item;\r
+    register struct object *obj;\r
+    register coord *er = &tp->t_pos;\r
+    register char ch;\r
+\r
+    /*\r
+     * If the thing is confused, let it move randomly. Invisible\r
+     * Stalkers are slightly confused all of the time, and bats are\r
+     * quite confused all the time\r
+     */\r
+    if ((on(*tp, ISHUH) && rnd(10) < 8) || (tp->t_type == 'I' && rnd(100) < 20)\r
+       || (tp->t_type == 'B' && rnd(100) < 50))\r
+    {\r
+       /*\r
+        * get a valid random move\r
+        */\r
+       ch_ret = *rndmove(tp);\r
+       dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x);\r
+       /*\r
+        * Small chance that it will become un-confused \r
+        */\r
+       if (rnd(1000) < 50)\r
+           tp->t_flags &= ~ISHUH;\r
+    }\r
+    /*\r
+     * Otherwise, find the empty spot next to the chaser that is\r
+     * closest to the chasee.\r
+     */\r
+    else\r
+    {\r
+       register int ey, ex;\r
+       /*\r
+        * This will eventually hold where we move to get closer\r
+        * If we can't find an empty spot, we stay where we are.\r
+        */\r
+       dist = DISTANCE(er->y, er->x, ee->y, ee->x);\r
+       ch_ret = *er;\r
+\r
+       ey = er->y + 1;\r
+       ex = er->x + 1;\r
+       for (x = er->x - 1; x <= ex; x++)\r
+           for (y = er->y - 1; y <= ey; y++)\r
+           {\r
+               coord tryp;\r
+\r
+               tryp.x = x;\r
+               tryp.y = y;\r
+               if (!diag_ok(er, &tryp))\r
+                   continue;\r
+               ch = winat(y, x);\r
+               if (step_ok(ch))\r
+               {\r
+                   /*\r
+                    * If it is a scroll, it might be a scare monster scroll\r
+                    * so we need to look it up to see what type it is.\r
+                    */\r
+                   if (ch == SCROLL)\r
+                   {\r
+                       for (item = lvl_obj; item != NULL; item = next(item))\r
+                       {\r
+                           obj = (struct object *) ldata(item);\r
+                           if (y == obj->o_pos.y && x == obj->o_pos.x)\r
+                               break;\r
+                       }\r
+                       if (item != NULL && obj->o_which == S_SCARE)\r
+                           continue;\r
+                   }\r
+                   /*\r
+                    * If we didn't find any scrolls at this place or it\r
+                    * wasn't a scare scroll, then this place counts\r
+                    */\r
+                   thisdist = DISTANCE(y, x, ee->y, ee->x);\r
+                   if (thisdist < dist)\r
+                   {\r
+                       ch_ret = tryp;\r
+                       dist = thisdist;\r
+                   }\r
+               }\r
+           }\r
+    }\r
+    return (dist != 0);\r
+}\r
+\r
+/*\r
+ * roomin:\r
+ *     Find what room some coordinates are in. NULL means they aren't\r
+ *     in any room.\r
+ */\r
+\r
+struct room *\r
+roomin(cp)\r
+register coord *cp;\r
+{\r
+    register struct room *rp;\r
+\r
+    for (rp = rooms; rp <= &rooms[MAXROOMS-1]; rp++)\r
+       if (inroom(rp, cp))\r
+           return rp;\r
+    return NULL;\r
+}\r
+\r
+/*\r
+ * find_mons:\r
+ *     Find the monster from his corrdinates\r
+ */\r
+\r
+struct linked_list *\r
+find_mons(y, x)\r
+register int y;\r
+int x;\r
+{\r
+    register struct linked_list *item;\r
+    register struct thing *th;\r
+\r
+    for (item = mlist; item != NULL; item = next(item))\r
+    {\r
+       th = (struct thing *) ldata(item);\r
+       if (th->t_pos.y == y && th->t_pos.x == x)\r
+           return item;\r
+    }\r
+    return NULL;\r
+}\r
+\r
+/*\r
+ * diag_ok:\r
+ *     Check to see if the move is legal if it is diagonal\r
+ */\r
+\r
+diag_ok(sp, ep)\r
+register coord *sp, *ep;\r
+{\r
+    if (ep->x == sp->x || ep->y == sp->y)\r
+       return TRUE;\r
+    return (step_ok(mvinch(ep->y, sp->x)) && step_ok(mvinch(sp->y, ep->x)));\r
+}\r
+\r
+/*\r
+ * cansee:\r
+ *     returns true if the hero can see a certain coordinate.\r
+ */\r
+\r
+cansee(y, x)\r
+register int y, x;\r
+{\r
+    register struct room *rer;\r
+    coord tp;\r
+\r
+    if (on(player, ISBLIND))\r
+       return FALSE;\r
+    tp.y = y;\r
+    tp.x = x;\r
+    rer = roomin(&tp);\r
+    /*\r
+     * We can only see if the hero in the same room as\r
+     * the coordinate and the room is lit or if it is close.\r
+     */\r
+    return (rer != NULL && rer == roomin(&hero) && !(rer->r_flags&ISDARK)) ||\r
+           DISTANCE(y, x, hero.y, hero.x) < 3;\r
+}\r
diff --git a/command.c b/command.c
new file mode 100644 (file)
index 0000000..6b8033b
--- /dev/null
+++ b/command.c
@@ -0,0 +1,633 @@
+/*\r
+ * Read and execute the user commands\r
+ *\r
+ * @(#)command.c       3.45 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <stdlib.h>\r
+#include <ctype.h>\r
+#include <signal.h>\r
+#include <string.h>\r
+#include "rogue.h"\r
+\r
+/*\r
+ * command:\r
+ *     Process the user commands\r
+ */\r
+\r
+command()\r
+{\r
+    register char ch;\r
+    register int ntimes = 1;                   /* Number of player moves */\r
+    static char countch, direction, newcount = FALSE;\r
+\r
+\r
+    if (on(player, ISHASTE)) ntimes++;\r
+    /*\r
+     * Let the daemons start up\r
+     */\r
+    do_daemons(BEFORE);\r
+    do_fuses(BEFORE);\r
+    while (ntimes--)\r
+    {\r
+       look(TRUE);\r
+       if (!running)\r
+           door_stop = FALSE;\r
+       status();\r
+       lastscore = purse;\r
+       wmove(cw, hero.y, hero.x);\r
+       if (!((running || count) && jump))\r
+           draw(cw);                   /* Draw screen */\r
+       take = 0;\r
+       after = TRUE;\r
+       /*\r
+        * Read command or continue run\r
+        */\r
+       if (wizard)\r
+           waswizard = TRUE;\r
+       if (!no_command)\r
+       {\r
+           if (running) ch = runch;\r
+           else if (count) ch = countch;\r
+           else\r
+           {\r
+               ch = readchar(cw);\r
+               if (mpos != 0 && !running)      /* Erase message if its there */\r
+                   msg("");\r
+           }\r
+       }\r
+       else ch = ' ';\r
+       if (no_command)\r
+       {\r
+           if (--no_command == 0)\r
+               msg("You can move again.");\r
+       }\r
+       else\r
+       {\r
+           /*\r
+            * check for prefixes\r
+            */\r
+           if (isdigit(ch))\r
+           {\r
+               count = 0;\r
+               newcount = TRUE;\r
+               while (isdigit(ch))\r
+               {\r
+                   count = count * 10 + (ch - '0');\r
+                   ch = readchar(cw);\r
+               }\r
+               countch = ch;\r
+               /*\r
+                * turn off count for commands which don't make sense\r
+                * to repeat\r
+                */\r
+               switch (ch) {\r
+                   case 'h': case 'j': case 'k': case 'l':\r
+                   case 'y': case 'u': case 'b': case 'n':\r
+                   case 'H': case 'J': case 'K': case 'L':\r
+                   case 'Y': case 'U': case 'B': case 'N':\r
+                   case 'q': case 'r': case 's': case 'f':\r
+                   case 't': case 'C': case 'I': case ' ':\r
+                   case 'z': case 'p':\r
+                       break;\r
+                   default:\r
+                       count = 0;\r
+               }\r
+           }\r
+           switch (ch)\r
+           {\r
+               case 'f':\r
+                   if (!on(player, ISBLIND))\r
+                   {\r
+                       door_stop = TRUE;\r
+                       firstmove = TRUE;\r
+                   }\r
+                   if (count && !newcount)\r
+                       ch = direction;\r
+                   else\r
+                       ch = readchar(cw);\r
+                   switch (ch)\r
+                   {\r
+                       case 'h': case 'j': case 'k': case 'l':\r
+                       case 'y': case 'u': case 'b': case 'n':\r
+                           ch = toupper(ch);\r
+                   }\r
+                   direction = ch;\r
+           }\r
+           newcount = FALSE;\r
+           /*\r
+            * execute a command\r
+            */\r
+           if (count && !running)\r
+               count--;\r
+           switch (ch)\r
+           {\r
+               case '!' : shell();\r
+               when 'h' : do_move(0, -1);\r
+               when 'j' : do_move(1, 0);\r
+               when 'k' : do_move(-1, 0);\r
+               when 'l' : do_move(0, 1);\r
+               when 'y' : do_move(-1, -1);\r
+               when 'u' : do_move(-1, 1);\r
+               when 'b' : do_move(1, -1);\r
+               when 'n' : do_move(1, 1);\r
+               when 'H' : do_run('h');\r
+               when 'J' : do_run('j');\r
+               when 'K' : do_run('k');\r
+               when 'L' : do_run('l');\r
+               when 'Y' : do_run('y');\r
+               when 'U' : do_run('u');\r
+               when 'B' : do_run('b');\r
+               when 'N' : do_run('n');\r
+               when 't':\r
+                   if (!get_dir())\r
+                       after = FALSE;\r
+                   else\r
+                       missile(delta.y, delta.x);\r
+               when 'Q' : after = FALSE; quit(0);\r
+               when 'i' : after = FALSE; inventory(pack, 0);\r
+               when 'I' : after = FALSE; picky_inven();\r
+               when 'd' : drop();\r
+               when 'q' : quaff();\r
+               when 'r' : read_scroll();\r
+               when 'e' : eat();\r
+               when 'w' : wield();\r
+               when 'W' : wear();\r
+               when 'T' : take_off();\r
+               when 'P' : ring_on();\r
+               when 'R' : ring_off();\r
+               when 'o' : option();\r
+               when 'c' : call();\r
+               when '>' : after = FALSE; d_level();\r
+               when '<' : after = FALSE; u_level();\r
+               when '?' : after = FALSE; help();\r
+               when '/' : after = FALSE; identify();\r
+               when 's' : search();\r
+               when 'z' : do_zap(FALSE);\r
+               when 'p':\r
+                   if (get_dir())\r
+                       do_zap(TRUE);\r
+                   else\r
+                       after = FALSE;\r
+               when 'v' : msg("Rogue version %s. (mctesq was here)", release);\r
+               when CTRL('L') : after = FALSE; clearok(curscr,TRUE);draw(curscr);\r
+               when CTRL('R') : after = FALSE; msg(huh);\r
+               when 'S' : \r
+                   after = FALSE;\r
+                   if (save_game())\r
+                   {\r
+                       wmove(cw, LINES-1, 0); \r
+                       wclrtoeol(cw);\r
+                       draw(cw);\r
+                       endwin();\r
+                       exit(0);\r
+                   }\r
+               when ' ' : ;                    /* Rest command */\r
+               when CTRL('P') :\r
+                   after = FALSE;\r
+                   if (wizard)\r
+                   {\r
+                       wizard = FALSE;\r
+                       msg("Not wizard any more");\r
+                   }\r
+                   else\r
+                   {\r
+                       if (wizard = passwd())\r
+                       {\r
+                           msg("You are suddenly as smart as Ken Arnold in dungeon #%d", dnum);\r
+                           wizard = TRUE;\r
+                           waswizard = TRUE;\r
+                       }\r
+                       else\r
+                           msg("Sorry");\r
+                   }\r
+               when ESCAPE :   /* Escape */\r
+                   door_stop = FALSE;\r
+                   count = 0;\r
+                   after = FALSE;\r
+               otherwise :\r
+                   after = FALSE;\r
+                   if (wizard) switch (ch)\r
+                   {\r
+                       case '@' : msg("@ %d,%d", hero.y, hero.x);\r
+                       when 'C' : create_obj();\r
+                       when CTRL('I') : inventory(lvl_obj, 0);\r
+                       when CTRL('W') : whatis();\r
+                       when CTRL('D') : level++; new_level();\r
+                       when CTRL('U') : level--; new_level();\r
+                       when CTRL('F') : show_win(stdscr, "--More (level map)--");\r
+                       when CTRL('X') : show_win(mw, "--More (monsters)--");\r
+                       when CTRL('T') : teleport();\r
+                       when CTRL('E') : msg("food left: %d", food_left);\r
+                       when CTRL('A') : msg("%d things in your pack", inpack);\r
+                       when CTRL('C') : add_pass();\r
+                       when CTRL('N') :\r
+                       {\r
+                           register struct linked_list *item;\r
+\r
+                           if ((item = get_item("charge", STICK)) != NULL)\r
+                               ((struct object *) ldata(item))->o_charges = 10000;\r
+                       }\r
+                       when CTRL('H') :\r
+                       {\r
+                           register int i;\r
+                           register struct linked_list *item;\r
+                           register struct object *obj;\r
+\r
+                           for (i = 0; i < 9; i++)\r
+                               raise_level();\r
+                           /*\r
+                            * Give the rogue a sword (+1,+1)\r
+                            */\r
+                           item = new_item(sizeof *obj);\r
+                           obj = (struct object *) ldata(item);\r
+                           obj->o_type = WEAPON;\r
+                           obj->o_which = TWOSWORD;\r
+                           init_weapon(obj, SWORD);\r
+                           obj->o_hplus = 1;\r
+                           obj->o_dplus = 1;\r
+                           add_pack(item, TRUE);\r
+                           cur_weapon = obj;\r
+                           /*\r
+                            * And his suit of armor\r
+                            */\r
+                           item = new_item(sizeof *obj);\r
+                           obj = (struct object *) ldata(item);\r
+                           obj->o_type = ARMOR;\r
+                           obj->o_which = PLATE_MAIL;\r
+                           obj->o_ac = -5;\r
+                           obj->o_flags |= ISKNOW;\r
+                           cur_armor = obj;\r
+                           add_pack(item, TRUE);\r
+                       }\r
+                       otherwise :\r
+                           msg("Illegal command '%s'.", unctrl(ch));\r
+                           count = 0;\r
+                   }\r
+                   else\r
+                   {\r
+                       msg("Illegal command '%s'.", unctrl(ch));\r
+                       count = 0;\r
+                   }\r
+           }\r
+           /*\r
+            * turn off flags if no longer needed\r
+            */\r
+           if (!running)\r
+               door_stop = FALSE;\r
+       }\r
+       /*\r
+        * If he ran into something to take, let him pick it up.\r
+        */\r
+       if (take != 0)\r
+           pick_up(take);\r
+       if (!running)\r
+           door_stop = FALSE;\r
+    }\r
+    /*\r
+     * Kick off the rest if the daemons and fuses\r
+     */\r
+    if (after)\r
+    {\r
+       look(FALSE);\r
+       do_daemons(AFTER);\r
+       do_fuses(AFTER);\r
+       if (ISRING(LEFT, R_SEARCH))\r
+           search();\r
+       else if (ISRING(LEFT, R_TELEPORT) && rnd(100) < 2)\r
+           teleport();\r
+       if (ISRING(RIGHT, R_SEARCH))\r
+           search();\r
+       else if (ISRING(RIGHT, R_TELEPORT) && rnd(100) < 2)\r
+           teleport();\r
+    }\r
+}\r
+\r
+/*\r
+ * quit:\r
+ *     Have player make certain, then exit.\r
+ */\r
+\r
+void\r
+quit(int p)\r
+{\r
+    /*\r
+     * Reset the signal in case we got here via an interrupt\r
+     */\r
+    if (signal(SIGINT, quit) != &quit)\r
+       mpos = 0;\r
+    msg("Really quit?");\r
+    draw(cw);\r
+    if (readchar(cw) == 'y')\r
+    {\r
+       clear();\r
+       move(LINES-1, 0);\r
+       draw(stdscr);\r
+       endwin();\r
+       score(purse, 1, 0);\r
+       exit(0);\r
+    }\r
+    else\r
+    {\r
+       signal(SIGINT, quit);\r
+       wmove(cw, 0, 0);\r
+       wclrtoeol(cw);\r
+       status();\r
+       draw(cw);\r
+       mpos = 0;\r
+       count = 0;\r
+    }\r
+}\r
+\r
+/*\r
+ * search:\r
+ *     Player gropes about him to find hidden things.\r
+ */\r
+\r
+search()\r
+{\r
+    register int x, y;\r
+    register char ch;\r
+\r
+    /*\r
+     * Look all around the hero, if there is something hidden there,\r
+     * give him a chance to find it.  If its found, display it.\r
+     */\r
+    if (on(player, ISBLIND))\r
+       return;\r
+    for (x = hero.x - 1; x <= hero.x + 1; x++)\r
+       for (y = hero.y - 1; y <= hero.y + 1; y++)\r
+       {\r
+           ch = winat(y, x);\r
+           switch (ch)\r
+           {\r
+               case SECRETDOOR:\r
+                   if (rnd(100) < 20) {\r
+                       mvaddch(y, x, DOOR);\r
+                       count = 0;\r
+                   }\r
+                   break;\r
+               case TRAP:\r
+               {\r
+                   register struct trap *tp;\r
+\r
+                   if (mvwinch(cw, y, x) == TRAP)\r
+                       break;\r
+                   if (rnd(100) > 50)\r
+                       break;\r
+                   tp = trap_at(y, x);\r
+                   tp->tr_flags |= ISFOUND;\r
+                   mvwaddch(cw, y, x, TRAP);\r
+                   count = 0;\r
+                   running = FALSE;\r
+                   msg(tr_name(tp->tr_type));\r
+               }\r
+           }\r
+       }\r
+}\r
+\r
+/*\r
+ * help:\r
+ *     Give single character help, or the whole mess if he wants it\r
+ */\r
+\r
+help()\r
+{\r
+    register struct h_list *strp = helpstr;\r
+    register char helpch;\r
+    register int cnt;\r
+\r
+    msg("Character you want help for (* for all): ");\r
+    helpch = readchar(cw);\r
+    mpos = 0;\r
+    /*\r
+     * If its not a *, print the right help string\r
+     * or an error if he typed a funny character.\r
+     */\r
+    if (helpch != '*')\r
+    {\r
+       wmove(cw, 0, 0);\r
+       while (strp->h_ch)\r
+       {\r
+           if (strp->h_ch == helpch)\r
+           {\r
+               msg("%s%s", unctrl(strp->h_ch), strp->h_desc);\r
+               break;\r
+           }\r
+           strp++;\r
+       }\r
+       if (strp->h_ch != helpch)\r
+           msg("Unknown character '%s'", unctrl(helpch));\r
+       return;\r
+    }\r
+    /*\r
+     * Here we print help for everything.\r
+     * Then wait before we return to command mode\r
+     */\r
+    wclear(hw);\r
+    cnt = 0;\r
+    while (strp->h_ch)\r
+    {\r
+       mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(strp->h_ch));\r
+       waddstr(hw, strp->h_desc);\r
+       cnt++;\r
+       strp++;\r
+    }\r
+    wmove(hw, LINES-1, 0);\r
+    wprintw(hw, "--Press space to continue--");\r
+    draw(hw);\r
+    wait_for(hw,' ');\r
+    wclear(hw);\r
+    draw(hw);\r
+    wmove(cw, 0, 0);\r
+    wclrtoeol(cw);\r
+    status();\r
+    touchwin(cw);\r
+}\r
+\r
+/*\r
+ * identify:\r
+ *     Tell the player what a certain thing is.\r
+ */\r
+\r
+identify()\r
+{\r
+    register char ch, *str;\r
+\r
+    msg("What do you want identified? ");\r
+    ch = readchar(cw);\r
+    mpos = 0;\r
+    if (ch == ESCAPE)\r
+    {\r
+       msg("");\r
+       return;\r
+    }\r
+    if (isalpha(ch) && isupper(ch))\r
+       str = monsters[ch-'A'].m_name;\r
+    else switch(ch)\r
+    {\r
+       case '|':\r
+       case '-':\r
+           str = "wall of a room";\r
+       when GOLD: str = "gold";\r
+       when STAIRS : str = "passage leading down";\r
+       when DOOR: str = "door";\r
+       when FLOOR: str = "room floor";\r
+       when PLAYER: str = "you";\r
+       when PASSAGE: str = "passage";\r
+       when TRAP: str = "trap";\r
+       when POTION: str = "potion";\r
+       when SCROLL: str = "scroll";\r
+       when FOOD: str = "food";\r
+       when WEAPON: str = "weapon";\r
+       when ' ' : str = "solid rock";\r
+       when ARMOR: str = "armor";\r
+       when AMULET: str = "The Amulet of Yendor";\r
+       when RING: str = "ring";\r
+       when STICK: str = "wand or staff";\r
+       otherwise: str = "unknown character";\r
+    }\r
+    msg("'%s' : %s", unctrl(ch), str);\r
+}\r
+\r
+/*\r
+ * d_level:\r
+ *     He wants to go down a level\r
+ */\r
+\r
+d_level()\r
+{\r
+    if (winat(hero.y, hero.x) != STAIRS)\r
+       msg("I see no way down.");\r
+    else\r
+    {\r
+       level++;\r
+       new_level();\r
+    }\r
+}\r
+\r
+/*\r
+ * u_level:\r
+ *     He wants to go up a level\r
+ */\r
+\r
+u_level()\r
+{\r
+    if (winat(hero.y, hero.x) == STAIRS)\r
+    {\r
+       if (amulet)\r
+       {\r
+           level--;\r
+           if (level == 0)\r
+               total_winner();\r
+           new_level();\r
+           msg("You feel a wrenching sensation in your gut.");\r
+           return;\r
+       }\r
+    }\r
+    msg("I see no way up.");\r
+}\r
+\r
+/*\r
+ * Let him escape for a while\r
+ */\r
+\r
+shell()\r
+{\r
+    /*\r
+     * Set the terminal back to original mode\r
+     */\r
+    wclear(hw);\r
+    wmove(hw, LINES-1, 0);\r
+    draw(hw);\r
+    endwin();\r
+    in_shell = TRUE;\r
+    fflush(stdout);\r
+\r
+    md_shellescape();\r
+\r
+    printf("\n[Press return to continue]");\r
+    fflush(stdout);\r
+    noecho();\r
+    crmode();\r
+    in_shell = FALSE;\r
+    wait_for(cw,'\n');\r
+    clearok(cw, TRUE);\r
+    touchwin(cw);\r
+    draw(cw);\r
+}\r
+\r
+/*\r
+ * allow a user to call a potion, scroll, or ring something\r
+ */\r
+call()\r
+{\r
+    register struct object *obj;\r
+    register struct linked_list *item;\r
+    register char **guess, *elsewise;\r
+    register bool *know;\r
+\r
+    item = get_item("call", CALLABLE);\r
+    /*\r
+     * Make certain that it is somethings that we want to wear\r
+     */\r
+    if (item == NULL)\r
+       return;\r
+    obj = (struct object *) ldata(item);\r
+    switch (obj->o_type)\r
+    {\r
+       case RING:\r
+           guess = r_guess;\r
+           know = r_know;\r
+           elsewise = (r_guess[obj->o_which] != NULL ?\r
+                       r_guess[obj->o_which] : r_stones[obj->o_which]);\r
+       when POTION:\r
+           guess = p_guess;\r
+           know = p_know;\r
+           elsewise = (p_guess[obj->o_which] != NULL ?\r
+                       p_guess[obj->o_which] : p_colors[obj->o_which]);\r
+       when SCROLL:\r
+           guess = s_guess;\r
+           know = s_know;\r
+           elsewise = (s_guess[obj->o_which] != NULL ?\r
+                       s_guess[obj->o_which] : s_names[obj->o_which]);\r
+       when STICK:\r
+           guess = ws_guess;\r
+           know = ws_know;\r
+           elsewise = (ws_guess[obj->o_which] != NULL ?\r
+                       ws_guess[obj->o_which] : ws_made[obj->o_which]);\r
+       otherwise:\r
+           msg("You can't call that anything");\r
+           return;\r
+    }\r
+    if (know[obj->o_which])\r
+    {\r
+       msg("That has already been identified");\r
+       return;\r
+    }\r
+    if (terse)\r
+       addmsg("C");\r
+    else\r
+       addmsg("Was c");\r
+    msg("alled \"%s\"", elsewise);\r
+    if (terse)\r
+       msg("Call it: ");\r
+    else\r
+       msg("What do you want to call it? ");\r
+    strcpy(prbuf, elsewise);\r
+    if (get_str(prbuf, cw) == NORM)\r
+    {\r
+        if (guess[obj->o_which] != NULL)\r
+           free(guess[obj->o_which]);\r
+       guess[obj->o_which] = malloc((unsigned int) strlen(prbuf) + 1);\r
+       if (guess[obj->o_which] != NULL)\r
+           strcpy(guess[obj->o_which], prbuf);\r
+    }\r
+}\r
diff --git a/daemon.c b/daemon.c
new file mode 100644 (file)
index 0000000..7a26866
--- /dev/null
+++ b/daemon.c
@@ -0,0 +1,201 @@
+/*\r
+ * Contains functions for dealing with things that happen in the\r
+ * future.\r
+ *\r
+ * @(#)daemon.c        3.3 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include "rogue.h"\r
+\r
+#define EMPTY 0\r
+#define DAEMON -1\r
+#define MAXDAEMONS 20\r
+\r
+#define _X_ { EMPTY }\r
+\r
+struct delayed_action d_list[MAXDAEMONS] = {\r
+    _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,\r
+    _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, \r
+};\r
+\r
+/*\r
+ * d_slot:\r
+ *     Find an empty slot in the daemon/fuse list\r
+ */\r
+struct delayed_action *\r
+d_slot()\r
+{\r
+    register int i;\r
+    register struct delayed_action *dev;\r
+\r
+    for (i = 0, dev = d_list; i < MAXDAEMONS; i++, dev++)\r
+       if (dev->d_type == EMPTY)\r
+           return dev;\r
+    debug("Ran out of fuse slots");\r
+    return NULL;\r
+}\r
+\r
+/*\r
+ * find_slot:\r
+ *     Find a particular slot in the table\r
+ */\r
+\r
+struct delayed_action *\r
+find_slot(func)\r
+register int (*func)();\r
+{\r
+    register int i;\r
+    register struct delayed_action *dev;\r
+\r
+    for (i = 0, dev = d_list; i < MAXDAEMONS; i++, dev++)\r
+       if (dev->d_type != EMPTY && func == dev->d_func)\r
+           return dev;\r
+    return NULL;\r
+}\r
+\r
+/*\r
+ * daemon:\r
+ *     Start a daemon, takes a function.\r
+ */\r
+\r
+start_daemon(func, arg, type)\r
+int (*func)(), arg, type;\r
+{\r
+    register struct delayed_action *dev;\r
+\r
+    dev = d_slot();\r
\r
+    if (dev != NULL) \r
+    {\r
+        dev->d_type = type;\r
+        dev->d_func = func;\r
+        dev->d_arg = arg;\r
+        dev->d_time = DAEMON;\r
+    }\r
+}\r
+\r
+/*\r
+ * kill_daemon:\r
+ *     Remove a daemon from the list\r
+ */\r
+\r
+kill_daemon(func)\r
+int (*func)();\r
+{\r
+    register struct delayed_action *dev;\r
+\r
+    if ((dev = find_slot(func)) == NULL)\r
+       return;\r
+    /*\r
+     * Take it out of the list\r
+     */\r
+    dev->d_type = EMPTY;\r
+}\r
+\r
+/*\r
+ * do_daemons:\r
+ *     Run all the daemons that are active with the current flag,\r
+ *     passing the argument to the function.\r
+ */\r
+\r
+do_daemons(flag)\r
+register int flag;\r
+{\r
+    register struct delayed_action *dev;\r
+\r
+    /*\r
+     * Loop through the devil list\r
+     */\r
+    for (dev = d_list; dev <= &d_list[MAXDAEMONS-1]; dev++)\r
+       /*\r
+        * Executing each one, giving it the proper arguments\r
+        */\r
+       if (dev->d_type == flag && dev->d_time == DAEMON)\r
+           (*dev->d_func)(dev->d_arg);\r
+}\r
+\r
+/*\r
+ * fuse:\r
+ *     Start a fuse to go off in a certain number of turns\r
+ */\r
+\r
+fuse(func, arg, time, type)\r
+int (*func)(), arg, time, type;\r
+{\r
+    register struct delayed_action *wire;\r
+\r
+    wire = d_slot();\r
+\r
+    if (wire != NULL)\r
+    {\r
+        wire->d_type = type;\r
+        wire->d_func = func;\r
+        wire->d_arg = arg;\r
+        wire->d_time = time;\r
+    }\r
+}\r
+\r
+/*\r
+ * lengthen:\r
+ *     Increase the time until a fuse goes off\r
+ */\r
+\r
+lengthen(func, xtime)\r
+int (*func)();\r
+int xtime;\r
+{\r
+    register struct delayed_action *wire;\r
+\r
+    if ((wire = find_slot(func)) == NULL)\r
+       return;\r
+    wire->d_time += xtime;\r
+}\r
+\r
+/*\r
+ * extinguish:\r
+ *     Put out a fuse\r
+ */\r
+\r
+extinguish(func)\r
+int (*func)();\r
+{\r
+    register struct delayed_action *wire;\r
+\r
+    if ((wire = find_slot(func)) == NULL)\r
+       return;\r
+    wire->d_type = EMPTY;\r
+}\r
+\r
+/*\r
+ * do_fuses:\r
+ *     Decrement counters and start needed fuses\r
+ */\r
+\r
+do_fuses(flag)\r
+register int flag;\r
+{\r
+    register struct delayed_action *wire;\r
+\r
+    /*\r
+     * Step though the list\r
+     */\r
+    for (wire = d_list; wire <= &d_list[MAXDAEMONS-1]; wire++)\r
+    {\r
+       /*\r
+        * Decrementing counters and starting things we want.  We also need\r
+        * to remove the fuse from the list once it has gone off.\r
+        */\r
+       if (flag == wire->d_type && wire->d_time > 0 && --wire->d_time == 0)\r
+       {\r
+           wire->d_type = EMPTY;\r
+           (*wire->d_func)(wire->d_arg);\r
+       }\r
+     }\r
+}\r
diff --git a/daemons.c b/daemons.c
new file mode 100644 (file)
index 0000000..380e5c4
--- /dev/null
+++ b/daemons.c
@@ -0,0 +1,169 @@
+/*\r
+ * All the daemon and fuse functions are in here\r
+ *\r
+ * @(#)daemons.c       3.7 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include "rogue.h"\r
+\r
+/*\r
+ * doctor:\r
+ *     A healing daemon that restors hit points after rest\r
+ */\r
+\r
+doctor()\r
+{\r
+    register int lv, ohp;\r
+\r
+    lv = pstats.s_lvl;\r
+    ohp = pstats.s_hpt;\r
+    quiet++;\r
+    if (lv < 8)\r
+    {\r
+       if (quiet > 20 - lv*2)\r
+           pstats.s_hpt++;\r
+    }\r
+    else\r
+       if (quiet >= 3)\r
+           pstats.s_hpt += rnd(lv - 7)+1;\r
+    if (ISRING(LEFT, R_REGEN))\r
+       pstats.s_hpt++;\r
+    if (ISRING(RIGHT, R_REGEN))\r
+       pstats.s_hpt++;\r
+    if (ohp != pstats.s_hpt)\r
+    {\r
+       if (pstats.s_hpt > max_hp)\r
+           pstats.s_hpt = max_hp;\r
+       quiet = 0;\r
+    }\r
+}\r
+\r
+/*\r
+ * Swander:\r
+ *     Called when it is time to start rolling for wandering monsters\r
+ */\r
+\r
+swander()\r
+{\r
+    start_daemon(rollwand, 0, BEFORE);\r
+}\r
+\r
+/*\r
+ * rollwand:\r
+ *     Called to roll to see if a wandering monster starts up\r
+ */\r
+\r
+int between = 0;\r
+\r
+rollwand()\r
+{\r
+    if (++between >= 4)\r
+    {\r
+       if (roll(1, 6) == 4)\r
+       {\r
+           wanderer();\r
+           kill_daemon(rollwand);\r
+           fuse(swander, 0, WANDERTIME, BEFORE);\r
+       }\r
+       between = 0;\r
+    }\r
+}\r
+\r
+/*\r
+ * unconfuse:\r
+ *     Release the poor player from his confusion\r
+ */\r
+\r
+unconfuse()\r
+{\r
+    player.t_flags &= ~ISHUH;\r
+    msg("You feel less confused now");\r
+}\r
+\r
+\r
+/*\r
+ * unsee:\r
+ *     He lost his see invisible power\r
+ */\r
+\r
+unsee()\r
+{\r
+    player.t_flags &= ~CANSEE;\r
+}\r
+\r
+/*\r
+ * sight:\r
+ *     He gets his sight back\r
+ */\r
+\r
+sight()\r
+{\r
+    if (on(player, ISBLIND))\r
+    {\r
+       extinguish(sight);\r
+       player.t_flags &= ~ISBLIND;\r
+       light(&hero);\r
+       msg("The veil of darkness lifts");\r
+    }\r
+}\r
+\r
+/*\r
+ * nohaste:\r
+ *     End the hasting\r
+ */\r
+\r
+nohaste()\r
+{\r
+    player.t_flags &= ~ISHASTE;\r
+    msg("You feel yourself slowing down.");\r
+}\r
+\r
+/*\r
+ * digest the hero's food\r
+ */\r
+stomach()\r
+{\r
+    register int oldfood;\r
+\r
+    if (food_left <= 0)\r
+    {\r
+       /*\r
+        * the hero is fainting\r
+        */\r
+       if (no_command || rnd(100) > 20)\r
+           return;\r
+       no_command = rnd(8)+4;\r
+       if (!terse)\r
+           addmsg("You feel too weak from lack of food.  ");\r
+       msg("You faint");\r
+       running = FALSE;\r
+       count = 0;\r
+       hungry_state = 3;\r
+    }\r
+    else\r
+    {\r
+       oldfood = food_left;\r
+       food_left -= ring_eat(LEFT) + ring_eat(RIGHT) + 1 - amulet;\r
+\r
+       if (food_left < MORETIME && oldfood >= MORETIME)\r
+       {\r
+           msg("You are starting to feel weak");\r
+           hungry_state = 2;\r
+       }\r
+       else if (food_left < 2 * MORETIME && oldfood >= 2 * MORETIME)\r
+       {\r
+           if (!terse)\r
+               msg("You are starting to get hungry");\r
+           else\r
+               msg("Getting hungry");\r
+           hungry_state = 1;\r
+       }\r
+    }\r
+}\r
diff --git a/fight.c b/fight.c
new file mode 100644 (file)
index 0000000..516d8b7
--- /dev/null
+++ b/fight.c
@@ -0,0 +1,742 @@
+/*\r
+ * All the fighting gets done here\r
+ *\r
+ * @(#)fight.c 3.28 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <ctype.h>\r
+#include <string.h>\r
+#include "rogue.h"\r
+\r
+long e_levels[] = {\r
+    10L,20L,40L,80L,160L,320L,640L,1280L,2560L,5120L,10240L,20480L,\r
+    40920L, 81920L, 163840L, 327680L, 655360L, 1310720L, 2621440L, 0L };\r
+\r
+/*\r
+ * fight:\r
+ *     The player attacks the monster.\r
+ */\r
+\r
+fight(mp, mn, weap, thrown)\r
+register coord *mp;\r
+char mn;\r
+struct object *weap;\r
+bool thrown;\r
+{\r
+    register struct thing *tp;\r
+    register struct linked_list *item;\r
+    register bool did_hit = TRUE;\r
+\r
+    /*\r
+     * Find the monster we want to fight\r
+     */\r
+    if ((item = find_mons(mp->y, mp->x)) == NULL)\r
+    {\r
+       debug("Fight what @ %d,%d", mp->y, mp->x);\r
+       return(0);\r
+    }\r
+    tp = (struct thing *) ldata(item);\r
+    /*\r
+     * Since we are fighting, things are not quiet so no healing takes\r
+     * place.\r
+     */\r
+    quiet = 0;\r
+    runto(mp, &hero);\r
+    /*\r
+     * Let him know it was really a mimic (if it was one).\r
+     */\r
+    if (tp->t_type == 'M' && tp->t_disguise != 'M' && off(player, ISBLIND))\r
+    {\r
+       msg("Wait! That's a mimic!");\r
+       tp->t_disguise = 'M';\r
+       did_hit = thrown;\r
+    }\r
+    if (did_hit)\r
+    {\r
+       register char *mname;\r
+\r
+       did_hit = FALSE;\r
+       if (on(player, ISBLIND))\r
+           mname = "it";\r
+       else\r
+           mname = monsters[mn-'A'].m_name;\r
+       if (roll_em(&pstats, &tp->t_stats, weap, thrown))\r
+       {\r
+           did_hit = TRUE;\r
+           if (thrown)\r
+               thunk(weap, mname);\r
+           else\r
+               hit(NULL, mname);\r
+           if (on(player, CANHUH))\r
+           {\r
+               msg("Your hands stop glowing red");\r
+               msg("The %s appears confused.", mname);\r
+               tp->t_flags |= ISHUH;\r
+               player.t_flags &= ~CANHUH;\r
+           }\r
+           if (tp->t_stats.s_hpt <= 0)\r
+               killed(item, TRUE);\r
+       }\r
+       else\r
+           if (thrown)\r
+               bounce(weap, mname);\r
+           else\r
+               miss(NULL, mname);\r
+    }\r
+    count = 0;\r
+    return did_hit;\r
+}\r
+\r
+/*\r
+ * attack:\r
+ *     The monster attacks the player\r
+ */\r
+\r
+attack(mp)\r
+register struct thing *mp;\r
+{\r
+    register char *mname;\r
+\r
+    /*\r
+     * Since this is an attack, stop running and any healing that was\r
+     * going on at the time.\r
+     */\r
+    running = FALSE;\r
+    quiet = 0;\r
+    if (mp->t_type == 'M' && off(player, ISBLIND))\r
+       mp->t_disguise = 'M';\r
+    if (on(player, ISBLIND))\r
+       mname = "it";\r
+    else\r
+       mname = monsters[mp->t_type-'A'].m_name;\r
+    if (roll_em(&mp->t_stats, &pstats, NULL, FALSE))\r
+    {\r
+       if (mp->t_type != 'E')\r
+           hit(mname, NULL);\r
+       if (pstats.s_hpt <= 0)\r
+           death(mp->t_type);  /* Bye bye life ... */\r
+       if (off(*mp, ISCANC))\r
+           switch (mp->t_type)\r
+           {\r
+               case 'R':\r
+                   /*\r
+                    * If a rust monster hits, you lose armor\r
+                    */\r
+                   if (cur_armor != NULL && cur_armor->o_ac < 9)\r
+                   {\r
+                       if (!terse)\r
+                           msg("Your armor appears to be weaker now. Oh my!");\r
+                       else\r
+                           msg("Your armor weakens");\r
+                       cur_armor->o_ac++;\r
+                   }\r
+               when 'E':\r
+                   /*\r
+                    * The gaze of the floating eye hypnotizes you\r
+                    */\r
+                   if (on(player, ISBLIND))\r
+                       break;\r
+                   if (!no_command)\r
+                   {\r
+                       addmsg("You are transfixed");\r
+                       if (!terse)\r
+                           addmsg(" by the gaze of the floating eye.");\r
+                       endmsg();\r
+                   }\r
+                   no_command += rnd(2)+2;\r
+               when 'A':\r
+                   /*\r
+                    * Ants have poisonous bites\r
+                    */\r
+                   if (!save(VS_POISON))\r
+                       if (!ISWEARING(R_SUSTSTR))\r
+                       {\r
+                           chg_str(-1);\r
+                           if (!terse)\r
+                               msg("You feel a sting in your arm and now feel weaker");\r
+                           else\r
+                               msg("A sting has weakened you");\r
+                       }\r
+                       else\r
+                           if (!terse)\r
+                               msg("A sting momentarily weakens you");\r
+                           else\r
+                               msg("Sting has no effect");\r
+               when 'W':\r
+                   /*\r
+                    * Wraiths might drain energy levels\r
+                    */\r
+                   if (rnd(100) < 15)\r
+                   {\r
+                       int fewer;\r
+\r
+                       if (pstats.s_exp == 0)\r
+                           death('W');         /* All levels gone */\r
+                       msg("You suddenly feel weaker.");\r
+                       if (--pstats.s_lvl == 0)\r
+                       {\r
+                           pstats.s_exp = 0;\r
+                           pstats.s_lvl = 1;\r
+                       }\r
+                       else\r
+                           pstats.s_exp = e_levels[pstats.s_lvl-1]+1;\r
+                       fewer = roll(1, 10);\r
+                       pstats.s_hpt -= fewer;\r
+                       max_hp -= fewer;\r
+                       if (pstats.s_hpt < 1)\r
+                           pstats.s_hpt = 1;\r
+                       if (max_hp < 1)\r
+                           death('W');\r
+                   }\r
+               when 'F':\r
+                   /*\r
+                    * Violet fungi stops the poor guy from moving\r
+                    */\r
+                   player.t_flags |= ISHELD;\r
+                   sprintf(monsters['F'-'A'].m_stats.s_dmg,"%dd1",++fung_hit);\r
+               when 'L':\r
+               {\r
+                   /*\r
+                    * Leperachaun steals some gold\r
+                    */\r
+                   register long lastpurse;\r
+\r
+                   lastpurse = purse;\r
+                   purse -= GOLDCALC;\r
+                   if (!save(VS_MAGIC))\r
+                       purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;\r
+                   if (purse < 0)\r
+                       purse = 0;\r
+                   if (purse != lastpurse)\r
+                       msg("Your purse feels lighter");\r
+                   remove_monster(&mp->t_pos, find_mons(mp->t_pos.y, mp->t_pos.x));\r
+                   mp = NULL;\r
+               }\r
+               when 'N':\r
+               {\r
+                   register struct linked_list *list, *steal;\r
+                   register struct object *obj;\r
+                   register int nobj;\r
+\r
+                   /*\r
+                    * Nymph's steal a magic item, look through the pack\r
+                    * and pick out one we like.\r
+                    */\r
+                   steal = NULL;\r
+                   for (nobj = 0, list = pack; list != NULL; list = next(list))\r
+                   {\r
+                       obj = (struct object *) ldata(list);\r
+                       if (obj != cur_armor && \r
+                            obj != cur_weapon &&\r
+                            obj != cur_ring[LEFT] &&\r
+                            obj != cur_ring[RIGHT] && /* Nymph bug fix */\r
+                           is_magic(obj) && \r
+                            rnd(++nobj) == 0)\r
+                               steal = list;\r
+                   }\r
+                   if (steal != NULL)\r
+                   {\r
+                       register struct object *obj;\r
+\r
+                       obj = (struct object *) ldata(steal);\r
+                       remove_monster(&mp->t_pos, find_mons(mp->t_pos.y, mp->t_pos.x));\r
+                       mp = NULL;\r
+                       if (obj->o_count > 1 && obj->o_group == 0)\r
+                       {\r
+                           register int oc;\r
+\r
+                           oc = obj->o_count;\r
+                           obj->o_count = 1;\r
+                           msg("She stole %s!", inv_name(obj, TRUE));\r
+                           obj->o_count = oc - 1;\r
+                       }\r
+                       else\r
+                       {\r
+                           msg("She stole %s!", inv_name(obj, TRUE));\r
+                           detach(pack, steal);\r
+                           discard(steal);\r
+                       }\r
+                       inpack--;\r
+                   }\r
+               }\r
+               otherwise:\r
+                   break;\r
+           }\r
+    }\r
+    else if (mp->t_type != 'E')\r
+    {\r
+       if (mp->t_type == 'F')\r
+       {\r
+           pstats.s_hpt -= fung_hit;\r
+           if (pstats.s_hpt <= 0)\r
+               death(mp->t_type);      /* Bye bye life ... */\r
+       }\r
+       miss(mname, NULL);\r
+    }\r
+    /*\r
+     * Check to see if this is a regenerating monster and let it heal if\r
+     * it is.\r
+     */\r
+    if ((mp != NULL) && (on(*mp, ISREGEN) && rnd(100) < 33))\r
+       mp->t_stats.s_hpt++;\r
+    if (fight_flush)\r
+    {\r
+       flush_type();   /* flush typeahead */\r
+    }\r
+    count = 0;\r
+    status();\r
+\r
+    if (mp == NULL)\r
+        return(-1);\r
+    else\r
+        return(0);\r
+}\r
+\r
+/*\r
+ * swing:\r
+ *     returns true if the swing hits\r
+ */\r
+\r
+swing(at_lvl, op_arm, wplus)\r
+int at_lvl, op_arm, wplus;\r
+{\r
+    register int res = rnd(20)+1;\r
+    register int need = (21-at_lvl)-op_arm;\r
+\r
+    return (res+wplus >= need);\r
+}\r
+\r
+/*\r
+ * check_level:\r
+ *     Check to see if the guy has gone up a level.\r
+ */\r
+\r
+check_level()\r
+{\r
+    register int i, add;\r
+\r
+    for (i = 0; e_levels[i] != 0; i++)\r
+       if (e_levels[i] > pstats.s_exp)\r
+           break;\r
+    i++;\r
+    if (i > pstats.s_lvl)\r
+    {\r
+       add = roll(i-pstats.s_lvl,10);\r
+       max_hp += add;\r
+       if ((pstats.s_hpt += add) > max_hp)\r
+           pstats.s_hpt = max_hp;\r
+       msg("Welcome to level %d", i);\r
+    }\r
+    pstats.s_lvl = i;\r
+}\r
+\r
+/*\r
+ * roll_em:\r
+ *     Roll several attacks\r
+ */\r
+\r
+roll_em(att, def, weap, hurl)\r
+struct stats *att, *def;\r
+struct object *weap;\r
+bool hurl;\r
+{\r
+    register char *cp;\r
+    register int ndice, nsides, def_arm;\r
+    register bool did_hit = FALSE;\r
+    register int prop_hplus, prop_dplus;\r
+\r
+    prop_hplus = prop_dplus = 0;\r
+    if (weap == NULL)\r
+       cp = att->s_dmg;\r
+    else if (hurl)\r
+       if ((weap->o_flags&ISMISL) && cur_weapon != NULL &&\r
+         cur_weapon->o_which == weap->o_launch)\r
+       {\r
+           cp = weap->o_hurldmg;\r
+           prop_hplus = cur_weapon->o_hplus;\r
+           prop_dplus = cur_weapon->o_dplus;\r
+       }\r
+       else\r
+           cp = (weap->o_flags&ISMISL ? weap->o_damage : weap->o_hurldmg);\r
+    else\r
+    {\r
+       cp = weap->o_damage;\r
+       /*\r
+        * Drain a staff of striking\r
+        */\r
+       if (weap->o_type == STICK && weap->o_which == WS_HIT\r
+           && weap->o_charges == 0)\r
+               {\r
+                   strcpy(weap->o_damage,"0d0");\r
+                   weap->o_hplus = weap->o_dplus = 0;\r
+               }\r
+    }\r
+    for (;;)\r
+    {\r
+       int damage;\r
+       int hplus = prop_hplus + (weap == NULL ? 0 : weap->o_hplus);\r
+       int dplus = prop_dplus + (weap == NULL ? 0 : weap->o_dplus);\r
+\r
+       if (weap == cur_weapon)\r
+       {\r
+           if (ISRING(LEFT, R_ADDDAM))\r
+               dplus += cur_ring[LEFT]->o_ac;\r
+           else if (ISRING(LEFT, R_ADDHIT))\r
+               hplus += cur_ring[LEFT]->o_ac;\r
+           if (ISRING(RIGHT, R_ADDDAM))\r
+               dplus += cur_ring[RIGHT]->o_ac;\r
+           else if (ISRING(RIGHT, R_ADDHIT))\r
+               hplus += cur_ring[RIGHT]->o_ac;\r
+       }\r
+       ndice = atoi(cp);\r
+       if ((cp = strchr(cp, 'd')) == NULL)\r
+           break;\r
+       nsides = atoi(++cp);\r
+       if (def == &pstats)\r
+       {\r
+           if (cur_armor != NULL)\r
+               def_arm = cur_armor->o_ac;\r
+           else\r
+               def_arm = def->s_arm;\r
+           if (ISRING(LEFT, R_PROTECT))\r
+               def_arm -= cur_ring[LEFT]->o_ac;\r
+           else if (ISRING(RIGHT, R_PROTECT))\r
+               def_arm -= cur_ring[RIGHT]->o_ac;\r
+       }\r
+       else\r
+           def_arm = def->s_arm;\r
+       if (swing(att->s_lvl, def_arm, hplus+str_plus(&att->s_str)))\r
+       {\r
+           register int proll;\r
+\r
+           proll = roll(ndice, nsides);\r
+           if (ndice + nsides > 0 && proll < 1)\r
+               debug("Damage for %dd%d came out %d.", ndice, nsides, proll);\r
+           damage = dplus + proll + add_dam(&att->s_str);\r
+           def->s_hpt -= max(0, damage);\r
+           did_hit = TRUE;\r
+       }\r
+       if ((cp = strchr(cp, '/')) == NULL)\r
+           break;\r
+       cp++;\r
+    }\r
+    return did_hit;\r
+}\r
+\r
+/*\r
+ * prname:\r
+ *     The print name of a combatant\r
+ */\r
+\r
+char *\r
+prname(who, upper)\r
+register char *who;\r
+bool upper;\r
+{\r
+    static char tbuf[80];\r
+\r
+    *tbuf = '\0';\r
+    if (who == 0)\r
+       strcpy(tbuf, "you"); \r
+    else if (on(player, ISBLIND))\r
+       strcpy(tbuf, "it");\r
+    else\r
+    {\r
+       strcpy(tbuf, "the ");\r
+       strcat(tbuf, who);\r
+    }\r
+    if (upper)\r
+       *tbuf = toupper(*tbuf);\r
+    return tbuf;\r
+}\r
+\r
+/*\r
+ * hit:\r
+ *     Print a message to indicate a succesful hit\r
+ */\r
+\r
+hit(er, ee)\r
+register char *er, *ee;\r
+{\r
+    register char *s;\r
+\r
+    addmsg(prname(er, TRUE));\r
+    if (terse)\r
+       s = " hit.";\r
+    else\r
+       switch (rnd(4))\r
+       {\r
+           case 0: s = " scored an excellent hit on ";\r
+           when 1: s = " hit ";\r
+           when 2: s = (er == 0 ? " have injured " : " has injured ");\r
+           when 3: s = (er == 0 ? " swing and hit " : " swings and hits ");\r
+       }\r
+    addmsg(s);\r
+    if (!terse)\r
+       addmsg(prname(ee, FALSE));\r
+    endmsg();\r
+}\r
+\r
+/*\r
+ * miss:\r
+ *     Print a message to indicate a poor swing\r
+ */\r
+\r
+miss(er, ee)\r
+register char *er, *ee;\r
+{\r
+    register char *s;\r
+\r
+    addmsg(prname(er, TRUE));\r
+    switch (terse ? 0 : rnd(4))\r
+    {\r
+       case 0: s = (er == 0 ? " miss" : " misses");\r
+       when 1: s = (er == 0 ? " swing and miss" : " swings and misses");\r
+       when 2: s = (er == 0 ? " barely miss" : " barely misses");\r
+       when 3: s = (er == 0 ? " don't hit" : " doesn't hit");\r
+    }\r
+    addmsg(s);\r
+    if (!terse)\r
+       addmsg(" %s", prname(ee, FALSE));\r
+    endmsg();\r
+}\r
+\r
+/*\r
+ * save_throw:\r
+ *     See if a creature save against something\r
+ */\r
+save_throw(which, tp)\r
+int which;\r
+struct thing *tp;\r
+{\r
+    register int need;\r
+\r
+    need = 14 + which - tp->t_stats.s_lvl / 2;\r
+    return (roll(1, 20) >= need);\r
+}\r
+\r
+/*\r
+ * save:\r
+ *     See if he saves against various nasty things\r
+ */\r
+\r
+save(which)\r
+int which;\r
+{\r
+    return save_throw(which, &player);\r
+}\r
+\r
+/*\r
+ * str_plus:\r
+ *     compute bonus/penalties for strength on the "to hit" roll\r
+ */\r
+\r
+str_plus(str)\r
+register str_t *str;\r
+{\r
+    if (str->st_str == 18)\r
+    {\r
+       if (str->st_add == 100)\r
+           return 3;\r
+       if (str->st_add > 50)\r
+           return 2;\r
+    }\r
+    if (str->st_str >= 17)\r
+       return 1;\r
+    if (str->st_str > 6)\r
+       return 0;\r
+    return str->st_str - 7;\r
+}\r
+\r
+/*\r
+ * add_dam:\r
+ *     compute additional damage done for exceptionally high or low strength\r
+ */\r
+\r
+ add_dam(str)\r
+ register str_t *str;\r
+ {\r
+    if (str->st_str == 18)\r
+    {\r
+       if (str->st_add == 100)\r
+           return 6;\r
+       if (str->st_add > 90)\r
+           return 5;\r
+       if (str->st_add > 75)\r
+           return 4;\r
+       if (str->st_add != 0)\r
+           return 3;\r
+       return 2;\r
+    }\r
+    if (str->st_str > 15)\r
+       return 1;\r
+    if (str->st_str > 6)\r
+       return 0;\r
+    return str->st_str - 7;\r
+}\r
+\r
+/*\r
+ * raise_level:\r
+ *     The guy just magically went up a level.\r
+ */\r
+\r
+raise_level()\r
+{\r
+    pstats.s_exp = e_levels[pstats.s_lvl-1] + 1L;\r
+    check_level();\r
+}\r
+\r
+/*\r
+ * thunk:\r
+ *     A missile hits a monster\r
+ */\r
+\r
+thunk(weap, mname)\r
+register struct object *weap;\r
+register char *mname;\r
+{\r
+    if (weap->o_type == WEAPON)\r
+       msg("The %s hits the %s", w_names[weap->o_which], mname);\r
+    else\r
+       msg("You hit the %s.", mname);\r
+}\r
+\r
+/*\r
+ * bounce:\r
+ *     A missile misses a monster\r
+ */\r
+\r
+bounce(weap, mname)\r
+register struct object *weap;\r
+register char *mname;\r
+{\r
+    if (weap->o_type == WEAPON)\r
+       msg("The %s misses the %s", w_names[weap->o_which], mname);\r
+    else\r
+       msg("You missed the %s.", mname);\r
+}\r
+\r
+/*\r
+ * remove a monster from the screen\r
+ */\r
+remove_monster(mp, item)\r
+register coord *mp;\r
+register struct linked_list *item;\r
+{\r
+    mvwaddch(mw, mp->y, mp->x, ' ');\r
+    mvwaddch(cw, mp->y, mp->x, ((struct thing *) ldata(item))->t_oldch);\r
+    detach(mlist, item);\r
+    discard(item);\r
+}\r
+\r
+/*\r
+ * is_magic:\r
+ *     Returns true if an object radiates magic\r
+ */\r
+\r
+is_magic(obj)\r
+register struct object *obj;\r
+{\r
+    switch (obj->o_type)\r
+    {\r
+       case ARMOR:\r
+           return obj->o_ac != a_class[obj->o_which];\r
+       when WEAPON:\r
+           return obj->o_hplus != 0 || obj->o_dplus != 0;\r
+       when POTION:\r
+       case SCROLL:\r
+       case STICK:\r
+       case RING:\r
+       case AMULET:\r
+           return TRUE;\r
+    }\r
+    return FALSE;\r
+}\r
+\r
+/*\r
+ * killed:\r
+ *     Called to put a monster to death\r
+ */\r
+\r
+killed(item, pr)\r
+register struct linked_list *item;\r
+bool pr;\r
+{\r
+    register struct thing *tp;\r
+    register struct linked_list *pitem, *nexti;\r
+\r
+    tp = (struct thing *) ldata(item);\r
+    if (pr)\r
+    {\r
+       addmsg(terse ? "Defeated " : "You have defeated ");\r
+       if (on(player, ISBLIND))\r
+           msg("it.");\r
+       else\r
+       {\r
+           if (!terse)\r
+               addmsg("the ");\r
+           msg("%s.", monsters[tp->t_type-'A'].m_name);\r
+       }\r
+    }\r
+    pstats.s_exp += tp->t_stats.s_exp;\r
+    /*\r
+     * Do adjustments if he went up a level\r
+     */\r
+    check_level();\r
+    /*\r
+     * If the monster was a violet fungi, un-hold him\r
+     */\r
+    switch (tp->t_type)\r
+    {\r
+       case 'F':\r
+           player.t_flags &= ~ISHELD;\r
+           fung_hit = 0;\r
+           strcpy(monsters['F'-'A'].m_stats.s_dmg, "000d0");\r
+       when 'L':\r
+       {\r
+           register struct room *rp;\r
+\r
+           if ((rp = roomin(&tp->t_pos)) == NULL)\r
+               break;\r
+           if (rp->r_goldval != 0 || fallpos(&tp->t_pos,&rp->r_gold,FALSE))\r
+           {\r
+               rp->r_goldval += GOLDCALC;\r
+               if (save(VS_MAGIC))\r
+                   rp->r_goldval += GOLDCALC + GOLDCALC\r
+                                  + GOLDCALC + GOLDCALC;\r
+               mvwaddch(stdscr, rp->r_gold.y, rp->r_gold.x, GOLD);\r
+               if (!(rp->r_flags & ISDARK))\r
+               {\r
+                   light(&hero);\r
+                   mvwaddch(cw, hero.y, hero.x, PLAYER);\r
+               }\r
+           }\r
+       }\r
+    }\r
+    /*\r
+     * Empty the monsters pack\r
+     */\r
+    pitem = tp->t_pack;\r
+    while (pitem != NULL)\r
+    {\r
+       register struct object *obj;\r
+\r
+       nexti = next(tp->t_pack);\r
+       obj = (struct object *) ldata(pitem);\r
+       obj->o_pos = tp->t_pos;\r
+       detach(tp->t_pack, pitem);\r
+       fall(pitem, FALSE);\r
+       pitem = nexti;\r
+    }\r
+    /*\r
+     * Get rid of the monster.\r
+     */\r
+    remove_monster(&tp->t_pos, item);\r
+}\r
diff --git a/init.c b/init.c
new file mode 100644 (file)
index 0000000..031ff3e
--- /dev/null
+++ b/init.c
@@ -0,0 +1,589 @@
+/*\r
+ * global variable initializaton\r
+ *\r
+ * @(#)init.c  3.33 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <ctype.h>\r
+#include <string.h>\r
+#include "rogue.h"\r
+\r
+bool playing = TRUE, running = FALSE, wizard = FALSE;\r
+bool notify = TRUE, fight_flush = FALSE, terse = FALSE, door_stop = FALSE;\r
+bool jump = FALSE, slow_invent = FALSE, firstmove = FALSE, askme = FALSE;\r
+bool amulet = FALSE, in_shell = FALSE;\r
+struct linked_list *lvl_obj = NULL, *mlist = NULL;\r
+struct object *cur_weapon = NULL;\r
+int mpos = 0, no_move = 0, no_command = 0, level = 1, purse = 0, inpack = 0;\r
+int total = 0, no_food = 0, count = 0, fung_hit = 0, quiet = 0;\r
+int food_left = HUNGERTIME, group = 1, hungry_state = 0;\r
+int lastscore = -1;\r
+\r
+struct thing player;\r
+struct room rooms[MAXROOMS];\r
+struct room *oldrp;\r
+struct stats max_stats; \r
+struct object *cur_armor;\r
+struct object *cur_ring[2];\r
+bool after;\r
+bool waswizard;\r
+coord oldpos;                            /* Position before last look() call */\r
+coord delta;                             /* Change indicated to get_dir()    */\r
+\r
+bool s_know[MAXSCROLLS];         /* Does he know what a scroll does */\r
+bool p_know[MAXPOTIONS];         /* Does he know what a potion does */\r
+bool r_know[MAXRINGS];                   /* Does he know what a ring does\r
+ */\r
+bool ws_know[MAXSTICKS];         /* Does he know what a stick does */\r
+\r
+char take;                               /* Thing the rogue is taking */\r
+char runch;                              /* Direction player is running */\r
+char whoami[80];                 /* Name of player */\r
+char fruit[80];                          /* Favorite fruit */\r
+char huh[80];                            /* The last message printed */\r
+int dnum;                                /* Dungeon number */\r
+char *s_names[MAXSCROLLS];               /* Names of the scrolls */\r
+char *p_colors[MAXPOTIONS];              /* Colors of the potions */\r
+char *r_stones[MAXRINGS];                /* Stone settings of the rings */\r
+char *a_names[MAXARMORS];                /* Names of armor types */\r
+char *ws_made[MAXSTICKS];                /* What sticks are made of */\r
+char *s_guess[MAXSCROLLS];               /* Players guess at what scroll is */\r
+char *p_guess[MAXPOTIONS];               /* Players guess at what potion is */\r
+char *r_guess[MAXRINGS];         /* Players guess at what ring is */\r
+char *ws_guess[MAXSTICKS];               /* Players guess at what wand is */\r
+char *ws_type[MAXSTICKS];                /* Is it a wand or a staff */\r
+char file_name[80];                      /* Save file name */\r
+char home[80];                           /* User's home directory */\r
+char prbuf[80];                          /* Buffer for sprintfs */\r
+int max_hp;                              /* Player's max hit points */\r
+int ntraps;                              /* Number of traps on this level */\r
+int max_level;                           /* Deepest player has gone */\r
+int seed;                                /* Random number seed */\r
+\r
+struct trap  traps[MAXTRAPS];\r
+\r
+\r
+#define ___ 1\r
+#define _x {1,1}\r
+struct monster monsters[26] = {\r
+       /* Name          CARRY  FLAG    str, exp, lvl, amr, hpt, dmg */\r
+       { "giant ant",   0,     ISMEAN, { _x, 10,   2,   3, ___, "1d6" } },\r
+       { "bat",         0,     0,      { _x,  1,   1,   3, ___, "1d2" } },\r
+       { "centaur",     15,    0,      { _x, 15,   4,   4, ___, "1d6/1d6" } },\r
+       { "dragon",      100,   ISGREED,{ _x,9000, 10,  -1, ___, "1d8/1d8/3d10" } },\r
+       { "floating eye",0,     0,      { _x,  5,   1,   9, ___, "0d0" } },\r
+       { "violet fungi",0,     ISMEAN, { _x, 85,   8,   3, ___, "000d0" } },\r
+       { "gnome",       10,    0,      { _x,  8,   1,   5, ___, "1d6" } },\r
+       { "hobgoblin",   0,     ISMEAN, { _x,  3,   1,   5, ___, "1d8" } },\r
+       { "invisible stalker",0,ISINVIS,{ _x,120,   8,   3, ___, "4d4" } },\r
+       { "jackal",      0,     ISMEAN, { _x,  2,   1,   7, ___, "1d2" } },\r
+       { "kobold",      0,     ISMEAN, { _x,  1,   1,   7, ___, "1d4" } },\r
+       { "leprechaun",  0,     0,      { _x, 10,   3,   8, ___, "1d1" } },\r
+       { "mimic",       30,    0,      { _x,140,   7,   7, ___, "3d4" } },\r
+       { "nymph",       100,   0,      { _x, 40,   3,   9, ___, "0d0" } },\r
+       { "orc",         15,    ISBLOCK,{ _x,  5,   1,   6, ___, "1d8" } },\r
+       { "purple worm", 70,    0,      { _x,7000, 15,   6, ___, "2d12/2d4" } },\r
+       { "quasit",      30,    ISMEAN, { _x, 35,   3,   2, ___, "1d2/1d2/1d4" } },\r
+       { "rust monster",0,     ISMEAN, { _x, 25,   5,   2, ___, "0d0/0d0" } },\r
+       { "snake",       0,     ISMEAN, { _x,  3,   1,   5, ___, "1d3" } },\r
+       { "troll",       50,    ISREGEN|ISMEAN,{ _x, 55,   6,   4, ___, "1d8/1d8/2d6" } },\r
+       { "umber hulk",  40,    ISMEAN, { _x,130,   8,   2, ___, "3d4/3d4/2d5" } },\r
+       { "vampire",     20,    ISREGEN|ISMEAN,{ _x,380,   8,   1, ___, "1d10" } },\r
+       { "wraith",      0,     0,      { _x, 55,   5,   4, ___, "1d6" } },\r
+       { "xorn",        0,     ISMEAN, { _x,120,   7,  -2, ___, "1d3/1d3/1d3/4d6" } },\r
+       { "yeti",        30,    0,      { _x, 50,   4,   6, ___, "1d6/1d6" } },\r
+       { "zombie",      0,     ISMEAN, { _x,  7,   2,   8, ___, "1d8" } }\r
+};\r
+#undef ___\r
+\r
+/*\r
+ * init_player:\r
+ *     roll up the rogue\r
+ */\r
+\r
+init_player()\r
+{\r
+    pstats.s_lvl = 1;\r
+    pstats.s_exp = 0L;\r
+    max_hp = pstats.s_hpt = 12;\r
+    if (rnd(100) == 7)\r
+    {\r
+       pstats.s_str.st_str = 18;\r
+       pstats.s_str.st_add = rnd(100) + 1;\r
+    }\r
+    else\r
+    {\r
+       pstats.s_str.st_str = 16;\r
+       pstats.s_str.st_add = 0;\r
+    }\r
+    strcpy(pstats.s_dmg,"1d4");\r
+    pstats.s_arm = 10;\r
+    max_stats = pstats;\r
+    pack = NULL;\r
+}\r
+\r
+/*\r
+ * Contains defintions and functions for dealing with things like\r
+ * potions and scrolls\r
+ */\r
+\r
+char *rainbow[] = {\r
+    "red",\r
+    "blue",\r
+    "green",\r
+    "yellow",\r
+    "black",\r
+    "brown",\r
+    "orange",\r
+    "pink",\r
+    "purple",\r
+    "grey",\r
+    "white",\r
+    "silver",\r
+    "gold",\r
+    "violet",\r
+    "clear",\r
+    "vermilion",\r
+    "ecru",\r
+    "turquoise",\r
+    "magenta",\r
+    "amber",\r
+    "topaz",\r
+    "plaid",\r
+    "tan",\r
+    "tangerine"\r
+};\r
+\r
+#define NCOLORS (sizeof rainbow / sizeof (char *))\r
+const int cNCOLORS = NCOLORS;\r
+\r
+char *sylls[] = {\r
+    "a", "ab", "ag", "aks", "ala", "an", "ankh", "app", "arg", "arze",\r
+    "ash", "ban", "bar", "bat", "bek", "bie", "bin", "bit", "bjor",\r
+    "blu", "bot", "bu", "byt", "comp", "con", "cos", "cre", "dalf",\r
+    "dan", "den", "do", "e", "eep", "el", "eng", "er", "ere", "erk",\r
+    "esh", "evs", "fa", "fid", "for", "fri", "fu", "gan", "gar",\r
+    "glen", "gop", "gre", "ha", "he", "hyd", "i", "ing", "ion", "ip",\r
+    "ish", "it", "ite", "iv", "jo", "kho", "kli", "klis", "la", "lech",\r
+    "man", "mar", "me", "mi", "mic", "mik", "mon", "mung", "mur",\r
+    "nej", "nelg", "nep", "ner", "nes", "nes", "nih", "nin", "o", "od",\r
+    "ood", "org", "orn", "ox", "oxy", "pay", "pet", "ple", "plu", "po",\r
+    "pot", "prok", "re", "rea", "rhov", "ri", "ro", "rog", "rok", "rol",\r
+    "sa", "san", "sat", "see", "sef", "seh", "shu", "ski", "sna",\r
+    "sne", "snik", "sno", "so", "sol", "sri", "sta", "sun", "ta",\r
+    "tab", "tem", "ther", "ti", "tox", "trol", "tue", "turs", "u",\r
+    "ulk", "um", "un", "uni", "ur", "val", "viv", "vly", "vom", "wah",\r
+    "wed", "werg", "wex", "whon", "wun", "xo", "y", "yot", "yu",\r
+    "zant", "zap", "zeb", "zim", "zok", "zon", "zum",\r
+};\r
+\r
+char *stones[] = {\r
+    "agate",\r
+    "alexandrite",\r
+    "amethyst",\r
+    "carnelian",\r
+    "diamond",\r
+    "emerald",\r
+    "granite",\r
+    "jade",\r
+    "kryptonite",\r
+    "lapus lazuli",\r
+    "moonstone",\r
+    "obsidian",\r
+    "onyx",\r
+    "opal",\r
+    "pearl",\r
+    "ruby",\r
+    "saphire",\r
+    "tiger eye",\r
+    "topaz",\r
+    "turquoise",\r
+};\r
+\r
+#define NSTONES (sizeof stones / sizeof (char *))\r
+const int cNSTONES = NSTONES;\r
+\r
+char *wood[] = {\r
+    "avocado wood",\r
+    "balsa",\r
+    "banyan",\r
+    "birch",\r
+    "cedar",\r
+    "cherry",\r
+    "cinnibar",\r
+    "driftwood",\r
+    "ebony",\r
+    "eucalyptus",\r
+    "hemlock",\r
+    "ironwood",\r
+    "mahogany",\r
+    "manzanita",\r
+    "maple",\r
+    "oak",\r
+    "persimmon wood",\r
+    "redwood",\r
+    "rosewood",\r
+    "teak",\r
+    "walnut",\r
+    "zebra wood",\r
+};\r
+\r
+#define NWOOD (sizeof wood / sizeof (char *))\r
+const int cNWOOD = NWOOD;\r
+\r
+char *metal[] = {\r
+    "aluminium",\r
+    "bone",\r
+    "brass",\r
+    "bronze",\r
+    "copper",\r
+    "iron",\r
+    "lead",\r
+    "pewter",\r
+    "steel",\r
+    "tin",\r
+    "zinc",\r
+};\r
+\r
+#define NMETAL (sizeof metal / sizeof (char *))\r
+const int cNMETAL = NMETAL;\r
+\r
+struct magic_item things[NUMTHINGS] = {\r
+    { "",                      27 },   /* potion */\r
+    { "",                      27 },   /* scroll */\r
+    { "",                      18 },   /* food */\r
+    { "",                       9 },   /* weapon */\r
+    { "",                       9 },   /* armor */\r
+    { "",                       5 },   /* ring */\r
+    { "",                       5 },   /* stick */\r
+};\r
+\r
+struct magic_item s_magic[MAXSCROLLS] = {\r
+    { "monster confusion",      8, 170 },\r
+    { "magic mapping",          5, 180 },\r
+    { "light",                 10, 100 },\r
+    { "hold monster",           2, 200 },\r
+    { "sleep",                  5,  50 },\r
+    { "enchant armor",          8, 130 },\r
+    { "identify",              21, 100 },\r
+    { "scare monster",          4, 180 },\r
+    { "gold detection",                 4, 110 },\r
+    { "teleportation",          7, 175 },\r
+    { "enchant weapon",                10, 150 },\r
+    { "create monster",                 5,  75 },\r
+    { "remove curse",           8, 105 },\r
+    { "aggravate monsters",     1,  60 },\r
+    { "blank paper",            1,  50 },\r
+    { "genocide",               1, 200 },\r
+};\r
+\r
+struct magic_item p_magic[MAXPOTIONS] = {\r
+    { "confusion",              8,  50 },\r
+    { "paralysis",             10,  50 },\r
+    { "poison",                         8,  50 },\r
+    { "gain strength",         15, 150 },\r
+    { "see invisible",          2, 170 },\r
+    { "healing",               15, 130 },\r
+    { "monster detection",      6, 120 },\r
+    { "magic detection",        6, 105 },\r
+    { "raise level",            2, 220 },\r
+    { "extra healing",          5, 180 },\r
+    { "haste self",             4, 200 },\r
+    { "restore strength",      14, 120 },\r
+    { "blindness",              4,  50 },\r
+    { "thirst quenching",       1,  50 },\r
+};\r
+\r
+struct magic_item r_magic[MAXRINGS] = {\r
+    { "protection",             9, 200 },\r
+    { "add strength",           9, 200 },\r
+    { "sustain strength",       5, 180 },\r
+    { "searching",             10, 200 },\r
+    { "see invisible",         10, 175 },\r
+    { "adornment",              1, 100 },\r
+    { "aggravate monster",     11, 100 },\r
+    { "dexterity",              8, 220 },\r
+    { "increase damage",        8, 220 },\r
+    { "regeneration",           4, 260 },\r
+    { "slow digestion",                 9, 240 },\r
+    { "teleportation",          9, 100 },\r
+    { "stealth",                7, 100 },\r
+};\r
+\r
+struct magic_item ws_magic[MAXSTICKS] = {\r
+    { "light",                 12, 120 },\r
+    { "striking",               9, 115 },\r
+    { "lightning",              3, 200 },\r
+    { "fire",                   3, 200 },\r
+    { "cold",                   3, 200 },\r
+    { "polymorph",             15, 210 },\r
+    { "magic missile",         10, 170 },\r
+    { "haste monster",          9,  50 },\r
+    { "slow monster",          11, 220 },\r
+    { "drain life",             9, 210 },\r
+    { "nothing",                1,  70 },\r
+    { "teleport away",          5, 140 },\r
+    { "teleport to",            5,  60 },\r
+    { "cancellation",           5, 130 },\r
+};\r
+\r
+int a_class[MAXARMORS] = {\r
+    8,\r
+    7,\r
+    7,\r
+    6,\r
+    5,\r
+    4,\r
+    4,\r
+    3,\r
+};\r
+\r
+char *a_names[MAXARMORS] = {\r
+    "leather armor",\r
+    "ring mail",\r
+    "studded leather armor",\r
+    "scale mail",\r
+    "chain mail",\r
+    "splint mail",\r
+    "banded mail",\r
+    "plate mail",\r
+};\r
+\r
+int a_chances[MAXARMORS] = {\r
+    20,\r
+    35,\r
+    50,\r
+    63,\r
+    75,\r
+    85,\r
+    95,\r
+    100\r
+};\r
+\r
+#define MAX3(a,b,c)     (a > b ? (a > c ? a : c) : (b > c ? b : c))\r
+static bool used[MAX3(NCOLORS, NSTONES, NWOOD)];\r
+\r
+/*\r
+ * init_things\r
+ *     Initialize the probabilities for types of things\r
+ */\r
+init_things()\r
+{\r
+    register struct magic_item *mp;\r
+\r
+    for (mp = &things[1]; mp <= &things[NUMTHINGS-1]; mp++)\r
+       mp->mi_prob += (mp-1)->mi_prob;\r
+    badcheck("things", things, NUMTHINGS);\r
+}\r
+\r
+/*\r
+ * init_colors:\r
+ *     Initialize the potion color scheme for this time\r
+ */\r
+\r
+init_colors()\r
+{\r
+    register int i, j;\r
+\r
+    for (i = 0; i < NCOLORS; i++)\r
+       used[i] = 0;\r
+    for (i = 0; i < MAXPOTIONS; i++)\r
+    {\r
+       do\r
+           j = rnd(NCOLORS);\r
+       until (!used[j]);\r
+       used[j] = TRUE;\r
+       p_colors[i] = rainbow[j];\r
+       p_know[i] = FALSE;\r
+       p_guess[i] = NULL;\r
+       if (i > 0)\r
+               p_magic[i].mi_prob += p_magic[i-1].mi_prob;\r
+    }\r
+    badcheck("potions", p_magic, MAXPOTIONS);\r
+}\r
+\r
+/*\r
+ * init_names:\r
+ *     Generate the names of the various scrolls\r
+ */\r
+\r
+init_names()\r
+{\r
+    register int nsyl;\r
+    register char *cp, *sp;\r
+    register int i, nwords;\r
+\r
+    for (i = 0; i < MAXSCROLLS; i++)\r
+    {\r
+       cp = prbuf;\r
+       nwords = rnd(4)+2;\r
+       while(nwords--)\r
+       {\r
+           nsyl = rnd(3)+1;\r
+           while(nsyl--)\r
+           {\r
+               sp = sylls[rnd((sizeof sylls) / (sizeof (char *)))];\r
+               while(*sp)\r
+                   *cp++ = *sp++;\r
+           }\r
+           *cp++ = ' ';\r
+       }\r
+       *--cp = '\0';\r
+       s_names[i] = (char *) new(strlen(prbuf)+1);\r
+       s_know[i] = FALSE;\r
+       s_guess[i] = NULL;\r
+       strcpy(s_names[i], prbuf);\r
+       if (i > 0)\r
+               s_magic[i].mi_prob += s_magic[i-1].mi_prob;\r
+    }\r
+    badcheck("scrolls", s_magic, MAXSCROLLS);\r
+}\r
+\r
+/*\r
+ * init_stones:\r
+ *     Initialize the ring stone setting scheme for this time\r
+ */\r
+\r
+init_stones()\r
+{\r
+    register int i, j;\r
+\r
+    for (i = 0; i < NSTONES; i++)\r
+       used[i] = FALSE;\r
+    for (i = 0; i < MAXRINGS; i++)\r
+    {\r
+       do\r
+           j = rnd(NSTONES);\r
+       until (!used[j]);\r
+       used[j] = TRUE;\r
+       r_stones[i] = stones[j];\r
+       r_know[i] = FALSE;\r
+       r_guess[i] = NULL;\r
+       if (i > 0)\r
+               r_magic[i].mi_prob += r_magic[i-1].mi_prob;\r
+    }\r
+    badcheck("rings", r_magic, MAXRINGS);\r
+}\r
+\r
+/*\r
+ * init_materials:\r
+ *     Initialize the construction materials for wands and staffs\r
+ */\r
+\r
+init_materials()\r
+{\r
+    register int i, j;\r
+    static bool metused[NMETAL];\r
+\r
+    for (i = 0; i < NWOOD; i++)\r
+       used[i] = FALSE;\r
+    for (i = 0; i < NMETAL; i++)\r
+       metused[i] = FALSE;\r
+\r
+    for (i = 0; i < MAXSTICKS; i++)\r
+    {\r
+       for (;;)\r
+           if (rnd(100) > 50)\r
+           {\r
+               j = rnd(NMETAL);\r
+               if (!metused[j])\r
+               {\r
+                   metused[j] = TRUE;\r
+                   ws_made[i] = metal[j];\r
+                   ws_type[i] = "wand";\r
+                   break;\r
+               }\r
+           }\r
+           else\r
+           {\r
+               j = rnd(NWOOD);\r
+               if (!used[j])\r
+               {\r
+                   used[j] = TRUE;\r
+                   ws_made[i] = wood[j];\r
+                   ws_type[i] = "staff";\r
+                   break;\r
+               }\r
+           }\r
+\r
+       ws_know[i] = FALSE;\r
+       ws_guess[i] = NULL;\r
+       if (i > 0)\r
+               ws_magic[i].mi_prob += ws_magic[i-1].mi_prob;\r
+    }\r
+    badcheck("sticks", ws_magic, MAXSTICKS);\r
+}\r
+\r
+badcheck(name, magic, bound)\r
+char *name;\r
+register struct magic_item *magic;\r
+register int bound;\r
+{\r
+    register struct magic_item *end;\r
+\r
+    if (magic[bound - 1].mi_prob == 100)\r
+       return;\r
+    printf("\nBad percentages for %s:\n", name);\r
+    for (end = &magic[bound]; magic < end; magic++)\r
+       printf("%3d%% %s\n", magic->mi_prob, magic->mi_name);\r
+    printf("[hit RETURN to continue]");\r
+    fflush(stdout);\r
+    while (getchar() != '\n')\r
+       continue;\r
+}\r
+\r
+struct h_list helpstr[] = {\r
+    '?',       "       prints help",\r
+    '/',       "       identify object",\r
+    'h',       "       left",\r
+    'j',       "       down",\r
+    'k',       "       up",\r
+    'l',       "       right",\r
+    'y',       "       up & left",\r
+    'u',       "       up & right",\r
+    'b',       "       down & left",\r
+    'n',       "       down & right",\r
+    'H',       "       run left",\r
+    'J',       "       run down",\r
+    'K',       "       run up",\r
+    'L',       "       run right",\r
+    'Y',       "       run up & left",\r
+    'U',       "       run up & right",\r
+    'B',       "       run down & left",\r
+    'N',       "       run down & right",\r
+    't',       "<dir>  throw something",\r
+    'f',       "<dir>  forward until find something",\r
+    'p',       "<dir>  zap a wand in a direction",\r
+    'z',       "       zap a wand or staff",\r
+    '>',       "       go down a staircase",\r
+    's',       "       search for trap/secret door",\r
+    ' ',       "       (space) rest for a while",\r
+    'i',       "       inventory",\r
+    'I',       "       inventory single item",\r
+    'q',       "       quaff potion",\r
+    'r',       "       read paper",\r
+    'e',       "       eat food",\r
+    'w',       "       wield a weapon",\r
+    'W',       "       wear armor",\r
+    'T',       "       take armor off",\r
+    'P',       "       put on ring",\r
+    'R',       "       remove ring",\r
+    'd',       "       drop object",\r
+    'c',       "       call object",\r
+    'o',       "       examine/set options",\r
+    CTRL('L'), "       redraw screen",\r
+    CTRL('R'), "       repeat last message",\r
+    ESCAPE,    "       cancel command",\r
+    'v',       "       print program version number",\r
+    '!',       "       shell escape",\r
+    'S',       "       save game",\r
+    'Q',       "       quit",\r
+    0, 0\r
+};\r
diff --git a/io.c b/io.c
new file mode 100644 (file)
index 0000000..dbc7481
--- /dev/null
+++ b/io.c
@@ -0,0 +1,241 @@
+/*\r
+ * Various input/output functions\r
+ *\r
+ * @(#)io.c    3.10 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <ctype.h>\r
+#include <stdarg.h>\r
+#include <string.h>\r
+#include "rogue.h"\r
+\r
+/*\r
+ * msg:\r
+ *     Display a message at the top of the screen.\r
+ */\r
+\r
+static char msgbuf[BUFSIZ];\r
+static int newpos = 0;\r
+\r
+/*VARARGS1*/\r
+msg(char *fmt, ...)\r
+{\r
+    va_list ap;\r
+    /*\r
+     * if the string is "", just clear the line\r
+     */\r
+    if (*fmt == '\0')\r
+    {\r
+       wmove(cw, 0, 0);\r
+       wclrtoeol(cw);\r
+       mpos = 0;\r
+       return;\r
+    }\r
+    /*\r
+     * otherwise add to the message and flush it out\r
+     */\r
+    va_start(ap, fmt);\r
+    doadd(fmt, ap);\r
+    va_end(ap);\r
+    endmsg();\r
+}\r
+\r
+/*\r
+ * add things to the current message\r
+ */\r
+addmsg(char *fmt, ...)\r
+{\r
+    va_list ap;\r
+\r
+    va_start(ap, fmt);\r
+    doadd(fmt, ap);\r
+    va_end(ap);\r
+}\r
+\r
+/*\r
+ * Display a new msg (giving him a chance to see the previous one if it\r
+ * is up there with the --More--)\r
+ */\r
+endmsg()\r
+{\r
+    strncpy(huh, msgbuf, 80);\r
+    huh[79] = 0;\r
+\r
+    if (mpos)\r
+    {\r
+       wmove(cw, 0, mpos);\r
+       waddstr(cw, "--More--");\r
+       draw(cw);\r
+       wait_for(cw,' ');\r
+    }\r
+    mvwaddstr(cw, 0, 0, msgbuf);\r
+    wclrtoeol(cw);\r
+    mpos = newpos;\r
+    newpos = 0;\r
+    draw(cw);\r
+}\r
+\r
+doadd(char *fmt, va_list ap)\r
+{\r
+    vsprintf(&msgbuf[newpos], fmt, ap);\r
+    newpos = (int) strlen(msgbuf);\r
+}\r
+\r
+/*\r
+ * step_ok:\r
+ *     returns true if it is ok to step on ch\r
+ */\r
+\r
+step_ok(ch)\r
+{\r
+    switch (ch)\r
+    {\r
+       case ' ':\r
+       case '|':\r
+       case '-':\r
+       case SECRETDOOR:\r
+           return FALSE;\r
+       default:\r
+           return (!isalpha(ch));\r
+    }\r
+}\r
+\r
+/*\r
+ * readchar:\r
+ *     flushes stdout so that screen is up to date and then returns\r
+ *     getchar.\r
+ */\r
+\r
+readchar(win)\r
+WINDOW *win;\r
+{\r
+    int ch;\r
+\r
+    ch = md_readchar(win);\r
+\r
+    if ((ch == 3) || (ch == 0))\r
+    {\r
+       quit(0);\r
+        return(27);\r
+    }\r
+\r
+    return(ch);\r
+}\r
+\r
+/*\r
+ * status:\r
+ *     Display the important stats line.  Keep the cursor where it was.\r
+ */\r
+\r
+status()\r
+{\r
+    register int oy, ox, temp;\r
+    register char *pb;\r
+    static char buf[80];\r
+    static int hpwidth = 0, s_hungry = -1;\r
+    static int s_lvl = -1, s_pur, s_hp = -1, s_str, s_add, s_ac = 0;\r
+    static long s_exp = 0;\r
+\r
+    /*\r
+     * If nothing has changed since the last status, don't\r
+     * bother.\r
+     */\r
+    if (s_hp == pstats.s_hpt && s_exp == pstats.s_exp && s_pur == purse\r
+       && s_ac == (cur_armor != NULL ? cur_armor->o_ac : pstats.s_arm)\r
+       && s_str == pstats.s_str.st_str && s_add == pstats.s_str.st_add\r
+       && s_lvl == level && s_hungry == hungry_state)\r
+           return;\r
+       \r
+    getyx(cw, oy, ox);\r
+    if (s_hp != max_hp)\r
+    {\r
+       temp = s_hp = max_hp;\r
+       for (hpwidth = 0; temp; hpwidth++)\r
+           temp /= 10;\r
+    }\r
+    sprintf(buf, "Level: %d  Gold: %-5d  Hp: %*d(%*d)  Str: %-2d",\r
+       level, purse, hpwidth, pstats.s_hpt, hpwidth, max_hp,\r
+       pstats.s_str.st_str);\r
+    if (pstats.s_str.st_add != 0)\r
+    {\r
+       pb = &buf[strlen(buf)];\r
+       sprintf(pb, "/%d", pstats.s_str.st_add);\r
+    }\r
+    pb = &buf[strlen(buf)];\r
+    sprintf(pb, "  Ac: %-2d  Exp: %d/%ld",\r
+       cur_armor != NULL ? cur_armor->o_ac : pstats.s_arm, pstats.s_lvl,\r
+       pstats.s_exp);\r
+    /*\r
+     * Save old status\r
+     */\r
+    s_lvl = level;\r
+    s_pur = purse;\r
+    s_hp = pstats.s_hpt;\r
+    s_str = pstats.s_str.st_str;\r
+    s_add = pstats.s_str.st_add;\r
+    s_exp = pstats.s_exp; \r
+    s_ac = (cur_armor != NULL ? cur_armor->o_ac : pstats.s_arm);\r
+    mvwaddstr(cw, LINES - 1, 0, buf);\r
+    switch (hungry_state)\r
+    {\r
+       case 0: ;\r
+       when 1:\r
+           waddstr(cw, "  Hungry");\r
+       when 2:\r
+           waddstr(cw, "  Weak");\r
+       when 3:\r
+           waddstr(cw, "  Fainting");\r
+    }\r
+    wclrtoeol(cw);\r
+    s_hungry = hungry_state;\r
+    wmove(cw, oy, ox);\r
+}\r
+\r
+/*\r
+ * wait_for\r
+ *     Sit around until the guy types the right key\r
+ */\r
+\r
+wait_for(win, ch)\r
+WINDOW *win;\r
+register char ch;\r
+{\r
+    register char c;\r
+\r
+    if (ch == '\n')\r
+        while ((c = readchar(win)) != '\n' && c != '\r')\r
+           continue;\r
+    else\r
+        while (readchar(win) != ch)\r
+           continue;\r
+}\r
+\r
+/*\r
+ * show_win:\r
+ *     function used to display a window and wait before returning\r
+ */\r
+\r
+show_win(scr, message)\r
+register WINDOW *scr;\r
+char *message;\r
+{\r
+    mvwaddstr(scr, 0, 0, message);\r
+    touchwin(scr);\r
+    wmove(scr, hero.y, hero.x);\r
+    draw(scr);\r
+    wait_for(scr,' ');\r
+    clearok(cw, TRUE);\r
+    touchwin(cw);\r
+}\r
+\r
+flush_type()\r
+{\r
+       flushinp();\r
+}\r
diff --git a/list.c b/list.c
new file mode 100644 (file)
index 0000000..0b710d2
--- /dev/null
+++ b/list.c
@@ -0,0 +1,121 @@
+/*\r
+ * Functions for dealing with linked lists of goodies\r
+ *\r
+ * @(#)list.c  3.3 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include "rogue.h"\r
+\r
+/*\r
+ * detach:\r
+ *     Takes an item out of whatever linked list it might be in\r
+ */\r
+\r
+_detach(list, item)\r
+register struct linked_list **list, *item;\r
+{\r
+    if (*list == item)\r
+       *list = next(item);\r
+    if (prev(item) != NULL) item->l_prev->l_next = next(item);\r
+    if (next(item) != NULL) item->l_next->l_prev = prev(item);\r
+    item->l_next = NULL;\r
+    item->l_prev = NULL;\r
+}\r
+\r
+/*\r
+ * _attach:\r
+ *     add an item to the head of a list\r
+ */\r
+\r
+_attach(list, item)\r
+register struct linked_list **list, *item;\r
+{\r
+    if (*list != NULL)\r
+    {\r
+       item->l_next = *list;\r
+       (*list)->l_prev = item;\r
+       item->l_prev = NULL;\r
+    }\r
+    else\r
+    {\r
+       item->l_next = NULL;\r
+       item->l_prev = NULL;\r
+    }\r
+\r
+    *list = item;\r
+}\r
+\r
+/*\r
+ * _free_list:\r
+ *     Throw the whole blamed thing away\r
+ */\r
+\r
+_free_list(ptr)\r
+register struct linked_list **ptr;\r
+{\r
+    register struct linked_list *item;\r
+\r
+    while (*ptr != NULL)\r
+    {\r
+       item = *ptr;\r
+       *ptr = next(item);\r
+       discard(item);\r
+    }\r
+}\r
+\r
+/*\r
+ * discard:\r
+ *     free up an item\r
+ */\r
+\r
+discard(item)\r
+register struct linked_list *item;\r
+{\r
+    total -= 2;\r
+    FREE(item->l_data);\r
+    FREE(item);\r
+}\r
+\r
+/*\r
+ * new_item\r
+ *     get a new item with a specified size\r
+ */\r
+\r
+struct linked_list *\r
+new_item(size)\r
+int size;\r
+{\r
+    register struct linked_list *item;\r
+\r
+    if ((item = (struct linked_list *) new(sizeof *item)) == NULL)\r
+       msg("Ran out of memory for header after %d items", total);\r
+    if ((item->l_data = new(size)) == NULL)\r
+       msg("Ran out of memory for data after %d items", total);\r
+    item->l_next = item->l_prev = NULL;\r
+    memset(item->l_data,0,size);\r
+    return item;\r
+}\r
+\r
+char *\r
+new(size)\r
+int size;\r
+{\r
+    register char *space = ALLOC(size);\r
+\r
+    if (space == NULL)\r
+    {\r
+       sprintf(prbuf, "Rogue ran out of memory (%d).  Fatal error!", md_memused());\r
+        fatal(prbuf);\r
+    }\r
+    total++;\r
+    return space;\r
+}\r
diff --git a/machdep.h b/machdep.h
new file mode 100644 (file)
index 0000000..45b072a
--- /dev/null
+++ b/machdep.h
@@ -0,0 +1,55 @@
+/*\r
+ * machine dependicies\r
+ *\r
+ * %G% (Berkeley) %W%\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+/*\r
+ * where scorefile should live\r
+ */\r
+\r
+#include <limits.h>\r
+#include <stdlib.h>\r
+\r
+/*\r
+ * Variables for checking to make sure the system isn't too loaded\r
+ * for people to play\r
+ */\r
+\r
+#define AUTHORUID        0\r
+#define        MAXUSERS        25      /* max number of users for this game */\r
+#define        MAXLOAD         40      /* 10 * max 15 minute load average */\r
+#define        CHECKTIME       15      /* number of minutes between load checks */\r
+\r
+#ifndef PATH_MAX\r
+#define PATH_MAX _MAX_PATH\r
+#endif\r
+\r
+#ifdef _WIN32\r
+#define fstat _fstat\r
+#define stat _stat\r
+#define open _open\r
+#define getpid _getpid\r
+#define fdopen _fdopen\r
+#define unlink _unlink\r
+#ifndef __MINGW32__\r
+#define fileno _fileno\r
+#endif\r
+#endif\r
+\r
+extern char *md_getusername();\r
+extern char *md_gethomedir();\r
+extern void md_flushinp();\r
+extern char *md_getshell();\r
+extern char *md_gethostname();\r
+extern void md_dobinaryio();\r
+extern char *md_getpass();\r
+extern void md_init();\r
+extern char *xcrypt();\r
+extern char *md_getroguedir();\r
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..32fdbd0
--- /dev/null
+++ b/main.c
@@ -0,0 +1,445 @@
+/*\r
+ * @(#)main.c  3.27 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <time.h>\r
+#include <signal.h>\r
+#include <limits.h>\r
+#include <stdlib.h>\r
+#include <stdarg.h>\r
+#include <string.h>\r
+#include "machdep.h"\r
+#include "rogue.h"\r
+\r
+int num_checks;                        /* times we've gone over in checkout() */\r
+WINDOW *cw;                              /* Window that the player sees */\r
+WINDOW *hw;                              /* Used for the help command */\r
+WINDOW *mw;                              /* Used to store mosnters */\r
+\r
+main(argc, argv, envp)\r
+char **argv;\r
+char **envp;\r
+{\r
+    register char *env;\r
+    register struct linked_list *item;\r
+    register struct object *obj;\r
+    int lowtime;\r
+    time_t now;\r
+\r
+    md_init();\r
+\r
+    /*\r
+     * check for print-score option\r
+     */\r
+    if (argc == 2 && strcmp(argv[1], "-s") == 0)\r
+    {\r
+       waswizard = TRUE;\r
+       score(0, -1, 0);\r
+       exit(0);\r
+    }\r
+    /*\r
+     * Check to see if he is a wizard\r
+     */\r
+    if (argc >= 2 && argv[1][0] == '\0')\r
+       if (strcmp(PASSWD, xcrypt(md_getpass("Wizard's password: "), "mT")) == 0)\r
+       {\r
+           wizard = TRUE;\r
+           argv++;\r
+           argc--;\r
+       }\r
+\r
+    /*\r
+     * get home and options from environment\r
+     */\r
+    strncpy(home, md_gethomedir(), PATH_MAX);\r
+\r
+    strcpy(file_name, home);\r
+    strcat(file_name, "rogue36.sav");\r
+\r
+    if ((env = getenv("ROGUEOPTS")) != NULL)\r
+       parse_opts(env);\r
+    if (env == NULL || whoami[0] == '\0')\r
+       strucpy(whoami, md_getusername(md_getuid()), strlen(md_getusername(md_getuid())));\r
+    if (env == NULL || fruit[0] == '\0')\r
+       strcpy(fruit, "slime-mold");\r
+\r
+    if (too_much() && !wizard && !author())\r
+    {\r
+       printf("Sorry, %s, but the system is too loaded now.\n", whoami);\r
+       printf("Try again later.  Meanwhile, why not enjoy a%s %s?\n",\r
+           vowelstr(fruit), fruit);\r
+       exit(1);\r
+    }\r
+\r
+    if (argc == 2)\r
+       if (!restore(argv[1], envp)) /* Note: restore will never return */\r
+           exit(1);\r
+\r
+    time(&now);\r
+    lowtime = (int) now;\r
+    dnum = (wizard && getenv("SEED") != NULL ?\r
+       atoi(getenv("SEED")) :\r
+       lowtime + getpid());\r
+    if (wizard)\r
+       printf("Hello %s, welcome to dungeon #%d", whoami, dnum);\r
+    else\r
+       printf("Hello %s, just a moment while I dig the dungeon...", whoami);\r
+    fflush(stdout);\r
+    seed = dnum;\r
+    init_player();                     /* Roll up the rogue */\r
+    init_things();                     /* Set up probabilities of things */\r
+    init_names();                      /* Set up names of scrolls */\r
+    init_colors();                     /* Set up colors of potions */\r
+    init_stones();                     /* Set up stone settings of rings */\r
+    init_materials();                  /* Set up materials of wands */\r
+    initscr();                         /* Start up cursor package */\r
+\r
+    if (COLS < 70)\r
+    {\r
+       endwin();\r
+       printf("\n\nSorry, %s, but your terminal window has too few columns.\n", whoami);\r
+       printf("Your terminal has %d columns, needs 70.\n",COLS);\r
+       exit(1);\r
+    }\r
+    if (LINES < 22)\r
+    {\r
+       endwin();\r
+       printf("\n\nSorry, %s, but your terminal window has too few lines.\n", whoami);\r
+       printf("Your terminal has %d lines, needs 22.\n",LINES);\r
+       exit(1);\r
+    }\r
+    \r
+\r
+    setup();\r
+    /*\r
+     * Set up windows\r
+     */\r
+    cw = newwin(LINES, COLS, 0, 0);\r
+    mw = newwin(LINES, COLS, 0, 0);\r
+    hw = newwin(LINES, COLS, 0, 0);\r
+    keypad(cw,1);\r
+    waswizard = wizard;\r
+    new_level();                       /* Draw current level */\r
+    /*\r
+     * Start up daemons and fuses\r
+     */\r
+    start_daemon(doctor, 0, AFTER);\r
+    fuse(swander, 0, WANDERTIME, AFTER);\r
+    start_daemon(stomach, 0, AFTER);\r
+    start_daemon(runners, 0, AFTER);\r
+    /*\r
+     * Give the rogue his weaponry.  First a mace.\r
+     */\r
+    item = new_item(sizeof *obj);\r
+    obj = (struct object *) ldata(item);\r
+    obj->o_type = WEAPON;\r
+    obj->o_which = MACE;\r
+    init_weapon(obj, MACE);\r
+    obj->o_hplus = 1;\r
+    obj->o_dplus = 1;\r
+    obj->o_flags |= ISKNOW;\r
+    add_pack(item, TRUE);\r
+    cur_weapon = obj;\r
+    /*\r
+     * Now a +1 bow\r
+     */\r
+    item = new_item(sizeof *obj);\r
+    obj = (struct object *) ldata(item);\r
+    obj->o_type = WEAPON;\r
+    obj->o_which = BOW;\r
+    init_weapon(obj, BOW);\r
+    obj->o_hplus = 1;\r
+    obj->o_dplus = 0;\r
+    obj->o_flags |= ISKNOW;\r
+    add_pack(item, TRUE);\r
+    /*\r
+     * Now some arrows\r
+     */\r
+    item = new_item(sizeof *obj);\r
+    obj = (struct object *) ldata(item);\r
+    obj->o_type = WEAPON;\r
+    obj->o_which = ARROW;\r
+    init_weapon(obj, ARROW);\r
+    obj->o_count = 25+rnd(15);\r
+    obj->o_hplus = obj->o_dplus = 0;\r
+    obj->o_flags |= ISKNOW;\r
+    add_pack(item, TRUE);\r
+    /*\r
+     * And his suit of armor\r
+     */\r
+    item = new_item(sizeof *obj);\r
+    obj = (struct object *) ldata(item);\r
+    obj->o_type = ARMOR;\r
+    obj->o_which = RING_MAIL;\r
+    obj->o_ac = a_class[RING_MAIL] - 1;\r
+    obj->o_flags |= ISKNOW;\r
+    cur_armor = obj;\r
+    add_pack(item, TRUE);\r
+    /*\r
+     * Give him some food too\r
+     */\r
+    item = new_item(sizeof *obj);\r
+    obj = (struct object *) ldata(item);\r
+    obj->o_type = FOOD;\r
+    obj->o_count = 1;\r
+    obj->o_which = 0;\r
+    add_pack(item, TRUE);\r
+    playit();\r
+}\r
+\r
+/*\r
+ * endit:\r
+ *     Exit the program abnormally.\r
+ */\r
+\r
+void\r
+endit(int p)\r
+{\r
+    fatal("Ok, if you want to exit that badly, I'll have to allow it\n");\r
+}\r
+\r
+/*\r
+ * fatal:\r
+ *     Exit the program, printing a message.\r
+ */\r
+\r
+fatal(s)\r
+char *s;\r
+{\r
+    clear();\r
+    move(LINES-2, 0);\r
+    printw("%s", s);\r
+    draw(stdscr);\r
+    endwin();\r
+    exit(0);\r
+}\r
+\r
+/*\r
+ * rnd:\r
+ *     Pick a very random number.\r
+ */\r
+\r
+rnd(range)\r
+register int range;\r
+{\r
+    return range == 0 ? 0 : abs(RN) % range;\r
+}\r
+\r
+/*\r
+ * roll:\r
+ *     roll a number of dice\r
+ */\r
+\r
+roll(number, sides)\r
+register int number, sides;\r
+{\r
+    register int dtotal = 0;\r
+\r
+    while(number--)\r
+       dtotal += rnd(sides)+1;\r
+    return dtotal;\r
+}\r
+/*\r
+ * handle stop and start signals\r
+ */\r
+\r
+void\r
+tstp(int p)\r
+{\r
+#ifdef SIGTSTP\r
+    signal(SIGTSTP, SIG_IGN);\r
+#endif\r
+    mvcur(0, COLS - 1, LINES - 1, 0);\r
+    endwin();\r
+    fflush(stdout);\r
+#ifdef SIGTSTP\r
+    signal(SIGTSTP, SIG_DFL);\r
+    kill(0, SIGTSTP);\r
+    signal(SIGTSTP, tstp);\r
+#endif\r
+    crmode();\r
+    noecho();\r
+    clearok(curscr, TRUE);\r
+    touchwin(cw);\r
+    draw(cw);\r
+    flush_type();      /* flush input */\r
+}\r
+\r
+setup()\r
+{\r
+#ifdef SIGHUP\r
+    signal(SIGHUP, auto_save);\r
+#endif\r
+    signal(SIGILL, auto_save);\r
+#ifdef SIGTRAP\r
+    signal(SIGTRAP, auto_save);\r
+#endif\r
+#ifdef SIGIOT\r
+    signal(SIGIOT, auto_save);\r
+#endif\r
+#ifdef SIGEMT\r
+    signal(SIGEMT, auto_save);\r
+#endif\r
+    signal(SIGFPE, auto_save);\r
+#ifdef SIGBUS\r
+    signal(SIGBUS, auto_save);\r
+#endif\r
+    signal(SIGSEGV, auto_save);\r
+#ifdef SIGSYS\r
+    signal(SIGSYS, auto_save);\r
+#endif\r
+#ifdef SIGPIPE\r
+    signal(SIGPIPE, auto_save);\r
+#endif\r
+    signal(SIGTERM, auto_save);\r
+    signal(SIGINT, quit);\r
+#ifdef SIGQUIT\r
+    signal(SIGQUIT, endit);\r
+#endif\r
+#ifdef SIGTSTP\r
+    signal(SIGTSTP, tstp);\r
+#endif\r
+\r
+    if (!author())\r
+    {\r
+#ifdef SIGALRM\r
+       signal(SIGALRM, checkout);\r
+       alarm(CHECKTIME * 60);\r
+#endif\r
+       num_checks = 0;\r
+    }\r
+\r
+    crmode();                          /* Cbreak mode */\r
+    noecho();                          /* Echo off */\r
+}\r
+\r
+/*\r
+ * playit:\r
+ *     The main loop of the program.  Loop until the game is over,\r
+ * refreshing things and looking at the proper times.\r
+ */\r
+\r
+playit()\r
+{\r
+    register char *opts;\r
+\r
+    /*\r
+     * set up defaults for slow terminals\r
+     */\r
+\r
+\r
+    if (baudrate() < 1200)\r
+    {\r
+       terse = TRUE;\r
+       jump = TRUE;\r
+    }\r
+\r
+    /*\r
+     * parse environment declaration of options\r
+     */\r
+    if ((opts = getenv("ROGUEOPTS")) != NULL)\r
+       parse_opts(opts);\r
+\r
+\r
+    oldpos = hero;\r
+    oldrp = roomin(&hero);\r
+    while (playing)\r
+       command();                      /* Command execution */\r
+    endit(-1);\r
+}\r
+\r
+/*\r
+ * see if the system is being used too much for this game\r
+ */\r
+too_much()\r
+{\r
+    double avec[3];\r
+\r
+    if (md_getloadavg(avec) == 0)\r
+       return (avec[2] > (MAXLOAD / 10.0));\r
+    else\r
+        return (md_ucount() > MAXUSERS);\r
+}\r
+\r
+/*\r
+ * see if a user is an author of the program\r
+ */\r
+author()\r
+{\r
+    switch (md_getuid())\r
+    {\r
+       case AUTHORUID:\r
+           return TRUE;\r
+       default:\r
+           return FALSE;\r
+    }\r
+}\r
+\r
+int chmsg(char *fmt, ...);\r
+\r
+void\r
+checkout(int p)\r
+{\r
+    static char *msgs[] = {\r
+       "The load is too high to be playing.  Please leave in %d minutes",\r
+       "Please save your game.  You have %d minutes",\r
+       "Last warning.  You have %d minutes to leave",\r
+    };\r
+    int checktime;\r
+#ifdef SIGALRM\r
+    signal(SIGALRM, checkout);\r
+#endif\r
+    if (too_much())\r
+    {\r
+       if (num_checks == 3)\r
+           fatal("Sorry.  You took to long.  You are dead\n");\r
+       checktime = CHECKTIME / (num_checks + 1);\r
+       chmsg(msgs[num_checks++], checktime);\r
+#ifdef SIGALRM\r
+       alarm(checktime * 60);\r
+#endif\r
+    }\r
+    else\r
+    {\r
+       if (num_checks)\r
+       {\r
+           chmsg("The load has dropped back down.  You have a reprieve.");\r
+           num_checks = 0;\r
+       }\r
+#ifdef SIGALRM\r
+       alarm(CHECKTIME * 60);\r
+#endif\r
+    }\r
+}\r
+\r
+/*\r
+ * checkout()'s version of msg.  If we are in the middle of a shell, do a\r
+ * printf instead of a msg to avoid the refresh.\r
+ */\r
+chmsg(char *fmt, ...)\r
+{\r
+    va_list args;\r
+\r
+    if (in_shell)\r
+    {\r
+       va_start(args, fmt);\r
+       vprintf(fmt, args);\r
+       va_end(args);\r
+       putchar('\n');\r
+       fflush(stdout);\r
+    }\r
+    else\r
+    {\r
+        va_start(args, fmt);\r
+        doadd(fmt, args);\r
+        va_end(args);\r
+       endmsg();\r
+    }\r
+}\r
diff --git a/mdport.c b/mdport.c
new file mode 100644 (file)
index 0000000..eb33c32
--- /dev/null
+++ b/mdport.c
@@ -0,0 +1,1250 @@
+/*\r
+    mdport.c - Machine Dependent Code for Porting Unix/Curses games\r
+\r
+    Copyright (C) 2005 Nicholas J. Kisseberth\r
+    All rights reserved.\r
+\r
+    Redistribution and use in source and binary forms, with or without\r
+    modification, are permitted provided that the following conditions\r
+    are met:\r
+    1. Redistributions of source code must retain the above copyright\r
+       notice, this list of conditions and the following disclaimer.\r
+    2. Redistributions in binary form must reproduce the above copyright\r
+       notice, this list of conditions and the following disclaimer in the\r
+       documentation and/or other materials provided with the distribution.\r
+    3. Neither the name(s) of the author(s) nor the names of other contributors\r
+       may be used to endorse or promote products derived from this software\r
+       without specific prior written permission.\r
+\r
+    THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND\r
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+    ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE\r
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+    SUCH DAMAGE.\r
+*/\r
+\r
+#if defined(_WIN32)\r
+#include <Windows.h>\r
+#include <Lmcons.h>\r
+#include <process.h>\r
+#include <shlobj.h>\r
+#include <sys/types.h>\r
+#include <io.h>\r
+#include <conio.h>\r
+#undef MOUSE_MOVED\r
+#elif defined(__DJGPP__)\r
+#include <process.h>\r
+#else\r
+#include <pwd.h>\r
+#include <sys/utsname.h>\r
+#include <unistd.h>\r
+#include <utmpx.h>\r
+#endif\r
+\r
+#ifdef __INTERIX\r
+char *strdup(const char *s);\r
+#endif\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#if defined(_WIN32) && !defined(__MINGW32__)\r
+#define PATH_MAX MAX_PATH\r
+#endif\r
+\r
+#include <curses.h>\r
+#if !defined(DJGPP)\r
+#include <term.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#include <fcntl.h>\r
+#include <limits.h>\r
+#include <sys/stat.h>\r
+#include <signal.h>\r
+\r
+#define MOD_MOVE(c) (toupper(c) )\r
+\r
+void\r
+md_init()\r
+{\r
+#ifdef __INTERIX\r
+    char *term;\r
+\r
+    term = getenv("TERM");\r
+\r
+    if (term == NULL)\r
+        setenv("TERM","interix",1);\r
+#endif\r
+#if defined(__DJGPP__) || defined(_WIN32)\r
+    _fmode = _O_BINARY;\r
+#endif\r
+#if defined(__CYGWIN__) || defined(__MSYS__)\r
+    ESCDELAY=250;\r
+#endif\r
+}\r
+\r
+int\r
+md_hasclreol()\r
+{\r
+#ifdef CE\r
+    return((CE != NULL) && (*CE != 0));\r
+#elif defined (clr_eol)\r
+    return((clr_eol != NULL) && (*clr_eol != 0));\r
+#elif !defined(__PDCURSES__)\r
+    return(clr_eol != NULL);\r
+#else\r
+    return(TRUE);\r
+#endif\r
+}\r
+\r
+void\r
+md_putchar(int c)\r
+{\r
+    putchar(c);\r
+}\r
+\r
+static int md_standout_mode = 0;\r
+\r
+void\r
+md_raw_standout()\r
+{\r
+#ifdef _WIN32\r
+    CONSOLE_SCREEN_BUFFER_INFO csbiInfo; \r
+    HANDLE hStdout;\r
+    int fgattr,bgattr;\r
+\r
+    if (md_standout_mode == 0)\r
+    {\r
+        hStdout = GetStdHandle(STD_OUTPUT_HANDLE); \r
+        GetConsoleScreenBufferInfo(hStdout, &csbiInfo);\r
+        fgattr = (csbiInfo.wAttributes & 0xF);\r
+        bgattr = (csbiInfo.wAttributes & 0xF0);\r
+        SetConsoleTextAttribute(hStdout,(fgattr << 4) | (bgattr >> 4));\r
+        md_standout_mode = 1;\r
+    }\r
+#elif defined(SO)\r
+    tputs(SO,0,md_putchar);\r
+    fflush(stdout);\r
+#endif\r
+}\r
+\r
+void\r
+md_raw_standend()\r
+{\r
+#ifdef _WIN32\r
+    CONSOLE_SCREEN_BUFFER_INFO csbiInfo; \r
+    HANDLE hStdout;\r
+    int fgattr,bgattr;\r
+\r
+    if (md_standout_mode == 1)\r
+    {\r
+        hStdout = GetStdHandle(STD_OUTPUT_HANDLE); \r
+        GetConsoleScreenBufferInfo(hStdout, &csbiInfo);\r
+        fgattr = (csbiInfo.wAttributes & 0xF);\r
+        bgattr = (csbiInfo.wAttributes & 0xF0);\r
+        SetConsoleTextAttribute(hStdout,(fgattr << 4) | (bgattr >> 4));\r
+        md_standout_mode = 0;\r
+    }\r
+#elif defined(SE)\r
+    tputs(SE,0,md_putchar);\r
+    fflush(stdout);\r
+#endif\r
+}\r
+\r
+int\r
+md_unlink_open_file(char *file, int inf)\r
+{\r
+#ifdef _WIN32\r
+    _close(inf);\r
+    _chmod(file, 0600);\r
+    return( _unlink(file) );\r
+#else\r
+    return(unlink(file));\r
+#endif\r
+}\r
+\r
+int\r
+md_unlink(char *file)\r
+{\r
+#ifdef _WIN32\r
+    _chmod(file, 0600);\r
+    return( _unlink(file) );\r
+#else\r
+    return(unlink(file));\r
+#endif\r
+}\r
+\r
+int\r
+md_creat(char *file, int mode)\r
+{\r
+    int fd;\r
+#ifdef _WIN32\r
+    mode = _S_IREAD | _S_IWRITE;\r
+    fd = _open(file,O_CREAT | O_EXCL | O_WRONLY, mode);\r
+#else\r
+    fd = open(file,O_CREAT | O_EXCL | O_WRONLY, mode);\r
+#endif\r
+\r
+    return(fd);\r
+}\r
+\r
+\r
+void\r
+md_normaluser()\r
+{\r
+#ifndef _WIN32\r
+    setuid(getuid());\r
+    setgid(getgid());\r
+#endif\r
+}\r
+\r
+int\r
+md_getuid()\r
+{\r
+#ifndef _WIN32\r
+    return( getuid() );\r
+#else\r
+    return(42);\r
+#endif\r
+}\r
+\r
+char *\r
+md_getusername(int uid)\r
+{\r
+    static char login[80];\r
+    char *l = NULL;\r
+#ifdef _WIN32\r
+    LPSTR mybuffer;\r
+    DWORD size = UNLEN + 1;\r
+    TCHAR buffer[UNLEN + 1];\r
+\r
+    mybuffer = buffer;\r
+    if (uid != md_getuid())\r
+       strcpy(mybuffer, "someone");\r
+    else\r
+       GetUserName(mybuffer,&size);\r
+    l = mybuffer;\r
+#endif\r
+#if !defined(_WIN32) && !defined(DJGPP)\r
+    struct passwd *pw;\r
+\r
+    pw = getpwuid(getuid());\r
+\r
+    l = pw->pw_name;\r
+#endif\r
+\r
+    if ((l == NULL) || (*l == '\0'))\r
+        if ( (l = getenv("USERNAME")) == NULL )\r
+            if ( (l = getenv("LOGNAME")) == NULL )\r
+                if ( (l = getenv("USER")) == NULL )\r
+                    l = "nobody";\r
+\r
+    strncpy(login,l,80);\r
+    login[79] = 0;\r
+\r
+    return(login);\r
+}\r
+\r
+char *\r
+md_gethomedir()\r
+{\r
+    static char homedir[PATH_MAX];\r
+    char *h = NULL;\r
+    size_t len;\r
+#if defined(_WIN32)\r
+    TCHAR szPath[PATH_MAX];\r
+#endif\r
+#if defined(_WIN32) || defined(DJGPP)\r
+        char slash = '\\';\r
+#else\r
+    char slash = '/';\r
+    struct passwd *pw;\r
+    pw = getpwuid(getuid());\r
+\r
+    h = pw->pw_dir;\r
+\r
+    if (strcmp(h,"/") == 0)\r
+        h = NULL;\r
+#endif\r
+    homedir[0] = 0;\r
+#ifdef _WIN32\r
+    if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, szPath)))\r
+        h = szPath;\r
+#endif\r
+\r
+    if ( (h == NULL) || (*h == '\0') )\r
+        if ( (h = getenv("HOME")) == NULL )\r
+                h = "";\r
+\r
+    strncpy(homedir,h,PATH_MAX-1);\r
+    len = strlen(homedir);\r
+\r
+    if ((len > 0) && (homedir[len-1] == slash))\r
+       homedir[len-1] = 0;\r
+\r
+    return(homedir);\r
+}\r
+\r
+void\r
+md_sleep(int s)\r
+{\r
+#ifdef _WIN32\r
+    Sleep(s);\r
+#else\r
+    sleep(s);\r
+#endif\r
+}\r
+\r
+char *\r
+md_getshell()\r
+{\r
+    static char shell[PATH_MAX];\r
+    char *s = NULL;\r
+#ifdef _WIN32\r
+    char *def = "C:\\WINDOWS\\SYSTEM32\\CMD.EXE";\r
+#elif defined(__DJGPP__)\r
+    char *def = "C:\\COMMAND.COM";\r
+#else\r
+    char *def = "/bin/sh";\r
+    struct passwd *pw;\r
+    pw = getpwuid(getuid());\r
+    s = pw->pw_shell;\r
+#endif\r
+    if ((s == NULL) || (*s == '\0'))\r
+        if ( (s = getenv("COMSPEC")) == NULL)\r
+            if ( (s = getenv("SHELL")) == NULL)\r
+                if ( (s = getenv("SystemRoot")) == NULL)\r
+                    s = def;\r
+\r
+    strncpy(shell,s,PATH_MAX);\r
+    shell[PATH_MAX-1] = 0;\r
+\r
+    return(shell);\r
+}\r
+\r
+int\r
+md_shellescape()\r
+{\r
+#if (!defined(_WIN32) && !defined(__DJGPP__))\r
+    int ret_status;\r
+    int pid;\r
+    void (*myquit)(int);\r
+    void (*myend)(int);\r
+#endif\r
+    char *sh;\r
+\r
+    sh = md_getshell();\r
+\r
+#if defined(_WIN32)\r
+    return((int)_spawnl(_P_WAIT,sh,"shell",NULL,0));\r
+#elif defined(__DJGPP__)\r
+    return ( spawnl(P_WAIT,sh,"shell",NULL,0) );\r
+#else\r
+    while((pid = fork()) < 0)\r
+        sleep(1);\r
+\r
+    if (pid == 0) /* Shell Process */\r
+    {\r
+        /*\r
+         * Set back to original user, just in case\r
+         */\r
+        setuid(getuid());\r
+        setgid(getgid());\r
+        execl(sh == NULL ? "/bin/sh" : sh, "shell", "-i", 0);\r
+        perror("No shelly");\r
+        _exit(-1);\r
+    }\r
+    else /* Application */\r
+    {\r
+       myend = signal(SIGINT, SIG_IGN);\r
+#ifdef SIGQUIT\r
+        myquit = signal(SIGQUIT, SIG_IGN);\r
+#endif  \r
+        while (wait(&ret_status) != pid)\r
+            continue;\r
+           \r
+        signal(SIGINT, myquit);\r
+#ifdef SIGQUIT\r
+        signal(SIGQUIT, myend);\r
+#endif\r
+    }\r
+\r
+    return(ret_status);\r
+#endif\r
+}\r
+\r
+int\r
+directory_exists(char *dirname)\r
+{\r
+    struct stat sb;\r
+\r
+    if (stat(dirname, &sb) == 0) /* path exists */\r
+        return (sb.st_mode & S_IFDIR);\r
+\r
+    return(0);\r
+}\r
+\r
+char *\r
+md_getroguedir()\r
+{\r
+    static char path[1024];\r
+    char *end,*home;\r
+\r
+    if ( (home = getenv("ROGUEHOME")) != NULL)\r
+    {\r
+        if (*home)\r
+        {\r
+            strncpy(path, home, PATH_MAX - 20);\r
+\r
+            end = &path[strlen(path)-1];\r
+\r
+            while( (end >= path) && ((*end == '/') || (*end == '\\')))\r
+                *end-- = '\0';\r
+\r
+            if (directory_exists(path))\r
+                return(path);\r
+        }\r
+    }\r
+\r
+    if (directory_exists("/var/games/roguelike"))\r
+        return("/var/games/roguelike");\r
+    if (directory_exists("/var/lib/roguelike"))\r
+        return("/var/lib/roguelike");\r
+    if (directory_exists("/var/roguelike"))\r
+        return("/var/roguelike");\r
+    if (directory_exists("/usr/games/lib"))\r
+        return("/usr/games/lib");\r
+    if (directory_exists("/games/roguelik"))\r
+        return("/games/roguelik");\r
+    if (directory_exists(md_gethomedir()))\r
+       return(md_gethomedir());\r
+    return("");\r
+}\r
+\r
+char *\r
+md_getrealname(int uid)\r
+{\r
+    static char uidstr[20];\r
+#if !defined(_WIN32) && !defined(DJGPP)\r
+    struct passwd *pp;\r
+\r
+       if ((pp = getpwuid(uid)) == NULL)\r
+    {\r
+        sprintf(uidstr,"%d", uid);\r
+        return(uidstr);\r
+    }\r
+       else\r
+           return(pp->pw_name);\r
+#else\r
+   sprintf(uidstr,"%d", uid);\r
+   return(uidstr);\r
+#endif\r
+}\r
+\r
+extern char *xcrypt(char *key, char *salt);\r
+\r
+char *\r
+md_crypt(char *key, char *salt)\r
+{\r
+    return( xcrypt(key,salt) );\r
+}\r
+\r
+char *\r
+md_getpass(char *prompt)\r
+{\r
+#ifdef _WIN32\r
+    static char password_buffer[9];\r
+    char *p = password_buffer;\r
+    int c, count = 0;\r
+    int max_length = 9;\r
+\r
+    fflush(stdout);\r
+    /* If we can't prompt, abort */\r
+    if (fputs(prompt, stderr) < 0)\r
+    {\r
+        *p = '\0';\r
+        return NULL;\r
+    }\r
+\r
+    for(;;)\r
+    {\r
+        /* Get a character with no echo */\r
+        c = _getch();\r
+\r
+        /* Exit on interrupt (^c or ^break) */\r
+        if (c == '\003' || c == 0x100)\r
+            exit(1);\r
+\r
+        /* Terminate on end of line or file (^j, ^m, ^d, ^z) */\r
+        if (c == '\r' || c == '\n' || c == '\004' || c == '\032')\r
+            break;\r
+\r
+        /* Back up on backspace */\r
+        if (c == '\b')\r
+        {\r
+            if (count)\r
+                count--;\r
+            else if (p > password_buffer)\r
+                p--;\r
+            continue;\r
+        }\r
+\r
+        /* Ignore DOS extended characters */\r
+        if ((c & 0xff) != c)\r
+            continue;\r
+\r
+        /* Add to password if it isn't full */\r
+        if (p < password_buffer + max_length - 1)\r
+            *p++ = c;\r
+        else\r
+            count++;\r
+    }\r
+   *p = '\0';\r
+\r
+   fputc('\n', stderr);\r
+\r
+   return password_buffer;\r
+#else\r
+   return( (char *) getpass(prompt) );\r
+#endif\r
+}\r
+\r
+\r
+int md_endian = 0x01020304;\r
+\r
+unsigned long int\r
+md_ntohl(unsigned long int x)\r
+{\r
+#ifdef _WIN32\r
+    if ( *((char *)&md_endian) == 0x01 )\r
+        return(x);\r
+    else\r
+        return( ((x & 0x000000ffU) << 24) |\r
+                ((x & 0x0000ff00U) <<  8) |\r
+                ((x & 0x00ff0000U) >>  8) |\r
+                ((x & 0xff000000U) >> 24) );\r
+#else\r
+    return( ntohl(x) );\r
+#endif\r
+}\r
+\r
+unsigned long int\r
+md_htonl(unsigned long int x)\r
+{\r
+#ifdef _WIN32\r
+    if ( *((char *)&md_endian) == 0x01 )\r
+        return(x);\r
+    else\r
+        return( ((x & 0x000000ffU) << 24) |\r
+                ((x & 0x0000ff00U) <<  8) |\r
+                ((x & 0x00ff0000U) >>  8) |\r
+                ((x & 0xff000000U) >> 24) );\r
+#else\r
+    return( htonl(x) );\r
+#endif\r
+}\r
+\r
+int\r
+md_ucount()\r
+{\r
+#ifdef __DJGPP__\r
+    return(1);\r
+#elif defined(_WIN32)\r
+    return(1);\r
+#else\r
+    struct utmpx *up=NULL;\r
+    int count=0;\r
+\r
+    setutxent();    \r
+    do\r
+    {\r
+       up = getutxent();\r
+       if (up && up->ut_type == USER_PROCESS)\r
+           count++;\r
+    } while(up != NULL);\r
+   \r
+   endutxent();\r
+\r
+   return(count);\r
+#endif\r
+}\r
+\r
+int\r
+md_getloadavg(double *avg)\r
+{\r
+#if defined(__GLIBC__) || defined(_BSD)\r
+    if (getloadavg(avg, 3) == -1)\r
+#endif\r
+    {\r
+       avg[0] = avg[1] = avg[2] = 0.0;\r
+       return -1;\r
+    }\r
+}\r
+\r
+long\r
+md_random()\r
+{\r
+#ifdef _WIN32\r
+    return(rand());\r
+#else\r
+    return( random() );\r
+#endif\r
+}\r
+\r
+void\r
+md_srandom(unsigned x)\r
+{\r
+#ifdef _WIN32\r
+    srand(x);\r
+#else\r
+    srandom(x);\r
+#endif\r
+}\r
+\r
+int\r
+md_rand()\r
+{\r
+#ifdef _WIN32\r
+    return(rand());\r
+#else\r
+    return(lrand48() & 0x7fffffff);\r
+#endif\r
+}\r
+\r
+void\r
+md_srand(int seed)\r
+{\r
+#ifdef _WIN32\r
+    srand(seed);\r
+#else\r
+    srand48(seed);\r
+#endif\r
+}\r
+\r
+char *\r
+md_strdup(const char *s)\r
+{\r
+#ifdef _WIN32\r
+    return( _strdup(s) );\r
+#else\r
+    return(strdup(s));\r
+#endif\r
+}\r
+\r
+long\r
+md_memused()\r
+{\r
+#ifdef _WIN32\r
+    MEMORYSTATUS stat;\r
+\r
+    GlobalMemoryStatus(&stat);\r
+\r
+    return((long)stat.dwTotalPageFile);\r
+#else\r
+    return( (long)sbrk(0) );\r
+#endif\r
+}\r
+\r
+char *\r
+md_gethostname()\r
+{\r
+    static char nodename[80];\r
+    char *n = NULL;\r
+#if !defined(_WIN32) && !defined(__DJGPP__)\r
+    struct utsname ourname;\r
+\r
+    if (uname(&ourname) == 0)\r
+        n = ourname.nodename;\r
+#endif\r
+    if ((n == NULL) || (*n == '\0'))\r
+        if ( (n = getenv("COMPUTERNAME")) == NULL)\r
+            if ( (n = getenv("HOSTNAME")) == NULL)\r
+                n = "localhost";\r
+\r
+    strncpy(nodename, n, 80);\r
+    nodename[79] = 0;\r
+\r
+    return(nodename);\r
+}\r
+\r
+int\r
+md_erasechar()\r
+{\r
+#ifdef BSD\r
+    return(_tty.sg_erase); /* process erase character */\r
+#elif defined(USG5_0)\r
+    return(_tty.c_cc[VERASE]); /* process erase character */\r
+#else /* USG5_2 .... curses */\r
+    return( erasechar() ); /* process erase character */\r
+#endif\r
+}\r
+\r
+int\r
+md_killchar()\r
+{\r
+#ifdef BSD\r
+    return(_tty.sg_kill);\r
+#elif defined(USG5_0)\r
+    return(_tty.c_cc[VKILL]);\r
+#else /* USG5_2 ..... curses */\r
+    return( killchar() );\r
+#endif\r
+}\r
+\r
+/*\r
+ * unctrl:\r
+ *     Print a readable version of a certain character\r
+ */\r
+\r
+char *\r
+md_unctrl(char ch)\r
+{\r
+#if USG5_0\r
+    extern char *_unctrl[];            /* Defined in curses library */\r
+\r
+    return _unctrl[ch&0177];\r
+#else\r
+    return( unctrl(ch) );\r
+#endif\r
+}\r
+\r
+void\r
+md_flushinp()\r
+{\r
+#ifdef BSD\r
+    ioctl(0, TIOCFLUSH);\r
+#elif defined(USG5_0)\r
+    ioctl(_tty_ch,TCFLSH,0)\r
+#else /* USG5_2.... curses */\r
+    flushinp();\r
+#endif\r
+}\r
+\r
+/*\r
+    Cursor/Keypad Support\r
+\r
+    Sadly Cursor/Keypad support is less straightforward than it should be.\r
+\r
+    The various terminal emulators/consoles choose to differentiate the\r
+    cursor and keypad keys (with modifiers) in different ways (if at all!).\r
+    Furthermore they use different code set sequences for each key only\r
+    a subset of which the various curses libraries recognize. Partly due\r
+    to incomplete termcap/terminfo entries and partly due to inherent\r
+    limitations of those terminal capability databases.\r
+\r
+    I give curses first crack at decoding the sequences. If it fails to decode\r
+    it we check for common ESC-prefixed sequences.\r
+\r
+    All cursor/keypad results are translated into standard rogue movement\r
+    commands.\r
+\r
+    Unmodified keys are translated to walk commands: hjklyubn\r
+    Modified (shift,control,alt) are translated to run commands: HJKLYUBN\r
+\r
+    Console and supported (differentiated) keys\r
+    Interix:  Cursor Keys, Keypad, Ctl-Keypad\r
+    Cygwin:   Cursor Keys, Keypad, Alt-Cursor Keys\r
+    MSYS:     Cursor Keys, Keypad, Ctl-Cursor Keys, Ctl-Keypad\r
+    Win32:    Cursor Keys, Keypad, Ctl/Shift/Alt-Cursor Keys, Ctl/Alt-Keypad\r
+    DJGPP:    Cursor Keys, Keypad, Ctl/Shift/Alt-Cursor Keys, Ctl/Alt-Keypad\r
+\r
+    Interix Console (raw, ncurses)\r
+    ==============================\r
+    normal      shift           ctrl        alt\r
+    ESC [D,     ESC F^,         ESC [D,     ESC [D          /# Left         #/\r
+    ESC [C,     ESC F$,         ESC [C,     ESC [C          /# Right        #/\r
+    ESC [A,     ESC F-,         local win,  ESC [A          /# Up           #/\r
+    ESC [B,     ESC F+,         local win,  ESC [B          /# Down         #/\r
+    ESC [H,     ESC [H,         ESC [H,     ESC [H          /# Home         #/\r
+    ESC [S,     local win,      ESC [S,     ESC [S          /# Page Up      #/\r
+    ESC [T,     local win,      ESC [T,     ESC [T          /# Page Down    #/\r
+    ESC [U,     ESC [U,         ESC [U,     ESC [U          /# End          #/\r
+    ESC [D,     ESC F^,         ESC [D,     O               /# Keypad Left  #/\r
+    ESC [C,     ESC F$,         ESC [C,     O               /# Keypad Right #/\r
+    ESC [A,     ESC [A,         ESC [-1,    O               /# Keypad Up    #/\r
+    ESC [B,     ESC [B,         ESC [-2,    O               /# Keypad Down  #/\r
+    ESC [H,     ESC [H,         ESC [-263,  O               /# Keypad Home  #/\r
+    ESC [S,     ESC [S,         ESC [-19,   O               /# Keypad PgUp  #/\r
+    ESC [T,     ESC [T,         ESC [-20,   O               /# Keypad PgDn  #/\r
+    ESC [U,     ESC [U,         ESC [-21,   O               /# Keypad End   #/\r
+    nothing,    nothing,        nothing,    O               /# Kaypad 5     #/\r
+\r
+    Interix Console (term=interix, ncurses)\r
+    ==============================\r
+    KEY_LEFT,   ESC F^,         KEY_LEFT,   KEY_LEFT        /# Left         #/\r
+    KEY_RIGHT,  ESC F$,         KEY_RIGHT,  KEY_RIGHT       /# Right        #/\r
+    KEY_UP,     0x146,          local win,  KEY_UP          /# Up           #/\r
+    KEY_DOWN,   0x145,          local win,  KEY_DOWN        /# Down         #/\r
+    ESC [H,     ESC [H,         ESC [H,     ESC [H          /# Home         #/\r
+    KEY_PPAGE,  local win,      KEY_PPAGE,  KEY_PPAGE       /# Page Up      #/\r
+    KEY_NPAGE,  local win,      KEY_NPAGE,  KEY_NPAGE       /# Page Down    #/\r
+    KEY_LL,     KEY_LL,         KEY_LL,     KEY_LL          /# End          #/\r
+    KEY_LEFT,   ESC F^,         ESC [-4,    O               /# Keypad Left  #/\r
+    KEY_RIGHT,  ESC F$,         ESC [-3,    O               /# Keypad Right #/\r
+    KEY_UP,     KEY_UP,         ESC [-1,    O               /# Keypad Up    #/\r
+    KEY_DOWN,   KEY_DOWN,       ESC [-2,    O               /# Keypad Down  #/\r
+    ESC [H,     ESC [H,         ESC [-263,  O               /# Keypad Home  #/\r
+    KEY_PPAGE,  KEY_PPAGE,      ESC [-19,   O               /# Keypad PgUp  #/\r
+    KEY_NPAGE,  KEY_NPAGE,      ESC [-20,   O               /# Keypad PgDn  #/\r
+    KEY_LL,     KEY_LL,         ESC [-21,   O               /# Keypad End   #/\r
+    nothing,    nothing,        nothing,    O               /# Keypad 5     #/\r
+\r
+    Cygwin Console (raw, ncurses)\r
+    ==============================\r
+    normal      shift           ctrl        alt\r
+    ESC [D,     ESC [D,         ESC [D,     ESC ESC [D      /# Left         #/\r
+    ESC [C,     ESC [C,         ESC [C,     ESC ESC [C      /# Rght         #/\r
+    ESC [A,     ESC [A,         ESC [A,     ESC ESC [A      /# Up           #/\r
+    ESC [B,     ESC [B,         ESC [B,     ESC ESC [B      /# Down         #/\r
+    ESC [1~,    ESC [1~,        ESC [1~,    ESC ESC [1~     /# Home         #/\r
+    ESC [5~,    ESC [5~,        ESC [5~,    ESC ESC [5~     /# Page Up      #/\r
+    ESC [6~,    ESC [6~,        ESC [6~,    ESC ESC [6~     /# Page Down    #/\r
+    ESC [4~,    ESC [4~,        ESC [4~,    ESC ESC [4~     /# End          #/\r
+    ESC [D,     ESC [D,         ESC [D,     ESC ESC [D,O    /# Keypad Left  #/\r
+    ESC [C,     ESC [C,         ESC [C,     ESC ESC [C,O    /# Keypad Right #/\r
+    ESC [A,     ESC [A,         ESC [A,     ESC ESC [A,O    /# Keypad Up    #/\r
+    ESC [B,     ESC [B,         ESC [B,     ESC ESC [B,O    /# Keypad Down  #/\r
+    ESC [1~,    ESC [1~,        ESC [1~,    ESC ESC [1~,O   /# Keypad Home  #/\r
+    ESC [5~,    ESC [5~,        ESC [5~,    ESC ESC [5~,O   /# Keypad PgUp  #/\r
+    ESC [6~,    ESC [6~,        ESC [6~,    ESC ESC [6~,O   /# Keypad PgDn  #/\r
+    ESC [4~,    ESC [4~,        ESC [4~,    ESC ESC [4~,O   /# Keypad End   #/\r
+    ESC [-71,   nothing,        nothing,    O               /# Keypad 5     #/\r
+\r
+    Cygwin Console (term=cygwin, ncurses)\r
+    ==============================\r
+    KEY_LEFT,   KEY_LEFT,       KEY_LEFT,   ESC-260         /# Left         #/\r
+    KEY_RIGHT,  KEY_RIGHT,      KEY_RIGHT,  ESC-261         /# Rght         #/\r
+    KEY_UP,     KEY_UP,         KEY_UP,     ESC-259         /# Up           #/\r
+    KEY_DOWN,   KEY_DOWN,       KEY_DOWN,   ESC-258         /# Down         #/\r
+    KEY_HOME,   KEY_HOME,       KEY_HOME,   ESC-262         /# Home         #/\r
+    KEY_PPAGE,  KEY_PPAGE,      KEY_PPAGE,  ESC-339         /# Page Up      #/\r
+    KEY_NPAGE,  KEY_NPAGE,      KEY_NPAGE,  ESC-338         /# Page Down    #/\r
+    KEY_END,    KEY_END,        KEY_END,    ESC-360         /# End          #/\r
+    KEY_LEFT,   KEY_LEFT,       KEY_LEFT,   ESC-260,O       /# Keypad Left  #/\r
+    KEY_RIGHT,  KEY_RIGHT,      KEY_RIGHT,  ESC-261,O       /# Keypad Right #/\r
+    KEY_UP,     KEY_UP,         KEY_UP,     ESC-259,O       /# Keypad Up    #/\r
+    KEY_DOWN,   KEY_DOWN,       KEY_DOWN,   ESC-258,O       /# Keypad Down  #/\r
+    KEY_HOME,   KEY_HOME,       KEY_HOME,   ESC-262,O       /# Keypad Home  #/\r
+    KEY_PPAGE,  KEY_PPAGE,      KEY_PPAGE,  ESC-339,O       /# Keypad PgUp  #/\r
+    KEY_NPAGE,  KEY_NPAGE,      KEY_NPAGE,  ESC-338,O       /# Keypad PgDn  #/\r
+    KEY_END,    KEY_END,        KEY_END,    ESC-360,O       /# Keypad End   #/\r
+    ESC [G,     nothing,        nothing,    O               /# Keypad 5     #/\r
+\r
+    MSYS Console (raw, ncurses)\r
+    ==============================\r
+    normal      shift           ctrl        alt\r
+    ESC OD,     ESC [d,         ESC Od      nothing         /# Left         #/\r
+    ESC OE,     ESC [e,         ESC Oe,     nothing         /# Right        #/\r
+    ESC OA,     ESC [a,         ESC Oa,     nothing         /# Up           #/\r
+    ESC OB,     ESC [b,         ESC Ob,     nothing         /# Down         #/\r
+    ESC [7~,    ESC [7$,        ESC [7^,    nothing         /# Home         #/\r
+    ESC [5~,    local window,   ESC [5^,    nothing         /# Page Up      #/\r
+    ESC [6~,    local window,   ESC [6^,    nothing         /# Page Down    #/\r
+    ESC [8~,    ESC [8$,        ESC [8^,    nothing         /# End          #/\r
+    ESC OD,     ESC [d,         ESC Od      O               /# Keypad Left  #/\r
+    ESC OE,     ESC [c,         ESC Oc,     O               /# Keypad Right #/\r
+    ESC OA,     ESC [a,         ESC Oa,     O               /# Keypad Up    #/\r
+    ESC OB,     ESC [b,         ESC Ob,     O               /# Keypad Down  #/\r
+    ESC [7~,    ESC [7$,        ESC [7^,    O               /# Keypad Home  #/\r
+    ESC [5~,    local window,   ESC [5^,    O               /# Keypad PgUp  #/\r
+    ESC [6~,    local window,   ESC [6^,    O               /# Keypad PgDn  #/\r
+    ESC [8~,    ESC [8$,        ESC [8^,    O               /# Keypad End   #/\r
+    11,         11,             11,         O               /# Keypad 5     #/\r
+\r
+    MSYS Console (term=rxvt, ncurses)\r
+    ==============================\r
+    normal      shift           ctrl        alt\r
+    KEY_LEFT,   KEY_SLEFT,      514         nothing         /# Left         #/\r
+    KEY_RIGHT,  KEY_SRIGHT,     516,        nothing         /# Right        #/\r
+    KEY_UP,     518,            519,        nothing         /# Up           #/\r
+    KEY_DOWN,   511,            512,        nothing         /# Down         #/\r
+    KEY_HOME,   KEY_SHOME,      ESC [7^,    nothing         /# Home         #/\r
+    KEY_PPAGE,  local window,   ESC [5^,    nothing         /# Page Up      #/\r
+    KEY_NPAGE,  local window,   ESC [6^,    nothing         /# Page Down    #/\r
+    KEY_END,    KEY_SEND,       KEY_EOL,    nothing         /# End          #/\r
+    KEY_LEFT,   KEY_SLEFT,      514         O               /# Keypad Left  #/\r
+    KEY_RIGHT,  KEY_SRIGHT,     516,        O               /# Keypad Right #/\r
+    KEY_UP,     518,            519,        O               /# Keypad Up    #/\r
+    KEY_DOWN,   511,            512,        O               /# Keypad Down  #/\r
+    KEY_HOME,   KEY_SHOME,      ESC [7^,    O               /# Keypad Home  #/\r
+    KEY_PPAGE,  local window,   ESC [5^,    O               /# Keypad PgUp  #/\r
+    KEY_NPAGE,  local window,   ESC [6^,    O               /# Keypad PgDn  #/\r
+    KEY_END,    KEY_SEND,       KEY_EOL,    O               /# Keypad End   #/\r
+    11,         11,             11,         O               /# Keypad 5     #/\r
+\r
+    Win32 Console (raw, pdcurses)\r
+   DJGPP Console (raw, pdcurses)\r
+   ==============================\r
+   normal      shift           ctrl        alt\r
+   260,        391,            443,        493             /# Left         #/\r
+   261,        400,            444,        492             /# Right        #/\r
+   259,        547,            480,        490             /# Up           #/\r
+   258,        548,            481,        491             /# Down         #/\r
+   262,        388,            447,        524             /# Home         #/\r
+   339,        396,            445,        526             /# Page Up      #/\r
+   338,        394,            446,        520             /# Page Down    #/\r
+   358,        384,            448,        518             /# End          #/\r
+   452,        52('4'),        511,        521             /# Keypad Left  #/\r
+   454,        54('6'),        513,        523             /# Keypad Right #/\r
+   450,        56('8'),        515,        525             /# Keypad Up    #/\r
+   456,        50('2'),        509,        519             /# Keypad Down  #/\r
+   449,        55('7'),        514,        524             /# Keypad Home  #/\r
+   451,        57('9'),        516,        526             /# Keypad PgUp  #/\r
+   457,        51('3'),        510,        520             /# Keypad PgDn  #/\r
+   455,        49('1'),        508,        518             /# Keypad End   #/\r
+   453,        53('5'),        512,        522             /# Keypad 5     #/\r
+\r
+   Win32 Console (pdcurses, MSVC/MingW32)\r
+   DJGPP Console (pdcurses)\r
+   ==============================\r
+   normal      shift           ctrl        alt\r
+   KEY_LEFT,   KEY_SLEFT,      CTL_LEFT,   ALT_LEFT        /# Left         #/\r
+   KEY_RIGHT,  KEY_SRIGHT,     CTL_RIGHT,  ALT_RIGHT       /# Right        #/\r
+   KEY_UP,     KEY_SUP,        CTL_UP,     ALT_UP          /# Up           #/\r
+   KEY_DOWN,   KEY_SDOWN,      CTL_DOWN,   ALT_DOWN        /# Down         #/\r
+   KEY_HOME,   KEY_SHOME,      CTL_HOME,   ALT_HOME        /# Home         #/\r
+   KEY_PPAGE,  KEY_SPREVIOUS,  CTL_PGUP,   ALT_PGUP        /# Page Up      #/\r
+   KEY_NPAGE,  KEY_SNEXTE,     CTL_PGDN,   ALT_PGDN        /# Page Down    #/\r
+   KEY_END,    KEY_SEND,       CTL_END,    ALT_END         /# End          #/\r
+   KEY_B1,     52('4'),        CTL_PAD4,   ALT_PAD4        /# Keypad Left  #/\r
+   KEY_B3,     54('6'),        CTL_PAD6,   ALT_PAD6        /# Keypad Right #/\r
+   KEY_A2,     56('8'),        CTL_PAD8,   ALT_PAD8        /# Keypad Up    #/\r
+   KEY_C2,     50('2'),        CTL_PAD2,   ALT_PAD2        /# Keypad Down  #/\r
+   KEY_A1,     55('7'),        CTL_PAD7,   ALT_PAD7        /# Keypad Home  #/\r
+   KEY_A3,     57('9'),        CTL_PAD9,   ALT_PAD9        /# Keypad PgUp  #/\r
+   KEY_C3,     51('3'),        CTL_PAD3,   ALT_PAD3        /# Keypad PgDn  #/\r
+   KEY_C1,     49('1'),        CTL_PAD1,   ALT_PAD1        /# Keypad End   #/\r
+   KEY_B2,     53('5'),        CTL_PAD5,   ALT_PAD5        /# Keypad 5     #/\r
+\r
+   Windows Telnet (raw)\r
+   ==============================\r
+   normal      shift           ctrl        alt\r
+   ESC [D,     ESC [D,         ESC [D,     ESC [D          /# Left         #/\r
+   ESC [C,     ESC [C,         ESC [C,     ESC [C          /# Right        #/\r
+   ESC [A,     ESC [A,         ESC [A,     ESC [A          /# Up           #/\r
+   ESC [B,     ESC [B,         ESC [B,     ESC [B          /# Down         #/\r
+   ESC [1~,    ESC [1~,        ESC [1~,    ESC [1~         /# Home         #/\r
+   ESC [5~,    ESC [5~,        ESC [5~,    ESC [5~         /# Page Up      #/\r
+   ESC [6~,    ESC [6~,        ESC [6~,    ESC [6~         /# Page Down    #/\r
+   ESC [4~,    ESC [4~,        ESC [4~,    ESC [4~         /# End          #/\r
+   ESC [D,     ESC [D,         ESC [D,     ESC [D          /# Keypad Left  #/\r
+   ESC [C,     ESC [C,         ESC [C,     ESC [C          /# Keypad Right #/\r
+   ESC [A,     ESC [A,         ESC [A,     ESC [A          /# Keypad Up    #/\r
+   ESC [B,     ESC [B,         ESC [B,     ESC [B          /# Keypad Down  #/\r
+   ESC [1~,    ESC [1~,        ESC [1~,    ESC [1~         /# Keypad Home  #/\r
+   ESC [5~,    ESC [5~,        ESC [5~,    ESC [5~         /# Keypad PgUp  #/\r
+   ESC [6~,    ESC [6~,        ESC [6~,    ESC [6~         /# Keypad PgDn  #/\r
+   ESC [4~,    ESC [4~,        ESC [4~,    ESC [4~         /# Keypad End   #/\r
+   nothing,    nothing,        nothing,    nothing         /# Keypad 5     #/\r
+\r
+   Windows Telnet (term=xterm)\r
+   ==============================\r
+   normal      shift           ctrl        alt\r
+   KEY_LEFT,   KEY_LEFT,       KEY_LEFT,   KEY_LEFT        /# Left         #/\r
+   KEY_RIGHT,  KEY_RIGHT,      KEY_RIGHT,  KEY_RIGHT       /# Right        #/\r
+   KEY_UP,     KEY_UP,         KEY_UP,     KEY_UP          /# Up           #/\r
+   KEY_DOWN,   KEY_DOWN,       KEY_DOWN,   KEY_DOWN        /# Down         #/\r
+   ESC [1~,    ESC [1~,        ESC [1~,    ESC [1~         /# Home         #/\r
+   KEY_PPAGE,  KEY_PPAGE,      KEY_PPAGE,  KEY_PPAGE       /# Page Up      #/\r
+   KEY_NPAGE,  KEY_NPAGE,      KEY_NPAGE,  KEY_NPAGE       /# Page Down    #/\r
+   ESC [4~,    ESC [4~,        ESC [4~,    ESC [4~         /# End          #/\r
+    KEY_LEFT,   KEY_LEFT,       KEY_LEFT,   O               /# Keypad Left  #/\r
+    KEY_RIGHT,  KEY_RIGHT,      KEY_RIGHT,  O               /# Keypad Right #/\r
+    KEY_UP,     KEY_UP,         KEY_UP,     O               /# Keypad Up    #/\r
+    KEY_DOWN,   KEY_DOWN,       KEY_DOWN,   O               /# Keypad Down  #/\r
+    ESC [1~,    ESC [1~,        ESC [1~,    ESC [1~         /# Keypad Home  #/\r
+    KEY_PPAGE,  KEY_PPAGE,      KEY_PPAGE,  KEY_PPAGE       /# Keypad PgUp  #/\r
+    KEY_NPAGE,  KEY_NPAGE,      KEY_NPAGE,  KEY_NPAGE       /# Keypad PgDn  #/\r
+    ESC [4~,    ESC [4~,        ESC [4~,    O               /# Keypad End   #/\r
+    ESC [-71,   nothing,        nothing,    O               /# Keypad 5     #/\r
+\r
+    PuTTY\r
+    ==============================\r
+    normal      shift           ctrl        alt\r
+    ESC [D,     ESC [D,         ESC OD,     ESC [D          /# Left         #/\r
+    ESC [C,     ESC [C,         ESC OC,     ESC [C          /# Right        #/\r
+    ESC [A,     ESC [A,         ESC OA,     ESC [A          /# Up           #/\r
+    ESC [B,     ESC [B,         ESC OB,     ESC [B          /# Down         #/\r
+    ESC [1~,    ESC [1~,        local win,  ESC [1~         /# Home         #/\r
+    ESC [5~,    local win,      local win,  ESC [5~         /# Page Up      #/\r
+    ESC [6~,    local win,      local win,  ESC [6~         /# Page Down    #/\r
+    ESC [4~,    ESC [4~,        local win,  ESC [4~         /# End          #/\r
+    ESC [D,     ESC [D,         ESC [D,     O               /# Keypad Left  #/\r
+    ESC [C,     ESC [C,         ESC [C,     O               /# Keypad Right #/\r
+    ESC [A,     ESC [A,         ESC [A,     O               /# Keypad Up    #/\r
+    ESC [B,     ESC [B,         ESC [B,     O               /# Keypad Down  #/\r
+    ESC [1~,    ESC [1~,        ESC [1~,    O               /# Keypad Home  #/\r
+    ESC [5~,    ESC [5~,        ESC [5~,    O               /# Keypad PgUp  #/\r
+    ESC [6~,    ESC [6~,        ESC [6~,    O               /# Keypad PgDn  #/\r
+    ESC [4~,    ESC [4~,        ESC [4~,    O               /# Keypad End   #/\r
+    nothing,    nothing,        nothing,    O               /# Keypad 5     #/\r
+\r
+    PuTTY\r
+    ==============================\r
+    normal      shift           ctrl        alt\r
+    KEY_LEFT,   KEY_LEFT,       ESC OD,     ESC KEY_LEFT    /# Left         #/\r
+    KEY_RIGHT   KEY_RIGHT,      ESC OC,     ESC KEY_RIGHT   /# Right        #/\r
+    KEY_UP,     KEY_UP,         ESC OA,     ESC KEY_UP      /# Up           #/\r
+    KEY_DOWN,   KEY_DOWN,       ESC OB,     ESC KEY_DOWN    /# Down         #/\r
+    ESC [1~,    ESC [1~,        local win,  ESC ESC [1~     /# Home         #/\r
+    KEY_PPAGE   local win,      local win,  ESC KEY_PPAGE   /# Page Up      #/\r
+    KEY_NPAGE   local win,      local win,  ESC KEY_NPAGE   /# Page Down    #/\r
+    ESC [4~,    ESC [4~,        local win,  ESC ESC [4~     /# End          #/\r
+    ESC Ot,     ESC Ot,         ESC Ot,     O               /# Keypad Left  #/\r
+    ESC Ov,     ESC Ov,         ESC Ov,     O               /# Keypad Right #/\r
+    ESC Ox,     ESC Ox,         ESC Ox,     O               /# Keypad Up    #/\r
+    ESC Or,     ESC Or,         ESC Or,     O               /# Keypad Down  #/\r
+    ESC Ow,     ESC Ow,         ESC Ow,     O               /# Keypad Home  #/\r
+    ESC Oy,     ESC Oy,         ESC Oy,     O               /# Keypad PgUp  #/\r
+    ESC Os,     ESC Os,         ESC Os,     O               /# Keypad PgDn  #/\r
+    ESC Oq,     ESC Oq,         ESC Oq,     O               /# Keypad End   #/\r
+    ESC Ou,     ESC Ou,         ESC Ou,     O               /# Keypad 5     #/\r
+*/\r
+\r
+#define M_NORMAL 0\r
+#define M_ESC    1\r
+#define M_KEYPAD 2\r
+#define M_TRAIL  3\r
+\r
+int\r
+md_readchar(WINDOW *win)\r
+{\r
+    int ch = 0;\r
+    int lastch = 0;\r
+    int mode = M_NORMAL;\r
+    int mode2 = M_NORMAL;\r
+\r
+    for(;;)\r
+    {\r
+        ch = wgetch(win);\r
+\r
+        if (ch == ERR)      /* timed out waiting for valid sequence */\r
+        {                   /* flush input so far and start over    */\r
+            mode = M_NORMAL;\r
+            nocbreak();\r
+            raw();\r
+            ch = 27;\r
+            break;\r
+        }\r
+\r
+        if (mode == M_TRAIL)\r
+        {\r
+            if (ch == '^')              /* msys console  : 7,5,6,8: modified*/\r
+                ch = MOD_MOVE( toupper(lastch) );\r
+\r
+            if (ch == '~')              /* cygwin console: 1,5,6,4: normal  */\r
+                ch = tolower(lastch);   /* windows telnet: 1,5,6,4: normal  */\r
+                                        /* msys console  : 7,5,6,8: normal  */\r
+\r
+            if (mode2 == M_ESC)         /* cygwin console: 1,5,6,4: modified*/\r
+                ch = MOD_MOVE( toupper(ch) );\r
+\r
+            break;\r
+        }\r
+\r
+        if (mode == M_ESC)\r
+        {\r
+            if (ch == 27)\r
+            {\r
+                mode2 = M_ESC;\r
+                continue;\r
+            }\r
+\r
+            if ((ch == 'F') || (ch == 'O') || (ch == '['))\r
+            {\r
+                mode = M_KEYPAD;\r
+                continue;\r
+            }\r
+\r
+\r
+            switch(ch)\r
+            {\r
+                /* Cygwin Console   */\r
+                /* PuTTY            */\r
+                case KEY_LEFT : ch = MOD_MOVE('H'); break;\r
+                case KEY_RIGHT: ch = MOD_MOVE('L'); break;\r
+                case KEY_UP   : ch = MOD_MOVE('K'); break;\r
+                case KEY_DOWN : ch = MOD_MOVE('J'); break;\r
+                case KEY_HOME : ch = MOD_MOVE('Y'); break;\r
+                case KEY_PPAGE: ch = MOD_MOVE('U'); break;\r
+                case KEY_NPAGE: ch = MOD_MOVE('N'); break;\r
+                case KEY_END  : ch = MOD_MOVE('B'); break;\r
+\r
+                default: break;\r
+            }\r
+\r
+            break;\r
+        }\r
+\r
+        if (mode == M_KEYPAD)\r
+        {\r
+            switch(ch)\r
+            {\r
+                /* ESC F - Interix Console codes */\r
+                case   '^': ch = MOD_MOVE('H'); break;      /* Shift-Left       */\r
+                case   '$': ch = MOD_MOVE('L'); break;      /* Shift-Right      */\r
+\r
+                /* ESC [ - Interix Console codes */\r
+                case   'H': ch = 'y'; break;            /* Home             */\r
+                case     1: ch = MOD_MOVE('K'); break;      /* Ctl-Keypad Up    */\r
+                case     2: ch = MOD_MOVE('J'); break;      /* Ctl-Keypad Down  */\r
+                case     3: ch = MOD_MOVE('L'); break;      /* Ctl-Keypad Right */\r
+                case     4: ch = MOD_MOVE('H'); break;      /* Ctl-Keypad Left  */\r
+                case   263: ch = MOD_MOVE('Y'); break;      /* Ctl-Keypad Home  */\r
+                case    19: ch = MOD_MOVE('U'); break;      /* Ctl-Keypad PgUp  */\r
+                case    20: ch = MOD_MOVE('N'); break;      /* Ctl-Keypad PgDn  */\r
+                case    21: ch = MOD_MOVE('B'); break;      /* Ctl-Keypad End   */\r
+\r
+                /* ESC [ - Cygwin Console codes */\r
+                case   'G': ch = '.'; break;            /* Keypad 5         */\r
+                case   '7': lastch = 'Y'; mode=M_TRAIL; break;  /* Ctl-Home */\r
+                case   '5': lastch = 'U'; mode=M_TRAIL; break;  /* Ctl-PgUp */\r
+                case   '6': lastch = 'N'; mode=M_TRAIL; break;  /* Ctl-PgDn */\r
+\r
+                /* ESC [ - Win32 Telnet, PuTTY */\r
+                case   '1': lastch = 'y'; mode=M_TRAIL; break;  /* Home     */\r
+                case   '4': lastch = 'b'; mode=M_TRAIL; break;  /* End      */\r
+\r
+                /* ESC O - PuTTY */\r
+                case   'D': ch = MOD_MOVE('H'); break;\r
+                case   'C': ch = MOD_MOVE('L'); break;\r
+                case   'A': ch = MOD_MOVE('K'); break;\r
+                case   'B': ch = MOD_MOVE('J'); break;\r
+                case   't': ch = 'h'; break;\r
+                case   'v': ch = 'l'; break;\r
+                case   'x': ch = 'k'; break;\r
+                case   'r': ch = 'j'; break;\r
+                case   'w': ch = 'y'; break;\r
+                case   'y': ch = 'u'; break;\r
+                case   's': ch = 'n'; break;\r
+                case   'q': ch = 'b'; break;\r
+                case   'u': ch = '.'; break;\r
+            }\r
+\r
+            if (mode != M_KEYPAD)\r
+                continue;\r
+        }\r
+\r
+        if (ch == 27)\r
+        {\r
+            halfdelay(1);\r
+            mode = M_ESC;\r
+            continue;\r
+        }\r
+\r
+        switch(ch)\r
+        {\r
+            case KEY_LEFT   : ch = 'h'; break;\r
+            case KEY_DOWN   : ch = 'j'; break;\r
+            case KEY_UP     : ch = 'k'; break;\r
+            case KEY_RIGHT  : ch = 'l'; break;\r
+            case KEY_HOME   : ch = 'y'; break;\r
+            case KEY_PPAGE  : ch = 'u'; break;\r
+            case KEY_END    : ch = 'b'; break;\r
+#ifdef KEY_LL\r
+            case KEY_LL     : ch = 'b'; break;\r
+#endif\r
+            case KEY_NPAGE  : ch = 'n'; break;\r
+\r
+#ifdef KEY_B1\r
+            case KEY_B1     : ch = 'h'; break;\r
+            case KEY_C2     : ch = 'j'; break;\r
+            case KEY_A2     : ch = 'k'; break;\r
+            case KEY_B3     : ch = 'l'; break;\r
+#endif\r
+            case KEY_A1     : ch = 'y'; break;\r
+            case KEY_A3     : ch = 'u'; break;\r
+            case KEY_C1     : ch = 'b'; break;\r
+            case KEY_C3     : ch = 'n'; break;\r
+            /* next should be '.', but for problem with putty/linux */\r
+            case KEY_B2     : ch = 'u'; break;\r
+\r
+#ifdef KEY_SLEFT\r
+            case KEY_SRIGHT  : ch = MOD_MOVE('L'); break;\r
+            case KEY_SLEFT   : ch = MOD_MOVE('H'); break;\r
+#ifdef KEY_SUP\r
+            case KEY_SUP     : ch = MOD_MOVE('K'); break;\r
+            case KEY_SDOWN   : ch = MOD_MOVE('J'); break;\r
+#endif\r
+            case KEY_SHOME   : ch = MOD_MOVE('Y'); break;\r
+            case KEY_SPREVIOUS:ch = MOD_MOVE('U'); break;\r
+            case KEY_SEND    : ch = MOD_MOVE('B'); break;\r
+            case KEY_SNEXT   : ch = MOD_MOVE('N'); break;\r
+#endif\r
+            case 0x146       : ch = MOD_MOVE('K'); break;   /* Shift-Up     */\r
+            case 0x145       : ch = MOD_MOVE('J'); break;   /* Shift-Down   */\r
+\r
+#ifdef CTL_RIGHT\r
+            case CTL_RIGHT   : ch = MOD_MOVE('L'); break;\r
+            case CTL_LEFT    : ch = MOD_MOVE('H'); break;\r
+            case CTL_UP      : ch = MOD_MOVE('K'); break;\r
+            case CTL_DOWN    : ch = MOD_MOVE('J'); break;\r
+            case CTL_HOME    : ch = MOD_MOVE('Y'); break;\r
+            case CTL_PGUP    : ch = MOD_MOVE('U'); break;\r
+            case CTL_END     : ch = MOD_MOVE('B'); break;\r
+            case CTL_PGDN    : ch = MOD_MOVE('N'); break;\r
+#endif\r
+#ifdef KEY_EOL\r
+            case KEY_EOL     : ch = MOD_MOVE('B'); break;\r
+#endif\r
+\r
+#ifndef CTL_PAD1\r
+            /* MSYS rxvt console */\r
+            case 511         : ch = MOD_MOVE('J'); break; /* Shift Dn */\r
+            case 512         : ch = MOD_MOVE('J'); break; /* Ctl Down */\r
+            case 514         : ch = MOD_MOVE('H'); break; /* Ctl Left */\r
+            case 516         : ch = MOD_MOVE('L'); break; /* Ctl Right*/\r
+            case 518         : ch = MOD_MOVE('K'); break; /* Shift Up */\r
+            case 519         : ch = MOD_MOVE('K'); break; /* Ctl Up   */\r
+#endif\r
+\r
+#ifdef CTL_PAD1\r
+            case CTL_PAD1   : ch = MOD_MOVE('B'); break;\r
+            case CTL_PAD2   : ch = MOD_MOVE('J'); break;\r
+            case CTL_PAD3   : ch = MOD_MOVE('N'); break;\r
+            case CTL_PAD4   : ch = MOD_MOVE('H'); break;\r
+            case CTL_PAD5   : ch = '.'; break;\r
+            case CTL_PAD6   : ch = MOD_MOVE('L'); break;\r
+            case CTL_PAD7   : ch = MOD_MOVE('Y'); break;\r
+            case CTL_PAD8   : ch = MOD_MOVE('K'); break;\r
+            case CTL_PAD9   : ch = MOD_MOVE('U'); break;\r
+#endif\r
+\r
+#ifdef ALT_RIGHT\r
+            case ALT_RIGHT  : ch = MOD_MOVE('L'); break;\r
+            case ALT_LEFT   : ch = MOD_MOVE('H'); break;\r
+            case ALT_DOWN   : ch = MOD_MOVE('J'); break;\r
+            case ALT_HOME   : ch = MOD_MOVE('Y'); break;\r
+            case ALT_PGUP   : ch = MOD_MOVE('U'); break;\r
+            case ALT_END    : ch = MOD_MOVE('B'); break;\r
+            case ALT_PGDN   : ch = MOD_MOVE('N'); break;\r
+#endif\r
+\r
+#ifdef ALT_PAD1\r
+            case ALT_PAD1   : ch = MOD_MOVE('B'); break;\r
+            case ALT_PAD2   : ch = MOD_MOVE('J'); break;\r
+            case ALT_PAD3   : ch = MOD_MOVE('N'); break;\r
+            case ALT_PAD4   : ch = MOD_MOVE('H'); break;\r
+            case ALT_PAD5   : ch = '.'; break;\r
+            case ALT_PAD6   : ch = MOD_MOVE('L'); break;\r
+            case ALT_PAD7   : ch = MOD_MOVE('Y'); break;\r
+            case ALT_PAD8   : ch = MOD_MOVE('K'); break;\r
+            case ALT_PAD9   : ch = MOD_MOVE('U'); break;\r
+#endif\r
+        }\r
+\r
+        break;\r
+    }\r
+\r
+    nocbreak();     /* disable halfdelay mode if on */\r
+    raw();\r
+\r
+    return(ch & 0x7F);\r
+}\r
diff --git a/misc.c b/misc.c
new file mode 100644 (file)
index 0000000..0b2871f
--- /dev/null
+++ b/misc.c
@@ -0,0 +1,432 @@
+/*\r
+ * all sorts of miscellaneous routines\r
+ *\r
+ * @(#)misc.c  3.13 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include "rogue.h"\r
+#include <ctype.h>\r
+\r
+/*\r
+ * tr_name:\r
+ *     print the name of a trap\r
+ */\r
+\r
+char *\r
+tr_name(ch)\r
+char ch;\r
+{\r
+    register char *s;\r
+\r
+    switch (ch)\r
+    {\r
+       case TRAPDOOR:\r
+           s = terse ? "A trapdoor." : "You found a trapdoor.";\r
+       when BEARTRAP:\r
+           s = terse ? "A beartrap." : "You found a beartrap.";\r
+       when SLEEPTRAP:\r
+           s = terse ? "A sleeping gas trap.":"You found a sleeping gas trap.";\r
+       when ARROWTRAP:\r
+           s = terse ? "An arrow trap." : "You found an arrow trap.";\r
+       when TELTRAP:\r
+           s = terse ? "A teleport trap." : "You found a teleport trap.";\r
+       when DARTTRAP:\r
+           s = terse ? "A dart trap." : "You found a poison dart trap.";\r
+    }\r
+    return s;\r
+}\r
+\r
+/*\r
+ * Look:\r
+ *     A quick glance all around the player\r
+ */\r
+\r
+look(wakeup)\r
+bool wakeup;\r
+{\r
+    register int x, y;\r
+    register char ch;\r
+    register int oldx, oldy;\r
+    register bool inpass;\r
+    register int passcount = 0;\r
+    register struct room *rp;\r
+    register int ey, ex;\r
+\r
+    getyx(cw, oldy, oldx);\r
+    if (oldrp != NULL && (oldrp->r_flags & ISDARK) && off(player, ISBLIND))\r
+    {\r
+       for (x = oldpos.x - 1; x <= oldpos.x + 1; x++)\r
+           for (y = oldpos.y - 1; y <= oldpos.y + 1; y++)\r
+               if ((y != hero.y || x != hero.x) && show(y, x) == FLOOR)\r
+                   mvwaddch(cw, y, x, ' ');\r
+    }\r
+    inpass = ((rp = roomin(&hero)) == NULL);\r
+    ey = hero.y + 1;\r
+    ex = hero.x + 1;\r
+    for (x = hero.x - 1; x <= ex; x++)\r
+       if (x >= 0 && x < COLS) for (y = hero.y - 1; y <= ey; y++)\r
+       {\r
+           if (y <= 0 || y >= LINES - 1)\r
+               continue;\r
+           if (isupper(mvwinch(mw, y, x)))\r
+           {\r
+               register struct linked_list *it;\r
+               register struct thing *tp;\r
+\r
+               if (wakeup)\r
+                   it = wake_monster(y, x);\r
+               else\r
+                   it = find_mons(y, x);\r
+               tp = (struct thing *) ldata(it);\r
+               if ((tp->t_oldch = mvinch(y, x)) == TRAP)\r
+                   tp->t_oldch =\r
+                       (trap_at(y,x)->tr_flags&ISFOUND) ? TRAP : FLOOR;\r
+               if (tp->t_oldch == FLOOR && (rp->r_flags & ISDARK)\r
+                   && off(player, ISBLIND))\r
+                       tp->t_oldch = ' ';\r
+           }\r
+           /*\r
+            * Secret doors show as walls\r
+            */\r
+           if ((ch = show(y, x)) == SECRETDOOR)\r
+               ch = secretdoor(y, x);\r
+           /*\r
+            * Don't show room walls if he is in a passage\r
+            */\r
+           if (off(player, ISBLIND))\r
+           {\r
+               if (y == hero.y && x == hero.x\r
+                || (inpass && (ch == '-' || ch == '|')))\r
+                       continue;\r
+           }\r
+           else if (y != hero.y || x != hero.x)\r
+               continue;\r
+           wmove(cw, y, x);\r
+           waddch(cw, ch);\r
+           if (door_stop && !firstmove && running)\r
+           {\r
+               switch (runch)\r
+               {\r
+                   case 'h':\r
+                       if (x == ex)\r
+                           continue;\r
+                   when 'j':\r
+                       if (y == hero.y - 1)\r
+                           continue;\r
+                   when 'k':\r
+                       if (y == ey)\r
+                           continue;\r
+                   when 'l':\r
+                       if (x == hero.x - 1)\r
+                           continue;\r
+                   when 'y':\r
+                       if ((x + y) - (hero.x + hero.y) >= 1)\r
+                           continue;\r
+                   when 'u':\r
+                       if ((y - x) - (hero.y - hero.x) >= 1)\r
+                           continue;\r
+                   when 'n':\r
+                       if ((x + y) - (hero.x + hero.y) <= -1)\r
+                           continue;\r
+                   when 'b':\r
+                       if ((y - x) - (hero.y - hero.x) <= -1)\r
+                           continue;\r
+               }\r
+               switch (ch)\r
+               {\r
+                   case DOOR:\r
+                       if (x == hero.x || y == hero.y)\r
+                           running = FALSE;\r
+                       break;\r
+                   case PASSAGE:\r
+                       if (x == hero.x || y == hero.y)\r
+                           passcount++;\r
+                       break;\r
+                   case FLOOR:\r
+                   case '|':\r
+                   case '-':\r
+                   case ' ':\r
+                       break;\r
+                   default:\r
+                       running = FALSE;\r
+                       break;\r
+               }\r
+           }\r
+       }\r
+    if (door_stop && !firstmove && passcount > 1)\r
+       running = FALSE;\r
+    mvwaddch(cw, hero.y, hero.x, PLAYER);\r
+    wmove(cw, oldy, oldx);\r
+    oldpos = hero;\r
+    oldrp = rp;\r
+}\r
+\r
+/*\r
+ * secret_door:\r
+ *     Figure out what a secret door looks like.\r
+ */\r
+\r
+secretdoor(y, x)\r
+register int y, x;\r
+{\r
+    register int i;\r
+    register struct room *rp;\r
+    register coord *cpp;\r
+    static coord cp;\r
+\r
+    cp.y = y;\r
+    cp.x = x;\r
+    cpp = &cp;\r
+    for (rp = rooms, i = 0; i < MAXROOMS; rp++, i++)\r
+       if (inroom(rp, cpp))\r
+           if (y == rp->r_pos.y || y == rp->r_pos.y + rp->r_max.y - 1)\r
+               return('-');\r
+           else\r
+               return('|');\r
+\r
+    return('p');\r
+}\r
+\r
+/*\r
+ * find_obj:\r
+ *     find the unclaimed object at y, x\r
+ */\r
+\r
+struct linked_list *\r
+find_obj(y, x)\r
+register int y;\r
+int x;\r
+{\r
+    register struct linked_list *obj;\r
+    register struct object *op;\r
+\r
+    for (obj = lvl_obj; obj != NULL; obj = next(obj))\r
+    {\r
+       op = (struct object *) ldata(obj);\r
+       if (op->o_pos.y == y && op->o_pos.x == x)\r
+               return obj;\r
+    }\r
+    sprintf(prbuf, "Non-object %d,%d", y, x);\r
+    debug(prbuf);\r
+    return NULL;\r
+}\r
+\r
+/*\r
+ * eat:\r
+ *     She wants to eat something, so let her try\r
+ */\r
+\r
+eat()\r
+{\r
+    register struct linked_list *item;\r
+    register struct object *obj;\r
+\r
+    if ((item = get_item("eat", FOOD)) == NULL)\r
+       return;\r
+    obj = (struct object *) ldata(item);\r
+    if (obj->o_type != FOOD)\r
+    {\r
+       if (!terse)\r
+           msg("Ugh, you would get ill if you ate that.");\r
+       else\r
+           msg("That's Inedible!");\r
+       return;\r
+    }\r
+    inpack--;\r
+    if (obj->o_which == 1)\r
+       msg("My, that was a yummy %s", fruit);\r
+    else\r
+       if (rnd(100) > 70)\r
+       {\r
+           msg("Yuk, this food tastes awful");\r
+           pstats.s_exp++;\r
+           check_level();\r
+       }\r
+       else\r
+           msg("Yum, that tasted good");\r
+    if ((food_left += HUNGERTIME + rnd(400) - 200) > STOMACHSIZE)\r
+       food_left = STOMACHSIZE;\r
+    hungry_state = 0;\r
+    if (obj == cur_weapon)\r
+       cur_weapon = NULL;\r
+    if (--obj->o_count < 1)\r
+    {\r
+       detach(pack, item);\r
+       discard(item);\r
+    }\r
+}\r
+\r
+/*\r
+ * Used to modify the playes strength\r
+ * it keeps track of the highest it has been, just in case\r
+ */\r
+\r
+chg_str(amt)\r
+register int amt;\r
+{\r
+    if (amt == 0)\r
+       return;\r
+    if (amt > 0)\r
+    {\r
+       while (amt--)\r
+       {\r
+           if (pstats.s_str.st_str < 18)\r
+               pstats.s_str.st_str++;\r
+           else if (pstats.s_str.st_add == 0)\r
+               pstats.s_str.st_add = rnd(50) + 1;\r
+           else if (pstats.s_str.st_add <= 50)\r
+               pstats.s_str.st_add = 51 + rnd(24);\r
+           else if (pstats.s_str.st_add <= 75)\r
+               pstats.s_str.st_add = 76 + rnd(14);\r
+           else if (pstats.s_str.st_add <= 90)\r
+               pstats.s_str.st_add = 91;\r
+           else if (pstats.s_str.st_add < 100)\r
+               pstats.s_str.st_add++;\r
+       }\r
+       if (pstats.s_str.st_str > max_stats.s_str.st_str ||\r
+           (pstats.s_str.st_str == 18 &&\r
+            pstats.s_str.st_add > max_stats.s_str.st_add))\r
+               max_stats.s_str = pstats.s_str;\r
+    }\r
+    else\r
+    {\r
+       while (amt++)\r
+       {\r
+           if (pstats.s_str.st_str < 18 || pstats.s_str.st_add == 0)\r
+               pstats.s_str.st_str--;\r
+           else if (pstats.s_str.st_add < 51)\r
+               pstats.s_str.st_add = 0;\r
+           else if (pstats.s_str.st_add < 76)\r
+               pstats.s_str.st_add = 1 + rnd(50);\r
+           else if (pstats.s_str.st_add < 91)\r
+               pstats.s_str.st_add = 51 + rnd(25);\r
+           else if (pstats.s_str.st_add < 100)\r
+               pstats.s_str.st_add = 76 + rnd(14);\r
+           else\r
+               pstats.s_str.st_add = 91 + rnd(8);\r
+       }\r
+       if (pstats.s_str.st_str < 3)\r
+           pstats.s_str.st_str = 3;\r
+    }\r
+}\r
+\r
+/*\r
+ * add_haste:\r
+ *     add a haste to the player\r
+ */\r
+\r
+add_haste(potion)\r
+bool potion;\r
+{\r
+    if (on(player, ISHASTE))\r
+    {\r
+       msg("You faint from exhaustion.");\r
+       no_command += rnd(8);\r
+       extinguish(nohaste);\r
+    }\r
+    else\r
+    {\r
+       player.t_flags |= ISHASTE;\r
+       if (potion)\r
+           fuse(nohaste, 0, rnd(4)+4, AFTER);\r
+    }\r
+}\r
+\r
+/*\r
+ * aggravate:\r
+ *     aggravate all the monsters on this level\r
+ */\r
+\r
+aggravate()\r
+{\r
+    register struct linked_list *mi;\r
+\r
+    for (mi = mlist; mi != NULL; mi = next(mi))\r
+       runto(&((struct thing *) ldata(mi))->t_pos, &hero);\r
+}\r
+\r
+/*\r
+ * for printfs: if string starts with a vowel, return "n" for an "an"\r
+ */\r
+char *\r
+vowelstr(str)\r
+register char *str;\r
+{\r
+    switch (*str)\r
+    {\r
+       case 'a':\r
+       case 'e':\r
+       case 'i':\r
+       case 'o':\r
+       case 'u':\r
+           return "n";\r
+       default:\r
+           return "";\r
+    }\r
+}\r
+\r
+/* \r
+ * see if the object is one of the currently used items\r
+ */\r
+is_current(obj)\r
+register struct object *obj;\r
+{\r
+    if (obj == NULL)\r
+       return FALSE;\r
+    if (obj == cur_armor || obj == cur_weapon || obj == cur_ring[LEFT]\r
+       || obj == cur_ring[RIGHT])\r
+    {\r
+       msg(terse ? "In use." : "That's already in use.");\r
+       return TRUE;\r
+    }\r
+    return FALSE;\r
+}\r
+\r
+/*\r
+ * set up the direction co_ordinate for use in varios "prefix" commands\r
+ */\r
+get_dir()\r
+{\r
+    register char *prompt;\r
+    register bool gotit;\r
+\r
+    if (!terse)\r
+       msg(prompt = "Which direction? ");\r
+    else\r
+       prompt = "Direction: ";\r
+    do\r
+    {\r
+       gotit = TRUE;\r
+       switch (readchar(cw))\r
+       {\r
+           case 'h': case'H': delta.y =  0; delta.x = -1;\r
+           when 'j': case'J': delta.y =  1; delta.x =  0;\r
+           when 'k': case'K': delta.y = -1; delta.x =  0;\r
+           when 'l': case'L': delta.y =  0; delta.x =  1;\r
+           when 'y': case'Y': delta.y = -1; delta.x = -1;\r
+           when 'u': case'U': delta.y = -1; delta.x =  1;\r
+           when 'b': case'B': delta.y =  1; delta.x = -1;\r
+           when 'n': case'N': delta.y =  1; delta.x =  1;\r
+           when ESCAPE: return FALSE;\r
+           otherwise:\r
+               mpos = 0;\r
+               msg(prompt);\r
+               gotit = FALSE;\r
+       }\r
+    } until (gotit);\r
+    if (on(player, ISHUH) && rnd(100) > 80)\r
+       do\r
+       {\r
+           delta.y = rnd(3) - 1;\r
+           delta.x = rnd(3) - 1;\r
+       } while (delta.y == 0 && delta.x == 0);\r
+    mpos = 0;\r
+    return TRUE;\r
+}\r
diff --git a/monsters.c b/monsters.c
new file mode 100644 (file)
index 0000000..8121959
--- /dev/null
@@ -0,0 +1,240 @@
+/*\r
+ * File with various monster functions in it\r
+ *\r
+ * @(#)monsters.c      3.18 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include "rogue.h"\r
+#include <string.h>\r
+#include <ctype.h>\r
+\r
+/*\r
+ * List of monsters in rough order of vorpalness\r
+ */\r
+char lvl_mons[27] =  "KJBSHEAOZGLCRQNYTWFIXUMVDP";\r
+char wand_mons[27] = "KJBSH AOZG CRQ Y W IXU V  ";\r
+\r
+/*\r
+ * randmonster:\r
+ *     Pick a monster to show up.  The lower the level,\r
+ *     the meaner the monster.\r
+ */\r
+\r
+randmonster(wander)\r
+bool wander;\r
+{\r
+    register int d;\r
+    register char *mons;\r
+\r
+    mons = wander ? wand_mons : lvl_mons;\r
+    do\r
+    {\r
+       d = level + (rnd(10) - 5);\r
+       if (d < 1)\r
+           d = rnd(5) + 1;\r
+       if (d > 26)\r
+           d = rnd(5) + 22;\r
+    } while (mons[--d] == ' ');\r
+    return mons[d];\r
+}\r
+\r
+/*\r
+ * new_monster:\r
+ *     Pick a new monster and add it to the list\r
+ */\r
+\r
+new_monster(item, type, cp)\r
+struct linked_list *item;\r
+char type;\r
+register coord *cp;\r
+{\r
+    register struct thing *tp;\r
+    register struct monster *mp;\r
+\r
+    attach(mlist, item);\r
+    tp = (struct thing *) ldata(item);\r
+    tp->t_type = type;\r
+    tp->t_pos = *cp;\r
+    tp->t_oldch = mvwinch(cw, cp->y, cp->x);\r
+    mvwaddch(mw, cp->y, cp->x, tp->t_type);\r
+    mp = &monsters[tp->t_type-'A'];\r
+    tp->t_stats.s_hpt = roll(mp->m_stats.s_lvl, 8);\r
+    tp->t_stats.s_lvl = mp->m_stats.s_lvl;\r
+    tp->t_stats.s_arm = mp->m_stats.s_arm;\r
+    strcpy(tp->t_stats.s_dmg,mp->m_stats.s_dmg);\r
+    tp->t_stats.s_exp = mp->m_stats.s_exp;\r
+    tp->t_stats.s_str.st_str = 10;\r
+    tp->t_flags = mp->m_flags;\r
+    tp->t_turn = TRUE;\r
+    tp->t_pack = NULL;\r
+    if (ISWEARING(R_AGGR))\r
+       runto(cp, &hero);\r
+    if (type == 'M')\r
+    {\r
+       char mch;\r
+\r
+       if (tp->t_pack != NULL)\r
+           mch = ((struct object *) ldata(tp->t_pack))->o_type;\r
+       else\r
+           switch (rnd(level > 25 ? 9 : 8))\r
+           {\r
+               case 0: mch = GOLD;\r
+               when 1: mch = POTION;\r
+               when 2: mch = SCROLL;\r
+               when 3: mch = STAIRS;\r
+               when 4: mch = WEAPON;\r
+               when 5: mch = ARMOR;\r
+               when 6: mch = RING;\r
+               when 7: mch = STICK;\r
+               when 8: mch = AMULET;\r
+           }\r
+       tp->t_disguise = mch;\r
+    }\r
+}\r
+\r
+/*\r
+ * wanderer:\r
+ *     A wandering monster has awakened and is headed for the player\r
+ */\r
+\r
+wanderer()\r
+{\r
+    register int i, ch;\r
+    register struct room *rp, *hr = roomin(&hero);\r
+    register struct linked_list *item;\r
+    register struct thing *tp;\r
+    coord cp;\r
+\r
+    item = new_item(sizeof *tp);\r
+    do\r
+    {\r
+       i = rnd_room();\r
+       if ((rp = &rooms[i]) == hr)\r
+           continue;\r
+       rnd_pos(rp, &cp);\r
+       if ((ch = mvwinch(stdscr, cp.y, cp.x)) == ERR)\r
+       {\r
+           debug("Routine wanderer: mvwinch failed to %d,%d", cp.y, cp.x);\r
+           if (wizard)\r
+               wait_for(cw,'\n');\r
+           return;\r
+       }\r
+    } until(hr != rp && step_ok(ch));\r
+    new_monster(item, randmonster(TRUE), &cp);\r
+    tp = (struct thing *) ldata(item);\r
+    tp->t_flags |= ISRUN;\r
+    tp->t_pos = cp;\r
+    tp->t_dest = &hero;\r
+    if (wizard)\r
+       msg("Started a wandering %s", monsters[tp->t_type-'A'].m_name);\r
+}\r
+\r
+/*\r
+ * what to do when the hero steps next to a monster\r
+ */\r
+struct linked_list *\r
+wake_monster(y, x)\r
+int y, x;\r
+{\r
+    register struct thing *tp;\r
+    register struct linked_list *it;\r
+    register struct room *rp;\r
+    register char ch;\r
+\r
+    if ((it = find_mons(y, x)) == NULL)\r
+       fatal("Can't find monster in wake");\r
+    tp = (struct thing *) ldata(it);\r
+    ch = tp->t_type;\r
+    /*\r
+     * Every time he sees mean monster, it might start chasing him\r
+     */\r
+    if (rnd(100) > 33 && on(*tp, ISMEAN) && off(*tp, ISHELD)\r
+       && !ISWEARING(R_STEALTH))\r
+    {\r
+       tp->t_dest = &hero;\r
+       tp->t_flags |= ISRUN;\r
+    }\r
+    if (ch == 'U' && off(player, ISBLIND))\r
+    {\r
+        rp = roomin(&hero);\r
+       if ((rp != NULL && !(rp->r_flags&ISDARK))\r
+           || DISTANCE(y, x, hero.y, hero.x) < 3)\r
+       {\r
+           if (off(*tp, ISFOUND) && !save(VS_MAGIC))\r
+           {\r
+               msg("The umber hulk's gaze has confused you.");\r
+               if (on(player, ISHUH))\r
+                   lengthen(unconfuse, rnd(20)+HUHDURATION);\r
+               else\r
+                   fuse(unconfuse, 0, rnd(20)+HUHDURATION, AFTER);\r
+               player.t_flags |= ISHUH;\r
+           }\r
+           tp->t_flags |= ISFOUND;\r
+       }\r
+    }\r
+    /*\r
+     * Hide invisible monsters\r
+     */\r
+    if (on(*tp, ISINVIS) && off(player, CANSEE))\r
+       ch = mvwinch(stdscr, y, x);\r
+    /*\r
+     * Let greedy ones guard gold\r
+     */\r
+    if (on(*tp, ISGREED) && off(*tp, ISRUN))\r
+    {\r
+        rp = roomin(&hero);\r
+\r
+       if (rp != NULL && rp->r_goldval)\r
+       {\r
+           tp->t_dest = &rp->r_gold;\r
+           tp->t_flags |= ISRUN;\r
+       }\r
+    }\r
+\r
+    return it;\r
+}\r
+\r
+genocide()\r
+{\r
+    register struct linked_list *ip;\r
+    register struct thing *mp;\r
+    register char c;\r
+    register int i;\r
+    register struct linked_list *nip;\r
+\r
+    addmsg("Which monster");\r
+    if (!terse)\r
+       addmsg(" do you wish to wipe out");\r
+    msg("? ");\r
+    while (!isalpha(c = readchar(cw)))\r
+       if (c == ESCAPE)\r
+           return;\r
+       else\r
+       {\r
+           mpos = 0;\r
+           msg("Please specify a letter between 'A' and 'Z'");\r
+       }\r
+    if (islower(c))\r
+       c = toupper(c);\r
+    for (ip = mlist; ip; ip = nip)\r
+    {\r
+       mp = (struct thing *) ldata(ip);\r
+       nip = next(ip);\r
+       if (mp->t_type == c)\r
+           remove_monster(&mp->t_pos, ip);\r
+    }\r
+    for (i = 0; i < 26; i++)\r
+       if (lvl_mons[i] == c)\r
+       {\r
+           lvl_mons[i] = ' ';\r
+           wand_mons[i] = ' ';\r
+           break;\r
+       }\r
+}\r
diff --git a/move.c b/move.c
new file mode 100644 (file)
index 0000000..e49107b
--- /dev/null
+++ b/move.c
@@ -0,0 +1,385 @@
+/*\r
+ * Hero movement commands\r
+ *\r
+ * @(#)move.c  3.26 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <ctype.h>\r
+#include "rogue.h"\r
+\r
+/*\r
+ * Used to hold the new hero position\r
+ */\r
+\r
+coord nh;\r
+\r
+/*\r
+ * do_run:\r
+ *     Start the hero running\r
+ */\r
+\r
+do_run(ch)\r
+char ch;\r
+{\r
+    running = TRUE;\r
+    after = FALSE;\r
+    runch = ch;\r
+}\r
+\r
+/*\r
+ * do_move:\r
+ *     Check to see that a move is legal.  If it is handle the\r
+ * consequences (fighting, picking up, etc.)\r
+ */\r
+\r
+do_move(dy, dx)\r
+int dy, dx;\r
+{\r
+    register char ch;\r
+\r
+    firstmove = FALSE;\r
+    if (no_move)\r
+    {\r
+       no_move--;\r
+       msg("You are still stuck in the bear trap");\r
+       return;\r
+    }\r
+    /*\r
+     * Do a confused move (maybe)\r
+     */\r
+    if (rnd(100) < 80 && on(player, ISHUH))\r
+       nh = *rndmove(&player);\r
+    else\r
+    {\r
+       nh.y = hero.y + dy;\r
+       nh.x = hero.x + dx;\r
+    }\r
+\r
+    /*\r
+     * Check if he tried to move off the screen or make an illegal\r
+     * diagonal move, and stop him if he did.\r
+     */\r
+    if (nh.x < 0 || nh.x > COLS-1 || nh.y < 0 || nh.y > LINES - 1\r
+       || !diag_ok(&hero, &nh))\r
+    {\r
+       after = FALSE;\r
+       running = FALSE;\r
+       return;\r
+    }\r
+    if (running && ce(hero, nh))\r
+       after = running = FALSE;\r
+    ch = winat(nh.y, nh.x);\r
+    if (on(player, ISHELD) && ch != 'F')\r
+    {\r
+       msg("You are being held");\r
+       return;\r
+    }\r
+    switch(ch)\r
+    {\r
+       case ' ':\r
+       case '|':\r
+       case '-':\r
+       case SECRETDOOR:\r
+           after = running = FALSE;\r
+           return;\r
+       case TRAP:\r
+           ch = be_trapped(&nh);\r
+           if (ch == TRAPDOOR || ch == TELTRAP)\r
+               return;\r
+           goto move_stuff;\r
+       case GOLD:\r
+       case POTION:\r
+       case SCROLL:\r
+       case FOOD:\r
+       case WEAPON:\r
+       case ARMOR:\r
+       case RING:\r
+       case AMULET:\r
+       case STICK:\r
+           running = FALSE;\r
+           take = ch;\r
+       default:\r
+move_stuff:\r
+           if (ch == PASSAGE && winat(hero.y, hero.x) == DOOR)\r
+               light(&hero);\r
+           else if (ch == DOOR)\r
+           {\r
+               running = FALSE;\r
+               if (winat(hero.y, hero.x) == PASSAGE)\r
+                   light(&nh);\r
+           }\r
+           else if (ch == STAIRS)\r
+               running = FALSE;\r
+           else if (isupper(ch))\r
+           {\r
+               running = FALSE;\r
+               fight(&nh, ch, cur_weapon, FALSE);\r
+               return;\r
+           }\r
+           ch = winat(hero.y, hero.x);\r
+           wmove(cw, unc(hero));\r
+           waddch(cw, ch);\r
+           hero = nh;\r
+           wmove(cw, unc(hero));\r
+           waddch(cw, PLAYER);\r
+    }\r
+}\r
+\r
+/*\r
+ * Called to illuminate a room.\r
+ * If it is dark, remove anything that might move.\r
+ */\r
+\r
+light(cp)\r
+coord *cp;\r
+{\r
+    register struct room *rp;\r
+    register int j, k;\r
+    register char ch, rch;\r
+    register struct linked_list *item;\r
+\r
+    if ((rp = roomin(cp)) != NULL && !on(player, ISBLIND))\r
+    {\r
+       for (j = 0; j < rp->r_max.y; j++)\r
+       {\r
+           for (k = 0; k < rp->r_max.x; k++)\r
+           {\r
+               ch = show(rp->r_pos.y + j, rp->r_pos.x + k);\r
+               wmove(cw, rp->r_pos.y + j, rp->r_pos.x + k);\r
+               /*\r
+                * Figure out how to display a secret door\r
+                */\r
+               if (ch == SECRETDOOR)\r
+               {\r
+                   if (j == 0 || j == rp->r_max.y - 1)\r
+                       ch = '-';\r
+                   else\r
+                       ch = '|';\r
+               }\r
+               /*\r
+                * If the room is a dark room, we might want to remove\r
+                * monsters and the like from it (since they might\r
+                * move)\r
+                */\r
+               if (isupper(ch))\r
+               {\r
+                   item = wake_monster(rp->r_pos.y+j, rp->r_pos.x+k);\r
+                   if (((struct thing *) ldata(item))->t_oldch == ' ')\r
+                       if (!(rp->r_flags & ISDARK))\r
+                           ((struct thing *) ldata(item))->t_oldch =\r
+                               mvwinch(stdscr, rp->r_pos.y+j, rp->r_pos.x+k);\r
+               }\r
+               if (rp->r_flags & ISDARK)\r
+               {\r
+                   rch = mvwinch(cw, rp->r_pos.y+j, rp->r_pos.x+k);\r
+                   switch (rch)\r
+                   {\r
+                       case DOOR:\r
+                       case STAIRS:\r
+                       case TRAP:\r
+                       case '|':\r
+                       case '-':\r
+                       case ' ':\r
+                           ch = rch;\r
+                       when FLOOR:\r
+                           ch = (on(player, ISBLIND) ? FLOOR : ' ');\r
+                       otherwise:\r
+                           ch = ' ';\r
+                   }\r
+               }\r
+               mvwaddch(cw, rp->r_pos.y+j, rp->r_pos.x+k, ch);\r
+           }\r
+       }\r
+    }\r
+}\r
+\r
+/*\r
+ * show:\r
+ *     returns what a certain thing will display as to the un-initiated\r
+ */\r
+\r
+show(y, x)\r
+register int y, x;\r
+{\r
+    register char ch = winat(y, x);\r
+    register struct linked_list *it;\r
+    register struct thing *tp;\r
+\r
+    if (ch == TRAP)\r
+       return (trap_at(y, x)->tr_flags & ISFOUND) ? TRAP : FLOOR;\r
+    else if (ch == 'M' || ch == 'I')\r
+    {\r
+       if ((it = find_mons(y, x)) == NULL)\r
+           fatal("Can't find monster in show");\r
+       tp = (struct thing *) ldata(it);\r
+       if (ch == 'M')\r
+           ch = tp->t_disguise;\r
+       /*\r
+        * Hide invisible monsters\r
+        */\r
+       else if (off(player, CANSEE))\r
+           ch = mvwinch(stdscr, y, x);\r
+    }\r
+    return ch;\r
+}\r
+\r
+/*\r
+ * be_trapped:\r
+ *     The guy stepped on a trap.... Make him pay.\r
+ */\r
+\r
+be_trapped(tc)\r
+register coord *tc;\r
+{\r
+    register struct trap *tp;\r
+    register char ch;\r
+\r
+    tp = trap_at(tc->y, tc->x);\r
+    count = running = FALSE;\r
+    mvwaddch(cw, tp->tr_pos.y, tp->tr_pos.x, TRAP);\r
+    tp->tr_flags |= ISFOUND;\r
+    switch (ch = tp->tr_type)\r
+    {\r
+       case TRAPDOOR:\r
+           level++;\r
+           new_level();\r
+           msg("You fell into a trap!");\r
+       when BEARTRAP:\r
+           no_move += BEARTIME;\r
+           msg("You are caught in a bear trap");\r
+       when SLEEPTRAP:\r
+           no_command += SLEEPTIME;\r
+           msg("A strange white mist envelops you and you fall asleep");\r
+       when ARROWTRAP:\r
+           if (swing(pstats.s_lvl-1, pstats.s_arm, 1))\r
+           {\r
+               msg("Oh no! An arrow shot you");\r
+               if ((pstats.s_hpt -= roll(1, 6)) <= 0)\r
+               {\r
+                   msg("The arrow killed you.");\r
+                   death('a');\r
+               }\r
+           }\r
+           else\r
+           {\r
+               register struct linked_list *item;\r
+               register struct object *arrow;\r
+\r
+               msg("An arrow shoots past you.");\r
+               item = new_item(sizeof *arrow);\r
+               arrow = (struct object *) ldata(item);\r
+               arrow->o_type = WEAPON;\r
+               arrow->o_which = ARROW;\r
+               init_weapon(arrow, ARROW);\r
+               arrow->o_count = 1;\r
+               arrow->o_pos = hero;\r
+               arrow->o_hplus = arrow->o_dplus = 0; /* "arrow bug" FIX */\r
+               fall(item, FALSE);\r
+           }\r
+       when TELTRAP:\r
+           teleport();\r
+       when DARTTRAP:\r
+           if (swing(pstats.s_lvl+1, pstats.s_arm, 1))\r
+           {\r
+               msg("A small dart just hit you in the shoulder");\r
+               if ((pstats.s_hpt -= roll(1, 4)) <= 0)\r
+               {\r
+                   msg("The dart killed you.");\r
+                   death('d');\r
+               }\r
+               if (!ISWEARING(R_SUSTSTR))\r
+                   chg_str(-1);\r
+           }\r
+           else\r
+               msg("A small dart whizzes by your ear and vanishes.");\r
+    }\r
+    flush_type();      /* flush typeahead */\r
+    return(ch);\r
+}\r
+\r
+/*\r
+ * trap_at:\r
+ *     find the trap at (y,x) on screen.\r
+ */\r
+\r
+struct trap *\r
+trap_at(y, x)\r
+register int y, x;\r
+{\r
+    register struct trap *tp, *ep;\r
+\r
+    ep = &traps[ntraps];\r
+    for (tp = traps; tp < ep; tp++)\r
+       if (tp->tr_pos.y == y && tp->tr_pos.x == x)\r
+           break;\r
+    if (tp == ep)\r
+    {\r
+       sprintf(prbuf, "Trap at %d,%d not in array", y, x);\r
+       fatal(prbuf);\r
+    }\r
+    return tp;\r
+}\r
+\r
+/*\r
+ * rndmove:\r
+ *     move in a random direction if the monster/person is confused\r
+ */\r
+\r
+coord *\r
+rndmove(who)\r
+struct thing *who;\r
+{\r
+    register int x, y;\r
+    register char ch;\r
+    register int ex, ey, nopen = 0;\r
+    register struct linked_list *item;\r
+    register struct object *obj;\r
+    static coord ret;  /* what we will be returning */\r
+    static coord dest;\r
+\r
+    ret = who->t_pos;\r
+    /*\r
+     * Now go through the spaces surrounding the player and\r
+     * set that place in the array to true if the space can be\r
+     * moved into\r
+     */\r
+    ey = ret.y + 1;\r
+    ex = ret.x + 1;\r
+    for (y = who->t_pos.y - 1; y <= ey; y++)\r
+       if (y >= 0 && y < LINES)\r
+           for (x = who->t_pos.x - 1; x <= ex; x++)\r
+           {\r
+               if (x < 0 || x >= COLS)\r
+                   continue;\r
+               ch = winat(y, x);\r
+               if (step_ok(ch))\r
+               {\r
+                   dest.y = y;\r
+                   dest.x = x;\r
+                   if (!diag_ok(&who->t_pos, &dest))\r
+                       continue;\r
+                   if (ch == SCROLL)\r
+                   {\r
+                       item = NULL;\r
+                       for (item = lvl_obj; item != NULL; item = next(item))\r
+                       {\r
+                           obj = (struct object *) ldata(item);\r
+                           if (y == obj->o_pos.y && x == obj->o_pos.x)\r
+                               break;\r
+                       }\r
+                       if (item != NULL && obj->o_which == S_SCARE)\r
+                           continue;\r
+                   }\r
+                   if (rnd(++nopen) == 0)\r
+                       ret = dest;\r
+               }\r
+           }\r
+    return &ret;\r
+}\r
diff --git a/newlevel.c b/newlevel.c
new file mode 100644 (file)
index 0000000..3f20c21
--- /dev/null
@@ -0,0 +1,173 @@
+/*\r
+ * new_level:\r
+ *     Dig and draw a new level\r
+ *\r
+ * @(#)new_level.c     3.7 (Berkeley) 6/2/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include "rogue.h"\r
+\r
+#include <string.h>\r
+\r
+new_level()\r
+{\r
+    register int rm, i;\r
+    register char ch;\r
+    coord stairs;\r
+\r
+    if (level > max_level)\r
+       max_level = level;\r
+    wclear(cw);\r
+    wclear(mw);\r
+    clear();\r
+    status();\r
+    /*\r
+     * Free up the monsters on the last level\r
+     */\r
+    free_list(mlist);\r
+    do_rooms();                                /* Draw rooms */\r
+    do_passages();                     /* Draw passages */\r
+    no_food++;\r
+    put_things();                      /* Place objects (if any) */\r
+    /*\r
+     * Place the staircase down.\r
+     */\r
+    do {\r
+        rm = rnd_room();\r
+       rnd_pos(&rooms[rm], &stairs);\r
+    } until (winat(stairs.y, stairs.x) == FLOOR);\r
+    addch(STAIRS);\r
+    /*\r
+     * Place the traps\r
+     */\r
+    if (rnd(10) < level)\r
+    {\r
+       ntraps = rnd(level/4)+1;\r
+       if (ntraps > MAXTRAPS)\r
+           ntraps = MAXTRAPS;\r
+       i = ntraps;\r
+       while (i--)\r
+       {\r
+           do\r
+           {\r
+               rm = rnd_room();\r
+               rnd_pos(&rooms[rm], &stairs);\r
+           } until (winat(stairs.y, stairs.x) == FLOOR);\r
+           switch(rnd(6))\r
+           {\r
+               case 0: ch = TRAPDOOR;\r
+               when 1: ch = BEARTRAP;\r
+               when 2: ch = SLEEPTRAP;\r
+               when 3: ch = ARROWTRAP;\r
+               when 4: ch = TELTRAP;\r
+               when 5: ch = DARTTRAP;\r
+           }\r
+           addch(TRAP);\r
+           traps[i].tr_type = ch;\r
+           traps[i].tr_flags = 0;\r
+           traps[i].tr_pos = stairs;\r
+       }\r
+    }\r
+    do\r
+    {\r
+       rm = rnd_room();\r
+       rnd_pos(&rooms[rm], &hero);\r
+    }\r
+    until(winat(hero.y, hero.x) == FLOOR);\r
+    light(&hero);\r
+    wmove(cw, hero.y, hero.x);\r
+    waddch(cw, PLAYER);\r
+}\r
+\r
+/*\r
+ * Pick a room that is really there\r
+ */\r
+\r
+rnd_room()\r
+{\r
+    register int rm;\r
+\r
+    do\r
+    {\r
+       rm = rnd(MAXROOMS);\r
+    } while (rooms[rm].r_flags & ISGONE);\r
+    return rm;\r
+}\r
+\r
+/*\r
+ * put_things:\r
+ *     put potions and scrolls on this level\r
+ */\r
+\r
+put_things()\r
+{\r
+    register int i;\r
+    register struct linked_list *item;\r
+    register struct object *cur;\r
+    register int rm;\r
+    coord tp;\r
+\r
+    /*\r
+     * Throw away stuff left on the previous level (if anything)\r
+     */\r
+    free_list(lvl_obj);\r
+    /*\r
+     * Once you have found the amulet, the only way to get new stuff is\r
+     * go down into the dungeon.\r
+     */\r
+    if (amulet && level < max_level)\r
+       return;\r
+    /*\r
+     * Do MAXOBJ attempts to put things on a level\r
+     */\r
+    for (i = 0; i < MAXOBJ; i++)\r
+       if (rnd(100) < 35)\r
+       {\r
+           /*\r
+            * Pick a new object and link it in the list\r
+            */\r
+           item = new_thing();\r
+           attach(lvl_obj, item);\r
+           cur = (struct object *) ldata(item);\r
+           /*\r
+            * Put it somewhere\r
+            */\r
+           rm = rnd_room();\r
+           do {\r
+               rnd_pos(&rooms[rm], &tp);\r
+           } until (winat(tp.y, tp.x) == FLOOR);\r
+           mvaddch(tp.y, tp.x, cur->o_type);\r
+           cur->o_pos = tp;\r
+       }\r
+    /*\r
+     * If he is really deep in the dungeon and he hasn't found the\r
+     * amulet yet, put it somewhere on the ground\r
+     */\r
+    if (level > 25 && !amulet)\r
+    {\r
+       item = new_item(sizeof *cur);\r
+       attach(lvl_obj, item);\r
+       cur = (struct object *) ldata(item);\r
+       cur->o_hplus = cur->o_dplus = 0;\r
+       strcpy(cur->o_damage, "0d0");\r
+       strcpy(cur->o_hurldmg, "0d0");\r
+       cur->o_ac = 11;\r
+       cur->o_type = AMULET;\r
+       /*\r
+        * Put it somewhere\r
+        */\r
+       do {\r
+           rm = rnd_room();\r
+           rnd_pos(&rooms[rm], &tp);\r
+       } until (winat(tp.y, tp.x) == FLOOR);\r
+       mvaddch(tp.y, tp.x, cur->o_type);\r
+       cur->o_pos = tp;\r
+    }\r
+}\r
diff --git a/options.c b/options.c
new file mode 100644 (file)
index 0000000..537e130
--- /dev/null
+++ b/options.c
@@ -0,0 +1,352 @@
+/*\r
+ * This file has all the code for the option command.\r
+ * I would rather this command were not necessary, but\r
+ * it is the only way to keep the wolves off of my back.\r
+ *\r
+ * @(#)options.c       3.3 (Berkeley) 5/25/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <ctype.h>\r
+#include <string.h>\r
+#include "rogue.h"\r
+\r
+#define        NUM_OPTS        (sizeof optlist / sizeof (OPTION))\r
+\r
+/*\r
+ * description of an option and what to do with it\r
+ */\r
+struct optstruct {\r
+    char       *o_name;        /* option name */\r
+    char       *o_prompt;      /* prompt for interactive entry */\r
+    int                *o_opt;         /* pointer to thing to set */\r
+    int                (*o_putfunc)(); /* function to print value */\r
+    int                (*o_getfunc)(); /* function to get value interactively */\r
+};\r
+\r
+typedef struct optstruct       OPTION;\r
+\r
+int    put_bool(), get_bool(), put_str(), get_str();\r
+\r
+OPTION optlist[] = {\r
+    {"terse",   "Terse output: ",\r
+                (int *) &terse,        put_bool,       get_bool        },\r
+    {"flush",   "Flush typeahead during battle: ",\r
+                (int *) &fight_flush,  put_bool,       get_bool        },\r
+    {"jump",    "Show position only at end of run: ",\r
+                (int *) &jump,         put_bool,       get_bool        },\r
+    {"step",   "Do inventories one line at a time: ",\r
+               (int *) &slow_invent,   put_bool,       get_bool        },\r
+    {"askme",  "Ask me about unidentified things: ",\r
+               (int *) &askme,         put_bool,       get_bool        },\r
+    {"name",    "Name: ",\r
+                (int *) whoami,        put_str,        get_str         },\r
+    {"fruit",   "Fruit: ",\r
+                (int *) fruit,         put_str,        get_str         },\r
+    {"file",    "Save file: ",\r
+                (int *) file_name,     put_str,        get_str         }\r
+};\r
+\r
+/*\r
+ * print and then set options from the terminal\r
+ */\r
+option()\r
+{\r
+    register OPTION    *op;\r
+    register int       retval;\r
+\r
+    wclear(hw);\r
+    touchwin(hw);\r
+    /*\r
+     * Display current values of options\r
+     */\r
+    for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++)\r
+    {\r
+       waddstr(hw, op->o_prompt);\r
+       (*op->o_putfunc)(op->o_opt);\r
+       waddch(hw, '\n');\r
+    }\r
+    /*\r
+     * Set values\r
+     */\r
+    wmove(hw, 0, 0);\r
+    for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++)\r
+    {\r
+       waddstr(hw, op->o_prompt);\r
+       if ((retval = (*op->o_getfunc)(op->o_opt, hw)))\r
+           if (retval == QUIT)\r
+               break;\r
+           else if (op > optlist) {    /* MINUS */\r
+               wmove(hw, (op - optlist) - 1, 0);\r
+               op -= 2;\r
+           }\r
+           else        /* trying to back up beyond the top */\r
+           {\r
+               beep();\r
+               wmove(hw, 0, 0);\r
+               op--;\r
+           }\r
+    }\r
+    /*\r
+     * Switch back to original screen\r
+     */\r
+    mvwaddstr(hw, LINES-1, 0, "--Press space to continue--");\r
+    draw(hw);\r
+    wait_for(hw,' ');\r
+    clearok(cw, TRUE);\r
+    touchwin(cw);\r
+    after = FALSE;\r
+}\r
+\r
+/*\r
+ * put out a boolean\r
+ */\r
+put_bool(b)\r
+bool   *b;\r
+{\r
+    waddstr(hw, *b ? "True" : "False");\r
+}\r
+\r
+/*\r
+ * put out a string\r
+ */\r
+put_str(str)\r
+char *str;\r
+{\r
+    waddstr(hw, str);\r
+}\r
+\r
+/*\r
+ * allow changing a boolean option and print it out\r
+ */\r
+\r
+get_bool(bp, win)\r
+bool *bp;\r
+WINDOW *win;\r
+{\r
+    register int oy, ox;\r
+    register bool op_bad;\r
+\r
+    op_bad = TRUE;\r
+    getyx(win, oy, ox);\r
+    waddstr(win, *bp ? "True" : "False");\r
+    while(op_bad)      \r
+    {\r
+       wmove(win, oy, ox);\r
+       draw(win);\r
+       switch (readchar(win))\r
+       {\r
+           case 't':\r
+           case 'T':\r
+               *bp = TRUE;\r
+               op_bad = FALSE;\r
+               break;\r
+           case 'f':\r
+           case 'F':\r
+               *bp = FALSE;\r
+               op_bad = FALSE;\r
+               break;\r
+           case '\n':\r
+           case '\r':\r
+               op_bad = FALSE;\r
+               break;\r
+           case '\033':\r
+           case '\007':\r
+               return QUIT;\r
+           case '-':\r
+               return MINUS;\r
+           default:\r
+               mvwaddstr(win, oy, ox + 10, "(T or F)");\r
+       }\r
+    }\r
+    wmove(win, oy, ox);\r
+    waddstr(win, *bp ? "True" : "False");\r
+    waddch(win, '\n');\r
+    return NORM;\r
+}\r
+\r
+/*\r
+ * set a string option\r
+ */\r
+get_str(opt, win)\r
+register char *opt;\r
+WINDOW *win;\r
+{\r
+    register char *sp;\r
+    register int c, oy, ox;\r
+    char buf[80];\r
+\r
+    draw(win);\r
+    getyx(win, oy, ox);\r
+    /*\r
+     * loop reading in the string, and put it in a temporary buffer\r
+     */\r
+    for (sp = buf;\r
+       (c = readchar(win)) != '\n' && c != '\r' && c != '\033' && c != '\007';\r
+       wclrtoeol(win), draw(win))\r
+    {\r
+       if (c == -1)\r
+           continue;\r
+       else if (c == md_erasechar())   /* process erase character */\r
+       {\r
+           if (sp > buf)\r
+           {\r
+               register int i;\r
+               int myx, myy;\r
+\r
+               sp--;\r
+\r
+               for (i = (int) strlen(unctrl(*sp)); i; i--)\r
+               {\r
+                   getyx(win,myy,myx);\r
+                   if ((myx == 0)&& (myy > 0))\r
+                   {\r
+                       wmove(win,myy-1,getmaxx(win)-1);\r
+                       waddch(win,' ');\r
+                       wmove(win,myy-1,getmaxx(win)-1);\r
+                   }\r
+                   else\r
+                       waddch(win, '\b');\r
+               }\r
+           }\r
+           continue;\r
+       }\r
+       else if (c == md_killchar())    /* process kill character */\r
+       {\r
+           sp = buf;\r
+           wmove(win, oy, ox);\r
+           continue;\r
+       }\r
+       else if (sp == buf)\r
+           if (c == '-')\r
+               break;\r
+           else if (c == '~')\r
+           {\r
+               strcpy(buf, home);\r
+               waddstr(win, home);\r
+               sp += strlen(home);\r
+               continue;\r
+           }\r
+\r
+       if ((sp - buf) < 78) /* Avoid overflow */\r
+       {\r
+           *sp++ = c;\r
+           waddstr(win, unctrl(c));\r
+       }\r
+    }\r
+    *sp = '\0';\r
+    if (sp > buf)      /* only change option if something has been typed */\r
+       strucpy(opt, buf, strlen(buf));\r
+    wmove(win, oy, ox);\r
+    waddstr(win, opt);\r
+    waddch(win, '\n');\r
+    draw(win);\r
+    if (win == cw)\r
+       mpos += sp - buf;\r
+    if (c == '-')\r
+       return MINUS;\r
+    else if (c == '\033' || c == '\007')\r
+       return QUIT;\r
+    else\r
+       return NORM;\r
+}\r
+\r
+/*\r
+ * parse options from string, usually taken from the environment.\r
+ * the string is a series of comma seperated values, with booleans\r
+ * being stated as "name" (true) or "noname" (false), and strings\r
+ * being "name=....", with the string being defined up to a comma\r
+ * or the end of the entire option string.\r
+ */\r
+\r
+parse_opts(str)\r
+register char *str;\r
+{\r
+    register char *sp;\r
+    register OPTION *op;\r
+    register int len;\r
+\r
+    while (*str)\r
+    {\r
+       /*\r
+        * Get option name\r
+        */\r
+       for (sp = str; isalpha(*sp); sp++)\r
+           continue;\r
+       len = sp - str;\r
+       /*\r
+        * Look it up and deal with it\r
+        */\r
+       for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++)\r
+           if (EQSTR(str, op->o_name, len))\r
+           {\r
+               if (op->o_putfunc == put_bool)  /* if option is a boolean */\r
+                   *(bool *)op->o_opt = TRUE;\r
+               else                            /* string option */\r
+               {\r
+                   register char *start;\r
+                   /*\r
+                    * Skip to start of string value\r
+                    */\r
+                   for (str = sp + 1; *str == '='; str++)\r
+                       continue;\r
+                   if (*str == '~')\r
+                   {\r
+                       strcpy((char *) op->o_opt, home);\r
+                       start = (char *) op->o_opt + strlen(home);\r
+                       while (*++str == '/')\r
+                           continue;\r
+                   }\r
+                   else\r
+                       start = (char *) op->o_opt;\r
+                   /*\r
+                    * Skip to end of string value\r
+                    */\r
+                   for (sp = str + 1; *sp && *sp != ','; sp++)\r
+                       continue;\r
+                   strucpy(start, str, sp - str);\r
+               }\r
+               break;\r
+           }\r
+           /*\r
+            * check for "noname" for booleans\r
+            */\r
+           else if (op->o_putfunc == put_bool\r
+             && EQSTR(str, "no", 2) && EQSTR(str + 2, op->o_name, len - 2))\r
+           {\r
+               *(bool *)op->o_opt = FALSE;\r
+               break;\r
+           }\r
+\r
+       /*\r
+        * skip to start of next option name\r
+        */\r
+       while (*sp && !isalpha(*sp))\r
+           sp++;\r
+       str = sp;\r
+    }\r
+}\r
+\r
+/*\r
+ * copy string using unctrl for things\r
+ */\r
+strucpy(s1, s2, len)\r
+register char *s1, *s2;\r
+register int len;\r
+{\r
+    register char *sp;\r
+\r
+    while (len--)\r
+    {\r
+       strcpy(s1, (sp = unctrl(*s2)));\r
+       s1 += strlen(sp);\r
+       s2++;\r
+    }\r
+    *s1 = '\0';\r
+}\r
diff --git a/pack.c b/pack.c
new file mode 100644 (file)
index 0000000..6dcb7f0
--- /dev/null
+++ b/pack.c
@@ -0,0 +1,402 @@
+/*\r
+ * Routines to deal with the pack\r
+ *\r
+ * @(#)pack.c  3.6 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <ctype.h>\r
+#include "rogue.h"\r
+\r
+/*\r
+ * add_pack:\r
+ *     Pick up an object and add it to the pack.  If the argument is non-null\r
+ * use it as the linked_list pointer instead of gettting it off the ground.\r
+ */\r
+add_pack(item, silent)\r
+register struct linked_list *item;\r
+bool silent;\r
+{\r
+    register struct linked_list *ip, *lp;\r
+    register struct object *obj, *op;\r
+    register bool exact, from_floor;\r
+\r
+    if (item == NULL)\r
+    {\r
+       from_floor = TRUE;\r
+       if ((item = find_obj(hero.y, hero.x)) == NULL)\r
+           return;\r
+    }\r
+    else\r
+       from_floor = FALSE;\r
+    obj = (struct object *) ldata(item);\r
+    /*\r
+     * Link it into the pack.  Search the pack for a object of similar type\r
+     * if there isn't one, stuff it at the beginning, if there is, look for one\r
+     * that is exactly the same and just increment the count if there is.\r
+     * it  that.  Food is always put at the beginning for ease of access, but\r
+     * is not ordered so that you can't tell good food from bad.  First check\r
+     * to see if there is something in thr same group and if there is then\r
+     * increment the count.\r
+     */\r
+    if (obj->o_group)\r
+    {\r
+       for (ip = pack; ip != NULL; ip = next(ip))\r
+       {\r
+           op = (struct object *) ldata(ip);\r
+           if (op->o_group == obj->o_group)\r
+           {\r
+               /*\r
+                * Put it in the pack and notify the user\r
+                */\r
+               op->o_count++;\r
+               if (from_floor)\r
+               {\r
+                   detach(lvl_obj, item);\r
+                   mvaddch(hero.y, hero.x,\r
+                       (roomin(&hero) == NULL ? PASSAGE : FLOOR));\r
+               }\r
+               discard(item);\r
+               item = ip;\r
+               goto picked_up;\r
+           }\r
+       }\r
+    }\r
+    /*\r
+     * Check if there is room\r
+     */\r
+    if (inpack == MAXPACK-1)\r
+    {\r
+       msg("You can't carry anything else.");\r
+       return;\r
+    }\r
+    /*\r
+     * Check for and deal with scare monster scrolls\r
+     */\r
+    if (obj->o_type == SCROLL && obj->o_which == S_SCARE)\r
+       if (obj->o_flags & ISFOUND)\r
+       {\r
+           msg("The scroll turns to dust as you pick it up.");\r
+           detach(lvl_obj, item);\r
+           mvaddch(hero.y, hero.x, FLOOR);\r
+           return;\r
+       }\r
+       else\r
+           obj->o_flags |= ISFOUND;\r
+\r
+    inpack++;\r
+    if (from_floor)\r
+    {\r
+       detach(lvl_obj, item);\r
+       mvaddch(hero.y, hero.x, (roomin(&hero) == NULL ? PASSAGE : FLOOR));\r
+    }\r
+    /*\r
+     * Search for an object of the same type\r
+     */\r
+    exact = FALSE;\r
+    for (ip = pack; ip != NULL; ip = next(ip))\r
+    {\r
+       op = (struct object *) ldata(ip);\r
+       if (obj->o_type == op->o_type)\r
+           break;\r
+    }\r
+    if (ip == NULL)\r
+    {\r
+       /*\r
+        * Put it at the end of the pack since it is a new type\r
+        */\r
+       for (ip = pack; ip != NULL; ip = next(ip))\r
+       {\r
+           op = (struct object *) ldata(ip);\r
+           if (op->o_type != FOOD)\r
+               break;\r
+           lp = ip;\r
+       }\r
+    }\r
+    else\r
+    {\r
+       /*\r
+        * Search for an object which is exactly the same\r
+        */\r
+       while (ip != NULL && op->o_type == obj->o_type)\r
+       {\r
+           if (op->o_which == obj->o_which)\r
+           {\r
+               exact = TRUE;\r
+               break;\r
+           }\r
+           lp = ip;\r
+           if ((ip = next(ip)) == NULL)\r
+               break;\r
+           op = (struct object *) ldata(ip);\r
+       }\r
+    }\r
+    if (ip == NULL)\r
+    {\r
+       /*\r
+        * Didn't find an exact match, just stick it here\r
+        */\r
+       if (pack == NULL)\r
+           pack = item;\r
+       else\r
+       {\r
+           lp->l_next = item;\r
+           item->l_prev = lp;\r
+           item->l_next = NULL;\r
+       }\r
+    }\r
+    else\r
+    {\r
+       /*\r
+        * If we found an exact match.  If it is a potion, food, or a \r
+        * scroll, increase the count, otherwise put it with its clones.\r
+        */\r
+       if (exact && ISMULT(obj->o_type))\r
+       {\r
+           op->o_count++;\r
+           discard(item);\r
+           item = ip;\r
+           goto picked_up;\r
+       }\r
+       if ((item->l_prev = prev(ip)) != NULL)\r
+           item->l_prev->l_next = item;\r
+       else\r
+           pack = item;\r
+       item->l_next = ip;\r
+       ip->l_prev = item;\r
+    }\r
+picked_up:\r
+    /*\r
+     * Notify the user\r
+     */\r
+    obj = (struct object *) ldata(item);\r
+    if (notify && !silent)\r
+    {\r
+       if (!terse)\r
+           addmsg("You now have ");\r
+       msg("%s (%c)", inv_name(obj, !terse), pack_char(obj));\r
+    }\r
+    if (obj->o_type == AMULET)\r
+       amulet = TRUE;\r
+}\r
+\r
+/*\r
+ * inventory:\r
+ *     list what is in the pack\r
+ */\r
+inventory(list, type)\r
+struct linked_list *list;\r
+int type;\r
+{\r
+    register struct object *obj;\r
+    register char ch;\r
+    register int n_objs;\r
+    char inv_temp[80];\r
+\r
+    n_objs = 0;\r
+    for (ch = 'a'; list != NULL; ch++, list = next(list))\r
+    {\r
+       obj = (struct object *) ldata(list);\r
+       if (type && type != obj->o_type && !(type == CALLABLE &&\r
+           (obj->o_type == SCROLL || obj->o_type == POTION ||\r
+            obj->o_type == RING || obj->o_type == STICK)))\r
+               continue;\r
+       switch (n_objs++)\r
+       {\r
+           /*\r
+            * For the first thing in the inventory, just save the string\r
+            * in case there is only one.\r
+            */\r
+           case 0:\r
+               sprintf(inv_temp, "%c) %s", ch, inv_name(obj, FALSE));\r
+               break;\r
+           /*\r
+            * If there is more than one, clear the screen, print the\r
+            * saved message and fall through to ...\r
+            */\r
+           case 1:\r
+               if (slow_invent)\r
+                   msg(inv_temp);\r
+               else\r
+               {\r
+                   wclear(hw);\r
+                   waddstr(hw, inv_temp);\r
+                   waddch(hw, '\n');\r
+               }\r
+           /*\r
+            * Print the line for this object\r
+            */\r
+           default:\r
+               if (slow_invent)\r
+                   msg("%c) %s", ch, inv_name(obj, FALSE));\r
+               else\r
+                   wprintw(hw, "%c) %s\n", ch, inv_name(obj, FALSE));\r
+       }\r
+    }\r
+    if (n_objs == 0)\r
+    {\r
+       if (terse)\r
+           msg(type == 0 ? "Empty handed." :\r
+                           "Nothing appropriate");\r
+       else\r
+           msg(type == 0 ? "You are empty handed." :\r
+                           "You don't have anything appropriate");\r
+       return FALSE;\r
+    }\r
+    if (n_objs == 1)\r
+    {\r
+       msg(inv_temp);\r
+       return TRUE;\r
+    }\r
+    if (!slow_invent)\r
+    {\r
+       mvwaddstr(hw, LINES-1, 0, "--Press space to continue--");\r
+       draw(hw);\r
+       wait_for(hw,' ');\r
+       clearok(cw, TRUE);\r
+       touchwin(cw);\r
+    }\r
+    return TRUE;\r
+}\r
+\r
+/*\r
+ * pick_up:\r
+ *     Add something to characters pack.\r
+ */\r
+pick_up(ch)\r
+char ch;\r
+{\r
+    switch(ch)\r
+    {\r
+       case GOLD:\r
+           money();\r
+           break;\r
+       default:\r
+           debug("Where did you pick that up???");\r
+       case ARMOR:\r
+       case POTION:\r
+       case FOOD:\r
+       case WEAPON:\r
+       case SCROLL:    \r
+       case AMULET:\r
+       case RING:\r
+       case STICK:\r
+           add_pack(NULL, FALSE);\r
+           break;\r
+    }\r
+}\r
+\r
+/*\r
+ * picky_inven:\r
+ *     Allow player to inventory a single item\r
+ */\r
+picky_inven()\r
+{\r
+    register struct linked_list *item;\r
+    register char ch, mch;\r
+\r
+    if (pack == NULL)\r
+       msg("You aren't carrying anything");\r
+    else if (next(pack) == NULL)\r
+       msg("a) %s", inv_name((struct object *) ldata(pack), FALSE));\r
+    else\r
+    {\r
+       msg(terse ? "Item: " : "Which item do you wish to inventory: ");\r
+       mpos = 0;\r
+       if ((mch = readchar(cw)) == ESCAPE)\r
+       {\r
+           msg("");\r
+           return;\r
+       }\r
+       for (ch = 'a', item = pack; item != NULL; item = next(item), ch++)\r
+           if (ch == mch)\r
+           {\r
+               msg("%c) %s",ch,inv_name((struct object *) ldata(item), FALSE));\r
+               return;\r
+           }\r
+       if (!terse)\r
+           msg("'%s' not in pack", unctrl(mch));\r
+       msg("Range is 'a' to '%c'", --ch);\r
+    }\r
+}\r
+\r
+/*\r
+ * get_item:\r
+ *     pick something out of a pack for a purpose\r
+ */\r
+struct linked_list *\r
+get_item(purpose, type)\r
+char *purpose;\r
+int type;\r
+{\r
+    register struct linked_list *obj;\r
+    register char ch, och;\r
+\r
+    if (pack == NULL)\r
+       msg("You aren't carrying anything.");\r
+    else\r
+    {\r
+       for (;;)\r
+       {\r
+           if (!terse)\r
+               addmsg("Which object do you want to ");\r
+           addmsg(purpose);\r
+           if (terse)\r
+               addmsg(" what");\r
+           msg("? (* for list): ");\r
+           ch = readchar(cw);\r
+           mpos = 0;\r
+           /*\r
+            * Give the poor player a chance to abort the command\r
+            */\r
+           if (ch == ESCAPE || ch == CTRL('G'))\r
+           {\r
+               after = FALSE;\r
+               msg("");\r
+               return NULL;\r
+           }\r
+           if (ch == '*')\r
+           {\r
+               mpos = 0;\r
+               if (inventory(pack, type) == 0)\r
+               {\r
+                   after = FALSE;\r
+                   return NULL;\r
+               }\r
+               continue;\r
+           }\r
+           for (obj = pack, och = 'a'; obj != NULL; obj = next(obj), och++)\r
+               if (ch == och)\r
+                   break;\r
+           if (obj == NULL)\r
+           {\r
+               msg("Please specify a letter between 'a' and '%c'", och-1);\r
+               continue;\r
+           }\r
+           else \r
+               return obj;\r
+       }\r
+    }\r
+    return NULL;\r
+}\r
+\r
+pack_char(obj)\r
+register struct object *obj;\r
+{\r
+    register struct linked_list *item;\r
+    register char c;\r
+\r
+    c = 'a';\r
+    for (item = pack; item != NULL; item = next(item))\r
+       if ((struct object *) ldata(item) == obj)\r
+           return c;\r
+       else\r
+           c++;\r
+    return 'z';\r
+}\r
diff --git a/passages.c b/passages.c
new file mode 100644 (file)
index 0000000..87314a7
--- /dev/null
@@ -0,0 +1,287 @@
+/*\r
+ * Draw the connecting passages\r
+ *\r
+ * @(#)passages.c      3.4 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include "rogue.h"\r
+\r
+/*\r
+ * do_passages:\r
+ *     Draw all the passages on a level.\r
+ */\r
+\r
+do_passages()\r
+{\r
+    register struct rdes *r1, *r2;\r
+    register int i, j;\r
+    register int roomcount;\r
+    static struct rdes\r
+    {\r
+       bool    conn[MAXROOMS];         /* possible to connect to room i? */\r
+       bool    isconn[MAXROOMS];       /* connection been made to room i? */\r
+       bool    ingraph;                /* this room in graph already? */\r
+    } rdes[MAXROOMS] = {\r
+       { { 0, 1, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },\r
+       { { 1, 0, 1, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },\r
+       { { 0, 1, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },\r
+       { { 1, 0, 0, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },\r
+       { { 0, 1, 0, 1, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },\r
+       { { 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },\r
+       { { 0, 0, 0, 1, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },\r
+       { { 0, 0, 0, 0, 1, 0, 1, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },\r
+       { { 0, 0, 0, 0, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },\r
+    };\r
+\r
+    /*\r
+     * reinitialize room graph description\r
+     */\r
+    for (r1 = rdes; r1 <= &rdes[MAXROOMS-1]; r1++)\r
+    {\r
+       for (j = 0; j < MAXROOMS; j++)\r
+           r1->isconn[j] = FALSE;\r
+       r1->ingraph = FALSE;\r
+    }\r
+\r
+    /*\r
+     * starting with one room, connect it to a random adjacent room and\r
+     * then pick a new room to start with.\r
+     */\r
+    roomcount = 1;\r
+    r1 = &rdes[rnd(MAXROOMS)];\r
+    r1->ingraph = TRUE;\r
+    do\r
+    {\r
+       /*\r
+        * find a room to connect with\r
+        */\r
+       j = 0;\r
+       for (i = 0; i < MAXROOMS; i++)\r
+           if (r1->conn[i] && !rdes[i].ingraph && rnd(++j) == 0)\r
+               r2 = &rdes[i];\r
+       /*\r
+        * if no adjacent rooms are outside the graph, pick a new room\r
+        * to look from\r
+        */\r
+       if (j == 0)\r
+       {\r
+           do\r
+               r1 = &rdes[rnd(MAXROOMS)];\r
+           until (r1->ingraph);\r
+       }\r
+       /*\r
+        * otherwise, connect new room to the graph, and draw a tunnel\r
+        * to it\r
+        */\r
+       else\r
+       {\r
+           r2->ingraph = TRUE;\r
+           i = r1 - rdes;\r
+           j = r2 - rdes;\r
+           conn(i, j);\r
+           r1->isconn[j] = TRUE;\r
+           r2->isconn[i] = TRUE;\r
+           roomcount++;\r
+       }\r
+    } while (roomcount < MAXROOMS);\r
+\r
+    /*\r
+     * attempt to add passages to the graph a random number of times so\r
+     * that there isn't just one unique passage through it.\r
+     */\r
+    for (roomcount = rnd(5); roomcount > 0; roomcount--)\r
+    {\r
+       r1 = &rdes[rnd(MAXROOMS)];      /* a random room to look from */\r
+       /*\r
+        * find an adjacent room not already connected\r
+        */\r
+       j = 0;\r
+       for (i = 0; i < MAXROOMS; i++)\r
+           if (r1->conn[i] && !r1->isconn[i] && rnd(++j) == 0)\r
+               r2 = &rdes[i];\r
+       /*\r
+        * if there is one, connect it and look for the next added\r
+        * passage\r
+        */\r
+       if (j != 0)\r
+       {\r
+           i = r1 - rdes;\r
+           j = r2 - rdes;\r
+           conn(i, j);\r
+           r1->isconn[j] = TRUE;\r
+           r2->isconn[i] = TRUE;\r
+       }\r
+    }\r
+}\r
+\r
+/*\r
+ * conn:\r
+ *     Draw a corridor from a room in a certain direction.\r
+ */\r
+\r
+conn(r1, r2)\r
+int r1, r2;\r
+{\r
+    register struct room *rpf, *rpt;\r
+    register char rmt;\r
+    register int distance, turn_spot, turn_distance;\r
+    register int rm;\r
+    register char direc;\r
+    coord delta, curr, turn_delta, spos, epos;\r
+\r
+    if (r1 < r2)\r
+    {\r
+       rm = r1;\r
+       if (r1 + 1 == r2)\r
+           direc = 'r';\r
+       else\r
+           direc = 'd';\r
+    }\r
+    else\r
+    {\r
+       rm = r2;\r
+       if (r2 + 1 == r1)\r
+           direc = 'r';\r
+       else\r
+           direc = 'd';\r
+    }\r
+    rpf = &rooms[rm];\r
+    /*\r
+     * Set up the movement variables, in two cases:\r
+     * first drawing one down.\r
+     */\r
+    if (direc == 'd')\r
+    {\r
+       rmt = rm + 3;                           /* room # of dest */\r
+       rpt = &rooms[rmt];                      /* room pointer of dest */\r
+       delta.x = 0;                            /* direction of move */\r
+       delta.y = 1;\r
+       spos.x = rpf->r_pos.x;                  /* start of move */\r
+       spos.y = rpf->r_pos.y;\r
+       epos.x = rpt->r_pos.x;                  /* end of move */\r
+       epos.y = rpt->r_pos.y;\r
+       if (!(rpf->r_flags & ISGONE))           /* if not gone pick door pos */\r
+       {\r
+           spos.x += rnd(rpf->r_max.x-2)+1;\r
+           spos.y += rpf->r_max.y-1;\r
+       }\r
+       if (!(rpt->r_flags & ISGONE))\r
+           epos.x += rnd(rpt->r_max.x-2)+1;\r
+       distance = abs(spos.y - epos.y) - 1;    /* distance to move */\r
+       turn_delta.y = 0;                       /* direction to turn */\r
+       turn_delta.x = (spos.x < epos.x ? 1 : -1);\r
+       turn_distance = abs(spos.x - epos.x);   /* how far to turn */\r
+       turn_spot = rnd(distance-1) + 1;                /* where turn starts */\r
+    }\r
+    else if (direc == 'r')                     /* setup for moving right */\r
+    {\r
+       rmt = rm + 1;\r
+       rpt = &rooms[rmt];\r
+       delta.x = 1;\r
+       delta.y = 0;\r
+       spos.x = rpf->r_pos.x;\r
+       spos.y = rpf->r_pos.y;\r
+       epos.x = rpt->r_pos.x;\r
+       epos.y = rpt->r_pos.y;\r
+       if (!(rpf->r_flags & ISGONE))\r
+       {\r
+           spos.x += rpf->r_max.x-1;\r
+           spos.y += rnd(rpf->r_max.y-2)+1;\r
+       }\r
+       if (!(rpt->r_flags & ISGONE))\r
+           epos.y += rnd(rpt->r_max.y-2)+1;\r
+       distance = abs(spos.x - epos.x) - 1;\r
+       turn_delta.y = (spos.y < epos.y ? 1 : -1);\r
+       turn_delta.x = 0;\r
+       turn_distance = abs(spos.y - epos.y);\r
+       turn_spot = rnd(distance-1) + 1;\r
+    }\r
+    else\r
+       fatal("error in connection tables");\r
+    /*\r
+     * Draw in the doors on either side of the passage or just put #'s\r
+     * if the rooms are gone.\r
+     */\r
+    if (!(rpf->r_flags & ISGONE)) door(rpf, &spos);\r
+    else\r
+    {\r
+       cmov(spos);\r
+       addch('#');\r
+    }\r
+    if (!(rpt->r_flags & ISGONE)) door(rpt, &epos);\r
+    else\r
+    {\r
+       cmov(epos);\r
+       addch('#');\r
+    }\r
+    /*\r
+     * Get ready to move...\r
+     */\r
+    curr.x = spos.x;\r
+    curr.y = spos.y;\r
+    while(distance)\r
+    {\r
+       /*\r
+        * Move to new position\r
+        */\r
+       curr.x += delta.x;\r
+       curr.y += delta.y;\r
+       /*\r
+        * Check if we are at the turn place, if so do the turn\r
+        */\r
+       if (distance == turn_spot && turn_distance > 0)\r
+           while(turn_distance--)\r
+           {\r
+               cmov(curr);\r
+               addch(PASSAGE);\r
+               curr.x += turn_delta.x;\r
+               curr.y += turn_delta.y;\r
+           }\r
+       /*\r
+        * Continue digging along\r
+        */\r
+       cmov(curr);\r
+       addch(PASSAGE);\r
+       distance--;\r
+    }\r
+    curr.x += delta.x;\r
+    curr.y += delta.y;\r
+    if (!ce(curr, epos))\r
+       msg("Warning, connectivity problem on this level.");\r
+}\r
+\r
+/*\r
+ * Add a door or possibly a secret door\r
+ * also enters the door in the exits array of the room.\r
+ */\r
+\r
+door(rm, cp)\r
+register struct room *rm;\r
+register coord *cp;\r
+{\r
+    cmov(*cp);\r
+    addch( (rnd(10) < level - 1 && rnd(100) < 20 ? SECRETDOOR : DOOR) );\r
+    rm->r_exit[rm->r_nexits++] = *cp;\r
+}\r
+\r
+/*\r
+ * add_pass:\r
+ *     add the passages to the current window (wizard command)\r
+ */\r
+\r
+add_pass()\r
+{\r
+    register int y, x, ch;\r
+\r
+    for (y = 1; y < LINES - 2; y++)\r
+       for (x = 0; x < COLS; x++)\r
+           if ((ch=mvinch(y, x)) == PASSAGE || ch == DOOR || ch == SECRETDOOR)\r
+               mvwaddch(cw, y, x, ch);\r
+}\r
diff --git a/potions.c b/potions.c
new file mode 100644 (file)
index 0000000..8a551f3
--- /dev/null
+++ b/potions.c
@@ -0,0 +1,211 @@
+/*\r
+ *     @(#)potions.c   3.1     3.1     5/7/81\r
+ * Function(s) for dealing with potions\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include "rogue.h"\r
+\r
+quaff()\r
+{\r
+    register struct object *obj;\r
+    register struct linked_list *item, *titem;\r
+    register struct thing *th;\r
+    char buf[80];\r
+\r
+    item = get_item("quaff", POTION);\r
+    /*\r
+     * Make certain that it is somethings that we want to drink\r
+     */\r
+    if (item == NULL)\r
+       return;\r
+    obj = (struct object *) ldata(item);\r
+    if (obj->o_type != POTION)\r
+    {\r
+       if (!terse)\r
+           msg("Yuk! Why would you want to drink that?");\r
+       else\r
+           msg("That's undrinkable");\r
+       return;\r
+    }\r
+    if (obj == cur_weapon)\r
+       cur_weapon = NULL;\r
+\r
+    /*\r
+     * Calculate the effect it has on the poor guy.\r
+     */\r
+    switch(obj->o_which)\r
+    {\r
+       case P_CONFUSE:\r
+           if (off(player, ISHUH))\r
+               msg("Wait, what's going on here. Huh? What? Who?");\r
+\r
+           if (on(player, ISHUH))\r
+               lengthen(unconfuse, rnd(8)+HUHDURATION);\r
+           else\r
+               fuse(unconfuse, 0, rnd(8)+HUHDURATION, AFTER);\r
+\r
+           player.t_flags |= ISHUH;\r
+           p_know[P_CONFUSE] = TRUE;\r
+       when P_POISON:\r
+           if (!ISWEARING(R_SUSTSTR))\r
+           {\r
+               chg_str(-(rnd(3)+1));\r
+               msg("You feel very sick now.");\r
+           }\r
+           else\r
+               msg("You feel momentarily sick");\r
+           p_know[P_POISON] = TRUE;\r
+       when P_HEALING:\r
+           if ((pstats.s_hpt += roll(pstats.s_lvl, 4)) > max_hp)\r
+               pstats.s_hpt = ++max_hp;\r
+           msg("You begin to feel better.");\r
+           sight();\r
+           p_know[P_HEALING] = TRUE;\r
+       when P_STRENGTH:\r
+           msg("You feel stronger, now.  What bulging muscles!");\r
+           chg_str(1);\r
+           p_know[P_STRENGTH] = TRUE;\r
+       when P_MFIND:\r
+           /*\r
+            * Potion of monster detection, if there are monters, detect them\r
+            */\r
+           if (mlist != NULL)\r
+           {\r
+               wclear(hw);\r
+               overwrite(mw, hw);\r
+               show_win(hw,\r
+                   "You begin to sense the presence of monsters.--More--");\r
+               p_know[P_MFIND] = TRUE;\r
+           }\r
+           else\r
+               msg("You have a strange feeling for a moment, then it passes.");\r
+       when P_TFIND:\r
+           /*\r
+            * Potion of magic detection.  Show the potions and scrolls\r
+            */\r
+           if (lvl_obj != NULL)\r
+           {\r
+               struct linked_list *mobj;\r
+               struct object *tp;\r
+               bool show;\r
+\r
+               show = FALSE;\r
+               wclear(hw);\r
+               for (mobj = lvl_obj; mobj != NULL; mobj = next(mobj))\r
+               {\r
+                   tp = (struct object *) ldata(mobj);\r
+                   if (is_magic(tp))\r
+                   {\r
+                       show = TRUE;\r
+                       mvwaddch(hw, tp->o_pos.y, tp->o_pos.x, MAGIC);\r
+                   }\r
+                   p_know[P_TFIND] = TRUE;\r
+               }\r
+               for (titem = mlist; titem != NULL; titem = next(titem))\r
+               {\r
+                   register struct linked_list *pitem;\r
+\r
+                   th = (struct thing *) ldata(titem);\r
+                   for (pitem = th->t_pack; pitem != NULL; pitem = next(pitem))\r
+                   {\r
+                       if (is_magic(ldata(pitem)))\r
+                       {\r
+                           show = TRUE;\r
+                           mvwaddch(hw, th->t_pos.y, th->t_pos.x, MAGIC);\r
+                       }\r
+                       p_know[P_TFIND] = TRUE;\r
+                   }\r
+               }\r
+               if (show)\r
+               {\r
+                   show_win(hw, \r
+                       "You sense the presence of magic on this level.--More--");\r
+                   break;\r
+               }\r
+           }\r
+           msg("You have a strange feeling for a moment, then it passes.");\r
+       when P_PARALYZE:\r
+           msg("You can't move.");\r
+           no_command = HOLDTIME;\r
+           p_know[P_PARALYZE] = TRUE;\r
+       when P_SEEINVIS:\r
+           msg("This potion tastes like %s juice.", fruit);\r
+           if (off(player, CANSEE))\r
+           {\r
+               player.t_flags |= CANSEE;\r
+               fuse(unsee, 0, SEEDURATION, AFTER);\r
+               light(&hero);\r
+           }\r
+           sight();\r
+       when P_RAISE:\r
+           msg("You suddenly feel much more skillful");\r
+           p_know[P_RAISE] = TRUE;\r
+           raise_level();\r
+       when P_XHEAL:\r
+           if ((pstats.s_hpt += roll(pstats.s_lvl, 8)) > max_hp)\r
+               pstats.s_hpt = ++max_hp;\r
+           msg("You begin to feel much better.");\r
+           p_know[P_XHEAL] = TRUE;\r
+           sight();\r
+       when P_HASTE:\r
+           add_haste(TRUE);\r
+           msg("You feel yourself moving much faster.");\r
+           p_know[P_HASTE] = TRUE;\r
+       when P_RESTORE:\r
+           msg("Hey, this tastes great.  It make you feel warm all over.");\r
+           if (pstats.s_str.st_str < max_stats.s_str.st_str ||\r
+               (pstats.s_str.st_str == 18 &&\r
+                pstats.s_str.st_add < max_stats.s_str.st_add))\r
+           pstats.s_str = max_stats.s_str;\r
+       when P_BLIND:\r
+           msg("A cloak of darkness falls around you.");\r
+           if (off(player, ISBLIND))\r
+           {\r
+               player.t_flags |= ISBLIND;\r
+               fuse(sight, 0, SEEDURATION, AFTER);\r
+               look(FALSE);\r
+           }\r
+           p_know[P_BLIND] = TRUE;\r
+       when P_NOP:\r
+           msg("This potion tastes extremely dull.");\r
+       otherwise:\r
+           msg("What an odd tasting potion!");\r
+           return;\r
+    }\r
+    status();\r
+    if (p_know[obj->o_which] && p_guess[obj->o_which])\r
+    {\r
+       free(p_guess[obj->o_which]);\r
+       p_guess[obj->o_which] = NULL;\r
+    }\r
+    else if (!p_know[obj->o_which] && askme && p_guess[obj->o_which] == NULL)\r
+    {\r
+       msg(terse ? "Call it: " : "What do you want to call it? ");\r
+       if (get_str(buf, cw) == NORM)\r
+       {\r
+           p_guess[obj->o_which] = malloc((unsigned int) strlen(buf) + 1);\r
+           if (p_guess[obj->o_which] != NULL)\r
+               strcpy(p_guess[obj->o_which], buf);\r
+       }\r
+    }\r
+    /*\r
+     * Throw the item away\r
+     */\r
+    inpack--;\r
+    if (obj->o_count > 1)\r
+       obj->o_count--;\r
+    else\r
+    {\r
+       detach(pack, item);\r
+        discard(item);\r
+    }\r
+}\r
diff --git a/readme36.html b/readme36.html
new file mode 100644 (file)
index 0000000..134e826
--- /dev/null
@@ -0,0 +1,78 @@
+<html>\r
+<head>\r
+<title>ROGUE</title>\r
+</head>\r
+<body>\r
+\r
+<h1 align=center>ROGUE 3.6</h1>\r
+\r
+<hr>\r
+\r
+<h2>NAME</h2>\r
+<blockquote>\r
+       <p>rogue36 &minus; Exploring The Dungeons of Doom</p>\r
+</blockquote>\r
+\r
+<h2>SYNOPSIS</h2>\r
+<blockquote>\r
+       <p><b>rogue36</b> [ <i>save_file</i> ]</p>\r
+</blockquote>\r
+\r
+<h2>DESCRIPTION</h2>\r
+<blockquote>\r
+\r
+       <p align="justify"><u>Rogue</u> 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 \r
+       monsters and get a lot of gold, rather than the puzzle solving orientation\r
+       of most computer fantasy games.</p>\r
+\r
+       <p align="justify">To get started you really only need to know two commands. \r
+       The command ? will give you a list of the available commands and the command /\r
+       will identify the things you see on the screen.</p>\r
+\r
+       <p align="justify">To win the game (as opposed to merely playing to beat \r
+       other people high scores) you must locate the Amulet of Yendor which is \r
+       somewhere below the 20th level of the dungeon and get it out. Nobody has \r
+       achieved this yet and if somebody does, they will probably go down in history\r
+       as a hero among heros.</p>\r
+\r
+       <p align="justify">When the game ends, either by your death, when you quit, \r
+       or if you (by some miracle) manage to win, <u>rogue</u> will give you a list of the \r
+       top-ten scorers. The scoring is based entirely upon how much gold you get.\r
+       There is a 10% penalty for getting yourself killed.</p>\r
+\r
+       <p align="justify">For more detailed directions, read the document A Guide \r
+       to the Dungeons of Doom.</p>\r
+\r
+</blockquote>\r
+\r
+<h2>FILES</h2>\r
+<blockquote>\r
+       <table border="0" id="table1">\r
+               <tr>\r
+                       <td>rogue36.scr</td>\r
+                       <td width="50">&nbsp;</td>\r
+                       <td>Score file</td>\r
+               </tr>\r
+               <tr>\r
+                       <td>rogue36.sav</td>\r
+                       <td>&nbsp;</td>\r
+                       <td>Default save file</td>\r
+               </tr>\r
+       </table>\r
+</blockquote>\r
+\r
+<h2>SEE ALSO</h2>\r
+<p>Michael C. Toy, <u>A Guide to the Dungeons of Doom</u></p>\r
+\r
+<h2>BUGS</h2>\r
+<p>Probably infinite. Currently known bugs are: Sometimes you are still\r
+hungry even after you eat food and sometimes you get a monster on the\r
+screen in reverse video which may or may not cause a core dump.</p>\r
+\r
+<h2>COPYRIGHT</h2>\r
+Rogue: Exploring the Dungeons of Doom<br>\r
+Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman <br>\r
+All rights reserved.\r
+\r
+</body>\r
+</html>
\ No newline at end of file
diff --git a/rings.c b/rings.c
new file mode 100644 (file)
index 0000000..1344ca1
--- /dev/null
+++ b/rings.c
@@ -0,0 +1,207 @@
+/*\r
+ * routines dealing specifically with rings\r
+ *\r
+ * @(#)rings.c 3.17 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include "rogue.h"\r
+\r
+ring_on()\r
+{\r
+    register struct object *obj;\r
+    register struct linked_list *item;\r
+    register int ring;\r
+    str_t save_max;\r
+    char buf[80];\r
+\r
+    item = get_item("put on", RING);\r
+    /*\r
+     * Make certain that it is somethings that we want to wear\r
+     */\r
+    if (item == NULL)\r
+       return;\r
+    obj = (struct object *) ldata(item);\r
+    if (obj->o_type != RING)\r
+    {\r
+       if (!terse)\r
+           msg("It would be difficult to wrap that around a finger");\r
+       else\r
+           msg("Not a ring");\r
+       return;\r
+    }\r
+\r
+    /*\r
+     * find out which hand to put it on\r
+     */\r
+    if (is_current(obj))\r
+       return;\r
+\r
+    if (cur_ring[LEFT] == NULL && cur_ring[RIGHT] == NULL)\r
+    {\r
+       if ((ring = gethand()) < 0)\r
+           return;\r
+    }\r
+    else if (cur_ring[LEFT] == NULL)\r
+       ring = LEFT;\r
+    else if (cur_ring[RIGHT] == NULL)\r
+       ring = RIGHT;\r
+    else\r
+    {\r
+       if (!terse)\r
+           msg("You already have a ring on each hand");\r
+       else\r
+           msg("Wearing two");\r
+       return;\r
+    }\r
+    cur_ring[ring] = obj;\r
+\r
+    /*\r
+     * Calculate the effect it has on the poor guy.\r
+     */\r
+    switch (obj->o_which)\r
+    {\r
+       case R_ADDSTR:\r
+           save_max = max_stats.s_str;\r
+           chg_str(obj->o_ac);\r
+           max_stats.s_str = save_max;\r
+           break;\r
+       case R_SEEINVIS:\r
+           player.t_flags |= CANSEE;\r
+           light(&hero);\r
+           mvwaddch(cw, hero.y, hero.x, PLAYER);\r
+           break;\r
+       case R_AGGR:\r
+           aggravate();\r
+           break;\r
+    }\r
+    status();\r
+    if (r_know[obj->o_which] && r_guess[obj->o_which])\r
+    {\r
+       free(r_guess[obj->o_which]);\r
+       r_guess[obj->o_which] = NULL;\r
+    }\r
+    else if (!r_know[obj->o_which] && askme && r_guess[obj->o_which] == NULL)\r
+    {\r
+       mpos = 0;\r
+       msg(terse ? "Call it: " : "What do you want to call it? ");\r
+       if (get_str(buf, cw) == NORM)\r
+       {\r
+           r_guess[obj->o_which] = malloc((unsigned int) strlen(buf) + 1);\r
+           if (r_guess[obj->o_which] != NULL)\r
+               strcpy(r_guess[obj->o_which], buf);\r
+       }\r
+       msg("");\r
+    }\r
+}\r
+\r
+ring_off()\r
+{\r
+    register int ring;\r
+    register struct object *obj;\r
+\r
+    if (cur_ring[LEFT] == NULL && cur_ring[RIGHT] == NULL)\r
+    {\r
+       if (terse)\r
+           msg("No rings");\r
+       else\r
+           msg("You aren't wearing any rings");\r
+       return;\r
+    }\r
+    else if (cur_ring[LEFT] == NULL)\r
+       ring = RIGHT;\r
+    else if (cur_ring[RIGHT] == NULL)\r
+       ring = LEFT;\r
+    else\r
+       if ((ring = gethand()) < 0)\r
+           return;\r
+    mpos = 0;\r
+    obj = cur_ring[ring];\r
+    if (obj == NULL)\r
+    {\r
+       msg("Not wearing such a ring");\r
+       return;\r
+    }\r
+    if (dropcheck(obj))\r
+       msg("Was wearing %s", inv_name(obj, TRUE));\r
+}\r
+\r
+gethand()\r
+{\r
+    register int c;\r
+\r
+    for (;;)\r
+    {\r
+       if (terse)\r
+           msg("Left or Right ring? ");\r
+       else\r
+           msg("Left hand or right hand? ");\r
+       if ((c = readchar(cw)) == 'l' || c == 'L')\r
+           return LEFT;\r
+       else if (c == 'r' || c == 'R')\r
+           return RIGHT;\r
+       else if (c == ESCAPE)\r
+           return -1;\r
+       mpos = 0;\r
+       if (terse)\r
+           msg("L or R");\r
+       else\r
+           msg("Please type L or R");\r
+    }\r
+}\r
+\r
+/*\r
+ * how much food does this ring use up?\r
+ */\r
+ring_eat(hand)\r
+register int hand;\r
+{\r
+    if (cur_ring[hand] == NULL)\r
+       return 0;\r
+    switch (cur_ring[hand]->o_which)\r
+    {\r
+       case R_REGEN:\r
+           return 2;\r
+       case R_SUSTSTR:\r
+           return 1;\r
+       case R_SEARCH:\r
+           return (rnd(100) < 33);\r
+       case R_DIGEST:\r
+           return -(rnd(100) < 50);\r
+       default:\r
+           return 0;\r
+    }\r
+}\r
+\r
+/*\r
+ * print ring bonuses\r
+ */\r
+char *\r
+ring_num(obj)\r
+register struct object *obj;\r
+{\r
+    static char buf[5];\r
+\r
+    if (!(obj->o_flags & ISKNOW))\r
+       return "";\r
+    switch (obj->o_which)\r
+    {\r
+       case R_PROTECT:\r
+       case R_ADDSTR:\r
+       case R_ADDDAM:\r
+       case R_ADDHIT:\r
+           buf[0] = ' ';\r
+           strcpy(&buf[1], num(obj->o_ac, 0));\r
+       otherwise:\r
+           return "";\r
+    }\r
+    return buf;\r
+}\r
diff --git a/rip.c b/rip.c
new file mode 100644 (file)
index 0000000..809ba6a
--- /dev/null
+++ b/rip.c
@@ -0,0 +1,376 @@
+/*\r
+ * File for the fun ends\r
+ * Death or a total win\r
+ *\r
+ * @(#)rip.c   3.13 (Berkeley) 6/16/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <time.h>\r
+#include <signal.h>\r
+#include <ctype.h>\r
+#include <sys/types.h>\r
+#include <fcntl.h>\r
+#include <string.h>\r
+#include "machdep.h"\r
+#include "rogue.h"\r
+\r
+static char *rip[] = {\r
+"                       __________",\r
+"                      /          \\",\r
+"                     /    REST    \\",\r
+"                    /      IN      \\",\r
+"                   /     PEACE      \\",\r
+"                  /                  \\",\r
+"                  |                  |",\r
+"                  |                  |",\r
+"                  |   killed by a    |",\r
+"                  |                  |",\r
+"                  |       1980       |",\r
+"                 *|     *  *  *      | *",\r
+"         ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______",\r
+    0\r
+};\r
+\r
+char   *killname();\r
+\r
+/*\r
+ * death:\r
+ *     Do something really fun when he dies\r
+ */\r
+\r
+death(monst)\r
+register char monst;\r
+{\r
+    register char **dp = rip, *killer;\r
+    register struct tm *lt;\r
+    time_t date;\r
+    char buf[80];\r
+\r
+    time(&date);\r
+    lt = localtime(&date);\r
+    clear();\r
+    move(8, 0);\r
+    while (*dp)\r
+       printw("%s\n", *dp++);\r
+    mvaddstr(14, 28-(((int)strlen(whoami)+1)/2), whoami);\r
+    purse -= purse/10;\r
+    sprintf(buf, "%d Au", purse);\r
+    mvaddstr(15, 28-(((int)strlen(buf)+1)/2), buf);\r
+    killer = killname(monst);\r
+    mvaddstr(17, 28-(((int)strlen(killer)+1)/2), killer);\r
+    mvaddstr(16, 33, vowelstr(killer));\r
+    sprintf(prbuf, "%4d", 1900+lt->tm_year);\r
+    mvaddstr(18, 26, prbuf);\r
+    move(LINES-1, 0);\r
+    draw(stdscr);\r
+    score(purse, 0, monst);\r
+    exit(0);\r
+}\r
+\r
+/*\r
+ * score -- figure score and post it.\r
+ */\r
+\r
+/* VARARGS2 */\r
+score(amount, flags, monst)\r
+char monst;\r
+{\r
+    static struct sc_ent {\r
+       int sc_score;\r
+       char sc_name[80];\r
+       int sc_flags;\r
+       int sc_level;\r
+       char sc_login[8];\r
+       char sc_monster;\r
+    } top_ten[10];\r
+    register struct sc_ent *scp;\r
+    register int i;\r
+    register struct sc_ent *sc2;\r
+    register FILE *outf;\r
+    register char *killer;\r
+    register int prflags = 0;\r
+    register int fd;\r
+    static char *reason[] = {\r
+       "killed",\r
+       "quit",\r
+       "A total winner",\r
+    };\r
+    char scoreline[100];\r
+    char score_file[PATH_MAX];\r
+    int rogue_ver = 0, scorefile_ver = 0;\r
+\r
+    /*\r
+     * Open file and read list\r
+     */\r
+    \r
+    /* Get default score file */\r
+    strcpy(score_file, md_getroguedir());\r
+\r
+    if (*score_file)\r
+        strcat(score_file,"\\");\r
+\r
+    strcat(score_file, "rogue36.scr");\r
+\r
+    if ((fd = open(score_file, O_RDWR | O_CREAT, 0666 )) < 0)\r
+       return;\r
+\r
+    outf = (FILE *) fdopen(fd, "w");\r
+\r
+    for (scp = top_ten; scp <= &top_ten[9]; scp++)\r
+    {\r
+       scp->sc_score = 0;\r
+       for (i = 0; i < 80; i++)\r
+           scp->sc_name[i] = rnd(255);\r
+       scp->sc_flags = RN;\r
+       scp->sc_level = RN;\r
+       scp->sc_monster = RN;\r
+       scp->sc_login[0] = '\0';\r
+    }\r
+\r
+    signal(SIGINT, SIG_DFL);\r
+    if ((flags != -1) && (flags != 1))\r
+    {\r
+       mvaddstr(LINES-1, 0, "[Press return to continue]");\r
+       draw(stdscr);\r
+       prbuf[0] = 0;\r
+       get_str(prbuf, stdscr);\r
+       endwin();\r
+    }\r
+    if (wizard)\r
+       if (strcmp(prbuf, "names") == 0)\r
+           prflags = 1;\r
+       else if (strcmp(prbuf, "edit") == 0)\r
+           prflags = 2;\r
+\r
+    encread((char *) scoreline, 100, fd);\r
+    sscanf(scoreline, "R%d %d\n", &rogue_ver, &scorefile_ver);\r
+\r
+    if ((rogue_ver == 36) && (scorefile_ver == 2))\r
+        for(i = 0; i < 10; i++)\r
+       {\r
+           encread((char *) &top_ten[i].sc_name, 80, fd);\r
+           encread((char *) &top_ten[i].sc_login, 8, fd);\r
+           encread((char *) scoreline, 100, fd);\r
+           sscanf(scoreline, " %d %d %d %d \n",\r
+               &top_ten[i].sc_score,  &top_ten[i].sc_flags,\r
+               &top_ten[i].sc_level,  &top_ten[i].sc_monster);\r
+       }\r
+\r
+    /*\r
+     * Insert her in list if need be\r
+     */\r
+    if (!waswizard)\r
+    {\r
+       for (scp = top_ten; scp <= &top_ten[9]; scp++)\r
+           if (amount > scp->sc_score)\r
+               break;\r
+       if (scp <= &top_ten[9])\r
+       {\r
+           for (sc2 = &top_ten[9]; sc2 > scp; sc2--)\r
+               *sc2 = *(sc2-1);\r
+           scp->sc_score = amount;\r
+           strcpy(scp->sc_name, whoami);\r
+           scp->sc_flags = flags;\r
+           if (flags == 2)\r
+               scp->sc_level = max_level;\r
+           else\r
+               scp->sc_level = level;\r
+           scp->sc_monster = monst;\r
+           strncpy(scp->sc_login, md_getusername(), 8);\r
+       }\r
+    }\r
+    /*\r
+     * Print the list\r
+     */\r
+    if (flags != -1)\r
+       printf("\n\n\n");\r
+    printf("Top Ten Adventurers:\nRank\tScore\tName\n");\r
+    for (scp = top_ten; scp <= &top_ten[9]; scp++) {\r
+       if (scp->sc_score) {\r
+           printf("%d\t%d\t%s: %s on level %d", scp - top_ten + 1,\r
+               scp->sc_score, scp->sc_name, reason[scp->sc_flags],\r
+               scp->sc_level);\r
+           if (scp->sc_flags == 0) {\r
+               printf(" by a");\r
+               killer = killname(scp->sc_monster);\r
+               if (*killer == 'a' || *killer == 'e' || *killer == 'i' ||\r
+                   *killer == 'o' || *killer == 'u')\r
+                       putchar('n');\r
+               printf(" %s", killer);\r
+           }\r
+           if (prflags == 1)\r
+           {\r
+               printf(" (%s)", scp->sc_login);\r
+               putchar('\n');\r
+           }\r
+           else if (prflags == 2)\r
+           {\r
+               fflush(stdout);\r
+               fgets(prbuf,80,stdin);\r
+               if (prbuf[0] == 'd')\r
+               {\r
+                   for (sc2 = scp; sc2 < &top_ten[9]; sc2++)\r
+                       *sc2 = *(sc2 + 1);\r
+                   top_ten[9].sc_score = 0;\r
+                   for (i = 0; i < 80; i++)\r
+                       top_ten[9].sc_name[i] = rnd(255);\r
+                   top_ten[9].sc_flags = RN;\r
+                   top_ten[9].sc_level = RN;\r
+                   top_ten[9].sc_monster = RN;\r
+                   scp--;\r
+               }\r
+           }\r
+           else\r
+               printf(".\n");\r
+       }\r
+    }\r
+    fseek(outf, 0L, 0);\r
+    /*\r
+     * Update the list file\r
+     */\r
+    strcpy(scoreline, "R36 2\n");\r
+    encwrite(scoreline, 100, outf);\r
+    for(i = 0; i < 10; i++)\r
+    {\r
+        encwrite((char *) &top_ten[i].sc_name, 80, outf);\r
+        encwrite((char *) &top_ten[i].sc_login, 8, outf);\r
+        sprintf(scoreline, " %d %d %d %d \n",\r
+        top_ten[i].sc_score,  top_ten[i].sc_flags,\r
+        top_ten[i].sc_level,  top_ten[i].sc_monster);\r
+        encwrite((char *) scoreline, 100, outf);\r
+    }\r
+    fclose(outf);\r
+}\r
+\r
+total_winner()\r
+{\r
+    register struct linked_list *item;\r
+    register struct object *obj;\r
+    register int worth;\r
+    register char c;\r
+    register int oldpurse;\r
+\r
+    clear();\r
+    standout();\r
+    addstr("                                                               \n");\r
+    addstr("  @   @               @   @           @          @@@  @     @  \n");\r
+    addstr("  @   @               @@ @@           @           @   @     @  \n");\r
+    addstr("  @   @  @@@  @   @   @ @ @  @@@   @@@@  @@@      @  @@@    @  \n");\r
+    addstr("   @@@@ @   @ @   @   @   @     @ @   @ @   @     @   @     @  \n");\r
+    addstr("      @ @   @ @   @   @   @  @@@@ @   @ @@@@@     @   @     @  \n");\r
+    addstr("  @   @ @   @ @  @@   @   @ @   @ @   @ @         @   @  @     \n");\r
+    addstr("   @@@   @@@   @@ @   @   @  @@@@  @@@@  @@@     @@@   @@   @  \n");\r
+    addstr("                                                               \n");\r
+    addstr("     Congratulations, you have made it to the light of day!    \n");\r
+    standend();\r
+    addstr("\nYou have joined the elite ranks of those who have escaped the\n");\r
+    addstr("Dungeons of Doom alive.  You journey home and sell all your loot at\n");\r
+    addstr("a great profit and are admitted to the fighters guild.\n");\r
+    mvaddstr(LINES - 1, 0, "--Press space to continue--");\r
+    refresh();\r
+    wait_for(' ');\r
+    clear();\r
+    mvaddstr(0, 0, "   Worth  Item");\r
+    oldpurse = purse;\r
+    for (c = 'a', item = pack; item != NULL; c++, item = next(item))\r
+    {\r
+       obj = (struct object *) ldata(item);\r
+       switch (obj->o_type)\r
+       {\r
+           case FOOD:\r
+               worth = 2 * obj->o_count;\r
+           when WEAPON:\r
+               switch (obj->o_which)\r
+               {\r
+                   case MACE: worth = 8;\r
+                   when SWORD: worth = 15;\r
+                   when BOW: worth = 75;\r
+                   when ARROW: worth = 1;\r
+                   when DAGGER: worth = 2;\r
+                   when ROCK: worth = 1;\r
+                   when TWOSWORD: worth = 30;\r
+                   when SLING: worth = 1;\r
+                   when DART: worth = 1;\r
+                   when CROSSBOW: worth = 15;\r
+                   when BOLT: worth = 1;\r
+                   when SPEAR: worth = 2;\r
+                   otherwise: worth = 0;\r
+               }\r
+               worth *= (1 + (10 * obj->o_hplus + 10 * obj->o_dplus));\r
+               worth *= obj->o_count;\r
+               obj->o_flags |= ISKNOW;\r
+           when ARMOR:\r
+               switch (obj->o_which)\r
+               {\r
+                   case LEATHER: worth = 5;\r
+                   when RING_MAIL: worth = 30;\r
+                   when STUDDED_LEATHER: worth = 15;\r
+                   when SCALE_MAIL: worth = 3;\r
+                   when CHAIN_MAIL: worth = 75;\r
+                   when SPLINT_MAIL: worth = 80;\r
+                   when BANDED_MAIL: worth = 90;\r
+                   when PLATE_MAIL: worth = 400;\r
+                   otherwise: worth = 0;\r
+               }\r
+               worth *= (1 + (10 * (a_class[obj->o_which] - obj->o_ac)));\r
+               obj->o_flags |= ISKNOW;\r
+           when SCROLL:\r
+               s_know[obj->o_which] = TRUE;\r
+               worth = s_magic[obj->o_which].mi_worth;\r
+               worth *= obj->o_count;\r
+           when POTION:\r
+               p_know[obj->o_which] = TRUE;\r
+               worth = p_magic[obj->o_which].mi_worth;\r
+               worth *= obj->o_count;\r
+           when RING:\r
+               obj->o_flags |= ISKNOW;\r
+               r_know[obj->o_which] = TRUE;\r
+               worth = r_magic[obj->o_which].mi_worth;\r
+               if (obj->o_which == R_ADDSTR || obj->o_which == R_ADDDAM ||\r
+                   obj->o_which == R_PROTECT || obj->o_which == R_ADDHIT)\r
+                       if (obj->o_ac > 0)\r
+                           worth += obj->o_ac * 20;\r
+                       else\r
+                           worth = 50;\r
+           when STICK:\r
+               obj->o_flags |= ISKNOW;\r
+               ws_know[obj->o_which] = TRUE;\r
+               worth = ws_magic[obj->o_which].mi_worth;\r
+               worth += 20 * obj->o_charges;\r
+           when AMULET:\r
+               worth = 1000;\r
+       }\r
+       mvprintw(c - 'a' + 1, 0, "%c) %5d  %s", c, worth, inv_name(obj, FALSE));\r
+       purse += worth;\r
+    }\r
+    mvprintw(c - 'a' + 1, 0,"   %5d  Gold Peices          ", oldpurse);\r
+    refresh();\r
+    score(purse, 2, 0);\r
+    exit(0);\r
+}\r
+\r
+char *\r
+killname(monst)\r
+register char monst;\r
+{\r
+    if (isupper(monst))\r
+       return monsters[monst-'A'].m_name;\r
+    else\r
+       switch (monst)\r
+       {\r
+           case 'a':\r
+               return "arrow";\r
+           case 'd':\r
+               return "dart";\r
+           case 'b':\r
+               return "bolt";\r
+       }\r
+    return("");\r
+}\r
diff --git a/rogue.6 b/rogue.6
new file mode 100644 (file)
index 0000000..2058b9f
--- /dev/null
+++ b/rogue.6
@@ -0,0 +1,58 @@
+.TH ROGUE 6\r
+.UC\r
+.SH NAME\r
+rogue \- Exploring The Dungeons of Doom\r
+.SH SYNOPSIS\r
+.B rogue\r
+[\r
+.I save_file\r
+]\r
+.SH DESCRIPTION\r
+.PP\r
+.I Rogue\r
+is a computer fantasy game with a new twist.  It is crt oriented and the\r
+object of the game is to survive the attacks of various monsters and get\r
+a lot of gold, rather than the puzzle solving orientation of most computer\r
+fantasy games.\r
+.PP\r
+To get started you really only need to know two commands.  The command\r
+.B ?\r
+will give you a list of the available commands and the command\r
+.B /\r
+will identify the things you see on the screen.\r
+.PP\r
+To win the game (as opposed to merely playing to beat other people high\r
+scores) you must locate the Amulet of Yendor which is somewhere below\r
+the 20th level of the dungeon and get it out.  Nobody has achieved this\r
+yet and if somebody does, they will probably go down in history as a hero\r
+among heros.\r
+.PP\r
+When the game ends, either by your death, when you quit, or if you (by\r
+some miracle) manage to win,\r
+.I rogue\r
+will give you alist of the top-ten scorers.  The scoring is based entirely\r
+upon how much gold you get.  There is a 10% penalty for getting yourself\r
+killed.\r
+.PP\r
+For more detailed directions, read the document\r
+.I "A Guide to the Dungeons of Doom."\r
+.SH FILES\r
+.ta 2i\r
+rogue36.scr                  Score file\r
+.br\r
+~/rogue36.sav                Default save file\r
+.DT\r
+.SH SEE ALSO\r
+Michael C. Toy,\r
+.I "A Guide to the Dungeons of Doom"\r
+.SH BUGS\r
+.PP\r
+Probably infinite.  Currently known bugs are: Sometimes you are still hungry\r
+even after you eat food and sometimes you get a monster on the screen in\r
+reverse video which may or may not cause a core dump.\r
+.SH COPYRIGHT\r
+Rogue: Exploring the Dungeons of Doom\r
+.br\r
+Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+.br\r
+All rights reserved.\r
diff --git a/rogue.h b/rogue.h
new file mode 100644 (file)
index 0000000..6ca801a
--- /dev/null
+++ b/rogue.h
@@ -0,0 +1,527 @@
+/*\r
+ * Rogue definitions and variable declarations\r
+ *\r
+ * @(#)rogue.h 3.38 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+/*\r
+ * Maximum number of different things\r
+ */\r
+#define MAXROOMS 9\r
+#define MAXTHINGS 9\r
+#define MAXOBJ 9\r
+#define MAXPACK 23\r
+#define MAXTRAPS 10\r
+#define        NUMTHINGS 7     /* number of types of things (scrolls, rings, etc.) */\r
+\r
+/*\r
+ * return values for get functions\r
+ */\r
+#define        NORM    0       /* normal exit */\r
+#define        QUIT    1       /* quit option setting */\r
+#define        MINUS   2       /* back up one option */\r
+\r
+/*\r
+ * All the fun defines\r
+ */\r
+#define next(ptr) (*ptr).l_next\r
+#define prev(ptr) (*ptr).l_prev\r
+#define ldata(ptr) (*ptr).l_data\r
+#define inroom(rp, cp) (\\r
+    (cp)->x <= (rp)->r_pos.x + ((rp)->r_max.x - 1) && (rp)->r_pos.x <= (cp)->x \\r
+ && (cp)->y <= (rp)->r_pos.y + ((rp)->r_max.y - 1) && (rp)->r_pos.y <= (cp)->y)\r
+#define winat(y, x) (mvwinch(mw,y,x)==' '?mvwinch(stdscr,y,x):winch(mw))\r
+#define debug if (wizard) msg\r
+#define RN (((seed = seed*11109+13849) & 0x7fff) >> 1)\r
+#define unc(cp) (cp).y, (cp).x\r
+#define cmov(xy) move((xy).y, (xy).x)\r
+#define DISTANCE(y1, x1, y2, x2) ((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1))\r
+#define OBJPTR(what)    (struct object *)((*what).l_data)\r
+#define THINGPTR(what)  (struct thing *)((*what).l_data)\r
+#define when break;case\r
+#define otherwise break;default\r
+#define until(expr) while(!(expr))\r
+#define ce(a, b) ((a).x == (b).x && (a).y == (b).y)\r
+#define draw(window) wrefresh(window)\r
+#define hero player.t_pos\r
+#define pstats player.t_stats\r
+#define pack player.t_pack\r
+#define attach(a,b) _attach(&a,b)\r
+#define detach(a,b) _detach(&a,b)\r
+#define free_list(a) _free_list(&a)\r
+#ifndef max\r
+#define max(a, b) ((a) > (b) ? (a) : (b))\r
+#endif\r
+#define on(thing, flag) (((thing).t_flags & flag) != 0)\r
+#define off(thing, flag) (((thing).t_flags & flag) == 0)\r
+#undef  CTRL\r
+#define CTRL(ch) (ch & 037)\r
+#define ALLOC(x) malloc((unsigned int) x)\r
+#define FREE(x) free((char *) x)\r
+#define        EQSTR(a, b, c)  (strncmp(a, b, c) == 0)\r
+#define GOLDCALC (rnd(50 + 10 * level) + 2)\r
+#define ISRING(h,r) (cur_ring[h] != NULL && cur_ring[h]->o_which == r)\r
+#define ISWEARING(r) (ISRING(LEFT, r) || ISRING(RIGHT, r))\r
+#define newgrp() ++group\r
+#define o_charges o_ac\r
+#define ISMULT(type) (type == POTION || type == SCROLL || type == FOOD)\r
+\r
+/*\r
+ * Things that appear on the screens\r
+ */\r
+#define PASSAGE '#'\r
+#define DOOR '+'\r
+#define FLOOR '.'\r
+#define PLAYER '@'\r
+#define TRAP '^'\r
+#define TRAPDOOR '>'\r
+#define ARROWTRAP '{'\r
+#define SLEEPTRAP '$'\r
+#define BEARTRAP '}'\r
+#define TELTRAP '~'\r
+#define DARTTRAP '`'\r
+#define SECRETDOOR '&'\r
+#define STAIRS '%'\r
+#define GOLD '*'\r
+#define POTION '!'\r
+#define SCROLL '?'\r
+#define MAGIC '$'\r
+#define FOOD ':'\r
+#define WEAPON ')'\r
+#define ARMOR ']'\r
+#define AMULET ','\r
+#define RING '='\r
+#define STICK '/'\r
+#define CALLABLE -1\r
+\r
+/*\r
+ * Various constants\r
+ */\r
+#define        PASSWD          "mTBellIQOsLNA"\r
+#define BEARTIME 3\r
+#define SLEEPTIME 5\r
+#define HEALTIME 30\r
+#define HOLDTIME 2\r
+#define STPOS 0\r
+#define WANDERTIME 70\r
+#define BEFORE 1\r
+#define AFTER 2\r
+#define HUHDURATION 20\r
+#define SEEDURATION 850\r
+#define HUNGERTIME 1300\r
+#define MORETIME 150\r
+#define STOMACHSIZE 2000\r
+#define ESCAPE 27\r
+#define LEFT 0\r
+#define RIGHT 1\r
+#define BOLT_LENGTH 6\r
+\r
+/*\r
+ * Save against things\r
+ */\r
+#define VS_POISON 00\r
+#define VS_PARALYZATION 00\r
+#define VS_DEATH 00\r
+#define VS_PETRIFICATION 01\r
+#define VS_BREATH 02\r
+#define VS_MAGIC  03\r
+\r
+/*\r
+ * Various flag bits\r
+ */\r
+#define ISDARK 0000001\r
+#define ISCURSED 000001\r
+#define ISBLIND 0000001\r
+#define ISGONE 0000002\r
+#define ISKNOW  0000002\r
+#define ISRUN  0000004\r
+#define ISFOUND 0000010\r
+#define ISINVIS 0000020\r
+#define ISMEAN  0000040\r
+#define ISGREED 0000100\r
+#define ISBLOCK 0000200\r
+#define ISHELD  0000400\r
+#define ISHUH   0001000\r
+#define ISREGEN 0002000\r
+#define CANHUH  0004000\r
+#define CANSEE  0010000\r
+#define ISMISL  0020000\r
+#define ISCANC 0020000\r
+#define ISMANY  0040000\r
+#define ISSLOW 0040000\r
+#define ISHASTE 0100000\r
+\r
+/*\r
+ * Potion types\r
+ */\r
+#define P_CONFUSE 0\r
+#define P_PARALYZE 1\r
+#define P_POISON 2\r
+#define P_STRENGTH 3\r
+#define P_SEEINVIS 4\r
+#define P_HEALING 5\r
+#define P_MFIND 6\r
+#define P_TFIND 7\r
+#define P_RAISE 8\r
+#define P_XHEAL 9\r
+#define P_HASTE 10\r
+#define P_RESTORE 11\r
+#define P_BLIND 12\r
+#define P_NOP 13\r
+#define MAXPOTIONS 14\r
+\r
+/*\r
+ * Scroll types\r
+ */\r
+#define S_CONFUSE 0\r
+#define S_MAP 1\r
+#define S_LIGHT 2\r
+#define S_HOLD 3\r
+#define S_SLEEP 4\r
+#define S_ARMOR 5\r
+#define S_IDENT 6\r
+#define S_SCARE 7\r
+#define S_GFIND 8\r
+#define S_TELEP 9\r
+#define S_ENCH 10\r
+#define S_CREATE 11\r
+#define S_REMOVE 12\r
+#define S_AGGR 13\r
+#define S_NOP 14\r
+#define S_GENOCIDE 15\r
+#define MAXSCROLLS 16\r
+\r
+/*\r
+ * Weapon types\r
+ */\r
+#define MACE 0\r
+#define SWORD 1\r
+#define BOW 2\r
+#define ARROW 3\r
+#define DAGGER 4\r
+#define ROCK 5\r
+#define TWOSWORD 6\r
+#define SLING 7\r
+#define DART 8\r
+#define CROSSBOW 9\r
+#define BOLT 10\r
+#define SPEAR 11\r
+#define MAXWEAPONS 12\r
+\r
+/*\r
+ * Armor types\r
+ */\r
+#define LEATHER 0\r
+#define RING_MAIL 1\r
+#define STUDDED_LEATHER 2\r
+#define SCALE_MAIL 3\r
+#define CHAIN_MAIL 4\r
+#define SPLINT_MAIL 5\r
+#define BANDED_MAIL 6\r
+#define PLATE_MAIL 7\r
+#define MAXARMORS 8\r
+\r
+/*\r
+ * Ring types\r
+ */\r
+#define R_PROTECT 0\r
+#define R_ADDSTR 1\r
+#define R_SUSTSTR 2\r
+#define R_SEARCH 3\r
+#define R_SEEINVIS 4\r
+#define R_NOP 5\r
+#define R_AGGR 6\r
+#define R_ADDHIT 7\r
+#define R_ADDDAM 8\r
+#define R_REGEN 9\r
+#define R_DIGEST 10\r
+#define R_TELEPORT 11\r
+#define R_STEALTH 12\r
+#define MAXRINGS 13\r
+\r
+/*\r
+ * Rod/Wand/Staff types\r
+ */\r
+\r
+#define WS_LIGHT 0\r
+#define WS_HIT 1\r
+#define WS_ELECT 2\r
+#define WS_FIRE 3\r
+#define WS_COLD 4\r
+#define WS_POLYMORPH 5\r
+#define WS_MISSILE 6\r
+#define WS_HASTE_M 7\r
+#define WS_SLOW_M 8\r
+#define WS_DRAIN 9\r
+#define WS_NOP 10\r
+#define WS_TELAWAY 11\r
+#define WS_TELTO 12\r
+#define WS_CANCEL 13\r
+#define MAXSTICKS 14\r
+\r
+/*\r
+ * Now we define the structures and types\r
+ */\r
+\r
+/*\r
+ * Help list\r
+ */\r
+\r
+struct h_list {\r
+    char h_ch;\r
+    char *h_desc;\r
+};\r
+\r
+extern struct h_list helpstr[];\r
+\r
+/*\r
+ * Coordinate data type\r
+ */\r
+typedef struct {\r
+    int x;\r
+    int y;\r
+} coord;\r
+\r
+typedef struct {\r
+    short st_str;\r
+    short st_add;\r
+} str_t;\r
+\r
+/*\r
+ * Linked list data type\r
+ */\r
+struct linked_list {\r
+    struct linked_list *l_next;\r
+    struct linked_list *l_prev;\r
+    char *l_data;                      /* Various structure pointers */\r
+};\r
+\r
+/*\r
+ * Stuff about magic items\r
+ */\r
+\r
+struct magic_item {\r
+    char mi_name[30];\r
+    int mi_prob;\r
+    int mi_worth;\r
+};\r
+\r
+/*\r
+ * Room structure\r
+ */\r
+struct room {\r
+    coord r_pos;                       /* Upper left corner */\r
+    coord r_max;                       /* Size of room */\r
+    coord r_gold;                      /* Where the gold is */\r
+    int r_goldval;                     /* How much the gold is worth */\r
+    int r_flags;                       /* Info about the room */\r
+    int r_nexits;                      /* Number of exits */\r
+    coord r_exit[4];                   /* Where the exits are */\r
+};\r
+\r
+/*\r
+ * Array of all traps on this level\r
+ */\r
+struct trap {\r
+    coord tr_pos;                      /* Where trap is */\r
+    char tr_type;                      /* What kind of trap */\r
+    int tr_flags;                      /* Info about trap (i.e. ISFOUND) */\r
+};\r
+\r
+extern struct trap  traps[MAXTRAPS];\r
+\r
+/*\r
+ * Structure describing a fighting being\r
+ */\r
+struct stats {\r
+    str_t s_str;                       /* Strength */\r
+    long s_exp;                                /* Experience */\r
+    int s_lvl;                         /* Level of mastery */\r
+    int s_arm;                         /* Armor class */\r
+    int s_hpt;                         /* Hit points */\r
+    char s_dmg[30];                    /* String describing damage done */\r
+};\r
+\r
+/*\r
+ * Structure for monsters and player\r
+ */\r
+struct thing {\r
+    coord t_pos;                       /* Position */\r
+    bool t_turn;                       /* If slowed, is it a turn to move */\r
+    char t_type;                       /* What it is */\r
+    char t_disguise;                   /* What mimic looks like */\r
+    char t_oldch;                      /* Character that was where it was */\r
+    coord *t_dest;                     /* Where it is running to */\r
+    short t_flags;                     /* State word */\r
+    struct stats t_stats;              /* Physical description */\r
+    struct linked_list *t_pack;                /* What the thing is carrying */\r
+       int t_reserved;         /* reserved for save/restore code */\r
+};\r
+\r
+/*\r
+ * Array containing information on all the various types of mosnters\r
+ */\r
+struct monster {\r
+    char m_name[20];                   /* What to call the monster */\r
+    short m_carry;                     /* Probability of carrying something */\r
+    short m_flags;                     /* Things about the monster */\r
+    struct stats m_stats;              /* Initial stats */\r
+};\r
+\r
+/*\r
+ * Structure for a thing that the rogue can carry\r
+ */\r
+\r
+struct object {\r
+    int o_type;                                /* What kind of object it is */\r
+    coord o_pos;                       /* Where it lives on the screen */\r
+    char o_launch;                     /* What you need to launch it */\r
+    char o_damage[8];                  /* Damage if used like sword */\r
+    char o_hurldmg[8];                 /* Damage if thrown */\r
+    int o_count;                       /* Count for plural objects */\r
+    int o_which;                       /* Which object of a type it is */\r
+    int o_hplus;                       /* Plusses to hit */\r
+    int o_dplus;                       /* Plusses to damage */\r
+    int o_ac;                          /* Armor class */\r
+    int o_flags;                       /* Information about objects */\r
+    int o_group;                       /* Group number for this object */\r
+};\r
+\r
+struct delayed_action {\r
+    int d_type;\r
+    int (*d_func)();\r
+    int d_arg;\r
+    int d_time;\r
+};\r
+\r
+/*\r
+ * Now all the global variables\r
+ */\r
+\r
+extern struct room rooms[MAXROOMS];            /* One for each room -- A level */\r
+extern struct room *oldrp;                     /* Roomin(&oldpos) */\r
+extern struct linked_list *mlist;              /* List of monsters on the level */\r
+extern struct thing player;                    /* The rogue */\r
+extern struct stats max_stats;                 /* The maximum for the player */\r
+extern struct monster monsters[26];            /* The initial monster states */\r
+extern struct linked_list *lvl_obj;            /* List of objects on this level */\r
+extern struct object *cur_weapon;              /* Which weapon he is weilding */\r
+extern struct object *cur_armor;               /* What a well dresssed rogue wears */\r
+extern struct object *cur_ring[2];             /* Which rings are being worn */\r
+extern struct magic_item things[NUMTHINGS];    /* Chances for each type of item */\r
+extern struct magic_item s_magic[MAXSCROLLS];  /* Names and chances for scrolls */\r
+extern struct magic_item p_magic[MAXPOTIONS];  /* Names and chances for potions */\r
+extern struct magic_item r_magic[MAXRINGS];    /* Names and chances for rings */\r
+extern struct magic_item ws_magic[MAXSTICKS];  /* Names and chances for sticks */\r
+\r
+extern int level;                              /* What level rogue is on */\r
+extern int purse;                              /* How much gold the rogue has */\r
+extern int mpos;                               /* Where cursor is on top line */\r
+extern int ntraps;                             /* Number of traps on this level */\r
+extern int no_move;                            /* Number of turns held in place */\r
+extern int no_command;                         /* Number of turns asleep */\r
+extern int inpack;                             /* Number of things in pack */\r
+extern int max_hp;                             /* Player's max hit points */\r
+extern int total;                              /* Total dynamic memory bytes */\r
+extern int a_chances[MAXARMORS];               /* Probabilities for armor */\r
+extern int a_class[MAXARMORS];                 /* Armor class for various armors */\r
+extern int lastscore;                          /* Score before this turn */\r
+extern int no_food;                            /* Number of levels without food */\r
+extern int seed;                               /* Random number seed */\r
+extern int count;                              /* Number of times to repeat command */\r
+extern int dnum;                               /* Dungeon number */\r
+extern int fung_hit;                           /* Number of time fungi has hit */\r
+extern int quiet;                              /* Number of quiet turns */\r
+extern int max_level;                          /* Deepest player has gone */\r
+extern int food_left;                          /* Amount of food in hero's stomach */\r
+extern int group;                              /* Current group number */\r
+extern int hungry_state;                       /* How hungry is he */\r
+\r
+extern char take;                              /* Thing the rogue is taking */\r
+extern char prbuf[80];                         /* Buffer for sprintfs */\r
+extern char runch;                             /* Direction player is running */\r
+extern char *s_names[MAXSCROLLS];              /* Names of the scrolls */\r
+extern char *p_colors[MAXPOTIONS];             /* Colors of the potions */\r
+extern char *r_stones[MAXRINGS];               /* Stone settings of the rings */\r
+extern char *w_names[MAXWEAPONS];              /* Names of the various weapons */\r
+extern char *a_names[MAXARMORS];               /* Names of armor types */\r
+extern char *ws_made[MAXSTICKS];               /* What sticks are made of */\r
+extern char *release;                          /* Release number of rogue */\r
+extern char whoami[80];                        /* Name of player */\r
+extern char fruit[80];                         /* Favorite fruit */\r
+extern char huh[80];                           /* The last message printed */\r
+extern char *s_guess[MAXSCROLLS];              /* Players guess at what scroll is */\r
+extern char *p_guess[MAXPOTIONS];              /* Players guess at what potion is */\r
+extern char *r_guess[MAXRINGS];                /* Players guess at what ring is */\r
+extern char *ws_guess[MAXSTICKS];              /* Players guess at what wand is */\r
+extern char *ws_type[MAXSTICKS];               /* Is it a wand or a staff */\r
+extern char file_name[80];                     /* Save file name */\r
+extern char home[80];                          /* User's home directory */\r
+\r
+extern WINDOW *cw;                             /* Window that the player sees */\r
+extern WINDOW *hw;                             /* Used for the help command */\r
+extern WINDOW *mw;                             /* Used to store mosnters */\r
+\r
+extern bool running;                           /* True if player is running */\r
+extern bool playing;                           /* True until he quits */\r
+extern bool wizard;                            /* True if allows wizard commands */\r
+extern bool after;                             /* True if we want after daemons */\r
+extern bool notify;                            /* True if player wants to know */\r
+extern bool fight_flush;                       /* True if toilet input */\r
+extern bool terse;                             /* True if we should be short */\r
+extern bool door_stop;                         /* Stop running when we pass a door */\r
+extern bool jump;                              /* Show running as series of jumps */\r
+extern bool slow_invent;                       /* Inventory one line at a time */\r
+extern bool firstmove;                         /* First move after setting door_stop */\r
+extern bool waswizard;                         /* Was a wizard sometime */\r
+extern bool askme;                             /* Ask about unidentified things */\r
+extern bool s_know[MAXSCROLLS];                /* Does he know what a scroll does */\r
+extern bool p_know[MAXPOTIONS];                /* Does he know what a potion does */\r
+extern bool r_know[MAXRINGS];                  /* Does he know what a ring does */\r
+extern bool ws_know[MAXSTICKS];                /* Does he know what a stick does */\r
+extern bool amulet;                            /* He found the amulet */\r
+extern bool in_shell;                          /* True if executing a shell */\r
+\r
+extern coord oldpos;                           /* Position before last look() call */\r
+extern coord delta;                            /* Change indicated to get_dir() */\r
+\r
+extern coord ch_ret;\r
+extern char countch,direction,newcount;\r
+extern struct delayed_action d_list[20];\r
+extern int between;\r
+extern int num_checks;\r
+extern char lvl_mons[27],wand_mons[27];\r
+extern coord nh;\r
+\r
+struct linked_list *find_mons(), *find_obj(), *get_item(), *new_item();\r
+struct linked_list *new_thing(), *wake_monster();\r
+\r
+char *tr_name(), *new();\r
+char *charge_str(),*vowelstr(), *inv_name();\r
+char *ctime(), *num(), *ring_num();\r
+\r
+struct room *roomin();\r
+\r
+coord *rndmove();\r
+\r
+void auto_save(int p), endit(int p), quit(int p), tstp(), checkout();\r
+int nohaste(), doctor(), runners(), swander();\r
+int unconfuse(), unsee(), rollwand(), stomach(), sight();\r
+\r
+struct trap *trap_at();\r
+\r
+extern char *rainbow[];\r
+extern char *stones[];\r
+extern char *wood[];\r
+extern char *metal[];\r
+\r
+extern const int cNCOLORS;\r
+extern const int cNSTONES;\r
+extern const int cNWOOD;\r
+extern const int cNMETAL;\r
diff --git a/rogue.r b/rogue.r
new file mode 100644 (file)
index 0000000..4642a25
--- /dev/null
+++ b/rogue.r
@@ -0,0 +1,411 @@
+.RP\r
+.ds RH A Guide to the Dungeons of Doom\r
+.ds CH\r
+.ds CF - % -\r
+.TL\r
+A Guide to the Dungeons of Doom\r
+.AU\r
+Michael C. Toy\r
+.AI\r
+Computer Systems Research Group\r
+Department of Electrical Engineering and Computer Science\r
+University of California\r
+Berkeley, California  94720\r
+.AB\r
+Rogue is a visual CRT based fantasy game which runs\r
+under the UNIX timesharing system.  This paper describes\r
+how to play rogue and gives a few hints for those who might\r
+otherwise get lost in the Dungeons of Doom.\r
+.AE\r
+.NH\r
+Introduction\r
+.PP\r
+You have just finished your years as a student at the local fighter's guild.\r
+After much practice and sweat you have finally completed your training and\r
+are ready to embark upon a perilous adventure.  As a test of your skills,\r
+the local guildmasters have sent you into the Dungeons of Doom.  Your\r
+task is to return with the Amulet of Yendor.  Your reward for the completion\r
+of this task will be a full membership in the local guild. In addition, you are\r
+allowed to keep all the loot you bring back from the dungeons.\r
+.PP\r
+In preparation for your journey, you are given an enchanted sword, taken\r
+from a dragon's hoard in the far off Dark Mountains.  You are also outfitted\r
+with elf-crafted armor and given enough food to reach the dungeons.  You\r
+say goodbye to family and friends for what may be the last time and head\r
+up the road.\r
+.PP\r
+You set out on your way to the dungeons and after several days of uneventful\r
+travel, you see the ancient ruins that mark the entrance to the Dungeons\r
+of Doom.  It is late at night so you make camp at the entrance and spend\r
+the night sleeping under the open skies.  In the morning you gather\r
+your sword, put on your armor, eat what is almost your last food and enter\r
+the dungeons.\r
+.NH\r
+What is going on here?\r
+.PP\r
+You have just begun a game of rogue.  Your goal is to grab as much treasure\r
+as you can, find the Amulet of Yendor, and get out of the Dungeons of Doom\r
+alive.  On the screen, a map of where you have been and what you have seen on\r
+the current dungeon level is kept.  As you explore more of the level,\r
+it appears on the screen in front of you.\r
+.PP\r
+Rogue differs from most computer fantasy games in that it is screen\r
+oriented.  Commands are all one or two keystrokes\(dg\r
+.FS\r
+\(dgAs opposed to pseudo English sentences.\r
+.FE\r
+and the results of your commands are displayed\r
+graphically on the screen rather than being explained in words.\r
+.PP\r
+Another major difference between rogue and other computer fantasy games\r
+is that once you have solved all the puzzles in a standard fantasy game,\r
+it has lost most of its excitement and it ceases to be fun.  Rogue on the\r
+other hand generates a new dungeon every time you play it and\r
+even the author finds it an entertaining and exciting game.\r
+.NH\r
+What do all those things on the screen mean?\r
+.PP\r
+In order to understand what is going on in rogue you have to first get\r
+some grasp of what rogue is doing with the screen.\r
+The rogue screen is intended to replace the "You can see ..." descriptions\r
+of standard fantasy games.  Here is a sample of what a rogue screen might\r
+look like.\r
+.in +1i\r
+.nf\r
+.cs R 15\r
+                  ---------------------\r
+                  |...................+\r
+                  |...@...........[...|\r
+                  |........B..........|\r
+                  |...................|\r
+                  --------+------------\r
+\r
+\r
+.cs R\r
+Level: 1  Gold: 0      Hp: 12(12)  Str: 16  Ac: 6  Exp: 1/0\r
+.fi\r
+.in 0\r
+.NH 2\r
+The bottom line\r
+.PP\r
+At the bottom line of the screen is a few pieces of cryptic information,\r
+describing your current status.  Here is an explanation of what these\r
+things mean:\r
+.IP Level 8\r
+This number indicates how deep you have gone in the dungeon.  It starts\r
+at one and goes up forever\(dg.\r
+.FS\r
+\(dgOr until you get killed or decide to quit.\r
+.FE\r
+.IP Gold\r
+The number of gold pieces you have managed to find and keep with\r
+you so far.\r
+.IP Hp\r
+Your current and maximum hit points.  Hit points indicate how much\r
+damage you can take before you die.  The more you get hit in a\r
+fight, the lower they\r
+get.  You can regain hit points by resting. The number in parentheses is\r
+the maximum number your hit points can reach.\r
+.IP Str\r
+Your current strength.  This can be any integer less than or\r
+equal to eighteen.  The higher the number, the stronger you are.\r
+.IP Ac\r
+Your current armor class.  This number indicates how effective\r
+your armor is in stopping blows from unfriendly creatures.  The lower\r
+this number is, the more effective the armor.\r
+.IP Exp\r
+These two numbers give your current experience level and experience points.\r
+As you do things, you gain experience points.  At certain experience point\r
+totals, you gain an experience level.  The more experienced you are, the\r
+better you are able to fight and to withstand magical attacks.\r
+.NH 2\r
+The top line\r
+.PP\r
+The top line of the screen is reserved for printing messages that describe\r
+things that are impossible to represent visually.  If you see a\r
+"--More--" on the top line, this means that rogue wants to print another\r
+message on the screen, but it wants to make certain that you have read\r
+the one that is there first.  To read the next message, just press a\r
+space.\r
+.NH 2\r
+The rest of the screen\r
+.PP\r
+The rest of the screen is the map of the level as you have explored it so far.\r
+Each symbol on the screen represents something.  Here is a list of what\r
+the various symbols mean:\r
+.IP @\r
+This symbol represents you, the adventurer.\r
+.IP "-|" 6\r
+These symbols represent the walls of rooms.\r
+.IP +\r
+A door to/from a room.\r
+.IP .\r
+The floor of a room.\r
+.IP #\r
+The floor of a passage between rooms.\r
+.IP *\r
+A pile or pot of gold.\r
+.IP )\r
+A weapon of some sort.\r
+.IP ]\r
+A piece of armor.\r
+.IP !\r
+A flask containing a magic potion.\r
+.IP ?\r
+A piece of paper, usually a magic scroll.\r
+.IP ^\r
+A trap, watch out for these.\r
+.IP %\r
+The passage leading down to the next level.\r
+.IP :\r
+A piece of food.\r
+.IP A-Z\r
+The uppercase letters represent the various inhabitants of the\r
+Dungeons of Doom.  Watch out, they can be mean.\r
+.NH\r
+Commands\r
+.PP\r
+Commands are given to rogue by pressing single letters.  Most commands can\r
+be preceded by a count to repeat them (e.g. typing "10s" will do ten searches)\r
+The list of commands is rather long, but it can be read at any time during\r
+the game with the ? command.  Here it is for reference, with a short\r
+explanation of each command.\r
+.IP ? 6\r
+The help command.  Asks for a character to give help on.  If you type\r
+a "*", it will list all the commands, otherwise it will explain what the\r
+character you typed does.\r
+.IP /\r
+This is the "What is that on the screen?" command. A "/" followed by any\r
+character that you see on the level, will tell you what that character\r
+is.  For instance, typing "/@" will tell you that the @ symbol represents\r
+you, the player.\r
+.IP "h , H"\r
+Move left.  You move one space to the left.  If you use upper case\r
+h, you will continue to move left until you run into something.  This\r
+works for all movement commands (e.g. "L" means run in direction "l")\r
+.IP j\r
+Move down.\r
+.IP k\r
+Move up.\r
+.IP l\r
+Move right.\r
+.IP y\r
+Move diagonally up and left.\r
+.IP u\r
+Move diagonally up and right.\r
+.IP b\r
+Move diagonally down and left.\r
+.IP n\r
+Move diagonally down and right.\r
+.IP f\r
+Find prefix.  When followed by a direction it means to continue moving\r
+in the specified direction until you pass something interesting or\r
+run into a wall.\r
+.IP t\r
+Throw an object.  This is a prefix command.  Follow it with a direction and\r
+you throw an object in the specified direction.  (e.g. type "th" to throw\r
+something left.)\r
+.IP >\r
+If you are standing over the passage down to the next level, this command\r
+means to climb down.\r
+.IP s\r
+Search for traps and secret doors.  Examine each space immediately adjacent\r
+to you for the existence of a trap or secret door.  There is a large chance\r
+that even if there is something there, you won't find it so you might\r
+have to search a while before you find something.\r
+.IP " "\r
+(space) Rest.  This is the "do nothing" command.\r
+This is good for waiting and healing.\r
+.IP i\r
+Inventory.  List what you are carrying in your pack.\r
+.IP I\r
+Selective inventory.  Tells you what a single item in your pack is.\r
+.IP q\r
+Quaff.  Drink one of the potions you are carrying.\r
+.IP r\r
+Read.  Read one of the scrolls in your pack.\r
+.IP e\r
+Eat food.  Take some food out of your pack and eat it.\r
+.IP w\r
+Wield a weapon.  Take a weapon out of your pack and carry it.  You must be\r
+wielding  weapon to use it (except to throw things).  To fire an arrow,\r
+you must wield the bow.  You can only wield one weapon at a time.\r
+.IP W\r
+Wear armor.  Take a piece of armor out of your pack and put it on.  You can\r
+only wear one suit of armor at a time.\r
+.IP T\r
+Take armor off.  You can't remove armor that is cursed.\r
+This takes extra time.\r
+.IP d\r
+Drop an object.  Take something out of your pack and leave it lying\r
+on the floor.  Only one object can occupy each space.\r
+.IP o\r
+Examine and set options.  This command is further explained in the section\r
+on options.\r
+.IP ^L\r
+REdraws the screen. Useful if spurious messages or transmission errors\r
+have messed up the display.\r
+.IP v\r
+Prints the program version number.\r
+.IP Q\r
+Quit.  Leave the game.\r
+.IP R\r
+Repeat last message.  Useful when a message disappears before you can\r
+read it.\r
+.IP S\r
+Save the current game in a file.  Caveat: Rogue won't let you start\r
+up a copy of a saved game, and it removes the save file as soon as\r
+you start up a restored game.  This is to prevent people from saving\r
+a game just before a dangerous position and then restarting it\r
+if they die.  To restore a saved game, give the file name as an argument\r
+to rogue. As in\r
+.ti +1i\r
+.nf\r
+% rogue save_file\r
+.NH\r
+Dealing with objects\r
+.PP\r
+When you find something in the dungeon, it is common to want to pick the\r
+object up.  This is accomplished in rogue by walking over the object.  If\r
+you are carrying too many things, the program will tell you and it won't pick\r
+up the object, otherwise it will add it to your pack and if the notify\r
+option is set, tell you what you just picked up.\r
+.PP\r
+Many of the commands that operate on objects must prompt you to find\r
+out which object you want to use.  If you change your mind and don't want to\r
+do that command after all, just press an escape and the command will be\r
+aborted.\r
+.NH\r
+Light\r
+.PP\r
+Rooms in the dungeons are either lit or dark.  If you walk into a lit room,\r
+the entire room will be drawn on the screen as soon as you enter.  If you\r
+walk into a dark room, it will only be displayed as you explore it.  Upon\r
+leaving a dark room, all objects inside the room which might move are\r
+removed from the screen.  In the darkness you can only see one space\r
+in all directions around you.\r
+.NH\r
+Fighting\r
+.PP\r
+If you see a monster and you wish to fight it, just attempt to run into it.\r
+Many times a monster you find will mind its own business unless you attack\r
+it.  It is often the case that discretion is the better part of valor.\r
+.NH\r
+Armor\r
+.PP\r
+There are various sorts of armor lying around in the dungeon.  Some of it\r
+is enchanted, some is cursed and some is just normal.  Different armor\r
+types have different armor classes.  The lower the armor class, the\r
+more protection the armor affords against the blows of monsters.\r
+If a piece of armor is enchanted or\r
+cursed, its armor class will be higher or lower than normal.  Here is\r
+a list of the various armor types and their normal armor class.\r
+.TS\r
+center box;\r
+c c\r
+l | c.\r
+Type   Class\r
+=\r
+Leather armor  8\r
+Studded leather / Ring mail    7\r
+Scale mail     6\r
+Chain mail     5\r
+Banded mail / Splint mail      4\r
+Plate mail     3\r
+.TE\r
+.NH\r
+Options\r
+.PP\r
+Due to variations in personal tastes and conceptions of the way rogue\r
+should do things, there are a set of options you can set that cause\r
+rogue to behave in various different ways.\r
+.NH 2\r
+Setting the options\r
+.PP\r
+There are basically two ways to set the options.  The first is with the\r
+"o" command of rogue, the second is with the ROGUEOPTS environment\r
+variable.  On Version 6 systems, there is no equivalent of\r
+the ROGUEOPTS feature.\r
+.NH 3\r
+Using the "o" command\r
+.PP\r
+When you press "o" in rogue, it clears the screen and displays the current\r
+settings for all the options.  It then places the cursor by the value of the\r
+first option and waits for you to type.  You can type a RETURN which means to\r
+go to the next option, a "\-" which means to go to the previous option, an\r
+escape which means to return to the game, or you can give the option a\r
+value.  For boolean options this merely involves pressing "t" for true or\r
+"f" for false.  For string options, type the new value followed by a\r
+return.\r
+.NH 3\r
+Using the ROGUEOPTS variable\r
+.PP\r
+The ROGUEOPTS variable is a string containing a comma separated list of\r
+initial values for the various options.  Boolean variables can be turned\r
+on by listing their name and turned off by putting a "no" in front of the\r
+name.  Thus to set up an environment variable so that jump is on, terse is\r
+off, the name is set to "Conan the Barbarian" and the fruit is "mango",\r
+use the command\r
+.nf\r
+.nf\r
+.ti +3\r
+% setenv ROGUEOPTS "jump,noterse,name=Conan the Barbarian,fruit=mango" \(dg\r
+.fi\r
+.ti +3\r
+% setenv ROGUEOPTS "jump,noterse,name=Conan the Barbarian,fruit=mango" \(dg\r
+.fi\r
+.FS\r
+\(dgFor those of you who use the bourne shell, the commands would be\r
+.in +3\r
+.nf\r
+$ ROGUEOPTS="jump,noterse,name=Conan the Barbarian,fruit=mango"\r
+$ export ROGUEOPTS\r
+.fi\r
+.in +0\r
+.FE\r
+.NH 2\r
+Option list\r
+.PP\r
+Here is a list of the options and an explanation of what each one is for.\r
+The default value for each is enclosed in square brackets.\r
+.IP "terse [noterse]" 25\r
+Useful for those who are tired of the sometimes lengthy messages of rogue.\r
+This is a useful option for those on slow terminals.  This option defaults to\r
+on if your are on a slow (under 1200 baud) terminal.\r
+.IP "jump [nojump]"\r
+If this option is set, running moves will not be displayed until you\r
+reach the end of the move.  This saves considerable cpu time and\r
+display time.  This option defaults to on if you are using a slow terminal.\r
+.IP "step [nostep]\r
+When step is set, lists of things, like inventories or "*" responses to\r
+"Which item do you wish to xxxx? " questions, are displayed one item\r
+at a time on the top of the screen, rather than clearing the screen,\r
+displaying the list, then re-displaying the dungeon level.\r
+.IP "flush [noflush]"\r
+If flush is set, all typeahead is thrown away after each round of battle.\r
+This is useful for those who type way ahead and watch to their dismay as\r
+a Kobold kills them.\r
+.IP "askme [noaskme]"\r
+Upon reading a scroll or quaffing a potion which does not automatically\r
+identify it upon use, rogue will ask you what to name it so you can\r
+recognize it in the future.\r
+.IP "name [account name]"\r
+This is the name of your character.  It is used if you get on the top ten\r
+scorer's list.  It should be less than eighty characters long.\r
+.IP "fruit [slime-mold]"\r
+This should hold the name of a fruit that you enjoy eating.  It is basically\r
+a whimsy that the program uses in a couple of places.\r
+.IP "file [rogue.save]"\r
+The default file name for saving the game.  If your phone is hung up by\r
+accident, rogue will automatically save the game in this file.  The\r
+file name may contain the special character "~" which expands to be\r
+your home directory.\r
+.NH\r
+Acknowledgements\r
+.PP\r
+Rogue was originally conceived of by Glenn Wichman and Michael Toy.  The\r
+help of Ken Arnold in making the program easier to use and putting the\r
+finishing touches on is greatly appreciated.  I would also like to thank\r
+Marty McNary, Scott Nelson, Daniel Jensen, Kipp Hickman, Joe Kalash,\r
+Steve Maurer, Bill Joy, Mark Horton and Jan Miller for their ideas\r
+and assistance.\r
diff --git a/rogue36.cat b/rogue36.cat
new file mode 100644 (file)
index 0000000..3ecefd9
--- /dev/null
@@ -0,0 +1,54 @@
+ROGUE(6)                                                              ROGUE(6)\r
+\r
+\r
+\r
+NAME\r
+       rogue - Exploring The Dungeons of Doom\r
+\r
+SYNOPSIS\r
+       rogue [ save_file ]\r
+\r
+DESCRIPTION\r
+       Rogue  is a computer fantasy game with a new twist.  It is crt oriented\r
+       and the object of the game is to survive the attacks  of  various  mon-\r
+       sters and get a lot of gold, rather than the puzzle solving orientation\r
+       of most computer fantasy games.\r
+\r
+       To get started you really only need to know two commands.  The  command\r
+       ?   will  give  you  a list of the available commands and the command /\r
+       will identify the things you see on the screen.\r
+\r
+       To win the game (as opposed to merely playing to beat other people high\r
+       scores)  you  must locate the Amulet of Yendor which is somewhere below\r
+       the 20th level of the dungeon and get it out.  Nobody has achieved this\r
+       yet  and  if  somebody does, they will probably go down in history as a\r
+       hero among heros.\r
+\r
+       When the game ends, either by your death, when you quit, or if you  (by\r
+       some  miracle)  manage to win, rogue will give you alist of the top-ten\r
+       scorers.  The scoring is based entirely upon how  much  gold  you  get.\r
+       There is a 10% penalty for getting yourself killed.\r
+\r
+       For more detailed directions, read the document A Guide to the Dungeons\r
+       of Doom.\r
+\r
+FILES\r
+       rogue36.scr                  Score file\r
+       ~/rogue36.sav                Default save file\r
+\r
+SEE ALSO\r
+       Michael C. Toy, A Guide to the Dungeons of Doom\r
+\r
+BUGS\r
+       Probably infinite.  Currently known bugs are: Sometimes you  are  still\r
+       hungry  even  after you eat food and sometimes you get a monster on the\r
+       screen in reverse video which may or may not cause a core dump.\r
+\r
+COPYRIGHT\r
+       Rogue: Exploring the Dungeons of Doom\r
+       Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+       All rights reserved.\r
+\r
+\r
+\r
+3rd Berkeley Distribution                                             ROGUE(6)\r
diff --git a/rogue36.doc b/rogue36.doc
new file mode 100644 (file)
index 0000000..9eef5a7
--- /dev/null
@@ -0,0 +1,660 @@
+
+
+
+
+
+
+
+
+
+              A Guide to the Dungeons of Doom
+
+                       Michael C. Toy
+              Computer Systems Research Group
+ Department of Electrical Engineering and Computer Science
+                  University of California
+                Berkeley, California  94720
+
+
+
+                          ABSTRACT
+
+          Rogue  is  a  visual  CRT  based fantasy game
+     which runs  under  the  UNIX  timesharing  system.
+     This paper describes how to play rogue and gives a
+     few hints for those who might otherwise  get  lost
+     in the Dungeons of Doom.
+
+
+
+11 July 2006
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+              A Guide to the Dungeons of Doom
+
+                       Michael C. Toy
+              Computer Systems Research Group
+ Department of Electrical Engineering and Computer Science
+                  University of California
+                Berkeley, California  94720
+
+
+1.  Introduction
+
+     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 mem-
+bership in the local guild. In addition, you are allowed  to
+keep all the loot you bring back from the dungeons.
+
+     In  preparation  for  your  journey,  you  are given an
+enchanted sword, 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.
+
+     You set out on your way to the dungeons and after  sev-
+eral  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  sword,  put  on your armor, eat what is almost
+your last food and enter the dungeons.
+
+2.  What is going on here?
+
+     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.
+
+     Rogue  differs from most computer fantasy games in that
+it  is  screen  oriented.   Commands  are  all  one  or  two
+keystrokes  and  the  results of your commands are displayed
+graphically on the screen rather  than  being  explained  in
+-----------
+As opposed to pseudo English sentences.
+
+
+
+                            - 1 -
+
+
+
+
+
+                             A Guide to the Dungeons of Doom
+
+
+words.
+
+     Another  major  difference between rogue and other com-
+puter 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.
+
+3.  What do all those things on the screen mean?
+
+     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  "You
+can  see  ..." descriptions of standard fantasy games.  Here
+is a sample of what a rogue screen might look like.
+                            ---------------------
+                            |...................+
+                            |...@...........[...|
+                            |........B..........|
+                            |...................|
+                            --------+------------
+
+
+          Level: 1  Gold: 0      Hp: 12(12)  Str: 16  Ac: 6  Exp: 1/0
+
+3.1.  The bottom line
+
+     At the bottom line of the screen is  a  few  pieces  of
+cryptic  information,  describing your current status.  Here
+is an explanation of what these things mean:
+
+Level   This number indicates how deep you have gone in  the
+        dungeon.  It starts at one and goes up forever.
+
+Gold    The  number  of gold pieces you have managed to find
+        and keep with you so far.
+
+Hp      Your current and maximum  hit  points.   Hit  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 hit points by resting. The
+        number in parentheses is the maximum number your hit
+        points can reach.
+
+Str     Your current strength.  This can be any integer less
+        than or equal to eighteen.  The higher  the  number,
+        the stronger you are.
+
+Ac      Your current armor class.  This number indicates how
+        effective your  armor  is  in  stopping  blows  from
+        unfriendly creatures.  The lower this number is, the
+-----------
+Or until you get killed or decide to quit.
+
+
+
+                            - 2 -
+
+
+
+
+
+                             A Guide to the Dungeons of Doom
+
+
+        more effective the armor.
+
+Exp     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.
+
+3.2.  The top line
+
+     The  top  line  of  the screen is reserved for printing
+messages that describe things that are impossible to  repre-
+sent  visually.   If  you  see a "--More--" 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
+press a space.
+
+3.3.  The rest of the screen
+
+     The  rest  of the screen is the map of the level as you
+have explored it so far.  Each symbol on the  screen  repre-
+sents something.  Here is a list of what the various symbols
+mean:
+
+@    This symbol represents you, the adventurer.
+
+-|    These symbols represent the walls of rooms.
+
++     A door to/from a room.
+
+.     The floor of a room.
+
+#     The floor of a passage between rooms.
+
+*     A pile or pot of gold.
+
+)     A weapon of some sort.
+
+]     A piece of armor.
+
+!     A flask containing a magic potion.
+
+?     A piece of paper, usually a magic scroll.
+
+^     A trap, watch out for these.
+
+%     The passage leading down to the next level.
+
+:     A piece of food.
+
+A-Z   The uppercase letters represent  the  various  inhabi-
+      tants of the Dungeons of Doom.  Watch out, they can be
+
+
+
+                            - 3 -
+
+
+
+
+
+                             A Guide to the Dungeons of Doom
+
+
+      mean.
+
+4.  Commands
+
+     Commands are given to rogue by pressing single letters.
+Most  commands  can  be  preceded  by a count to repeat them
+(e.g. typing "10s" will do ten searches) The  list  of  com-
+mands  is rather long, but it can be read at any time during
+the game with the ? command.  Here it is for reference, with
+a short explanation of each command.
+
+?     The  help  command.  Asks for a character to give help
+      on.  If you type a "*", it will list all the commands,
+      otherwise it will explain what the character you typed
+      does.
+
+/     This is the "What is that on the screen?"  command.  A
+      "/"  followed  by  any  character  that you see on the
+      level, will tell you  what  that  character  is.   For
+      instance,  typing "/@" will tell you that the @ symbol
+      represents you, the player.
+
+h , H Move left.  You move one space to the  left.   If  you
+      use upper case h, you will continue to move left until
+      you run into something.  This works for  all  movement
+      commands (e.g. "L" means run in direction "l")
+
+j     Move down.
+
+k     Move up.
+
+l     Move right.
+
+y     Move diagonally up and left.
+
+u     Move diagonally up and right.
+
+b     Move diagonally down and left.
+
+n     Move diagonally down and right.
+
+f     Find prefix.  When followed by a direction it means to
+      continue moving in the specified direction  until  you
+      pass something interesting or run into a wall.
+
+t     Throw an object.  This is a prefix command.  Follow it
+      with a direction and you throw an object in the speci-
+      fied  direction.   (e.g.  type "th" to throw something
+      left.)
+
+>     If you are standing over the passage down to the  next
+      level, this command means to climb down.
+
+
+
+
+
+                            - 4 -
+
+
+
+
+
+                             A Guide to the Dungeons of Doom
+
+
+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 some-
+      thing.
+
+      (space) Rest.  This is the "do nothing" command.  This
+      is good for waiting and healing.
+
+i     Inventory.  List what you are carrying in your pack.
+
+I     Selective  inventory.  Tells you what a single item in
+      your pack is.
+
+q     Quaff.  Drink one of the potions you are carrying.
+
+r     Read.  Read one of the scrolls in your pack.
+
+e     Eat food.  Take some food out of your pack and eat it.
+
+w     Wield  a  weapon.   Take a weapon out of your pack and
+      carry it.  You must be  wielding   weapon  to  use  it
+      (except  to throw things).  To fire an arrow, you must
+      wield the bow.  You can only wield  one  weapon  at  a
+      time.
+
+W     Wear  armor.   Take  a piece of armor out of your pack
+      and put it on.  You can only wear one suit of armor at
+      a time.
+
+T     Take  armor  off.   You  can't  remove  armor  that is
+      cursed.  This takes extra time.
+
+d     Drop an object.  Take something out of your  pack  and
+      leave  it  lying  on  the  floor.  Only one object can
+      occupy each space.
+
+o     Examine and set  options.   This  command  is  further
+      explained in the section on options.
+
+^L    REdraws  the  screen.  Useful  if spurious messages or
+      transmission errors have messed up the display.
+
+v     Prints the program version number.
+
+Q     Quit.  Leave the game.
+
+R     Repeat last message.  Useful when a message disappears
+      before you can read it.
+
+S     Save  the current game in a file.  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
+
+
+
+                            - 5 -
+
+
+
+
+
+                             A Guide to the Dungeons of Doom
+
+
+      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
+                % rogue save_file
+
+5.  Dealing with objects
+
+     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.  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 if the
+notify option is set, tell you what you just picked up.
+
+     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 press an escape and the command will be aborted.
+
+6.  Light
+
+     Rooms  in  the dungeons are either lit or dark.  If you
+walk into a lit room, the entire room will be drawn  on  the
+screen  as soon as you enter.  If you walk into a dark room,
+it will only be displayed as you explore it.  Upon leaving a
+dark  room, all objects inside the room which might move are
+removed from the screen.  In the darkness you can  only  see
+one space in all directions around you.
+
+7.  Fighting
+
+     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.
+
+8.  Armor
+
+     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
+classes.  The lower the armor class, the more protection the
+armor affords against the blows of monsters.  If a piece  of
+armor is enchanted or cursed, its armor class will be higher
+or lower than normal.  Here is a list of the  various  armor
+types and their normal armor class.
+
+
+
+
+
+
+
+
+
+
+                            - 6 -
+
+
+
+
+
+                             A Guide to the Dungeons of Doom
+
+
+           +------------------------------------+
+           |           Type               Class |
+           +----------------------------+-------+
+           |Leather armor               |   8   |
+           |Studded leather / Ring mail |   7   |
+           |Scale mail                  |   6   |
+           |Chain mail                  |   5   |
+           |Banded mail / Splint mail   |   4   |
+           |Plate mail                  |   3   |
+           +----------------------------+-------+
+
+9.  Options
+
+     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.
+
+9.1.  Setting the options
+
+     There are basically two ways to set the  options.   The
+first  is  with the "o" command of rogue, the second is with
+the ROGUEOPTS environment variable.  On Version  6  systems,
+there is no equivalent of the ROGUEOPTS feature.
+
+9.1.1.  Using the "o" command
+
+     When  you  press "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 RETURN which means to go to
+the  next  option,  a  "-" which means to go to the previous
+option, an escape which means to return to the game, or  you
+can  give  the  option  a  value.   For boolean options this
+merely involves pressing "t" for true or "f" for false.  For
+string options, type the new value followed by a return.
+
+9.1.2.  Using the ROGUEOPTS variable
+
+     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 and
+turned off by putting a "no" in front of the name.  Thus  to
+set  up an environment variable so that jump is on, terse is
+off, the name is set to "Conan the Barbarian" and the  fruit
+is "mango", use the command
+   % setenv ROGUEOPTS "jump,noterse,name=Conan the Barbarian,fruit=mango"
+   %  setenv  ROGUEOPTS "jump,noterse,name=Conan the Barbar-
+ian,fruit=mango"
+
+-----------
+For those of you who use  the  bourne  shell,  the
+commands would be
+   $ ROGUEOPTS="jump,noterse,name=Conan the Barbarian,fruit=mango"
+
+
+
+                            - 7 -
+
+
+
+
+
+                             A Guide to the Dungeons of Doom
+
+
+9.2.  Option list
+
+     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.
+
+terse [noterse]          Useful  for  those who are tired of
+                         the sometimes lengthy  messages  of
+                         rogue.  This is a useful option for
+                         those  on  slow  terminals.    This
+                         option  defaults  to on if your are
+                         on a slow (under 1200 baud)  termi-
+                         nal.
+
+jump [nojump]            If  this  option  is  set,  running
+                         moves will not be  displayed  until
+                         you  reach  the  end  of  the move.
+                         This saves  considerable  cpu  time
+                         and   display  time.   This  option
+                         defaults to on if you are  using  a
+                         slow terminal.
+
+step [nostep]            When  step is set, lists of things,
+                         like inventories or  "*"  responses
+                         to "Which item do you wish to xxxx?
+                         " questions, are displayed one item
+                         at a time on the top of the screen,
+                         rather than  clearing  the  screen,
+                         displaying  the  list, then re-dis-
+                         playing the dungeon level.
+
+flush [noflush]          If flush is set, all  typeahead  is
+                         thrown  away  after  each  round of
+                         battle.  This is useful  for  those
+                         who  type  way  ahead  and watch to
+                         their  dismay  as  a  Kobold  kills
+                         them.
+
+askme [noaskme]          Upon reading a scroll or quaffing a
+                         potion which does not automatically
+                         identify  it  upon  use, rogue will
+                         ask you what to name it so you  can
+                         recognize it in the future.
+
+name [account name]      This is the name of your character.
+                         It is used if you get  on  the  top
+                         ten  scorer's  list.   It should be
+                         less than eighty characters long.
+
+fruit [slime-mold]       This should  hold  the  name  of  a
+                         fruit that you enjoy eating.  It is
+                         basically a whimsy that the program
+-----------
+   $ export ROGUEOPTS
+
+
+
+                            - 8 -
+
+
+
+
+
+                             A Guide to the Dungeons of Doom
+
+
+                         uses in a couple of places.
+
+file [rogue.save]        The  default  file  name for saving
+                         the game.  If your phone is hung up
+                         by  accident,  rogue will automati-
+                         cally save the game in  this  file.
+                         The  file name may contain the spe-
+                         cial character "~" which expands to
+                         be your home directory.
+
+10.  Acknowledgements
+
+     Rogue  was originally conceived of by Glenn Wichman and
+Michael Toy.  The help of Ken Arnold in making  the  program
+easier  to  use  and  putting  the  finishing  touches on is
+greatly appreciated.  I  would  also  like  to  thank  Marty
+McNary,  Scott  Nelson,  Daniel  Jensen,  Kipp  Hickman, Joe
+Kalash, Steve Maurer, Bill Joy, Mark Horton and  Jan  Miller
+for their ideas and assistance.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                            - 9 -
+
+
diff --git a/rogue36.html b/rogue36.html
new file mode 100644 (file)
index 0000000..d5a70a2
--- /dev/null
@@ -0,0 +1,633 @@
+<html>\r
+<head>\r
+<title></title>\r
+</head>\r
+<body>\r
+\r
+<h1 align=center><b>A Guide to the Dungeons of Doom</b></h1>\r
+\r
+<h2 align=center><i>Michael C. Toy</i></h2>\r
+\r
+<h3 align=center>\r
+Computer Systems Research Group<br>\r
+Department of Electrical Engineering and Computer Science<br>\r
+University of California<br>\r
+Berkeley, California 94720</h3>\r
+\r
+<h2 align=center><i>ABSTRACT</i></h2>\r
+\r
+<blockquote>\r
+       <blockquote>\r
+               <p align="justify"><font size="2">Rogue is a visual CRT based fantasy game which runs under the \r
+               UNIX timesharing system. This paper describes how to play rogue, and gives a few hints for \r
+               those who might otherwise get \r
+               lost in the Dungeons of Doom.</font></p>\r
+       </blockquote>\r
+</blockquote>\r
+\r
+<h2 align="justify"><b>1. Introduction</b></h2>\r
+\r
+<p align="justify">You have just finished your years as a\r
+student at the local fighter&rsquo;s guild. After much\r
+practice and sweat you have finally completed your training\r
+and are ready to embark upon a perilous adventure. As a test\r
+of your skills, the local guildmasters have sent you into\r
+the Dungeons of Doom. Your task is to return with the Amulet\r
+of Yendor. Your reward for the completion of this task will\r
+be a full membership in the local guild. In addition, you\r
+are allowed to keep all the loot you bring back from the\r
+dungeons.</p>\r
+\r
+<p align="justify">In preparation for your journey, you are\r
+given an enchanted sword, taken\r
+from a dragon&rsquo;s hoard in the far off Dark Mountains.\r
+You are also outfitted with elf-crafted armor and given\r
+enough food to reach the dungeons. You say goodbye to family\r
+and friends for what may be the last time and head up the\r
+road.</p>\r
+\r
+<p align="justify">You set out on your way to the dungeons and\r
+after several days of uneventful travel, you see the\r
+ancient ruins that mark the entrance to the Dungeons of\r
+Doom. It is late at night so you make camp at the entrance\r
+and spend the night sleeping under the open skies. In the\r
+morning you gather your sword, put on your armor, eat what\r
+is almost your last food and enter the\r
+dungeons.</p>\r
+\r
+<h2 align="justify"><b>2. What is going on here?</b></h2>\r
+\r
+<p align="justify">You have just begun a game of rogue. Your\r
+goal is to grab as much treasure as you can, find the Amulet\r
+of Yendor, and get out of the Dungeons of Doom alive. On the\r
+screen, a map of where you have been and what you have seen\r
+on the current dungeon level is kept. As you explore more of\r
+the level, it appears on the screen in front of\r
+you.</p>\r
+\r
+<p align="justify">Rogue differs from most computer fantasy\r
+games in that it is screen oriented. Commands are all one or\r
+two keystrokes<sup>1 </sup>and the\r
+results of your commands are displayed graphically on the\r
+screen rather than being explained in words<sup>2</sup>.</p>\r
+\r
+<p align="justify">Another major difference between rogue and \r
+other computer fantasy games is that once you have solved\r
+all the puzzles in a standard fantasy game, it has lost most\r
+of its excitement and it ceases to be fun. Rogue on the\r
+other hand generates a new dungeon every time you play it\r
+and even the author finds it an entertaining and exciting\r
+game.</p>\r
+\r
+<h2 align="justify"><b>3. What do all those things on the screen mean?</b></h2>\r
+\r
+<p align="justify">In order to understand what is going on in\r
+rogue you have to first get some grasp of what rogue is\r
+doing with the screen. The rogue screen is intended to\r
+replace the &ldquo;You can see ...&rdquo; descriptions of\r
+standard fantasy games. Here is a sample of what a \r
+rogue screen might look like.</p>\r
+\r
+<div align="center"><pre>\r
+                  ---------------------\r
+                  |...................+\r
+                  |...@...........[...|\r
+                  |........B..........|\r
+                  |...................|\r
+                  --------+------------\r
+\r
+Level: 1  Gold: 0      Hp: 12(12)  Str: 16  Ac: 6  Exp: 1/0\r
+</pre></div>\r
+\r
+<h3 align="justify"><b>3.1. The bottom line</b></h3>\r
+\r
+<p align="justify">At the bottom line of the screen is a few\r
+pieces of cryptic information describing your current\r
+status. Here is an explanation of what these things\r
+mean:</p>\r
+\r
+<table border="0" width="100%" id="table1" cellspacing="3" cellpadding="3">\r
+       <tr>\r
+               <td><p align="justify">Level&nbsp;&nbsp;</p></td>\r
+               <td><p align="justify">This number indicates how deep you have gone in the \r
+               dungeon. It starts at one and goes up forever<sup>2</sup>.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td><p align="justify">Gold</p></td>\r
+               <td><p align="justify">The number of gold pieces you have managed to find \r
+               and keep with you so far.</td>\r
+       </tr>\r
+       <tr>\r
+               <td><p align="justify">Hp</p></td>\r
+               <td><p align="justify">Your current and maximum hit points.\r
+               Health points indicate how much damage you can take before\r
+               you die. The more you get hit in a fight, the lower they\r
+               get. You can regain health points by resting. The number in\r
+               parentheses is the maximum number your hit points can\r
+               reach.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td><p align="justify">Str</p></td>\r
+               <td><p align="justify">Your current strength. This can be any \r
+               integer less than or equal to eighteen. The higher the number, \r
+               the stronger you are.</td>\r
+       </tr>\r
+       <tr>\r
+               <td><p align="justify">Ac</p></td>\r
+               <td><p align="justify">Your current armor class. This number \r
+               indicates how effective your armor is in stopping blows from \r
+               unfriendly creatures. The lower this number is, the more \r
+               effective the armor.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td><p align="justify">Exp</p></td>\r
+               <td><p align="justify">These two numbers give your current experience \r
+               level and experience points. As you do things, you gain experience\r
+               points. At certain experience point totals, you gain an\r
+               experience level. The more experienced you are, the better\r
+               you are able to fight and to withstand magical attacks.</p></td>\r
+       </tr>\r
+</table>\r
+\r
+<h3 align="justify"><b>3.2. The top line</b></h3>\r
+\r
+<p align="justify">The top line of the screen is reserved for\r
+printing messages that describe things that are impossible\r
+to represent visually. If you see a &ldquo;--More--&rdquo;\r
+on the top line, this means that rogue wants to print\r
+another message on the screen, but it wants to make certain\r
+that you have read the one that is there first. To read the\r
+next message, just type a space.</p>\r
+\r
+<h3 align="justify"><b>3.3. The rest of the screen</b></h3>\r
+\r
+<p align="justify">The rest of the screen is the map of the\r
+level as you have explored it so far. Each symbol on the\r
+screen represents something. Here is a list of what the\r
+various symbols mean:</p>\r
+\r
+<table border="0" width="100%" id="table2" cellspacing="3" cellpadding="3">\r
+       <tr>\r
+               <td>@</td>\r
+               <td><p align="justify">This symbol represents you, the adventurer.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>- |</td>\r
+               <td><p align="justify">These symbols represent the walls of rooms.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>+</td>\r
+               <td>\r
+               <p align="justify">A door to/from a room.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>.</td>\r
+               <td><p align="justify">The floor of a room.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>#</td>\r
+               <td><p align="justify">The floor of a passage between rooms.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>*</td>\r
+               <td><p align="justify">A pile or pot of gold.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>)</td>\r
+               <td><p align="justify">A weapon of some sort.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>]</td>\r
+               <td><p align="justify">A piece of armor.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>!</td>\r
+               <td><p align="justify">A flask containing a magic potion.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>?</td>\r
+               <td><p align="justify">A piece of paper, usually a magic scroll.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>^</td>\r
+               <td><p align="justify">A trap, watch out for these.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>%</td>\r
+               <td><p align="justify">The passage leading down to the next level.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>:</td>\r
+               <td><p align="justify">A piece of food.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>A-Z&nbsp;&nbsp;</td>\r
+               <td><p align="justify">The uppercase letters represent the various \r
+               inhabitants of the Dungeons of Doom. Watch out, they can be mean.</p></td>\r
+       </tr>\r
+</table>\r
+\r
+<h2 align="justify"><b>4. Commands</b></h2>\r
+\r
+<p align="justify">Commands are given to rogue by pressing single letters.\r
+Most commands can be preceded by a count to repeat them\r
+(e.g. typing &quot;10s&quot; will do ten searches) The list\r
+of commands is rather long, but it can be read at any time\r
+during the game with the ? command. Here it is for\r
+reference, with a short explanation of each command.</p>\r
+\r
+<div align="center">\r
+<table border="0" cellspacing="3" cellpadding="3" id="table3">\r
+       <tr>\r
+               <td>?</td>\r
+               <td><p align="justify">The help command. Asks for a character to give help \r
+               on. If you type a &quot;*&quot;, it will list all the commands,\r
+               otherwise it will explain what the character you typed\r
+               does.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>/</td>\r
+               <td align="justify"><p>This is the &quot;What is that on the screen?&quot;\r
+               command. A &quot;/&quot; followed by any character that you\r
+               see on the level, will tell you what that character is. For\r
+               instance, typing &quot;/@&quot; will tell you that the @\r
+               symbol represents you, the player.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td colspan="2">h, H</td>\r
+       </tr>\r
+       <tr>\r
+               <td>&nbsp;</td>\r
+               <td><p align="justify">Move left. You move one space to the left. If you use\r
+               upper case h, you will continue to move left until you run into something. \r
+               This works for all movement commands (e.g. &quot;L&quot; means run in direction\r
+               &quot;l&quot;)</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>j</td>\r
+               <td><p align="justify">Move down.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>k</td>\r
+               <td><p align="justify">Move up.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>l</td>\r
+               <td><p align="justify">Move right.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>y</td>\r
+               <td><p align="justify">Move diagonally up and left.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>u</td>\r
+               <td><p align="justify">Move diagonally up and right.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>b</td>\r
+               <td><p align="justify">Move diagonally down and left.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>n</td>\r
+               <td><p align="justify">Move diagonally down and right.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>t</td>\r
+               <td><p align="justify">Throw an object. This is a prefix command. When \r
+               followed with a direction it throws an object in the specified direction. \r
+               (e.g. type &ldquo;th&rdquo; to throw something to the left.)</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>f</td>\r
+               <td><p align="justify">Find prefix. When followed by a direction it means to\r
+               continue moving in the specified direction until you pass\r
+               something interesting or run into a wall.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>t</td>\r
+               <td><p align="justify">Throw an object. This is a prefix command. Follow it\r
+               with a direction and you throw an object in the specified\r
+               direction. (e.g. type &quot;th&quot; to throw something\r
+               left.)</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>&gt;</td>\r
+               <td><p align="justify">If you are standing over the passage down to the next\r
+               level, this command means to climb down.</p></td>\r
+               </tr>\r
+       <tr>\r
+               <td>s</td>\r
+               <td><p align="justify">Search for traps and secret doors. Examine each space\r
+               immediately adjacent to you for the existence of a trap or\r
+               secret door. There is a large chance that even if there is\r
+               something there, you won&rsquo;t find it so you might have\r
+               to search a while before you find something.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>&nbsp;</td>\r
+               <td><p align="justify">(space) Rest. This is the &quot;do nothing&quot;\r
+               command. This is good for waiting and healing.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td align="left" valign="top">\r
+               <p>i</td>\r
+               <td align="justify">\r
+               <p>Inventory. List what you are carrying in your pack.</td>\r
+       </tr>\r
+       <tr>\r
+               <td>I</td>\r
+               <td><p align="justify">Selective inventory. Tells you what a single item in\r
+               your pack is.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>q</td>\r
+               <td><p align="justify">Quaff. Drink one of the potions you are \r
+               carrying.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>r</td>\r
+               <td><p align="justify">Read. Read one of the scrolls in your pack.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>e</td>\r
+               <td><p align="justify">Eat food. Take some food out of your pack and eat\r
+               it.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>w</td>\r
+               <td><p align="justify">Wield a weapon. Take a weapon out of your pack and \r
+               carry it. You must be wielding weapon to use it (except to throw\r
+               things). To fire an arrow, you must wield the bow. You can\r
+               only wield one weapon at a time.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>W</td>\r
+               <td><p align="justify">Wear armor. Take a piece of armor out of your pack\r
+               and put it on. You can only wear one suit of armor at a time.</td>\r
+       </tr>\r
+       <tr>\r
+               <td>T</td>\r
+               <td><p align="justify">Take armor off. You can&rsquo;t remove armor that is\r
+               cursed. This takes extra time.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>d</td>\r
+               <td><p align="justify">Drop an object. Take something out of your pack and\r
+               leave it lying on the floor. Only one object can occupy each\r
+               space.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>o</td>\r
+               <td><p align="justify">Examine and set options. This command is further\r
+               explained in the section on options.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>^L</td>\r
+               <td><p align="justify">Redraws the screen. Useful if spurious messages or\r
+               transmission errors have messed up the display.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>v</td>\r
+               <td><p align="justify">Prints the program version number.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>Q</td>\r
+               <td><p align="justify">Quit. Leave the game.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>R</td>\r
+               <td><p align="justify">Repeat last message. Useful when a message disappears\r
+               before you can read it.</p></td>\r
+       </tr>\r
+       <tr>\r
+               <td>S</td>\r
+               <td><p align="justify">Save the current game in a file. Caveat: Rogue\r
+               won&rsquo;t let you start up a copy of a saved game, and it\r
+               removes the save file as soon as you start up a restored\r
+               game. This is to prevent people from saving a game just\r
+               before a dangerous position and then restarting it if they\r
+               die. To restore a saved game, give the file name as an\r
+               argument to rogue. As in % rogue36 save_file</p></td>\r
+       </tr>\r
+</table>\r
+</div>\r
+\r
+<h2 align="justify"><b>5. Dealing with objects</b></h2>\r
+\r
+<p align="justify">When you find something in the dungeon, it is common to\r
+want to pick the object up. This is accomplished in rogue by\r
+walking over the object. If you are carrying too many\r
+things, the program will tell you and it won&rsquo;t pick up\r
+the object, otherwise it will add it to your pack and if the\r
+notify option is set, tell you what you just picked up.</p>\r
+\r
+<p align="justify">Many of the commands that operate on objects must prompt\r
+you to find out which object you want to use. If you change\r
+your mind and don&rsquo;t want to do that command after all,\r
+just press an escape and the command will be aborted.</p>\r
+\r
+<h2 align="justify"><b>6. Light</b></h2>\r
+\r
+<p align="justify">Rooms in the dungeons are either lit or dark. If you\r
+walk into a lit room, the entire room will be drawn on the\r
+screen as soon as you enter. If you walk into a dark room,\r
+it will only be displayed as you explore it. Upon leaving a\r
+dark room, all objects inside the room which might move are\r
+removed from the screen. In the darkness you can only see\r
+one space in all directions around you.</p>\r
+\r
+<h2 align="justify"><b>7. Fighting</b></h2>\r
+<p align="justify">If you see a monster and you wish to fight it, just\r
+attempt to run into it. Many times a monster you find will\r
+mind its own business unless you attack it. It is often the\r
+case that discretion is the better part of valor.</p>\r
+\r
+<h2 align="justify">8<b>. Armor</b></h2>\r
+\r
+<p align="justify">There are various sorts of armor lying around in the\r
+dungeon. Some of it is enchanted, some is cursed and some is\r
+just normal. Different armor types have different armor\r
+classes. The lower the armor class, the more protection the\r
+armor affords against the blows of monsters. If a piece of\r
+armor is enchanted or cursed, its armor class will be higher\r
+or lower than normal. Here is a list of the various armor\r
+types and their normal armor class.</p>\r
+\r
+<div align="center">\r
+       <table border="1" cellspacing="3" cellpadding="3" id="table4" style="border-collapse: collapse">\r
+               <tr>\r
+                       <th><i>Type</i></th>\r
+                       <th><i>Class</i></th>\r
+               </tr>\r
+               <tr>\r
+                       <td>Leather armor</td>\r
+                       <td align="center">8</td>\r
+               </tr>\r
+               <tr>\r
+                       <td>Studded leather / Ring mail</td>\r
+                       <td align="center">7</td>\r
+               </tr>\r
+               <tr>\r
+                       <td>Scale mail </td>\r
+                       <td align="center">6</td>\r
+               </tr>\r
+               <tr>\r
+                       <td>Chain mail&nbsp; </td>\r
+                       <td align="center">5</td>\r
+               </tr>\r
+               <tr>\r
+                       <td>Banded mail / Splint mail</td>\r
+                       <td align="center">4</td>\r
+               </tr>\r
+               <tr>\r
+                       <td>Plate mail</td>\r
+                       <td align="center">3</td>\r
+               </tr>\r
+       </table>\r
+</div>\r
+\r
+<h2 align="justify">9<b>. Options</b></h2>\r
+\r
+<p align="justify">Due to variations in personal tastes and conceptions of\r
+the way rogue should do things, there are a set of options\r
+you can set that cause rogue to behave in various different\r
+ways.</p>\r
+\r
+<h3 align="justify"><b>9.1 Setting the options</b></h3>\r
+\r
+<p align="justify">There are basically two ways to set the options. The\r
+first is with the &quot;o&quot; command of rogue, the second\r
+is with the ROGUEOPTS environment variable. On Version 6\r
+systems, there is no equivalent of the ROGUEOPTS\r
+feature.</p>\r
+\r
+<h3 align="justify"><b>9.1.1. Using the &quot;o&quot; command</b></h3>\r
+\r
+<p align="justify">When you press &quot;o&quot; in rogue, it clears the\r
+screen and displays the current settings for all the\r
+options. It then places the cursor by the value of the first\r
+option and waits for you to type. You can type a RETURN\r
+which means to go to the next option, a &quot;&minus;&quot;\r
+which means to go to the previous option, an escape which\r
+means to return to the game, or you can give the option a\r
+value. For boolean options this merely involves pressing\r
+&quot;t&quot; for true or &quot;f&quot; for false. For\r
+string options, type the new value followed by a return.</p>\r
+\r
+<h3 align="justify">9<b>.1.2. Using the ROGUEOPTS variable</b></h3>\r
+\r
+<p align="justify">The ROGUEOPTS variable is a string containing a comma\r
+separated list of initial values for the various options.\r
+Boolean variables can be turned on by listing their name and\r
+turned off by putting a &quot;no&quot; in front of the name.\r
+Thus to set up an environment variable so that jump is on,\r
+terse is off, the name is set to &quot;Conan the\r
+Barbarian&quot; and the fruit is &quot;mango&quot;, use the\r
+command</p>\r
+\r
+<div align="justify"><pre>\r
+   % setenv ROGUEOPTS &quot;jump,noterse,name=Conan the Barbarian,fruit=mango&quot;<sup>3</sup>\r
+</pre></div>\r
+\r
+<h3 align="justify"><b>9.2. Option list</b></h3>\r
+\r
+<p align="justify">Here is a list of the options and an explanation of what\r
+each one is for. The default value for each is enclosed in\r
+square brackets.</p>\r
+\r
+<p align="justify"><b>terse</b>[<i>noterse</i>]</p>\r
+<blockquote>\r
+       <p align="justify">\r
+       Useful for those who are tired of the sometimes lengthy\r
+       messages of rogue. This is a useful option for those on slow\r
+       terminals. This option defaults to on if your are on a slow\r
+       (under 1200 baud) terminal.</p>\r
+</blockquote>\r
+\r
+<p align="justify"><b>jump</b>[<i>nojump</i>]</p>\r
+<blockquote>\r
+       <p align="justify">If this option is set, running moves will not be\r
+       displayed until you reach the end of the move. This saves\r
+       considerable cpu time and display time. This option defaults\r
+       to on if you are using a slow terminal.</p>\r
+</blockquote>\r
+\r
+<p align="justify"><b>step</b>[<i>nostep</i>]</p>\r
+<blockquote>\r
+       <p align="justify">When step is set, lists of things, like inventories or\r
+       &quot;*&quot; responses to &quot;Which item do you wish to\r
+       xxxx? &quot; questions, are displayed one item at a time on\r
+       the top of the screen, rather than clearing the screen,\r
+       displaying the list, then re-displaying the dungeon\r
+       level.</p>\r
+</blockquote>\r
+\r
+<p align="justify"><b>flush</b>[<i>noflush</i>]</p>\r
+<blockquote>\r
+       <p align="justify">If flush is set, all typeahead is thrown away after each\r
+       round of battle. This is useful for those who type way ahead\r
+       and watch to their dismay as a Kobold kills them.</p>\r
+</blockquote>\r
+\r
+<p align="justify"><b>askme</b>[<i>noaskme</i>]</p>\r
+<blockquote>\r
+       <p align="justify">Upon reading a scroll or quaffing a potion which does\r
+       not automatically identify it upon use, rogue will ask you\r
+       what to name it so you can recognize it in the future.</p>\r
+</blockquote>\r
+\r
+<p align="justify"><b>name</b> [account name]</p>\r
+<blockquote>\r
+       <p align="justify">This is the name of your character. It is used if you\r
+       get on the top ten scorer&rsquo;s list. It should be less\r
+       than eighty characters long.</p>\r
+</blockquote>\r
+\r
+<p align="justify"><b>fruit</b>[<i>slime-mold</i>]</p>\r
+<blockquote>\r
+       <p align="justify">This should hold the name of a fruit that you enjoy\r
+       eating. It is basically a whimsy that the program uses in a\r
+       couple of places.</p>\r
+</blockquote>\r
+\r
+<p align="justify"><b>file</b>[<i>rogue.save</i>]</p>\r
+<blockquote>\r
+       <p align="justify">The default file name for saving the game. If your phone\r
+       is hung up by accident, rogue will automatically save the\r
+       game in this file. The file name may contain the special\r
+       character &quot;~&quot; which expands to be your home\r
+       directory.</p>\r
+</blockquote>\r
+\r
+<h2 align="justify"><br>\r
+\r
+<b>10. Acknowledgements</b></h2>\r
+\r
+<p align="justify">Rogue was originally conceived of by Glenn Wichman and\r
+Michael Toy. The help of Ken Arnold in making the program\r
+easier to use and putting the finishing touches on is\r
+greatly appreciated. I would also like to thank Marty\r
+McNary, Scott Nelson, Daniel Jensen, Kipp Hickman, Joe\r
+Kalash, Steve Maurer, Bill Joy, Mark Horton and Jan Miller\r
+for their ideas and assistance.</p>\r
+\r
+<table border="0" width="100%" cellspacing="3" cellpadding="0" id="table5">\r
+       <tr>\r
+               <td align="center"><sup>1</sup></td>\r
+               <td>As opposed to pseudo English sentences.</td>\r
+       </tr>\r
+       <tr>\r
+               <td align="center"><sup>2</sup></td>\r
+               <td>Or until you get killed or decide to quit.</td>\r
+       </tr>\r
+       <tr>\r
+               <td align="center"><sup>3</sup>&nbsp;&nbsp;</td>\r
+               <td><p>For those of you who use the Bourne shell, the commands would be</p>\r
+<pre>    $ ROGUEOPTS=&quot;jump,noterse,name=Conan the Barbarian,fruit=mango&quot;\r
+    $ export ROGUEOPTS</pre>\r
+               </td>\r
+       </tr>\r
+</table>\r
+\r
+</body>\r
+</html>
\ No newline at end of file
diff --git a/rogue36.sln b/rogue36.sln
new file mode 100644 (file)
index 0000000..2b4f12e
--- /dev/null
@@ -0,0 +1,20 @@
+\r
+Microsoft Visual Studio Solution File, Format Version 9.00\r
+# Visual C++ Express 2005\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rogue36", "rogue36.vcproj", "{B986AB16-E9C2-4299-A772-F02B28620521}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Debug|Win32 = Debug|Win32\r
+               Release|Win32 = Release|Win32\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {B986AB16-E9C2-4299-A772-F02B28620521}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {B986AB16-E9C2-4299-A772-F02B28620521}.Debug|Win32.Build.0 = Debug|Win32\r
+               {B986AB16-E9C2-4299-A772-F02B28620521}.Release|Win32.ActiveCfg = Release|Win32\r
+               {B986AB16-E9C2-4299-A772-F02B28620521}.Release|Win32.Build.0 = Release|Win32\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/rogue36.vcproj b/rogue36.vcproj
new file mode 100644 (file)
index 0000000..4878426
--- /dev/null
@@ -0,0 +1,360 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="rogue36"\r
+       ProjectGUID="{B986AB16-E9C2-4299-A772-F02B28620521}"\r
+       RootNamespace="rogue36"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+                       IntermediateDirectory="$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="../pdcurses"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;$(NOINHERIT)"\r
+                               MinimalRebuild="false"\r
+                               ExceptionHandling="0"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="1"\r
+                               DisableSpecificWarnings="4033;4716;4013;4131;4244;4201;4431;4127;4706;4100"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="Ws2_32.lib pdcurses.lib advapi32.lib shfolder.lib user32.lib"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="../pdcurses"\r
+                               IgnoreDefaultLibraryNames="LIBC.LIB"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+                       IntermediateDirectory="$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="1"\r
+                       WholeProgramOptimization="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"\r
+                               RuntimeLibrary="2"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\armor.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\chase.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\command.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\daemon.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\daemons.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\fight.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\init.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\io.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\list.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\main.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\mdport.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\misc.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\monsters.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\move.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\newlevel.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\options.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\pack.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\passages.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\potions.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\rings.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\rip.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\rooms.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\save.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\scrolls.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\state.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\sticks.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\things.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\vers.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\weapons.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\wizard.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\xcrypt.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\machdep.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\rogue.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+               <File\r
+                       RelativePath=".\LICENSE.TXT"\r
+                       >\r
+               </File>\r
+               <File\r
+                       RelativePath=".\Makefile"\r
+                       >\r
+               </File>\r
+               <File\r
+                       RelativePath=".\readme36.html"\r
+                       >\r
+               </File>\r
+               <File\r
+                       RelativePath=".\rogue.r"\r
+                       >\r
+               </File>\r
+               <File\r
+                       RelativePath=".\rogue36.cat"\r
+                       >\r
+               </File>\r
+               <File\r
+                       RelativePath=".\rogue36.doc"\r
+                       >\r
+               </File>\r
+               <File\r
+                       RelativePath=".\rogue36.html"\r
+                       >\r
+               </File>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/rooms.c b/rooms.c
new file mode 100644 (file)
index 0000000..0e4530e
--- /dev/null
+++ b/rooms.c
@@ -0,0 +1,185 @@
+/*\r
+ * Draw the nine rooms on the screen\r
+ *\r
+ * @(#)rooms.c 3.8 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include "rogue.h"\r
+\r
+do_rooms()\r
+{\r
+    register int i;\r
+    register struct room *rp;\r
+    register struct linked_list *item;\r
+    register struct thing *tp;\r
+    register int left_out;\r
+    coord top;\r
+    coord bsze;\r
+    coord mp;\r
+\r
+    /*\r
+     * bsze is the maximum room size\r
+     */\r
+    bsze.x = COLS/3;\r
+    bsze.y = LINES/3;\r
+    /*\r
+     * Clear things for a new level\r
+     */\r
+    for (rp = rooms; rp <= &rooms[MAXROOMS-1]; rp++)\r
+       rp->r_goldval = rp->r_nexits = rp->r_flags = 0;\r
+    /*\r
+     * Put the gone rooms, if any, on the level\r
+     */\r
+    left_out = rnd(4);\r
+    for (i = 0; i < left_out; i++)\r
+       rooms[rnd_room()].r_flags |= ISGONE;\r
+    /*\r
+     * dig and populate all the rooms on the level\r
+     */\r
+    for (i = 0, rp = rooms; i < MAXROOMS; rp++, i++)\r
+    {\r
+       /*\r
+        * Find upper left corner of box that this room goes in\r
+        */\r
+       top.x = (i%3)*bsze.x + 1;\r
+       top.y = i/3*bsze.y;\r
+       if (rp->r_flags & ISGONE)\r
+       {\r
+           /*\r
+            * Place a gone room.  Make certain that there is a blank line\r
+            * for passage drawing.\r
+            */\r
+           do\r
+           {\r
+               rp->r_pos.x = top.x + rnd(bsze.x-2) + 1;\r
+               rp->r_pos.y = top.y + rnd(bsze.y-2) + 1;\r
+               rp->r_max.x = -COLS;\r
+               rp->r_max.y = -LINES;\r
+           } until(rp->r_pos.y > 0 && rp->r_pos.y < LINES-1);\r
+           continue;\r
+       }\r
+       if (rnd(10) < level-1)\r
+           rp->r_flags |= ISDARK;\r
+       /*\r
+        * Find a place and size for a random room\r
+        */\r
+       do\r
+       {\r
+           rp->r_max.x = rnd(bsze.x - 4) + 4;\r
+           rp->r_max.y = rnd(bsze.y - 4) + 4;\r
+           rp->r_pos.x = top.x + rnd(bsze.x - rp->r_max.x);\r
+           rp->r_pos.y = top.y + rnd(bsze.y - rp->r_max.y);\r
+       } until (rp->r_pos.y != 0);\r
+       /*\r
+        * Put the gold in\r
+        */\r
+       if (rnd(100) < 50 && (!amulet || level >= max_level))\r
+       {\r
+           rp->r_goldval = GOLDCALC;\r
+           rnd_pos(rp, &rp->r_gold);\r
+           if (roomin(&rp->r_gold) != rp)\r
+               endwin(), abort();\r
+       }\r
+       draw_room(rp);\r
+       /*\r
+        * Put the monster in\r
+        */\r
+       if (rnd(100) < (rp->r_goldval > 0 ? 80 : 25))\r
+       {\r
+           item = new_item(sizeof *tp);\r
+           tp = (struct thing *) ldata(item);\r
+           do\r
+           {\r
+               rnd_pos(rp, &mp);\r
+           } until(mvwinch(stdscr, mp.y, mp.x) == FLOOR);\r
+           new_monster(item, randmonster(FALSE), &mp);\r
+           /*\r
+            * See if we want to give it a treasure to carry around.\r
+            */\r
+           if (rnd(100) < monsters[tp->t_type-'A'].m_carry)\r
+               attach(tp->t_pack, new_thing());\r
+       }\r
+    }\r
+}\r
+\r
+/*\r
+ * Draw a box around a room\r
+ */\r
+\r
+draw_room(rp)\r
+register struct room *rp;\r
+{\r
+    register int j, k;\r
+\r
+    move(rp->r_pos.y, rp->r_pos.x+1);\r
+    vert(rp->r_max.y-2);                               /* Draw left side */\r
+    move(rp->r_pos.y+rp->r_max.y-1, rp->r_pos.x);\r
+    horiz(rp->r_max.x);                                        /* Draw bottom */\r
+    move(rp->r_pos.y, rp->r_pos.x);\r
+    horiz(rp->r_max.x);                                        /* Draw top */\r
+    vert(rp->r_max.y-2);                               /* Draw right side */\r
+    /*\r
+     * Put the floor down\r
+     */\r
+    for (j = 1; j < rp->r_max.y-1; j++)\r
+    {\r
+       move(rp->r_pos.y + j, rp->r_pos.x+1);\r
+       for (k = 1; k < rp->r_max.x-1; k++)\r
+           addch(FLOOR);\r
+    }\r
+    /*\r
+     * Put the gold there\r
+     */\r
+    if (rp->r_goldval)\r
+       mvaddch(rp->r_gold.y, rp->r_gold.x, GOLD);\r
+}\r
+\r
+/*\r
+ * horiz:\r
+ *     draw a horizontal line\r
+ */\r
+\r
+horiz(cnt)\r
+register int cnt;\r
+{\r
+    while (cnt--)\r
+       addch('-');\r
+}\r
+\r
+/*\r
+ * vert:\r
+ *     draw a vertical line\r
+ */\r
+\r
+vert(cnt)\r
+register int cnt;\r
+{\r
+    register int x, y;\r
+\r
+    getyx(stdscr, y, x);\r
+    x--;\r
+    while (cnt--) {\r
+       move(++y, x);\r
+       addch('|');\r
+    }\r
+}\r
+\r
+/*\r
+ * rnd_pos:\r
+ *     pick a random spot in a room\r
+ */\r
+\r
+rnd_pos(rp, cp)\r
+register struct room *rp;\r
+register coord *cp;\r
+{\r
+    cp->x = rp->r_pos.x + rnd(rp->r_max.x-2) + 1;\r
+    cp->y = rp->r_pos.y + rnd(rp->r_max.y-2) + 1;\r
+}\r
diff --git a/save.c b/save.c
new file mode 100644 (file)
index 0000000..03f4511
--- /dev/null
+++ b/save.c
@@ -0,0 +1,276 @@
+/*\r
+ * save and restore routines\r
+ *\r
+ * @(#)save.c  3.9 (Berkeley) 6/16/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <ctype.h>\r
+#include <sys/types.h>\r
+#include <sys/stat.h>\r
+#include <signal.h>\r
+#include <errno.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include "rogue.h"\r
+#include "machdep.h"\r
+\r
+typedef struct stat STAT;\r
+\r
+extern char version[], encstr[];\r
+\r
+STAT sbuf;\r
+\r
+save_game()\r
+{\r
+    register FILE *savef;\r
+    register int c;\r
+    char buf[80];\r
+\r
+    /*\r
+     * get file name\r
+     */\r
+    mpos = 0;\r
+    if (file_name[0] != '\0')\r
+    {\r
+       msg("Save file (%s)? ", file_name);\r
+       do\r
+       {\r
+           c = readchar(cw);\r
+       } while (c != 'n' && c != 'N' && c != 'y' && c != 'Y');\r
+       mpos = 0;\r
+       if (c == 'y' || c == 'Y')\r
+       {\r
+           msg("File name: %s", file_name);\r
+           goto gotfile;\r
+       }\r
+    }\r
+\r
+    do\r
+    {\r
+       msg("File name: ");\r
+       mpos = 0;\r
+       buf[0] = '\0';\r
+       if (get_str(buf, cw) == QUIT)\r
+       {\r
+           msg("");\r
+           return FALSE;\r
+       }\r
+       strcpy(file_name, buf);\r
+gotfile:\r
+       if ((savef = fopen(file_name, "w")) == NULL)\r
+           msg(strerror(errno));       /* fake perror() */\r
+    } while (savef == NULL);\r
+\r
+    /*\r
+     * write out encrpyted file (after a stat)\r
+     * The fwrite is to force allocation of the buffer before the write\r
+     */\r
+    if (save_file(savef) != 0)\r
+    {\r
+        msg("Save game failed!");\r
+        return FALSE;\r
+    }\r
+    return TRUE;\r
+}\r
+\r
+/*\r
+ * automatically save a file.  This is used if a HUP signal is\r
+ * recieved\r
+ */\r
+void\r
+auto_save(int p)\r
+{\r
+    register FILE *savef;\r
+    register int i;\r
+\r
+    for (i = 0; i < NSIG; i++)\r
+       signal(i, SIG_IGN);\r
+    if (file_name[0] != '\0' && (savef = fopen(file_name, "w")) != NULL)\r
+       save_file(savef);\r
+    endwin();\r
+    exit(1);\r
+}\r
+\r
+/*\r
+ * write the saved game on the file\r
+ */\r
+save_file(savef)\r
+register FILE *savef;\r
+{\r
+    char buf[80];\r
+    int ret;\r
+\r
+    wmove(cw, LINES-1, 0);\r
+    draw(cw);\r
+    fseek(savef, 0L, 0);\r
+\r
+    memset(buf,0,80);\r
+    strcpy(buf,version);\r
+    encwrite(buf,80,savef);\r
+    memset(buf,0,80);\r
+    strcpy(buf,"R36 2\n");\r
+    encwrite(buf,80,savef);\r
+    memset(buf,0,80);\r
+    sprintf(buf,"%d x %d\n", LINES, COLS);\r
+    encwrite(buf,80,savef);\r
+\r
+    ret = rs_save_file(savef);\r
+\r
+    fclose(savef);\r
+\r
+    return(ret);\r
+}\r
+\r
+restore(file, envp)\r
+register char *file;\r
+char **envp;\r
+{\r
+    register int inf;\r
+    extern char **environ;\r
+    char buf[80];\r
+    int slines, scols;\r
+    int rogue_version = 0, savefile_version = 0;\r
+\r
+    if (strcmp(file, "-r") == 0)\r
+       file = file_name;\r
+    if ((inf = open(file, 0)) < 0)\r
+    {\r
+       perror(file);\r
+       return FALSE;\r
+    }\r
+\r
+    fflush(stdout);\r
+    encread(buf, 80, inf);\r
+\r
+    if (strcmp(buf, version) != 0)\r
+    {\r
+       printf("Sorry, saved game is out of date.\n");\r
+       return FALSE;\r
+    }\r
+\r
+    encread(buf, 80, inf);\r
+    sscanf(buf, "R%d %d\n", &rogue_version, &savefile_version);\r
+\r
+    if ((rogue_version != 36) && (savefile_version != 2))\r
+    {\r
+       printf("Sorry, saved game format is out of date.\n");\r
+       return FALSE;\r
+    }\r
+\r
+    encread(buf,80,inf);\r
+    sscanf(buf,"%d x %d\n",&slines, &scols);\r
+\r
+    /*\r
+     * we do not close the file so that we will have a hold of the\r
+     * inode for as long as possible\r
+     */\r
+\r
+    initscr();\r
+       \r
+    if (slines > LINES)\r
+    {\r
+       endwin();\r
+       printf("Sorry, original game was played on a screen with %d lines.\n",slines);\r
+       printf("Current screen only has %d lines. Unable to restore game\n",LINES);\r
+       return(FALSE);\r
+    }\r
+       \r
+    if (scols > COLS)\r
+    {\r
+       endwin();\r
+       printf("Sorry, original game was played on a screen with %d columns.\n",scols);\r
+       printf("Current screen only has %d columns. Unable to restore game\n",COLS);\r
+       return(FALSE);\r
+    }\r
+    \r
+    cw = newwin(LINES, COLS, 0, 0);\r
+    mw = newwin(LINES, COLS, 0, 0);\r
+    hw = newwin(LINES, COLS, 0, 0);\r
+    nocrmode();\r
+    keypad(cw,1);\r
+    mpos = 0;\r
+    mvwprintw(cw, 0, 0, "%s", file);\r
+\r
+    if (rs_restore_file(inf) != 0)\r
+    {\r
+       endwin();\r
+       printf("Cannot restore file\n");\r
+       return(FALSE);\r
+    }\r
+       \r
+    if (!wizard && (md_unlink_open_file(file, inf) < 0))\r
+    {\r
+       endwin();\r
+       printf("Cannot unlink file\n");\r
+       return FALSE;\r
+    }\r
+\r
+    environ = envp;\r
+    strcpy(file_name, file);\r
+    setup();\r
+    clearok(curscr, TRUE);\r
+    touchwin(cw);\r
+    srand(getpid());\r
+    status();\r
+    playit();\r
+    /*NOTREACHED*/\r
+    return(0);\r
+}\r
+\r
+/*\r
+ * perform an encrypted write\r
+ */\r
+encwrite(starta, size, outf)\r
+register void *starta;\r
+unsigned int size;\r
+register FILE *outf;\r
+{\r
+    register char *ep;\r
+    register char *start = starta;\r
+    unsigned int o_size = size;\r
+    ep = encstr;\r
+\r
+    while (size)\r
+    {\r
+       if (putc(*start++ ^ *ep++, outf) == EOF)\r
+           return(o_size - size);\r
+       if (*ep == '\0')\r
+           ep = encstr;\r
+       size--;\r
+    }\r
+\r
+    return(o_size - size);\r
+}\r
+\r
+/*\r
+ * perform an encrypted read\r
+ */\r
+encread(starta, size, inf)\r
+register void *starta;\r
+unsigned int size;\r
+register int inf;\r
+{\r
+    register char *ep;\r
+    register int read_size;\r
+    register char *start = starta;\r
+\r
+    if ((read_size = read(inf, start, size)) == -1 || read_size == 0)\r
+       return read_size;\r
+\r
+    ep = encstr;\r
+\r
+    while (size--)\r
+    {\r
+       *start++ ^= *ep++;\r
+       if (*ep == '\0')\r
+           ep = encstr;\r
+    }\r
+    return read_size;\r
+}\r
diff --git a/scrolls.c b/scrolls.c
new file mode 100644 (file)
index 0000000..24a5578
--- /dev/null
+++ b/scrolls.c
@@ -0,0 +1,316 @@
+\r
+/*\r
+ * Read a scroll and let it happen\r
+ *\r
+ * @(#)scrolls.c       3.5 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <stdlib.h>\r
+#include <ctype.h>\r
+#include <string.h>\r
+#include "rogue.h"\r
+\r
+read_scroll()\r
+{\r
+    register struct object *obj;\r
+    register struct linked_list *item;\r
+    register struct room *rp;\r
+    register int i,j;\r
+    register char ch, nch;\r
+    register struct linked_list *titem;\r
+    char buf[80];\r
+\r
+    item = get_item("read", SCROLL);\r
+    if (item == NULL)\r
+       return;\r
+    obj = (struct object *) ldata(item);\r
+    if (obj->o_type != SCROLL)\r
+    {\r
+       if (!terse)\r
+           msg("There is nothing on it to read");\r
+       else\r
+           msg("Nothing to read");\r
+       return;\r
+    }\r
+    msg("As you read the scroll, it vanishes.");\r
+    /*\r
+     * Calculate the effect it has on the poor guy.\r
+     */\r
+    if (obj == cur_weapon)\r
+       cur_weapon = NULL;\r
+    switch(obj->o_which)\r
+    {\r
+       case S_CONFUSE:\r
+           /*\r
+            * Scroll of monster confusion.  Give him that power.\r
+            */\r
+           msg("Your hands begin to glow red");\r
+           player.t_flags |= CANHUH;\r
+       when S_LIGHT:\r
+           s_know[S_LIGHT] = TRUE;\r
+           if ((rp = roomin(&hero)) == NULL)\r
+               msg("The corridor glows and then fades");\r
+           else\r
+           {\r
+               addmsg("The room is lit");\r
+               if (!terse)\r
+                   addmsg(" by a shimmering blue light.");\r
+               endmsg();\r
+               rp->r_flags &= ~ISDARK;\r
+               /*\r
+                * Light the room and put the player back up\r
+                */\r
+               light(&hero);\r
+               mvwaddch(cw, hero.y, hero.x, PLAYER);\r
+           }\r
+       when S_ARMOR:\r
+           if (cur_armor != NULL)\r
+           {\r
+               msg("Your armor glows faintly for a moment");\r
+               cur_armor->o_ac--;\r
+               cur_armor->o_flags &= ~ISCURSED;\r
+           }\r
+       when S_HOLD:\r
+           /*\r
+            * Hold monster scroll.  Stop all monsters within two spaces\r
+            * from chasing after the hero.\r
+            */\r
+           {\r
+               register int x,y;\r
+               register struct linked_list *mon;\r
+\r
+               for (x = hero.x-2; x <= hero.x+2; x++)\r
+                   for (y = hero.y-2; y <= hero.y+2; y++)\r
+                       if (y > 0 && x > 0 && isupper(mvwinch(mw, y, x)))\r
+                           if ((mon = find_mons(y, x)) != NULL)\r
+                           {\r
+                               register struct thing *th;\r
+\r
+                               th = (struct thing *) ldata(mon);\r
+                               th->t_flags &= ~ISRUN;\r
+                               th->t_flags |= ISHELD;\r
+                           }\r
+           }\r
+       when S_SLEEP:\r
+           /*\r
+            * Scroll which makes you fall asleep\r
+            */\r
+           s_know[S_SLEEP] = TRUE;\r
+           msg("You fall asleep.");\r
+           no_command += 4 + rnd(SLEEPTIME);\r
+       when S_CREATE:\r
+           /*\r
+            * Create a monster\r
+            * First look in a circle around him, next try his room\r
+            * otherwise give up\r
+            */\r
+           {\r
+               register int x, y;\r
+               register bool appear = 0;\r
+               coord mp;\r
+\r
+               /*\r
+                * Search for an open place\r
+                */\r
+               for (y = hero.y-1; y <= hero.y+1; y++)\r
+                   for (x = hero.x-1; x <= hero.x+1; x++)\r
+                   {\r
+                       /*\r
+                        * Don't put a monster in top of the player.\r
+                        */\r
+                       if (y == hero.y && x == hero.x)\r
+                           continue;\r
+                       /*\r
+                        * Or anything else nasty\r
+                        */\r
+                       if (step_ok(winat(y, x)))\r
+                       {\r
+                           if (rnd(++appear) == 0)\r
+                           {\r
+                               mp.y = y;\r
+                               mp.x = x;\r
+                           }\r
+                       }\r
+                   }\r
+               if (appear)\r
+               {\r
+                   titem = new_item(sizeof (struct thing));\r
+                   new_monster(titem, randmonster(FALSE), &mp);\r
+               }\r
+               else\r
+                   msg("You hear a faint cry of anguish in the distance.");\r
+           }\r
+       when S_IDENT:\r
+           /*\r
+            * Identify, let the rogue figure something out\r
+            */\r
+           msg("This scroll is an identify scroll");\r
+           s_know[S_IDENT] = TRUE;\r
+           whatis();\r
+       when S_MAP:\r
+           /*\r
+            * Scroll of magic mapping.\r
+            */\r
+           s_know[S_MAP] = TRUE;\r
+           msg("Oh, now this scroll has a map on it.");\r
+           overwrite(stdscr, hw);\r
+           /*\r
+            * Take all the things we want to keep hidden out of the window\r
+            */\r
+           for (i = 0; i < LINES; i++)\r
+               for (j = 0; j < COLS; j++)\r
+               {\r
+                   switch (nch = ch = mvwinch(hw, i, j))\r
+                   {\r
+                       case SECRETDOOR:\r
+                            nch = DOOR;\r
+                           mvaddch(i, j, nch);\r
+                       case '-':\r
+                       case '|':\r
+                       case DOOR:\r
+                       case PASSAGE:\r
+                       case ' ':\r
+                       case STAIRS:\r
+                           if (mvwinch(mw, i, j) != ' ')\r
+                           {\r
+                               register struct thing *it;\r
+\r
+                               it = (struct thing *) ldata(find_mons(i, j));\r
+                               if ((it != NULL) && (it->t_oldch == ' '))\r
+                                   it->t_oldch = nch;\r
+                           }\r
+                           break;\r
+                       default:\r
+                           nch = ' ';\r
+                   }\r
+                   if (nch != ch)\r
+                       waddch(hw, nch);\r
+               }\r
+           /*\r
+            * Copy in what he has discovered\r
+            */\r
+           overlay(cw, hw);\r
+           /*\r
+            * And set up for display\r
+            */\r
+           overwrite(hw, cw);\r
+       when S_GFIND:\r
+           /*\r
+            * Potion of gold detection\r
+            */\r
+           {\r
+               int gtotal = 0;\r
+\r
+               wclear(hw);\r
+               for (i = 0; i < MAXROOMS; i++)\r
+               {\r
+                   gtotal += rooms[i].r_goldval;\r
+                   if (rooms[i].r_goldval != 0 &&\r
+                       mvwinch(stdscr, rooms[i].r_gold.y, rooms[i].r_gold.x)\r
+                       == GOLD)\r
+                       mvwaddch(hw,rooms[i].r_gold.y,rooms[i].r_gold.x,GOLD);\r
+               }\r
+               if (gtotal)\r
+               {\r
+                   s_know[S_GFIND] = TRUE;\r
+                   show_win(hw,\r
+                       "You begin to feel greedy and you sense gold.--More--");\r
+               }\r
+               else msg("You begin to feel a pull downward");\r
+           }\r
+       when S_TELEP:\r
+           /*\r
+            * Scroll of teleportation:\r
+            * Make him dissapear and reappear\r
+            */\r
+           {\r
+               int rm;\r
+               struct room *cur_room;\r
+\r
+               cur_room = roomin(&hero);\r
+               rm = teleport();\r
+               if (cur_room != &rooms[rm])\r
+                   s_know[S_TELEP] = TRUE;\r
+           }\r
+       when S_ENCH:\r
+           if (cur_weapon == NULL)\r
+               msg("You feel a strange sense of loss.");\r
+           else\r
+           {\r
+               cur_weapon->o_flags &= ~ISCURSED;\r
+               if (rnd(100) > 50)\r
+                   cur_weapon->o_hplus++;\r
+               else\r
+                   cur_weapon->o_dplus++;\r
+               msg("Your %s glows blue for a moment.", w_names[cur_weapon->o_which]);\r
+           }\r
+       when S_SCARE:\r
+           /*\r
+            * A monster will refuse to step on a scare monster scroll\r
+            * if it is dropped.  Thus reading it is a mistake and produces\r
+            * laughter at the poor rogue's boo boo.\r
+            */\r
+           msg("You hear maniacal laughter in the distance.");\r
+       when S_REMOVE:\r
+           if (cur_armor != NULL)\r
+               cur_armor->o_flags &= ~ISCURSED;\r
+           if (cur_weapon != NULL)\r
+               cur_weapon->o_flags &= ~ISCURSED;\r
+           if (cur_ring[LEFT] != NULL)\r
+               cur_ring[LEFT]->o_flags &= ~ISCURSED;\r
+           if (cur_ring[RIGHT] != NULL)\r
+               cur_ring[RIGHT]->o_flags &= ~ISCURSED;\r
+           msg("You feel as if somebody is watching over you.");\r
+       when S_AGGR:\r
+           /*\r
+            * This scroll aggravates all the monsters on the current\r
+            * level and sets them running towards the hero\r
+            */\r
+           aggravate();\r
+           msg("You hear a high pitched humming noise.");\r
+       when S_NOP:\r
+           msg("This scroll seems to be blank.");\r
+       when S_GENOCIDE:\r
+           msg("You have been granted the boon of genocide");\r
+           genocide();\r
+           s_know[S_GENOCIDE] = TRUE;\r
+       otherwise:\r
+           msg("What a puzzling scroll!");\r
+           return;\r
+    }\r
+    look(TRUE);        /* put the result of the scroll on the screen */\r
+    status();\r
+    if (s_know[obj->o_which] && s_guess[obj->o_which])\r
+    {\r
+       free(s_guess[obj->o_which]);\r
+       s_guess[obj->o_which] = NULL;\r
+    }\r
+    else if (!s_know[obj->o_which] && askme && s_guess[obj->o_which] == NULL)\r
+    {\r
+       msg(terse ? "Call it: " : "What do you want to call it? ");\r
+       if (get_str(buf, cw) == NORM)\r
+       {\r
+           s_guess[obj->o_which] = malloc((unsigned int) strlen(buf) + 1);\r
+           if (s_guess[obj->o_which] != NULL)\r
+               strcpy(s_guess[obj->o_which], buf);\r
+       }\r
+    }\r
+    /*\r
+     * Get rid of the thing\r
+     */\r
+    inpack--;\r
+    if (obj->o_count > 1)\r
+       obj->o_count--;\r
+    else\r
+    {\r
+       detach(pack, item);\r
+        discard(item);\r
+    }\r
+}\r
diff --git a/state.c b/state.c
new file mode 100644 (file)
index 0000000..3006337
--- /dev/null
+++ b/state.c
@@ -0,0 +1,2079 @@
+/*\r
+    state.c - Portable Rogue Save State Code\r
+\r
+    Copyright (C) 1999, 2000, 2005, 2006 Nicholas J. Kisseberth\r
+    All rights reserved.\r
+\r
+    Redistribution and use in source and binary forms, with or without\r
+    modification, are permitted provided that the following conditions\r
+    are met:\r
+    1. Redistributions of source code must retain the above copyright\r
+       notice, this list of conditions and the following disclaimer.\r
+    2. Redistributions in binary form must reproduce the above copyright\r
+       notice, this list of conditions and the following disclaimer in the\r
+       documentation and/or other materials provided with the distribution.\r
+    3. Neither the name(s) of the author(s) nor the names of other contributors\r
+       may be used to endorse or promote products derived from this software\r
+       without specific prior written permission.\r
+\r
+    THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND\r
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+    ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE\r
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+    SUCH DAMAGE.\r
+*/\r
+\r
+/************************************************************************/\r
+/* Save State Code                                                      */\r
+/************************************************************************/\r
+\r
+#define RSID_STATS        0xABCD0001\r
+#define RSID_THING        0xABCD0002\r
+#define RSID_THING_NULL   0xDEAD0002\r
+#define RSID_OBJECT       0xABCD0003\r
+#define RSID_MAGICITEMS   0xABCD0004\r
+#define RSID_KNOWS        0xABCD0005\r
+#define RSID_GUESSES      0xABCD0006\r
+#define RSID_OBJECTLIST   0xABCD0007\r
+#define RSID_BAGOBJECT    0xABCD0008\r
+#define RSID_MONSTERLIST  0xABCD0009\r
+#define RSID_MONSTERSTATS 0xABCD000A\r
+#define RSID_MONSTERS     0xABCD000B\r
+#define RSID_TRAP         0xABCD000C\r
+#define RSID_WINDOW       0xABCD000D\r
+#define RSID_DAEMONS      0xABCD000E\r
+#define RSID_IWEAPS       0xABCD000F\r
+#define RSID_IARMOR       0xABCD0010\r
+#define RSID_SPELLS       0xABCD0011\r
+#define RSID_ILIST        0xABCD0012\r
+#define RSID_HLIST        0xABCD0013\r
+#define RSID_DEATHTYPE    0xABCD0014\r
+#define RSID_CTYPES       0XABCD0015\r
+#define RSID_COORDLIST    0XABCD0016\r
+#define RSID_ROOMS        0XABCD0017\r
+\r
+#include <curses.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include "rogue.h"\r
+\r
+#define READSTAT (format_error || read_error )\r
+#define WRITESTAT (write_error)\r
+\r
+static int read_error   = FALSE;\r
+static int write_error  = FALSE;\r
+static int format_error = FALSE;\r
+static int endian = 0x01020304;\r
+#define  big_endian ( *((char *)&endian) == 0x01 )\r
+\r
+int\r
+rs_write(FILE *savef, void *ptr, size_t size)\r
+{\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    if (encwrite(ptr, size, savef) != size)\r
+        write_error = 1;\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read(int inf, void *ptr, size_t size)\r
+{\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    if (encread(ptr, size, inf) != size)\r
+        read_error = 1;\r
+       \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_char(FILE *savef, char c)\r
+{\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write(savef, &c, 1);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_char(int inf, char *c)\r
+{\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read(inf, c, 1);\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_chars(FILE *savef, char *c, int count)\r
+{\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_int(savef, count);\r
+    rs_write(savef, c, count);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_chars(int inf, char *i, int count)\r
+{\r
+    int value = 0;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_int(inf, &value);\r
+    \r
+    if (value != count)\r
+        format_error = TRUE;\r
+\r
+    rs_read(inf, i, count);\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_int(FILE *savef, int c)\r
+{\r
+    unsigned char bytes[4];\r
+    unsigned char *buf = (unsigned char *) &c;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    if (big_endian)\r
+    {\r
+        bytes[3] = buf[0];\r
+        bytes[2] = buf[1];\r
+        bytes[1] = buf[2];\r
+        bytes[0] = buf[3];\r
+        buf = bytes;\r
+    }\r
+    \r
+    rs_write(savef, buf, 4);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_int(int inf, int *i)\r
+{\r
+    unsigned char bytes[4];\r
+    int input = 0;\r
+    unsigned char *buf = (unsigned char *)&input;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read(inf, &input, 4);\r
+\r
+    if (big_endian)\r
+    {\r
+        bytes[3] = buf[0];\r
+        bytes[2] = buf[1];\r
+        bytes[1] = buf[2];\r
+        bytes[0] = buf[3];\r
+        buf = bytes;\r
+    }\r
+    \r
+    *i = *((int *) buf);\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_ints(FILE *savef, int *c, int count)\r
+{\r
+    int n = 0;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_int(savef, count);\r
+\r
+    for(n = 0; n < count; n++)\r
+        if( rs_write_int(savef,c[n]) != 0)\r
+            break;\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_ints(int inf, int *i, int count)\r
+{\r
+    int n, value;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_int(inf,&value);\r
+\r
+    if (value != count)\r
+        format_error = TRUE;\r
+\r
+    for(n = 0; n < count; n++)\r
+        if (rs_read_int(inf, &i[n]) != 0)\r
+            break;\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_boolean(FILE *savef, bool c)\r
+{\r
+    unsigned char buf = (c == 0) ? 0 : 1;\r
+    \r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write(savef, &buf, 1);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_boolean(int inf, bool *i)\r
+{\r
+    unsigned char buf = 0;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read(inf, &buf, 1);\r
+\r
+    *i = (buf != 0);\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_booleans(FILE *savef, bool *c, int count)\r
+{\r
+    int n = 0;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_int(savef, count);\r
+\r
+    for(n = 0; n < count; n++)\r
+        if (rs_write_boolean(savef, c[n]) != 0)\r
+            break;\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_booleans(int inf, bool *i, int count)\r
+{\r
+    int n = 0, value = 0;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_int(inf,&value);\r
+\r
+    if (value != count)\r
+        format_error = TRUE;\r
+\r
+    for(n = 0; n < count; n++)\r
+        if (rs_read_boolean(inf, &i[n]) != 0)\r
+            break;\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_short(FILE *savef, short c)\r
+{\r
+    unsigned char bytes[2];\r
+    unsigned char *buf = (unsigned char *) &c;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    if (big_endian)\r
+    {\r
+        bytes[1] = buf[0];\r
+        bytes[0] = buf[1];\r
+        buf = bytes;\r
+    }\r
+\r
+    rs_write(savef, buf, 2);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_short(int inf, short *i)\r
+{\r
+    unsigned char bytes[2];\r
+    short  input;\r
+    unsigned char *buf = (unsigned char *)&input;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read(inf, &input, 2);\r
+\r
+    if (big_endian)\r
+    {\r
+        bytes[1] = buf[0];\r
+        bytes[0] = buf[1];\r
+        buf = bytes;\r
+    }\r
+    \r
+    *i = *((short *) buf);\r
+\r
+    return(READSTAT);\r
+} \r
+\r
+int\r
+rs_write_shorts(FILE *savef, short *c, int count)\r
+{\r
+    int n = 0;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_int(savef, count);\r
+\r
+    for(n = 0; n < count; n++)\r
+        if (rs_write_short(savef, c[n]) != 0)\r
+            break; \r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_shorts(int inf, short *i, int count)\r
+{\r
+    int n = 0, value = 0;\r
+\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_int(inf,&value);\r
+\r
+    if (value != count)\r
+        format_error = TRUE;\r
+\r
+    for(n = 0; n < value; n++)\r
+        if (rs_read_short(inf, &i[n]) != 0)\r
+            break;\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_ushort(FILE *savef, unsigned short c)\r
+{\r
+    unsigned char bytes[2];\r
+    unsigned char *buf = (unsigned char *) &c;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    if (big_endian)\r
+    {\r
+        bytes[1] = buf[0];\r
+        bytes[0] = buf[1];\r
+        buf = bytes;\r
+    }\r
+\r
+    rs_write(savef, buf, 2);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_ushort(int inf, unsigned short *i)\r
+{\r
+    unsigned char bytes[2];\r
+    unsigned short  input;\r
+    unsigned char *buf = (unsigned char *)&input;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read(inf, &input, 2);\r
+\r
+    if (big_endian)\r
+    {\r
+        bytes[1] = buf[0];\r
+        bytes[0] = buf[1];\r
+        buf = bytes;\r
+    }\r
+    \r
+    *i = *((unsigned short *) buf);\r
+\r
+    return(READSTAT);\r
+} \r
+\r
+int\r
+rs_write_uint(FILE *savef, unsigned int c)\r
+{\r
+    unsigned char bytes[4];\r
+    unsigned char *buf = (unsigned char *) &c;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    if (big_endian)\r
+    {\r
+        bytes[3] = buf[0];\r
+        bytes[2] = buf[1];\r
+        bytes[1] = buf[2];\r
+        bytes[0] = buf[3];\r
+        buf = bytes;\r
+    }\r
+    \r
+    rs_write(savef, buf, 4);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_uint(int inf, unsigned int *i)\r
+{\r
+    unsigned char bytes[4];\r
+    int  input;\r
+    unsigned char *buf = (unsigned char *)&input;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read(inf, &input, 4);\r
+\r
+    if (big_endian)\r
+    {\r
+        bytes[3] = buf[0];\r
+        bytes[2] = buf[1];\r
+        bytes[1] = buf[2];\r
+        bytes[0] = buf[3];\r
+        buf = bytes;\r
+    }\r
+    \r
+    *i = *((unsigned int *) buf);\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_long(FILE *savef, long c)\r
+{\r
+    int c2;\r
+    unsigned char bytes[4];\r
+    unsigned char *buf = (unsigned char *)&c;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    if (sizeof(long) == 8)\r
+    {\r
+        c2 = c;\r
+        buf = (unsigned char *) &c2;\r
+    }\r
+\r
+    if (big_endian)\r
+    {\r
+        bytes[3] = buf[0];\r
+        bytes[2] = buf[1];\r
+        bytes[1] = buf[2];\r
+        bytes[0] = buf[3];\r
+        buf = bytes;\r
+    }\r
+    \r
+    rs_write(savef, buf, 4);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_long(int inf, long *i)\r
+{\r
+    unsigned char bytes[4];\r
+    long input;\r
+    unsigned char *buf = (unsigned char *) &input;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read(inf, &input, 4);\r
+\r
+    if (big_endian)\r
+    {\r
+        bytes[3] = buf[0];\r
+        bytes[2] = buf[1];\r
+        bytes[1] = buf[2];\r
+        bytes[0] = buf[3];\r
+        buf = bytes;\r
+    }\r
+    \r
+    *i = *((long *) buf);\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_longs(FILE *savef, long *c, int count)\r
+{\r
+    int n = 0;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_int(savef,count);\r
+    \r
+    for(n = 0; n < count; n++)\r
+        rs_write_long(savef, c[n]);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_longs(int inf, long *i, int count)\r
+{\r
+    int n = 0, value = 0;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_int(inf,&value);\r
+\r
+    if (value != count)\r
+        format_error = TRUE;\r
+\r
+    for(n = 0; n < value; n++)\r
+        if (rs_read_long(inf, &i[n]) != 0)\r
+            break;\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_ulong(FILE *savef, unsigned long c)\r
+{\r
+    unsigned int c2;\r
+    unsigned char bytes[4];\r
+    unsigned char *buf = (unsigned char *)&c;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    if ( (sizeof(long) == 8) && (sizeof(int) == 4) )\r
+    {\r
+        c2 = c;\r
+        buf = (unsigned char *) &c2;\r
+    }\r
+\r
+    if (big_endian)\r
+    {\r
+        bytes[3] = buf[0];\r
+        bytes[2] = buf[1];\r
+        bytes[1] = buf[2];\r
+        bytes[0] = buf[3];\r
+        buf = bytes;\r
+    }\r
+    \r
+    rs_write(savef, buf, 4);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_ulong(int inf, unsigned long *i)\r
+{\r
+    unsigned char bytes[4];\r
+    unsigned long input;\r
+    unsigned char *buf = (unsigned char *) &input;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read(inf, &input, 4);\r
+\r
+    if (big_endian)\r
+    {\r
+        bytes[3] = buf[0];\r
+        bytes[2] = buf[1];\r
+        bytes[1] = buf[2];\r
+        bytes[0] = buf[3];\r
+        buf = bytes;\r
+    }\r
+    \r
+    *i = *((unsigned long *) buf);\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_ulongs(FILE *savef, unsigned long *c, int count)\r
+{\r
+    int n = 0;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_int(savef,count);\r
+\r
+    for(n = 0; n < count; n++)\r
+        if (rs_write_ulong(savef,c[n]) != 0)\r
+            break;\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_ulongs(int inf, unsigned long *i, int count)\r
+{\r
+    int n = 0, value = 0;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_int(inf,&value);\r
+\r
+    if (value != count)\r
+        format_error = TRUE;\r
+\r
+    for(n = 0; n < count; n++)\r
+        if (rs_read_ulong(inf, &i[n]) != 0)\r
+            break;\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_marker(FILE *savef, int id)\r
+{\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_int(savef, id);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int \r
+rs_read_marker(int inf, int id)\r
+{\r
+    int nid;\r
+\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    if (rs_read_int(inf, &nid) == 0)\r
+        if (id != nid)\r
+            format_error = 1;\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+\r
+\r
+/******************************************************************************/\r
+\r
+int\r
+rs_write_string(FILE *savef, char *s)\r
+{\r
+    int len = 0;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    len = (s == NULL) ? 0 : (int) strlen(s) + 1;\r
+\r
+    rs_write_int(savef, len);\r
+    rs_write_chars(savef, s, len);\r
+            \r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_string(int inf, char *s, int max)\r
+{\r
+    int len = 0;\r
+\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_int(inf, &len);\r
+\r
+    if (len > max)\r
+        format_error = TRUE;\r
+\r
+    rs_read_chars(inf, s, len);\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_read_new_string(int inf, char **s)\r
+{\r
+    int len=0;\r
+    char *buf=0;\r
+\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_int(inf, &len);\r
+\r
+    if (len == 0)\r
+        buf = NULL;\r
+    else\r
+    { \r
+        buf = malloc(len);\r
+\r
+        if (buf == NULL)            \r
+            read_error = TRUE;\r
+    }\r
+\r
+    rs_read_chars(inf, buf, len);\r
+\r
+    *s = buf;\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_strings(FILE *savef, char *s[], int count)\r
+{\r
+    int n = 0;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_int(savef, count);\r
+\r
+    for(n = 0; n < count; n++)\r
+        if (rs_write_string(savef, s[n]) != 0)\r
+            break;\r
+    \r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_strings(int inf, char **s, int count, int max)\r
+{\r
+    int n     = 0;\r
+    int value = 0;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_int(inf, &value);\r
+\r
+    if (value != count)\r
+        format_error = TRUE;\r
+\r
+    for(n = 0; n < count; n++)\r
+        if (rs_read_string(inf, s[n], max) != 0)\r
+            break;\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_read_new_strings(int inf, char **s, int count)\r
+{\r
+    int n     = 0;\r
+    int value = 0;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_int(inf, &value);\r
+\r
+    if (value != count)\r
+        format_error = TRUE;\r
+\r
+    for(n = 0; n < count; n++)\r
+        if (rs_read_new_string(inf, &s[n]) != 0)\r
+            break;\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_string_index(FILE *savef, char *master[], int max, const char *str)\r
+{\r
+    int i;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    for(i = 0; i < max; i++)\r
+        if (str == master[i])\r
+            return( rs_write_int(savef, i) );\r
+\r
+    return( rs_write_int(savef,-1) );\r
+}\r
+\r
+int\r
+rs_read_string_index(int inf, char *master[], int maxindex, char **str)\r
+{\r
+    int i;\r
+\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_int(inf, &i);\r
+\r
+    if (i > maxindex)\r
+        format_error = TRUE;\r
+    else if (i >= 0)\r
+        *str = master[i];\r
+    else\r
+        *str = NULL;\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_str_t(FILE *savef, str_t st)\r
+{\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_short(savef,st.st_str);\r
+    rs_write_short(savef,st.st_add);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_str_t(int inf, str_t *st)\r
+{\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_short(inf,&st->st_str);\r
+    rs_read_short(inf,&st->st_add);\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_coord(FILE *savef, coord c)\r
+{\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_int(savef, c.x);\r
+    rs_write_int(savef, c.y);\r
+    \r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_coord(int inf, coord *c)\r
+{\r
+    coord in;\r
+\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_int(inf,&in.x);\r
+    rs_read_int(inf,&in.y);\r
+\r
+    if (READSTAT == 0) \r
+    {\r
+        c->x = in.x;\r
+        c->y = in.y;\r
+    }\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_window(FILE *savef, WINDOW *win)\r
+{\r
+    int row,col,height,width;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    width  = getmaxx(win);\r
+    height = getmaxy(win);\r
+\r
+    rs_write_marker(savef,RSID_WINDOW);\r
+    rs_write_int(savef,height);\r
+    rs_write_int(savef,width);\r
+\r
+    for(row=0;row<height;row++)\r
+        for(col=0;col<width;col++)\r
+            if (rs_write_int(savef, mvwinch(win,row,col)) != 0)\r
+                return(WRITESTAT);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_window(int inf, WINDOW *win)\r
+{\r
+    int row,col,maxlines,maxcols,value,width,height;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    width  = getmaxx(win);\r
+    height = getmaxy(win);\r
+\r
+    rs_read_marker(inf, RSID_WINDOW);\r
+\r
+    rs_read_int(inf, &maxlines);\r
+    rs_read_int(inf, &maxcols);\r
+\r
+    for(row = 0; row < maxlines; row++)\r
+        for(col = 0; col < maxcols; col++)\r
+        {\r
+            if (rs_read_int(inf, &value) != 0)\r
+                return(READSTAT);\r
+\r
+            if ((row < height) && (col < width))\r
+                mvwaddch(win,row,col,value);\r
+        }\r
+        \r
+    return(READSTAT);\r
+}\r
+\r
+/******************************************************************************/\r
+\r
+void *\r
+get_list_item(struct linked_list *l, int i)\r
+{\r
+    int count;\r
+\r
+    for(count = 0; l != NULL; count++, l = l->l_next)\r
+        if (count == i)\r
+            return(l->l_data);\r
+    \r
+    return(NULL);\r
+}\r
+\r
+int\r
+find_list_ptr(struct linked_list *l, void *ptr)\r
+{\r
+    int count;\r
+\r
+    for(count = 0; l != NULL; count++, l = l->l_next)\r
+        if (l->l_data == ptr)\r
+            return(count);\r
+               \r
+    return(-1);\r
+}\r
+\r
+int\r
+list_size(struct linked_list *l)\r
+{\r
+    int count;\r
+    \r
+    for(count = 0; l != NULL; count++, l = l->l_next)\r
+        if (l->l_data == NULL)\r
+            return(count);\r
+    \r
+    return(count);\r
+}\r
+\r
+/******************************************************************************/\r
+\r
+int\r
+rs_write_stats(FILE *savef, struct stats *s)\r
+{\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_marker(savef, RSID_STATS);\r
+    rs_write_str_t(savef, s->s_str);\r
+    rs_write_long(savef, s->s_exp);\r
+    rs_write_int(savef, s->s_lvl);\r
+    rs_write_int(savef, s->s_arm);\r
+    rs_write_int(savef, s->s_hpt);\r
+    rs_write_chars(savef, s->s_dmg, sizeof(s->s_dmg));\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_stats(int inf, struct stats *s)\r
+{\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_marker(inf, RSID_STATS);\r
+    rs_read_str_t(inf,&s->s_str);\r
+    rs_read_long(inf,&s->s_exp);\r
+    rs_read_int(inf,&s->s_lvl);\r
+    rs_read_int(inf,&s->s_arm);\r
+    rs_read_int(inf,&s->s_hpt);\r
+    rs_read_chars(inf,s->s_dmg,sizeof(s->s_dmg));\r
+    \r
+    return(READSTAT);\r
+}\r
+        \r
+int\r
+rs_write_scrolls(FILE *savef)\r
+{\r
+    int i;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    for(i = 0; i < MAXSCROLLS; i++)\r
+    {\r
+        rs_write_string(savef,s_names[i]);\r
+        rs_write_boolean(savef,s_know[i]);\r
+        rs_write_string(savef,s_guess[i]);\r
+    }\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_read_scrolls(int inf)\r
+{\r
+    int i;\r
+\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    for(i = 0; i < MAXSCROLLS; i++)\r
+    {\r
+        rs_read_new_string(inf,&s_names[i]);\r
+        rs_read_boolean(inf,&s_know[i]);\r
+        rs_read_new_string(inf,&s_guess[i]);\r
+    }\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_potions(FILE *savef)\r
+{\r
+    int i;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    for(i = 0; i < MAXPOTIONS; i++)\r
+    {\r
+        rs_write_string_index(savef, rainbow, cNCOLORS, p_colors[i]);\r
+        rs_write_boolean(savef,p_know[i]);\r
+        rs_write_string(savef,p_guess[i]);\r
+    }\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_potions(int inf)\r
+{\r
+    int i;\r
+\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    for(i = 0; i < MAXPOTIONS; i++)\r
+    {\r
+        rs_read_string_index(inf, rainbow, cNCOLORS, &p_colors[i]);\r
+        rs_read_boolean(inf,&p_know[i]);\r
+        rs_read_new_string(inf,&p_guess[i]);\r
+    }\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_rings(FILE *savef)\r
+{\r
+    int i;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    for(i = 0; i < MAXRINGS; i++)\r
+    {\r
+        rs_write_string_index(savef, stones, cNSTONES, r_stones[i]);\r
+        rs_write_boolean(savef,r_know[i]);\r
+        rs_write_string(savef,r_guess[i]);\r
+    }\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_rings(int inf)\r
+{\r
+    int i;\r
+\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    for(i = 0; i < MAXRINGS; i++)\r
+    {\r
+        rs_read_string_index(inf, stones, cNSTONES, &r_stones[i]);\r
+        rs_read_boolean(inf,&r_know[i]);\r
+        rs_read_new_string(inf,&r_guess[i]);\r
+    }\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_sticks(FILE *savef)\r
+{\r
+    int i;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    for (i = 0; i < MAXSTICKS; i++)\r
+    {\r
+        if (strcmp(ws_type[i],"staff") == 0)\r
+        {\r
+            rs_write_int(savef,0);\r
+            rs_write_string_index(savef, wood, cNWOOD, ws_made[i]);\r
+        }\r
+        else\r
+        {\r
+            rs_write_int(savef,1);\r
+            rs_write_string_index(savef, metal, cNMETAL, ws_made[i]);\r
+        }\r
+        rs_write_boolean(savef, ws_know[i]);\r
+        rs_write_string(savef, ws_guess[i]);\r
+    }\r
\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_sticks(int inf)\r
+{\r
+    int i = 0, list = 0;\r
+\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    for(i = 0; i < MAXSTICKS; i++)\r
+    { \r
+        rs_read_int(inf,&list);\r
+\r
+       if (list == 0)\r
+        {\r
+            rs_read_string_index(inf, wood, cNWOOD, &ws_made[i]);\r
+            ws_type[i] = "staff";\r
+        }\r
+        else \r
+        {\r
+            rs_read_string_index(inf, metal, cNMETAL, &ws_made[i]);\r
+            ws_type[i] = "wand";\r
+        }\r
+        rs_read_boolean(inf, &ws_know[i]);\r
+        rs_read_new_string(inf, &ws_guess[i]);\r
+    }\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_daemons(FILE *savef, struct delayed_action *d_list, int count)\r
+{\r
+    int i = 0;\r
+    int func = 0;\r
+        \r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_marker(savef, RSID_DAEMONS);\r
+    rs_write_int(savef, count);\r
+        \r
+    for(i = 0; i < count; i++)\r
+    {\r
+        if (d_list[i].d_func == rollwand)\r
+            func = 1;\r
+        else if (d_list[i].d_func == doctor)\r
+            func = 2;\r
+        else if (d_list[i].d_func == stomach)\r
+            func = 3;\r
+        else if (d_list[i].d_func == runners)\r
+            func = 4;\r
+        else if (d_list[i].d_func == swander)\r
+            func = 5;\r
+        else if (d_list[i].d_func == nohaste)\r
+            func = 6;\r
+        else if (d_list[i].d_func == unconfuse)\r
+            func = 7;\r
+        else if (d_list[i].d_func == unsee)\r
+            func = 8;\r
+        else if (d_list[i].d_func == sight)\r
+            func = 9;\r
+        else if (d_list[i].d_func == NULL)\r
+            func = 0;\r
+        else\r
+            func = -1;\r
+\r
+        rs_write_int(savef, d_list[i].d_type);\r
+        rs_write_int(savef, func);\r
+        rs_write_int(savef, d_list[i].d_arg);\r
+        rs_write_int(savef, d_list[i].d_time);\r
+    }\r
+    \r
+    return(WRITESTAT);\r
+}       \r
+\r
+int\r
+rs_read_daemons(int inf, struct delayed_action *d_list, int count)\r
+{\r
+    int i = 0;\r
+    int func = 0;\r
+    int value = 0;\r
+\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+    \r
+    rs_read_marker(inf, RSID_DAEMONS);\r
+    rs_read_int(inf, &value);\r
+\r
+    if (value != count)\r
+        format_error = TRUE;\r
+\r
+    for(i=0; i < count; i++)\r
+    {\r
+       func = 0;\r
+        rs_read_int(inf, &d_list[i].d_type);\r
+        rs_read_int(inf, &func);\r
+        rs_read_int(inf, &d_list[i].d_arg);\r
+        rs_read_int(inf, &d_list[i].d_time);\r
+                    \r
+        switch(func)\r
+        {\r
+           case 1: d_list[i].d_func = rollwand;\r
+                   break;\r
+           case 2: d_list[i].d_func = doctor;\r
+                    break;\r
+            case 3: d_list[i].d_func = stomach;\r
+                    break;\r
+            case 4: d_list[i].d_func = runners;\r
+                    break;\r
+            case 5: d_list[i].d_func = swander;\r
+                    break;\r
+            case 6: d_list[i].d_func = nohaste;\r
+                    break;\r
+            case 7: d_list[i].d_func = unconfuse;\r
+                    break;\r
+            case 8: d_list[i].d_func = unsee;\r
+                    break;\r
+            case 9: d_list[i].d_func = sight;\r
+                    break;\r
+            default:d_list[i].d_func = NULL;\r
+                    break;\r
+       }   \r
+    }\r
+\r
+    if (d_list[i].d_func == NULL)\r
+    {\r
+        d_list[i].d_type = 0;\r
+        d_list[i].d_arg = 0;\r
+        d_list[i].d_time = 0;\r
+    }\r
+    \r
+    return(READSTAT);\r
+}       \r
+\r
+int\r
+rs_write_trap(FILE *savef, struct trap *trap)\r
+{\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_coord(savef, trap->tr_pos);\r
+    rs_write_char(savef, trap->tr_type);\r
+    rs_write_int(savef, trap->tr_flags);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_trap(int inf, struct trap *trap)\r
+{\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_coord(inf,&trap->tr_pos);\r
+    rs_read_char(inf,&trap->tr_type);\r
+    rs_read_int(inf,&trap->tr_flags);\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_traps(FILE *savef, struct trap t[], int count)\r
+{\r
+    int n = 0;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_marker(savef, RSID_MONSTERS);\r
+    rs_write_int(savef, count);\r
+    \r
+    for(n = 0; n < count; n++)\r
+        rs_write_trap(savef, &t[n]);\r
+    \r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_traps(int inf, struct trap *t, int count)\r
+{\r
+    int value = 0, n = 0;\r
+\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_marker(inf, RSID_MONSTERS);\r
+\r
+    rs_read_int(inf,&value);\r
+\r
+    if (value > count)\r
+        format_error = TRUE;\r
+\r
+    for(n = 0; n < value; n++)\r
+        rs_read_trap(inf,&t[n]);\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_room(FILE *savef, struct room *r)\r
+{\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_coord(savef, r->r_pos);\r
+    rs_write_coord(savef, r->r_max);\r
+    rs_write_coord(savef, r->r_gold);\r
+    rs_write_int(savef, r->r_goldval);\r
+    rs_write_int(savef, r->r_flags);\r
+    rs_write_int(savef, r->r_nexits);\r
+    rs_write_coord(savef, r->r_exit[0]);\r
+    rs_write_coord(savef, r->r_exit[1]);\r
+    rs_write_coord(savef, r->r_exit[2]);\r
+    rs_write_coord(savef, r->r_exit[3]);\r
+    \r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_room(int inf, struct room *r)\r
+{\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_coord(inf,&r->r_pos);\r
+    rs_read_coord(inf,&r->r_max);\r
+    rs_read_coord(inf,&r->r_gold);\r
+    rs_read_int(inf,&r->r_goldval);\r
+    rs_read_int(inf,&r->r_flags);\r
+    rs_read_int(inf,&r->r_nexits);\r
+    rs_read_coord(inf,&r->r_exit[0]);\r
+    rs_read_coord(inf,&r->r_exit[1]);\r
+    rs_read_coord(inf,&r->r_exit[2]);\r
+    rs_read_coord(inf,&r->r_exit[3]);\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_rooms(FILE *savef, struct room r[], int count)\r
+{\r
+    int n = 0;\r
+\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_int(savef, count);\r
+    \r
+    for(n = 0; n < count; n++)\r
+        rs_write_room(savef, &r[n]);\r
+    \r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_rooms(int inf, struct room *r, int count)\r
+{\r
+    int value = 0, n = 0;\r
+\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_int(inf,&value);\r
+\r
+    if (value > count)\r
+        format_error = TRUE;\r
+\r
+    for(n = 0; n < value; n++)\r
+        rs_read_room(inf,&r[n]);\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_room_reference(FILE *savef, struct room *rp)\r
+{\r
+    int i, room = -1;\r
+    \r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    for (i = 0; i < MAXROOMS; i++)\r
+        if (&rooms[i] == rp)\r
+            room = i;\r
+\r
+    rs_write_int(savef, room);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_room_reference(int inf, struct room **rp)\r
+{\r
+    int i;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_int(inf, &i);\r
+\r
+    *rp = &rooms[i];\r
+            \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_object(FILE *savef, struct object *o)\r
+{\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_marker(savef, RSID_OBJECT);\r
+    rs_write_int(savef, o->o_type);\r
+    rs_write_coord(savef, o->o_pos);\r
+    rs_write_char(savef, o->o_launch);\r
+    rs_write_chars(savef, o->o_damage, sizeof(o->o_damage));\r
+    rs_write_chars(savef, o->o_hurldmg, sizeof(o->o_damage));\r
+    rs_write_int(savef, o->o_count);\r
+    rs_write_int(savef, o->o_which);\r
+    rs_write_int(savef, o->o_hplus);\r
+    rs_write_int(savef, o->o_dplus);\r
+    rs_write_int(savef, o->o_ac);\r
+    rs_write_int(savef, o->o_flags);\r
+    rs_write_int(savef, o->o_group);\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_object(int inf, struct object *o)\r
+{\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_marker(inf, RSID_OBJECT);\r
+    rs_read_int(inf, &o->o_type);\r
+    rs_read_coord(inf, &o->o_pos);\r
+    rs_read_char(inf, &o->o_launch);\r
+    rs_read_chars(inf, o->o_damage, sizeof(o->o_damage));\r
+    rs_read_chars(inf, o->o_hurldmg, sizeof(o->o_hurldmg));\r
+    rs_read_int(inf, &o->o_count);\r
+    rs_read_int(inf, &o->o_which);\r
+    rs_read_int(inf, &o->o_hplus);\r
+    rs_read_int(inf, &o->o_hplus);\r
+    rs_read_int(inf,&o->o_ac);\r
+    rs_read_int(inf,&o->o_flags);\r
+    rs_read_int(inf,&o->o_group);\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_object_list(FILE *savef, struct linked_list *l)\r
+{\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_marker(savef, RSID_OBJECTLIST);\r
+    rs_write_int(savef, list_size(l));\r
+\r
+    for( ;l != NULL; l = l->l_next) \r
+        rs_write_object(savef, (struct object *) l->l_data);\r
+    \r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_object_list(int inf, struct linked_list **list)\r
+{\r
+    int i, cnt;\r
+    struct linked_list *l = NULL, *previous = NULL, *head = NULL;\r
+\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_marker(inf, RSID_OBJECTLIST);\r
+    rs_read_int(inf, &cnt);\r
+\r
+    for (i = 0; i < cnt; i++) \r
+    {\r
+       l = new_item(sizeof(struct object));\r
+\r
+        memset(l->l_data,0,sizeof(struct object));\r
+\r
+        l->l_prev = previous;\r
+\r
+        if (previous != NULL)\r
+           previous->l_next = l;\r
+\r
+        rs_read_object(inf,(struct object *) l->l_data);\r
+\r
+        if (previous == NULL)\r
+           head = l;\r
+\r
+        previous = l;\r
+    }\r
+            \r
+    if (l != NULL)\r
+       l->l_next = NULL;\r
+    \r
+    *list = head;\r
+\r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_write_object_reference(FILE *savef, struct linked_list *list, \r
+    struct object *item)\r
+{\r
+    int i;\r
+    \r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    i = find_list_ptr(list, item);\r
+\r
+    rs_write_int(savef, i);\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_object_reference(int inf, struct linked_list *list, \r
+    struct object **item)\r
+{\r
+    int i;\r
+    \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_int(inf, &i);\r
+\r
+    *item = get_list_item(list,i);\r
+            \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+find_room_coord(struct room *rmlist, coord *c, int n)\r
+{\r
+    int i = 0;\r
+    \r
+    for(i = 0; i < n; i++)\r
+        if(&rmlist[i].r_gold == c)\r
+            return(i);\r
+    \r
+    return(-1);\r
+}\r
+\r
+int\r
+find_thing_coord(struct linked_list *monlist, coord *c)\r
+{\r
+    struct linked_list *mitem;\r
+    struct thing *tp;\r
+    int i = 0;\r
+\r
+    for(mitem = monlist; mitem != NULL; mitem = mitem->l_next)\r
+    {\r
+        tp = THINGPTR(mitem);\r
+\r
+        if (c == &tp->t_pos)\r
+            return(i);\r
+\r
+        i++;\r
+    }\r
+\r
+    return(-1);\r
+}\r
+\r
+int\r
+find_object_coord(struct linked_list *objlist, coord *c)\r
+{\r
+    struct linked_list *oitem;\r
+    struct object *obj;\r
+    int i = 0;\r
+\r
+    for(oitem = objlist; oitem != NULL; oitem = oitem->l_next)\r
+    {\r
+        obj = OBJPTR(oitem);\r
+\r
+        if (c == &obj->o_pos)\r
+            return(i);\r
+\r
+        i++;\r
+    }\r
+\r
+    return(-1);\r
+}\r
+\r
+int\r
+rs_write_thing(FILE *savef, struct thing *t)\r
+{\r
+    int i = -1;\r
+    \r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_marker(savef, RSID_THING);\r
+\r
+    if (t == NULL)\r
+    {\r
+        rs_write_int(savef, 0);\r
+        return(WRITESTAT);\r
+    }\r
+\r
+    rs_write_int(savef, 1);\r
+    rs_write_coord(savef, t->t_pos);\r
+    rs_write_boolean(savef, t->t_turn);\r
+    rs_write_char(savef, t->t_type);\r
+    rs_write_char(savef, t->t_disguise);\r
+    rs_write_char(savef, t->t_oldch);\r
+\r
+    /* \r
+        t_dest can be:\r
+        0,0: NULL\r
+        0,1: location of hero\r
+        1,i: location of a thing (monster)\r
+        2,i: location of an object\r
+        3,i: location of gold in a room\r
+\r
+        We need to remember what we are chasing rather than \r
+        the current location of what we are chasing.\r
+    */\r
+\r
+    if (t->t_dest == &hero)\r
+    {\r
+        rs_write_int(savef,0);\r
+        rs_write_int(savef,1);\r
+    }\r
+    else if (t->t_dest != NULL)\r
+    {\r
+        i = find_thing_coord(mlist, t->t_dest);\r
+            \r
+        if (i >=0 )\r
+        {\r
+            rs_write_int(savef,1);\r
+            rs_write_int(savef,i);\r
+        }\r
+        else\r
+        {\r
+            i = find_object_coord(lvl_obj, t->t_dest);\r
+            \r
+            if (i >= 0)\r
+            {\r
+                rs_write_int(savef,2);\r
+                rs_write_int(savef,i);\r
+            }\r
+            else\r
+            {\r
+                i = find_room_coord(rooms, t->t_dest, MAXROOMS);\r
+        \r
+                if (i >= 0) \r
+                {\r
+                    rs_write_int(savef,3);\r
+                    rs_write_int(savef,i);\r
+                }\r
+                else \r
+                {\r
+                    rs_write_int(savef, 0);\r
+                    rs_write_int(savef,1); /* chase the hero anyway */\r
+                }\r
+            }\r
+        }\r
+    }\r
+    else\r
+    {\r
+        rs_write_int(savef,0);\r
+        rs_write_int(savef,0);\r
+    }\r
+    \r
+    rs_write_short(savef, t->t_flags);\r
+    rs_write_stats(savef, &t->t_stats);\r
+    rs_write_object_list(savef, t->t_pack);\r
+    \r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_thing(int inf, struct thing *t)\r
+{\r
+    int listid = 0, index = -1;\r
+    struct linked_list *item;\r
+        \r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_marker(inf, RSID_THING);\r
+\r
+    rs_read_int(inf, &index);\r
+\r
+    if (index == 0)\r
+        return(READSTAT);\r
+\r
+    rs_read_coord(inf,&t->t_pos);\r
+    rs_read_boolean(inf,&t->t_turn);\r
+    rs_read_char(inf,&t->t_type);\r
+    rs_read_char(inf,&t->t_disguise);\r
+    rs_read_char(inf,&t->t_oldch);\r
+\r
+    /* \r
+        t_dest can be (listid,index):\r
+        0,0: NULL\r
+        0,1: location of hero\r
+        1,i: location of a thing (monster)\r
+        2,i: location of an object\r
+        3,i: location of gold in a room\r
+\r
+        We need to remember what we are chasing rather than \r
+        the current location of what we are chasing.\r
+    */\r
+            \r
+    rs_read_int(inf, &listid);\r
+    rs_read_int(inf, &index);\r
+    t->t_reserved = -1;\r
+\r
+    if (listid == 0) /* hero or NULL */\r
+    {\r
+       if (index == 1)\r
+           t->t_dest = &hero;\r
+        else\r
+           t->t_dest = NULL;\r
+    }\r
+    else if (listid == 1) /* monster/thing */\r
+    {\r
+       t->t_dest     = NULL;\r
+        t->t_reserved = index;\r
+    }\r
+    else if (listid == 2) /* object */\r
+    {\r
+       struct object *obj;\r
+\r
+        item = get_list_item(lvl_obj,index);\r
+\r
+        if (item != NULL)\r
+       {\r
+           obj = OBJPTR(item);\r
+            t->t_dest = &obj->o_pos;   \r
+       }\r
+    }\r
+    else if (listid == 3) /* gold */\r
+    {\r
+       t->t_dest = &rooms[index].r_gold;\r
+    }\r
+    else\r
+       t->t_dest = NULL;\r
+            \r
+    rs_read_short(inf,&t->t_flags);\r
+    rs_read_stats(inf,&t->t_stats);\r
+    rs_read_object_list(inf,&t->t_pack);\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_fix_thing(struct thing *t)\r
+{\r
+    struct linked_list *item;\r
+    struct thing *tp;\r
+\r
+    if (t->t_reserved < 0)\r
+        return;\r
+\r
+    item = get_list_item(mlist,t->t_reserved);\r
+\r
+    if (item != NULL)\r
+    {\r
+        tp = THINGPTR(item);\r
+        t->t_dest = &tp->t_pos;\r
+    }\r
+}\r
+\r
+int\r
+rs_write_thing_list(FILE *savef, struct linked_list *l)\r
+{\r
+    int cnt = 0;\r
+    \r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_marker(savef, RSID_MONSTERLIST);\r
+\r
+    cnt = list_size(l);\r
+\r
+    rs_write_int(savef, cnt);\r
+\r
+    if (cnt < 1)\r
+        return(WRITESTAT);\r
+\r
+    while (l != NULL) {\r
+        rs_write_thing(savef, (struct thing *)l->l_data);\r
+        l = l->l_next;\r
+    }\r
+    \r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_read_thing_list(int inf, struct linked_list **list)\r
+{\r
+    int i, cnt;\r
+    struct linked_list *l = NULL, *previous = NULL, *head = NULL;\r
+\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_marker(inf, RSID_MONSTERLIST);\r
+\r
+    rs_read_int(inf, &cnt);\r
+\r
+    for (i = 0; i < cnt; i++) \r
+    {\r
+       l = new_item(sizeof(struct thing));\r
+\r
+        l->l_prev = previous;\r
+        \r
+       if (previous != NULL)\r
+           previous->l_next = l;\r
+\r
+       rs_read_thing(inf,(struct thing *)l->l_data);\r
+\r
+       if (previous == NULL)\r
+           head = l;\r
+\r
+       previous = l;\r
+    }\r
+      \r
+    if (l != NULL)\r
+       l->l_next = NULL;\r
+\r
+    *list = head;\r
+    \r
+    return(READSTAT);\r
+}\r
+\r
+int\r
+rs_fix_thing_list(struct linked_list *list)\r
+{\r
+    struct linked_list *item;\r
+\r
+    for(item = list; item != NULL; item = item->l_next)\r
+        rs_fix_thing(THINGPTR(item));\r
+}\r
+\r
+int\r
+rs_fix_magic_items(struct magic_item *mi, int count)\r
+{\r
+    int i;\r
+\r
+    for (i = 0; i < count; i++)\r
+       if (i > 0)\r
+           mi[i].mi_prob += mi[i-1].mi_prob;\r
+}\r
+\r
+int\r
+rs_fix_monsters(struct monster monsters[26])\r
+{\r
+    sprintf(monsters['F'-'A'].m_stats.s_dmg,"%dd1",fung_hit);\r
+}\r
+\r
+int\r
+rs_save_file(FILE *savef)\r
+{\r
+    if (write_error)\r
+        return(WRITESTAT);\r
+\r
+    rs_write_thing(savef, &player);                     \r
+    rs_write_object_list(savef, lvl_obj);               \r
+    rs_write_thing_list(savef, mlist);                \r
+    rs_write_traps(savef, traps, MAXTRAPS);             \r
+    rs_write_rooms(savef, rooms, MAXROOMS);             \r
+    rs_write_room_reference(savef, oldrp);              \r
+    rs_write_stats(savef,&max_stats);                   \r
+    rs_write_object_reference(savef, player.t_pack, cur_weapon); \r
+    rs_write_object_reference(savef, player.t_pack, cur_armor);\r
+    rs_write_object_reference(savef, player.t_pack, cur_ring[0]);\r
+    rs_write_object_reference(savef, player.t_pack, cur_ring[1]);\r
+    rs_write_int(savef, level);                         \r
+    rs_write_int(savef, purse);                         \r
+    rs_write_int(savef, mpos);                          \r
+    rs_write_int(savef, ntraps);                        \r
+    rs_write_int(savef, no_move);                       \r
+    rs_write_int(savef, no_command);                    \r
+    rs_write_int(savef, inpack);                        \r
+    rs_write_int(savef, max_hp);                        \r
+    rs_write_int(savef, total);                         \r
+    rs_write_int(savef, lastscore);                     \r
+    rs_write_int(savef, no_food);                       \r
+    rs_write_int(savef, seed);                          \r
+    rs_write_int(savef, count);                         \r
+    rs_write_int(savef, dnum);                          \r
+    rs_write_int(savef, fung_hit);                      \r
+    rs_write_int(savef, quiet);                         \r
+    rs_write_int(savef, max_level);                     \r
+    rs_write_int(savef, food_left);                     \r
+    rs_write_int(savef, group);                         \r
+    rs_write_int(savef, hungry_state);                  \r
+    rs_write_char(savef, take);\r
+    rs_write_char(savef, runch);\r
+    rs_write_scrolls(savef);\r
+    rs_write_potions(savef);\r
+    rs_write_rings(savef);\r
+    rs_write_sticks(savef);\r
+    rs_write_chars(savef,whoami,80);\r
+    rs_write_chars(savef,fruit,80);\r
+    rs_write_window(savef, cw);\r
+    rs_write_window(savef, mw);\r
+    rs_write_window(savef, stdscr);\r
+    rs_write_boolean(savef, running);                   \r
+    rs_write_boolean(savef, playing);                   \r
+    rs_write_boolean(savef, wizard);                    \r
+    rs_write_boolean(savef, after);\r
+    rs_write_boolean(savef, notify);                    \r
+    rs_write_boolean(savef, fight_flush);               \r
+    rs_write_boolean(savef, terse);                     \r
+    rs_write_boolean(savef, door_stop);                 \r
+    rs_write_boolean(savef, jump);                      \r
+    rs_write_boolean(savef, slow_invent);               \r
+    rs_write_boolean(savef, firstmove);                 \r
+    rs_write_boolean(savef, waswizard);                 \r
+    rs_write_boolean(savef, askme);                     \r
+    rs_write_boolean(savef, amulet);                    \r
+    rs_write_boolean(savef, in_shell);                  \r
+    rs_write_coord(savef, oldpos);                      \r
+    rs_write_coord(savef, delta);                       \r
+    rs_write_coord(savef, ch_ret);                      /* chase.c      */\r
+    rs_write_daemons(savef, &d_list[0], 20);            /* daemon.c     */\r
+    rs_write_int(savef,between);                        /* daemons.c    */\r
+    rs_write_int(savef,num_checks);                     /* main.c       */\r
+    rs_write_chars(savef,lvl_mons,sizeof(lvl_mons));    /* monsters.c   */\r
+    rs_write_chars(savef,wand_mons,sizeof(wand_mons)); /* monsters.c   */\r
+\r
+    return(WRITESTAT);\r
+}\r
+\r
+int\r
+rs_restore_file(int inf)\r
+{\r
+    if (read_error || format_error)\r
+        return(READSTAT);\r
+\r
+    rs_read_thing(inf, &player);                        \r
+    rs_read_object_list(inf, &lvl_obj);                 \r
+    rs_read_thing_list(inf, &mlist);                  \r
+    rs_fix_thing(&player);\r
+    rs_fix_thing_list(mlist);\r
+    rs_read_traps(inf, traps, MAXTRAPS);\r
+    rs_read_rooms(inf, rooms, MAXROOMS);\r
+    rs_read_room_reference(inf, &oldrp);\r
+    rs_read_stats(inf,&max_stats);                      \r
+    rs_read_object_reference(inf, player.t_pack, &cur_weapon);\r
+    rs_read_object_reference(inf, player.t_pack, &cur_armor);\r
+    rs_read_object_reference(inf, player.t_pack, &cur_ring[0]);\r
+    rs_read_object_reference(inf, player.t_pack, &cur_ring[1]);\r
+    rs_fix_magic_items(things,NUMTHINGS);         \r
+    rs_fix_magic_items(s_magic,MAXSCROLLS);       \r
+    rs_fix_magic_items(p_magic,MAXPOTIONS);       \r
+    rs_fix_magic_items(r_magic,MAXRINGS);         \r
+    rs_fix_magic_items(ws_magic,MAXSTICKS);       \r
+    rs_read_int(inf, &level);                           \r
+    rs_read_int(inf, &purse);                           \r
+    rs_read_int(inf, &mpos);                            \r
+    rs_read_int(inf, &ntraps);                          \r
+    rs_read_int(inf, &no_move);                         \r
+    rs_read_int(inf, &no_command);                      \r
+    rs_read_int(inf, &inpack);                          \r
+    rs_read_int(inf, &max_hp);                          \r
+    rs_read_int(inf, &total);                           \r
+    rs_read_int(inf, &lastscore);                       \r
+    rs_read_int(inf, &no_food);                         \r
+    rs_read_int(inf, &seed);                            \r
+    rs_read_int(inf, &count);                           \r
+    rs_read_int(inf, &dnum);                            \r
+    rs_read_int(inf, &fung_hit);                        \r
+    rs_read_int(inf, &quiet);                           \r
+    rs_read_int(inf, &max_level);                       \r
+    rs_read_int(inf, &food_left);                       \r
+    rs_read_int(inf, &group);                           \r
+    rs_read_int(inf, &hungry_state);                    \r
+    rs_read_char(inf, &take);\r
+    rs_read_char(inf, &runch);\r
+    rs_read_scrolls(inf);\r
+    rs_read_potions(inf);\r
+    rs_read_rings(inf);\r
+    rs_read_sticks(inf);\r
+    rs_read_chars(inf,whoami,80);\r
+    rs_read_chars(inf,fruit,80);\r
+    rs_read_window(inf, cw);\r
+    rs_read_window(inf, mw);\r
+    rs_read_window(inf, stdscr);\r
+    rs_read_boolean(inf, &running);                     \r
+    rs_read_boolean(inf, &playing);                     \r
+    rs_read_boolean(inf, &wizard);                      \r
+    rs_read_boolean(inf, &after);\r
+    rs_read_boolean(inf, &notify);                      \r
+    rs_read_boolean(inf, &fight_flush);                 \r
+    rs_read_boolean(inf, &terse);                       \r
+    rs_read_boolean(inf, &door_stop);                   \r
+    rs_read_boolean(inf, &jump);                        \r
+    rs_read_boolean(inf, &slow_invent);                 \r
+    rs_read_boolean(inf, &firstmove);                   \r
+    rs_read_boolean(inf, &waswizard);                   \r
+    rs_read_boolean(inf, &askme);                       \r
+    rs_read_boolean(inf, &amulet);                      \r
+    rs_read_boolean(inf, &in_shell);                    \r
+    rs_read_coord(inf,&oldpos);                         \r
+    rs_read_coord(inf,&delta);                          \r
+    rs_read_coord(inf, &ch_ret);                        /* chase.c      */\r
+    rs_read_daemons(inf, d_list, 20);                   /* daemon.c     */\r
+    rs_read_int(inf,&between);                          /* daemons.c    */\r
+    rs_read_int(inf,&num_checks);                       /* main.c       */\r
+    rs_read_chars(inf, lvl_mons, sizeof(lvl_mons));     /* monsters.c   */\r
+    rs_read_chars(inf, wand_mons, sizeof(wand_mons));  /* monsters.c   */\r
+    rs_fix_monsters(monsters);    \r
+    return(READSTAT);\r
+}\r
diff --git a/sticks.c b/sticks.c
new file mode 100644 (file)
index 0000000..262dce1
--- /dev/null
+++ b/sticks.c
@@ -0,0 +1,398 @@
+/*\r
+ * Functions to implement the various sticks one might find\r
+ * while wandering around the dungeon.\r
+ *\r
+ * @(#)sticks.c        3.14 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <ctype.h>\r
+#include <string.h>\r
+#include "rogue.h"\r
+\r
+fix_stick(cur)\r
+register struct object *cur;\r
+{\r
+    if (strcmp(ws_type[cur->o_which], "staff") == 0)\r
+       strcpy(cur->o_damage,"2d3");\r
+    else\r
+       strcpy(cur->o_damage,"1d1");\r
+    strcpy(cur->o_hurldmg,"1d1");\r
+\r
+    cur->o_charges = 3 + rnd(5);\r
+    switch (cur->o_which)\r
+    {\r
+       case WS_HIT:\r
+           cur->o_hplus = 3;\r
+           cur->o_dplus = 3;\r
+           strcpy(cur->o_damage,"1d8");\r
+       when WS_LIGHT:\r
+           cur->o_charges = 10 + rnd(10);\r
+    }\r
+}\r
+\r
+do_zap(gotdir)\r
+bool gotdir;\r
+{\r
+    register struct linked_list *item;\r
+    register struct object *obj;\r
+    register struct room *rp;\r
+    register struct thing *tp;\r
+    register int y, x;\r
+\r
+    if ((item = get_item("zap with", STICK)) == NULL)\r
+       return;\r
+    obj = (struct object *) ldata(item);\r
+    if (obj->o_type != STICK)\r
+    {\r
+       msg("You can't zap with that!");\r
+       after = FALSE;\r
+       return;\r
+    }\r
+    if (obj->o_charges == 0)\r
+    {\r
+       msg("Nothing happens.");\r
+       return;\r
+    }\r
+    if (!gotdir)\r
+       do {\r
+           delta.y = rnd(3) - 1;\r
+           delta.x = rnd(3) - 1;\r
+       } while (delta.y == 0 && delta.x == 0);\r
+    switch (obj->o_which)\r
+    {\r
+       case WS_LIGHT:\r
+           /*\r
+            * Reddy Kilowat wand.  Light up the room\r
+            */\r
+           ws_know[WS_LIGHT] = TRUE;\r
+           if ((rp = roomin(&hero)) == NULL)\r
+               msg("The corridor glows and then fades");\r
+           else\r
+           {\r
+               addmsg("The room is lit");\r
+               if (!terse)\r
+                   addmsg(" by a shimmering blue light.");\r
+               endmsg();\r
+               rp->r_flags &= ~ISDARK;\r
+               /*\r
+                * Light the room and put the player back up\r
+                */\r
+               light(&hero);\r
+               mvwaddch(cw, hero.y, hero.x, PLAYER);\r
+           }\r
+       when WS_DRAIN:\r
+           /*\r
+            * Take away 1/2 of hero's hit points, then take it away\r
+            * evenly from the monsters in the room (or next to hero\r
+            * if he is in a passage)\r
+            */\r
+           if (pstats.s_hpt < 2)\r
+           {\r
+               msg("You are too weak to use it.");\r
+               return;\r
+           }\r
+           else if ((rp = roomin(&hero)) == NULL)\r
+               drain(hero.y-1, hero.y+1, hero.x-1, hero.x+1);\r
+           else\r
+               drain(rp->r_pos.y, rp->r_pos.y+rp->r_max.y,\r
+                   rp->r_pos.x, rp->r_pos.x+rp->r_max.x);\r
+       when WS_POLYMORPH:\r
+       case WS_TELAWAY:\r
+       case WS_TELTO:\r
+       case WS_CANCEL:\r
+       {\r
+           register char monster, oldch;\r
+           register int rm;\r
+\r
+           y = hero.y;\r
+           x = hero.x;\r
+           while (step_ok(winat(y, x)))\r
+           {\r
+               y += delta.y;\r
+               x += delta.x;\r
+           }\r
+           if (isupper(monster = mvwinch(mw, y, x)))\r
+           {\r
+               register char omonst = monster;\r
+\r
+               if (monster == 'F')\r
+                   player.t_flags &= ~ISHELD;\r
+               item = find_mons(y, x);\r
+               tp = (struct thing *) ldata(item);\r
+               if (obj->o_which == WS_POLYMORPH)\r
+               {\r
+                   detach(mlist, item);\r
+                   oldch = tp->t_oldch;\r
+                   delta.y = y;\r
+                   delta.x = x;\r
+                   new_monster(item, monster = rnd(26) + 'A', &delta);\r
+                   if (!(tp->t_flags & ISRUN))\r
+                       runto(&delta, &hero);\r
+                   if (isupper(mvwinch(cw, y, x)))\r
+                       mvwaddch(cw, y, x, monster);\r
+                   tp->t_oldch = oldch;\r
+                   ws_know[WS_POLYMORPH] |= (monster != omonst);\r
+               }\r
+               else if (obj->o_which == WS_CANCEL)\r
+               {\r
+                   tp->t_flags |= ISCANC;\r
+                   tp->t_flags &= ~ISINVIS;\r
+               }\r
+               else\r
+               {\r
+                   if (obj->o_which == WS_TELAWAY)\r
+                   {\r
+                       do\r
+                       {\r
+                           rm = rnd_room();\r
+                           rnd_pos(&rooms[rm], &tp->t_pos);\r
+                       } until(winat(tp->t_pos.y, tp->t_pos.x) == FLOOR);\r
+                   }\r
+                   else\r
+                   {\r
+                       tp->t_pos.y = hero.y + delta.y;\r
+                       tp->t_pos.x = hero.x + delta.x;\r
+                   }\r
+                   if (isupper(mvwinch(cw, y, x)))\r
+                       mvwaddch(cw, y, x, tp->t_oldch);\r
+                   tp->t_dest = &hero;\r
+                   tp->t_flags |= ISRUN;\r
+                   mvwaddch(mw, y, x, ' ');\r
+                   mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, monster);\r
+                   if (tp->t_pos.y != y || tp->t_pos.x != x)\r
+                       tp->t_oldch = mvwinch(cw, tp->t_pos.y, tp->t_pos.x);\r
+               }\r
+           }\r
+       }\r
+       when WS_MISSILE:\r
+       {\r
+           static struct object bolt =\r
+           {\r
+               '*' , {0, 0}, 0, "", "1d4" , 0, 0, 100, 1, 0, 0, 0\r
+           };\r
+\r
+           do_motion(&bolt, delta.y, delta.x);\r
+           if (isupper(mvwinch(mw, bolt.o_pos.y, bolt.o_pos.x))\r
+               && !save_throw(VS_MAGIC, ldata(find_mons(unc(bolt.o_pos)))))\r
+                   hit_monster(unc(bolt.o_pos), &bolt);\r
+           else if (terse)\r
+               msg("Missile vanishes");\r
+           else\r
+               msg("The missile vanishes with a puff of smoke");\r
+           ws_know[WS_MISSILE] = TRUE;\r
+       }\r
+       when WS_HIT:\r
+       {\r
+           register char ch;\r
+\r
+           delta.y += hero.y;\r
+           delta.x += hero.x;\r
+           ch = winat(delta.y, delta.x);\r
+           if (isupper(ch))\r
+           {\r
+               if (rnd(20) == 0)\r
+               {\r
+                   strcpy(obj->o_damage,"3d8");\r
+                   obj->o_dplus = 9;\r
+               }\r
+               else\r
+               {\r
+                   strcpy(obj->o_damage,"1d8");\r
+                   obj->o_dplus = 3;\r
+               }\r
+               fight(&delta, ch, obj, FALSE);\r
+           }\r
+       }\r
+       when WS_HASTE_M:\r
+       case WS_SLOW_M:\r
+           y = hero.y;\r
+           x = hero.x;\r
+           while (step_ok(winat(y, x)))\r
+           {\r
+               y += delta.y;\r
+               x += delta.x;\r
+           }\r
+           if (isupper(mvwinch(mw, y, x)))\r
+           {\r
+               item = find_mons(y, x);\r
+               tp = (struct thing *) ldata(item);\r
+               if (obj->o_which == WS_HASTE_M)\r
+               {\r
+                   if (on(*tp, ISSLOW))\r
+                       tp->t_flags &= ~ISSLOW;\r
+                   else\r
+                       tp->t_flags |= ISHASTE;\r
+               }\r
+               else\r
+               {\r
+                   if (on(*tp, ISHASTE))\r
+                       tp->t_flags &= ~ISHASTE;\r
+                   else\r
+                       tp->t_flags |= ISSLOW;\r
+                   tp->t_turn = TRUE;\r
+               }\r
+               delta.y = y;\r
+               delta.x = x;\r
+               runto(&delta, &hero);\r
+           }\r
+       when WS_ELECT:\r
+       case WS_FIRE:\r
+       case WS_COLD:\r
+       {\r
+           register char dirch, ch, *name;\r
+           register bool bounced, used;\r
+           coord pos;\r
+           coord spotpos[BOLT_LENGTH];\r
+           static struct object bolt =\r
+           {\r
+               '*' , {0, 0}, 0, "", "6d6" , 0, 0, 100, 0, 0, 0 ,0\r
+           };\r
+\r
+\r
+           switch (delta.y + delta.x)\r
+           {\r
+               case 0: dirch = '/';\r
+               when 1: case -1: dirch = (delta.y == 0 ? '-' : '|');\r
+               when 2: case -2: dirch = '\\';\r
+           }\r
+           pos = hero;\r
+           bounced = FALSE;\r
+           used = FALSE;\r
+           if (obj->o_which == WS_ELECT)\r
+               name = "bolt";\r
+           else if (obj->o_which == WS_FIRE)\r
+               name = "flame";\r
+           else\r
+               name = "ice";\r
+           for (y = 0; y < BOLT_LENGTH && !used; y++)\r
+           {\r
+               ch = winat(pos.y, pos.x);\r
+               spotpos[y] = pos;\r
+               switch (ch)\r
+               {\r
+                   case DOOR:\r
+                   case SECRETDOOR:\r
+                   case '|':\r
+                   case '-':\r
+                   case ' ':\r
+                       bounced = TRUE;\r
+                       delta.y = -delta.y;\r
+                       delta.x = -delta.x;\r
+                       y--;\r
+                       msg("The bolt bounces");\r
+                       break;\r
+                   default:\r
+                       if (!bounced && isupper(ch))\r
+                       {\r
+                           if (!save_throw(VS_MAGIC, ldata(find_mons(unc(pos)))))\r
+                           {\r
+                               bolt.o_pos = pos;\r
+                               hit_monster(unc(pos), &bolt);\r
+                               used = TRUE;\r
+                           }\r
+                           else if (ch != 'M' || show(pos.y, pos.x) == 'M')\r
+                           {\r
+                               if (terse)\r
+                                   msg("%s misses", name);\r
+                               else\r
+                                   msg("The %s whizzes past the %s", name, monsters[ch-'A'].m_name);\r
+                               runto(&pos, &hero);\r
+                           }\r
+                       }\r
+                       else if (bounced && pos.y == hero.y && pos.x == hero.x)\r
+                       {\r
+                           bounced = FALSE;\r
+                           if (!save(VS_MAGIC))\r
+                           {\r
+                               if (terse)\r
+                                   msg("The %s hits", name);\r
+                               else\r
+                                   msg("You are hit by the %s", name);\r
+                               if ((pstats.s_hpt -= roll(6, 6)) <= 0)\r
+                                   death('b');\r
+                               used = TRUE;\r
+                           }\r
+                           else\r
+                               msg("The %s whizzes by you", name);\r
+                       }\r
+                       mvwaddch(cw, pos.y, pos.x, dirch);\r
+                       draw(cw);\r
+               }\r
+               pos.y += delta.y;\r
+               pos.x += delta.x;\r
+           }\r
+           for (x = 0; x < y; x++)\r
+               mvwaddch(cw, spotpos[x].y, spotpos[x].x, show(spotpos[x].y, spotpos[x].x));\r
+           ws_know[obj->o_which] = TRUE;\r
+       }\r
+       otherwise:\r
+           msg("What a bizarre schtick!");\r
+    }\r
+    obj->o_charges--;\r
+}\r
+\r
+/*\r
+ * drain:\r
+ *     Do drain hit points from player shtick\r
+ */\r
+\r
+drain(ymin, ymax, xmin, xmax)\r
+int ymin, ymax, xmin, xmax;\r
+{\r
+    register int i, j, count;\r
+    register struct thing *ick;\r
+    register struct linked_list *item;\r
+\r
+    /*\r
+     * First count how many things we need to spread the hit points among\r
+     */\r
+    count = 0;\r
+    for (i = ymin; i <= ymax; i++)\r
+       for (j = xmin; j <= xmax; j++)\r
+           if (isupper(mvwinch(mw, i, j)))\r
+               count++;\r
+    if (count == 0)\r
+    {\r
+       msg("You have a tingling feeling");\r
+       return;\r
+    }\r
+    count = pstats.s_hpt / count;\r
+    pstats.s_hpt /= 2;\r
+    /*\r
+     * Now zot all of the monsters\r
+     */\r
+    for (i = ymin; i <= ymax; i++)\r
+       for (j = xmin; j <= xmax; j++)\r
+           if (isupper(mvwinch(mw, i, j)) &&\r
+               ((item = find_mons(i, j)) != NULL))\r
+           {\r
+               ick = (struct thing *) ldata(item);\r
+               if ((ick->t_stats.s_hpt -= count) < 1)\r
+                   killed(item, cansee(i, j) && !on(*ick, ISINVIS));\r
+           }\r
+}\r
+\r
+/*\r
+ * charge a wand for wizards.\r
+ */\r
+char *\r
+charge_str(obj)\r
+register struct object *obj;\r
+{\r
+    static char buf[20];\r
+\r
+    if (!(obj->o_flags & ISKNOW))\r
+       buf[0] = '\0';\r
+    else if (terse)\r
+       sprintf(buf, " [%d]", obj->o_charges);\r
+    else\r
+       sprintf(buf, " [%d charges]", obj->o_charges);\r
+    return buf;\r
+}\r
diff --git a/things.c b/things.c
new file mode 100644 (file)
index 0000000..ee08f26
--- /dev/null
+++ b/things.c
@@ -0,0 +1,382 @@
+/*\r
+ * Contains functions for dealing with things like\r
+ * potions and scrolls\r
+ *\r
+ * @(#)things.c        3.37 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <ctype.h>\r
+#include <string.h>\r
+#include "rogue.h"\r
+\r
+/*\r
+ * inv_name:\r
+ *     return the name of something as it would appear in an\r
+ *     inventory.\r
+ */\r
+char *\r
+inv_name(obj, drop)\r
+register struct object *obj;\r
+register bool drop;\r
+{\r
+    register char *pb;\r
+\r
+    switch(obj->o_type)\r
+    {\r
+       case SCROLL:\r
+           if (obj->o_count == 1)\r
+               strcpy(prbuf, "A scroll ");\r
+           else\r
+               sprintf(prbuf, "%d scrolls ", obj->o_count);\r
+           pb = &prbuf[strlen(prbuf)];\r
+           if (s_know[obj->o_which])\r
+               sprintf(pb, "of %s", s_magic[obj->o_which].mi_name);\r
+           else if (s_guess[obj->o_which])\r
+               sprintf(pb, "called %s", s_guess[obj->o_which]);\r
+           else\r
+               sprintf(pb, "titled '%s'", s_names[obj->o_which]);\r
+        when POTION:\r
+           if (obj->o_count == 1)\r
+               strcpy(prbuf, "A potion ");\r
+           else\r
+               sprintf(prbuf, "%d potions ", obj->o_count);\r
+           pb = &prbuf[strlen(prbuf)];\r
+           if (p_know[obj->o_which])\r
+               sprintf(pb, "of %s(%s)", p_magic[obj->o_which].mi_name,\r
+                   p_colors[obj->o_which]);\r
+           else if (p_guess[obj->o_which])\r
+               sprintf(pb, "called %s(%s)", p_guess[obj->o_which],\r
+                   p_colors[obj->o_which]);\r
+           else if (obj->o_count == 1)\r
+               sprintf(prbuf, "A%s %s potion",\r
+                   vowelstr(p_colors[obj->o_which]),\r
+                   p_colors[obj->o_which]);\r
+           else\r
+               sprintf(prbuf, "%d %s potions", obj->o_count,\r
+                   p_colors[obj->o_which]);\r
+       when FOOD:\r
+           if (obj->o_which == 1)\r
+               if (obj->o_count == 1)\r
+                   sprintf(prbuf, "A%s %s", vowelstr(fruit), fruit);\r
+               else\r
+                   sprintf(prbuf, "%d %ss", obj->o_count, fruit);\r
+           else\r
+               if (obj->o_count == 1)\r
+                   strcpy(prbuf, "Some food");\r
+               else\r
+                   sprintf(prbuf, "%d rations of food", obj->o_count);\r
+       when WEAPON:\r
+           if (obj->o_count > 1)\r
+               sprintf(prbuf, "%d ", obj->o_count);\r
+           else\r
+               strcpy(prbuf, "A ");\r
+           pb = &prbuf[strlen(prbuf)];\r
+           if (obj->o_flags & ISKNOW)\r
+               sprintf(pb, "%s %s", num(obj->o_hplus, obj->o_dplus),\r
+                   w_names[obj->o_which]);\r
+           else\r
+               sprintf(pb, "%s", w_names[obj->o_which]);\r
+           if (obj->o_count > 1)\r
+               strcat(prbuf, "s");\r
+       when ARMOR:\r
+           if (obj->o_flags & ISKNOW)\r
+               sprintf(prbuf, "%s %s",\r
+                   num(a_class[obj->o_which] - obj->o_ac, 0),\r
+                   a_names[obj->o_which]);\r
+           else\r
+               sprintf(prbuf, "%s", a_names[obj->o_which]);\r
+       when AMULET:\r
+           strcpy(prbuf, "The Amulet of Yendor");\r
+       when STICK:\r
+           sprintf(prbuf, "A %s ", ws_type[obj->o_which]);\r
+           pb = &prbuf[strlen(prbuf)];\r
+           if (ws_know[obj->o_which])\r
+               sprintf(pb, "of %s%s(%s)", ws_magic[obj->o_which].mi_name,\r
+                   charge_str(obj), ws_made[obj->o_which]);\r
+           else if (ws_guess[obj->o_which])\r
+               sprintf(pb, "called %s(%s)", ws_guess[obj->o_which],\r
+                   ws_made[obj->o_which]);\r
+           else\r
+               sprintf(&prbuf[2], "%s %s", ws_made[obj->o_which],\r
+                   ws_type[obj->o_which]);\r
+        when RING:\r
+           if (r_know[obj->o_which])\r
+               sprintf(prbuf, "A%s ring of %s(%s)", ring_num(obj),\r
+                   r_magic[obj->o_which].mi_name, r_stones[obj->o_which]);\r
+           else if (r_guess[obj->o_which])\r
+               sprintf(prbuf, "A ring called %s(%s)",\r
+                   r_guess[obj->o_which], r_stones[obj->o_which]);\r
+           else\r
+               sprintf(prbuf, "A%s %s ring", vowelstr(r_stones[obj->o_which]),\r
+                   r_stones[obj->o_which]);\r
+       otherwise:\r
+           debug("Picked up something funny");\r
+           sprintf(prbuf, "Something bizarre %s", unctrl(obj->o_type));\r
+    }\r
+    if (obj == cur_armor)\r
+       strcat(prbuf, " (being worn)");\r
+    if (obj == cur_weapon)\r
+       strcat(prbuf, " (weapon in hand)");\r
+    if (obj == cur_ring[LEFT])\r
+       strcat(prbuf, " (on left hand)");\r
+    else if (obj == cur_ring[RIGHT])\r
+       strcat(prbuf, " (on right hand)");\r
+    if (drop && isupper(prbuf[0]))\r
+       prbuf[0] = tolower(prbuf[0]);\r
+    else if (!drop && islower(*prbuf))\r
+       *prbuf = toupper(*prbuf);\r
+    if (!drop)\r
+       strcat(prbuf, ".");\r
+    return prbuf;\r
+}\r
+\r
+/*\r
+ * money:\r
+ *     Add to characters purse\r
+ */\r
+money()\r
+{\r
+    register struct room *rp;\r
+\r
+    for (rp = rooms; rp <= &rooms[MAXROOMS-1]; rp++)\r
+       if (ce(hero, rp->r_gold))\r
+       {\r
+           if (notify)\r
+           {\r
+               if (!terse)\r
+                   addmsg("You found ");\r
+               msg("%d gold pieces.", rp->r_goldval);\r
+           }\r
+           purse += rp->r_goldval;\r
+           rp->r_goldval = 0;\r
+           cmov(rp->r_gold);\r
+           addch(FLOOR);\r
+           return;\r
+       }\r
+    msg("That gold must have been counterfeit");\r
+}\r
+\r
+/*\r
+ * drop:\r
+ *     put something down\r
+ */\r
+drop()\r
+{\r
+    register char ch;\r
+    register struct linked_list *obj, *nobj;\r
+    register struct object *op;\r
+\r
+    ch = mvwinch(stdscr, hero.y, hero.x);\r
+    if (ch != FLOOR && ch != PASSAGE)\r
+    {\r
+       msg("There is something there already");\r
+       return;\r
+    }\r
+    if ((obj = get_item("drop", 0)) == NULL)\r
+       return;\r
+    op = (struct object *) ldata(obj);\r
+    if (!dropcheck(op))\r
+       return;\r
+    /*\r
+     * Take it out of the pack\r
+     */\r
+    if (op->o_count >= 2 && op->o_type != WEAPON)\r
+    {\r
+       nobj = new_item(sizeof *op);\r
+       op->o_count--;\r
+       op = (struct object *) ldata(nobj);\r
+       *op = *((struct object *) ldata(obj));\r
+       op->o_count = 1;\r
+       obj = nobj;\r
+       if (op->o_group != 0)\r
+               inpack++;\r
+    }\r
+    else\r
+       detach(pack, obj);\r
+    inpack--;\r
+    /*\r
+     * Link it into the level object list\r
+     */\r
+    attach(lvl_obj, obj);\r
+    mvaddch(hero.y, hero.x, op->o_type);\r
+    op->o_pos = hero;\r
+    msg("Dropped %s", inv_name(op, TRUE));\r
+}\r
+\r
+/*\r
+ * do special checks for dropping or unweilding|unwearing|unringing\r
+ */\r
+dropcheck(op)\r
+register struct object *op;\r
+{\r
+    str_t save_max;\r
+\r
+    if (op == NULL)\r
+       return TRUE;\r
+    if (op != cur_armor && op != cur_weapon\r
+       && op != cur_ring[LEFT] && op != cur_ring[RIGHT])\r
+           return TRUE;\r
+    if (op->o_flags & ISCURSED)\r
+    {\r
+       msg("You can't.  It appears to be cursed.");\r
+       return FALSE;\r
+    }\r
+    if (op == cur_weapon)\r
+       cur_weapon = NULL;\r
+    else if (op == cur_armor)\r
+    {\r
+       waste_time();\r
+       cur_armor = NULL;\r
+    }\r
+    else if (op == cur_ring[LEFT] || op == cur_ring[RIGHT])\r
+    {\r
+       switch (op->o_which)\r
+       {\r
+           case R_ADDSTR:\r
+               save_max = max_stats.s_str;\r
+               chg_str(-op->o_ac);\r
+               max_stats.s_str = save_max;\r
+               break;\r
+           case R_SEEINVIS:\r
+               player.t_flags &= ~CANSEE;\r
+               extinguish(unsee);\r
+               light(&hero);\r
+               mvwaddch(cw, hero.y, hero.x, PLAYER);\r
+               break;\r
+       }\r
+       cur_ring[op == cur_ring[LEFT] ? LEFT : RIGHT] = NULL;\r
+    }\r
+    return TRUE;\r
+}\r
+\r
+/*\r
+ * return a new thing\r
+ */\r
+struct linked_list *\r
+new_thing()\r
+{\r
+    register struct linked_list *item;\r
+    register struct object *cur;\r
+    register int j, k;\r
+\r
+    item = new_item(sizeof *cur);\r
+    cur = (struct object *) ldata(item);\r
+    cur->o_hplus = cur->o_dplus = 0;\r
+    strcpy(cur->o_damage,"0d0");\r
+    strcpy(cur->o_hurldmg,"0d0");\r
+    cur->o_ac = 11;\r
+    cur->o_count = 1;\r
+    cur->o_group = 0;\r
+    cur->o_flags = 0;\r
+    /*\r
+     * Decide what kind of object it will be\r
+     * If we haven't had food for a while, let it be food.\r
+     */\r
+    switch (no_food > 3 ? 2 : pick_one(things, NUMTHINGS))\r
+    {\r
+       case 0:\r
+           cur->o_type = POTION;\r
+           cur->o_which = pick_one(p_magic, MAXPOTIONS);\r
+       when 1:\r
+           cur->o_type = SCROLL;\r
+           cur->o_which = pick_one(s_magic, MAXSCROLLS);\r
+       when 2:\r
+           no_food = 0;\r
+           cur->o_type = FOOD;\r
+           if (rnd(100) > 10)\r
+               cur->o_which = 0;\r
+           else\r
+               cur->o_which = 1;\r
+       when 3:\r
+           cur->o_type = WEAPON;\r
+           cur->o_which = rnd(MAXWEAPONS);\r
+           init_weapon(cur, cur->o_which);\r
+           if ((k = rnd(100)) < 10)\r
+           {\r
+               cur->o_flags |= ISCURSED;\r
+               cur->o_hplus -= rnd(3)+1;\r
+           }\r
+           else if (k < 15)\r
+               cur->o_hplus += rnd(3)+1;\r
+       when 4:\r
+           cur->o_type = ARMOR;\r
+           for (j = 0, k = rnd(100); j < MAXARMORS; j++)\r
+               if (k < a_chances[j])\r
+                   break;\r
+           if (j == MAXARMORS)\r
+           {\r
+               debug("Picked a bad armor %d", k);\r
+               j = 0;\r
+           }\r
+           cur->o_which = j;\r
+           cur->o_ac = a_class[j];\r
+           if ((k = rnd(100)) < 20)\r
+           {\r
+               cur->o_flags |= ISCURSED;\r
+               cur->o_ac += rnd(3)+1;\r
+           }\r
+           else if (k < 28)\r
+               cur->o_ac -= rnd(3)+1;\r
+       when 5:\r
+           cur->o_type = RING;\r
+           cur->o_which = pick_one(r_magic, MAXRINGS);\r
+           switch (cur->o_which)\r
+           {\r
+               case R_ADDSTR:\r
+               case R_PROTECT:\r
+               case R_ADDHIT:\r
+               case R_ADDDAM:\r
+                   if ((cur->o_ac = rnd(3)) == 0)\r
+                   {\r
+                       cur->o_ac = -1;\r
+                       cur->o_flags |= ISCURSED;\r
+                   }\r
+               when R_AGGR:\r
+               case R_TELEPORT:\r
+                   cur->o_flags |= ISCURSED;\r
+           }\r
+       when 6:\r
+           cur->o_type = STICK;\r
+           cur->o_which = pick_one(ws_magic, MAXSTICKS);\r
+           fix_stick(cur);\r
+       otherwise:\r
+           debug("Picked a bad kind of object");\r
+           wait_for(' ');\r
+    }\r
+    return item;\r
+}\r
+\r
+/*\r
+ * pick an item out of a list of nitems possible magic items\r
+ */\r
+pick_one(magic, nitems)\r
+register struct magic_item *magic;\r
+int nitems;\r
+{\r
+    register struct magic_item *end;\r
+    register int i;\r
+    register struct magic_item *start;\r
+\r
+    start = magic;\r
+    for (end = &magic[nitems], i = rnd(100); magic < end; magic++)\r
+       if (i < magic->mi_prob)\r
+           break;\r
+    if (magic == end)\r
+    {\r
+       if (wizard)\r
+       {\r
+           msg("bad pick_one: %d from %d items", i, nitems);\r
+           for (magic = start; magic < end; magic++)\r
+               msg("%s: %d%%", magic->mi_name, magic->mi_prob);\r
+       }\r
+       magic = start;\r
+    }\r
+    return magic - start;\r
+}\r
diff --git a/vers.c b/vers.c
new file mode 100644 (file)
index 0000000..b30cd2a
--- /dev/null
+++ b/vers.c
@@ -0,0 +1,16 @@
+/*\r
+ * version number.  Whenever a new version number is desired, use\r
+ * sccs to get vers.c.  Environ and encstr are declared here to\r
+ * force them to be loaded before the version number, and therefore\r
+ * not to be written in saved games.\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+char encstr[] = "\354\251\243\332A\201|\301\321p\210\251\327\"\257\365t\341%3\271^`~\203z{\341};\f\341\231\222e\234\351]\321";\r
+char version[] = "@(#)vers.c   3.6 (Berkeley) 4/21/81";\r
+char *release = "3.6.3";\r
diff --git a/weapons.c b/weapons.c
new file mode 100644 (file)
index 0000000..24e811f
--- /dev/null
+++ b/weapons.c
@@ -0,0 +1,316 @@
+/*\r
+ * Functions for dealing with problems brought about by weapons\r
+ *\r
+ * @(#)weapons.c       3.17 (Berkeley) 6/15/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <ctype.h>\r
+#include <string.h>\r
+#include "rogue.h"\r
+\r
+#define NONE 100\r
+\r
+char *w_names[MAXWEAPONS] = {\r
+    "mace",\r
+    "long sword",\r
+    "short bow",\r
+    "arrow",\r
+    "dagger",\r
+    "rock",\r
+    "two handed sword",\r
+    "sling",\r
+    "dart",\r
+    "crossbow",\r
+    "crossbow bolt",\r
+    "spear",\r
+};\r
+\r
+static struct init_weps {\r
+    char *iw_dam;\r
+    char *iw_hrl;\r
+    char iw_launch;\r
+    int iw_flags;\r
+} init_dam[MAXWEAPONS] = {\r
+    "2d4", "1d3", NONE, 0,             /* Mace */\r
+    "1d10", "1d2", NONE,0,             /* Long sword */\r
+    "1d1", "1d1", NONE,        0,              /* Bow */\r
+    "1d1", "1d6", BOW, ISMANY|ISMISL,  /* Arrow */\r
+    "1d6", "1d4", NONE,        ISMISL,         /* Dagger */\r
+    "1d2", "1d4", SLING,ISMANY|ISMISL, /* Rock */\r
+    "3d6", "1d2", NONE,        0,              /* 2h sword */\r
+    "0d0", "0d0", NONE, 0,             /* Sling */\r
+    "1d1", "1d3", NONE,        ISMANY|ISMISL,  /* Dart */\r
+    "1d1", "1d1", NONE, 0,             /* Crossbow */\r
+    "1d2", "1d10", CROSSBOW, ISMANY|ISMISL,/* Crossbow bolt */\r
+    "1d8", "1d6", NONE, ISMISL,                /* Spear */\r
+};\r
+\r
+/*\r
+ * missile:\r
+ *     Fire a missile in a given direction\r
+ */\r
+\r
+missile(ydelta, xdelta)\r
+int ydelta, xdelta;\r
+{\r
+    register struct object *obj;\r
+    register struct linked_list *item, *nitem;\r
+\r
+    /*\r
+     * Get which thing we are hurling\r
+     */\r
+    if ((item = get_item("throw", WEAPON)) == NULL)\r
+       return;\r
+    obj = (struct object *) ldata(item);\r
+    if (!dropcheck(obj) || is_current(obj))\r
+       return;\r
+    /*\r
+     * Get rid of the thing.  If it is a non-multiple item object, or\r
+     * if it is the last thing, just drop it.  Otherwise, create a new\r
+     * item with a count of one.\r
+     */\r
+    if (obj->o_count < 2)\r
+    {\r
+       detach(pack, item);\r
+       inpack--;\r
+    }\r
+    else\r
+    {\r
+       obj->o_count--;\r
+       if (obj->o_group == 0)\r
+           inpack--;\r
+       nitem = (struct linked_list *) new_item(sizeof *obj);\r
+       obj = (struct object *) ldata(nitem);\r
+       *obj = *((struct object *) ldata(item));\r
+       obj->o_count = 1;\r
+       item = nitem;\r
+    }\r
+    do_motion(obj, ydelta, xdelta);\r
+    /*\r
+     * AHA! Here it has hit something.  If it is a wall or a door,\r
+     * or if it misses (combat) the mosnter, put it on the floor\r
+     */\r
+    if (!isupper(mvwinch(mw, obj->o_pos.y, obj->o_pos.x))\r
+       || !hit_monster(unc(obj->o_pos), obj))\r
+           fall(item, TRUE);\r
+    mvwaddch(cw, hero.y, hero.x, PLAYER);\r
+}\r
+\r
+/*\r
+ * do the actual motion on the screen done by an object traveling\r
+ * across the room\r
+ */\r
+do_motion(obj, ydelta, xdelta)\r
+register struct object *obj;\r
+register int ydelta, xdelta;\r
+{\r
+    /*\r
+     * Come fly with us ...\r
+     */\r
+    obj->o_pos = hero;\r
+    for (;;)\r
+    {\r
+       register int ch;\r
+\r
+       /*\r
+        * Erase the old one\r
+        */\r
+       if (!ce(obj->o_pos, hero) && cansee(unc(obj->o_pos)) &&\r
+           mvwinch(cw, obj->o_pos.y, obj->o_pos.x) != ' ')\r
+                   mvwaddch(cw, obj->o_pos.y, obj->o_pos.x,\r
+                           show(obj->o_pos.y, obj->o_pos.x));\r
+       /*\r
+        * Get the new position\r
+        */\r
+       obj->o_pos.y += ydelta;\r
+       obj->o_pos.x += xdelta;\r
+       if (step_ok(ch = winat(obj->o_pos.y, obj->o_pos.x)) && ch != DOOR)\r
+       {\r
+           /*\r
+            * It hasn't hit anything yet, so display it\r
+            * If it alright.\r
+            */\r
+           if (cansee(unc(obj->o_pos)) &&\r
+               mvwinch(cw, obj->o_pos.y, obj->o_pos.x) != ' ')\r
+           {\r
+               mvwaddch(cw, obj->o_pos.y, obj->o_pos.x, obj->o_type);\r
+               draw(cw);\r
+           }\r
+           continue;\r
+       }\r
+       break;\r
+    }\r
+}\r
+\r
+/*\r
+ * fall:\r
+ *     Drop an item someplace around here.\r
+ */\r
+\r
+fall(item, pr)\r
+register struct linked_list *item;\r
+bool pr;\r
+{\r
+    register struct object *obj;\r
+    register struct room *rp;\r
+    static coord fpos;\r
+\r
+    obj = (struct object *) ldata(item);\r
+    if (fallpos(&obj->o_pos, &fpos, TRUE))\r
+    {\r
+       mvaddch(fpos.y, fpos.x, obj->o_type);\r
+       obj->o_pos = fpos;\r
+       if ((rp = roomin(&hero)) != NULL && !(rp->r_flags & ISDARK))\r
+       {\r
+           light(&hero);\r
+           mvwaddch(cw, hero.y, hero.x, PLAYER);\r
+       }\r
+       attach(lvl_obj, item);\r
+       return;\r
+    }\r
+    if (pr)\r
+        if (obj->o_type == WEAPON) /* BUGFUX: Identification trick */\r
+            msg("Your %s vanishes as it hits the ground.", w_names[obj->o_which]);\r
+        else\r
+            msg("%s vanishes as it hits the ground.", inv_name(obj,TRUE));\r
+    discard(item);\r
+}\r
+\r
+/*\r
+ * init_weapon:\r
+ *     Set up the initial goodies for a weapon\r
+ */\r
+\r
+init_weapon(weap, type)\r
+register struct object *weap;\r
+char type;\r
+{\r
+    register struct init_weps *iwp;\r
+\r
+    iwp = &init_dam[type];\r
+    strcpy(weap->o_damage,iwp->iw_dam);\r
+    strcpy(weap->o_hurldmg,iwp->iw_hrl);\r
+    weap->o_launch = iwp->iw_launch;\r
+    weap->o_flags = iwp->iw_flags;\r
+    if (weap->o_flags & ISMANY)\r
+    {\r
+       weap->o_count = rnd(8) + 8;\r
+       weap->o_group = newgrp();\r
+    }\r
+    else\r
+       weap->o_count = 1;\r
+}\r
+\r
+/*\r
+ * Does the missile hit the monster\r
+ */\r
+\r
+hit_monster(y, x, obj)\r
+register int y, x;\r
+struct object *obj;\r
+{\r
+    static coord mp;\r
+\r
+    mp.y = y;\r
+    mp.x = x;\r
+    return fight(&mp, winat(y, x), obj, TRUE);\r
+}\r
+\r
+/*\r
+ * num:\r
+ *     Figure out the plus number for armor/weapons\r
+ */\r
+\r
+char *\r
+num(n1, n2)\r
+register int n1, n2;\r
+{\r
+    static char numbuf[80];\r
+\r
+    if (n1 == 0 && n2 == 0)\r
+       return "+0";\r
+    if (n2 == 0)\r
+       sprintf(numbuf, "%s%d", n1 < 0 ? "" : "+", n1);\r
+    else\r
+        sprintf(numbuf, "%s%d,%s%d",\r
+                               n1 < 0 ? "" : "+", n1, n2 < 0 ? "" : "+", n2);\r
+    return numbuf;\r
+}    \r
+\r
+/*\r
+ * wield:\r
+ *     Pull out a certain weapon\r
+ */\r
+\r
+wield()\r
+{\r
+    register struct linked_list *item;\r
+    register struct object *obj, *oweapon;\r
+\r
+    oweapon = cur_weapon;\r
+    if (!dropcheck(cur_weapon))\r
+    {\r
+       cur_weapon = oweapon;\r
+       return;\r
+    }\r
+    cur_weapon = oweapon;\r
+    if ((item = get_item("wield", WEAPON)) == NULL)\r
+    {\r
+bad:\r
+       after = FALSE;\r
+       return;\r
+    }\r
+\r
+    obj = (struct object *) ldata(item);\r
+    if (obj->o_type == ARMOR)\r
+    {\r
+       msg("You can't wield armor");\r
+       goto bad;\r
+    }\r
+    if (is_current(obj))\r
+        goto bad;\r
+\r
+    if (terse)\r
+       addmsg("W");\r
+    else\r
+       addmsg("You are now w");\r
+    msg("ielding %s", inv_name(obj, TRUE));\r
+    cur_weapon = obj;\r
+}\r
+\r
+/*\r
+ * pick a random position around the give (y, x) coordinates\r
+ */\r
+fallpos(pos, newpos, passages)\r
+register coord *pos, *newpos;\r
+register bool passages;\r
+{\r
+    register int y, x, cnt, ch;\r
+\r
+    cnt = 0;\r
+    for (y = pos->y - 1; y <= pos->y + 1; y++)\r
+       for (x = pos->x - 1; x <= pos->x + 1; x++)\r
+       {\r
+           /*\r
+            * check to make certain the spot is empty, if it is,\r
+            * put the object there, set it in the level list\r
+            * and re-draw the room if he can see it\r
+            */\r
+           if (y == hero.y && x == hero.x)\r
+               continue;\r
+           if (((ch = winat(y, x)) == FLOOR || (passages && ch == PASSAGE))\r
+                                       && rnd(++cnt) == 0)\r
+           {\r
+               newpos->y = y;\r
+               newpos->x = x;\r
+           }\r
+       }\r
+    return (cnt != 0);\r
+}\r
diff --git a/wizard.c b/wizard.c
new file mode 100644 (file)
index 0000000..d5d13c7
--- /dev/null
+++ b/wizard.c
@@ -0,0 +1,197 @@
+\r
+/*\r
+ * Special wizard commands (some of which are also non-wizard commands\r
+ * under strange circumstances)\r
+ *\r
+ * @(#)wizard.c        3.8 (Berkeley) 6/3/81\r
+ *\r
+ * Rogue: Exploring the Dungeons of Doom\r
+ * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman\r
+ * All rights reserved.\r
+ *\r
+ * See the file LICENSE.TXT for full copyright and licensing information.\r
+ */\r
+\r
+#include "curses.h"\r
+#include <ctype.h>\r
+#include <string.h>\r
+#include "rogue.h"\r
+\r
+/*\r
+ * whatis:\r
+ *     What a certin object is\r
+ */\r
+\r
+whatis()\r
+{\r
+    register struct object *obj;\r
+    register struct linked_list *item;\r
+\r
+    if ((item = get_item("identify", 0)) == NULL)\r
+       return;\r
+    obj = (struct object *) ldata(item);\r
+    switch (obj->o_type)\r
+    {\r
+        case SCROLL:\r
+           s_know[obj->o_which] = TRUE;\r
+           if (s_guess[obj->o_which])\r
+           {\r
+               free(s_guess[obj->o_which]);\r
+               s_guess[obj->o_which] = NULL;\r
+           }\r
+        when POTION:\r
+           p_know[obj->o_which] = TRUE;\r
+           if (p_guess[obj->o_which])\r
+           {\r
+               free(p_guess[obj->o_which]);\r
+               p_guess[obj->o_which] = NULL;\r
+           }\r
+       when STICK:\r
+           ws_know[obj->o_which] = TRUE;\r
+           obj->o_flags |= ISKNOW;\r
+           if (ws_guess[obj->o_which])\r
+           {\r
+               free(ws_guess[obj->o_which]);\r
+               ws_guess[obj->o_which] = NULL;\r
+           }\r
+        when WEAPON:\r
+        case ARMOR:\r
+           obj->o_flags |= ISKNOW;\r
+        when RING:\r
+           r_know[obj->o_which] = TRUE;\r
+           obj->o_flags |= ISKNOW;\r
+           if (r_guess[obj->o_which])\r
+           {\r
+               free(r_guess[obj->o_which]);\r
+               r_guess[obj->o_which] = NULL;\r
+           }\r
+    }\r
+    msg(inv_name(obj, FALSE));\r
+}\r
+\r
+/*\r
+ * create_obj:\r
+ *     Wizard command for getting anything he wants\r
+ */\r
+\r
+create_obj()\r
+{\r
+    register struct linked_list *item;\r
+    register struct object *obj;\r
+    register char ch, bless;\r
+\r
+    item = new_item(sizeof *obj);\r
+    obj = (struct object *) ldata(item);\r
+    msg("Type of item: ");\r
+    obj->o_type = readchar(cw);\r
+    mpos = 0;\r
+    msg("Which %c do you want? (0-f)", obj->o_type);\r
+    obj->o_which = (isdigit((ch = readchar(cw))) ? ch - '0' : ch - 'a' + 10);\r
+    obj->o_group = 0;\r
+    obj->o_count = 1;\r
+    mpos = 0;\r
+    if (obj->o_type == WEAPON || obj->o_type == ARMOR)\r
+    {\r
+       msg("Blessing? (+,-,n)");\r
+       bless = readchar(cw);\r
+       mpos = 0;\r
+       if (obj->o_type == WEAPON)\r
+       {\r
+           init_weapon(obj, obj->o_which);\r
+           if (bless == '-') {\r
+               obj->o_hplus -= rnd(3)+1;\r
+               obj->o_flags |= ISCURSED;\r
+           }\r
+           if (bless == '+')\r
+               obj->o_hplus += rnd(3)+1;\r
+       }\r
+       else\r
+       {\r
+           obj->o_ac = a_class[obj->o_which];\r
+           if (bless == '-') {\r
+               obj->o_ac += rnd(3)+1;\r
+               obj->o_flags |= ISCURSED;\r
+           }\r
+           if (bless == '+')\r
+               obj->o_ac -= rnd(3)+1;\r
+       }\r
+    }\r
+    else if (obj->o_type == RING)\r
+       switch (obj->o_which)\r
+       {\r
+           case R_PROTECT:\r
+           case R_ADDSTR:\r
+           case R_ADDHIT:\r
+           case R_ADDDAM:\r
+               msg("Blessing? (+,-,n)");\r
+               bless = readchar(cw);\r
+               mpos = 0;\r
+               if (bless == '-')\r
+                   obj->o_flags |= ISCURSED;\r
+               obj->o_ac = (bless == '-' ? -1 : rnd(2) + 1);\r
+       }\r
+    else if (obj->o_type == STICK)\r
+       fix_stick(obj);\r
+    add_pack(item, FALSE);\r
+}\r
+\r
+/*\r
+ * telport:\r
+ *     Bamf the hero someplace else\r
+ */\r
+\r
+teleport()\r
+{\r
+    register int rm;\r
+    coord c;\r
+\r
+    c = hero;\r
+    mvwaddch(cw, hero.y, hero.x, mvwinch(stdscr, hero.y, hero.x));\r
+    do\r
+    {\r
+       rm = rnd_room();\r
+       rnd_pos(&rooms[rm], &hero);\r
+    } until(winat(hero.y, hero.x) == FLOOR);\r
+    light(&c);\r
+    light(&hero);\r
+    mvwaddch(cw, hero.y, hero.x, PLAYER);\r
+    /*\r
+     * turn off ISHELD in case teleportation was done while fighting\r
+     * a Fungi\r
+     */\r
+    if (on(player, ISHELD)) {\r
+       player.t_flags &= ~ISHELD;\r
+       fung_hit = 0;\r
+       strcpy(monsters['F'-'A'].m_stats.s_dmg, "000d0");\r
+    }\r
+    count = 0;\r
+    running = FALSE;\r
+    flush_type();              /* flush typeahead */\r
+    return rm;\r
+}\r
+\r
+/*\r
+ * passwd:\r
+ *     see if user knows password\r
+ */\r
+\r
+passwd()\r
+{\r
+    register char *sp, c;\r
+    char buf[80], *xcrypt();\r
+\r
+    msg("Wizard's Password:");\r
+    mpos = 0;\r
+    sp = buf;\r
+    while ((c = readchar(cw)) != '\n' && c != '\r' && c != '\033')\r
+       if (c == md_killchar())\r
+           sp = buf;\r
+       else if (c == md_erasechar() && sp > buf)\r
+           sp--;\r
+       else\r
+           *sp++ = c;\r
+    if (sp == buf)\r
+       return FALSE;\r
+    *sp = '\0';\r
+    return (strcmp(PASSWD, xcrypt(buf, "mT")) == 0);\r
+}\r
diff --git a/xcrypt.c b/xcrypt.c
new file mode 100644 (file)
index 0000000..26a55cd
--- /dev/null
+++ b/xcrypt.c
@@ -0,0 +1,684 @@
+/*\r
+ * FreeSec: libcrypt\r
+ *\r
+ * Copyright (C) 1994 David Burren\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * 1. Redistributions of source code must retain the above copyright\r
+ *    notice, this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ *    notice, this list of conditions and the following disclaimer in the\r
+ *    documentation and/or other materials provided with the distribution.\r
+ * 3. Neither the name(s) of the author(s) nor the names of other contributors\r
+ *    may be used to endorse or promote products derived from this software\r
+ *    without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND\r
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE\r
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+ * SUCH DAMAGE.\r
+ *\r
+ *\r
+ * This is an original implementation of the DES and the crypt(3) interfaces\r
+ * by David Burren <davidb@werj.com.au>.\r
+ *\r
+ * An excellent reference on the underlying algorithm (and related\r
+ * algorithms) is:\r
+ *\r
+ *     B. Schneier, Applied Cryptography: protocols, algorithms,\r
+ *     and source code in C, John Wiley & Sons, 1994.\r
+ *\r
+ * Note that in that book's description of DES the lookups for the initial,\r
+ * pbox, and final permutations are inverted (this has been brought to the\r
+ * attention of the author).  A list of errata for this book has been\r
+ * posted to the sci.crypt newsgroup by the author and is available for FTP.\r
+ *\r
+ * NOTE:\r
+ * This file has a static version of des_setkey() so that crypt.o exports\r
+ * only the crypt() interface. This is required to make binaries linked\r
+ * against crypt.o exportable or re-exportable from the USA.\r
+ */\r
+\r
+#include <sys/types.h>\r
+#include <string.h>\r
+\r
+extern unsigned long int md_ntohl(unsigned long int x);\r
+extern unsigned long int md_htonl(unsigned long int x);\r
+\r
+#define _PASSWORD_EFMT1 '_'\r
+\r
+static unsigned char   IP[64] = {\r
+       58, 50, 42, 34, 26, 18, 10,  2, 60, 52, 44, 36, 28, 20, 12,  4,\r
+       62, 54, 46, 38, 30, 22, 14,  6, 64, 56, 48, 40, 32, 24, 16,  8,\r
+       57, 49, 41, 33, 25, 17,  9,  1, 59, 51, 43, 35, 27, 19, 11,  3,\r
+       61, 53, 45, 37, 29, 21, 13,  5, 63, 55, 47, 39, 31, 23, 15,  7\r
+};\r
+\r
+static unsigned char   inv_key_perm[64];\r
+static unsigned char   key_perm[56] = {\r
+       57, 49, 41, 33, 25, 17,  9,  1, 58, 50, 42, 34, 26, 18,\r
+       10,  2, 59, 51, 43, 35, 27, 19, 11,  3, 60, 52, 44, 36,\r
+       63, 55, 47, 39, 31, 23, 15,  7, 62, 54, 46, 38, 30, 22,\r
+       14,  6, 61, 53, 45, 37, 29, 21, 13,  5, 28, 20, 12,  4\r
+};\r
+\r
+static unsigned char   key_shifts[16] = {\r
+       1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1\r
+};\r
+\r
+static unsigned char   inv_comp_perm[56];\r
+static unsigned char   comp_perm[48] = {\r
+       14, 17, 11, 24,  1,  5,  3, 28, 15,  6, 21, 10,\r
+       23, 19, 12,  4, 26,  8, 16,  7, 27, 20, 13,  2,\r
+       41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,\r
+       44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32\r
+};\r
+\r
+/*\r
+ *     No E box is used, as it's replaced by some ANDs, shifts, and ORs.\r
+ */\r
+\r
+static unsigned char   u_sbox[8][64];\r
+static unsigned char   sbox[8][64] = {\r
+       {\r
+               14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,\r
+                0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,\r
+                4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,\r
+               15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13\r
+       },\r
+       {\r
+               15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,\r
+                3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,\r
+                0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,\r
+               13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9\r
+       },\r
+       {\r
+               10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,\r
+               13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,\r
+               13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,\r
+                1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12\r
+       },\r
+       {\r
+                7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,\r
+               13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,\r
+               10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,\r
+                3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14\r
+       },\r
+       {\r
+                2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,\r
+               14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,\r
+                4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,\r
+               11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3\r
+       },\r
+       {\r
+               12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,\r
+               10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,\r
+                9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,\r
+                4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13\r
+       },\r
+       {\r
+                4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,\r
+               13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,\r
+                1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,\r
+                6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12\r
+       },\r
+       {\r
+               13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,\r
+                1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,\r
+                7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,\r
+                2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11\r
+       }\r
+};\r
+\r
+static unsigned char   un_pbox[32];\r
+static unsigned char   pbox[32] = {\r
+       16,  7, 20, 21, 29, 12, 28, 17,  1, 15, 23, 26,  5, 18, 31, 10,\r
+        2,  8, 24, 14, 32, 27,  3,  9, 19, 13, 30,  6, 22, 11,  4, 25\r
+};\r
+\r
+static unsigned int bits32[32] =\r
+{\r
+       0x80000000, 0x40000000, 0x20000000, 0x10000000,\r
+       0x08000000, 0x04000000, 0x02000000, 0x01000000,\r
+       0x00800000, 0x00400000, 0x00200000, 0x00100000,\r
+       0x00080000, 0x00040000, 0x00020000, 0x00010000,\r
+       0x00008000, 0x00004000, 0x00002000, 0x00001000,\r
+       0x00000800, 0x00000400, 0x00000200, 0x00000100,\r
+       0x00000080, 0x00000040, 0x00000020, 0x00000010,\r
+       0x00000008, 0x00000004, 0x00000002, 0x00000001\r
+};\r
+\r
+static unsigned char   bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };\r
+\r
+static unsigned int saltbits;\r
+static int     old_salt;\r
+static unsigned int *bits28, *bits24;\r
+static unsigned char   init_perm[64], final_perm[64];\r
+static unsigned int en_keysl[16], en_keysr[16];\r
+static unsigned int de_keysl[16], de_keysr[16];\r
+static int     des_initialised = 0;\r
+static unsigned char   m_sbox[4][4096];\r
+static unsigned int psbox[4][256];\r
+static unsigned int ip_maskl[8][256], ip_maskr[8][256];\r
+static unsigned int fp_maskl[8][256], fp_maskr[8][256];\r
+static unsigned int key_perm_maskl[8][128], key_perm_maskr[8][128];\r
+static unsigned int comp_maskl[8][128], comp_maskr[8][128];\r
+static unsigned int old_rawkey0, old_rawkey1;\r
+\r
+static unsigned char   ascii64[] =\r
+        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";\r
+/*       0000000000111111111122222222223333333333444444444455555555556666 */\r
+/*       0123456789012345678901234567890123456789012345678901234567890123 */\r
+\r
+static __inline int\r
+ascii_to_bin(char ch)\r
+{\r
+       if (ch > 'z')\r
+               return(0);\r
+       if (ch >= 'a')\r
+               return(ch - 'a' + 38);\r
+       if (ch > 'Z')\r
+               return(0);\r
+       if (ch >= 'A')\r
+               return(ch - 'A' + 12);\r
+       if (ch > '9')\r
+               return(0);\r
+       if (ch >= '.')\r
+               return(ch - '.');\r
+       return(0);\r
+}\r
+\r
+static void\r
+des_init()\r
+{\r
+       int     i, j, b, k, inbit, obit;\r
+       unsigned int    *p, *il, *ir, *fl, *fr;\r
+\r
+       old_rawkey0 = old_rawkey1 = 0;\r
+       saltbits = 0;\r
+       old_salt = 0;\r
+       bits24 = (bits28 = bits32 + 4) + 4;\r
+\r
+       /*\r
+        * Invert the S-boxes, reordering the input bits.\r
+        */\r
+       for (i = 0; i < 8; i++)\r
+               for (j = 0; j < 64; j++) {\r
+                       b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf);\r
+                       u_sbox[i][j] = sbox[i][b];\r
+               }\r
+\r
+       /*\r
+        * Convert the inverted S-boxes into 4 arrays of 8 bits.\r
+        * Each will handle 12 bits of the S-box input.\r
+        */\r
+       for (b = 0; b < 4; b++)\r
+               for (i = 0; i < 64; i++)\r
+                       for (j = 0; j < 64; j++)\r
+                               m_sbox[b][(i << 6) | j] =\r
+                                       (u_sbox[(b << 1)][i] << 4) |\r
+                                       u_sbox[(b << 1) + 1][j];\r
+\r
+       /*\r
+        * Set up the initial & final permutations into a useful form, and\r
+        * initialise the inverted key permutation.\r
+        */\r
+       for (i = 0; i < 64; i++) {\r
+               init_perm[final_perm[i] = IP[i] - 1] = i;\r
+               inv_key_perm[i] = 255;\r
+       }\r
+\r
+       /*\r
+        * Invert the key permutation and initialise the inverted key\r
+        * compression permutation.\r
+        */\r
+       for (i = 0; i < 56; i++) {\r
+               inv_key_perm[key_perm[i] - 1] = i;\r
+               inv_comp_perm[i] = 255;\r
+       }\r
+\r
+       /*\r
+        * Invert the key compression permutation.\r
+        */\r
+       for (i = 0; i < 48; i++) {\r
+               inv_comp_perm[comp_perm[i] - 1] = i;\r
+       }\r
+\r
+       /*\r
+        * Set up the OR-mask arrays for the initial and final permutations,\r
+        * and for the key initial and compression permutations.\r
+        */\r
+       for (k = 0; k < 8; k++) {\r
+               for (i = 0; i < 256; i++) {\r
+                       *(il = &ip_maskl[k][i]) = 0;\r
+                       *(ir = &ip_maskr[k][i]) = 0;\r
+                       *(fl = &fp_maskl[k][i]) = 0;\r
+                       *(fr = &fp_maskr[k][i]) = 0;\r
+                       for (j = 0; j < 8; j++) {\r
+                               inbit = 8 * k + j;\r
+                               if (i & bits8[j]) {\r
+                                       if ((obit = init_perm[inbit]) < 32)\r
+                                               *il |= bits32[obit];\r
+                                       else\r
+                                               *ir |= bits32[obit-32];\r
+                                       if ((obit = final_perm[inbit]) < 32)\r
+                                               *fl |= bits32[obit];\r
+                                       else\r
+                                               *fr |= bits32[obit - 32];\r
+                               }\r
+                       }\r
+               }\r
+               for (i = 0; i < 128; i++) {\r
+                       *(il = &key_perm_maskl[k][i]) = 0;\r
+                       *(ir = &key_perm_maskr[k][i]) = 0;\r
+                       for (j = 0; j < 7; j++) {\r
+                               inbit = 8 * k + j;\r
+                               if (i & bits8[j + 1]) {\r
+                                       if ((obit = inv_key_perm[inbit]) == 255)\r
+                                               continue;\r
+                                       if (obit < 28)\r
+                                               *il |= bits28[obit];\r
+                                       else\r
+                                               *ir |= bits28[obit - 28];\r
+                               }\r
+                       }\r
+                       *(il = &comp_maskl[k][i]) = 0;\r
+                       *(ir = &comp_maskr[k][i]) = 0;\r
+                       for (j = 0; j < 7; j++) {\r
+                               inbit = 7 * k + j;\r
+                               if (i & bits8[j + 1]) {\r
+                                       if ((obit=inv_comp_perm[inbit]) == 255)\r
+                                               continue;\r
+                                       if (obit < 24)\r
+                                               *il |= bits24[obit];\r
+                                       else\r
+                                               *ir |= bits24[obit - 24];\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       /*\r
+        * Invert the P-box permutation, and convert into OR-masks for\r
+        * handling the output of the S-box arrays setup above.\r
+        */\r
+       for (i = 0; i < 32; i++)\r
+               un_pbox[pbox[i] - 1] = i;\r
+\r
+       for (b = 0; b < 4; b++)\r
+               for (i = 0; i < 256; i++) {\r
+                       *(p = &psbox[b][i]) = 0;\r
+                       for (j = 0; j < 8; j++) {\r
+                               if (i & bits8[j])\r
+                                       *p |= bits32[un_pbox[8 * b + j]];\r
+                       }\r
+               }\r
+\r
+       des_initialised = 1;\r
+}\r
+\r
+static void\r
+setup_salt(int salt)\r
+{\r
+       unsigned int    obit, saltbit;\r
+       int     i;\r
+\r
+       if (salt == old_salt)\r
+               return;\r
+       old_salt = salt;\r
+\r
+       saltbits = 0;\r
+       saltbit = 1;\r
+       obit = 0x800000;\r
+       for (i = 0; i < 24; i++) {\r
+               if (salt & saltbit)\r
+                       saltbits |= obit;\r
+               saltbit <<= 1;\r
+               obit >>= 1;\r
+       }\r
+}\r
+\r
+static int\r
+des_setkey(const unsigned char *key)\r
+{\r
+       unsigned int k0, k1, rawkey0, rawkey1;\r
+       int     shifts, round;\r
+\r
+       if (!des_initialised)\r
+               des_init();\r
+\r
+       rawkey0 = md_ntohl(*(unsigned int *) key);\r
+       rawkey1 = md_ntohl(*(unsigned int *) (key + 4));\r
+\r
+       if ((rawkey0 | rawkey1)\r
+           && rawkey0 == old_rawkey0\r
+           && rawkey1 == old_rawkey1) {\r
+               /*\r
+                * Already setup for this key.\r
+                * This optimisation fails on a zero key (which is weak and\r
+                * has bad parity anyway) in order to simplify the starting\r
+                * conditions.\r
+                */\r
+               return(0);\r
+       }\r
+       old_rawkey0 = rawkey0;\r
+       old_rawkey1 = rawkey1;\r
+\r
+       /*\r
+        *      Do key permutation and split into two 28-bit subkeys.\r
+        */\r
+       k0 = key_perm_maskl[0][rawkey0 >> 25]\r
+          | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f]\r
+          | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f]\r
+          | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f]\r
+          | key_perm_maskl[4][rawkey1 >> 25]\r
+          | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f]\r
+          | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f]\r
+          | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f];\r
+       k1 = key_perm_maskr[0][rawkey0 >> 25]\r
+          | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f]\r
+          | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f]\r
+          | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f]\r
+          | key_perm_maskr[4][rawkey1 >> 25]\r
+          | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f]\r
+          | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f]\r
+          | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f];\r
+       /*\r
+        *      Rotate subkeys and do compression permutation.\r
+        */\r
+       shifts = 0;\r
+       for (round = 0; round < 16; round++) {\r
+               unsigned int    t0, t1;\r
+\r
+               shifts += key_shifts[round];\r
+\r
+               t0 = (k0 << shifts) | (k0 >> (28 - shifts));\r
+               t1 = (k1 << shifts) | (k1 >> (28 - shifts));\r
+\r
+               de_keysl[15 - round] =\r
+               en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f]\r
+                               | comp_maskl[1][(t0 >> 14) & 0x7f]\r
+                               | comp_maskl[2][(t0 >> 7) & 0x7f]\r
+                               | comp_maskl[3][t0 & 0x7f]\r
+                               | comp_maskl[4][(t1 >> 21) & 0x7f]\r
+                               | comp_maskl[5][(t1 >> 14) & 0x7f]\r
+                               | comp_maskl[6][(t1 >> 7) & 0x7f]\r
+                               | comp_maskl[7][t1 & 0x7f];\r
+\r
+               de_keysr[15 - round] =\r
+               en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f]\r
+                               | comp_maskr[1][(t0 >> 14) & 0x7f]\r
+                               | comp_maskr[2][(t0 >> 7) & 0x7f]\r
+                               | comp_maskr[3][t0 & 0x7f]\r
+                               | comp_maskr[4][(t1 >> 21) & 0x7f]\r
+                               | comp_maskr[5][(t1 >> 14) & 0x7f]\r
+                               | comp_maskr[6][(t1 >> 7) & 0x7f]\r
+                               | comp_maskr[7][t1 & 0x7f];\r
+       }\r
+       return(0);\r
+}\r
+\r
+static int\r
+do_des(unsigned int l_in, unsigned int r_in, unsigned int *l_out, \r
+       unsigned int *r_out, int count)\r
+{\r
+       /*\r
+        *      l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format.\r
+        */\r
+       unsigned int    l, r, *kl, *kr, *kl1, *kr1;\r
+       unsigned int    f = 0, r48l, r48r;\r
+       int             round;\r
+\r
+       if (count == 0) {\r
+               return(1);\r
+       } else if (count > 0) {\r
+               /*\r
+                * Encrypting\r
+                */\r
+               kl1 = en_keysl;\r
+               kr1 = en_keysr;\r
+       } else {\r
+               /*\r
+                * Decrypting\r
+                */\r
+               count = -count;\r
+               kl1 = de_keysl;\r
+               kr1 = de_keysr;\r
+       }\r
+\r
+       /*\r
+        *      Do initial permutation (IP).\r
+        */\r
+       l = ip_maskl[0][l_in >> 24]\r
+         | ip_maskl[1][(l_in >> 16) & 0xff]\r
+         | ip_maskl[2][(l_in >> 8) & 0xff]\r
+         | ip_maskl[3][l_in & 0xff]\r
+         | ip_maskl[4][r_in >> 24]\r
+         | ip_maskl[5][(r_in >> 16) & 0xff]\r
+         | ip_maskl[6][(r_in >> 8) & 0xff]\r
+         | ip_maskl[7][r_in & 0xff];\r
+       r = ip_maskr[0][l_in >> 24]\r
+         | ip_maskr[1][(l_in >> 16) & 0xff]\r
+         | ip_maskr[2][(l_in >> 8) & 0xff]\r
+         | ip_maskr[3][l_in & 0xff]\r
+         | ip_maskr[4][r_in >> 24]\r
+         | ip_maskr[5][(r_in >> 16) & 0xff]\r
+         | ip_maskr[6][(r_in >> 8) & 0xff]\r
+         | ip_maskr[7][r_in & 0xff];\r
+\r
+       while (count--) {\r
+               /*\r
+                * Do each round.\r
+                */\r
+               kl = kl1;\r
+               kr = kr1;\r
+               round = 16;\r
+               while (round--) {\r
+                       /*\r
+                        * Expand R to 48 bits (simulate the E-box).\r
+                        */\r
+                       r48l    = ((r & 0x00000001) << 23)\r
+                               | ((r & 0xf8000000) >> 9)\r
+                               | ((r & 0x1f800000) >> 11)\r
+                               | ((r & 0x01f80000) >> 13)\r
+                               | ((r & 0x001f8000) >> 15);\r
+\r
+                       r48r    = ((r & 0x0001f800) << 7)\r
+                               | ((r & 0x00001f80) << 5)\r
+                               | ((r & 0x000001f8) << 3)\r
+                               | ((r & 0x0000001f) << 1)\r
+                               | ((r & 0x80000000) >> 31);\r
+                       /*\r
+                        * Do salting for crypt() and friends, and\r
+                        * XOR with the permuted key.\r
+                        */\r
+                       f = (r48l ^ r48r) & saltbits;\r
+                       r48l ^= f ^ *kl++;\r
+                       r48r ^= f ^ *kr++;\r
+                       /*\r
+                        * Do sbox lookups (which shrink it back to 32 bits)\r
+                        * and do the pbox permutation at the same time.\r
+                        */\r
+                       f = psbox[0][m_sbox[0][r48l >> 12]]\r
+                         | psbox[1][m_sbox[1][r48l & 0xfff]]\r
+                         | psbox[2][m_sbox[2][r48r >> 12]]\r
+                         | psbox[3][m_sbox[3][r48r & 0xfff]];\r
+                       /*\r
+                        * Now that we've permuted things, complete f().\r
+                        */\r
+                       f ^= l;\r
+                       l = r;\r
+                       r = f;\r
+               }\r
+               r = l;\r
+               l = f;\r
+       }\r
+       /*\r
+        * Do final permutation (inverse of IP).\r
+        */\r
+       *l_out  = fp_maskl[0][l >> 24]\r
+               | fp_maskl[1][(l >> 16) & 0xff]\r
+               | fp_maskl[2][(l >> 8) & 0xff]\r
+               | fp_maskl[3][l & 0xff]\r
+               | fp_maskl[4][r >> 24]\r
+               | fp_maskl[5][(r >> 16) & 0xff]\r
+               | fp_maskl[6][(r >> 8) & 0xff]\r
+               | fp_maskl[7][r & 0xff];\r
+       *r_out  = fp_maskr[0][l >> 24]\r
+               | fp_maskr[1][(l >> 16) & 0xff]\r
+               | fp_maskr[2][(l >> 8) & 0xff]\r
+               | fp_maskr[3][l & 0xff]\r
+               | fp_maskr[4][r >> 24]\r
+               | fp_maskr[5][(r >> 16) & 0xff]\r
+               | fp_maskr[6][(r >> 8) & 0xff]\r
+               | fp_maskr[7][r & 0xff];\r
+       return(0);\r
+}\r
+\r
+static int\r
+des_cipher(const unsigned char *in, unsigned char *out, int salt, int count)\r
+{\r
+       unsigned int l_out, r_out, rawl, rawr;\r
+       unsigned int x[2];\r
+       int     retval;\r
+\r
+       if (!des_initialised)\r
+               des_init();\r
+\r
+       setup_salt(salt);\r
+\r
+       memcpy(x, in, sizeof x);\r
+       rawl = md_ntohl(x[0]);\r
+       rawr = md_ntohl(x[1]);\r
+       retval = do_des(rawl, rawr, &l_out, &r_out, count);\r
+\r
+       x[0] = md_htonl(l_out);\r
+       x[1] = md_htonl(r_out);\r
+       memcpy(out, x, sizeof x);\r
+       return(retval);\r
+}\r
+\r
+char *\r
+xcrypt(const char *key, const char *setting)\r
+{\r
+       int             i;\r
+       unsigned int    count, salt, l, r0, r1, keybuf[2];\r
+       unsigned char           *p, *q;\r
+       static unsigned char    output[21];\r
+\r
+       if (!des_initialised)\r
+               des_init();\r
+\r
+       /*\r
+        * Copy the key, shifting each character up by one bit\r
+        * and padding with zeros.\r
+        */\r
+       q = (unsigned char *) keybuf;\r
+       while ((q - (unsigned char *) keybuf) < sizeof(keybuf)) {\r
+               if ((*q++ = *key << 1))\r
+                       key++;\r
+       }\r
+       if (des_setkey((unsigned char *) keybuf))\r
+               return(NULL);\r
+\r
+       if (*setting == _PASSWORD_EFMT1) {\r
+               /*\r
+                * "new"-style:\r
+                *      setting - underscore, 4 bytes of count, 4 bytes of salt\r
+                *      key - unlimited characters\r
+                */\r
+               for (i = 1, count = 0; i < 5; i++)\r
+                       count |= ascii_to_bin(setting[i]) << (i - 1) * 6;\r
+\r
+               for (i = 5, salt = 0; i < 9; i++)\r
+                       salt |= ascii_to_bin(setting[i]) << (i - 5) * 6;\r
+\r
+               while (*key) {\r
+                       /*\r
+                        * Encrypt the key with itself.\r
+                        */\r
+                       if (des_cipher((unsigned char*)keybuf, (unsigned char*)keybuf, 0, 1))\r
+                               return(NULL);\r
+                       /*\r
+                        * And XOR with the next 8 characters of the key.\r
+                        */\r
+                       q = (unsigned char *) keybuf;\r
+                       while (((q - (unsigned char *) keybuf) < sizeof(keybuf)) &&\r
+                                       *key)\r
+                               *q++ ^= *key++ << 1;\r
+\r
+                       if (des_setkey((unsigned char *) keybuf))\r
+                               return(NULL);\r
+               }\r
+               strncpy((char *)output, setting, 9);\r
+\r
+               /*\r
+                * Double check that we weren't given a short setting.\r
+                * If we were, the above code will probably have created\r
+                * wierd values for count and salt, but we don't really care.\r
+                * Just make sure the output string doesn't have an extra\r
+                * NUL in it.\r
+                */\r
+               output[9] = '\0';\r
+               p = output + strlen((const char *)output);\r
+       } else {\r
+               /*\r
+                * "old"-style:\r
+                *      setting - 2 bytes of salt\r
+                *      key - up to 8 characters\r
+                */\r
+               count = 25;\r
+\r
+               salt = (ascii_to_bin(setting[1]) << 6)\r
+                    |  ascii_to_bin(setting[0]);\r
+\r
+               output[0] = setting[0];\r
+               /*\r
+                * If the encrypted password that the salt was extracted from\r
+                * is only 1 character long, the salt will be corrupted.  We\r
+                * need to ensure that the output string doesn't have an extra\r
+                * NUL in it!\r
+                */\r
+               output[1] = setting[1] ? setting[1] : output[0];\r
+\r
+               p = output + 2;\r
+       }\r
+       setup_salt(salt);\r
+       /*\r
+        * Do it.\r
+        */\r
+       if (do_des(0, 0, &r0, &r1, count))\r
+               return(NULL);\r
+       /*\r
+        * Now encode the result...\r
+        */\r
+       l = (r0 >> 8);\r
+       *p++ = ascii64[(l >> 18) & 0x3f];\r
+       *p++ = ascii64[(l >> 12) & 0x3f];\r
+       *p++ = ascii64[(l >> 6) & 0x3f];\r
+       *p++ = ascii64[l & 0x3f];\r
+\r
+       l = (r0 << 16) | ((r1 >> 16) & 0xffff);\r
+       *p++ = ascii64[(l >> 18) & 0x3f];\r
+       *p++ = ascii64[(l >> 12) & 0x3f];\r
+       *p++ = ascii64[(l >> 6) & 0x3f];\r
+       *p++ = ascii64[l & 0x3f];\r
+\r
+       l = r1 << 2;\r
+       *p++ = ascii64[(l >> 12) & 0x3f];\r
+       *p++ = ascii64[(l >> 6) & 0x3f];\r
+       *p++ = ascii64[l & 0x3f];\r
+       *p = 0;\r
+\r
+       return((char *)output);\r
+}\r