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
+          &nbs