changeset 256:c495a4f288c6

Import UltraRogue from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 31 Jan 2017 19:56:04 -0500
parents d9badb9c0179
children c4b12d2d1dcd
files urogue/LICENSE.TXT urogue/Makefile urogue/README urogue/TODO urogue/armor.c urogue/artifact.c urogue/bag.c urogue/chase.c urogue/command.c urogue/daemon.c urogue/daemons.c urogue/dict.c urogue/dict.h urogue/dictutil.c urogue/dictutil.h urogue/encumb.c urogue/fight.c urogue/getplay.c urogue/history.txt urogue/ident.c urogue/init.c urogue/io.c urogue/lint-curses.h urogue/list.c urogue/magic.c urogue/main.c urogue/maze.c urogue/mdport.c urogue/memory.c urogue/misc.c urogue/monsdata.c urogue/monsters.c urogue/move.c urogue/newlvl.c urogue/options.c urogue/pack.c urogue/passages.c urogue/player.c urogue/potions.c urogue/random.c urogue/rings.c urogue/rip.c urogue/rogue.h urogue/rooms.c urogue/save.c urogue/scrolls.c urogue/state.c urogue/status.c urogue/sticks.c urogue/things.c urogue/trader.c urogue/urogue.6 urogue/urogue.sln urogue/urogue.vcproj urogue/verify.c urogue/vers.c urogue/weapons.c urogue/wizard.c urogue/xcrypt.c
diffstat 59 files changed, 42044 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/LICENSE.TXT	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,138 @@
+Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+Portions Copyright (C) 1985 Michael Morgan, Ken Dalka
+Portions Copyright (C) 1981 Michael Toy, Ken Arnold and Glenn Wichman
+Portions Copyright (C) 1993, 1995  Nicholas J. Kisseberth
+All rights reserved.
+
+===========================================================================
+
+UltaRogue: The Ultimate Adventure in the Dungeons of Doom
+Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name(s) of the author(s) nor the names of other contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+4. The name "UltraRogue" and "urogue" must not be used to endorse or 
+   promote products derived from this software without prior written 
+   permission.
+5. Products derived from this software may not be called "UltraRogue" or
+   "urogue", nor may "UltraRogue" or "urogue" appear in their name, 
+   without prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+===========================================================================
+
+Portions of this software are based on the work of Michael Morgan and 
+Ken Dalka. Used under license:
+
+Advanced Rogue
+Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka 
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name(s) of the author(s) nor the names of other contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+===========================================================================
+
+Portions of this software are based on the work of Michael Toy, Ken Arnold
+and Glenn Wichman. Used under license:
+
+Rogue: Exploring the Dungeons of Doom
+Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name(s) of the author(s) nor the names of other contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+===========================================================================
+
+Portions of this software (save/restore game state) are based on the work 
+of Nicholas J. Kisseberth. Used under license:
+
+Copyright (C) 1993, 1995 Nicholas J. Kisseberth
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name(s) of the author(s) nor the names of other contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/Makefile	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,167 @@
+# UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+# Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+# All rights reserved.
+#
+# See the file LICENSE.TXT for full copyright and licensing information.
+
+#
+# Makefile for urogue
+#
+
+DISTNAME=urogue1.0.7
+
+HDRS		  = dict.h dictutil.h rogue.h
+OBJS		  = armor.o \
+		artifact.o \
+		bag.o \
+		chase.o \
+		command.o \
+		daemon.o \
+		daemons.o \
+		dict.o \
+		dictutil.o \
+		encumb.o \
+		fight.o \
+		getplay.o \
+		ident.o \
+		init.o \
+		io.o \
+		list.o \
+		magic.o \
+		main.o \
+		maze.o \
+		memory.o \
+		misc.o \
+		monsdata.o \
+		monsters.o \
+		move.o \
+		newlvl.o \
+		options.o \
+		pack.o \
+		passages.o \
+		player.o \
+		potions.o \
+		random.o \
+		rings.o \
+		rip.o \
+		rooms.o \
+		save.o \
+		scrolls.o \
+		state.o \
+		status.o \
+		sticks.o \
+		things.o \
+		trader.o \
+		verify.o \
+		vers.o \
+		weapons.o \
+		wizard.o
+
+PROGRAM 	  = ur
+
+CFILES		  = armor.c \
+		artifact.c \
+		bag.c \
+		chase.c \
+		command.c \
+		daemon.c \
+		daemons.c \
+		dict.c \
+		dictutil.c \
+		encumb.c \
+		fight.c \
+		getplay.c \
+		ident.c \
+		init.c \
+		io.c \
+		list.c \
+		magic.c \
+		main.c \
+		maze.c \
+		memory.c \
+		misc.c \
+		monsdata.c \
+		monsters.c \
+		move.c \
+		newlvl.c \
+		options.c \
+		pack.c \
+		passages.c \
+		player.c \
+		potions.c \
+		random.c \
+		rings.c \
+		rip.c \
+		rooms.c \
+		save.c \
+		scrolls.c \
+		state.c \
+		status.c \
+		sticks.c \
+		things.c \
+		trader.c \
+		verify.c \
+		vers.c \
+		weapons.c \
+		wizard.c
+
+MISC=           Makefile README LICENSE.TXT history.txt TODO
+
+CC    = gcc
+CFLAGS= -O3
+CRLIB = -lcurses
+RM    = rm -f
+TAR   = tar
+
+urogue:	$(OBJS) $(MAKEFILE)
+	$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(CRLIB) -o $@
+
+clean:		
+	rm -f $(OBJS) urogue a.out core *.map urogue.exe urogue.cat 
+
+dist.src:
+	make clean
+	tar cf $(DISTNAME)-src.tar $(CFILES) $(HDRS) $(MISC)
+	gzip -f $(DISTNAME)-src.tar
+
+dist.irix:
+	make clean
+	make CC=cc CFLAGS="-woff 1116 -O3" urogue
+	nroff -man urogue.6 | colcrt - > urogue.cat
+	tar cf $(DISTNAME)-irix.tar urogue urogue.cat README LICENSE.TXT
+	gzip -f $(DISTNAME)-irix.tar
+
+dist.aix:
+	make clean
+	make CC=xlc CFLAGS="-qmaxmem=16768 -O3 -qstrict" urogue
+	nroff -man urogue.6 | colcrt - > urogue.cat
+	tar cf $(DISTNAME)-aix.tar urogue urogue.cat README LICENSE.TXT
+	gzip -f $(DISTNAME)-aix.tar
+
+dist.linux:
+	make clean
+	make urogue
+	groff -man urogue.6 | sed -e 's/.\x08//g' > urogue.cat
+	tar cf $(DISTNAME)-linux.tar urogue urogue.cat README LICENSE.TXT
+	gzip -f $(DISTNAME)-linux.tar
+
+dist.interix:
+	make clean
+	make urogue
+	groff -P-b -P-u -man -Tascii urogue.6 > urogue.cat
+	tar cf $(DISTNAME)-interix.tar urogue urogue.cat README LICENSE.TXT
+	gzip -f $(DISTNAME)-interix.tar
+
+dist.cygwin:
+	make clean
+	make urogue
+	groff -P-c -man -Tascii urogue.6 | sed -e 's/.\x08//g' > urogue.cat
+	tar cf $(DISTNAME)-cygwin.tar urogue.exe urogue.cat README LICENSE.TXT
+	gzip -f $(DISTNAME)-cygwin.tar
+
+dist.djgpp:
+	make clean
+	make LDFLAGS="-L$(DJDIR)/LIB" CRLIB="-lpdcurses" urogue
+	groff -man -Tascii urogue.6 | sed -e 's/.\x08//g' > urogue.cat
+	rm -f $(DISTNAME)-djgpp.zip
+	zip $(DISTNAME)-djgpp.zip urogue.exe urogue.cat README LICENSE.TXT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/README	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,74 @@
+UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+All rights reserved.
+
+There are 8 different treasures to be picked up in this version of rogue.
+The first is on level 25 and is relatively easy to pick up.  The last is
+on level 100 and is very difficult to get.  Carrying any one of the
+unique treasures allows the rogue to go up the stairs, but one has to
+be very careful.  To be a total winner, yu must pick up all 8 and
+return to the surface again.
+
+(note: the above may be incorrect, i think the number of levels is
+reduced to 50 and you have to get all 8 artifacts to go back up)
+
+The environment variable UROGUE is used to set up the default things
+for a player.  The options that can be set are:
+
+terse:		short output messages
+flush:		flush typeahead when fighting
+jump:		show position only at the end of running
+inven:		inventory style
+askme:		ask about unidentified things
+stopdoor:       stop running when next to something interesting
+name:		the rogue's name (string)
+fruit:		the funny fruit used by the rogue (string)
+file:		default savefile name (string)
+score:		default scorefile name (string)
+class:		default player class (string)
+
+Something like
+
+setenv UROGUE "name=George of the Jungle,fruit=peach,noterse,jump"
+
+does the obvious.  The "score" option is ignored unless you start
+urogue in wizard mode.  The class option string can have the following
+values: "fighter", "illus", "paladin", "ranger", "cleric", "magic",
+"assasin", "druid", "ninja", and "thief" and is initialized only at
+startup time.  The "inven" option can take the values "slow", "clear",
+and "overwrite".
+
+
+About the Author
+================
+
+Herb Chong is currently freelance writing and doing some teaching.
+If you pick up a copy of Windows Sources Magazine, you can usually
+find something he has written. Starting in October (1993) he will
+have a regular column. Herb has also just started teaching Adult Ed
+and undergraduate classes at Mercy College, a small and not very well
+known college in Westchester, NY.
+
+Acknowledgements
+================
+
+The source code for Rogue 3.6 (by Michael Toy, Ken Arnold and Glenn 
+Wichman) was used as the original basis for this game. A thousand 
+thanks go out to them and their classic adventure game of the early 1980s.
+
+Modifications of a long forgotten and bastardized nature were taken
+from Advanced Rogue 1.0 and/or SuperRogue. We believe that the flea market, 
+pools, and maze levels had their origin somewhere around here. 
+
+Chief Architect   : 	Herb Chong
+
+Major Contributers: 	Carlton Hommel	Mike Cooper 	Mike Laman
+			Jason Venner	Nick Kisseberth
+
+Other Contributers: 	Nick Flor	Henry Chai	Pat Place
+			Michael Maudlin	dan@ciprico 	edjames@ucbshadow
+			Web Dove	Tim Haapanen	tecot@cmu-cs-k.arpa
+
+Any omissions or errors are purely unintentional. The above list was
+compiled by Nick Kisseberth from the change log in UltraRogue through
+1987 and from correspondense with Herb Chong.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/TODO	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,23 @@
+UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+Copyright (C) 1993, 1995 Herb Chong
+All rights reserved.
+
+%W% %G%
+
+add_pack() calls ur_free() on the linked list pointer passed
+to it. Need to go through code and look for cases where we
+use that pointer after calling add_pack(). Electric
+fence in guard-free() mode should help.
+
+Similary throw_away(), discard(), discard_pack() free items...
+there will be more like this...
+
+Bug in genocide scroll: don't request list, type letter, etc...
+
+Implement potion of true sight.
+
+Bug: apparently when creating a new familiar after a player level
+change, something isn't begin reset because ur SEGVs when running
+through the monster list in do_chase() right after the new
+familiar is created. It appears that the familiar isn't being removed
+from the monster list.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/armor.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,207 @@
+/*
+    armor.c  -  functions for dealing with armor
+
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include "rogue.h"
+
+/*
+    wear()
+        The player wants to wear something, so let him/her put it on.
+*/
+
+void
+wear(void)
+{
+    struct object *obj;
+
+    if (cur_armor != NULL)
+    {
+        msg("You are already wearing some.");
+
+        after = FALSE;
+
+        return;
+    }
+
+    /* What does player want to wear? */
+
+    if ((obj = get_object(pack, "wear", ARMOR, NULL)) == NULL)
+        return;
+
+    wear_ok(&player, obj, MESSAGE);
+    waste_time();
+
+    cur_armor = obj;
+    obj->o_flags |= ISKNOW;
+
+    msg("You are now wearing %s.", inv_name(obj, TRUE));
+
+    return;
+}
+
+/*
+    take_off()
+        Get the armor off of the players back
+*/
+
+void
+take_off(void)
+{
+    struct object   *obj;
+
+    if ((obj = cur_armor) == NULL)
+    {
+        msg("You aren't wearing armor!");
+        return;
+    }
+
+    if (!dropcheck(cur_armor))
+        return;
+
+    msg("You were wearing %c%c) %s.", ARMOR, print_letters[get_ident(obj)],
+        inv_name(obj, LOWERCASE));
+
+    cur_armor = NULL;
+
+    if (on(player, STUMBLER))
+    {
+        msg("Your foot feels a lot better now.");
+        turn_off(player, STUMBLER);
+    }
+}
+
+/*
+    wear_ok()
+        enforce player class armor restrictions
+*/
+
+int
+wear_ok(struct thing *wearee, struct object *obj, int print_message)
+{
+    int which      = obj->o_which;
+    int ret_val    = TRUE;
+    int class_type = wearee->t_ctype;
+
+    if (obj->o_type != ARMOR)
+        return(FALSE);
+    else
+        switch (class_type)
+        {
+            case C_MAGICIAN: /* cannot wear metal */
+            case C_ILLUSION:
+                switch (which)
+                {
+                    case RING_MAIL:
+                    case SCALE_MAIL:
+                    case PADDED_ARMOR:
+                    case CHAIN_MAIL:
+                    case BRIGANDINE:
+                    case SPLINT_MAIL:
+                    case GOOD_CHAIN:
+                    case PLATE_MAIL:
+                    case PLATE_ARMOR:
+                        ret_val = FALSE;
+                        break;
+                    default:
+                        break;
+                }
+
+            case C_THIEF:    /* cannot clank around */
+            case C_ASSASIN:
+            case C_NINJA:
+                switch (which)
+                {
+                    case CHAIN_MAIL:
+                    case BRIGANDINE:
+                    case SPLINT_MAIL:
+                    case GOOD_CHAIN:
+                    case PLATE_MAIL:
+                    case PLATE_ARMOR:
+                        ret_val = FALSE;
+                        break;
+                    default:
+                        break;
+                }
+
+            case C_CLERIC:   /* cannot wear plate */
+            case C_DRUID:
+                switch (which)
+                {
+                    case PLATE_MAIL:
+                    case PLATE_ARMOR:
+                    case MITHRIL:
+                        ret_val = FALSE;
+                        break;
+                    default:
+                        break;
+                }
+
+            case C_FIGHTER: /* wear anything */
+            case C_RANGER:
+                break;
+
+            case    C_PALADIN:  /* cannot wear common stuff */
+                switch (which)
+                {
+                    case SOFT_LEATHER:
+                    case CUIRBOLILLI:
+                    case HEAVY_LEATHER:
+                    case STUDDED_LEATHER:
+                    case PADDED_ARMOR:
+                    case BRIGANDINE:
+                        ret_val = FALSE;
+                        break;
+                    default:
+                        break;
+                }
+
+            case C_MONSTER:
+                break;
+
+            default:      /* Unknown class */
+                debug("Unknown class %d.", class_type);
+                break;
+        }
+
+    if (ret_val == FALSE && print_message == MESSAGE)
+        switch (class_type)
+        {
+            case C_MAGICIAN:
+            case C_ILLUSION:
+                msg("You cannot regenerate spell points while wearing that!");
+                break;
+
+            case C_THIEF:
+            case C_ASSASIN:
+            case C_NINJA:
+                msg("Don't expect to be stealthy while wearing that!");
+                break;
+
+            case C_CLERIC:
+            case C_DRUID:
+            case C_PALADIN:
+                msg("Your god strongly disapproves of your wearing that!");
+                break;
+
+            case C_FIGHTER:
+            case C_RANGER:
+            case C_MONSTER:
+                break;
+        }
+
+    return(ret_val);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/artifact.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1922 @@
+/*
+    artifact.c  -  functions for dealing with artifacts
+
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <stdlib.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+    apply()
+        apply an artifact
+*/
+
+void
+apply(void)
+{
+    struct linked_list  *item;
+    struct object   *obj;
+    int which;
+    int chance;
+
+    if ((item = get_item("activate", ARTIFACT)) == NULL)
+        return;
+
+    obj = OBJPTR(item);
+    which = obj->o_which;
+
+    if (!(obj->ar_flags & ISACTIVE))
+    {
+        chance = rnd(100) - 10 * rnd(luck);
+        debug("Rolled %d.", chance);
+        if (chance < 5)
+            do_major();
+        else if (chance < 50)
+            do_minor(obj);
+        else
+            obj->ar_flags |= ISACTIVE;
+    }
+
+    if (obj->ar_flags & ISACTIVE)
+    {
+        switch (which)
+        {
+            case TR_PURSE:    do_bag(obj);
+                              break;
+            case TR_PHIAL:    do_phial();
+                              break;
+            case TR_AMULET:   do_amulet();
+                              break;
+            case TR_PALANTIR: do_palantir();
+                              break;
+            case TR_CROWN:    do_crown();
+                              break;
+            case TR_SCEPTRE:  do_sceptre();
+                              break;
+            case TR_SILMARIL: do_silmaril();
+                              break;
+            case TR_WAND:     do_wand();
+                              break;
+            default:          nothing_message(ISCURSED);
+                              return;
+        }
+    }
+
+    if (rnd(pstats.s_lvl) < 6)
+        do_minor(obj);
+
+    turn_on(player, POWEREAT);
+}
+
+/*
+    possessed(int artifact)
+        was the hero carrying a particular artifact
+*/
+
+int
+possessed(int artifact)
+{
+    return (picked_artifact >> artifact) & 1;
+}
+
+/*
+    is_carrying(int artifact)
+        is the hero carrying a particular artifact
+*/
+
+int
+is_carrying(int artifact)
+{
+    return (has_artifact >> artifact) & 1;
+}
+
+/*
+    make_artifact()
+        is it time to make a new artifact?
+*/
+
+int
+make_artifact(void)
+{
+    int i;
+
+    mpos = 0;
+
+    debug("Artifact possession and picked flags : %x %x.",
+        has_artifact, picked_artifact);
+
+    for(i = 0; i < maxartifact; i++)
+    {
+       if (!is_carrying(i) && arts[i].ar_level <= level)
+           return TRUE;
+    }
+
+    return FALSE;
+}
+
+/*
+    new_artifact(int which, struct object *cur)
+        make a specified artifact
+*/
+
+struct object *
+new_artifact(int which, struct object *cur)
+{
+    if (which >= maxartifact)
+    {
+        debug("Bad artifact %d.  Random one created.", which);
+        which = rnd(maxartifact);
+    }
+
+    if (which < 0)
+    {
+        for (which = 0; which < maxartifact; which++)
+            if (!is_carrying(which) && arts[which].ar_level <= level)
+                break;
+    }
+
+    debug("Artifact number: %d.", which);
+
+    cur->o_hplus = cur->o_dplus = 0;
+    cur->o_damage = cur->o_hurldmg = "0d0";
+    cur->o_ac = 11;
+    cur->o_mark[0] = '\0';
+    cur->o_type = ARTIFACT;
+    cur->o_which = which;
+    cur->o_weight = arts[which].ar_weight;
+    cur->o_flags = 0;
+    cur->o_group = 0;
+    cur->o_count = 1;
+    cur->o_bag = NULL;
+    cur->ar_flags = 0;
+
+    return(cur);
+}
+
+/*
+    do_minor(struct object *tr)
+        side effects and minor malevolent effects of artifacts
+*/
+
+void
+do_minor(struct object *tr)
+{
+    int which;
+    long loss;
+
+    which = rnd(110);
+
+    debug("Rolled %d.", which);
+
+    switch (which)
+    {
+        case 0:
+            seemsg("You develop some acne on your face.");
+            break;
+
+        case 1:
+            if (on(player, CANSCENT))
+            {
+                msg("A sudden whiff of BO causes you to faint.");
+                no_command = STONETIME;
+            }
+            else if (off(player, ISUNSMELL))
+                msg("You begin to smell funny.");
+            break;
+
+        case 2:
+            seemsg("A wart grows on the end of your nose.");
+            break;
+
+        case 3:
+            hearmsg("Your hear strange noises in the distance.");
+            break;
+
+        case 4:
+            hearmsg("You hear shuffling in the distance.");
+            break;
+
+        case 5:
+            hearmsg("You hear clanking in the distance.");
+            break;
+
+        case 6:
+            hearmsg("You hear water dripping onto the floor.");
+            break;
+
+        case 7:
+            hearmsg("The dungeon goes strangely silent.");
+            break;
+
+        case 8:
+            msg("You suddenly feel very warm.");
+            break;
+
+        case 9:
+            msg("You feel very hot.");
+            break;
+
+        case 10:
+            msg("A blast of heat hits you.");
+            break;
+
+        case 11:
+            {
+                 struct room *rp;
+
+                 if (off(player, ISBLIND))
+                    msg("A pillar of flame leaps up beside you.");
+                 else
+                    msg("You feel something very hot nearby.");
+
+                 if (ntraps + 1 < 2 * MAXTRAPS &&
+                     fallpos(hero, &traps[ntraps].tr_pos))
+                 {
+                    mvaddch(traps[ntraps].tr_pos.y, traps[ntraps].tr_pos.x,
+                       FIRETRAP);
+                    traps[ntraps].tr_type = FIRETRAP;
+                    traps[ntraps].tr_flags = ISFOUND;
+                    traps[ntraps].tr_show = FIRETRAP;
+                    ntraps++;
+
+                    if ((rp = roomin(hero)) != NULL)
+                    {
+                        rp->r_flags &= ~ISDARK;
+                        light(&hero);
+                        mvwaddch(cw, hero.y, hero.x, PLAYER);
+                    }
+                }
+            }
+            break;
+
+        case 12:
+            msg("You feel a blast of hot air.");
+            break;
+
+        case 13:
+            msg("You feel very cold.");
+            break;
+
+        case 14:
+            msg("You break out in a cold sweat.");
+            break;
+
+        case 15:
+            if (off(player, ISBLIND) && cur_armor == NULL)
+                msg("You are covered with frost.");
+            else if (off(player, ISBLIND))
+                msg("Your armor is covered with frost.");
+            else if (cur_armor == NULL)
+                msg("Your body feels very cold and you begin to shiver.");
+            else
+                msg("Your armor feels very cold.  You hear cracking ice.");
+            break;
+
+        case 16:
+            msg("A cold wind whistles through the dungeon.");
+            break;
+
+        case 17:
+            {
+                int change;
+
+                change = 18 - pstats.s_str;
+                chg_str(change, TRUE, FALSE);
+                chg_dext(-change, TRUE, FALSE);
+
+                if (change > 0)
+                    msg("You feel stronger and clumsier now.");
+                else if (change < 0)
+                    msg("You feel weaker and more dextrous now.");
+                else
+                    nothing_message(ISCURSED);
+            }
+            break;
+
+        case 18:
+            msg("You begin to itch all over.");
+            break;
+
+        case 19:
+            msg("You begin to feel hot and itchy.");
+            break;
+
+        case 20:
+            msg("You feel a burning itch.");
+            chg_dext(-1, FALSE, TRUE);
+
+            if (off(player, HASITCH))
+            {
+                turn_on(player, HASITCH);
+                light_fuse(FUSE_UNITCH, 0, roll(4,6), AFTER);
+            }
+            else
+                lengthen_fuse(FUSE_UNITCH, roll(4,6));
+            break;
+
+        case 21:
+            if (off(player, ISBLIND))
+               msg("Your skin begins to flake and peel.");
+            else
+               msg("You feel an urge to scratch an itch.");
+            break;
+
+
+        case 22:
+            seemsg("Your hair begins to turn grey.");
+            break;
+
+        case 23:
+            seemsg("Your hair begins to turn white.");
+            break;
+
+        case 24:
+            seemsg("Some of your hair instantly turns white.");
+            break;
+
+        case 25:
+            seemsg("You are covered with long white hair.");
+            break;
+
+        case 26:
+            seemsg("You are covered with long red hair.");
+            break;
+
+        case 27:
+            msg("You grow a beard.");
+            break;
+
+        case 28:
+            msg("Your hair falls out.");
+            break;
+
+        case 29:
+            msg("You feel a burning down below.");
+            break;
+
+        case 30:
+            msg("Your toes fall off.");
+            break;
+
+        case 31:
+            msg("You grow some extra toes.");
+            break;
+
+        case 32:
+            msg("You grow some extra fingers.");
+            break;
+
+        case 33:
+            msg("You grow an extra thumb.");
+            break;
+
+        case 34:
+            msg("Your nose falls off.");
+            break;
+
+        case 35:
+            msg("Your nose gets bigger.");
+            break;
+
+        case 36:
+            msg("Your nose shrinks.");
+            break;
+
+        case 37:
+            msg("An eye grows on your forehead.");
+            break;
+
+        case 38:
+            seemsg("You see beady eyes watching from a distance.");
+            break;
+
+        case 39:
+            msg("The dungeon rumbles for a moment.");
+            break;
+
+        case 40:
+            seemsg("A flower grows on the floor next to you.");
+            break;
+
+        case 41:
+            msg("You are stunned by a psionic blast.");
+
+            if (on(player, ISHUH))
+                lengthen_fuse(FUSE_UNCONFUSE, rnd(40) + (HUHDURATION * 3));
+            else
+            {
+                light_fuse(FUSE_UNCONFUSE,0,rnd(40)+(HUHDURATION * 3), AFTER);
+                turn_on(player, ISHUH);
+            }
+            break;
+
+        case 42:
+            msg("You are confused by thousands of voices in your head.");
+
+            if (on(player, ISHUH))
+                lengthen_fuse(FUSE_UNCONFUSE, rnd(10) + (HUHDURATION * 2));
+            else
+            {
+                light_fuse(FUSE_UNCONFUSE,0,rnd(10)+(HUHDURATION * 2), AFTER);
+                turn_on(player, ISHUH);
+            }
+            break;
+
+        case 43:
+            hearmsg("You hear voices in the distance.");
+            break;
+
+        case 44:
+            msg("You feel a strange pull.");
+            teleport();
+
+            if (off(player, ISCLEAR))
+            {
+                if (on(player, ISHUH))
+                    lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION);
+                else
+                {
+                    light_fuse(FUSE_UNCONFUSE, 0, rnd(8) + HUHDURATION, AFTER);
+                    turn_on(player, ISHUH);
+                }
+            }
+            break;
+
+        case 45:
+            msg("You feel less healthy now.");
+            pstats.s_const = max(pstats.s_const - 1, 3);
+            max_stats.s_const = max(max_stats.s_const - 1, 3);
+            break;
+
+        case 46:
+            msg("You feel weaker now.");
+            chg_str(-1, TRUE, FALSE);
+            break;
+
+        case 47:
+            msg("You feel less wise now.");
+            pstats.s_wisdom = max(pstats.s_wisdom - 1, 3);
+            max_stats.s_wisdom = max(max_stats.s_wisdom - 1, 3);
+            break;
+
+        case 48:
+            msg("You feel less dextrous now.");
+            chg_dext(-1, TRUE, FALSE);
+            break;
+
+        case 49:
+            msg("You feel less intelligent now.");
+            pstats.s_intel = max(pstats.s_intel - 1, 3);
+            max_stats.s_intel = max(max_stats.s_intel - 1, 3);
+            break;
+
+        case 50:
+            msg("A trap door opens underneath your feet.");
+            mpos = 0;
+            level++;
+            new_level(NORMLEV,0);
+
+            if (rnd(4) < 2)
+            {
+                addmsg("You are damaged by the fall");
+
+                if ((pstats.s_hpt -= roll(1, 6)) <= 0)
+                {
+                    addmsg("!  The fall killed you.");
+                    endmsg();
+                    death(D_FALL);
+                    return;
+                }
+            }
+
+            addmsg("!");
+            endmsg();
+
+            if (off(player, ISCLEAR) && rnd(4) < 3)
+            {
+                if (on(player, ISHUH))
+                    lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION);
+                else
+                    light_fuse(FUSE_UNCONFUSE, 0, rnd(8) + HUHDURATION, AFTER);
+
+                turn_on(player, ISHUH);
+            }
+            else
+                msg("You feel dizzy for a moment, but it quickly passes.");
+
+            break;
+
+        case 51:
+            msg("A maze entrance opens underneath your feet.");
+            mpos = 0;
+            level++;
+            new_level(MAZELEV,0);
+
+            if (rnd(4) < 2)
+            {
+                addmsg("You are damaged by the fall");
+
+                if ((pstats.s_hpt -= roll(1, 6)) <= 0)
+                {
+                    addmsg("!  The fall killed you.");
+                    endmsg();
+                    death(D_FALL);
+                    return;
+                }
+            }
+            addmsg("!");
+            endmsg();
+
+            if (off(player, ISCLEAR) && rnd(4) < 3)
+            {
+                if (on(player, ISHUH))
+                    lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION);
+                else
+                    light_fuse(FUSE_UNCONFUSE,0, rnd(8) + HUHDURATION, AFTER);
+
+                turn_on(player, ISHUH);
+            }
+            else
+                msg("You feel dizzy for a moment, but it quickly passes.");
+
+            break;
+
+        case 52:
+            hearmsg("You hear a wailing sound in the distance.");
+            aggravate();
+            break;
+
+        case 53:
+            read_scroll(&player, S_HOLD, ISCURSED);
+            break;
+
+        case 54:
+            msg("You can't move.");
+            no_command = 3 * HOLDTIME;
+            break;
+
+        case 55:
+            hearmsg("You hear a buzzing sound.");
+            aggravate();
+            break;
+
+        case 56:
+            msg("Your limbs stiffen.");
+            no_command = 3 * STONETIME;
+            break;
+
+        case 57:
+            msg("You feel a rock in your shoe hurting your foot.");
+            turn_on(player, STUMBLER);
+            break;
+
+        case 58:
+            msg("You get a hollow feeling in your stomach.");
+            food_left -= 500;
+            break;
+
+        case 59:
+            msg("Your purse feels lighter.");
+
+            loss  = 50L + ulrnd(purse / 2L);
+            purse = (purse > loss) ? purse - loss : 0L;
+            break;
+
+        case 60:
+            msg("A pixie appears and grabs gold from your purse.");
+
+            loss = 50L + rnd(50);
+            purse = (purse > loss) ? purse - loss : 0L;
+            break;
+
+        case 61:
+            msg("You feel a tingling sensation all over.");
+            pstats.s_hpt -= ulrnd(pstats.s_hpt / 3L);
+            break;
+
+        case 62:
+            msg("You feel a pull downwards.");
+            break;
+
+        case 63:
+            msg("You feel a strange pull downwards.");
+            break;
+
+        case 64:
+            msg("You feel a peculiar pull downwards.");
+            break;
+
+        case 65:
+            msg("You have a strange urge to go down.");
+            break;
+
+        case 66:
+            msg("You feel a pull upwards.");
+            break;
+
+        case 67:
+            msg("You feel a strange pull upwards.");
+            break;
+
+        case 68:
+            msg("You have a strange feeling for a moment.");
+            break;
+
+        case 69:
+            msg("You float in the air for a moment.");
+            break;
+
+        case 70:
+            msg("You feel very heavy for a moment.");
+            break;
+
+        case 71:
+            msg("You feel a strange sense of loss.");
+            break;
+
+        case 72:
+            msg("You feel the earth spinning underneath your feet.");
+            break;
+
+        case 73:
+            msg("You feel in touch with a Universal Oneness.");
+            break;
+
+        case 74:
+            hearmsg("You hear voices in the distance.");
+            break;
+
+        case 75:
+            msg("A strange feeling of power comes over you.");
+            break;
+
+        case 76:
+            msg("You feel a strange sense of unease.");
+            break;
+
+        case 77:
+            msg("You feel Lady Luck is looking the other way.");
+            luck++;
+            break;
+
+        case 78:
+            msg("You feel your pack vibrate for a moment.");
+            break;
+
+        case 79:
+            msg("You feel someone is watching you.");
+            break;
+
+        case 80:
+            msg("You feel your hair standing on end.");
+            break;
+
+        case 81:
+            msg("Wait!  The walls are moving!");
+            new_level(NORMLEV,0);
+            break;
+
+        case 82:
+            msg("Wait!  Walls are appearing out of nowhere!");
+            new_level(MAZELEV,0);
+            break;
+
+        case 83:
+            blue_light(ISCURSED);
+            break;
+
+        case 84:
+            msg("Your mind goes blank for a moment.");
+            wclear(cw);
+            light(&hero);
+            status(TRUE);
+            break;
+
+        case 85:
+            if (on(player, ISDEAF))
+            {
+                msg("You feel your ears burn for a moment.");
+                lengthen_fuse(FUSE_HEAR, 2 * PHASEDURATION);
+            }
+            else
+            {
+                msg("You are suddenly surrounded by silence.");
+                turn_on(player, ISDEAF);
+                light_fuse(FUSE_HEAR, 0, 2 * PHASEDURATION, AFTER);
+            }
+            break;
+
+        case 86:
+            {
+                apply_to_bag(pack, 0, NULL, baf_curse, NULL);
+
+                if (off(player, ISUNSMELL))
+                    msg("You smell a faint trace of burning sulfur.");
+            }
+            break;
+
+        case 87:
+            msg("You have contracted a parasitic infestation.");
+            infest_dam++;
+            turn_on(player, HASINFEST);
+            break;
+
+        case 88:
+            msg("You suddenly feel a chill run up and down your spine.");
+            turn_on(player, ISFLEE);
+            player.t_ischasing = FALSE;
+            player.t_chasee = &player;
+            break;
+
+        case 89:
+            if (cur_weapon != NULL)
+                msg("You feel your %s get very hot.",
+                    inv_name(cur_weapon, LOWERCASE));
+            break;
+
+        case 90:
+            if (cur_weapon != NULL)
+                msg("Your %s glows white for an instant.",
+                    inv_name(cur_weapon, LOWERCASE));
+            break;
+
+        case 91:
+            if (cur_armor != NULL)
+                msg("Your %s gets very hot.", inv_name(cur_armor, LOWERCASE));
+            break;
+
+        case 92:
+            if (cur_weapon != NULL)
+                msg("Your %s suddenly feels very cold.",
+                    inv_name(cur_weapon, LOWERCASE));
+            break;
+
+        case 93:
+            if (cur_armor != NULL)
+                msg("Your armor is covered by an oily film.");
+            break;
+
+        case 94:
+            read_scroll(&player, S_CREATE, ISNORMAL);
+            break;
+
+        case 95:
+            lower_level(D_POTION);
+            break;
+
+        case 96:
+            {
+                int x, y;
+
+                for (x = -1; x <= 1; x++)
+                {
+                    for (y = -1; y <= 1; y++)
+                    {
+                        if (x == 0 && y == 0)
+                            continue;
+
+                        delta.x = x;
+                        delta.y = y;
+
+                        do_zap(&player, WS_POLYMORPH, rnd(2)
+                            ? ISCURSED : ISNORMAL);
+                    }
+                }
+            }
+            break;
+
+        case 97:
+            {
+                int x, y;
+
+                for (x = -1; x <= 1; x++)
+                {
+                    for (y = -1; y <= 1; y++)
+                    {
+                        if (x == 0 && y == 0)
+                            continue;
+
+                        delta.x = x;
+                        delta.y = y;
+
+                        do_zap(&player, WS_INVIS, ISNORMAL);
+                    }
+                }
+            }
+            break;
+
+        default:
+            tr->ar_flags &= ~ISACTIVE;
+            hearmsg("You hear a click coming from %s.",inv_name(tr,LOWERCASE));
+            break;
+
+    }
+}
+
+/*
+    do_major()
+
+        major malevolent effects
+
+        0.  read_scroll(S_SELFTELEPORT, ISCURSED)
+        1.  PERMBLIND for twice normal duration
+        2.  new_level(THRONE);
+        3.  turn_on(player, SUPEREAT);
+        4.  lengthen(noslow, 20 + rnd(20));
+        5.  lower_level(D_POTION) * roll(1,4)
+        6.  change stats
+        7.  FIRETRAP
+        8.  armor crumbles
+        9.  weapon crumbles
+       10. weapon crumbles
+       11. curse weapon
+*/
+
+void
+do_major(void)
+{
+    int which;
+
+    which = rnd(12);
+
+    debug("Rolled %d.", which);
+
+    switch (which)
+    {
+        case 0:
+            read_scroll(&player, S_SELFTELEP, ISCURSED);
+            break;
+
+        case 1:
+            quaff(&player, P_TRUESEE, ISCURSED);
+            quaff(&player, P_TRUESEE, ISCURSED);
+            break;
+
+        case 2:
+            new_level(THRONE,0);
+            break;
+
+        case 3: /* Turn off other body-affecting spells */
+
+            if (on(player, ISREGEN))
+            {
+                extinguish_fuse(FUSE_UNREGEN);
+                turn_off(player, ISREGEN);
+                unregen(NULL);
+            }
+
+            if (on(player, NOCOLD))
+            {
+                extinguish_fuse(FUSE_UNCOLD);
+                turn_off(player, NOCOLD);
+                uncold(NULL);
+            }
+
+            if (on(player, NOFIRE))
+            {
+                extinguish_fuse(FUSE_UNHOT);
+                turn_off(player, NOFIRE);
+                unhot(NULL);
+            }
+
+            if (on(player, SUPEREAT))
+            {
+                lengthen_fuse(FUSE_UNSUPEREAT, 2 * PHASEDURATION);
+                msg("Your body temperature rises still further.");
+            }
+            else
+            {
+                msg("You feel very warm all over.");
+                light_fuse(FUSE_UNSUPEREAT, 0, 2 * PHASEDURATION, AFTER);
+                turn_on(player, SUPEREAT);
+            }
+            break;
+
+        case 4:
+            msg("You feel yourself moving %sslower.",
+            on(player, ISSLOW) ? "even " : "");
+
+            if (on(player, ISSLOW))
+                lengthen_fuse(FUSE_NOSLOW, PHASEDURATION);
+            else
+            {
+                turn_on(player, ISSLOW);
+                player.t_turn = TRUE;
+                light_fuse(FUSE_NOSLOW, 0, PHASEDURATION, AFTER);
+            }
+            break;
+
+        case 5:
+            {
+                int i, n = roll(1, 4);
+
+                for (i = 1; i < n; i++)
+                    lower_level(D_POTION);
+            }
+            break;
+
+        case 6:
+            if (rnd(2))
+                add_intelligence(TRUE);
+
+            if (rnd(2))
+                chg_dext(-1, TRUE, FALSE);
+
+            if (rnd(2))
+                chg_str(-1, TRUE, FALSE);
+
+            if (rnd(2))
+                add_wisdom(TRUE);
+
+            if (rnd(2))
+                add_const(TRUE);
+
+            break;
+
+        case 7:
+            {
+                struct room *rp;
+
+                if (ntraps + 1 >= MAXTRAPS)
+                {
+                    msg("You feel a puff of hot air.");
+                    return;
+                }
+
+                for (; ntraps < 2 * MAXTRAPS; ntraps++)
+                {
+                    if (!fallpos(hero, &traps[ntraps].tr_pos))
+                        break;
+
+                    mvaddch(traps[ntraps].tr_pos.y, traps[ntraps].tr_pos.x,
+                        FIRETRAP);
+                    traps[ntraps].tr_type   = FIRETRAP;
+                    traps[ntraps].tr_flags |= ISFOUND;
+                    traps[ntraps].tr_show   = FIRETRAP;
+
+                    if ((rp = roomin(hero)) != NULL)
+                        rp->r_flags &= ~ISDARK;
+                }
+            }
+            break;
+
+        case 8:
+            {
+                object  *obj;
+
+                if (cur_weapon == NULL)
+                {
+                    msg("You feel your hands tingle a moment.");
+                    pstats.s_dmg = "1d2";
+                    return;
+                }
+
+                obj = apply_to_bag(pack, 0, NULL, bafcweapon, NULL);
+
+                if (obj->o_flags & ISMETAL)
+                    msg("Your %s melts and disappears.",
+                        inv_name(obj,LOWERCASE));
+                else
+                    msg("Your %s crumbles in your hands.",
+                        inv_name(obj, LOWERCASE));
+
+                obj->o_flags &= ~ISCURSED;
+                dropcheck(obj);
+                del_bag(pack, obj);
+
+            }
+            break;
+
+        case 9:
+            {
+                object  *obj;
+
+                if (cur_armor == NULL)
+                {
+                    msg("Your body tingles a moment.");
+                    return;
+                }
+
+                obj = apply_to_bag(pack, 0, NULL, bafcarmor, NULL);
+
+                msg("Your %s crumbles into small black powdery dust.",
+                    inv_name(obj, LOWERCASE));
+
+                obj->o_flags &= ~ISCURSED;
+                dropcheck(obj);
+                del_bag(pack, obj);
+            }
+            break;
+
+        default:
+
+            if (cur_weapon == NULL)
+            {
+                seemsg("Your hand glows yellow for an instant.");
+                pstats.s_dmg = "1d3";
+                return;
+            }
+
+            seemsg("Your %s glows bright red for a moment.",
+                   weaps[cur_weapon->o_which].w_name);
+
+            if (cur_weapon->o_hplus > 0)
+                cur_weapon->o_hplus = -rnd(3);
+            else
+                cur_weapon->o_hplus -= rnd(3);
+
+            if (cur_weapon->o_dplus > 0)
+                cur_weapon->o_dplus = -rnd(3);
+            else
+                cur_weapon->o_dplus -= rnd(3);
+
+            cur_weapon->o_flags = ISCURSED | ISLOST;
+            cur_weapon->o_ac = 0;
+
+            break;
+    }
+}
+
+/*
+    do_phial()
+        handle powers of the Phial of Galadriel
+*/
+
+void
+do_phial(void)
+{
+    int which;
+
+    /* Prompt for action */
+
+    msg("How do you wish to apply the Phial of Galadriel (* for list)? ");
+
+    which = (short) ((readchar() & 0177) - 'a');
+
+    if (which == (short) ESCAPE - (short) 'a')
+    {
+        after = FALSE;
+        return;
+    }
+
+    if (which < 0 || which > 1)
+    {
+        add_line("[a] total healing");
+        add_line("[b] total monster confusion");
+        end_line();
+        msg("");
+        msg("Which power do you wish to use? ");
+
+        which = (short) ((readchar() & 0177) - 'a');
+
+        while (which < 0 || which > 1)
+        {
+            if (which == (short) ESCAPE - (short) 'a')
+            {
+                after = FALSE;
+                return;
+            }
+
+            msg("");
+            msg("Please enter one of the listed powers: ");
+
+            which = (short) ((readchar() & 0177) - 'a');
+        }
+        msg("Your attempt is successful.");
+    }
+    else
+        msg("Your attempt is successsful.");
+
+    switch (which)
+    {
+        case 0:
+            pstats.s_hpt = max_stats.s_hpt += rnd(pstats.s_lvl) + 1;
+            pstats.s_power = max_stats.s_power += rnd(pstats.s_lvl) + 1;
+            break;
+
+        case 1:
+            {
+                struct linked_list  *mi;
+                struct thing    *tp;
+
+                for (mi = mlist; mi != NULL; mi = next(mi))
+                {
+                    tp = THINGPTR(mi);
+
+                    if (off(*tp, ISUNIQUE) || !save_throw(VS_MAGIC, tp))
+                        turn_on(*tp, ISHUH);
+                }
+            }
+            break;
+
+        default:
+            msg("What a strange thing to do!!");
+            break;
+
+    }
+}
+
+/*
+    do_palantir()
+        handle powers of the Palantir of Might
+*/
+
+void
+do_palantir(void)
+{
+    int which, limit;
+
+    /* Prompt for action */
+
+    msg("How do you wish to apply the Palantir of Might? (* for list): ");
+
+    limit = 3;
+
+    if (is_carrying(TR_SCEPTRE))
+        limit += 1;
+
+    if (is_carrying(TR_CROWN))
+        limit += 1;
+
+    which = (short) ((readchar() & 0177) - 'a');
+
+    if (which == (short) ESCAPE - (short) 'a')
+    {
+        after = FALSE;
+        return;
+    }
+
+    if (which < 0 || which > limit)
+    {
+        msg("");
+        add_line("[a] monster detection");
+        add_line("[b] gold detection");
+        add_line("[c] magic detection");
+        add_line("[d] food detection");
+
+        if (limit >= 4)
+            add_line("[e] teleportation");
+
+        if (limit >= 5)
+            add_line("[f] clear thought");
+
+        end_line();
+
+        msg("Which power do you wish to use?");
+
+        which = (short) ((readchar() & 0177) - 'a');
+
+        while (which < 0 || which > limit)
+        {
+            if (which == (short) ESCAPE - (short) 'a')
+            {
+                after = FALSE;
+                return;
+            }
+
+            msg("Please enter one of the listed powers: ");
+            which = (short) ((readchar() & 0177) - 'a');
+        }
+
+        msg("Your attempt is successful.");
+    }
+    else
+        msg("Your attempt is successful.");
+
+    switch (which)
+    {
+        case 0: quaff(&player, P_MONSTDET, ISNORMAL);
+                break;
+        case 1: read_scroll(&player, S_GFIND, ISNORMAL);
+                break;
+        case 2: quaff(&player, P_TREASDET, ISNORMAL);
+                break;
+        case 3: read_scroll(&player, S_FOODDET, ISNORMAL);
+                break;
+        case 4: read_scroll(&player, S_SELFTELEP, ISNORMAL);
+                break;
+        case 5: quaff(&player, P_CLEAR, ISNORMAL);
+                break;
+        default:
+                msg("What a strange thing to do!!");
+                break;
+    }
+}
+
+/*
+    do_silmaril()
+        handle powers of the Silamril of Ea
+*/
+
+void
+do_silmaril(void)
+{
+    int which;
+
+    /* Prompt for action */
+    msg("How do you wish to apply the Silamril of Ea (* for list)? ");
+
+    which = (short) ((readchar() & 0177) - 'a');
+
+    if (which == (short) ESCAPE - (short) 'a')
+    {
+        after = FALSE;
+        return;
+    }
+
+    if (which < 0 || which > 2)
+    {
+        msg("");
+        add_line("[a] magic mapping");
+        add_line("[b] petrification");
+        add_line("[c] stairwell downwards");
+        end_line();
+
+        msg("Which power do you wish to use?");
+
+        which = (short) ((readchar() & 0177) - 'a');
+
+        while (which < 0 || which > 2)
+        {
+            if (which == (short) ESCAPE - (short) 'a')
+            {
+                after = FALSE;
+                return;
+            }
+            msg("");
+            msg("Please enter one of the listed powers: ");
+            which = (short) ((readchar() & 0177) - 'a');
+        }
+        msg("Your attempt is successful.");
+    }
+    else
+        msg("Your attempt is successful.");
+
+    switch (which)
+    {
+        case 0: read_scroll(&player, S_MAP, ISNORMAL);
+                break;
+        case 1: read_scroll(&player, S_PETRIFY, ISNORMAL);
+                break;
+        case 2: msg("A stairwell opens beneath your feet and you go down.");
+                level++;
+                new_level(NORMLEV,0);
+                break;
+        default:msg("What a strange thing to do!!");
+                break;
+    }
+}
+
+/*
+    do_amulet()
+        handle powers of the Amulet of Yendor
+*/
+
+void
+do_amulet(void)
+{
+    int which, limit;
+
+    /* Prompt for action */
+    msg("How do you wish to apply the Amulet of Yendor (* for list)? ");
+
+    limit = 0;
+
+    if (is_carrying(TR_PURSE))
+        limit += 1;
+
+    which = (short) ((readchar() & 0177) - 'a');
+
+    if (which == (short) ESCAPE - (short) 'a')
+    {
+        after = FALSE;
+        return;
+    }
+
+    if (which < 0 || which > limit)
+    {
+        msg("");
+        add_line("[a] level evaluation");
+
+        if (limit >= 1)
+            add_line("[b] invisibility");
+
+        end_line();
+        msg("Which power do you wish to use?");
+
+        which = (short) ((readchar() & 0177) - 'a');
+
+        while (which < 0 || which > limit)
+        {
+            if (which == (short) ESCAPE - (short) 'a')
+            {
+                after = FALSE;
+                return;
+            }
+
+            msg("");
+            msg("Please enter one of the listed powers: ");
+            which = (short) ((readchar() & 0177) - 'a');
+        }
+
+        msg("Your attempt is successful.");
+    }
+    else
+        msg("Your attempt is successful.");
+
+    switch (which)
+    {
+        case 0: level_eval();
+                break;
+        case 1: quaff(&player, P_INVIS, ISNORMAL);
+                break;
+        default:msg("What a strange thing to do!!");
+                break;
+    }
+}
+
+/*
+    do_bag()
+        handle powers of the Magic Purse of Yendor as a bag of holding
+*/
+
+void
+do_bag(struct object *obj)
+{
+    int which, limit;
+
+    /* Prompt for action */
+    msg("How do you wish to apply the Magic Purse of Yendor (* for list)? ");
+
+    which = (short) ((readchar() & 0177) - 'a');
+
+    if (which == (short) ESCAPE - (short) 'a')
+    {
+        after = FALSE;
+        return;
+    }
+
+    limit = 2;
+
+    if (is_carrying(TR_AMULET))
+        limit += 1;
+
+    if (which < 0 || which > limit)
+    {
+        msg("");
+        add_line("[a] inventory");
+        add_line("[b] add to bag");
+        add_line("[c] remove from bag");
+
+        if (limit >= 3)
+            add_line("[d] see invisible");
+
+        end_line();
+
+        msg("Which power do you wish to use?");
+
+        which = (short) ((readchar() & 0177) - 'a');
+
+        while (which < 0 || which > limit)
+        {
+            if (which == (short) ESCAPE - (short) 'a')
+            {
+                after = FALSE;
+                return;
+            }
+
+            msg("");
+            msg("Please enter one of the listed powers: ");
+            which = (short) ((readchar() & 0177) - 'a');
+        }
+
+        msg("Your attempt is successful.");
+    }
+    else
+        msg("Your attempt is successful.");
+
+    switch (which)
+    {
+        case 0:
+            inventory(obj->o_bag, 0);
+            break;
+
+        case 1:
+            {
+                object  *new_obj_p; /* what the user selected */
+
+                if ((new_obj_p = get_object(pack, "add", 0, NULL)) != NULL)
+                {
+                    rem_pack(new_obj_p);    /* free up pack slot */
+                    push_bag(&obj->o_bag, new_obj_p);
+                    pack_report(new_obj_p, MESSAGE, "You just added ");
+                }
+            }
+            break;
+
+        case 2:
+            {
+                object  *obj_p;
+                linked_list *item_p;
+
+                if ((obj_p=get_object(obj->o_bag,"remove",0,NULL)) != NULL)
+                {
+                    item_p = make_item(obj_p);  /* attach upper structure */
+
+                    if (add_pack(item_p, MESSAGE) != FALSE)
+                        pop_bag(&obj->o_bag, obj_p);
+                }
+            }
+            break;
+
+        case 3:
+            quaff(&player, P_TRUESEE, ISBLESSED);
+            break;
+
+        default:
+            msg("What a strange thing to do!!");
+    }
+}
+
+/*
+    do_sceptre()
+        handle powers of the Sceptre of Might
+*/
+
+void
+do_sceptre(void)
+{
+    int which, limit;
+
+    /* Prompt for action */
+    msg("How do you wish to apply the Sceptre of Might (* for list)? ");
+
+    which = (short) ((readchar() & 0177) - 'a');
+
+    if (which == (short) ESCAPE - (short) 'a')
+    {
+        after = FALSE;
+        return;
+    }
+
+    limit = 5;
+
+    if (is_carrying(TR_CROWN))
+        limit += 1;
+
+    if (is_carrying(TR_PALANTIR))
+        limit += 1;
+
+    if (which < 0 || which > limit)
+    {
+        msg("");
+        add_line("[a] cancellation");
+        add_line("[b] polymorph monster");
+        add_line("[c] slow monster");
+        add_line("[d] teleport monster");
+        add_line("[e] monster confusion");
+        add_line("[f] paralyze monster");
+
+        if (limit >= 6)
+            add_line("[g] drain life");
+
+        if (limit >= 7)
+            add_line("[h] smell monster");
+
+        end_line();
+
+        msg("Which power do you wish to use?");
+
+        which = (short) ((readchar() & 0177) - 'a');
+
+        while (which < 0 || which > limit)
+        {
+            if (which == (short) ESCAPE - (short) 'a')
+            {
+                after = FALSE;
+                return;
+            }
+
+            msg("");
+            msg("Please enter one of the listed powers: ");
+            which = (short) ((readchar() & 0177) - 'a');
+        }
+
+        msg("Your attempt is successful.");
+    }
+    else
+        msg("Your attempt is successful.");
+
+    if (rnd(pstats.s_lvl) < 7)
+    {
+        msg("Your finger slips.");
+        which = rnd(6);
+        if (wizard)
+        {
+            msg("What wand? (%d)", which);
+
+            if (get_string(prbuf, cw) == NORM)
+            {
+                which = atoi(prbuf);
+                if (which < 0 || which > 5)
+                {
+                    msg("Invalid selection.");
+                    which = rnd(6);
+                    msg("Rolled %d.", which);
+                }
+            }
+        }
+    }
+
+    switch (which)
+    {
+        case 0:
+            if (get_dir())
+                do_zap(&player, WS_CANCEL, ISBLESSED);
+            break;
+
+        case 1:
+            if (get_dir())
+                do_zap(&player, WS_POLYMORPH, ISBLESSED);
+            break;
+
+        case 2:
+            if (get_dir())
+                do_zap(&player, WS_SLOW_M, ISBLESSED);
+            break;
+
+        case 3:
+            if (get_dir())
+                do_zap(&player, WS_MONSTELEP, ISBLESSED);
+            break;
+
+        case 4:
+            if (get_dir())
+                do_zap(&player, WS_CONFMON, ISBLESSED);
+            break;
+
+        case 5:
+            if (get_dir())
+                do_zap(&player, WS_PARALYZE, ISBLESSED);
+            break;
+
+        case 6:
+            if (get_dir())
+                do_zap(&player, WS_DRAIN, ISBLESSED);
+            break;
+
+        case 7:
+            quaff(&player, P_SMELL, ISBLESSED);
+            break;
+
+        default:
+            msg("What a strange thing to do!!");
+            break;
+    }
+}
+
+/*
+    do_wand()
+        handle powers of the Wand of Yendor
+*/
+
+void
+do_wand(void)
+{
+    int which, i;
+
+    /* Prompt for action */
+    msg("How do you wish to apply the Wand of Yendor (* for list)? ");
+
+    which = (short) ((readchar() & 0177) - 'a');
+
+    if (which == (short) ESCAPE - (short) 'a')
+    {
+        after = FALSE;
+        return;
+    }
+
+    if (which < 0 || which >= maxsticks)
+    {
+        msg("");
+
+        for (i = 0; i < maxsticks; i++)
+        {
+            sprintf(prbuf, "[%c] %s", i + 'a', ws_magic[i].mi_name);
+            add_line(prbuf);
+        }
+
+        end_line();
+
+        msg("Which power do you wish to use?");
+
+        which = (short) ((readchar() & 0177) - 'a');
+
+        while (which < 0 || which >= maxsticks)
+        {
+            if (which == (short) ESCAPE - (short) 'a')
+            {
+                after = FALSE;
+                return;
+            }
+
+            msg("");
+            msg("Please enter one of the listed powers: ");
+            which = (short) ((readchar() & 0177) - 'a');
+        }
+        msg("Your attempt is successful.");
+    }
+    else
+        msg("Your attempt is successful.");
+
+    if (rnd(pstats.s_lvl) < 12)
+    {
+        msg("Your finger slips.");
+        which = rnd(maxsticks);
+
+        if (wizard)
+        {
+            msg("What wand? (%d)", which);
+
+            if (get_string(prbuf, cw) == NORM)
+            {
+                which = atoi(prbuf);
+
+                if (which < 0 || which >= maxsticks)
+                {
+                    msg("Invalid selection.");
+                    which = rnd(maxsticks);
+                    msg("Rolled %d.", which);
+                }
+            }
+        }
+    }
+
+    if (get_dir())
+        do_zap(&player, which, ISBLESSED);
+}
+
+/*
+    do_crown()
+        handle powers of the Crown of Might
+*/
+
+void
+do_crown(void)
+{
+    int which, limit;
+
+    /* Prompt for action */
+    msg("How do you wish to apply the Crown of Might (* for list)? ");
+
+    which = (short) ((readchar() & 0177) - 'a');
+
+    if (which == (short) ESCAPE - (short) 'a')
+    {
+        after = FALSE;
+        return;
+    }
+
+    limit = 9;
+
+    if (is_carrying(TR_PALANTIR))
+        limit += 1;
+
+    if (is_carrying(TR_SCEPTRE))
+        limit += 1;
+
+    if (which < 0 || which > limit)
+    {
+        msg("");
+        add_line("[a] add strength");
+        add_line("[b] add intelligence");
+        add_line("[c] add wisdom");
+        add_line("[d] add dexterity");
+        add_line("[e] add constitution");
+        add_line("[f] normal strength");
+        add_line("[g] normal intelligence");
+        add_line("[h] normal wisdom");
+        add_line("[i] normal dexterity");
+        add_line("[j] normal constitution");
+
+        if (limit >= 10)
+            add_line("[k] disguise");
+
+        if (limit >= 11)
+            add_line("[l] super heroism");
+
+        end_line();
+
+        msg("Which power do you wish to use?");
+
+        which = (short) ((readchar() & 0177) - 'a');
+
+        while (which < 0 || which > limit)
+        {
+            if (which == (short) ESCAPE - (short) 'a')
+            {
+                after = FALSE;
+                return;
+            }
+            msg("");
+            msg("Please enter one of the listed powers: ");
+            which = (short) ((readchar() & 0177) - 'a');
+        }
+
+        msg("Your attempt is successful.");
+    }
+    else
+        msg("Your attempt is successful.");
+
+    switch (which)
+    {
+        case 0:
+            if (off(player, POWERSTR))
+            {
+                turn_on(player, POWERSTR);
+                chg_str(10, FALSE, FALSE);
+                msg("You feel much stronger now.");
+            }
+            else
+                nothing_message(ISCURSED);
+            break;
+
+        case 1:
+            if (off(player, POWERINTEL))
+            {
+                pstats.s_intel += 10;
+                turn_on(player, POWERINTEL);
+                msg("You feel much more intelligent now.");
+            }
+            else
+                nothing_message(ISCURSED);
+            break;
+
+        case 2:
+            if (off(player, POWERWISDOM))
+            {
+                pstats.s_wisdom += 10;
+                turn_on(player, POWERWISDOM);
+                msg("Your feel much wiser know.");
+            }
+            else
+                nothing_message(ISCURSED);
+            break;
+
+        case 3:
+            if (off(player, POWERDEXT))
+            {
+                turn_on(player, POWERDEXT);
+                chg_dext(10, FALSE, FALSE);
+                msg("You feel much more dextrous now.");
+            }
+            else
+                nothing_message(ISCURSED);
+            break;
+
+        case 4:
+            if (off(player, POWERCONST))
+            {
+                pstats.s_const += 10;
+                turn_on(player, POWERCONST);
+                msg("You feel much healthier now.");
+            }
+            else
+                nothing_message(ISCURSED);
+            break;
+
+        case 5:
+            if (on(player, POWERSTR))
+            {
+                turn_off(player, POWERSTR);
+                chg_str(-10, FALSE, FALSE);
+                msg("Your muscles bulge less now.");
+            }
+            else
+                nothing_message(ISCURSED);
+            break;
+
+        case 6:
+            if (on(player, POWERINTEL))
+            {
+                pstats.s_intel = max(pstats.s_intel - 10,
+                             3 + ring_value(R_ADDINTEL));
+                turn_off(player, POWERINTEL);
+                msg("You feel less intelligent now.");
+            }
+            else
+                nothing_message(ISCURSED);
+            break;
+
+        case 7:
+            if (on(player, POWERWISDOM))
+            {
+                pstats.s_wisdom = max(pstats.s_wisdom - 10,
+                              3 + ring_value(R_ADDWISDOM));
+                turn_off(player, POWERWISDOM);
+                msg("You feel less wise now.");
+            }
+            else
+                nothing_message(ISCURSED);
+            break;
+
+        case 8:
+            if (on(player, POWERDEXT))
+            {
+                turn_off(player, POWERDEXT);
+                chg_dext(-10, FALSE, FALSE);
+                msg("You feel less dextrous now.");
+            }
+            else
+                nothing_message(ISCURSED);
+            break;
+
+        case 9:
+            if (on(player, POWERCONST))
+            {
+                pstats.s_const -= 10;
+                turn_off(player, POWERCONST);
+                msg("You feel less healthy now.");
+            }
+            else
+                nothing_message(ISCURSED);
+            break;
+
+        case 10: quaff(&player, P_DISGUISE, ISNORMAL);
+            break;
+
+        case 11: quaff(&player, P_SHERO, ISNORMAL);
+            break;
+
+        default:
+            msg("What a strange thing to do!!");
+            break;
+
+    }
+}
+
+/*
+    level_eval()
+        have amulet evaluate danger on this level
+*/
+
+void
+level_eval(void)
+{
+    int cnt = 0;
+    long max_nasty = 0;
+    struct linked_list  *item;
+    struct thing    *tp;
+    char    *colour, *temp;
+
+    for (item = mlist; item != NULL; item = next(item))
+    {
+        tp = THINGPTR(item);
+        cnt++;
+        max_nasty = max(max_nasty,(10L-tp->t_stats.s_arm) * tp->t_stats.s_hpt);
+    }
+
+    if (cnt < 3)
+        colour = "black";
+    else if (cnt < 6)
+        colour = "red";
+    else if (cnt < 9)
+        colour = "orange";
+    else if (cnt < 12)
+        colour = "yellow";
+    else if (cnt < 15)
+        colour = "green";
+    else if (cnt < 18)
+        colour = "blue";
+    else if (cnt < 25)
+        colour = "violet";
+    else
+        colour = "pink with purple polka dots";
+
+    if (max_nasty < 10)
+        temp = "feels cold and lifeless";
+    else if (max_nasty < 30)
+        temp = "feels cool";
+    else if (max_nasty < 200)
+        temp = "feels warm and soft";
+    else if (max_nasty < 1000)
+        temp = "feels warm and slippery";
+    else if (max_nasty < 5000)
+        temp = "feels hot and dry";
+    else if (max_nasty < 10000)
+        temp = "feels too hot to hold";
+    else if (max_nasty < 20000)
+        temp = "burns your hand";
+    else
+        temp = "jumps up and down shrieking 'DANGER! DANGER'";
+
+    msg("The amulet glows %s and %s.", colour, temp);
+
+    return;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/bag.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,448 @@
+/*
+    bag.c  -  functions for dealing with bags
+
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+/*
+ * new bag functions
+ *
+ * This is a simple version of bag.c that uses linked lists to perform the bag
+ * functions. The bag is just a linked list of objects (struct object) to be
+ * specific, but most of that is supposed to be hidden from the user, who
+ * should access the bag only through the functions presented here.
+ */
+
+#include <stdlib.h>
+#include "rogue.h"
+
+/*
+ * apply_to_bag
+ *
+ * This is the general bag manipulation routine. The bag is subjected to
+ * selection criteria and those objects which pass are processed by an action
+ * routine. The two criteria are type and filter function. The filter
+ * function returns TRUE if the object passes and FALSE otherwise. The filter
+ * function is passed the object and the user-supplied argument. This gives
+ * the user plenty of flexibility in determining which items will be
+ * processed. The action routine is passed the object, the id, and the
+ * user-supplied argument given to apply_to_bag. Specifying NULL for either
+ * the type or filter function means that criterion always selects. A NULL
+ * action routine means no processing is done and the first object which
+ * passes the filter is returned to the user. The action routine returns TRUE
+ * if processing should continue or FALSE if the current item should be
+ * returned to the caller.
+ *
+ * Returns NULL if the bag is empty or if nothing qualified.
+ *
+ * linked_list *bag_p;       // linked list of objects
+ * int          type;        // what is its type (ARMOR, ...)
+ * int        (*bff_p)();    // bag filter function
+ * int        (*baf_p)();    // bag action routine
+ * long         user_arg;    // user argument for filter, action
+ *
+ */
+
+struct object *
+apply_to_bag(struct linked_list *bag_p,
+             int type,
+             int (*bff_p)(struct object *obj, bag_arg *user_arg),
+             int (*baf_p)(struct object *obj, bag_arg *user_arg, int id),
+             void *user_arg)
+{
+    struct object *bag_obj_p = NULL;  /* qualifying object */
+    struct object *cur_obj_p;         /* current object */
+    bag_arg arg;
+
+    arg.varg = user_arg;
+
+    if (bag_p == NULL)
+        return (NULL);
+
+    for (; bag_p != NULL; bag_p = next(bag_p))
+    {
+        cur_obj_p = OBJPTR(bag_p);
+
+        if (type != 0 && type != cur_obj_p->o_type)
+            continue;
+
+        if (bff_p != NULL && !(*bff_p)(cur_obj_p, &arg))
+            continue;
+
+        /*
+         * At this point, we have an object which qualifies for
+         * processing
+         */
+
+        bag_obj_p = cur_obj_p;  /* in case the user wants it */
+
+        if (baf_p != NULL && (*baf_p)(cur_obj_p, &arg, identifier(bag_obj_p)))
+            continue;
+
+        /*
+         * We have an object which qualifies, quit now!
+         */
+
+        break;
+    }
+
+    if (bag_p == NULL)
+        return (NULL);
+
+    return (bag_obj_p);
+}
+
+/*
+    count_bag()
+
+        Counts up all bag items which meet the selection criteria
+*/
+
+int
+count_bag(linked_list *bag_p,
+          int type,
+          int (*bff_p)(struct object *obj, bag_arg *junk))
+{
+    int cnt = 0;
+    apply_to_bag(bag_p, type, bff_p, baf_increment, &cnt);
+
+    return(cnt);
+}
+
+/*
+    del_bag()
+
+        Removes an object from a bag and throws it away.
+*/
+
+void
+del_bag(linked_list *bag_p, object *obj_p)
+{
+    pop_bag(&bag_p, obj_p);  /* get the thing from the bag */
+    ur_free(obj_p);         /* release the memory */
+}
+
+/*
+    pop_bag()
+
+        Removes an item from a bag and returns it to the user. If the item is
+        not in the bag, return NULL.
+*/
+
+struct object *
+pop_bag(linked_list **bag_pp, object *obj_p)
+{
+    linked_list *item_p;
+
+    for (item_p = *bag_pp; item_p != NULL && OBJPTR(item_p) != obj_p;
+         item_p = next(item_p));
+
+    if (item_p == NULL)
+        return (NULL);
+
+    _detach(bag_pp, item_p);
+
+    return (obj_p);
+}
+
+/*
+    push_bag()
+
+        stuff another item into the bag
+*/
+
+void
+push_bag(linked_list **bag_pp, object *obj_p)
+{
+    struct linked_list *item_p = NULL;
+    struct linked_list *new_p  = NULL;
+    struct linked_list *best_p = NULL;
+
+    new_p             = new_list();
+    new_p->data.obj   = obj_p;              /* attach our object   */
+    identifier(obj_p) = get_ident(obj_p);   /* tag this object for */
+                                            /*     inventory       */
+    /*
+     * Find a place in the bag - try to match the type, then sort by
+     * identifier
+     */
+
+    for (item_p = *bag_pp; item_p != NULL; item_p = next(item_p))
+    {
+        if ((OBJPTR(item_p))->o_type == obj_p->o_type)
+        {
+            if (best_p == NULL)
+                best_p = item_p;
+            else if (identifier((OBJPTR(item_p))) >
+                     identifier((OBJPTR(best_p))) &&
+                     identifier((OBJPTR(item_p))) <
+                     identifier(obj_p))
+                best_p = item_p;
+        }
+    }
+
+    _attach_after(bag_pp, best_p, new_p);   /* stuff it in the list */
+
+    return;
+}
+
+/*
+    scan_bag()
+
+        Gets the object from the bag that matches the type and id. The object
+        is not removed from the bag.
+*/
+
+struct object *
+scan_bag(linked_list *bag_p, int type, int id)
+{
+    object  *obj_p = NULL;
+
+    for (; bag_p != NULL; bag_p = next(bag_p))
+    {
+        obj_p = OBJPTR(bag_p);
+
+        if (obj_p->o_type == type && identifier(obj_p) == id)
+            break;
+    }
+
+    if (bag_p == NULL)
+        return(NULL);
+
+    return(obj_p);
+}
+
+/*
+    baf_decrement_test()
+
+        Assumes the argument is a pointer to int and it just decrements it.
+        Returns TRUE, except when the count goes to zero.
+*/
+
+int
+baf_decrement_test(struct object *obj_p, bag_arg *count_p, int id)
+{
+    NOOP(obj_p);
+    NOOP(id);
+
+    if (*count_p->iarg > 0)
+        return(TRUE);
+
+    return(FALSE);
+}
+
+/*
+    baf_identify()
+
+        Bag action function to identify an object. This is needed to conform
+        to bag action routine calling conventions and to put the linked list
+        structure on top of the object before calling whatis()
+*/
+
+int
+baf_identify(struct object *obj_p, bag_arg *junk, int id)
+{
+    linked_list l;
+    linked_list *lp = &l;
+
+    NOOP(junk);
+    NOOP(id);
+
+    lp->data.obj = obj_p;    /* stuff object in the right place */
+    whatis(lp);
+
+    return(TRUE);
+}
+
+/*
+    baf_increment()
+
+        Assumes the argument is a pointer to int and it just increments it and
+        returns TRUE
+*/
+
+int
+baf_increment(object *obj_p, bag_arg *count_p, int id)
+{
+    NOOP(obj_p);
+    NOOP(id);
+
+    (*count_p->iarg)++;
+
+    return(TRUE);
+}
+
+/*
+    baf_print_item()
+        Bag action function to print a single item, inventory style.
+*/
+
+int
+baf_print_item(struct object *obj_p, bag_arg *type, int id)
+{
+    char inv_temp[3 * LINELEN];  /* plenty of space for paranoid programmers */
+
+    if (*type->iarg == 0)
+        sprintf(inv_temp, "%c%c) %s", obj_p->o_type,
+              print_letters[id], inv_name(obj_p, LOWERCASE), FALSE);
+    else
+        sprintf(inv_temp, "%c) %s", print_letters[id],
+            inv_name(obj_p, LOWERCASE), FALSE);
+
+    add_line(inv_temp);
+    return(TRUE);
+}
+
+/*
+    bff_group()
+        This bag filter function checks to see if two items can be combined by
+        adjusting the count. Grouped items can be combined if the group numbers
+        match. The only other item that is allowed to have a count is food, and
+        there an exact match is required.
+*/
+
+int
+bff_group(struct object *obj_p, bag_arg *arg)
+{
+    struct object *new_obj_p = arg->obj;
+
+    if (new_obj_p->o_group > 0 && new_obj_p->o_group == obj_p->o_group)
+        return(TRUE);
+
+    if (new_obj_p->o_type == FOOD &&
+        obj_p->o_type == new_obj_p->o_type &&
+        obj_p->o_which == new_obj_p->o_which)
+        return(TRUE);
+
+    return(FALSE);
+}
+
+/*
+    bff_callable
+        Figures out which items can be callable: current rules are:
+            potions, scrolls, staffs, and rings.
+*/
+
+int
+bff_callable(struct object *obj_p, bag_arg *junk)
+{
+    NOOP(junk);
+
+    if (obj_p->o_type == POTION || obj_p->o_type == RING ||
+        obj_p->o_type == STICK || obj_p->o_type == SCROLL)
+        return(TRUE);
+
+    return(FALSE);
+}
+
+/*
+    bff_markable()
+        Selects which items can be marked. Current rules exclude only gold.
+*/
+
+int
+bff_markable(struct object *obj_p, bag_arg *junk)
+{
+    NOOP(junk);
+
+    if (obj_p->o_type == GOLD)
+        return(FALSE);
+
+    return(TRUE);
+}
+
+/*
+    bffron()
+        returns TRUE if hero is wearing this ring
+*/
+
+int
+bffron(object *obj_p, bag_arg *junk)
+{
+    NOOP(junk);
+
+    return(cur_ring[LEFT_1] == obj_p || cur_ring[LEFT_2] == obj_p ||
+        cur_ring[LEFT_3] == obj_p || cur_ring[LEFT_4] == obj_p ||
+        cur_ring[LEFT_5] ||
+        cur_ring[RIGHT_1] == obj_p || cur_ring[RIGHT_2] == obj_p ||
+        cur_ring[RIGHT_3] == obj_p || cur_ring[RIGHT_4] == obj_p ||
+        cur_ring[RIGHT_5]);
+}
+
+/*
+    bff_zappable()
+        Selects which items can be zapped. This includes both sticks and
+        magically enhanced weapons with lightning ability.
+*/
+
+int
+bff_zappable(struct object *obj_p, bag_arg *junk)
+{
+    NOOP(junk);
+
+    if (obj_p->o_type == STICK)
+        return(TRUE);
+
+    if (obj_p->o_type == WEAPON && obj_p->o_flags & ISZAPPED)
+        return(TRUE);
+
+    return (FALSE);
+}
+
+/*
+    baf_curse()
+        Curse all non-artifact items in the player's pack
+*/
+
+int
+baf_curse(struct object *obj_p, bag_arg *junk, int id)
+{
+    NOOP(junk);
+    NOOP(id);
+
+    if (obj_p->o_type != ARTIFACT && rnd(8) == 0)
+    {
+        obj_p->o_flags |= ISCURSED;
+        obj_p->o_flags &= ~ISBLESSED;
+    }
+
+    return(TRUE);
+}
+
+/*
+    bafcweapon()
+        bag action routine to fetch the current weapon
+*/
+
+int
+bafcweapon(struct object *obj_p, bag_arg *junk, int id)
+{
+    NOOP(junk);
+    NOOP(id);
+
+    if (obj_p == cur_weapon)
+        return(FALSE); /* found what we wanted - stop and return it */
+
+    return(TRUE);
+}
+
+/*
+    bafcarmor()
+        bag action routine to fetch the current armor
+*/
+
+int
+bafcarmor(struct object *obj_p, bag_arg *junk, int id)
+{
+    NOOP(junk);
+    NOOP(id);
+
+    if (obj_p == cur_armor)
+        return(FALSE); /* found what we wanted - stop and return it */
+
+    return(TRUE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/chase.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1326 @@
+/*
+    chase.c  -  Code for one creature to chase another
+ 
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+#include "rogue.h"
+
+/*
+    do_chase()
+        Make one thing chase another.
+*/
+
+void
+do_chase(struct thing *th, int flee)
+{
+    struct room    *rer;        /* room of chaser */
+    struct room    *ree;        /* room of chasee */
+    struct room    *old_room;   /* old room of monster */
+    struct room    *new_room;   /* new room of monster */
+
+    int i, mindist = INT_MAX, maxdist = INT_MIN, dist = INT_MIN;
+
+    int last_door = -1;     /* Door we just came from */
+    int stoprun = FALSE;    /* TRUE means we are there */
+    int rundoor;            /* TRUE means run to a door */
+    int hit_bad = FALSE;    /* TRUE means hit bad monster */
+    int mon_attack;         /* TRUE means find a monster to hit */
+
+    char    sch;
+    struct linked_list *item;
+    coord   this;           /* Temporary destination for chaser */
+
+    if (!th->t_ischasing)
+        return;
+
+    /* Make sure the monster can move */
+
+    if (th->t_no_move != 0)
+    {
+        th->t_no_move--;
+        return;
+    }
+
+    /*
+     * Bad monsters check for a good monster to hit, friendly monsters
+     * check for a bad monster to hit.
+     */
+
+    mon_attack = FALSE;
+
+    if (good_monster(*th))
+    {
+        hit_bad = TRUE;
+        mon_attack = TRUE;
+    }
+    else if (on(*th, ISMEAN))
+    {
+        hit_bad = FALSE;
+        mon_attack = TRUE;
+    }
+
+    if (mon_attack)
+    {
+        struct linked_list  *mon_to_hit;
+
+	mon_to_hit = f_mons_a(th->t_pos.y, th->t_pos.x, hit_bad);
+
+        if (mon_to_hit)
+        {
+            mon_mon_attack(th, mon_to_hit, pick_weap(th), NOTHROWN);
+            return;
+        }
+    }
+	
+    /* no nearby monster to hit */
+	
+    rer = roomin(th->t_pos);            /* Find room of chaser */
+    ree = roomin(th->t_chasee->t_pos);  /* Find room of chasee */
+
+    /*
+     * We don't count doors as inside rooms for this routine
+     */
+
+    if (mvwinch(stdscr, th->t_pos.y, th->t_pos.x) == DOOR)
+        rer = NULL;
+
+    this = th->t_chasee->t_pos;
+
+    /*
+     * If we are not in a corridor and not a phasing monster, then if we
+     * are running after the player, we run to a door if he is not in the
+     * same room. If we are fleeing, we run to a door if he IS in the
+     * same room.  Note:  We don't bother with doors in mazes. Phasing 
+     * monsters don't need to look for doors. There are no doors in mazes
+     * and throne rooms. 
+     */
+
+    if (levtype != MAZELEV && levtype != THRONE && rer != NULL && off(*th, CANINWALL))
+    {
+        if (flee)
+            rundoor = (rer == ree);
+        else
+            rundoor = (rer != ree);
+    }
+    else
+        rundoor = FALSE;
+
+    if (rundoor)
+    {
+        coord   d_exit;   /* A particular door */
+        int exity, exitx;   /* Door's coordinates */
+
+        if (th->t_doorgoal != -1)
+        { /* Do we already have the goal? */
+            this = rer->r_exit[th->t_doorgoal];
+            dist = 0;   /* Indicate that we have our door */
+        }
+        else
+            for (i = 0; i < rer->r_nexits; i++)
+            {   /* Loop through doors */
+                d_exit = rer->r_exit[i];
+                exity = d_exit.y;
+                exitx = d_exit.x;
+
+                /* Avoid secret doors */
+                if (mvwinch(stdscr, exity, exitx) == DOOR)
+                {
+                    /* Were we just on this door? */
+                    if (ce(d_exit, th->t_oldpos))
+                        last_door = i;
+                    else
+                    {
+                        dist = DISTANCE(th->t_chasee->t_pos, d_exit);
+
+                        /*
+                         * If fleeing, we want to
+                         * maximize distance from
+                         * door to what we flee, and
+                         * minimize distance from
+                         * door to us.
+                         */
+
+                        if (flee)
+                            dist-=DISTANCE(th->t_pos,d_exit);
+
+                        /*
+                         * Maximize distance if
+                         * fleeing, otherwise
+                         * minimize it
+                         */
+
+                        if ((flee && (dist > maxdist)) ||
+                            (!flee && (dist < mindist)))
+                        {
+                            th->t_doorgoal = i; /* Use this door */
+                            this = d_exit;
+                            mindist = maxdist = dist;
+                        }
+                    }
+                }
+            }
+
+        /* Could we not find a door? */
+        if (dist == INT_MIN)
+        {
+            /* If we were on a door, go ahead and use it */
+            if (last_door != -1)
+            {
+                th->t_doorgoal = last_door;
+                this = th->t_oldpos;
+                dist = 0;   /* Indicate that we found a door */
+            }
+        }
+
+        /* Indicate that we do not want to flee from the door */
+        if (dist != INT_MIN)
+            flee = FALSE;
+    }
+    else
+        th->t_doorgoal = -1;    /* Not going to any door */
+
+    /*
+     * this now contains what we want to run to this time so we run to
+     * it.  If we hit it we either want to fight it or stop running
+     */
+
+    if (!chase(th, &this, flee))
+    {
+        if (ce(th->t_nxtpos, hero))
+        {
+            /* merchants try to sell something */
+
+            if (on(*th, CANSELL))
+            {
+                sell(th);
+                return;
+            }
+            else if (off(*th, ISFRIENDLY) && off(*th, ISCHARMED)
+                    && (off(*th, CANFLY) || (on(*th, CANFLY) && rnd(2))))
+                    attack(th, pick_weap(th), FALSE);
+                return;
+        }
+        else if (on(*th, NOMOVE))
+            stoprun = TRUE;
+    }
+
+    if (!curr_mons)
+        return;     /* Did monster get itself killed? */
+
+    if (on(*th, NOMOVE))
+        return;
+
+    /* If we have a scavenger, it can pick something up */
+
+    if ((item = find_obj(th->t_nxtpos.y, th->t_nxtpos.x)) != NULL)
+    {
+		struct linked_list *node, *top = item;
+        struct object *obt;
+		
+		while(top)
+		{
+			/* grab all objects that qualify */
+			
+			struct object *obj = OBJPTR(item);
+			
+			obt = OBJPTR(top);
+			node = obt->next_obj;
+			
+			if (on(*th, ISSCAVENGE) ||
+                ((on(*th, CANWIELD) || on(*th, CANSHOOT)) &&
+                (obj->o_type == WEAPON || obj->o_type == ARMOR)) ||
+                (on(*th, CANCAST) && is_magic(obj))) 
+			{
+                rem_obj(top, FALSE);
+                attach(th->t_pack, top);
+            }
+			
+			top = node;
+		}
+		
+		light(&hero);
+    }
+
+    mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch);
+    sch = CCHAR( mvwinch(cw, th->t_nxtpos.y, th->t_nxtpos.x) );
+
+    /* Get old and new room of monster */
+    old_room = roomin(th->t_pos);
+    new_room = roomin(th->t_nxtpos);
+
+    /* If the monster can illuminate rooms, check for a change */
+    if (on(*th, HASFIRE))
+    {
+        /* Is monster entering a room? */
+        if (old_room != new_room && new_room != NULL)
+        {
+            new_room->r_flags |= HASFIRE;
+            new_room->r_fires++;
+            if (cansee(th->t_nxtpos.y, th->t_nxtpos.x) && new_room->r_fires==1)
+                light(&hero);
+        }
+
+        /* Is monster leaving a room? */
+        if (old_room != new_room && old_room != NULL)
+        {
+            if (--(old_room->r_fires) <= 0)
+            {
+                old_room->r_flags &= ~HASFIRE;
+                if (cansee(th->t_pos.y, th->t_pos.x))
+                    light(&th->t_pos);
+            }
+        }
+    }
+
+    /*
+     * If monster is entering player's room and player can see it, stop
+     * the player's running.
+     */
+
+    if (new_room != old_room && new_room != NULL &&
+        new_room == ree && cansee(th->t_nxtpos.y, th->t_nxtpos.x) &&
+        (off(*th, ISINVIS) || (off(*th, ISSHADOW) || rnd(10) == 0) ||
+         on(player, CANSEE)) && off(*th, CANSURPRISE))
+        running = FALSE;
+
+    if (rer != NULL && (rer->r_flags & ISDARK) &&
+        !(rer->r_flags & HASFIRE) && sch == FLOOR &&
+         DISTANCE(th->t_nxtpos, th->t_pos) < see_dist &&
+        off(player, ISBLIND))
+        th->t_oldch = ' ';
+    else
+        th->t_oldch = sch;
+
+    if (cansee(th->t_nxtpos.y, th->t_nxtpos.x) &&
+      off(*th, ISINWALL) &&
+      ((off(*th, ISINVIS) && (off(*th, ISSHADOW) || rnd(100) < 10)) ||
+      on(player, CANSEE)) &&
+      off(*th, CANSURPRISE))
+        mvwaddch(cw, th->t_nxtpos.y, th->t_nxtpos.x, th->t_type);
+
+    mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
+    mvwaddch(mw, th->t_nxtpos.y, th->t_nxtpos.x, th->t_type);
+
+    /* Record monster's last position (if new one is different) */
+
+    if (!ce(th->t_nxtpos, th->t_pos))
+        th->t_oldpos = th->t_pos;
+
+    th->t_pos = th->t_nxtpos; /* Mark the monster's new position */
+
+    /* If the monster is on a trap, trap it */
+
+    sch = CCHAR(mvinch(th->t_nxtpos.y, th->t_nxtpos.x));
+
+    if (isatrap(sch))
+    {
+        debug("Monster trapped by %c.", sch);
+
+        if (cansee(th->t_nxtpos.y, th->t_nxtpos.x))
+            th->t_oldch = sch;
+
+        be_trapped(th, th->t_nxtpos);
+    }
+
+    /* And stop running if need be */
+
+    if (stoprun && ce(th->t_pos, th->t_chasee->t_pos))
+    {
+        th->t_ischasing = FALSE;
+        turn_off(*th, ISRUN);
+    }
+}
+
+/*
+    chase_it()
+        Set a monster running after something or stop it from running (for
+        when it dies)
+*/
+
+void
+chase_it(coord *runner, struct thing *th)
+{
+    struct linked_list  *item;
+    struct thing    *tp;
+
+    /* If we couldn't find him, something is funny */
+
+    if ((item = find_mons(runner->y, runner->x)) == NULL)
+    {
+        debug("CHASER '%s'", unctrl(winat(runner->y, runner->x)));
+        return;
+    }
+
+    tp = THINGPTR(item);
+
+    /* Start the beastie running */
+
+    tp->t_ischasing = TRUE;
+    tp->t_chasee    = th;
+
+    turn_on(*tp, ISRUN);
+    turn_off(*tp, ISDISGUISE);
+
+    return;
+}
+
+/*
+    chase()
+        Find the spot for the chaser(er) to move closer to the chasee(ee).
+        Returns TRUE if we want to keep on chasing later, FALSE if we reach the
+        goal.
+*/
+
+int
+chase(struct thing *tp, coord *ee, int flee)
+{
+    int x, y;
+    int dist, thisdist, monst_dist = INT_MAX;
+    struct linked_list  *weapon;
+    coord   *er = &tp->t_pos;
+    coord shoot;
+    coord *shootit_dir = NULL;
+    int ch;
+    char   mch;
+    int    next_player = FALSE;
+
+    /* Take care of shooting directions */
+
+    if (on(*tp, CANBREATHE) || on(*tp, CANSHOOT) || on(*tp, CANCAST))
+    {
+        if (good_monster(*tp))
+        {
+            shootit_dir = find_shoot(tp, &shoot); /* find a mean monster */
+
+            if (wizard && shootit_dir)
+                msg("Found monster to attack towards (%d,%d).",
+                    shootit_dir->x, shootit_dir->y);
+        }
+        else
+            shootit_dir = can_shoot(er, ee, &shoot);  /* shoot hero */
+    }
+
+    /*
+     * If the thing is confused, let it move randomly. Some monsters are
+     * slightly confused all of the time.
+     */
+
+    if ((on(*tp, ISHUH) && rnd(10) < 8) ||
+        ((on(*tp, ISINVIS) || on(*tp, ISSHADOW)) && rnd(100) < 20) ||
+        (on(player, ISINVIS) && off(*tp, CANSEE)))
+    {   /* Player is invisible */
+
+        /* get a valid random move */
+
+        tp->t_nxtpos = rndmove(tp);
+
+        dist = DISTANCE(tp->t_nxtpos, *ee);
+
+        if (on(*tp, ISHUH) && rnd(20) == 0) /* monster might lose confusion */
+            turn_off(*tp, ISHUH);
+
+        /*
+         * check to see if random move takes creature away from
+         * player if it does then turn off ISHELD
+         */
+
+        if (dist > 1 && on(*tp, DIDHOLD))
+        {
+            turn_off(*tp, DIDHOLD);
+            turn_on(*tp, CANHOLD);
+
+            if (--hold_count == 0)
+                turn_off(player, ISHELD);
+        }
+    } /* If we can breathe, we may do so */
+    else if (on(*tp, CANBREATHE) && (shootit_dir) && (rnd(100) < 67) &&
+         (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6)) &&
+         (DISTANCE(*er, *ee) < BOLT_LENGTH * BOLT_LENGTH))
+    {
+        int   chance;
+        char    *breath;
+
+        /* Will it breathe at random */
+
+        if (on(*tp, CANBRANDOM))
+        {
+            if (rnd(level / 20) == 0 && tp->t_index != nummonst + 1
+                && !(good_monster(*tp)))
+                turn_off(*tp, CANBRANDOM);
+
+            /* Select type of breath */
+
+            chance = rnd(100);
+
+            if (chance < 11)
+                breath = "acid";
+            else if (chance < 22)
+                breath = "flame";
+            else if (chance < 33)
+                breath = "lightning bolt";
+            else if (chance < 44)
+                breath = "chlorine gas";
+            else if (chance < 55)
+                breath = "ice";
+            else if (chance < 66)
+                breath = "nerve gas";
+            else if (chance < 77)
+                breath = "sleeping gas";
+            else if (chance < 88)
+                breath = "slow gas";
+            else
+                breath = "fear gas";
+        } /* Or can it breathe acid? */
+        else if (on(*tp, CANBACID))
+        {
+            if (!good_monster(*tp) && rnd(level / 15) == 0)
+                turn_off(*tp, CANBACID);
+
+            breath = "acid";
+        } /* Or can it breathe fire */
+        else if (on(*tp, CANBFIRE))
+        {
+            if (!good_monster(*tp) && rnd(level / 15) == 0)
+                turn_off(*tp, CANBFIRE);
+
+            breath = "flame";
+        } /* Or can it breathe electricity? */
+        else if (on(*tp, CANBBOLT))
+        {
+            if (!good_monster(*tp) && rnd(level / 15) == 0)
+                turn_off(*tp, CANBBOLT);
+
+            breath = "lightning bolt";
+        } /* Or can it breathe gas? */
+        else if (on(*tp, CANBGAS))
+        {
+            if (!good_monster(*tp) && rnd(level / 15) == 0)
+                turn_off(*tp, CANBGAS);
+
+            breath = "chlorine gas";
+        } /* Or can it breathe ice? */
+        else if (on(*tp, CANBICE))
+        {
+            if (!good_monster(*tp) && rnd(level / 15) == 0)
+                turn_off(*tp, CANBICE);
+
+            breath = "ice";
+        }
+        else if (on(*tp, CANBPGAS))
+        {
+            if (!good_monster(*tp) && rnd(level / 15) == 0)
+                turn_off(*tp, CANBPGAS);
+
+            breath = "nerve gas";
+        }
+        else if (on(*tp, CANBSGAS))
+        {
+            if (!good_monster(*tp) && rnd(level / 15) == 0)
+                turn_off(*tp, CANBSGAS);
+
+            breath = "sleeping gas";
+        }
+        else if (on(*tp, CANBSLGAS))
+        {
+            if (!good_monster(*tp) && rnd(level / 15) == 0)
+                turn_off(*tp, CANBSLGAS);
+
+            breath = "slow gas";
+        }
+        else
+        {
+            if (!good_monster(*tp) && rnd(level / 15) == 0)
+                turn_off(*tp, CANBFGAS);
+
+            breath = "fear gas";
+        }
+
+        shoot_bolt(tp, *er, *shootit_dir, (tp == THINGPTR(fam_ptr)),
+               tp->t_index, breath, roll(tp->t_stats.s_lvl, 6));
+
+        tp->t_nxtpos = *er;
+
+        dist = DISTANCE(tp->t_nxtpos, *ee);
+
+        if (!curr_mons)
+            return (TRUE);
+    }
+    else if (shootit_dir && on(*tp, CANCAST) &&
+         (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6)))
+    {
+        /*
+            If we can cast spells we might do so - even if adjacent fleeing
+            monsters are restricted to certain spells
+        */
+
+        incant(tp, *shootit_dir);
+        tp->t_nxtpos = *er;
+        dist = DISTANCE(tp->t_nxtpos, *ee);
+    }
+    else if (shootit_dir && on(*tp, CANSHOOT)) 
+    {
+	weapon = get_hurl(tp);
+	
+	if (weapon &&
+         (off(*tp, ISFLEE) || rnd(DISTANCE(*er, *ee)) > 2) &&
+         (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6)))
+	{
+	    /*
+	        Should we shoot or throw something? fleeing monsters 
+		may to shoot anyway if far enough away
+	    */
+
+	    missile(shootit_dir->y, shootit_dir->x, weapon, tp);
+	    tp->t_nxtpos = *er;
+	    dist = DISTANCE(tp->t_nxtpos, *ee);
+	}
+    }
+    else
+    {
+        /*
+            Otherwise, find the empty spot next to the chaser that is closest
+            to the chasee.
+        */
+        int ey, ex;
+        struct room *rer, *ree;
+        int dist_to_old = INT_MIN;   /* Dist from goal to old position */
+
+        /* Get rooms */
+        rer = roomin(*er);
+        ree = roomin(*ee);
+
+        /*
+         * This will eventually hold where we move to get closer. If
+         * we can't find an empty spot, we stay where we are.
+         */
+
+        dist = flee ? 0 : INT_MAX;
+        tp->t_nxtpos = *er;
+
+        /* Are we at our goal already? */
+
+        if (!flee && ce(tp->t_nxtpos, *ee))
+            return (FALSE);
+
+        ey = er->y + 1;
+        ex = er->x + 1;
+
+        for (x = er->x - 1; x <= ex; x++)
+            for (y = er->y - 1; y <= ey; y++)
+            {
+                coord   tryp; /* test position */
+
+                /* Don't try off the screen */
+
+                if ((x < 0) || (x >= COLS) || (y < 1) || (y >= LINES - 2))
+                    continue;
+
+                /*
+                 * Don't try the player if not going after
+                 * the player or he's disguised and monster is dumb
+                 */
+
+                if (((off(*tp, ISFLEE) && !ce(hero, *ee)) ||
+                     (on(player, ISDISGUISE) && (rnd(tp->t_stats.s_lvl) < 6))
+                     || good_monster(*tp))
+                    && x == hero.x && y == hero.y)
+                    continue;
+
+                tryp.x = x;
+                tryp.y = y;
+
+                /*
+                 * Is there a monster on this spot closer to
+                 * our goal? Don't look in our spot or where
+                 * we were.
+                 */
+
+                if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) &&
+                    isalpha( (mch = CCHAR(mvwinch(mw, y, x))) ) )
+                {
+                    int test_dist;
+
+                    test_dist = DISTANCE(tryp,*ee);
+                    if (test_dist <= 25 &&  /* Let's be fairly close */
+                        test_dist < monst_dist)
+                    {
+
+                        /* Could we really move there? */
+
+                        mvwaddch(mw, y, x, ' '); /* Temp blank monst */
+
+                        if (diag_ok(er, &tryp, tp))
+                            monst_dist = test_dist;
+
+                        mvwaddch(mw, y, x, mch);    /* Restore monster */
+                    }
+                }
+
+                if (!diag_ok(er, &tryp, tp))
+                    continue;
+
+                ch = mvwinch(cw, y, x); /* Screen character */
+
+                /*
+                 * Stepping on player is NOT okay if we are
+                 * fleeing
+                 */
+
+                if (on(*tp, ISFLEE) && (ch == PLAYER))
+				    next_player = TRUE;
+					
+                if (step_ok(y, x, NOMONST, tp) &&
+                    (off(*tp, ISFLEE) || ch != PLAYER))
+                {
+
+                    /*
+                     * If it is a trap, an intelligent
+                     * monster may not step on it (unless
+                     * our hero is on top!)
+                     */
+
+                    if (isatrap(ch))
+                    {
+                        if (!(ch == RUSTTRAP) &&
+                            !(ch == FIRETRAP && on(*tp, NOFIRE)) &&
+                            rnd(10) < tp->t_stats.s_intel &&
+                        (y != hero.y || x != hero.x))
+                            continue;
+                    }
+
+                    /*
+                     * OK -- this place counts
+                     */
+
+                    thisdist = DISTANCE(tryp, *ee);
+					
+                    /*
+                     * Adjust distance if we are being
+                     * shot at to moving out of line of sight.
+                     */
+
+                    if (tp->t_wasshot && tp->t_stats.s_intel > 5 &&
+                        ce(hero, *ee))
+                    {
+                        /* Move out of line of sight */
+                        if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, NULL))
+                        {
+                            if (flee)
+                                thisdist -= SHOTPENALTY;
+                            else
+                                thisdist += SHOTPENALTY;
+                        }
+
+                        /*
+                         * But do we want to leave
+                         * the room?
+                         */
+                        else if (rer && rer == ree && ch == DOOR)
+                            thisdist += DOORPENALTY;
+                    }
+
+                    /*
+                     * Don't move to the last position if
+                     * we can help it
+                     */
+
+                    if (ce(tryp, tp->t_oldpos))
+                        dist_to_old = thisdist;
+                    else if ((flee && (thisdist > dist)) ||
+                         (!flee && (thisdist < dist)))
+                    {
+                        tp->t_nxtpos = tryp;
+                        dist = thisdist;
+                    }
+                }
+            }
+
+        /*
+         * If we are running from the player and he is in our way, go
+         * ahead and slug him.
+         */
+
+        if (next_player && DISTANCE(*er,*ee) < dist &&
+            step_ok(tp->t_chasee->t_pos.y, tp->t_chasee->t_pos.x, NOMONST, tp))
+        {
+            tp->t_nxtpos = tp->t_chasee->t_pos;    /* Okay to hit player */
+            return(FALSE);
+        }
+
+
+        /*
+         * If we can't get closer to the player (if that's our goal)
+         * because other monsters are in the way, just stay put
+         */
+
+        if (!flee && ce(hero, *ee) && monst_dist < INT_MAX &&
+            DISTANCE(*er, hero) < dist)
+            tp->t_nxtpos = *er;
+
+        /* Do we want to go back to the last position? */
+        else if (dist_to_old != INT_MIN &&   /* It is possible to move back */
+             ((flee && dist == 0) ||        /* No other possible moves */
+              (!flee && dist == INT_MAX)))
+        {
+            /* Do we move back or just stay put (default)? */
+
+            dist = DISTANCE(*er,*ee); /* Current distance */
+
+            if (!flee || (flee && (dist_to_old > dist)))
+                tp->t_nxtpos = tp->t_oldpos;
+        }
+    }
+
+    /* Make sure we have the real distance now */
+    dist = DISTANCE(tp->t_nxtpos, *ee);
+
+    /* Mark monsters in a wall */
+
+    switch(mvinch(tp->t_nxtpos.y, tp->t_nxtpos.x))
+    {
+        case WALL:
+        case '-':
+        case '|':
+            turn_on(*tp, ISINWALL);
+            break;
+        default:
+            turn_off(*tp, ISINWALL);
+    }
+
+    if (off(*tp, ISFLEE) &&
+        !(!SAME_POS((tp->t_chasee->t_pos),hero) || off(player, ISINWALL) || on(*tp, CANINWALL)))
+        return(dist != 0);
+    else /* May actually hit here from a confused move */
+        return(!ce(tp->t_nxtpos, hero));
+}
+
+/*
+    roomin(coord *cp)
+
+        Find what room some coordinates are in.
+        NULL means they aren't in any room.
+*/
+
+struct room *
+roomin(coord cp)
+{
+    struct room *rp;
+    int i;
+
+    for (i = 0; i < MAXROOMS; i++)
+    {
+        rp = &rooms[i];
+
+        if ((cp.x <= (rp->r_pos.x + (rp->r_max.x - 1))) &&
+            (cp.y <= (rp->r_pos.y + (rp->r_max.y - 1))) &&
+            (cp.x >= rp->r_pos.x)                       &&
+            (cp.y >= rp->r_pos.y))
+        {
+            return(rp);
+        }
+    }
+
+    return(NULL);
+}
+
+/*
+ * find_mons: Find the monster from his corrdinates
+ */
+
+struct linked_list  *
+find_mons(int y, int x)
+{
+    struct linked_list  *item;
+
+    for (item = mlist; item != NULL; item = next(item))
+    {
+        struct thing *th = THINGPTR(item);
+
+        if (th->t_pos.y == y && th->t_pos.x == x)
+            return item;
+    }
+    return NULL;
+}
+
+/*
+ * Find an unfriendly monster around us to hit
+ */
+
+struct linked_list  *
+f_mons_a(int y, int x, int hit_bad)
+{
+    int row, col;
+    struct linked_list  *item;
+    struct thing    *tp;
+
+    for (row = x - 1; row <= x + 1; row++)
+        for (col = y - 1; col <= y + 1; col++)
+            if (row == x && col == y)
+                continue;
+            else if (col > 0 && row > 0 &&
+                isalpha(mvwinch(mw, col, row)) &&
+                 ((item = find_mons(col, row)) != NULL))
+            {
+                tp = THINGPTR(item);
+                if ((good_monster(*tp) && !hit_bad) ||
+                    (!good_monster(*tp) && hit_bad))
+                    return (item);
+            }
+
+    return (NULL);
+}
+
+
+/*
+    diag_ok()
+        Check to see if the move is legal if it is diagonal
+*/
+
+int
+diag_ok(coord *sp, coord *ep, struct thing *flgptr)
+{
+    if (ep->x == sp->x || ep->y == sp->y)
+        return TRUE;
+
+    return (step_ok(ep->y, sp->x, MONSTOK, flgptr) &&
+        step_ok(sp->y, ep->x, MONSTOK, flgptr));
+}
+
+/*
+    cansee()
+        returns true if the hero can see a certain coordinate.
+*/
+
+int
+cansee(int y, int x)
+{
+    struct room *rer;
+    coord   tp;
+
+    if (on(player, ISBLIND))
+        return FALSE;
+
+    tp.y = y;
+    tp.x = x;
+    rer = roomin(tp);
+
+    /*
+     * We can only see if the hero in the same room as the coordinate and
+     * the room is lit or if it is close.
+     */
+
+    return ((rer != NULL &&
+         rer == roomin(hero) &&
+         (!(rer->r_flags & ISDARK) || (rer->r_flags & HASFIRE)) &&
+         (levtype != MAZELEV || /* Maze level needs direct line */
+          maze_view(tp.y, tp.x))) ||
+        DISTANCE(tp,hero) < see_dist);
+}
+
+coord   *
+find_shoot(struct thing *tp, coord *dir)
+{
+    struct room *rtp;
+    int ulx, uly, xmx, ymx, xmon, ymon, tpx, tpy, row, col;
+    struct linked_list  *mon;
+    struct thing    *ick;
+
+    rtp = roomin(tp->t_pos);   /* Find room of chaser */
+
+    if (rtp == NULL)
+        return NULL;
+
+    ulx = rtp->r_pos.x;
+    uly = rtp->r_pos.y;
+    xmx = rtp->r_max.x;
+    ymx = rtp->r_max.y;
+
+    tpx = tp->t_pos.x;
+    tpy = tp->t_pos.y;
+
+    for (col = ulx; col < (ulx + xmx); col++)
+        for (row = uly; row < (uly + ymx); row++)
+        {
+            if (row > 0 && col > 0 && isalpha(mvwinch(mw, row, col)))
+            {
+		mon = find_mons(row, col);
+
+                if (mon)
+                {
+                    ick = THINGPTR(mon);
+                    xmon = ick->t_pos.x;
+                    ymon = ick->t_pos.y;
+
+                    if (!(good_monster(*ick)))
+                    {
+                        if (straight_shot(tpy, tpx, ymon, xmon, dir))
+                            return(dir);
+                    }
+                }
+            }
+        }
+
+    return(NULL);
+}
+
+/*
+    can_shoot()
+        determines if the monster (er) has a direct line of shot at the
+        player (ee).  If so, it returns the direction in which to shoot.
+*/
+
+coord *
+can_shoot(coord *er, coord *ee, coord *dir)
+{
+    int ery, erx, eey, eex;
+
+    /* Make sure we are chasing the player */
+
+    if (!ce((*ee), hero))
+        return(NULL);
+
+    /* They must be in the same room */
+
+    if (roomin(*er) != roomin(hero))
+        return(NULL);
+
+    ery = er->y;
+    erx = er->x;
+    eey = ee->y;
+    eex = ee->x;
+
+    /* Will shoot unless next to player, then 80% prob will fight */
+
+    if ((DISTANCE(*er,*ee) < 4) && (rnd(100) < 80))
+        return(NULL);
+
+    /* Do we have a straight shot? */
+
+    if (!straight_shot(ery, erx, eey, eex, dir))
+        return(NULL);
+    else
+        return(dir);
+}
+
+/*
+    straight_shot()
+        See if there is a straight line of sight between the two
+        given coordinates.  If shooting is not NULL, it is a pointer to a
+        structure which should be filled with the direction to shoot (if
+        there is a line of sight).  If shooting, monsters get in the way.
+        Otherwise, they do not.
+*/
+
+int
+straight_shot(int ery, int erx, int eey, int eex, coord *dir)
+{
+    int dy, dx; /* Deltas */
+    int ch;
+
+    /* Does the monster have a straight shot at player */
+
+    if ((ery != eey) && (erx != eex) &&
+        (abs(ery - eey) != abs(erx - eex)))
+        return (FALSE);
+
+    /* Get the direction to shoot */
+
+    if (eey > ery)
+        dy = 1;
+    else if (eey == ery)
+        dy = 0;
+    else
+        dy = -1;
+
+    if (eex > erx)
+        dx = 1;
+    else if (eex == erx)
+        dx = 0;
+    else
+        dx = -1;
+
+    /* Make sure we have free area all the way to the player */
+
+    ery += dy;
+    erx += dx;
+
+    while ((ery != eey) || (erx != eex))
+    {
+        switch(ch = winat(ery, erx))
+        {
+            case '|':
+            case '-':
+            case WALL:
+            case DOOR:
+            case SECRETDOOR:
+                return(FALSE);
+            default:
+                if (dir && isalpha(ch))
+                    return(FALSE);
+        }
+
+        ery += dy;
+        erx += dx;
+    }
+
+    if (dir)
+    {     /* If we are shooting -- put in the directions */
+        dir->y = dy;
+        dir->x = dx;
+    }
+
+    return(TRUE);
+}
+
+/*
+    get_hurl
+        returns the weapon that the monster will "throw" if it has one
+*/
+
+struct linked_list  *
+get_hurl(struct thing *tp)
+{
+    struct linked_list  *arrow,  *bolt,      *rock, *silverarrow, *fbbolt;
+    struct linked_list  *bullet, *firearrow, *dart, *dagger,      *shuriken;
+    struct linked_list  *oil,    *grenade;
+
+    struct linked_list  *pitem;
+    int bow = FALSE, crossbow = FALSE, sling = FALSE, footbow = FALSE;
+
+    /* Don't point to anything to begin with */
+
+    arrow = bolt = rock = silverarrow = fbbolt = NULL;
+    bullet = firearrow = dart = dagger = shuriken = NULL;
+    oil = grenade = NULL;
+
+    for (pitem = tp->t_pack; pitem != NULL; pitem = next(pitem))
+        if ((OBJPTR(pitem))->o_type == WEAPON)
+            switch ((OBJPTR(pitem))->o_which)
+            {
+                case    BOW:bow = TRUE; break;
+                case    CROSSBOW:crossbow = TRUE; break;
+                case    SLING:sling = TRUE; break;
+                case    FOOTBOW:footbow = TRUE; break;
+                case    ROCK:rock = pitem; break;
+                case    ARROW:arrow = pitem; break;
+                case    SILVERARROW:silverarrow = pitem; break;
+                case    BOLT:bolt = pitem; break;
+                case    FBBOLT:fbbolt = pitem; break;
+                case    BULLET:bullet = pitem; break;
+                case    FLAMEARROW:firearrow = pitem; break;
+                case    DART:dart = pitem; break;
+                case    DAGGER:dagger = pitem; break;
+                case    SHURIKEN:shuriken = pitem; break;
+                case    MOLOTOV:oil = pitem; break;
+                case    GRENADE:shuriken = pitem; break;
+            }
+
+    if (bow && silverarrow)
+        return(silverarrow);
+
+    if (crossbow && bolt)
+        return(bolt);
+
+    if (bow && firearrow)
+        return(firearrow);
+
+    if (off(*tp, ISCHARMED) && oil)
+        return(oil);
+		
+	if (off(*tp, ISCHARMED) && grenade)
+		return(grenade);
+
+    if (footbow && fbbolt)
+        return(fbbolt);
+
+    if (bow && arrow)
+        return(arrow);
+
+    if (sling && bullet)
+        return(bullet);
+
+    if (sling && rock)
+        return(rock);
+
+    if (shuriken)
+        return(shuriken);
+
+    if (dagger)
+        return(dagger);
+
+    if (silverarrow)
+        return(silverarrow);
+
+    if (firearrow)
+        return(firearrow);
+
+    if (fbbolt)
+        return(fbbolt);
+
+    if (bolt)
+        return(bolt);
+
+    if (bullet)
+        return(bullet);
+
+    if (dart)
+        return(dart);
+
+    if (rock)
+        return(rock);
+
+    return(NULL);
+}
+
+/*
+    pick_weap()
+        returns the biggest weapon that the monster will wield if it
+        has a non-launching or non-missile weapon returns NULL if no weapon, or
+        bare hands is better
+*/
+
+struct object *
+pick_weap(struct thing *tp)
+{
+    int weap_dam = maxdamage(tp->t_stats.s_dmg);
+    struct object   *ret_obj = NULL;
+    struct linked_list  *pitem;
+
+    if (on(*tp, CANWIELD))
+    {
+        for (pitem = tp->t_pack; pitem != NULL; pitem = next(pitem))
+        {
+            struct object   *obj = OBJPTR(pitem);
+
+            if (obj->o_type != WEAPON && !(obj->o_flags&(ISLAUNCHER|ISMISL)) &&
+                maxdamage(obj->o_damage) > weap_dam)
+            {
+                weap_dam = maxdamage(obj->o_damage);
+                ret_obj = obj;
+            }
+        }
+    }
+
+    return (ret_obj);
+}
+
+/*
+    canblink()
+        checks if the monster can teleport (blink).  If so, it will try
+        to blink the monster next to the player.
+*/
+
+int
+can_blink(struct thing *tp)
+{
+    int   y, x, index = 9;
+    coord   tryp;       /* To hold the coordinates for use in diag_ok */
+    int    spots[9], found_one = FALSE;
+
+    /*
+     * First, can the monster even blink?  And if so, there is only a 30%
+     * chance that it will do so.  And it won't blink if it is running.
+     */
+
+    if (off(*tp, CANBLINK) || (on(*tp, ISHELD)) ||
+        on(*tp, ISFLEE) ||
+        (on(*tp, ISSLOW) && off(*tp, ISHASTE) && !(tp->t_turn)) ||
+        (rnd(10) < 9))
+        return (FALSE);
+
+    /* Initialize the spots as illegal */
+
+    do
+    {
+        spots[--index] = FALSE;
+    }
+    while (index > 0);
+
+    /* Find a suitable spot next to the player */
+
+    for (y = hero.y - 1; y < hero.y + 2; y++)
+        for (x = hero.x - 1; x < hero.x + 2; x++, index++)
+        {
+            /*
+             * Make sure x coordinate is in range and that we are
+             * not at the player's position
+             */
+
+            if (x < 0 || x >= COLS || index == 4)
+                continue;
+
+            /* Is it OK to move there? */
+
+            if (!step_ok(y, x, NOMONST, tp))
+                spots[index] = FALSE;
+           else
+           {
+
+                /*
+                 * OK, we can go here.  But don't go there if
+                 * monster can't get at player from there
+                 */
+
+                tryp.y = y;
+                tryp.x = x;
+                if (diag_ok(&tryp, &hero, tp))
+                {
+                    spots[index] = TRUE;
+                    found_one = TRUE;
+                }
+            }
+        }
+
+    /* If we found one, go to it */
+
+    if (found_one)
+    {
+        /* Find a legal spot */
+
+        while (spots[index = rnd(9)] == FALSE)
+            continue;
+
+        /* Get the coordinates */
+
+        y = hero.y + (index / 3) - 1;
+        x = hero.x + (index % 3) - 1;
+
+        /* Move the monster from the old space */
+
+        mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
+
+        /* Move it to the new space */
+
+        tp->t_oldch = CCHAR( mvwinch(cw, y, x) );
+
+        if (cansee(y, x) &&
+            off(*tp, ISINWALL) &&
+            ((off(*tp, ISINVIS) &&
+              (off(*tp, ISSHADOW) || rnd(100) < 10)) || on(player, CANSEE)) &&
+            off(*tp, CANSURPRISE))
+            mvwaddch(cw, y, x, tp->t_type);
+
+        mvwaddch(mw, tp->t_pos.y,tp->t_pos.x,' '); /*Clear old position */
+        mvwaddch(mw, y, x, tp->t_type);
+        tp->t_pos.y = y;
+        tp->t_pos.x = x;
+    }
+
+    return (found_one);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/command.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1383 @@
+/*
+    command.c  -  Read and execute the user commands
+ 
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+    command()
+        Process the user commands
+*/
+
+void
+command(void)
+{
+    static char repcommand;     /* Command to repeat if we are repeating */
+    static int fight_to_death; /* Flags if we are fighting to death     */
+    static coord dir;          /* Last direction specified              */
+
+    object  *obj;
+    char     ch;
+    int      ntimes = 1; /* Number of player moves */
+    coord    nullcoord;
+
+    nullcoord.x = nullcoord.y = 0;
+
+    if (on(player, CANFLY) && rnd(2))
+        ntimes++;
+
+    if (on(player, ISHASTE))
+        ntimes++;
+
+    if (fighting && att_bonus())
+        ntimes *= 2;
+
+    if (on(player, ISSLOW))
+    {
+        if (player.t_turn != TRUE)
+            ntimes--;
+
+        player.t_turn ^= TRUE;
+    }
+
+    if (ntimes == 0)
+        return;
+
+    while (ntimes--)
+    {
+        moving = FALSE;
+
+        /* If player is infested, take off a hit point */
+
+        if (on(player, HASINFEST) && !is_wearing(R_HEALTH))
+        {
+            if ((pstats.s_hpt -= infest_dam) <= 0)
+            {
+                death(D_INFESTATION);
+                return;
+            }
+        }
+
+        look(after);
+
+        if (!running)
+            door_stop = FALSE;
+
+        status(FALSE);
+        wmove(cw, hero.y, hero.x);
+
+        if (!((running || count) && jump))
+            wrefresh(cw);   /* Draw screen */
+
+        take = 0;
+        after = TRUE;
+
+        /*
+         * Read command or continue run
+         */
+
+        if (!no_command)
+        {
+            if (fighting)
+            {
+                ch = (fight_to_death) ? 'F' : 'f';
+            }
+            else if (running)
+            {
+                /*
+                 * If in a corridor, if we are at a turn with
+                 * only one way to go, turn that way.
+                 */
+
+                if ((winat(hero.y, hero.x) == PASSAGE) && off(player, ISHUH) &&
+                    (off(player, ISBLIND)))
+                    switch (runch)
+                    {
+                        case 'h': corr_move(0, -1); break;
+                        case 'j': corr_move(1, 0); break;
+                        case 'k': corr_move(-1, 0); break;
+                        case 'l': corr_move(0, 1); break;
+                    }
+
+                ch = runch;
+            }
+            else if (count)
+                ch = repcommand;
+            else
+            {
+                ch = readchar();
+
+                if (mpos != 0 && !running)
+                    msg("");    /* Erase message if its there */
+            }
+        }
+        else
+        {
+            ch = '.';
+            fighting = moving = FALSE;
+        }
+
+        if (no_command)
+        {
+            if (--no_command == 0)
+                msg("You can move again.");
+        }
+        else
+        {
+
+            /*
+             * check for prefixes
+             */
+
+            if (isdigit(ch))
+            {
+                count = 0;
+                while (isdigit(ch))
+                {
+                    count = count * 10 + (ch - '0');
+                    ch = readcharw(cw);
+                }
+                repcommand = ch;
+
+                /*
+                 * Preserve count for commands which can be
+                 * repeated.
+                 */
+
+                switch(ch)
+                {
+                    case 'h':
+                    case 'j':
+                    case 'k':
+                    case 'l':
+                    case 'y':
+                    case 'u':
+                    case 'b':
+                    case 'n':
+                    case 'H':
+                    case 'J':
+                    case 'K':
+                    case 'L':
+                    case 'Y':
+                    case 'U':
+                    case 'B':
+                    case 'N':
+                    case 'q':
+                    case 'r':
+                    case 's':
+                    case 'm':
+                    case 't':
+                    case 'C':
+                    case 'I':
+                    case '.':
+                    case 'z':
+                    case 'p':
+                        break;
+                    default:
+                        count = 0;
+                }
+            }
+
+            /* Save current direction */
+
+            if (!running)   /* If running, it is already saved */
+                switch (ch)
+                {
+                    case 'h':
+                    case 'j':
+                    case 'k':
+                    case 'l':
+                    case 'y':
+                    case 'u':
+                    case 'b':
+                    case 'n':
+                        runch = ch;
+                        break;
+                    case 'H':
+                    case 'J':
+                    case 'K':
+                    case 'L':
+                    case 'Y':
+                    case 'U':
+                    case 'B':
+                    case 'N':
+                        runch = (char) tolower(ch);
+                        break;
+                }
+
+            /*
+             * execute a command
+             */
+
+            if (count && !running)
+                count--;
+
+            switch(ch)
+            {
+                /*
+                 * Movement and combat commands
+                 */
+
+                case 'h': do_move(0,-1); break;
+                case 'j': do_move(1, 0);  break;
+                case 'k': do_move(-1, 0); break;
+                case 'l': do_move(0, 1); break;
+                case 'y': do_move(-1, -1); break;
+                case 'u': do_move(-1, 1); break;
+                case 'b': do_move(1, -1); break;
+                case 'n': do_move(1, 1); break;
+                case 'H': do_run('h'); break;
+                case 'J': do_run('j'); break;
+                case 'K': do_run('k'); break;
+                case 'L': do_run('l'); break;
+                case 'Y': do_run('y'); break;
+                case 'U': do_run('u'); break;
+                case 'B': do_run('b'); break;
+                case 'N': do_run('n'); break;
+                case 'm':
+                    moving = TRUE;
+                    if (!get_dir())
+                    {
+                        after = FALSE;
+                        break;
+                    }
+                    do_move(delta.y, delta.x);
+                    break;
+                case 'F':
+                case 'f':
+                    fight_to_death = (ch == 'F');
+                    if (!fighting)
+                    {
+                        if (get_dir())
+                        {
+                            dir = delta;
+                            beast = NULL;
+                        }
+                        else
+                        {
+                            after = FALSE;
+                            break;
+                        }
+                    }
+                    do_fight(dir, (ch == 'F') ? TRUE : FALSE);
+                    break;
+                case 't':
+                    if (get_dir())
+                        missile(delta.y, delta.x, get_item("throw", 0),
+                            &player);
+                    else
+                        after = FALSE;
+
+                    /*
+                     * Informational commands - Do not do
+                     * after daemons
+                     */
+                     break;
+
+                case 0x7f:            /* sometime generated by */
+                                      /* suspend/foreground    */
+                case ESCAPE:
+                case ' ':
+                    after = FALSE;    /* do nothing */
+                    break;
+                case 'Q':
+                    after = FALSE;
+                    quit();
+                    break;
+                case 'i':
+                    after = FALSE;
+                    inventory(pack, '*');
+                    break;
+                case 'I':
+                    after = FALSE;
+                    inventory(pack, 0);
+                    break;
+                case '~':
+                    after = FALSE;
+                    next_exp_level(MESSAGE);
+                    break;
+                case '>':
+                    after = FALSE;
+                    d_level();
+                    break;
+                case '<':
+                    after = FALSE;
+                    u_level();
+                    break;
+                case '?':
+                    after = FALSE;
+                    help();
+                    break;
+                case '/':
+                    after = FALSE;
+                    identify();
+                    break;
+                case 'v':
+                    after = FALSE;
+                    msg("UltraRogue Version %s.", release);
+                    break;
+                case 'o':
+                    after = FALSE;
+                    option();
+                    strcpy(fd_data[1].mi_name, fruit);
+                    break;
+                case 12:    /* ctrl-l */
+                case 18:    /* ctrl-r */
+                    after = FALSE;
+                    clearok(cw, TRUE);
+					wrefresh(cw);
+                    break;
+                case 16: /* ctrl-p */
+                {
+                    int decrement = FALSE;
+                    after = FALSE;
+
+                    if (mpos == 0)
+                        decrement = TRUE;
+
+                    msg_index = (msg_index + 9) % 10;
+                    msg(msgbuf[msg_index]);
+                    if (decrement)
+                        msg_index = (msg_index + 9) % 10;
+                }
+                break;
+
+                case 'S':
+                    after = FALSE;
+                    if (save_game())
+                    {
+                        wclear(cw);
+                        wrefresh(cw);
+                        endwin();
+                        exit(0);
+                    }
+                    break;
+
+                /*
+                 * Other misc commands
+                 */
+
+                case '.':   break;   /* rest */
+                case ',':   add_pack(NULL, NOMESSAGE); break;
+                case 'q': quaff(&player, -1, ISNORMAL); break;
+                case 'r': read_scroll(&player, -1, ISNORMAL); break;
+                case 'd': drop(NULL); break;
+                case '^': set_trap(&player, hero.y, hero.x); break;
+                case 'c': incant(&player, nullcoord); break;
+                case 'D': dip_it(); break;
+                case 'e': eat(); break;
+                case '=': listen(); break;
+                case 'A': apply(); break;
+                case 'w': wield(); break;
+                case 'W': wear(); break;
+                case 'T': take_off(); break;
+                case 'P': ring_on(); break;
+                case 'R': ring_off(); break;
+                case 'p': prayer(); break;
+                case 'C': call(FALSE); break;
+                case 'M': call(TRUE); break;
+                case 's': search(FALSE); break;
+
+                /*
+                 * Directional commands - get_dir sets delta
+                 */
+                case 20:    /* ctrl-t */
+                    if (get_dir())
+                        steal();
+                    else
+                        after = FALSE;
+                    break;
+
+                case 'z':
+                    if (get_dir())
+                        do_zap(&player, -1, ISNORMAL);
+                    else
+                        after = FALSE;
+                    break;
+
+                case 'a':
+                    if (get_dir())
+                        affect();
+                    else
+                        after = FALSE;
+                    touchwin(cw);
+                    break;
+
+                /*
+                 * wizard commands
+                 */
+
+                case 0x17:    /* ctrl-w */
+                    after = FALSE;
+
+                    if (!wizard)
+                    {
+                        if (!canwizard)
+                        {
+                            msg("Illegal command '^W'.");
+                            break;
+                        }
+
+                        if (passwd())
+                        {
+                            msg("Welcome, oh mighty wizard.");
+                            wizard = waswizard = TRUE;
+                        }
+                        else
+                        {
+                            msg("Incorrect password.");
+                            break;
+                        }
+                    }
+
+                    msg("Wizard command: ");
+                    mpos = 0;
+                    ch = readchar();
+
+                    switch (ch)
+                    {
+                        case 'v':
+                            wiz_verbose = !wiz_verbose;
+                            break;
+
+                        case 'e':
+                            wizard = FALSE;
+                            msg("Not wizard any more.");
+                            break;
+
+                        case 's': activity(); break;
+                        case 't': teleport(); break;
+                        case 'm': overlay(mw, cw); break;
+                        case 'f': overlay(stdscr, cw); break;
+                        case 'i': inventory(lvl_obj, 0); break;
+                        case 'c': buy_it('\0', ISNORMAL); break;
+                        case 'I': whatis(NULL); break;
+                        case 'F':
+                             msg("food left: %d\tfood level: %d",
+                                  food_left,foodlev);
+                             break;
+                        case 'M':
+                            creat_mons(&player, get_monster_number("create"),
+                                       MESSAGE);
+                            break;
+
+                        case 'r':
+                            msg("rnd(4)%d, rnd(40)%d, rnd(100)%d",
+                                 rnd(4), rnd(40), rnd(100));
+                            break;
+
+                        case 'C':
+                            obj = get_object(pack, "charge", STICK, NULL);
+
+                            if (obj != NULL)
+                                obj->o_charges = 10000;
+
+                            break;
+
+                        case 'w':
+                            obj = get_object(pack, "price", 0, NULL);
+
+                            if (obj != NULL)
+                                msg("Worth %d.", get_worth(obj));
+
+                            break;
+
+                        case 'g':
+                            {
+                                int tlev;
+
+                                prbuf[0] = '\0';
+                                msg("Which level? ");
+
+                                if (get_string(prbuf, cw) == NORM)
+                                {
+                                    msg("");
+
+                                    if ((tlev = atoi(prbuf)) < 1)
+                                        msg("Illegal level.");
+                                    else if (tlev > 3000)
+                                    {
+                                        levtype = THRONE;
+                                        level = tlev - 3000;
+                                    }
+                                    else if (tlev > 2000)
+                                    {
+                                        levtype = MAZELEV;
+                                        level = tlev - 2000;
+                                    }
+                                    else if (tlev > 1000)
+                                    {
+                                        levtype = POSTLEV;
+                                        level = tlev - 1000;
+                                    }
+                                    else
+                                    {
+                                        levtype = NORMLEV;
+                                        level = tlev;
+                                    }
+
+                                    new_level(levtype,0);
+                                }
+                            }
+                            break;
+
+                        case 'o':   make_omnipotent(); break;
+
+                        case ESCAPE: /* Escape */
+                            door_stop = FALSE;
+
+                            count = 0;
+                            after = FALSE;
+                            break;
+
+                        default:
+                            msg("Illegal wizard command '%s', %d.",
+                                unctrl(ch), ch);
+                            count = 0;
+                            break;
+
+                    }
+
+                break;
+
+                default:
+                    msg("Illegal command '%s', %d.",
+                        unctrl(ch), ch);
+                    count = 0;
+                    after = FALSE;
+                    break;
+            }
+
+            /*
+             * turn off flags if no longer needed
+             */
+            if (!running)
+                door_stop = FALSE;
+        }
+
+        /*
+         * If he ran into something to take, let him pick it up.
+         */
+        if (take != 0)
+            if (!moving)
+                pick_up(take);
+            else
+                show_floor();
+        if (!running)
+            door_stop = FALSE;
+    } /* end while */
+}
+
+
+void
+do_after_effects(void)
+{
+    int i;
+
+    /* Kick off the rest of the daemons and fuses */
+
+    look(FALSE);
+    do_daemons(AFTER);
+    do_fuses(AFTER);
+
+    /* Special abilities */
+
+    if ((player.t_ctype == C_THIEF || player.t_ctype == C_ASSASIN ||
+     player.t_ctype == C_NINJA || player.t_ctype == C_RANGER) &&
+     (rnd(100) < (2 * pstats.s_dext + 5 * pstats.s_lvl)))
+        search(TRUE);
+
+    for (i = 0; i < ring_value(R_SEARCH); i++)
+        search(FALSE);
+
+    if (is_wearing(R_TELEPORT) && rnd(50) < 2)
+    {
+        teleport();
+
+        if (off(player, ISCLEAR))
+        {
+            if (on(player, ISHUH))
+                lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION);
+            else
+                light_fuse(FUSE_UNCONFUSE, 0, rnd(8) + HUHDURATION, AFTER);
+
+            turn_on(player, ISHUH);
+        }
+        else
+            msg("You feel dizzy for a moment, but it quickly passes.");
+    }
+
+    /* accidents and general clumsiness */
+
+    if (fighting && rnd(50) == 0)
+    {
+        msg("You become tired of this nonsense.");
+        fighting = after = FALSE;
+    }
+
+    if (on(player, ISELECTRIC))
+        electrificate();
+
+    if (!fighting && (no_command == 0) && cur_weapon != NULL
+        && rnd(on(player, STUMBLER) ? 399 : 9999) == 0
+        && rnd(pstats.s_dext) <
+        2 - hitweight() + (on(player, STUMBLER) ? 4 : 0))
+    {
+        msg("You trip and stumble over your weapon.");
+        running = after = FALSE;
+
+        if (rnd(8) == 0 && (pstats.s_hpt -= roll(1, 10)) <= 0)
+        {
+            msg("You break your neck and die.");
+            death(D_FALL);
+            return;
+        }
+        else if (cur_weapon->o_flags & ISPOISON && rnd(4) == 0)
+        {
+            msg("You are cut by your %s!",
+                inv_name(cur_weapon, LOWERCASE));
+
+            if (player.t_ctype != C_PALADIN
+                && !(player.t_ctype == C_NINJA &&
+                pstats.s_lvl > 12)
+                && !save(VS_POISON))
+            {
+                if (pstats.s_hpt == 1)
+                {
+                    msg("You die from the poison in the cut.");
+                    death(D_POISON);
+                    return;
+                }
+                else
+                {
+                    msg("You feel very sick now.");
+                    pstats.s_hpt /= 2;
+                    chg_str(-2, FALSE, FALSE);
+                }
+            }
+       }
+   }
+
+   /* Time to enforce weapon and armor restrictions */
+   if (rnd(9999) == 0)
+        if (((cur_weapon == NULL) ||
+            (wield_ok(&player, cur_weapon, NOMESSAGE)))
+            && ((cur_armor == NULL) ||
+            (wear_ok(&player, cur_armor, NOMESSAGE))))
+        {
+            switch (player.t_ctype)
+            {
+                case C_CLERIC:
+                case C_DRUID:
+                case C_RANGER:
+                case C_PALADIN:
+                    if (rnd(luck) != 0)
+                        /* You better have done
+                         * little wrong */
+                        goto bad_cleric;
+
+                    msg("You are enraptured by the renewed "
+                        "power of your god.");
+                    break;
+
+                case C_MAGICIAN:
+                case C_ILLUSION:
+                    msg("You become in tune with the universe.");
+                    break;
+
+                case C_THIEF:
+                case C_NINJA:
+                case C_ASSASIN:
+                    msg("You become supernaly sensitive to your "
+                        "surroundings.");
+                    break;
+
+                case C_FIGHTER:
+                    msg("You catch your second wind.");
+                    break;
+
+                default:
+                    msg("What a strange type you are!");
+                    break;
+           }
+           pstats.s_hpt = max_stats.s_hpt += rnd(pstats.s_lvl) + 1;
+            pstats.s_power = max_stats.s_power += rnd(pstats.s_lvl) + 1;
+        }
+        else
+        {   /* he blew it - make him pay */
+
+            int death_cause = 0;
+
+            switch (player.t_ctype)
+            {
+                case C_CLERIC:
+                case C_DRUID:
+                case C_RANGER:
+                case C_PALADIN:
+            bad_cleric:
+                    msg("Your god scourges you for your misdeeds.");
+                    death_cause = D_GODWRATH;
+                    break;
+
+                case C_MAGICIAN:
+                case C_ILLUSION:
+                    msg("You short out your manna on the unfamiliar %s.",
+                        (cur_armor != NULL ? "armor" : "weapon"));
+
+                   death_cause = D_SPELLFUMBLE;
+                   break;
+
+                case C_THIEF:
+                case C_NINJA:
+                case C_ASSASIN:
+                    msg("You trip and fall because of the unfamiliar %s.",
+                        (cur_armor != NULL ? "armor" : "weapon"));
+                    death_cause = D_CLUMSY;
+                    break;
+
+                case C_FIGHTER:
+                    debug("Fighter getting raw deal?");
+                   break;
+
+                default:
+                    msg("What a strange type you are!");
+                    break;
+            }
+
+            aggravate();
+            pstats.s_power /= 2;
+            pstats.s_hpt /= 2;
+            player.t_no_move++;
+
+            if ((pstats.s_hpt -= rnd(pstats.s_lvl)) <= 0)
+            {
+                death(death_cause);
+            }
+        }
+
+    if (rnd(500000) == 0)
+    {
+        new_level(THRONE,0);
+        fighting = running = after = FALSE;
+        command();
+    }
+}
+
+void
+make_omnipotent(void)
+{
+    int i;
+    struct linked_list  *item;
+    struct object *obj;
+
+    for (i = 0; i < 20; i++)
+        raise_level();
+
+    max_stats.s_hpt += 1000;
+    max_stats.s_power += 1000;
+    pstats.s_hpt = max_stats.s_hpt;
+    pstats.s_power = max_stats.s_power;
+    max_stats.s_str = pstats.s_str = 25;
+    max_stats.s_intel = pstats.s_intel = 25;
+    max_stats.s_wisdom = pstats.s_wisdom = 25;
+    max_stats.s_dext = pstats.s_dext = 25;
+    max_stats.s_const = pstats.s_const = 25;
+
+    if (cur_weapon == NULL || cur_weapon->o_which != CLAYMORE)
+    {
+        item = spec_item(WEAPON, CLAYMORE, 10, 10);
+        cur_weapon = OBJPTR(item);
+        cur_weapon->o_flags |= ISKNOW;
+        add_pack(item, NOMESSAGE);
+    }
+
+    /* and a kill-o-zap stick */
+
+    item = spec_item(STICK, WS_DISINTEGRATE, 10000, 0);
+    obj = OBJPTR(item);
+    obj->o_flags |= ISKNOW;
+    know_items[TYP_STICK][WS_DISINTEGRATE] = TRUE;
+
+    if (guess_items[TYP_STICK][WS_DISINTEGRATE])
+    {
+        ur_free(guess_items[TYP_STICK][WS_DISINTEGRATE]);
+        guess_items[TYP_STICK][WS_DISINTEGRATE] = NULL;
+    }
+
+    add_pack(item, NOMESSAGE);
+
+    /* and his suit of armor */
+
+    if (cur_armor == NULL ||
+        !(cur_armor->o_which == CRYSTAL_ARMOR ||
+          cur_armor->o_which == MITHRIL))
+    {
+        item = spec_item(ARMOR, CRYSTAL_ARMOR, 15, 0);
+        obj = OBJPTR(item);
+        obj->o_flags |= ISKNOW;
+        obj->o_weight =
+            (int) (armors[CRYSTAL_ARMOR].a_wght * 0.2);
+        cur_armor = obj;
+        add_pack(item, NOMESSAGE);
+    }
+
+    /* and some rings (have to put them on, for now) */
+
+
+    if (!is_wearing(R_SEARCH))
+    {
+        item = spec_item(RING, R_SEARCH, 0, 0);
+        obj = OBJPTR(item);
+        obj->o_flags |= ISKNOW;
+        know_items[TYP_RING][R_SEARCH] = TRUE;
+
+        if (guess_items[TYP_RING][R_SEARCH])
+        {
+            ur_free(guess_items[TYP_RING][R_SEARCH]);
+            guess_items[TYP_RING][R_SEARCH] = NULL;
+        }
+
+        add_pack(item, NOMESSAGE);
+    }
+
+    if (!is_wearing(R_PIETY))
+    {
+        item = spec_item(RING, R_PIETY, 0, 0);
+        obj = OBJPTR(item);
+        obj->o_flags |= ISKNOW;
+        know_items[TYP_RING][R_PIETY] = TRUE;
+
+        if (guess_items[TYP_RING][R_PIETY])
+        {
+            ur_free(guess_items[TYP_RING][R_PIETY]);
+            guess_items[TYP_RING][R_PIETY] = NULL;
+        }
+
+        add_pack(item, NOMESSAGE);
+    }
+
+    item = spec_item(SCROLL, S_ELECTRIFY, 0, 0);
+    obj = OBJPTR(item);
+    obj->o_flags |= ISKNOW;
+    know_items[TYP_SCROLL][S_ELECTRIFY] = TRUE;
+
+    if (guess_items[TYP_SCROLL][S_ELECTRIFY])
+    {
+        ur_free(guess_items[TYP_SCROLL][S_ELECTRIFY]);
+        guess_items[TYP_SCROLL][S_ELECTRIFY] = NULL;
+    }
+
+    add_pack(item, NOMESSAGE);
+
+    /* Spiff him up a bit */
+    quaff(&player, P_SHERO, ISBLESSED);
+    quaff(&player, P_CLEAR, ISBLESSED);
+    quaff(&player, P_FIRERESIST, ISBLESSED);
+    quaff(&player, P_TRUESEE, ISBLESSED);
+    quaff(&player, P_PHASE, ISBLESSED);
+    purse += 50000L;
+    updpack();
+}
+
+
+/*
+    quit()
+        Have player make certain, then exit.
+*/
+
+void
+quit_handler(int sig)
+{
+    if (signal(SIGINT, quit_handler) != quit_handler)
+        mpos = 0;
+
+    sig = 0;
+
+    quit();
+}
+
+void
+quit(void)
+{
+    msg("Really quit?");
+
+    wrefresh(cw);
+
+    if (readchar() == 'y')
+    {
+        clear();
+        wclear(cw);
+        wrefresh(cw);
+        move(LINES - 1, 0);
+        wrefresh(stdscr);
+        score(pstats.s_exp, pstats.s_lvl, CHICKEN, 0);
+        byebye();
+    }
+    else
+    {
+        signal(SIGINT, quit_handler);
+        wmove(cw, 0, 0);
+        wclrtoeol(cw);
+        status(FALSE);
+        wrefresh(cw);
+        mpos = 0;
+        count = 0;
+        fighting = running = 0;
+    }
+}
+
+/*
+    search()
+        Player gropes about him to find hidden things.
+*/
+
+void
+search(int is_thief)
+{
+    int x, y;
+    char ch;
+
+    /*
+     * Look all around the hero, if there is something hidden there, give
+     * him a chance to find it.  If its found, display it.
+     */
+
+    if (on(player, ISBLIND))
+        return;
+
+    for (x = hero.x - 1; x <= hero.x + 1; x++)
+        for (y = hero.y - 1; y <= hero.y + 1; y++)
+        {
+            ch = winat(y, x);
+
+            if (isatrap(ch))
+            {
+                static char trname[1024]; /* temp scratch space */
+                struct trap *tp;
+                struct room *rp;
+
+                if (isatrap( mvwinch(cw, y, x)))
+                    continue;
+
+                tp = trap_at(y, x);
+
+                if ((tp->tr_flags & ISTHIEFSET) ||
+                    (rnd(100) > 50 && !is_thief))
+                    break;
+
+                rp = roomin(hero);
+
+                if (tp->tr_type == FIRETRAP && rp != NULL)
+                {
+                    rp->r_flags &= ~ISDARK;
+                    light(&hero);
+                }
+
+                tp->tr_flags |= ISFOUND;
+                mvwaddch(cw, y, x, ch);
+                count = 0;
+                running = FALSE;
+                msg(tr_name(tp->tr_type,trname));
+            }
+            else if (ch == SECRETDOOR)
+            {
+                if (rnd(100) < 20 && !is_thief)
+                {
+                    mvaddch(y, x, DOOR);
+                    count = 0;
+                }
+            }
+        }
+}
+
+/*
+    help()
+        Give single character help, or the whole mess if he wants it
+*/
+
+void
+help(void)
+{
+    const struct h_list *strp = helpstr;
+    char helpch;
+    int cnt;
+
+    msg("Character you want help for (* for all): ");
+    helpch = readchar();
+    mpos = 0;
+
+    /*
+     * If its not a *, print the right help string or an error if he
+     * typed a funny character.
+     */
+
+    if (helpch != '*')
+    {
+        wmove(cw, 0, 0);
+
+        while (strp->h_ch)
+        {
+            if (strp->h_desc == 0)
+                if (!wizard)
+                    break;
+                else
+                {
+                    strp++;
+                    continue;
+                }
+
+            if (strp->h_ch == helpch)
+            {
+                msg("%s%s", unctrl(strp->h_ch), strp->h_desc);
+                break;
+            }
+            strp++;
+        }
+
+        if (strp->h_ch != helpch)
+            msg("Unknown character '%s'.", unctrl(helpch));
+
+        return;
+    }
+
+    /*
+     * Here we print help for everything. Then wait before we return to
+     * command mode
+     */
+
+    wclear(hw);
+    cnt = 0;
+
+    while (strp->h_ch)
+    {
+        if (strp->h_desc == 0)
+            if (!wizard)
+                break;
+            else
+            {
+                strp++;
+                continue;
+            }
+
+        mvwaddstr(hw, cnt % 23, cnt > 22 ? 40 : 0, unctrl(strp->h_ch));
+        waddstr(hw, strp->h_desc);
+        strp++;
+
+        if (++cnt >= 46 && strp->h_ch && (strp->h_desc != NULL || wizard))
+        {
+            wmove(hw, LINES - 1, 0);
+            wprintw(hw, (char *) morestr);
+            wrefresh(hw);
+            wait_for(' ');
+            wclear(hw);
+            cnt = 0;
+        }
+    }
+
+    wmove(hw, LINES - 1, 0);
+    wprintw(hw, (char *) morestr);
+    wrefresh(hw);
+    wait_for(' ');
+    wclear(hw);
+    wrefresh(hw);
+
+    wmove(cw, 0, 0);
+    wclrtoeol(cw);
+    status(FALSE);
+    touchwin(cw);
+
+    return;
+}
+
+/*
+    identify()
+        Tell the player what a certain thing is.
+*/
+
+void
+identify(void)
+{
+    int   ch;
+    char *str;
+
+    msg("What do you want identified? ");
+    mpos = 0;
+
+    if ((ch = readchar()) == ESCAPE)
+    {
+        msg("");
+        return;
+    }
+
+    if (isalpha(ch))
+    {
+        id_monst(ch);
+        return;
+    }
+
+    switch (ch)
+    {
+        case '|':
+        case '-':        str = "wall of a room";                 break;
+        case GOLD:       str = "gold";                           break;
+        case STAIRS:     str = "passage leading down";           break;
+        case DOOR:       str = "door";                           break;
+        case FLOOR:      str = "room floor";                     break;
+        case VPLAYER:    str = "The hero of the game ---> you";  break;
+        case IPLAYER:    str = "you (but invisible)";            break;
+        case PASSAGE:    str = "passage";                        break;
+        case POST:       str = "trading post";                   break;
+        case POOL:       str = "a shimmering pool";              break;
+        case TRAPDOOR:   str = "trapdoor";                       break;
+        case ARROWTRAP:  str = "arrow trap";                     break;
+        case SLEEPTRAP:  str = "sleeping gas trap";              break;
+        case BEARTRAP:   str = "bear trap";                      break;
+        case TELTRAP:    str = "teleport trap";                  break;
+        case DARTTRAP:   str = "dart trap";                      break;
+        case MAZETRAP:   str = "entrance to a maze";             break;
+        case FIRETRAP:   str = "fire trap";                      break;
+        case POISONTRAP: str = "poison pool trap";               break;
+        case LAIR:       str = "monster lair entrance";          break;
+        case RUSTTRAP:   str = "rust trap";                      break;
+        case POTION:     str = "potion";                         break;
+        case SCROLL:     str = "scroll";                         break;
+        case FOOD:       str = "food";                           break;
+        case WEAPON:     str = "weapon";                         break;
+        case ' ':        str = "solid rock";                     break;
+        case ARMOR:      str = "armor";                          break;
+        case ARTIFACT:   str = "an artifact from bygone ages";   break;
+        case RING:       str = "ring";                           break;
+        case STICK:      str = "wand or staff";                  break;
+        default:         str = "unknown character";              break;
+    }
+    msg("'%s'; %s", unctrl(ch), str);
+}
+
+/*
+    d_level()
+        He wants to go down a level
+*/
+
+void
+d_level(void)
+{
+    int no_phase = FALSE;
+
+    if (mvinch(hero.y, hero.x) != STAIRS)
+    {
+        if (off(player, CANINWALL))  /* Must use stairs if can't phase */
+        {
+            msg("I see no way down.");
+            return;
+        }
+
+        extinguish_fuse(FUSE_UNPHASE);/*Using phase to go down gets rid of it*/
+        no_phase = TRUE;
+    }
+
+    if (is_wearing(R_LEVITATION) || on(player, CANFLY))
+    {
+        msg("You can't!  You're floating in the air.");
+        return;
+    }
+
+    if (rnd(pstats.s_dext) < 3 * (2 - hitweight() +
+        (on(player, STUMBLER) ? 4 : 0)))
+    {
+        msg("You trip and fall down the stairs.");
+
+        if ((pstats.s_hpt -= roll(1, 10)) <= 0)
+        {
+            msg("You break your neck and die.");
+            death(D_FALL);
+            return;
+        }
+    }
+
+    level++;
+    new_level(NORMLEV,0);
+
+    if (no_phase)
+        unphase(NULL);
+
+    return;
+}
+
+/*
+    u_level()
+        He wants to go up a level
+*/
+
+void
+u_level(void)
+{
+    char ch = 0;
+
+    if (has_artifact && ((ch = CCHAR(mvinch(hero.y, hero.x))) == STAIRS ||
+                 (on(player, CANINWALL)
+            && (is_wearing(R_LEVITATION) || on(player, CANFLY)))))
+    {
+        if (--level == 0)
+            total_winner();
+        else if (rnd(wizard ? 3 : 15) == 0)
+            new_level(THRONE,0);
+        else
+        {
+            new_level(NORMLEV,0);
+            msg("You feel a wrenching sensation in your gut.");
+        }
+
+        if (on(player, CANINWALL) && ch != STAIRS)
+        {
+            extinguish_fuse(FUSE_UNPHASE);
+            unphase(NULL);
+        }
+
+        return;
+    }
+    else if (ch != STAIRS &&
+         !(on(player, CANINWALL) && (is_wearing(R_LEVITATION)
+                         || on(player, CANFLY))))
+        msg("I see no way up.");
+    else
+        msg("Your way is magically blocked.");
+
+    return;
+}
+
+/*
+    call()
+        allow a user to call a potion, scroll, or ring something
+*/
+
+void
+call(int mark)
+{
+    struct object    *obj;
+    char             *elsewise;
+    int item_type =   numthings;
+    char            **item_color = NULL;
+
+    if (mark)
+        obj = get_object(pack, "mark", 0, bff_markable);
+    else
+        obj = get_object(pack, "call", 0, bff_callable);
+
+    if (obj == NULL)
+        return;
+
+    switch (obj->o_type)
+    {
+        case RING:
+            item_type = TYP_RING;
+            item_color = r_stones;
+            break;
+        case POTION:
+            item_type = TYP_POTION;
+            item_color = p_colors;
+            break;
+        case SCROLL:
+            item_type = TYP_SCROLL;
+            item_color = s_names;
+            break;
+        case STICK:
+            item_type = TYP_STICK;
+            item_color = ws_made;
+        default:
+            if (!mark)
+            {
+                msg("You can't call that anything.");
+                return;
+            }
+            break;
+    }
+
+    elsewise = (guess_items[item_type][obj->o_which] != NULL ?
+       guess_items[item_type][obj->o_which] : item_color[obj->o_which]);
+
+    if (know_items[item_type][obj->o_which] && !mark)
+    {
+        msg("That has already been identified.");
+        return;
+    }
+
+    if (mark)
+    {
+        if (obj->o_mark[0])
+            msg("Was marked \"%s\".", obj->o_mark);
+
+        msg("What do you want to mark it? ");
+        prbuf[0] = '\0';
+    }
+    else
+    {
+        msg("Was called \"%s\".", elsewise);
+        msg("What do you want to call it? ");
+
+        if (guess_items[item_type][obj->o_which] != NULL)
+            ur_free(guess_items[item_type][obj->o_which]);
+
+        strcpy(prbuf, elsewise);
+    }
+
+    if (get_string(prbuf, cw) == NORM)
+    {
+        if (mark)
+        {
+            strncpy(obj->o_mark, prbuf, MARKLEN - 1);
+            obj->o_mark[MARKLEN - 1] = '\0';
+        }
+        else
+        {
+            guess_items[item_type][obj->o_which] = new_alloc(strlen(prbuf) + 1);
+            strcpy(guess_items[item_type][obj->o_which], prbuf);
+        }
+    }
+
+    return;
+}
+
+/*
+    att_bonus()
+        bonus attacks for certain player classes
+*/
+
+int
+att_bonus(void)
+{
+    int bonus = FALSE;
+
+    if ((player.t_ctype == C_FIGHTER || player.t_ctype == C_PALADIN)
+            && (pstats.s_lvl > 12 ||
+            (pstats.s_lvl > 6 && pstats.s_lvl < 13 && rnd(2))))
+        bonus = TRUE;
+
+    else if ((player.t_ctype == C_RANGER)
+             && (pstats.s_lvl > 14 ||
+             (pstats.s_lvl > 7 && pstats.s_lvl < 15 && rnd(2))))
+        bonus = TRUE;
+
+    else if ((player.t_ctype == C_NINJA)
+             && (pstats.s_lvl > 8 ||
+             (pstats.s_lvl > 4 && pstats.s_lvl < 9 && rnd(2))))
+        bonus = TRUE;
+
+    return(bonus);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/daemon.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,327 @@
+/*
+    daemon.c - functions for dealing with things that happen in the future
+ 
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+/*
+        Needs to be rewritten again to work on a per creature basis.
+        Either each monster will have a list of effect, or each
+        fuse will take a creature pointer and multiple entries
+        for each fuse will be allowed. I tend to want to attach
+        the effects to the creature.
+*/
+
+#include "rogue.h"
+
+int demoncnt;
+
+struct daemon daemons[DAEMON_MAX] =
+{
+    { DAEMON_NULL,       NULL         },
+    { DAEMON_DOCTOR,     doctor       },
+    { DAEMON_ROLLWAND,   rollwand     },
+    { DAEMON_STOMACH,    stomach      },
+    { DAEMON_RUNNERS,    runners      }
+};
+
+struct fuse fuses[FUSE_MAX] =
+{
+    { FUSE_NULL,         NULL         },
+    { FUSE_SWANDER,      swander      },
+    { FUSE_UNCONFUSE,    unconfuse    },
+    { FUSE_UNSCENT,      unscent      },
+    { FUSE_SCENT,        scent        },
+    { FUSE_UNHEAR,       unhear       },
+    { FUSE_HEAR,         hear         },
+    { FUSE_UNSEE,        unsee        },
+    { FUSE_UNSTINK,      unstink      },
+    { FUSE_UNCLRHEAD,    unclrhead    },
+    { FUSE_UNPHASE,      unphase      },
+    { FUSE_SIGHT,        sight        },
+    { FUSE_RES_STRENGTH, res_strength },
+    { FUSE_NOHASTE,      nohaste      },
+    { FUSE_NOSLOW,       noslow       },
+    { FUSE_SUFFOCATE,    suffocate    },
+    { FUSE_CURE_DISEASE, cure_disease },
+    { FUSE_UNITCH,       un_itch      },
+    { FUSE_APPEAR,       appear       },
+    { FUSE_UNELECTRIFY,  unelectrify  },
+    { FUSE_UNBHERO,      unbhero      },
+    { FUSE_UNSHERO,      unshero      },
+    { FUSE_UNXRAY,       NULL         },
+    { FUSE_UNDISGUISE,   undisguise   },
+    { FUSE_SHERO,        shero        },
+    { FUSE_WGHTCHK,      wghtchk      },
+    { FUSE_UNSUMMON,     unsummon     },
+    { FUSE_UNGAZE,       ungaze       },
+    { FUSE_UNCOLD,       uncold       },
+    { FUSE_UNHOT,        unhot        },
+    { FUSE_UNFLY,        unfly        },
+    { FUSE_UNBREATHE,    unbreathe    },
+    { FUSE_UNREGEN,      unregen      },
+    { FUSE_UNSUPEREAT,   unsupereat   },
+    { FUSE_UNSHIELD,     unshield     },
+    { FUSE_UNMSHIELD,    unmshield    },
+    { FUSE_UNTRUESEE,    untruesee    }
+};
+
+/*
+    d_slot()
+        Find an empty slot in the daemon/fuse list
+*/
+
+struct delayed_action *
+d_slot(void)
+{
+    int i;
+    struct delayed_action *dev;
+
+    for (i = 0, dev = d_list; i < MAXDAEMONS; i++, dev++)
+        if (dev->d_type == EMPTY)
+            return(dev);
+
+    return(NULL);
+}
+
+
+/*
+     find_slot()
+         Find a particular slot in the table
+*/
+
+struct delayed_action *
+find_slot(int type, int id)
+{
+    int i;
+    struct delayed_action *dev;
+
+    for (i = 0, dev = d_list; i < MAXDAEMONS; i++, dev++)
+        if ( (dev->d_type == type) && (id == dev->d_id) )
+            return(dev);
+
+    return(NULL);
+}
+
+
+/*
+    daemon()
+        Start a daemon, takes a function.
+*/
+
+void
+start_daemon(int id, void *arg, int whendo)
+{
+    struct delayed_action *dev;
+
+    dev = d_slot();
+
+    if (dev != NULL)
+    {
+        dev->d_type = DAEMON;
+        dev->d_when = whendo;
+        dev->d_id = id;
+        dev->d_arg = arg;
+        dev->d_time = 1;
+        demoncnt += 1;  /* update count */
+    }
+}
+
+
+/*
+    kill_daemon()
+        Remove a daemon from the list
+*/
+
+void
+kill_daemon(int id)
+{
+    struct delayed_action *dev;
+
+    if ((dev = find_slot(DAEMON, id)) == NULL)
+        return;
+
+    /* Take it out of the list */
+
+    dev->d_type = EMPTY;
+    demoncnt -= 1;      /* update count */
+
+    return;
+}
+
+
+/*
+    do_daemons()
+        Run all the daemons that are active with the current flag,
+        passing the argument to the function.
+*/
+
+void
+do_daemons(int now)
+{
+    struct delayed_action *dev;
+
+    /* Loop through the devil list */
+
+    for (dev = d_list; dev < &d_list[MAXDAEMONS]; dev++)
+        /* Executing each one, giving it the proper arguments */
+        if ( (dev->d_when == now) && (dev->d_type == DAEMON))
+        {
+            if ((dev->d_id < 1) || (dev->d_id >= DAEMON_MAX))
+                printf("Bad daemon id %d\n", dev->d_id);
+            else if (daemons[dev->d_id].func == NULL)
+                printf("No action for daemon %d!!!\n", dev->d_id);
+            else
+            {
+                daemon_arg arg;
+				
+                arg.varg = dev->d_arg;
+                daemons[dev->d_id].func(&arg);
+            }
+        }
+
+}
+
+
+/*
+    fuse()
+        Start a fuse to go off in a certain number of turns
+*/
+
+void
+light_fuse(int id, void *arg, int time, int whendo)
+{
+    struct delayed_action   *wire;
+
+    wire = d_slot();
+
+    if (wire != NULL)
+    {
+        wire->d_type = FUSE;
+        wire->d_when = whendo;
+        wire->d_id   = id;
+        wire->d_arg  = arg;
+        wire->d_time = time;
+        demoncnt += 1;  /* update count */
+    }
+}
+
+
+/*
+    lengthen()
+        Increase the time until a fuse goes off
+*/
+
+void
+lengthen_fuse(int id, int xtime)
+{
+    struct delayed_action *wire;
+
+    if ((wire = find_slot(FUSE,id)) == NULL)
+        return;
+
+    wire->d_time += xtime;
+
+    return;
+}
+
+
+/*
+    extinguish()
+        Put out a fuse
+*/
+
+void
+extinguish_fuse(int id)
+{
+    struct delayed_action   *wire;
+
+    if ((wire = find_slot(FUSE,id)) == NULL)
+        return;
+
+    wire->d_type = EMPTY;
+    demoncnt -= 1;
+
+    return;
+}
+
+
+/*
+    do_fuses()
+        Decrement counters and start needed fuses
+*/
+
+void
+do_fuses(int now)
+{
+    struct delayed_action   *wire;
+
+    /* Step though the list */
+
+    for (wire = d_list; wire < &d_list[MAXDAEMONS]; wire++)
+    {
+        /*
+         * Decrementing counters and starting things we want.  We
+         * also need to remove the fuse from the list once it has
+         * gone off.
+         */
+
+        if( (wire->d_type == FUSE) && (wire->d_when == now) )
+        {
+            if (--wire->d_time <= 0)
+            {
+                fuse_arg arg;
+
+                arg.varg = wire->d_arg;
+                wire->d_type = EMPTY;
+                fuses[wire->d_id].func(&arg);
+                demoncnt -= 1;
+            }
+        }
+
+    }
+
+    return;
+}
+
+
+/*
+    activity()
+        Show wizard number of demaons and memory blocks used
+*/
+
+void
+activity(void)
+{
+    msg("Daemons = %d : Memory Items = %d ", demoncnt, total);
+    return;
+}
+
+/*
+    waste_time()
+        Do nothing but let other things happen
+*/
+
+void
+waste_time(void)
+{
+    if (inwhgt)     /* if from wghtchk then done */
+        return;
+
+    do_daemons(BEFORE);
+    do_fuses(BEFORE);
+    do_daemons(AFTER);
+    do_fuses(AFTER);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/daemons.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,999 @@
+/*
+    daemons.c - All the daemon and fuse functions are in here
+  
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include "rogue.h"
+
+/*
+    doctor()
+        A healing daemon that restors spell and hit points after rest
+*/
+
+void
+doctor(daemon_arg *who)
+{
+    struct thing *tp = who->thingptr;
+    long ohp;   /* turn off ISFLEE? */
+    struct stats *curp;  /* current stats pointer */
+    struct stats *maxp;  /* max stats pointer */
+    int         turns_quiet, new_points;
+
+    curp = &(tp->t_stats);
+    maxp = &(tp->maxstats);
+
+    if (on(*tp, ISINWALL))
+    {
+        tp->t_rest_hpt = 0;
+        return;
+    }
+
+    /* Check for regenerating spell points first */
+
+    doctor_spell_points(tp);
+
+    if (curp->s_hpt == maxp->s_hpt)
+    {
+        tp->t_rest_hpt = 0;
+        return;
+    }
+
+    tp->t_rest_hpt++;
+
+    switch (tp->t_ctype)
+    {
+        case C_MAGICIAN:
+        case C_ILLUSION:
+            turns_quiet = 24 - curp->s_lvl;
+            new_points = curp->s_lvl / 2 - 4;
+            break;
+
+        case C_THIEF:
+        case C_ASSASIN:
+        case C_NINJA:
+            turns_quiet = 16 - curp->s_lvl;
+            new_points = curp->s_lvl / 2 - 1;
+            break;
+
+        case C_CLERIC:
+        case C_DRUID:
+            turns_quiet = 16 - curp->s_lvl;
+            new_points = curp->s_lvl / 2 - 2;
+            break;
+
+        case C_FIGHTER:
+        case C_RANGER:
+        case C_PALADIN:
+            turns_quiet = 8 - curp->s_lvl / 2;
+            new_points = curp->s_lvl / 2 - 1;
+            break;
+
+        case C_MONSTER:
+            turns_quiet = 16 - curp->s_lvl;
+            new_points = curp->s_lvl / 2 - 6;
+            break;
+
+        default:
+            debug("What a strange character you are!");
+            return;
+    }
+
+    ohp = curp->s_hpt;
+
+    if (off(*tp, HASDISEASE))
+    {
+        if (curp->s_lvl < 8)
+        {
+            if (tp->t_rest_hpt > turns_quiet)
+                curp->s_hpt++;
+        }
+        else if (tp->t_rest_hpt >= 15)
+            curp->s_hpt += rnd(new_points) + 1;
+    }
+
+    if (tp == &player)
+    {
+        if (curp->s_lvl > 10)
+            turns_quiet = 2;
+        else
+            turns_quiet = rnd(turns_quiet / 6) + 1;
+
+        if (is_wearing(R_REGEN))
+            curp->s_hpt += ring_value(R_REGEN);
+    }
+
+    if (on(*tp, ISREGEN))
+        curp->s_hpt += curp->s_lvl / 5 + 1;
+
+    if (ohp != curp->s_hpt)
+    {
+        if (curp->s_hpt >= maxp->s_hpt)
+        {
+            curp->s_hpt = maxp->s_hpt;
+
+            if (off(*tp, WASTURNED) && on(*tp, ISFLEE)
+                && tp != &player)
+            {
+                turn_off(*tp, ISFLEE);
+                tp->t_oldpos = tp->t_pos;
+                /* Start our trek over */
+            }
+        }
+        tp->t_rest_hpt = 0;
+    }
+
+    return;
+}
+
+
+/*
+    doctor_spell_points()
+        A healing daemon that restors spell points
+*/
+
+void
+doctor_spell_points(struct thing *tp)
+{
+    int        turns_quiet, new_points;
+    struct stats *curp;   /* current stats pointer */
+    struct stats *maxp;   /* max stats pointer */
+    int         opower; /* current power */
+
+    curp = &(tp->t_stats);
+    maxp = &(tp->maxstats);
+    opower = curp->s_power;
+
+    /* The right ring will let you regenerate while wearing bad armor */
+
+    if (off(*tp, CANCAST) ||
+        ((tp == &player) &&
+         (cur_armor && wear_ok(tp, cur_armor, NOMESSAGE) == FALSE) &&
+         !(is_wearing(R_WIZARD) || is_wearing(R_PIETY))))
+    {
+        tp->t_rest_pow = 0;
+        return;
+    }
+
+    tp->t_rest_pow++;
+
+    switch (tp->t_ctype)
+    {
+        case C_MAGICIAN:
+        case C_ILLUSION:
+            turns_quiet = 18 - curp->s_lvl / 2;
+            new_points = curp->s_lvl / 2;
+            break;
+        case C_CLERIC:
+        case C_DRUID:
+            turns_quiet = 24 - curp->s_lvl;
+            new_points = curp->s_lvl / 2 - 2;
+            break;
+        case C_THIEF:
+        case C_ASSASIN:
+        case C_NINJA:
+            turns_quiet = 32 - curp->s_lvl;
+            new_points = curp->s_lvl / 3 - 3;
+            break;
+        case C_FIGHTER:
+        case C_RANGER:
+        case C_PALADIN:
+            turns_quiet = 32 - curp->s_lvl;
+            new_points = curp->s_lvl / 3 - 4;
+            break;
+        case C_MONSTER:
+            turns_quiet = 24 - curp->s_lvl;
+            new_points = curp->s_lvl - 6;
+            break;
+        default:
+            return;
+    }
+
+    if (curp->s_lvl < 8)
+    {
+        if (tp->t_rest_pow > turns_quiet)
+            curp->s_power++;
+    }
+    else if (tp->t_rest_pow >= 15)
+        curp->s_power += rnd(new_points) + 1;
+
+    if (tp == &player && (is_wearing(R_WIZARD) || is_wearing(R_PIETY)))
+        curp->s_power += ring_value(R_WIZARD) + ring_value(R_PIETY);
+
+    curp->s_power = min(max(0, curp->s_power), maxp->s_power);
+
+    if (curp->s_power != opower)
+        tp->t_rest_pow = 0;
+
+    return;
+}
+
+/*
+    rollwand()
+        called to roll to see if a wandering monster starts up
+*/
+
+daemon
+rollwand(daemon_arg *arg)
+{
+    NOOP(arg);
+
+    if ((rnd(6) == 0) && (player.t_ctype != C_THIEF ||
+        (rnd(30) >= pstats.s_dext)))
+    {
+        wanderer();
+        kill_daemon(DAEMON_ROLLWAND);
+        light_fuse(FUSE_SWANDER, 0, WANDERTIME, BEFORE);
+    }
+
+    return;
+}
+
+/*
+    stomach()
+        digest the hero's food
+*/
+
+daemon
+stomach(daemon_arg *arg)
+{
+    int oldfood, old_hunger;
+    int amount;
+    int power_scale;
+
+    NOOP(arg);
+
+    old_hunger = hungry_state;
+
+    if (food_left <= 0)
+    {
+        /* the hero is fainting */
+
+        if (no_command || rnd(100) > 20)
+            return;
+
+        no_command = rnd(8) + 4;
+        running = FALSE;
+        count = 0;
+        hungry_state = F_FAINT;
+        feed_me(hungry_state);
+    }
+    else
+    {
+        oldfood = food_left;
+
+        amount = ring_eat(LEFT_1) + ring_eat(LEFT_2) +
+            ring_eat(LEFT_3) + ring_eat(LEFT_4) +
+            ring_eat(RIGHT_1) + ring_eat(RIGHT_2) +
+            ring_eat(RIGHT_3) + ring_eat(RIGHT_4) +
+            foodlev;
+
+        if (on(player, SUPEREAT))   /* artifact or regeneration munchies */
+            amount *= 2;
+
+        if (on(player, POWEREAT))  /* Used an artifact power */
+        {
+            amount += 40;
+            turn_off(player, POWEREAT);
+        }
+
+        power_scale = (on(player, POWERDEXT) + on(player, POWERSTR) +
+            on(player, POWERWISDOM) + on(player, POWERINTEL) +
+            on(player, POWERCONST) + 1);
+
+        food_left -= amount * power_scale;
+
+        if (food_left < MORETIME && oldfood >= MORETIME)
+        {
+            hungry_state = F_WEAK;
+            running = FALSE;
+            feed_me(hungry_state);
+        }
+        else if (food_left < 2 * MORETIME && oldfood >= 2 * MORETIME)
+        {
+            hungry_state = F_HUNGRY;
+            running = FALSE;
+            feed_me(hungry_state);
+        }
+    }
+
+    if (old_hunger != hungry_state)
+        updpack();
+
+    wghtchk(NULL);
+}
+
+
+/*
+    runners()
+        Make all the running monsters move. with monsters now fighting
+        each other, this routine have been enhanced and may need more work yet
+*/
+
+daemon
+runners(daemon_arg *arg)
+{
+    struct linked_list  *item;
+    struct thing        *tp;
+
+    NOOP(arg);
+
+    for (item = mlist; item != NULL; item = next_mons)
+    {
+        curr_mons = item;
+        next_mons = next(curr_mons);
+        tp        = THINGPTR(item);
+
+        if (on(*tp, ISHELD) && rnd(tp->t_stats.s_str +
+            tp->t_stats.s_lvl) > 10 + rnd(50))
+        {
+            turn_off(*tp, ISHELD);
+            turn_off(*tp, ISDISGUISE);
+            turn_on(*tp, ISRUN);
+            tp->t_ischasing = TRUE;
+            tp->t_chasee = &player;
+            tp->t_horde  = NULL;
+
+            if (tp->t_stats.s_hpt < rnd(tp->maxstats.s_hpt))
+                turn_on(*tp, ISFLEE);
+
+            if (cansee(tp->t_pos.y, tp->t_pos.x))
+                msg("The %s breaks free!", monsters[tp->t_index].m_name);
+        }
+
+        if (off(*tp, ISHELD) && on(*tp, ISRUN))
+        {
+            int flee = FALSE;
+
+            flee = on(*tp, ISFLEE) ||
+                     ( (tp->t_chasee == &player) &&
+                         on(player, ISINWALL) &&
+                         off(*tp, CANINWALL) && off(*tp, ISFAMILIAR) );
+
+            if (off(*tp, ISSLOW) || tp->t_turn)
+            {
+                daemon_arg targ;
+
+                targ.thingptr = tp;
+                doctor(&targ);
+                do_chase(tp, flee);
+            }
+
+            if (curr_mons && (on(*tp, ISHASTE) ||
+               ((on(*tp, CANFLY) || on(*tp, ISFAST)) &&
+               DISTANCE(hero, tp->t_pos) >= 4)))
+            {
+                daemon_arg targ;
+
+                targ.thingptr = tp;
+                doctor(&targ);
+                do_chase(tp, flee);
+            }
+
+            if (curr_mons)
+            {
+                tp->t_turn ^= TRUE;
+                tp->t_wasshot ^= FALSE; /* Not shot anymore */
+            }
+
+        }
+    }
+
+    curr_mons = next_mons = NULL;
+
+    return;
+}
+
+/*
+    swander()
+        called when it is time to start rolling for wandering monsters
+*/
+
+fuse
+swander(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    start_daemon(DAEMON_ROLLWAND, 0, BEFORE);
+    return;
+}
+
+/*
+    unconfuse
+        release the poor player from his confusion
+*/
+
+fuse
+unconfuse(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, ISHUH);
+    msg("You feel less confused now.");
+    return;
+}
+
+/*
+    unscent()
+        turn of extra smelling ability
+*/
+
+fuse
+unscent(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, CANSCENT);
+    msg("The smell of monsters goes away.");
+}
+
+/*
+    scent
+        give back the players sense of smell
+*/
+
+fuse
+scent(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, ISUNSMELL);
+    msg("You begin to smell the damp dungeon air again.");
+}
+
+
+/*
+    unhear
+        player doesn't have extra hearing any more
+*/
+
+fuse
+unhear(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, CANHEAR);
+    msg("The sounds of monsters fades away.");
+}
+
+/*
+    hear()
+        return the players sense of hearing
+*/
+
+fuse
+hear(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, ISDEAF);
+    msg("You can hear again.");
+}
+
+
+/*
+    unsee
+        He lost his see invisible power
+
+    Need to make monsters invisible again? This
+    was done in Rogue 5.2
+
+    for (th = mlist; th != NULL; th = next(th))
+        if (on(*th, ISINVIS) && see_monst(th))
+        {
+            move(th->t_pos.y, th->t_pos.x);
+            addch(th->t_oldch);
+        }
+*/
+
+fuse
+unsee(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    if (!is_wearing(R_SEEINVIS))
+    {
+        turn_off(player, CANSEE);
+        msg("The tingling feeling leaves your eyes.");
+    }
+}
+
+/*
+    unstink()
+        Remove to-hit handicap from player
+*/
+
+fuse
+unstink(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, HASSTINK);
+}
+
+/*
+    unclrhead
+        Player is no longer immune to confusion
+*/
+
+fuse
+unclrhead(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, ISCLEAR);
+    msg("The blue aura about your head fades away.");
+}
+
+/*
+    unphase()
+        Player can no longer walk through walls
+*/
+
+fuse
+unphase(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, CANINWALL);
+
+    msg("Your dizzy feeling leaves you.");
+
+    if (!step_ok(hero.y, hero.x, NOMONST, &player))
+        death(D_PETRIFY);
+}
+
+/*
+    sight()
+        He gets his sight back
+*/
+
+fuse
+sight(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    if (on(player, ISBLIND))
+    {
+        extinguish_fuse(FUSE_SIGHT);
+        turn_off(player, ISBLIND);
+        light(&hero);
+        msg("The veil of darkness lifts.");
+    }
+}
+
+/*
+    res_strength()
+        Restore player's strength
+*/
+
+fuse
+res_strength(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    if (lost_str)
+    {
+        chg_str(lost_str, FALSE, FALSE);
+        lost_str = 0;
+    }
+    else
+        pstats.s_str = max_stats.s_str + ring_value(R_ADDSTR) +
+            (on(player, POWERSTR) ? 10 : 0) +
+            (on(player, SUPERHERO) ? 10 : 0);
+
+    updpack();
+}
+
+/*
+    nohaste()
+        End the hasting
+*/
+
+fuse
+nohaste(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, ISHASTE);
+    msg("You feel yourself slowing down.");
+}
+
+/*
+    noslow()
+        End the slowing
+*/
+
+fuse
+noslow(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, ISSLOW);
+    msg("You feel yourself speeding up.");
+}
+
+/*
+    suffocate()
+        If this gets called, the player has suffocated
+*/
+
+fuse
+suffocate(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    death(D_SUFFOCATION);
+}
+
+/*
+    cure_disease()
+        daemon for curing the diseased
+*/
+
+fuse
+cure_disease(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, HASDISEASE);
+
+    if (off(player, HASINFEST))
+        msg("You begin to feel yourself improving again.");
+}
+
+/*
+    un_itch()
+        daemon for adding back dexterity
+*/
+
+fuse
+un_itch(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    if (lost_dext)
+    {
+        chg_dext(lost_dext, FALSE, FALSE);
+        lost_dext = 0;
+        turn_off(player, HASITCH);
+    }
+}
+
+/*
+    appear()
+        Become visible again
+*/
+
+fuse
+appear(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, ISINVIS);
+    PLAYER = VPLAYER;
+    msg("The tingling feeling leaves your body.");
+    light(&hero);
+}
+
+/*
+     unelectrify()
+       stop shooting off sparks
+*/
+
+fuse
+unelectrify(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, ISELECTRIC);
+    msg("The sparks and violet glow from your body fade away.");
+    light(&hero);
+}
+
+/*
+    unshero()
+        super heroism wears off, now do nasty effects
+*/
+
+fuse
+unshero(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    msg("Your feeling of invulnerability goes away.");
+    turn_off(player, SUPERHERO);
+    chg_str(-11, FALSE, FALSE);
+    chg_dext(-6, FALSE, FALSE);
+    food_left -= HEROTIME + rnd(HEROTIME);
+    no_command += 5 + rnd(5);
+    msg("You fall asleep.");
+}
+
+/*
+    unbhero()
+        blessed super heroism wears off, no bad effects
+*/
+
+fuse
+unbhero(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    msg("Your feeling of invincibility goes away.");
+    turn_off(player, SUPERHERO);
+    chg_str(-10, FALSE, FALSE);
+    chg_dext(-5, FALSE, FALSE);
+}
+
+/*
+    undisguise()
+        player stops looking like a monster
+*/
+
+fuse
+undisguise(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    msg("Your skin feels itchy for a moment.");
+    turn_off(player, ISDISGUISE);
+    PLAYER = VPLAYER;
+    light(&hero);
+}
+
+/*
+    unsummon()
+        Unsummon a monster
+*/
+
+void
+unsummon(fuse_arg *monny)
+{
+    struct linked_list *monst = monny->ll;
+    struct linked_list  *sum_monst = (struct linked_list *) monst;
+    struct thing    *tp = THINGPTR(sum_monst);
+    char    *mname = monsters[tp->t_index].m_name;
+
+    turn_off(*tp, WASSUMMONED);
+    turn_off(player, HASSUMMONED);
+    msg("Goodbye, master.");
+    msg("The summoned %s phases out of existence", mname);
+    killed(NULL, sum_monst, NOMESSAGE, NOPOINTS);
+    mons_summoned--;
+}
+
+/*
+    ungaze()
+        Turn off gaze reflection
+*/
+
+fuse
+ungaze(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    msg("The shiny particles swirl to the floor.");
+    turn_off(player, CANREFLECT);
+}
+
+/*
+    shero()
+        restore lost abilities from cursed potion of shero
+*/
+
+fuse
+shero(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    msg("You feel normal again.");
+    chg_str(2, FALSE, TRUE);
+    chg_dext(2, FALSE, TRUE);
+    turn_off(player, ISUNHERO);
+}
+
+/*
+    wghtchk()
+	    check that the pack weight is OK 
+*/
+
+fuse
+wghtchk(fuse_arg *arg)
+{
+    int dropchk, err = TRUE;
+    char    ch;
+
+    NOOP(arg);
+
+    inwhgt = TRUE;
+
+    if (pstats.s_pack > pstats.s_carry)
+    {
+        ch = CCHAR( mvwinch(stdscr, hero.y, hero.x) );
+
+        if ((ch != FLOOR && ch != PASSAGE))
+        {
+            extinguish_fuse(FUSE_WGHTCHK);
+            light_fuse(FUSE_WGHTCHK, (void *)TRUE, 1, AFTER);
+            inwhgt = FALSE;
+            return;
+        }
+
+        extinguish_fuse(FUSE_WGHTCHK);
+        msg("Your pack is too heavy for you.");
+
+        do
+        {
+            dropchk = drop(NULL);
+
+            if (dropchk == FALSE)
+            {
+                mpos = 0;
+                msg("You must drop something.");
+            }
+
+            if (dropchk == TRUE)
+                err = FALSE;
+
+        }
+        while (err);
+
+    }
+
+    inwhgt = FALSE;
+}
+
+
+/*
+    uncold()
+        He lost his cold resistance power
+*/
+
+fuse
+uncold(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, NOCOLD);
+
+    if (!is_wearing(R_COLDRESIST))
+        msg("You feel a slight chill in the air.");
+}
+
+/*
+    unhot()
+        He lost his fire resistance power
+*/
+
+fuse
+unhot(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, NOFIRE);
+
+    if (!is_wearing(R_FIRERESIST))
+        msg("You feel a flush of warmth.");
+}
+
+/*
+    unfly()
+        He stopped flying
+*/
+
+fuse
+unfly(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, CANFLY);
+
+    if (!is_wearing(R_LEVITATION))
+        msg("You float gently to the ground.");
+}
+
+/*
+    unbreathe()
+        He started needing oxygen
+*/
+
+fuse
+unbreathe(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, HASOXYGEN);
+
+    if (!is_wearing(R_BREATHE))
+        msg("You start huffing and puffing.");
+}
+
+/*
+    unregen()
+        He stops being regenerative
+*/
+
+fuse
+unregen(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, ISREGEN);
+
+    if (!is_wearing(R_REGEN))
+        msg("Your metabolism slows down.");
+}
+
+/*
+    unsupereat()
+        He stops being excessively hungry
+*/
+
+fuse
+unsupereat(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, SUPEREAT);
+    msg("You stop feeling so hungry.");
+}
+
+/*
+    unshield()
+        He stops having his AC helped by magic
+*/
+
+fuse
+unshield(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, HASSHIELD);
+    pstats.s_arm -= pstats.s_acmod;
+    pstats.s_acmod = 0;
+    msg("Your skin feels normal.");
+}
+
+/*
+    unmshield()
+        He stops ignoring thrown weapons
+*/
+
+fuse
+unmshield(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    turn_off(player, HASMSHIELD);
+    msg("The fog dissapates.");
+}
+
+/*
+    untrue()
+        He lost his true sight power
+*/
+
+void
+untruesee(fuse_arg *arg)
+{
+    NOOP(arg);
+
+    if (!is_wearing(R_TRUESEE))
+    {
+        turn_off(player, CANTRUESEE);
+        msg("Your sensory perceptions return to normal.");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/dict.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1160 @@
+/*
+    dict.c
+
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1995 Herb Chong
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+/******************
+**  Change history:
+**
+**  (AK:04/03/95) - In dict_create, initialize hook for extensions to dictionary structure.
+**  (AK:04/04/95) - In dict_insert, only set any_ptr when a new string entry is created.
+**  (AK:04/17/95) - Added dict_union and dict_merge.
+**  (AK:04/18/95) - In dict_create, added code to create signature,
+**                  table of contents, and parameter array.
+**  (AK:04/18/95) - Revised dict_load, dict_save
+**  (AK:04/18/95) - Added dict_import
+**
+******************/
+
+static char sccsid[] = "%W% %G%";
+
+#include <stdlib.h>
+#include <string.h>
+#if !defined(OS2) && !defined(_WIN32)
+   #include <unistd.h>
+#endif
+
+#include "dict.h"
+#include "dictutil.h"
+
+#define BUFLEN      300
+
+/*************************************************************************
+*       Generic dictionary and hash table functions for word and
+*       string storage.
+*
+*       Implements generic dictionary management by using a
+*       hash table with direct chaining.  All terms are stored in a
+*       separate, unsorted, string table. When inserting into the
+*       hash table exceeds the current size, allocate a new hash table
+*       and rehash the old contents into the new table. When the string
+*       table fills, append more empty entries onto the old table and
+*       continue adding. Inserting a string that already exists increments
+*       the count for the string. Deleting a string only decrements the
+*       count to no less than 0. This will allow a 0 occurence string to be
+*       retrieved. To remove the 0 occurence string table entries, you must
+*       rebuild the dictionary. Merging from one dictionary to a new one will
+*       do this because it only copies nonzero occurences.
+*
+*       Assumptions:
+*               unsigned long >= 32 bits
+*               int >= 16 bits
+*               char == 8 bits
+*               number of entries < 2^28
+*************************************************************************/
+
+/*************************************************************************
+*       hash_string: calculate hash value for string, modified
+*       version of hashpjw() from the new Dragon book.
+*
+*       s - string to calculate hash for
+*
+*       Returns: hash value
+*************************************************************************/
+static unsigned long hash_string(const char *s)
+{
+        unsigned long h = 0;
+        unsigned long g = 0;
+
+        while (*s) {
+                h <<= 4;
+                h += *s++;
+                if ((g = h & 0xf0000000) != 0)
+                        h ^= g >> 24;
+        }
+        return h ^ g;
+}
+
+/*************************************************************************
+*       dict_create: create a dictionary and initialize its structures
+*
+*       toc_size - number of entries in table of contents ( >= 4 )
+*       initial_string_count - number of strings to hold as initial allocation
+*       initial_hash_chains - size of hash table, must be power of 4
+*       max_chain_length - max number of elements in hash chain before signalling growth
+*
+*       Returns: pointer to dictionary
+*               NULL - error creating dictionary
+*               non-NULL - sucessful creation
+*************************************************************************/
+
+DICTIONARY *dict_create(
+        const long toc_size,
+        const long initial_string_count,
+        const long initial_hash_chains,
+        const long max_chain_length )
+{
+        DICTIONARY      *dtemp = NULL;
+        STRING_ENTRY    *stemp = NULL;
+        long    *ltemp = NULL;
+        char    *sltemp;
+        long    i, j, tocsize;
+
+        /* check for a power of 4 in number of initial hash entries */
+        switch(initial_hash_chains) {
+        case 0x00000004:
+        case 0x00000010:
+        case 0x00000040:
+        case 0x00000100:
+        case 0x00000400:
+        case 0x00001000:
+        case 0x00004000:
+        case 0x00010000:
+        case 0x00040000:
+        case 0x00100000:
+        case 0x00400000:
+        case 0x01000000:
+        case 0x04000000:
+                break;
+        default:
+                return NULL;
+        }
+
+        /* Allocate the dictionary structure */
+        if ((dtemp = (DICTIONARY *)malloc(sizeof(DICTIONARY))) == NULL)
+                goto err_exit;
+
+        /* string count has to be within range */
+        j = initial_string_count;
+        if (j > 0x04000000)
+                return NULL;
+
+        /* force a reasonable value */
+        if (j < 100)
+                j = 100;
+
+        /* Allocate the string table and string array */
+        if ((stemp = (STRING_ENTRY *)malloc(sizeof(STRING_ENTRY) * j)) == NULL)
+                goto err_exit;
+        if ((sltemp = (char *)malloc(8 * j)) == NULL)
+                goto err_exit;
+
+        /* Allocate the hash table */
+        if ((ltemp = (long *)malloc(sizeof(long) * initial_hash_chains)) == NULL)
+                goto err_exit;
+
+        /* Allocate the parameter array */
+        if ( (dtemp->parm = (DICT_PARM_ENTRY *)malloc(14*sizeof(DICT_PARM_ENTRY))) == NULL)
+                goto err_exit;
+
+        /* Allocate the signature structure */
+        if ( (dtemp->sig=(DICT_SIG*)malloc(sizeof(DICT_SIG))) == NULL )
+                goto err_exit;
+
+        /* Allocate the Table of Contents */
+        tocsize = toc_size;
+        if ( tocsize < 4 )
+           tocsize = 4;
+        dtemp->sig->toc_size = tocsize;
+        if ( (dtemp->toc=(DICT_TOC_ENTRY*)malloc(dtemp->sig->toc_size*sizeof(DICT_TOC_ENTRY))) == NULL )
+                goto err_exit;
+
+        dtemp->check_value = DICT_VALIDATE;                     /* validation value */
+        dtemp->flags = DICT_NONE;                               /* no flags set */
+        dtemp->entry_count = 0;                                 /* nothing in either table */
+
+        dtemp->string_table = stemp;                            /* connect string table */
+        dtemp->string_max = j;                                  /* size of string table */
+        dtemp->scan_string_index = DICT_ENTRY_NONE;             /* not pointing to anything in scan */
+        dtemp->string_growth_count = 0;                         /* haven't grown any */
+
+        dtemp->string_array = sltemp;                           /* character array for strings */
+        dtemp->array_size = j * 8;                              /* how many bytes available */
+        dtemp->array_used = 0;                                  /* nothing used yet */
+        dtemp->array_growth_count = 0;                          /* haven't grown any */
+
+        /* force maximum hash chain length to a reasonable value */
+        i = max_chain_length;
+        if (i < 1 || i > 200)
+                i = 200;
+        dtemp->chains = ltemp;                                  /* connect hash table */
+        dtemp->longest_chain_length = 0;                        /* nothing in table yet */
+        dtemp->allowable_chain_length = i;                      /* chain length limit */
+        dtemp->table_size = initial_hash_chains;                /* size of hash table */
+        dtemp->hash_mask = initial_hash_chains - 1;             /* mask for mod() function */
+        dtemp->hash_growth_count = 0;                           /* haven't grown any */
+
+        /* string table is empty */
+        for (i = 0 ; i < j ; i++) {
+                dtemp->string_table[i].string_offset = DICT_ENTRY_NONE;
+                dtemp->string_table[i].count = 0;
+                dtemp->string_table[i].next = DICT_ENTRY_NONE;
+                dtemp->string_table[i].flags = 0;
+                dtemp->string_table[i].hash_value = 0;
+        }
+
+        /* no entries chained */
+        for (i = 0; i < initial_hash_chains; i++)
+                dtemp->chains[i] = DICT_ENTRY_NONE;
+
+        /* Initialize hook to extended dictionary structure  */
+        dtemp->ext = NULL;
+
+        /* Set up the parameter array */
+        if ( dict_set_parm_ids(dtemp) == FALSE )
+                goto err_exit;
+        if ( dict_set_parm_values(dtemp) == FALSE )
+                goto err_exit;
+
+        /* Set up the Table of Contents */
+        strcpy( dtemp->toc[0].id , "PARM" );
+        dtemp->toc[0].size = dtemp->sig->nparms * sizeof(DICT_PARM_ENTRY);
+        dtemp->toc[0].ptr = dtemp->parm;
+        dtemp->toc[0].type = 0;
+
+        strcpy( dtemp->toc[1].id , "HASH" );
+        dtemp->toc[1].size = dtemp->table_size * sizeof(long);
+        dtemp->toc[1].ptr = dtemp->chains;
+        dtemp->toc[1].type = 0;
+
+        strcpy( dtemp->toc[2].id , "STTB" );
+        dtemp->toc[2].size = dtemp->string_max * sizeof(char);
+        dtemp->toc[2].ptr = dtemp->string_table;
+        dtemp->toc[2].type = 0;
+
+        strcpy( dtemp->toc[3].id , "STAR" );
+        dtemp->toc[3].size = dtemp->array_size * sizeof(STRING_ENTRY);
+        dtemp->toc[3].ptr = dtemp->string_array;
+        dtemp->toc[3].type = 0;
+
+        /* Set up the signature */
+        dtemp->sig->check_value = DICT_VALIDATE;
+        dtemp->sig->toc_size = tocsize;
+        dtemp->sig->nparms = 14;
+
+        return dtemp;
+
+        /* error exit - saves duplicate code */
+err_exit:
+
+        dict_destroy( dtemp );
+        return NULL;
+}
+
+/*************************************************************************
+*       dict_destroy: discard a dictionary and its contents
+*               multiple calls to destroy the same dictionary is safe
+*
+*       dict - pointer to a dictionary to discard
+*
+*       Returns: status code
+*               TRUE - dictionary destroyed
+*               FALSE - error when destroying dictionary
+*       Note: Does free the dictionary structure itself.
+*************************************************************************/
+BOOLEANC dict_destroy(DICTIONARY *dict)
+{
+        int  i;
+
+        /* have to point to something */
+        if (dict == NULL)
+                return FALSE;
+
+        /* check value has to be OK */
+        if (dict->check_value != DICT_VALIDATE)
+                return FALSE;
+
+        if ( (dict->sig==NULL) || (dict->toc==NULL) || (dict->parm==NULL) )
+                return FALSE;
+
+        /* Free the type=0 tables */
+        for ( i = 0 ; i < dict->sig->toc_size ; i++ ) {
+           if ( dict->toc[i].ptr != NULL && dict->toc[i].type == 0 )
+                free( dict->toc[i].ptr );
+        } /* endfor */
+
+        /* Free the Table of Contents and signature */
+        free( dict->toc );
+        free( dict->sig );
+
+        /* Free the dictionary structure itself */
+        free( dict );
+
+        return TRUE;
+}
+
+/*************************************************************************
+*       dict_insert: add entries into the dictionary, growing as necessary
+*
+*       dict - pointer to dictionary to insert into
+*       s - string to insert
+*       count - count of occurences of string
+*       flags - flag bits associated with the string
+*       number - pointer to long to return word number
+*
+*       Returns: pointer to new entry in dictionary
+*               NULL - error during insert
+*               non-NULL - pointer to inserted or updated entry
+*
+*       Notes: if the entry already exists, increment the count.
+*       If NULL is returned, the dictionary state can no longer
+*       be trusted. Terminating with an error code would be
+*       safest.
+*************************************************************************/
+STRING_ENTRY *dict_insert(DICTIONARY *dict, char *s,
+        const long occurences, const unsigned long flags,
+        void *any_ptr, long *number)
+{
+        unsigned long   hash_value;
+        long    hash_index;
+        long    string_index = -1;
+        long    he2;
+        int     chain_len;
+
+        /* have to point to something */
+        if (dict == NULL)
+                return FALSE;
+
+        /* check value has to be OK */
+        if (dict->check_value != DICT_VALIDATE)
+                return FALSE;
+
+        /* must have a string */
+        if (s == NULL) {
+                *number = -1;
+                return FALSE;
+        }
+
+        /* must be non-NULL */
+        if (s[0] == '\0') {
+                *number = -1;
+                return FALSE;
+        }
+
+        /* figure out which chain it should go into */
+        hash_value = hash_string(s);
+        hash_index = hash_value & dict->hash_mask;
+
+        /* look for the entry in the chain */
+        for (he2 = dict->chains[hash_index], chain_len = 0; he2 != DICT_ENTRY_NONE;
+                        he2 = dict->string_table[he2].next, chain_len++) {
+                char    *sa = &dict->string_array[dict->string_table[he2].string_offset];
+
+                /* compare hash_value and then string, in that order, for speed */
+                if (dict->string_table[he2].hash_value == hash_value && !strcmp(s, sa)) {
+                        string_index = he2;
+                        break;
+                }
+        }
+
+        /* string wasn't found */
+        if (string_index < 0) {
+                /* make sure there is room in string entry table */
+                if (dict->entry_count + 1 > dict->string_max) {
+                        /* make new table 20% bigger */
+                        dict->string_max = (dict->string_max * 6) / 5;
+                        dict->string_table = (STRING_ENTRY *)realloc(dict->string_table,
+                                        sizeof(STRING_ENTRY) * dict->string_max);
+                        if (dict->string_table == NULL)
+                                return NULL;
+                        dict->string_growth_count++;
+                }
+                string_index = dict->entry_count;
+                dict->entry_count++;
+
+                /* make sure there is room in the string array */
+                if (dict->array_used + (long)strlen(s) + 1 > dict->array_size) {
+                        dict->array_size = (dict->array_size * 6) / 5;
+                        dict->string_array = (char *) realloc(dict->string_array,
+                                dict->array_size);
+                        if (dict->string_array == NULL)
+                                return NULL;
+                }
+
+                /* fill in starting values */
+                strcpy(&dict->string_array[dict->array_used], s);
+                dict->string_table[string_index].string_offset = dict->array_used;
+                dict->array_used += (long) strlen(s) + 1;
+                dict->string_table[string_index].count = 0 ;
+                dict->string_table[string_index].flags = DICT_NONE;
+                dict->string_table[string_index].any_ptr = any_ptr; /* (AK:04/04/95) */
+                dict->string_table[string_index].hash_value = hash_value;
+
+                /* hook entry at beginning of chain */
+                dict->string_table[string_index].next = dict->chains[hash_index];
+                dict->chains[hash_index] = string_index;
+
+                /* record chain lengths */
+                chain_len++;
+                if (chain_len > dict->longest_chain_length)
+                        dict->longest_chain_length = chain_len;
+
+                /* if a chain is too long */
+                if (chain_len > dict->allowable_chain_length) {
+                        long    new_size = dict->table_size * 4;
+                        long    new_mask = new_size - 1;
+                        long    *hetemp;
+                        long    i;
+                        int     longest_chain;
+
+                        if ((hetemp = (long *)malloc(sizeof(long) * new_size)) == NULL)
+                                return NULL;
+
+                        /* hash table chains are empty */
+                        for (i = 0; i < new_size; i++)
+                                hetemp[i] = DICT_ENTRY_NONE;
+
+                        /* reset all chains */
+                        for (i = 0; i < dict->entry_count; i++)
+                                dict->string_table[i].next = DICT_ENTRY_NONE;
+
+                        /* recreate hash table entries by reinserting all strings */
+                        for (i = 0; i < dict->entry_count; i++) {
+                                long    he = dict->string_table[i].hash_value & new_mask;
+
+                                dict->string_table[i].next = hetemp[he];
+                                hetemp[he] = i;
+                        }
+
+                        /* find longest chain length */
+                        for (i = 0, longest_chain = 0; i < new_size; i++) {
+                                int     len;
+                                long    cur;
+
+                                for (cur = hetemp[i], len = 0; cur != DICT_ENTRY_NONE;
+                                                cur = dict->string_table[cur].next)
+                                    len++;
+                                        ;
+                                if (len > longest_chain)
+                                        longest_chain = len;
+                        }
+
+                        /* delete old table and attach new one */
+                        free(dict->chains);
+                        dict->chains = hetemp;
+                        dict->longest_chain_length = longest_chain;
+                        dict->table_size = new_size;
+                        dict->hash_mask = new_mask;
+
+                        /* keep track of growth */
+                        dict->hash_growth_count++;
+                }
+        }
+
+        dict->string_table[string_index].count += occurences;
+        dict->string_table[string_index].flags |= flags;
+        *number = string_index;
+
+        return &dict->string_table[string_index];
+}
+
+/*************************************************************************
+*       dict_delete: deletes an entry from the dictionary
+*       (Actually, only decrements the entry's count)
+*
+*       dict - pointer to dictionary to delete
+*       s - string to find and delete
+*       count - count to decrement entry by
+*
+*       Returns: status code
+*               TRUE - entry has been deleted
+*               FALSE - entry wasn't found or error occured
+*************************************************************************/
+BOOLEANC dict_delete(const DICTIONARY *dict, const char *s, const long count)
+{
+        STRING_ENTRY    *se;
+        long    n;
+
+        /* find the string */
+        if ((se = dict_search(dict, s, &n)) == NULL)
+                return FALSE;
+
+        /* decrement count and make sure it stays valid */
+        se->count -= count;
+        if (se->count < 0)
+                se->count = 0;
+        return TRUE;
+}
+
+/*************************************************************************
+*       dict_search: look for entries in the dictionary
+*
+*       dict - pointer to dictionary to search
+*       s - string to search for
+*       number - pointer to long to return string number
+*
+*       Returns: pointer to string entry
+*               NULL - entry not found
+*               non-NULL - pointer to string entry
+*************************************************************************/
+STRING_ENTRY *dict_search(const DICTIONARY *dict, const char *s,
+        long *number)
+{
+        unsigned long   hash_value;
+        long    hash_index;
+        long    string_index = -1;
+        long    he;
+
+        /* have to point to something */
+        if (dict == NULL)
+                return NULL;
+
+        /* check value has to be OK */
+        if (dict->check_value != DICT_VALIDATE)
+                return NULL;
+
+        /* must have a string */
+        if (s == NULL) {
+                *number = -1;
+                return NULL;
+        }
+
+        /* must be non-NULL */
+        if (s[0] == '\0') {
+                *number = -1;
+                return FALSE;
+        }
+
+        /* figure out which chain it should be in */
+        hash_value = hash_string(s);
+        hash_index = hash_value & dict->hash_mask;
+
+        /* look for the entry in the chain */
+        for (he = dict->chains[hash_index]; he != DICT_ENTRY_NONE;
+                        he = dict->string_table[he].next) {
+                char    *sa = (char*)(&dict->string_array[dict->string_table[he].string_offset]);
+
+                /* compare hash_value and then string, in that order, for speed */
+                if (dict->string_table[he].hash_value == hash_value && !strcmp(s, sa)) {
+                        string_index = he;
+                        break;
+                }
+        }
+        if (string_index < 0) {
+                *number = -1;
+                return NULL;
+        }
+
+        *number = string_index;
+        return dict->string_table+string_index;
+}
+
+/*************************************************************************
+*       dict_union: merges contents of 2 dictionaries into
+*       a third
+*
+*       dict1 - pointer to dictionary 1
+*       dict2 - pointer to dictionary 2
+*
+*       Returns: dictionary pointer
+*               NULL - failed to merge
+*               non-NULL - pointer to new dictionary
+*
+*       Notes: entries of the same string have their counts
+*       added and their flags ORed together.
+*************************************************************************/
+DICTIONARY *dict_union( const DICTIONARY *dict1 , const DICTIONARY *dict2 )
+{
+        DICTIONARY    *dict = NULL;
+        STRING_ENTRY  *se, *se2;
+        long          initial_string_count, initial_hash_chains, max_chain_length;
+        long          i, string_index;
+
+        /***********
+        **  Initialize the new dictionary.
+        ***********/
+
+        if ( dict1==NULL || dict2==NULL )
+                goto err_exit;
+        if ((dict=(DICTIONARY *)malloc(sizeof(DICTIONARY))) == NULL)
+                goto err_exit;
+
+        initial_string_count = dict1->string_max;
+        initial_hash_chains = dict1->table_size;
+        max_chain_length = dict1->allowable_chain_length;
+        dict = dict_create( 4,
+                            initial_string_count,
+                            initial_hash_chains,
+                            max_chain_length );
+
+        /***********
+        **  Copy the entries from dict1 into the new dictionary.
+        ***********/
+
+        for ( i = 0 ; i < dict1->entry_count ; i++ ) {
+                se = (STRING_ENTRY*)&dict1->string_table[i];
+                if ( se->count > 0 ) {
+                        se2 = dict_insert(
+                                  dict,
+                                  dict1->string_array+se->string_offset,
+                                  se->count,
+                                  se->flags,
+                                  NULL,
+                                  &string_index );
+                        if ( se2 == NULL )
+                                goto err_exit;
+                } /* endif */
+        } /* endfor */
+
+        /*  Merge the entries from dict2 into the new dictionary. */
+        if ( dict_merge(dict,dict2,FALSE) == FALSE )
+                goto err_exit;
+
+        /*  Success. Return a pointer to the new dictionary.  */
+        return( dict );
+
+        /*  Failure. Ignominiously erase our tracks and return NULL. */
+err_exit:
+        dict_destroy( dict );
+        return NULL;
+}
+
+/*************************************************************************
+*       dict_merge: merges the contents of a dictionary into
+*       another one, updating the contents of the destination
+*
+*       dst - dictionary to update
+*       src - dictionary to add
+*       move - boolean flag
+*               TRUE - move to dest
+*               FALSE - copy to dest
+*
+*       Returns: status code
+*               TRUE - merge completed
+*               FALSE - error on merge
+*
+*       Notes: entries of the same string have their counts
+*       added. At the end of a move, src is empty. If there
+*       is an error during a move, the contents of both
+*       dictionaries cannot be trusted.
+*************************************************************************/
+BOOLEANC dict_merge(const DICTIONARY *dst, const DICTIONARY *src, const BOOLEANC move)
+{
+        STRING_ENTRY  *se, *se2;
+        DICTIONARY    *dict1, *dict2;
+        long          i, string_index, index;
+
+        dict1 = (DICTIONARY*)src;
+        dict2 = (DICTIONARY*)dst;
+
+        /***********
+        **  Copy the dictionary entries into the new dictionary.
+        ***********/
+
+        for ( i = 0 ; i < dict1->entry_count ; i++ ) {
+                se = (STRING_ENTRY*)&dict1->string_table[i];
+                if ( se->count > 0 ) {
+                        se2 = dict_insert(
+                                  dict2,
+                                  dict1->string_array+se->string_offset,
+                                  se->count,
+                                  se->flags,
+                                  NULL,
+                                  &string_index );
+                        if ( se2 == NULL )
+                                goto err_exit;
+                } /* endif */
+        } /* endfor */
+
+        /***********
+        **  Set up the dictionary parameter vector.
+        ***********/
+
+        if ( dict_set_parm_values(dict2) == FALSE )
+                return( FALSE );
+
+        /***********
+        **  Update the table of contents.
+        **     PARM HASH STTB STAR
+        ***********/
+
+        if ( (index=dict_toc_index(dict2,"HASH")) == -1)
+                goto err_exit;
+        dict2->toc[index].size = dict2->table_size * sizeof(long);
+        dict2->toc[index].ptr = dict2->chains;
+
+        if ( (index=dict_toc_index(dict2,"STTB")) == -1)
+                goto err_exit;
+        dict2->toc[index].size = dict2->string_max * sizeof(char);
+        dict2->toc[index].ptr = dict2->string_table;
+
+        if ( (index=dict_toc_index(dict2,"STAR")) == -1)
+                goto err_exit;
+        dict2->toc[index].size = dict2->array_size * sizeof(STRING_ENTRY);
+        dict2->toc[index].ptr = dict2->string_array;
+
+        /***********
+        **  Update the signature
+        ***********/
+
+        dict2->sig->checksum =
+                compute_checksum( 4*sizeof(DICT_TOC_ENTRY) , (char*)(dict2->toc) );
+
+        /***********
+        **  If this is a move, destroy the source dictionary
+        ***********/
+
+        if ( move == TRUE )
+                if ( dict_destroy(dict1) == FALSE )
+                        goto err_exit;
+
+        /***********
+        **  Success
+        ***********/
+
+        return( TRUE );
+
+        /***********
+        **  Failure
+        ***********/
+
+err_exit:
+        dict_destroy( dict2 );
+        return FALSE;
+}
+
+/*************************************************************************
+*       dict_string_by_number: return string pointer for
+*       a given string number
+*
+*       number - string number
+*
+*       Returns: pointer to string entry
+*               NULL - entry not found
+*               non-NULL - pointer to string entry
+*************************************************************************/
+STRING_ENTRY *dict_string_by_number(const DICTIONARY *dict, const long number)
+{
+        if (dict == NULL)
+                return NULL;
+
+        /* check value has to be OK */
+        if (dict->check_value != DICT_VALIDATE)
+                return NULL;
+
+        /* string number has to be within range */
+        if (number < 0 || number >= dict->entry_count)
+                return NULL;
+
+        return dict->string_table+number;
+}
+
+/*************************************************************************
+*       dict_scan_begin: begin a scan of the dictionary
+*
+*       dict - pointer to dictionary to scan
+*
+*       Returns: status code
+*               TRUE - scan initialized
+*               FALSE - error
+*
+*       Notes: if a scan is already in progress, it is
+*       abandoned and the scan is reset to the
+*       beginning.
+*************************************************************************/
+BOOLEANC dict_scan_begin(DICTIONARY *dict)
+{
+        /* have to point to something */
+        if (dict == NULL)
+                return FALSE;
+
+        /* check value has to be OK */
+        if (dict->check_value != DICT_VALIDATE)
+                return FALSE;
+
+        /* point to first entry in string table */
+        dict->scan_string_index = 0;
+        return TRUE;
+}
+
+/*************************************************************************
+*       dict_scan_next: get the next entry in a scan
+*
+*       dict - pointer to dictionary to continue scanning
+*
+*       Returns: pointer to string entry
+*               NULL - no more entries
+*               non-NULL - next string entry
+*************************************************************************/
+STRING_ENTRY *dict_scan_next(DICTIONARY *dict)
+{
+        /* have to point to something */
+        if (dict == NULL)
+                return NULL;
+
+        /* check value has to be OK */
+        if (dict->check_value != DICT_VALIDATE)
+                return NULL;
+
+        /* scan index has to be within range */
+        if (dict->scan_string_index < 0
+                        || dict->scan_string_index > dict->entry_count)
+                return NULL;
+
+        /* for first non-empty table entry */
+        while (dict->scan_string_index < dict->entry_count
+                        && dict->string_table[dict->scan_string_index].count == 0)
+                dict->scan_string_index++;
+
+        /* past end of table? */
+        if (dict->scan_string_index >= dict->entry_count)
+                return NULL;
+
+        return &dict->string_table[dict->scan_string_index++];
+}
+
+
+/*************************************************************************
+*       dict_load - load a compiled dictionary into memory
+*                   creates a new dictionary
+*
+*       fname - fully qualified file name
+*
+*       Returns: pointer to created dictionary structure
+*                (NULL on failure)
+*************************************************************************/
+DICTIONARY *dict_load(const char *fname)
+{
+        DICTIONARY       *dict = NULL;
+        int              code, index;
+        FILE             *fi;
+        int              ntoc;
+
+        if ( (fi=fopen((char*)fname,"rb")) == NULL ) {
+                signal_error( "dict_load: could not open file" , (char*)fname , 0 );
+                goto err_exit;
+        } /* endif */
+
+        if ((dict = (DICTIONARY *)malloc(sizeof(DICTIONARY))) == NULL) {
+                /* signal_error( "dict_load: alloc failed" , "" , 0 ); */
+                goto err_exit;
+        } /* endif */
+
+        /* Read the dictionary signature record */
+        if ((dict->sig = (DICT_SIG *)malloc(sizeof(DICT_SIG))) == NULL) {
+                goto err_exit;
+        } /* endif */
+        code = block_read( fi , (char*)(dict->sig) , sizeof(DICT_SIG) , 0 );
+        if ( code == -1 ) {
+                signal_error( "dict_load: could not read signature" , (char*)fname , 0 );
+                goto err_exit;
+        } /* endif */
+
+        if ( dict->sig->check_value != DICT_VALIDATE ) {
+                signal_error( "dict_load: could not validate file" , (char*)fname , 0 );
+                goto err_exit;
+        } /* endif */
+        dict->check_value = dict->sig->check_value;
+
+        /* Read the dictionary Table of Contents */
+        ntoc = dict->sig->toc_size;
+        dict->toc = (DICT_TOC_ENTRY *) malloc( ntoc * sizeof(DICT_TOC_ENTRY) );
+        if ( dict->toc == NULL ) {
+                signal_error( "dict_load: alloc of TOC failed" , "" , 0 );
+                goto err_exit;
+        } /* endif */
+        code = block_read( fi ,
+                           (char*)(dict->toc) ,
+                           ntoc * sizeof(DICT_TOC_ENTRY) ,
+                           sizeof(DICT_SIG) );
+        if ( code == -1 ) {
+                signal_error( "dict_load: could not read Table of Contents" , (char*)fname , 0 );
+                goto err_exit;
+        } /* endif */
+
+        /* Read the dictionary parameters */
+        dict->parm = (DICT_PARM_ENTRY *)
+                         dict_load_block( dict , "PARM" , fi , NULL );
+        if ( dict->parm == NULL ) {
+                signal_error( "dict_load: could not load parameter table" , "" , 0 );
+                goto err_exit;
+        } /* endif */
+        index = dict_toc_index( dict , "PARM" );
+        dict->sig->nparms = dict->toc[index].size / sizeof(DICT_PARM_ENTRY);
+
+        /* Set the parameter values in the dictionary structure */
+        if ( dict_set_parm_variables(dict) == FALSE )
+                goto err_exit;
+
+        /* Load the string array */
+        dict->string_array = (char *)
+                dict_load_block( dict , "STAR" , fi , NULL );
+        if ( dict->string_array == NULL ) {
+                signal_error( "dict_load: could not load string array" , (char*)fname , 0 );
+                goto err_exit;
+        } /* endif */
+
+        /* Load the string table */
+        dict->string_table = (STRING_ENTRY *)
+                dict_load_block( dict , "STTB" , fi , NULL );
+        if ( dict->string_table == NULL ) {
+                signal_error( "dict_load: could not load string table" , (char*)fname , 0 );
+                goto err_exit;
+        } /* endif */
+
+        /* Load the hash table */
+        dict->chains = (long *)
+                dict_load_block( dict , "HASH" , fi , NULL );
+        if ( dict->chains == NULL ) {
+                signal_error( "dict_load: could not load hash table" , (char*)fname , 0 );
+                goto err_exit;
+        } /* endif */
+
+        /*  Initialize the hook for dictionary extensions  */
+        dict->ext = NULL;
+
+        /*  Success  */
+        fclose( fi );
+        return( dict );
+
+        /*  Failure  */
+err_exit:
+        if ( fi != NULL )
+                fclose( fi );
+        dict_destroy( dict );
+        return NULL;
+}
+
+
+/*************************************************************************
+*       dict_save - save a dictionary from memory into a file
+*
+*       dict - pointer to dictionary to save
+*       fname - full qualified file name prefix of dictionary
+*
+*       Returns: status code
+*               TRUE - dictionary was saved sucessfully
+*               FALSE - error during save
+*************************************************************************/
+BOOLEANC dict_save( DICTIONARY *dict, const char *fname )
+{
+        int   index, ret_code;
+        FILE  *fo = NULL;
+
+        /* Have to be pointing at a valid dictionary */
+        if ( dict == NULL || dict->sig->check_value != DICT_VALIDATE )
+                goto err_exit;
+
+        /* Open the file for output */
+        if ( (fo=fopen((char*)fname,"wb")) == NULL )
+                goto err_exit;
+
+        /*  Make the table of contents entries current  */
+        /*  Note: This will not be necessary once the data is stored in EVECTORs  */
+
+        if ( (index=dict_toc_index(dict,"PARM")) == -1 )
+                goto err_exit;
+        dict->toc[index].size = dict->sig->nparms * sizeof(DICT_PARM_ENTRY);
+        dict->toc[index].ptr = dict->parm;
+
+        if ( (index=dict_toc_index(dict,"STAR")) == -1 )
+                goto err_exit;
+        dict->toc[index].size = dict->array_size * sizeof(char);
+        dict->toc[index].ptr = dict->string_array;
+
+        if ( (index=dict_toc_index(dict,"STTB")) == -1 )
+                goto err_exit;
+        dict->toc[index].size = dict->string_max * sizeof(STRING_ENTRY);
+        dict->toc[index].ptr = dict->string_table;
+
+        if ( (index=dict_toc_index(dict,"HASH")) == -1 )
+                goto err_exit;
+        dict->toc[index].size = dict->table_size * sizeof(long);
+        dict->toc[index].ptr = dict->chains;
+
+        /*  Reset the TOC offsets and checksums for ALL tables  */
+        /*  (not just type=0 tables)                            */
+        dict_reset_toc_offsets( dict );
+
+        /* Set the dictionary parm structure from the parameter values */
+        if ( dict_set_parm_values(dict) == FALSE )
+                goto err_exit;
+
+        /* Save the signature */
+        dict->sig->checksum = compute_checksum( sizeof(DICT_SIG) , (char*)(dict->sig) );
+        ret_code = block_write( fo ,
+                                (char*)dict->sig ,
+                                sizeof(DICT_SIG) );
+        if ( ret_code == -1 )
+                goto err_exit;
+
+        /* Save the table of contents */
+        ret_code = block_write( fo,
+                                (char*)dict->toc,
+                                dict->sig->toc_size * sizeof(DICT_TOC_ENTRY) );
+        if ( ret_code == -1 )
+                goto err_exit;
+
+        /* Save the tables */
+        /* For now, only save type=0 tables */
+        for ( index = 0 ; index < dict->sig->toc_size ; index++ ) {
+                if ( dict->toc[index].type == 0 ) {  /* Ordinary table */
+                        ret_code = dict_save_block( dict , dict->toc[index].id , fo );
+                        if ( ret_code == FALSE )
+                                goto err_exit;
+                     } /* endif */
+        } /* endfor */
+
+        /*  Success  */
+        fclose( fo );
+        return TRUE;
+
+        /*  Failure  */
+err_exit:
+        if ( fo != NULL )
+                fclose( fo );
+        return FALSE;
+}
+
+
+/*************************************************************************
+*       dict_import: read in an ASCII dictionary.
+*
+*       dict_fname - name of dictionary file
+*       parameters to create a DICTIONARY structure (see dict_create)
+*
+*       Returns: pointer to created DICTIONARY structure
+*                (NULL on failure)
+*
+*************************************************************************/
+DICTIONARY *dict_import( const char *dict_fname ,
+                         const long initial_string_count ,
+                         const long initial_hash_entries ,
+                         const long max_chain_length )
+{
+        DICTIONARY     *dict;
+        char           buffer[BUFLEN], ch;
+        int            index, c, c0;
+        long           number;
+        FILE           *fi = NULL;
+
+        /***********
+        **  Dictionary setup.
+        ***********/
+
+        dict = dict_create( 4,
+                            initial_string_count ,
+                            initial_hash_entries ,
+                            max_chain_length );
+        if ( dict == NULL )
+           goto err_exit;
+
+        /***********
+        **  Read the dictionary file
+        **  Each line should have one word or a string delimited by '|'
+        ***********/
+
+        if ( (fi=fopen(dict_fname,"r")) == NULL )
+                goto err_exit;
+        while( fgets(buffer,BUFLEN,fi) != NULL ) {
+                c0 = 0;
+                   /*  Skip to non-blank  */
+                while ( (c0<BUFLEN-2) && (buffer[c0]==' ') ) ++c0;
+                if ( buffer[c0] == '|' ) {
+                        c = ++c0;
+                        ch = '|';
+                } else {
+                        c = c0;
+                        ch = ' ';
+                } /* endif */
+                   /*  Scan to blank or matching '|' */
+                while ( (c<BUFLEN-1) && (buffer[c]!='\0') &&
+                        (buffer[c]!='\n') && (buffer[c]!=ch)  )
+                        ++c;
+                buffer[c] = '\0';
+                   /*  Insert the word  */
+                if ( dict_insert(dict,buffer+c0,1,0,NULL,&number) == NULL )
+                        goto err_exit;
+        } /* endwhile */
+
+        /***********
+        **  Fill in the dictionary parameter vector.
+        ***********/
+
+        if ( dict_set_parm_values(dict) == FALSE )
+                goto err_exit;
+
+        /***********
+        **  Update the table of contents for HASH STTB STAR
+        ***********/
+
+        if ( (index=dict_toc_index(dict,"HASH")) == -1 )
+                goto err_exit;
+        dict->toc[index].size = dict->table_size * sizeof(long);
+
+        if ( (index=dict_toc_index(dict,"STTB")) == -1 )
+                goto err_exit;
+        dict->toc[index].size = dict->string_max * sizeof(char);
+
+        if ( (index=dict_toc_index(dict,"STAR")) == -1 )
+                goto err_exit;
+        dict->toc[index].size = dict->array_size * sizeof(STRING_ENTRY);
+
+           /*  Success. Return a pointer to the new dictionary.  */
+        fclose(fi);
+        return( dict );
+
+           /*  Failure. Ignominiously erase our tracks and return NULL.  */
+err_exit:
+        if ( fi != NULL )
+           fclose(fi);
+        dict_destroy( dict );
+        return NULL;
+}
+
+/*************************************************************************
+*       dict_export - save an extended dictionary from memory into
+*                     an ASCII file
+*
+*       dict - pointer to dictionary to save
+*       fname - full qualified file name prefix of dictionary
+*
+*       Returns: status code
+*               TRUE - dictionary was saved sucessfully
+*               FALSE - error during save
+*
+*************************************************************************/
+BOOLEANC dict_export( DICTIONARY *dict , const char *fname )
+{
+        FILE          *fp = NULL;
+        STRING_ENTRY  *se;
+        int       i;
+
+        /* have to point to something */
+        if (dict == NULL)
+                goto err_exit;
+
+        /* check value has to be OK */
+        if (dict->check_value != DICT_VALIDATE)
+                goto err_exit;
+
+        /* must have a filename */
+        if (fname == NULL)
+                goto err_exit;
+
+        fp = fopen( (char*)fname , "w" );
+        if ( fp == NULL )
+                goto err_exit;
+
+        for ( i = 0 ; i < dict->entry_count ; i++ ) {
+           se = &dict->string_table[i];
+           fprintf( fp , "|%s|\n" , dict->string_array + se->string_offset );
+        } /* endfor */
+        fclose( fp );
+
+        /*  Success.  */
+        fclose(fp);
+        return TRUE;
+
+        /*  Failure.  */
+err_exit:
+        if ( fp != NULL )
+           fclose(fp);
+        dict_destroy( dict );
+        return FALSE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/dict.h	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,216 @@
+/*
+    dict.h
+
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1995 Herb Chong
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+/*-----------------
+  Change history:
+  (AK:04/03/95) - Added hook for extensions to dictionary structure.
+  (AK:04/04/95) - Added dictionary signature, table of contents and parameter
+                  structure defintions and fields in DICTIONARY structure
+-------------------*/
+
+#ifndef dict_h_included
+#define dict_h_included
+
+static char dict_sccsid[] = "%W% %G%";
+
+#ifndef TRUE
+#define TRUE    1
+#define FALSE   0
+#endif
+
+#define DICT_NONE       0x00000000              /* no flags set */
+#define DICT_VALIDATE   0xdeadbeef              /* look for this in every dictionary structure */
+#define DICT_ENTRY_NONE -1                      /* index of invalid entry */
+
+typedef unsigned char BOOLEANC;
+
+/*------------------
+  string table entry
+  ------------------*/
+typedef struct string_entry {
+        long    string_offset;       /* offset in string array */
+        long    count;               /* number of occurrences of string */
+        long    next;                /* offset of next in hash chain */
+        void    *any_ptr;            /* free pointer */
+        unsigned long flags;         /* user definable flag value for string */
+        unsigned long hash_value;    /* hash value of string using hash function */
+} STRING_ENTRY;
+
+/*--------------------
+  Dictionary signature (AK:04/04/95)
+  --------------------*/
+typedef struct dict_sig_ {      /*  Dictionary signature               */
+   unsigned long  check_value;  /*  0xdeadbeef                         */
+   int            toc_size;     /*  # of entries in Table of Contents  */
+   long           nparms;       /*  # of parameters                    */
+   unsigned long  checksum;     /*  Checksum for TOC                   */
+} DICT_SIG;
+
+/*----------------------------------
+  Dictionary table of contents entry (AK:04/04/95)
+  ----------------------------------*/
+typedef struct TOC_entry_ {     /*  Dictionary table of contents entry  */
+   char           id[5];        /*  Field identifier:                   */
+   long           offset;       /*  Offset (bytes) of entry in file     */
+   long           size;         /*  Size (bytes) of entry               */
+   void           *ptr;         /*  Where entry is stored in memory     */
+   unsigned long  checksum;     /*  Checksum of entry                   */
+   int            type;         /*  0=ordinary ; 1=EVECTOR ; 2=NULL     */
+} DICT_TOC_ENTRY;
+
+/*--------------------------------
+  Dictionary parameter table entry (AK:04/04/95)
+  --------------------------------*/
+typedef struct dict_parm_entry_ {   /*  Dictionary parameter table entry  */
+   char           id[13];           /*  Parameter identifier              */
+   unsigned long  value;            /*  Parameter value                   */
+} DICT_PARM_ENTRY;
+
+
+/*---------------------------
+  Hash dictionary information
+  ---------------------------*/
+typedef struct dictionary {
+        unsigned long   check_value;            /* check validation value */
+        unsigned long   flags;                  /* flag values */
+        long    entry_count;                    /* number of used entries in each table */
+
+        char    *string_array;                  /* storage for strings */
+        long    array_size;                     /* number of bytes allocated */
+        long    array_used;                     /* number of bytes occupied */
+        int     array_growth_count;             /* number of times grown */
+
+        STRING_ENTRY    *string_table;          /* string table */
+        long    string_max;                     /* max number of entries in string table */
+        long    scan_string_index;              /* current index into string table for scan */
+        int     string_growth_count;            /* number of times had to grow string table */
+
+        long            *chains;                /* vector of array indices to hash entries */
+        int     longest_chain_length;           /* longest chain length in hash table */
+        int     allowable_chain_length;         /* chain lengths always < this */
+        long    table_size;                     /* number of elements in hash entries vector */
+        unsigned long   hash_mask;              /* mask for doing mod() function */
+        int     hash_growth_count;              /* number of times had to grow hash table */
+
+        void    *ext;                           /* Hook for extensions to the dictionary (AK:04/03/95) */
+
+        DICT_SIG         *sig;                  /* Signature (AK:04/04/95) */
+        DICT_TOC_ENTRY   *toc;                  /* Table of contents (AK:04/04/95) */
+        DICT_PARM_ENTRY  *parm;                 /* Parameters (AK:04/04/95) */
+
+} DICTIONARY;
+
+/*--------------------------------------------------------------
+  dict_create: create a dictionary and initialize its structures
+  --------------------------------------------------------------*/
+extern DICTIONARY *dict_create(
+        const long  toc_size,
+        const long  initial_string_count,
+        const long  initial_hash_entries,
+        const long  max_chain_length );
+
+/*-------------------------------------------------
+  dict_delete: deletes an entry from the dictionary
+  -------------------------------------------------*/
+extern BOOLEANC dict_delete(
+        const DICTIONARY  *dict,
+        const char        *s,
+        const long        count );
+
+/*---------------------------------------------------
+  dict_destroy: discard a dictionary and its contents
+  ---------------------------------------------------*/
+extern BOOLEANC dict_destroy(
+        DICTIONARY  *dict );
+
+/*------------------------------------------------
+  dict_export: write a dictionary to an ASCII file
+  ------------------------------------------------*/
+extern BOOLEANC dict_export(
+        DICTIONARY  *dict,
+        const char  *fname );
+
+/*-------------------------------------------------
+  dict_import: read a dictionary from an ASCII file
+  -------------------------------------------------*/
+extern DICTIONARY *dict_import(
+        const char  *dict_fname,
+        const long  initial_string_count,
+        const long  initial_hash_entries,
+        const long  max_chain_length );
+
+/*------------------------------------------------------------------
+  dict_insert: add entries into the dictionary, growing as necessary
+  ------------------------------------------------------------------*/
+extern STRING_ENTRY *dict_insert(
+        DICTIONARY           *dict,
+        char                 *s,
+        const long           occurences,
+        const unsigned long  flags,
+        void                 *any_ptr,
+        long                 *number );
+
+/*----------------------------------------------------
+  dict_load: read a dictionary from a file into memory
+  ----------------------------------------------------*/
+extern DICTIONARY *dict_load(
+        const char  *fname );
+
+/*-----------------------------------------------------------------
+  dict_merge: merges the contents of a dictionary into another one,
+  updating the contents of the destination
+  -----------------------------------------------------------------*/
+extern BOOLEANC dict_merge(
+        const DICTIONARY  *dst,
+        const DICTIONARY  *src,
+        const BOOLEANC    move );
+
+/*----------------------------------------------------
+  dict_save: save a dictionary from memory into a file
+  ----------------------------------------------------*/
+extern BOOLEANC dict_save(
+        DICTIONARY  *dict,
+        const char  *fname );
+
+/*-----------------------------------------------
+  dict_scan_begin: begin a scan of the dictionary
+  -----------------------------------------------*/
+extern BOOLEANC dict_scan_begin(
+        DICTIONARY  *dict );
+
+/*--------------------------------------------
+  dict_scan_next: get the next entry in a scan
+  --------------------------------------------*/
+extern STRING_ENTRY *dict_scan_next(
+        DICTIONARY  *dict );
+
+/*-----------------------------------------------
+  dict_search: look for entries in the dictionary
+  -----------------------------------------------*/
+extern STRING_ENTRY *dict_search(
+        const DICTIONARY  *dict,
+        const char        *s,
+        long              *number );
+
+/*----------------------------------------------------------------------
+  dict_string_by_number: return string pointer for a given string number
+  ----------------------------------------------------------------------*/
+extern STRING_ENTRY *dict_string_by_number(
+        const DICTIONARY  *dict,
+        const long        number );
+
+/*----------------------------------------------------------
+  dict_union: merges contents of 2 dictionaries into a third
+  ----------------------------------------------------------*/
+extern DICTIONARY *dict_union(
+        const DICTIONARY  *dict1,
+        const DICTIONARY  *dict2 );
+
+#endif  /* dict_h_included */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/dictutil.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,438 @@
+/*
+    dictutil.c
+
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1995 Herb Chong
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+/*************************************************************************
+**   Utilities for Dictionary Maintenence Functions
+*************************************************************************/
+
+static char sccsid[] = "%W% %G%";
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#if !defined(OS2) && !defined(_WIN32)
+   #include <unistd.h>
+#else
+   #include <io.h>
+   #include <fcntl.h>
+#endif
+
+#include "dict.h"
+#include "dictutil.h"
+#include "rogue.h"
+
+int   trace;
+FILE  *ft;
+
+
+/***********
+**  Read 'count' characters into 'buffer' at 'offset' in a binary file
+**  Return 0 on success; -1 on failure;
+***********/
+
+int block_read( FILE *fi , char *buffer , size_t count , long offset )
+{
+   if ( fseek(fi,offset,SEEK_SET) == -1 )
+      return( -1 );
+
+   if ( fread(buffer,1,count,fi) != count )
+      return( -1 );
+   return( 0 );
+}
+
+/***********
+**  Write 'count' characters from 'buffer' to a binary file.
+**  Return -1 on failure; 0 on success.
+***********/
+
+int block_write( FILE *fo , char *buffer , size_t count )
+{
+   if ( fwrite(buffer,1,count,fo) != count )
+      return( -1 );
+   return( 0 );
+}
+
+/***********
+**  Load a dictionary table entry with id TOC_id into memory pointed to by block.
+**  Update the dictionary TOC.
+**  If *block=NULL, allocate the block of memory.
+**  Return 0 on success; -1 on failure.
+**  Set dt_entry->ptr to where the block is stored.
+***********/
+
+void *dict_load_block( DICTIONARY *dict , char *toc_id ,
+                          FILE *fi , void *block )
+{  DICT_TOC_ENTRY  *dt_entry;
+   static void     *ptr;
+   int             index, ret_code;
+
+   index = dict_toc_index( dict , toc_id );
+   if ( index != -1 ) {  /* Found the id */
+      dt_entry = &(dict->toc[index]);
+   } else {
+      signal_error( "dict_load_block: could not find TOC_id" , toc_id , 1 );
+      return( NULL );
+   } /* endif */
+
+   if ( block == NULL ) {
+      ptr = malloc( dt_entry->size );
+      if ( trace > 3 ) {
+         fprintf( ft , "\ndict_load_block allocates %lx bytes at location %p\n" ,
+                   dt_entry->size , ptr );
+      } /* endif */
+   } else {
+      ptr = block;
+      if ( trace > 3 ) {
+         fprintf( ft , "\ndict_load_block uses memory at location %p\n" , ptr );
+      } /* endif */
+   } /* endif */
+   if ( ptr == NULL ) {
+      signal_error( "dict_load_block: alloc failed " , toc_id , 1 );
+      return( NULL );
+   } /* endif */
+
+   ret_code = block_read( fi ,
+                          (char*)ptr ,
+                          dt_entry->size ,
+                          dt_entry->offset );
+   if ( ret_code == -1 )
+      return( NULL );
+
+   if ( dt_entry->checksum !=
+        compute_checksum( dt_entry->size , (char*)ptr ) ) {
+      signal_error( "dict_load_block: invalid checksum ", toc_id, 1);
+      return( NULL );
+   } /* endif */
+
+   dt_entry->ptr = ptr;
+
+   if ( trace > 3 ) {
+      fprintf( ft , "\nLoaded block\nTOC entry:    id:%s  offset:%lx  size:%lx  ptr:%p  checksum:%lx  type:%d\n" ,
+               dict->toc[index].id , dict->toc[index].offset ,
+               dict->toc[index].size , dict->toc[index].ptr ,
+               dict->toc[index].checksum , dict->toc[index].type );
+   } /* endif */
+
+   return( ptr );
+}
+
+/***********
+**  Save a dictionary table entry.
+**  Update the dictionary TOC entry offset and checksum fields.
+**  Return 0 on success, -1 on failure.
+**  Note: It is assumed that the size and pointer fields in TOC entry are
+**        already up to date; i.e., that they are consistent with the current
+**        location and size of the block being written. This is essential
+**        because the table of contents must have already been written
+**        into the file.
+***********/
+
+BOOLEANC dict_save_block( DICTIONARY *dict , char *toc_id , FILE *fo )
+{  DICT_TOC_ENTRY   *dt_entry;
+   int              index, ret_code;
+   char             *block;
+
+   index = dict_toc_index( dict , toc_id );
+   if ( index == -1 ) {
+      signal_error( "dict_save_block: id not found " , toc_id , 1 );
+      return( FALSE );
+   } /* endif */
+   dt_entry = &(dict->toc[index]);
+   block = (char*)(dt_entry->ptr);
+
+   if ( block == NULL ) {
+      signal_error( "dict_save_block: NULL block " , toc_id , 1 );
+      return( FALSE );
+   } /* endif */
+
+   /* dt_entry->offset = fseek( fo , 0 , SEEK_END ); */
+   dt_entry->checksum = compute_checksum( dt_entry->size , block );
+   ret_code = block_write( fo , dt_entry->ptr , dt_entry->size );
+   if ( ret_code == -1 ) {
+      signal_error( "dict_save_block: block_write failed " , toc_id , 1 );
+      return( FALSE );
+   } /* endif */
+
+   if ( trace > 3 ) {
+      fprintf( ft , "\nStored block\nTOC entry:           id:%s  offset:%lx  size:%lx  ptr:%p  checksum:%lx  type:%d\n" ,
+               dict->toc[index].id , dict->toc[index].offset ,
+               dict->toc[index].size , dict->toc[index].ptr ,
+               dict->toc[index].checksum , dict->toc[index].type );
+   } /* endif */
+
+   return( TRUE );
+}
+
+/***********
+**  Look up and id in the table of contents.
+**  Return its index (-1 on failure).
+***********/
+
+int dict_toc_index( DICTIONARY *dict , char *toc_id )
+{  int index;
+
+   for ( index = 0 ; index < dict->sig->toc_size ; index++ ) {
+           if ( strcmp(dict->toc[index].id,toc_id) == 0 )
+                   return( index );
+   } /* endfor */
+
+   return( -1 );
+}
+
+/***********
+**  Compute a block checksum.
+**  (Currently just returns 0.)
+***********/
+
+unsigned long compute_checksum( size_t size , char *block )
+{
+    NOOP(size);
+    NOOP(block);
+    return( 0 );
+}
+
+/***********
+**  Create a dictionary paramter entry.
+***********/
+
+DICT_PARM_ENTRY *dict_make_parm_entry( char *id , unsigned long value )
+{  static DICT_PARM_ENTRY  *entry;
+
+   entry = (DICT_PARM_ENTRY *) malloc( sizeof(DICT_PARM_ENTRY) );
+   if ( entry == NULL )
+      return(NULL);
+
+   strncpy( entry->id , id , 13 );
+   entry->value = value;
+
+   return( entry );
+}
+
+/***********
+**  Look up and id in the parameter array.
+**  Return its index (-1 on failure).
+***********/
+
+int dict_parm_index( DICTIONARY *dict , char *parm_id )
+{  long index;
+
+   for ( index = 0 ; index < dict->sig->nparms ; index++ ) {
+           if ( strcmp( dict->parm[index].id , parm_id ) == 0 )
+                   return( (int) index );
+   } /* endfor */
+
+   return( -1 );
+}
+
+/***********
+**  Reset table of contents offsets and checksums
+**  in preparation for dict_save().
+***********/
+
+BOOLEANC dict_reset_toc_offsets( DICTIONARY *dict )
+{  int  i;
+   long offset;
+
+   offset = sizeof(DICT_SIG)
+          + dict->sig->toc_size * sizeof(DICT_TOC_ENTRY);
+   for ( i = 0 ; i < dict->sig->toc_size ; i++ ) {
+      dict->toc[i].offset = offset;
+      offset += dict->toc[i].size;
+      dict->toc[i].checksum =
+         compute_checksum( dict->toc[i].size , dict->toc[i].ptr );
+   } /* endfor */
+
+   return( TRUE );
+}
+
+/***********
+**  Load the names of the dictionary parameters.
+**  14 parms
+***********/
+
+BOOLEANC dict_set_parm_ids( DICTIONARY *dict )
+{
+   if ( dict==NULL || dict->sig == NULL ) {
+      signal_error( "dict_set_parm_ids: Allocate dict and signature first." , "" , 0 );
+      return( FALSE );
+   }
+   dict->sig->nparms = 14;
+   strcpy( dict->parm[0].id , "FLAGS_______" );
+   strcpy( dict->parm[1].id , "ENTRY_COUNT_" );
+   strcpy( dict->parm[2].id , "ARRAY_SIZE__" );
+   strcpy( dict->parm[3].id , "ARRAY_USED__" );
+   strcpy( dict->parm[4].id , "ARR_GROW_CT_" );
+   strcpy( dict->parm[5].id , "STRING_MAX__" );
+   strcpy( dict->parm[6].id , "STR_GROW_CT_" );
+   strcpy( dict->parm[7].id , "LONG_CHAIN__" );
+   strcpy( dict->parm[8].id , "ALLOW_CHAIN_" );
+   strcpy( dict->parm[9].id , "HASH_TAB_SIZ" );
+   strcpy( dict->parm[10].id , "HASH_MASK___" );
+   strcpy( dict->parm[11].id , "HASH_GROW_CT" );
+   strcpy( dict->parm[12].id , "CHECK_VALUE_" );
+   strcpy( dict->parm[13].id , "SCAN_STR_IX_" );
+
+   return( TRUE );
+}
+
+/***********
+**  Set the dictionary parm structure from the values in the dict structure.
+**  14 parms
+***********/
+
+BOOLEANC dict_set_parm_values( DICTIONARY *dict )
+{  int  index;
+
+   if ( (index=dict_parm_index(dict,"FLAGS_______")) == -1 )
+      return( FALSE );
+   dict->parm[index].value = (unsigned long)dict->flags;
+
+   if ( (index=dict_parm_index(dict,"ENTRY_COUNT_")) == -1 )
+      return( FALSE );
+   dict->parm[index].value = (unsigned long)dict->entry_count;
+
+   if ( (index=dict_parm_index(dict,"ARRAY_SIZE__")) == -1 )
+      return( FALSE );
+   dict->parm[index].value = (unsigned long)dict->array_size;
+
+   if ( (index=dict_parm_index(dict,"ARRAY_USED__")) == -1 )
+      return( FALSE );
+   dict->parm[index].value = (unsigned long)dict->array_used;
+
+   if ( (index=dict_parm_index(dict,"ARR_GROW_CT_")) == -1 )
+      return( FALSE );
+   dict->parm[index].value = (unsigned long)dict->array_growth_count;
+
+   if ( (index=dict_parm_index(dict,"STRING_MAX__")) == -1 )
+      return( FALSE );
+   dict->parm[index].value = (unsigned long)dict->string_max;
+
+   if ( (index=dict_parm_index(dict,"STR_GROW_CT_")) == -1 )
+      return( FALSE );
+   dict->parm[index].value = (unsigned long)dict->string_growth_count;
+
+   if ( (index=dict_parm_index(dict,"LONG_CHAIN__")) == -1 )
+      return( FALSE );
+   dict->parm[index].value = (unsigned long)dict->longest_chain_length;
+
+   if ( (index=dict_parm_index(dict,"ALLOW_CHAIN_")) == -1 )
+      return( FALSE );
+   dict->parm[index].value = (unsigned long)dict->allowable_chain_length;
+
+   if ( (index=dict_parm_index(dict,"HASH_TAB_SIZ")) == -1 )
+      return( FALSE );
+   dict->parm[index].value = (unsigned long)dict->table_size;
+
+   if ( (index=dict_parm_index(dict,"HASH_MASK___")) == -1 )
+      return( FALSE );
+   dict->parm[index].value = (unsigned long)dict->hash_mask;
+
+   if ( (index=dict_parm_index(dict,"HASH_GROW_CT")) == -1 )
+      return( FALSE );
+   dict->parm[index].value = (unsigned long)dict->hash_growth_count;
+
+   if ( (index=dict_parm_index(dict,"CHECK_VALUE_")) == -1 )
+      return( FALSE );
+   dict->parm[index].value = (unsigned long)dict->check_value;
+
+   if ( (index=dict_parm_index(dict,"SCAN_STR_IX_")) == -1 )
+      return( FALSE );
+   dict->parm[index].value = (unsigned long)dict->scan_string_index;
+
+   return( TRUE );
+}
+
+
+/***********
+**  Set the values in the dict structure from the dictionary parm structure.
+**  14 parms
+***********/
+
+BOOLEANC dict_set_parm_variables( DICTIONARY *dict )
+{  int  index;
+
+   if ( (index=dict_parm_index(dict,"FLAGS_______")) == -1 )
+      return( FALSE );
+   dict->flags = (unsigned long)dict->parm[index].value;
+
+   if ( (index=dict_parm_index(dict,"ENTRY_COUNT_")) == -1 )
+      return( FALSE );
+   dict->entry_count = (long)dict->parm[index].value;
+
+   if ( (index=dict_parm_index(dict,"ARRAY_SIZE__")) == -1 )
+      return( FALSE );
+   dict->array_size = (long)dict->parm[index].value;
+
+   if ( (index=dict_parm_index(dict,"ARRAY_USED__")) == -1 )
+      return( FALSE );
+   dict->array_used = (long)dict->parm[index].value;
+
+   if ( (index=dict_parm_index(dict,"ARR_GROW_CT_")) == -1 )
+      return( FALSE );
+   dict->array_growth_count = (int)dict->parm[index].value;
+
+   if ( (index=dict_parm_index(dict,"STRING_MAX__")) == -1 )
+      return( FALSE );
+   dict->string_max = (long)dict->parm[index].value ;
+
+   if ( (index=dict_parm_index(dict,"STR_GROW_CT_")) == -1 )
+      return( FALSE );
+   dict->string_growth_count = (int)dict->parm[index].value;
+
+   if ( (index=dict_parm_index(dict,"LONG_CHAIN__")) == -1 )
+      return( FALSE );
+   dict->longest_chain_length = (int)dict->parm[index].value;
+
+   if ( (index=dict_parm_index(dict,"ALLOW_CHAIN_")) == -1 )
+      return( FALSE );
+   dict->allowable_chain_length = (int)dict->parm[index].value;
+
+   if ( (index=dict_parm_index(dict,"HASH_TAB_SIZ")) == -1 )
+      return( FALSE );
+   dict->table_size = (long)dict->parm[index].value;
+
+   if ( (index=dict_parm_index(dict,"HASH_MASK___")) == -1 )
+      return( FALSE );
+   dict->hash_mask = (unsigned long)dict->parm[index].value;
+
+   if ( (index=dict_parm_index(dict,"HASH_GROW_CT")) == -1 )
+      return( FALSE );
+   dict->hash_growth_count = (int)dict->parm[index].value;
+
+   if ( (index=dict_parm_index(dict,"CHECK_VALUE_")) == -1 )
+      return( FALSE );
+   dict->check_value = (unsigned long)dict->parm[index].value;
+
+   if ( (index=dict_parm_index(dict,"SCAN_STR_IX_")) == -1 )
+      return( FALSE );
+   dict->scan_string_index = (long)dict->parm[index].value;
+
+   return( TRUE );
+}
+
+/***********
+**  If trace (global) > 0 , signal an error
+**  If severity > 0 , abort
+***********/
+
+void signal_error( char *header , char *message , int severity )
+{
+  FILE *fpe;
+
+  if ( trace > 0 ) {
+     printf( "%s: %s\n" , header , message );
+     fpe = fopen( "ERROR.FIL" , "a" );
+     fprintf( fpe , "\n%s: %s\n" , header , message );
+     fclose( fpe );
+  } /* endif */
+
+  if ( severity > 0 )
+     abort();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/dictutil.h	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,116 @@
+/*
+    dictutil.h
+
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1995 Herb Chong
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+/****************************************************************/
+/*     HEADERS FOR DICTIONARY MAINTENENCE ROUTINE UTILITIES     */
+/****************************************************************/
+
+#ifndef dictutil_h_included
+#define dictutil_h_included
+
+static char dictutil_sccsid[] = "%W% %G%";
+
+#include <stdio.h>
+#include "dict.h"
+
+/*-------------------------------
+  Binary read of a block of bytes
+  -------------------------------*/
+extern int block_read(
+        FILE  *fi,
+        char  *buffer,
+        size_t  count,
+        long  offset );
+
+/*--------------------------------
+  Binary write of a block of bytes
+  --------------------------------*/
+extern int block_write(
+        FILE  *fo,
+        char  *buffer,
+        size_t  count );
+
+/*--------------------------------------
+  Compute a checksum of a block of bytes
+  --------------------------------------*/
+extern unsigned long compute_checksum(
+        size_t size,
+        char  *block );
+
+/*-----------------------------------------------------------------
+  Load a block of bytes from a compiled dictionary file into memory
+  -----------------------------------------------------------------*/
+extern void *dict_load_block(
+        DICTIONARY  *dict,
+        char        *toc_id,
+        FILE        *fi,
+        void        *block );
+
+/*-----------------------------------
+  Create a dictionary parameter entry
+  -----------------------------------*/
+extern DICT_PARM_ENTRY *dict_make_parm_entry(
+        char *id,
+        unsigned long value );
+
+/*------------------------------------
+  Look up an id in the parameter array
+  ------------------------------------*/
+extern int dict_parm_index(
+        DICTIONARY  *dict,
+        char        *parm_id );
+
+/*-------------------------------
+  Reset table of contents offsets
+  -------------------------------*/
+extern BOOLEANC dict_reset_toc_offsets(
+        DICTIONARY  *dict );
+
+/*-----------------------------------------------------------------
+  Save a block of bytes from memory into a compiled dictionary file
+  -----------------------------------------------------------------*/
+extern BOOLEANC dict_save_block(
+        DICTIONARY  *dict,
+        char        *toc_id,
+        FILE        *fo );
+
+/*--------------------------------------------------------------------
+  Set the dictionary parm values from the values in the dict structure
+  --------------------------------------------------------------------*/
+extern BOOLEANC dict_set_parm_values(
+        DICTIONARY  *dict );
+
+/*--------------------------------------------------------------------
+  Set the values in the dict structure from the dictionary parm values
+  --------------------------------------------------------------------*/
+extern BOOLEANC dict_set_parm_variables(
+        DICTIONARY  *dict );
+
+/*---------------------------
+  Set the dictionary parm ids
+  ---------------------------*/
+extern BOOLEANC dict_set_parm_ids(
+        DICTIONARY *dict );
+
+/*--------------------------------------
+  Look up an id in the table of contents
+  --------------------------------------*/
+extern int dict_toc_index(
+        DICTIONARY  *dict,
+        char        *toc_id );
+
+/*------------------------------------
+  Record and error and abort if needed
+  ------------------------------------*/
+extern void signal_error(
+	char *header,
+	char *message,
+	int severity );
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/encumb.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,185 @@
+/*
+    encumb.c - Stuff to do with encumberance
+ 
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include "rogue.h"
+
+/*
+    updpack()
+        Update his pack weight and adjust fooduse accordingly
+*/
+
+void
+updpack(void)
+{
+    int curcarry = packweight();
+
+    pstats.s_carry = totalenc();    /* update max encumb */
+
+    if (is_carrying(TR_PURSE))
+        pstats.s_carry += 1000;
+
+    foodlev = 0;
+
+    switch ((curcarry * 5) / pstats.s_carry)   /* % of total capacity */
+    {
+        case 5:     /* 100 % */
+            foodlev++;
+
+        case 4:     /* 80 % */
+            if (rnd(100) < 80)
+                foodlev++;
+
+        case 3:     /* 60 % */
+            if (rnd(100) < 60)
+                foodlev++;
+
+        case 2:     /* 40 % */
+            if (rnd(100) < 40)
+                foodlev++;
+
+        case 1:     /* 20 % */
+            if (rnd(100) < 20)
+                foodlev++;
+
+        case 0:     /* 0 % */
+            foodlev++;
+    }
+
+    pstats.s_pack = curcarry;   /* update pack weight */
+
+    if (is_carrying(TR_PURSE))  /* makes pack lighter */
+        foodlev--;
+}
+
+
+/*
+    packweight()
+        Get the total weight of the hero's pack
+*/
+
+int
+packweight(void)
+{
+    struct linked_list  *pc;
+    int weight = 0;
+
+    for (pc = pack; pc != NULL; pc = next(pc))
+    {
+        struct object   *obj = OBJPTR(pc);
+
+        weight += itemweight(obj) * obj->o_count;
+    }
+
+    if (weight < 0)     /* caused by artifacts or blessed items */
+        weight = 0;
+
+    return (weight);
+}
+
+
+/*
+    itemweight()
+        Get the weight of an object
+*/
+
+int
+itemweight(struct object *wh)
+{
+    int weight = wh->o_weight;  /* get base weight */
+    int ac;
+
+    switch (wh->o_type)
+    {
+        case ARMOR:  /* 10% for each plus or minus*/
+            ac = armors[wh->o_which].a_class - wh->o_ac;
+            weight *= (10 - ac) / 10;
+            break;
+
+        case WEAPON:
+            if ((wh->o_hplus + wh->o_dplus) > 0)
+                weight /= 2;
+    }
+
+    if (wh->o_flags & ISCURSED)
+        weight += weight / 2;   /* +50% for cursed */
+    else if (wh->o_flags & ISBLESSED)
+        weight -= weight / 5;   /* -20% for blessed */
+
+    if (weight < 0)
+        weight = 0;
+
+    return (weight);
+}
+
+
+/*
+    playenc()
+        Get hero's carrying ability above norm 50 units per point of STR
+        over 10, 300 units per plus on R_CARRYING 1000 units for TR_PURSE
+*/
+
+int
+playenc(void)
+{
+    int ret_val = (pstats.s_str - 10) * 50;
+
+    if (is_wearing(R_CARRYING))
+        ret_val += ring_value(R_CARRYING) * 300;
+
+    return (ret_val);
+}
+
+
+/*
+    totalenc()
+        Get total weight that the hero can carry
+*/
+
+int
+totalenc(void)
+{
+    int wtotal = 1400 + playenc();
+
+    switch (hungry_state)
+    {
+        case F_OK:
+        case F_HUNGRY: /* no change */
+            break;
+
+        case F_WEAK:
+            wtotal -= wtotal / 4;  /* 25% off weak */
+            break;
+
+        case F_FAINT:
+            wtotal /= 2;    /* 50% off faint */
+            break;
+    }
+
+    return (wtotal);
+}
+
+
+/*
+    hitweight()
+        Gets the fighting ability according to current weight This
+        returns a  +2 hit for very light pack weight, +1 hit
+        for light pack weight, 0 hit for medium pack weight, -1 hit for heavy
+        pack weight, -2 hit for very heavy pack weight
+*/
+
+int
+hitweight(void)
+{
+    return(3 - foodlev);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/fight.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,2175 @@
+/*
+    fight.c - All the fighting gets done here
+ 
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+ * This are the beginning experience levels for all players all further
+ * experience levels are computed by multiplying by 2
+ */
+
+static long e_levels[10] =
+{
+    143L,           /* Fighter     */
+    182L,           /* Paladin     */
+    169L,           /* Ranger      */
+    127L,           /* Cleric      */
+    154L,           /* Druid       */
+    185L,           /* Magician    */
+    169L,           /* Illusionist */
+    112L,           /* Thief       */
+    126L,           /* Assasin     */
+    319L            /* Ninja       */
+};
+
+static struct matrix att_mat[11] =
+{
+    /* Base, Max_lvl, Factor, Offset, Range */
+
+    {  10,     17,      2,      1,      2     },  /* fi */
+    {  10,     17,      2,      1,      2     },  /* pa */
+    {  10,     17,      2,      1,      2     },  /* ra */
+    {  10,     19,      2,      1,      3     },  /* cl */
+    {  10,     19,      2,      1,      3     },  /* dr */
+    {   9,     21,      2,      1,      5     },  /* mu */
+    {   9,     21,      2,      1,      5     },  /* il */
+    {  10,     21,      2,      1,      4     },  /* th */
+    {  10,     21,      2,      1,      4     },  /* as */
+    {  10,     21,      2,      1,      4     },  /* nj */
+    {   7,     25,      1,      0,      2     }   /* mn */
+};
+
+void
+do_fight(coord dir, int tothedeath)
+{
+    int x,y;
+
+    x = dir.x;
+    y = dir.y;
+
+    if (!tothedeath && pstats.s_hpt < max_stats.s_hpt / 3)
+    {
+        msg("That's not wise.");
+
+        after = fighting = FALSE;
+        return;
+    }
+
+    if (isalpha(CCHAR(winat(hero.y + y, hero.x + x))))
+    {
+        after = fighting = TRUE;
+        do_move(y, x);
+    }
+    else
+    {
+        if (fighting == FALSE)
+            msg("Nothing there.");
+
+        after = fighting = FALSE;
+    }
+
+    return;
+}
+
+/*
+    fight()
+        The player attacks the monster.
+*/
+
+int
+fight(coord *mp, struct object *weap, int thrown)
+{
+    struct thing    *tp;
+    struct linked_list  *item;
+    int    did_hit = TRUE;
+    char    *mname;
+
+    /* Find the monster we want to fight */
+
+    if ((item = find_mons(mp->y, mp->x)) == NULL)
+    {
+        debug("Fight what @ %d,%d", mp->y, mp->x);
+        return 0;
+    }
+
+    tp = THINGPTR(item);
+
+    mname = (on(player, ISBLIND)) ? "it" : monsters[tp->t_index].m_name;
+
+    /* Since we are fighting, things are not quiet so no healing takes place */
+
+    player.t_rest_hpt = player.t_rest_pow = 0;
+    tp->t_rest_hpt = tp->t_rest_pow = 0;
+
+    /*  Let him know it was really a mimic (if it was one). */
+
+    if (off(player, ISBLIND))
+    {
+        if (on(*tp, ISDISGUISE) && (tp->t_type != tp->t_disguise))
+        {
+            msg("Wait! That's a %s!", mname);
+            turn_off(*tp, ISDISGUISE);
+            did_hit = thrown;
+        }
+
+        if (on(*tp, CANSURPRISE))
+        {
+            turn_off(*tp, CANSURPRISE);
+            if ((player.t_ctype == C_RANGER && rnd(6) != 0) ||
+                (player.t_ctype == C_NINJA && rnd(pstats.s_lvl / 2)
+                 != 0))
+                msg("You notice a %s trying to hide!", mname);
+            else
+            {
+                msg("Wait! There's a %s!", mname);
+                did_hit = thrown;
+            }
+        }
+    }
+
+    /* Protection from Normal Missiles */
+
+    if (thrown && on(*tp, HASMSHIELD))
+    {
+        msg("The %s slows as it approaches %s.",
+            weaps[weap->o_which].w_name, mname);
+
+        did_hit = FALSE;
+    }
+
+    if (did_hit)
+    {
+        did_hit = FALSE;
+
+        if (!can_blink(tp) &&
+            (off(*tp, MAGICHIT) || (weap != NULL &&
+                   (weap->o_hplus > 0 || weap->o_dplus > 0))) &&
+            (off(*tp, BMAGICHIT) || (weap != NULL &&
+                   (weap->o_hplus > 2 || weap->o_dplus > 2))) &&
+            roll_em(&player, tp, weap, thrown, cur_weapon))
+        {
+            did_hit = TRUE;
+            tp->t_wasshot = TRUE;
+
+            if (thrown)
+            {
+                if (weap != NULL && weap->o_type == WEAPON
+                    && weap->o_which == GRENADE)
+                {
+                    hearmsg("BOOOM!");
+                    aggravate();
+                }
+
+                thunk(weap, mname);
+            }
+            else
+                hit(mname);
+
+            /* hitting a friendly monster is curtains */
+
+            if (on(*tp, ISFRIENDLY))
+            {
+                turn_off(*tp, ISFRIENDLY);
+                turn_on(*tp, ISMEAN);
+            }
+
+            /* Charmed monsters become uncharmed */
+
+            if (on(*tp, ISCHARMED))
+            {
+                turn_off(*tp, ISCHARMED);
+                turn_on(*tp, ISMEAN);
+            }
+
+            /*
+             * If the player hit a rust monster, he better have a
+             * + weapon
+            */
+
+            if (on(*tp, CANRUST))
+            {
+                if (!thrown && (weap != NULL) &&
+                    (weap->o_flags & ISMETAL) &&
+                    !(weap->o_flags & ISPROT) &&
+                    !(weap->o_flags & ISSILVER) &&
+                (weap->o_hplus < 1) && (weap->o_dplus < 1))
+                {
+                    if (rnd(100) < 50)
+                        weap->o_hplus--;
+                    else
+                        weap->o_dplus--;
+
+                    msg("Your %s weakens!", weaps[weap->o_which].w_name);
+                }
+                else if (!thrown && weap != NULL && (weap->o_flags & ISMETAL))
+                    msg("The rust vanishes from your %s!",
+                        weaps[weap->o_which].w_name);
+            }
+
+            /* flammable monsters die from burning weapons */
+
+            if (thrown && on(*tp, CANBBURN) &&
+                (weap->o_flags & CANBURN) &&
+                !save_throw(VS_WAND, tp))
+            {
+                msg("The %s vanishes in a ball of flame.",
+                    monsters[tp->t_index].m_name);
+
+                tp->t_stats.s_hpt = 0;
+            }
+
+            /* spores explode and infest hero  */
+
+            if (on(*tp, CANSPORE))
+            {
+                msg("The %s explodes in a cloud of dust.",
+                    monsters[tp->t_index].m_name);
+
+                if (is_wearing(R_HEALTH) ||
+                    player.t_ctype == C_PALADIN ||
+                    (player.t_ctype == C_NINJA && pstats.s_lvl
+                     > 6) ||
+                    thrown && rnd(50) > 0 ||
+                    rnd(20) > 0)
+                {
+                    msg("The dust makes it hard to breath.");
+                }
+                else
+                {
+                    msg("You have contracted a parasitic infestation!");
+
+                    infest_dam++;
+                    turn_on(player, HASINFEST);
+                }
+
+                tp->t_stats.s_hpt = 0;
+            }
+
+            /* fireproof monsters laugh at you when burning weapon hits */
+
+            if (thrown && on(*tp, NOFIRE) && (weap->o_flags & CANBURN))
+                msg("The %s laughs as the %s bounces.",
+                    monsters[tp->t_index].m_name,
+                    weaps[weap->o_which].w_name);
+
+            /* sharp weapons have no effect on NOSHARP monsters */
+
+            if (on(*tp, NOSHARP) && (weap != NULL) &&
+                (weap->o_flags & ISSHARP))
+            {
+                msg("The %s has no effect on the %s!",
+                    weaps[weap->o_which].w_name,
+                    monsters[tp->t_index].m_name);
+
+                fighting = FALSE;
+            }
+
+            /* metal weapons pass through NOMETAL monsters */
+
+            if (on(*tp, NOMETAL) && (weap != NULL) &&
+                (weap->o_flags & ISMETAL))
+            {
+                msg("The %s passes through the %s!",
+                    weaps[weap->o_which].w_name,
+                    monsters[tp->t_index].m_name);
+
+                fighting = FALSE;
+            }
+
+            /*
+             * If the player hit something that shrieks, wake the
+             * dungeon
+             */
+
+            if (on(*tp, CANSHRIEK))
+            {
+                turn_off(*tp, CANSHRIEK);
+
+                if (on(player, CANHEAR))
+                {
+                    msg("You are stunned by the %s's shriek.", mname);
+                    no_command += 4 + rnd(8);
+                }
+                else if (off(player, ISDEAF))
+                    msg("The %s emits a piercing shriek.", mname);
+                else
+                    msg("The %s seems to be trying to make some noise.", mname);
+
+                aggravate();
+
+                if (rnd(wizard ? 3 : 39) == 0 && cur_armor
+                    != NULL
+                    && cur_armor->o_which == CRYSTAL_ARMOR)
+                {
+                    struct linked_list  *itm;
+                    struct object   *obj;
+
+                    for (itm = pack; itm != NULL; itm = next(itm))
+                    {
+                        obj = OBJPTR(itm);
+
+                        if (obj == cur_armor)
+                            break;
+                    }
+
+                    if (itm == NULL)
+                        debug("Can't find crystalline armor being worn.");
+                    else
+                    {
+                        msg("Your armor shatters from the shriek.");
+                        cur_armor = NULL;
+                        del_pack(itm);
+                    }
+                }
+            }
+
+            /*
+             * If the player hit something that can surprise, it
+             * can't now
+             */
+
+            if (on(*tp, CANSURPRISE))
+                turn_off(*tp, CANSURPRISE);
+
+            /*
+             * If the player hit something that can summon, it
+             * will try to
+             */
+
+            summon_help(tp, NOFORCE);
+
+            /* Can the player confuse? */
+
+            if (on(player, CANHUH) && !thrown)
+            {
+                seemsg("Your hands stop glowing red!");
+                seemsg("The %s appears confused.", mname);
+                turn_on(*tp, ISHUH);
+                turn_off(player, CANHUH);
+            }
+
+            /* Merchants just disappear if hit */
+
+            /*
+             * increases prices and curses objects from now on
+             * though
+             */
+
+            if (on(*tp, CANSELL))
+            {
+                msg("The %s disappears with his wares with a BOOM and a flash.",
+                     mname);
+                killed(NULL, item, NOMESSAGE, NOPOINTS);
+                aggravate();
+                luck++;
+            }
+            else if (tp->t_stats.s_hpt <= 0)
+                killed(&player, item, MESSAGE, POINTS);
+
+            /*
+             * If the monster is fairly intelligent and about to
+             * die, it may turn tail and run.
+             */
+
+            else if ((tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt / 10)) &&
+                 (rnd(25) < tp->t_stats.s_intel))
+            {
+                turn_on(*tp, ISFLEE);
+
+                /* If monster was suffocating, stop it */
+
+                if (on(*tp, DIDSUFFOCATE))
+                {
+                    turn_off(*tp, DIDSUFFOCATE);
+                    extinguish_fuse(FUSE_SUFFOCATE);
+                }
+
+                /* If monster held us, stop it */
+
+                if (on(*tp, DIDHOLD) && (--hold_count == 0))
+                    turn_off(player, ISHELD);
+
+                turn_off(*tp, DIDHOLD);
+
+                if (on(*tp, CANTELEPORT))
+                {
+                    int rm;
+
+                    /*
+                     * Erase the monster from the old
+                     * position
+                     */
+
+                    if (isalpha(mvwinch(cw, tp->t_pos.y, tp->t_pos.x)))
+                        mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
+
+                    mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' ');
+
+                    /* Get a new position */
+
+                    do
+                    {
+                        rm = rnd_room();
+                        rnd_pos(&rooms[rm], &tp->t_pos);
+                    }
+                    while (winat(tp->t_pos.y, tp->t_pos.x) != FLOOR);
+
+                    /* Put it there */
+
+                    mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type);
+                    tp->t_oldch = CCHAR( mvwinch(cw, tp->t_pos.y, tp->t_pos.x) );
+                    seemsg("The %s seems to have disappeared!", mname);
+                }
+            }
+        }
+        else if (thrown)
+            bounce(weap, mname);
+        else
+            miss(mname);
+    }
+
+    if (curr_mons)
+        chase_it(mp,&player);   /* after so that backstabbing can happen */
+
+    count = 0;
+
+    return(did_hit);
+}
+
+/*
+    attack()
+        The monster attacks the player
+*/
+
+int
+attack(struct thing *mp, struct object *weapon, int thrown)
+{
+    char    *mname;
+    int    did_hit = FALSE;
+
+    /* If the monster is in a wall, it cannot attack */
+
+    if (on(*mp, ISINWALL))
+        return (FALSE);
+
+    /* If two monsters start to gang up on our hero, stop fight mode */
+
+    if (fighting)
+    {
+        if (beast == NULL)
+            beast = mp;
+        else if (beast != mp)
+            fighting = FALSE;
+    }
+
+    /*
+       Since this is an attack, stop running and any healing that was
+       going on at the time.
+    */
+
+    running = FALSE;
+    player.t_rest_hpt = player.t_rest_pow = 0;
+    mp->t_rest_hpt = mp->t_rest_pow = 0;
+
+    if (on(*mp, ISDISGUISE) && off(player, ISBLIND))
+        turn_off(*mp, ISDISGUISE);
+    mname = on(player, ISBLIND) ? "the monster" :
+        monsters[mp->t_index].m_name;
+
+    if (roll_em(mp, &player, weapon, thrown, wield_weap(weapon, mp)) &&
+        (!thrown || off(player, HASMSHIELD)))
+    {
+        did_hit = TRUE;
+
+        m_thunk(weapon, mname);
+
+        if (pstats.s_hpt <= 0)
+        {
+            death(mp->t_index); /* Bye bye life ... */
+            return TRUE;
+        }
+
+        /* surprising monsters appear after they shoot at you */
+
+        if (thrown && on(*mp, CANSURPRISE))
+            turn_off(*mp, CANSURPRISE);
+        else if (!thrown)
+        {
+
+            /*
+               If a vampire hits, it may take half your hit
+               points
+            */
+
+            if ( on(*mp, CANSUCK) && !save(VS_MAGIC) )
+            {
+                if (pstats.s_hpt == 1)
+                {
+                    death(mp->t_index);
+                    return TRUE;
+                }
+                else
+                {
+                    pstats.s_hpt /= 2;
+                    msg("You feel your life force being drawn from you.");
+                }
+            }
+
+            /*
+               strong monsters can shatter or gong crystalline
+               armor
+            */
+
+            if (cur_armor != NULL && cur_armor->o_which == CRYSTAL_ARMOR)
+            {
+                if (rnd(mp->t_stats.s_str + (cur_armor->o_ac / 2)) > 20)
+                {
+                    struct linked_list  *item;
+                    struct object   *obj;
+
+                    for (item = pack; item != NULL; item = next(item))
+                    {
+                        obj = OBJPTR(item);
+
+                        if (obj == cur_armor)
+                            break;
+                    }
+
+                    if (item == NULL)
+                        debug("Can't find crystalline armor being worn.");
+                    else
+                    {
+                        msg("Your armor is shattered by the blow.");
+                        cur_armor = NULL;
+                        del_pack(item);
+                    }
+                }
+                else if (rnd(mp->t_stats.s_str) > 15)
+                {
+                    msg("Your armor rings from the blow.");
+                    aggravate();
+                }
+            }
+
+            /* Stinking monsters reduce the player's strength */
+
+            if (on(*mp, CANSTINK))
+            {
+                turn_off(*mp, CANSTINK);
+
+                if (player.t_ctype != C_PALADIN
+                    && !(player.t_ctype == C_NINJA && pstats.s_lvl > 12)
+                    && !save(VS_POISON))
+                {
+                    if (on(player, CANSCENT))
+                    {
+                        msg("You pass out from the stench of the %s.", mname);
+                        no_command += 4 + rnd(8);
+                    }
+                    else if (off(player, ISUNSMELL))
+                        msg("The stench of the %s sickens you.", mname);
+
+                    if (on(player, HASSTINK))
+                        lengthen_fuse(FUSE_UNSTINK, STINKTIME);
+                    else
+                    {
+                        turn_on(player, HASSTINK);
+                        light_fuse(FUSE_UNSTINK, 0, STINKTIME, AFTER);
+                    }
+                }
+            }
+
+            /* chilling monster reduces strength permanently */
+
+            if (on(*mp, CANCHILL) &&
+                (cur_armor == NULL || cur_armor->o_which != CRYSTAL_ARMOR))
+            {
+                msg("You cringe at the %s's chilling touch.", mname);
+
+                if (!is_wearing(R_SUSABILITY))
+                {
+                    chg_str(-1, FALSE, TRUE);
+
+                    if (lost_str == 0)
+                        light_fuse(FUSE_RES_STRENGTH, 0, CHILLTIME, AFTER);
+                    else
+                        lengthen_fuse(FUSE_RES_STRENGTH, CHILLTIME);
+                }
+            }
+
+            /* itching monsters reduce dexterity (temporarily) */
+
+            if (on(*mp, CANITCH) && player.t_ctype != C_PALADIN
+                && !(player.t_ctype == C_NINJA && pstats.s_lvl > 12)
+                && !save(VS_POISON))
+            {
+                msg("The claws of the %s scratch you!", mname);
+
+                if (is_wearing(R_SUSABILITY))
+                    msg("The scratch has no effect.");
+                else
+                {
+                    msg("You feel a burning itch.");
+                    turn_on(player, HASITCH);
+                    chg_dext(-1, FALSE, TRUE);
+                    light_fuse(FUSE_UNITCH, 0, roll(4, 6), AFTER);
+                }
+            }
+
+            /* a hugging monster may SQUEEEEEEEZE */
+
+            if (on(*mp, CANHUG) &&
+                (cur_armor == NULL || cur_armor->o_which != CRYSTAL_ARMOR))
+            {
+                if (roll(1, 20) >= 18 || roll(1, 20) >= 18)
+                {
+                    msg("The %s squeezes you against itself.", mname);
+
+                    if ((pstats.s_hpt -= roll(2, 8)) <= 0)
+                    {
+                        death(mp->t_index);
+                        return TRUE;
+                    }
+                }
+            }
+
+            /* a trampling monster may step on the player */
+
+            if (on(*mp, CANTRAMPLE))
+            {
+                if (roll(1, 20) >= 16 || roll(1, 20) >= 16)
+                {
+                    msg("The %s steps on you.", mname);
+
+                    if ((pstats.s_hpt -= roll(3, mp->t_stats.s_lvl)) <= 0)
+                    {
+                        death(mp->t_index);
+                        return TRUE;
+                    }
+                }
+            }
+
+            /* a disease-carrying monster may transmit the disease */
+
+            if (on(*mp, CANDISEASE) &&
+                (rnd(pstats.s_const) < mp->t_stats.s_lvl) &&
+                off(player, HASDISEASE))
+            {
+
+                if (is_wearing(R_HEALTH)
+                    || (player.t_ctype == C_PALADIN)
+                    || (player.t_ctype == C_NINJA &&
+                    pstats.s_lvl > 6))
+                    msg("The wound heals quickly.");
+                else
+                {
+                    turn_on(player, HASDISEASE);
+                    light_fuse(FUSE_CURE_DISEASE,0,roll(4,4) * SICKTIME, AFTER);
+                    msg("You have contracted a disease!");
+                }
+            }
+
+            /* a rust monster will weaken your armor */
+
+           if (on(*mp, CANRUST))
+           {
+                if (cur_armor != NULL &&
+                    cur_armor->o_which != SOFT_LEATHER &&
+                    cur_armor->o_which != HEAVY_LEATHER &&
+                    cur_armor->o_which != CUIRBOLILLI &&
+                    cur_armor->o_which != PADDED_ARMOR &&
+                    cur_armor->o_which != CRYSTAL_ARMOR &&
+                    cur_armor->o_which != MITHRIL &&
+                    !(cur_armor->o_flags & ISPROT) &&
+                    cur_armor->o_ac < pstats.s_arm + 1)
+                {
+                    msg("Your armor weakens!");
+                    cur_armor->o_ac++;
+                }
+                else if (cur_armor != NULL &&
+                     (cur_armor->o_flags & ISPROT) &&
+                    cur_armor->o_which != SOFT_LEATHER &&
+                     cur_armor->o_which != HEAVY_LEATHER &&
+                     cur_armor->o_which != CUIRBOLILLI &&
+                    cur_armor->o_which != PADDED_ARMOR &&
+                     cur_armor->o_which != CRYSTAL_ARMOR &&
+                     cur_armor->o_which != MITHRIL)
+                    msg("The rust vanishes instantly!");
+            }
+
+            /* If a surprising monster hit you, you can see it now */
+
+            if (on(*mp, CANSURPRISE))
+                turn_off(*mp, CANSURPRISE);
+
+            /* an infesting monster will give you a parasite or rot */
+
+            if (on(*mp, CANINFEST) && rnd(pstats.s_const) < mp->t_stats.s_lvl)
+            {
+                if (is_wearing(R_HEALTH) || (player.t_ctype == C_PALADIN)
+                    || (player.t_ctype == C_NINJA && pstats.s_lvl > 6))
+                    msg("The wound quickly heals.");
+                else
+                {
+                    turn_off(*mp, CANINFEST);
+                    msg("You have contracted a parasitic infestation!");
+                    infest_dam++;
+                    turn_on(player, HASINFEST);
+                }
+            }
+
+            /* Some monsters have poisonous bites */
+
+            if (on(*mp, CANPOISON) && !save(VS_POISON))
+            {
+                if (is_wearing(R_SUSABILITY) || (player.t_ctype == C_PALADIN)
+                    || (player.t_ctype == C_NINJA && pstats.s_lvl > 12))
+                    msg("The sting has no effect on you!");
+                else
+                {
+                    chg_str(-1, FALSE, FALSE);
+                    msg("You feel a sting in your arm and now feel weaker.");
+                }
+            }
+
+            /* a hideous monster may cause fear by touching */
+
+            if (on(*mp, TOUCHFEAR))
+            {
+                turn_off(*mp, TOUCHFEAR);
+
+                if (!save(VS_WAND)&&!(on(player,ISFLEE)&&(player.t_chasee==mp)))
+                {
+                    if (off(player, SUPERHERO)
+                         && (player.t_ctype != C_PALADIN))
+                    {
+                        turn_on(player, ISFLEE);
+                        player.t_ischasing = FALSE;
+                        player.t_chasee = mp;
+                        msg("The %s's touch terrifies you.", mname);
+                    }
+                    else
+                        msg("The %s's touch feels cold and clammy.", mname);
+                }
+            }
+
+            /* some monsters will suffocate our hero */
+
+            if (on(*mp, CANSUFFOCATE) && (rnd(100) < 15) &&
+                (find_slot(FUSE_SUFFOCATE, FUSE) == NULL))
+            {
+                turn_on(*mp, DIDSUFFOCATE);
+                msg("The %s is beginning to suffocate you.",
+                    mname);
+                light_fuse(FUSE_SUFFOCATE, 0, roll(4, 2), AFTER);
+            }
+
+            /* don't look now, you will get turned to stone */
+
+            if (on(*mp, TOUCHSTONE))
+            {
+                turn_off(*mp, TOUCHSTONE);
+
+                if (on(player, CANINWALL))
+                    msg("The %s's touch has no effect.", mname);
+                else
+                {
+                    if (!save(VS_PETRIFICATION) && rnd(100) < 3)
+                    {
+                        msg("Your body begins to solidify.");
+                        msg("You are turned to stone !!! --More--");
+                        wait_for(' ');
+                        death(D_PETRIFY);
+                        return TRUE;
+                    }
+                    else
+                    {
+                        msg("The %s's touch stiffens your limbs.", mname);
+                        no_command = rnd(STONETIME) + 2;
+                    }
+                }
+            }
+
+            /* Undead might drain energy levels */
+
+            if ((on(*mp, CANDRAIN) || on(*mp, DOUBLEDRAIN)) && rnd(100) < 15)
+            {
+                if (is_carrying(TR_AMULET))
+                   msg("The Amulet protects you from the %s's negative energy!",
+                       mname);
+                else
+                {
+                    lower_level(mp->t_index);
+
+                    if (on(*mp, DOUBLEDRAIN))
+                        lower_level(mp->t_index);
+                }
+
+                turn_on(*mp, DIDDRAIN);
+            }
+
+            /* permanently drain a wisdom point */
+
+            if (on(*mp, DRAINWISDOM) && rnd(100) < 15)
+            {
+                int ring_str;   /* Value of ring strengths */
+
+                /* Undo any ring changes */
+
+                ring_str = ring_value(R_ADDWISDOM) +
+                    (on(player, POWERWISDOM) ? 10 : 0);
+
+                pstats.s_wisdom -= ring_str;
+				
+                msg("You feel slightly less wise now.");
+				
+                pstats.s_wisdom = max(pstats.s_wisdom - 1, 3);
+                max_stats.s_wisdom = pstats.s_wisdom;
+
+                /* Now put back the ring changes */
+
+                pstats.s_wisdom += ring_str;
+
+            }
+
+            /* permanently drain a intelligence point */
+
+            if (on(*mp, DRAINBRAIN) && rnd(100) < 15)
+            {
+                int ring_str;   /* Value of ring strengths */
+
+                /* Undo any ring changes */
+
+                ring_str = ring_value(R_ADDINTEL) +
+                    (on(player, POWERINTEL) ? 10 : 0);
+
+                pstats.s_intel -= ring_str;
+
+                msg("You feel slightly less intelligent now.");
+                pstats.s_intel = max(pstats.s_intel - 1, 3);
+                max_stats.s_intel = pstats.s_intel;
+
+                /* Now put back the ring changes */
+
+                pstats.s_intel += ring_str;
+            }
+
+            /* Violet fungi and others hold the hero */
+
+            if (on(*mp, CANHOLD) && off(*mp, DIDHOLD)
+                && !is_wearing(R_FREEDOM))
+            {
+                turn_on(player, ISHELD);
+                turn_on(*mp, DIDHOLD);
+                hold_count++;
+            }
+
+            /* suckers will suck blood and run away */
+
+            if (on(*mp, CANDRAW))
+            {
+                turn_off(*mp, CANDRAW);
+                turn_on(*mp, ISFLEE);
+                msg("The %s sates itself with your blood.", mname);
+
+                if ((pstats.s_hpt -= 12) <= 0)
+                {
+                    death(mp->t_index);
+                    return TRUE;
+                }
+            }
+
+            /* el stinkos will force a reduction in strength */
+
+            if (on(*mp, CANSMELL))
+            {
+                turn_off(*mp, CANSMELL);
+
+                if (save(VS_MAGIC) || is_wearing(R_SUSABILITY))
+                    msg("You smell an unpleasant odor.");
+                else
+                {
+                    int   odor_str = -(rnd(6) + 1);
+
+                    if (on(player, CANSCENT))
+                    {
+                        msg("You pass out from a foul odor.");
+                        no_command += 4 + rnd(8);
+                    }
+                    else if (off(player, ISUNSMELL))
+                        msg("You are overcome by a foul odor.");
+
+                    if (lost_str == 0)
+                    {
+                        chg_str(odor_str, FALSE, TRUE);
+                        light_fuse(FUSE_RES_STRENGTH, 0, SMELLTIME, AFTER);
+                    }
+                    else
+                        lengthen_fuse(FUSE_RES_STRENGTH, SMELLTIME);
+                }
+            }
+
+            /* Paralyzation */
+
+            if (on(*mp, CANPARALYZE))
+            {
+                turn_off(*mp, CANPARALYZE);
+
+                if (!save(VS_PARALYZATION) && no_command == 0)
+                {
+                    if (on(player, CANINWALL))
+                        msg("The %s's touch has no effect.", mname);
+                    else
+                    {
+                        msg("The %s's touch paralyzes you.", mname);
+                        no_command = FREEZETIME;
+                    }
+                }
+            }
+
+            /* Rotting */
+
+            if (on(*mp, CANROT))
+            {
+                turn_off(*mp, CANROT);
+                turn_on(*mp, DOROT);
+            }
+
+            /* some monsters steal gold */
+
+            if (on(*mp, STEALGOLD))
+            {
+                long    lastpurse;
+                struct linked_list  *item;
+                struct object   *obj;
+
+                lastpurse = purse;
+                purse = (purse > GOLDCALC) ? purse - GOLDCALC : 0L;
+
+                if (!save(VS_MAGIC))
+                    purse = (purse > (4*GOLDCALC)) ? purse-(4*GOLDCALC) : 0L;
+
+                if (purse != lastpurse)
+                {
+                    msg("Your purse feels lighter.");
+
+                    /* Give the gold to the thief */
+
+                    for (item = mp->t_pack; item != NULL; item = next(item))
+                    {
+                        obj = OBJPTR(item);
+
+                        if (obj->o_type == GOLD)
+                        {
+                            obj->o_count += lastpurse - purse;
+                            break;
+                        }
+                    }
+
+                    /* Did we do it? */
+
+                    if (item == NULL)  /* Then make some */
+                    {
+                        item = new_item(sizeof *obj);
+                        obj = OBJPTR(item);
+                        obj->o_type = GOLD;
+                        obj->o_count = lastpurse - purse;
+                        obj->o_hplus = obj->o_dplus = 0;
+                        obj->o_damage = obj->o_hurldmg = "0d0";
+                        obj->o_ac = 11;
+                        obj->o_group = 0;
+                        obj->o_flags = 0;
+                        obj->o_mark[0] = '\0';
+                        obj->o_pos = mp->t_pos;
+
+                        attach(mp->t_pack, item);
+                    }
+                }
+
+                if (rnd(2))
+                    turn_on(*mp, ISFLEE);
+
+                turn_on(*mp, ISINVIS);
+            }
+
+            /* other monsters steal magic */
+
+            if (on(*mp, STEALMAGIC))
+            {
+                struct linked_list  *list, *stealit;
+                struct object   *obj;
+                int worth = 0;
+
+                stealit = NULL;
+
+                for (list = pack; list != NULL; list = next(list))
+                {
+                    obj = OBJPTR(list);
+
+                    if (rnd(33) == 0) /* some stuff degrades */
+                    {
+                        if (obj->o_flags & ISBLESSED)
+                            obj->o_flags &= ~ISBLESSED;
+                        else
+                            obj->o_flags |= ISCURSED;
+
+                        msg("You feel nimble fingers reach into you pack.");
+                    }
+
+                    if ((obj != cur_armor &&
+                         obj != cur_weapon &&
+                         obj != cur_ring[LEFT_1] &&
+                         obj != cur_ring[LEFT_2] &&
+                         obj != cur_ring[LEFT_3] &&
+                         obj != cur_ring[LEFT_4] &&
+                         obj != cur_ring[LEFT_5] &&
+                         obj != cur_ring[RIGHT_1] &&
+                         obj != cur_ring[RIGHT_2] &&
+                         obj != cur_ring[RIGHT_3] &&
+                         obj != cur_ring[RIGHT_4] &&
+                         obj != cur_ring[RIGHT_5] &&
+                         !(obj->o_flags & ISPROT) &&
+                         is_magic(obj)
+                         || level > 45)
+                        && get_worth(obj) > worth)
+                    {
+                        stealit = list;
+                        worth = get_worth(obj);
+                    }
+                }
+
+                if (stealit != NULL)
+                {
+                    struct object   *newobj;
+
+                    newobj = OBJPTR(stealit);
+
+                    if (newobj->o_count > 1 && newobj->o_group == 0)
+                    {
+                        int oc;
+                        struct linked_list  *nitem;
+                        struct object   *op;
+
+                        oc = --(newobj->o_count);
+                        newobj->o_count = 1;
+                        nitem = new_item(sizeof *newobj);
+                        op = OBJPTR(nitem);
+                        *op = *newobj;
+
+                       msg("The %s stole %s!",mname,inv_name(newobj,LOWERCASE));
+                        newobj->o_count = oc;
+                        attach(mp->t_pack, nitem);
+                    }
+                    else
+                    {
+                       msg("The %s stole %s!",mname,inv_name(newobj,LOWERCASE));
+                        newobj->o_flags &= ~ISCURSED;
+                        dropcheck(newobj);
+                        rem_pack(newobj);
+                        attach(mp->t_pack, stealit);
+
+                        if (newobj->o_type == ARTIFACT)
+                            has_artifact &= ~(1 << newobj->o_which);
+                    }
+
+                    if (newobj->o_flags & ISOWNED)
+                    {
+                        turn_on(*mp, NOMOVE);
+                        msg("The %s is transfixed by your ownership spell.",
+                            mname);
+                    }
+
+                    if (rnd(2))
+                        turn_on(*mp, ISFLEE);
+
+                    turn_on(*mp, ISINVIS);
+                    updpack();
+                }
+            }
+        }
+    }
+    else /* missed */
+    {
+        /* If the thing was trying to surprise, no good */
+
+        if (on(*mp, CANSURPRISE))
+            turn_off(*mp, CANSURPRISE);
+
+        m_bounce(weapon, mname);
+    }
+
+    count = 0;
+
+    status(FALSE);
+
+    return(did_hit);
+}
+
+
+/*
+    mon_mon_attack()
+        A monster attacks another monster
+*/
+
+int
+mon_mon_attack(struct thing *attacker, struct linked_list *mon, struct object *weapon, int thrown)
+{
+    struct thing *attackee = THINGPTR(mon);
+    int           did_hit  = FALSE;
+    int           ee_visible = cansee(attackee->t_pos.y, attackee->t_pos.x);
+    int           er_visible = cansee(attacker->t_pos.y, attacker->t_pos.x);
+    char         *mname1   = monsters[attacker->t_index].m_name;
+    char         *mname2   = monsters[attackee->t_index].m_name;
+
+    /* Similar monsters don't hit each other */
+
+    if (attacker->t_index == attackee->t_index)
+    {
+        if (attacker == THINGPTR(fam_ptr) && er_visible)
+            msg("Master, I cannot hit one of my brethren.");
+        if (!thrown && rnd(100) - attacker->t_stats.s_charisma + luck < 0) 
+		{
+            if (er_visible)
+                msg("Your %s has made a new ally.", mname1);
+				
+            turn_on(*attackee, ISCHARMED);
+		}
+
+        return(FALSE);
+    }
+
+    /* stop running and any healing */
+
+    attackee->t_rest_hpt = attackee->t_rest_pow = 0;
+    attacker->t_rest_hpt = attacker->t_rest_pow = 0;
+
+    if (roll_em(attacker, attackee, weapon, thrown,
+        wield_weap(weapon, attacker)))
+    {
+        did_hit = TRUE;
+
+        if (ee_visible && on(*attackee, CANSURPRISE))
+            turn_off(*attackee, CANSURPRISE);
+
+        if (ee_visible && er_visible && weapon != NULL)
+            msg("The %s's %s hits the %s.", mname1,
+                weaps[weapon->o_which].w_name, mname2);
+        else if (ee_visible && er_visible)
+            msg("The %s hits the %s.", mname1, mname2);
+
+        if (attackee->t_stats.s_hpt <= 0)
+        {
+            killed(attacker, mon, MESSAGE,
+                 on(*attacker, ISFAMILIAR) ? POINTS : NOPOINTS);
+            return(TRUE);
+        }
+    } 
+    else  /* missed */
+	{
+	    did_hit = FALSE;
+		
+		if (ee_visible && er_visible && weapon != NULL)
+            msg("The %s's %s misses the %s.", mname1,
+                weaps[weapon->o_which].w_name, mname2);
+        else if (ee_visible && er_visible)
+            msg("The %s misses the %s.", mname1, mname2);
+	}
+	
+	if (er_visible && !ee_visible)
+        msg("The %s struggles with something.",mname1);
+
+    if (off(*attackee, ISMEAN) && off(*attackee, ISFAMILIAR))
+        turn_on(*attackee, ISRUN);
+
+    count = 0;
+
+    status(FALSE);
+
+    return(did_hit);
+}
+
+
+/*
+    swing()
+        returns true if the swing hits
+*/
+
+int
+swing(int class, int at_lvl, int op_arm, int wplus)
+{
+    int res = rnd(20) + 1;
+    int need;
+
+    need = att_mat[class].base -
+        att_mat[class].factor *
+        ((min(at_lvl, att_mat[class].max_lvl) -
+          att_mat[class].offset) / att_mat[class].range) +
+        (10 - op_arm);
+
+    if (need > 20 && need <= 25)
+        need = 20;
+
+    return(res + wplus >= need);
+}
+
+/*
+    init_exp()
+        set up initial experience level change threshold
+*/
+
+void
+init_exp(void)
+{
+    max_stats.s_exp = e_levels[player.t_ctype];
+}
+
+/*
+    next_exp_level()
+        Do the next level arithmetic Returns number of levels to jump
+*/
+
+int
+next_exp_level(int print_message)
+{
+    int level_jump = 0;
+
+    while (pstats.s_exp >= max_stats.s_exp)
+    {
+        pstats.s_exp -= max_stats.s_exp;    /* excess experience points */
+        level_jump++;
+
+        if (max_stats.s_exp < 0x3fffffffL)  /* 2^30 - 1 */
+            max_stats.s_exp *= 2L;  /* twice as many for next */
+    }
+
+    if (print_message)
+        msg("You need %d more points to attain the %stitle of %s.",
+            max_stats.s_exp - pstats.s_exp,
+            (pstats.s_lvl > 14 ? "next " : ""),
+            cnames[player.t_ctype][min(pstats.s_lvl, 14)]);
+
+    return(level_jump);
+}
+
+/*
+    check_level()
+        Check to see if the guy has gone up a level.
+*/
+
+void
+check_level(void)
+{
+    int num_jumped, j, add;
+    int nsides;
+
+    if ((num_jumped = next_exp_level(NOMESSAGE)) <= 0)
+        return;
+
+    pstats.s_lvl += num_jumped; /* new experience level */
+
+    switch (player.t_ctype)
+    {
+        case C_MAGICIAN:
+        case C_ILLUSION: nsides = 4;
+                         break;
+        case C_THIEF:
+        case C_ASSASIN:
+        case C_NINJA:
+        case C_MONSTER:
+        default:         nsides = 6;
+                         break;
+        case C_CLERIC:
+        case C_DRUID:    nsides = 8;
+                         break;
+
+        case C_FIGHTER:
+        case C_PALADIN:
+        case C_RANGER:
+                         nsides = 12;
+                         break;
+    }
+
+    /* Take care of multi-level jumps */
+
+    for (add = 0, j = 0; j < num_jumped; j++)
+    {
+        int increase = roll(1, nsides) + const_bonus();
+
+        add += max(1, increase);
+    }
+
+    max_stats.s_hpt += add;
+    pstats.s_hpt += add;
+
+    msg("Welcome, %s, to level %d.",
+        cnames[player.t_ctype][min(pstats.s_lvl - 1, 14)], pstats.s_lvl);
+
+    next_exp_level(MESSAGE);
+
+    /* Now add new spell points and learn new spells */
+
+    nsides = 16 - nsides;
+
+    for (add = 0, j = 0; j < num_jumped; j++)
+    {
+        int increase = roll(1, nsides) + int_wis_bonus();
+
+        add += max(1, increase);
+    }
+
+    max_stats.s_power += add;
+    pstats.s_power += add;
+
+    learn_new_spells();
+
+    /* Create a more powerful familiar (if player has one) */
+
+    if (on(player, HASFAMILIAR) && on(player, CANSUMMON))
+        summon_monster((short) 0, FAMILIAR, NOMESSAGE);
+}
+
+/*
+    roll_em()
+        Roll several attacks
+*/
+
+int
+roll_em(struct thing *att_er, struct thing *def_er, struct object *weap, int thrown, struct object *my_weapon)
+{
+    struct stats *att = &att_er->t_stats;
+    struct stats *def = &def_er->t_stats;
+    int ndice, nsides, nplus, def_arm;
+    char *cp;
+    int prop_hplus = 0, prop_dplus = 0;
+    int is_player = (att_er == &player);
+    int did_hit = FALSE;
+
+    if (weap == NULL)
+        cp = att->s_dmg;
+    else if (!thrown)
+        cp = weap->o_damage;
+    else if ((weap->o_flags & ISMISL) && my_weapon != NULL &&
+         my_weapon->o_which == weap->o_launch)
+    {
+        cp = weap->o_hurldmg;
+        prop_hplus = my_weapon->o_hplus;
+        prop_dplus = my_weapon->o_dplus;
+    }
+    else
+        cp = (weap->o_flags & ISMISL ? weap->o_damage :
+            weap->o_hurldmg);
+
+    for (;;)
+    {
+        int damage;
+        int hplus = prop_hplus + (weap == NULL ? 0 : weap->o_hplus);
+        int dplus = prop_dplus + (weap == NULL ? 0 : weap->o_dplus);
+
+        /* Is attacker weak? */
+
+        if (on(*att_er, HASSTINK))
+            hplus -= 2;
+
+        if (is_player)
+        {
+            hplus += hitweight();   /* adjust for encumberence */
+            dplus += hung_dam();    /* adjust damage for hungry player */
+            dplus += ring_value(R_ADDDAM);
+        }
+
+        ndice = atoi(cp);
+
+        if (cp == NULL || (cp = strchr(cp, 'd')) == NULL)
+            break;
+
+        nsides = atoi(++cp);
+
+        if (cp != NULL && (cp = strchr(cp, '+')) != NULL)
+            nplus = atoi(++cp);
+        else
+            nplus = 0;
+
+        if (def == &pstats)
+        {
+            if (on(*att_er, NOMETAL) && cur_armor != NULL &&
+                (cur_armor->o_which == RING_MAIL ||
+                 cur_armor->o_which == SCALE_MAIL ||
+                 cur_armor->o_which == CHAIN_MAIL ||
+                 cur_armor->o_which == SPLINT_MAIL ||
+                 cur_armor->o_which == BANDED_MAIL ||
+                 cur_armor->o_which == GOOD_CHAIN ||
+                 cur_armor->o_which == PLATE_MAIL ||
+                 cur_armor->o_which == PLATE_ARMOR))
+                def_arm = def->s_arm;
+            else if (cur_armor != NULL)
+                def_arm = cur_armor->o_ac - 10 + pstats.s_arm;
+            else
+                def_arm = def->s_arm;
+            def_arm -= ring_value(R_PROTECT);
+        }
+        else
+            def_arm = def->s_arm;
+
+        if ((weap != NULL && weap->o_type == WEAPON &&
+             (weap->o_flags & ISSILVER) &&
+            !save_throw(VS_MAGIC, def_er)) ||
+            swing(att_er->t_ctype, att->s_lvl,
+            def_arm - dext_prot(def->s_dext),
+           hplus + str_plus(att->s_str) + dext_plus(att->s_dext)))
+        {
+            damage = roll(ndice, nsides) + dplus + nplus +
+                add_dam(att->s_str);
+
+            /* Rangers do +1/lvl vs. ISLARGE */
+
+            if (att_er->t_ctype == C_RANGER && on(*def_er, ISLARGE))
+                damage += pstats.s_lvl;
+
+            /* Ninja do +1 per lvl/2 */
+
+            if (att_er->t_ctype == C_NINJA)
+                damage += pstats.s_lvl / 2;
+
+            /* Check for half damage monsters */
+
+            if (on(*def_er, HALFDAMAGE) && (weap != NULL) &&
+                !((weap->o_flags & CANBURN) &&
+                on(*def_er, CANBBURN)))
+                damage /= 2;
+
+            /* undead get twice damage from silver weapons */
+
+            if (on(*def_er, ISUNDEAD) &&
+                (weap != NULL) && (weap->o_flags & ISSILVER))
+                damage *= 2;
+
+            /* Check for fireproof monsters */
+
+            if (on(*def_er, NOFIRE) && (weap != NULL) &&
+                (weap->o_flags & CANBURN))
+                damage = 0;
+
+            /* Check for metal proof monsters */
+
+            if (on(*def_er, NOMETAL) && (weap != NULL) &&
+                (weap->o_flags & ISMETAL))
+                damage = 0;
+
+            /* Check for monsters that ignore sharp weapons  */
+
+            if (on(*def_er, NOSHARP) && (weap != NULL) &&
+                (weap->o_flags & ISSHARP))
+                damage = 0;
+
+            /* Check for poisoned weapons */
+
+            if ((weap != NULL) && (weap->o_flags & ISPOISON)
+                && off(*def_er, ISUNDEAD)
+                && !save_throw(VS_POISON, def_er))
+                damage = max(damage, (def->s_hpt / 2) + 5);
+
+            /* Check for no-damage and division */
+
+            if (on(*def_er, BLOWDIVIDE) && rnd(3) == 0 &&
+                !((weap != NULL) && (weap->o_flags & CANBURN)))
+            {
+                damage = 0;
+                creat_mons(def_er, def_er->t_index, NOMESSAGE);
+            }
+
+            damage = max(0, damage);
+
+            /*
+             * sleeping monsters are backstabbed by certain
+             * player classes, but only when they can see
+             */
+
+            if (is_player && !thrown && damage > 0 &&
+                (off(*def_er, ISRUN) || def_er->t_no_move > 0) &&
+                (player.t_ctype == C_THIEF ||
+                 player.t_ctype == C_NINJA ||
+                 player.t_ctype == C_ASSASIN) &&
+				 off(player,ISBLIND)
+                && (wield_ok(&player, my_weapon, NOMESSAGE))
+                && (wear_ok(&player, cur_armor, NOMESSAGE)))
+            {
+                damage *= (pstats.s_lvl / 4 + 2);
+
+                msg("You backstabbed the %s %d times!",
+                    monsters[def_er->t_index].m_name,
+                    (pstats.s_lvl / 4) + 2);
+
+                if (player.t_ctype == C_NINJA ||
+                    player.t_ctype == C_ASSASIN)
+                    pstats.s_exp += def_er->t_stats.s_exp
+                        / 2;
+            }
+
+            def->s_hpt -= damage;   /* Do the damage */
+
+            debug("Hit %s for %d (%d) ",
+                  monsters[def_er->t_index].m_name, damage,
+                  def_er->t_stats.s_hpt);
+
+            if (is_player && is_wearing(R_VREGEN))
+            {
+                damage = (ring_value(R_VREGEN) * damage) / 3;
+                pstats.s_hpt = min(max_stats.s_hpt,
+                    pstats.s_hpt + damage);
+            }
+
+            /* stun monsters when taking more than 1/3 their max hpts */
+
+            if (is_player && !thrown && !did_hit &&
+                (player.t_ctype == C_FIGHTER) &&
+                (damage > def_er->maxstats.s_hpt / 3) )
+            {
+                if (def->s_hpt > 0)
+                {
+                    msg("The %s has been stunned!",
+                      monsters[def_er->t_index].m_name);
+                    def_er->t_no_move += rnd(4) + 1;
+                }
+                pstats.s_exp += def_er->t_stats.s_exp / 4;
+            }
+
+            did_hit = TRUE;
+        }
+
+        if (cp == NULL || (cp = strchr(cp, '/')) == NULL)
+            break;
+
+        cp++;
+    }
+
+    return(did_hit);
+}
+
+/*
+    prname()
+        Figure out the monsters name
+*/
+
+const char *
+prname(char *who)
+{
+    if (on(player, ISBLIND))
+        return(monstern);
+    else
+        return(who);
+}
+
+/*
+    hit()
+        Print a message to indicate a succesful hit
+*/
+
+void
+hit(char *ee)
+{
+    char    *s;
+
+    if (fighting)
+        return;
+
+    switch (rnd(15))
+    {
+        default:  s = "hit";                            break;
+        case 1:   s = "score an excellent hit on";      break;
+        case 2:   s = "injure";                         break;
+        case 3:   s = "swing and hit";                  break;
+        case 4:   s = "damage";                         break;
+        case 5:   s = "barely nick";                    break;
+        case 6:   s = "scratch";                        break;
+        case 7:   s = "gouge a chunk out of";           break;
+        case 8:   s = "severely wound";                 break;
+        case 9:   s = "counted coup on";                break;
+        case 10:  s = "drew blood from";                break;
+        case 11:  s = "nearly decapitate";              break;
+        case 12:  s = "deal a wacking great blow to";   break;
+    }
+
+    msg("You %s the %s.", s, prname(ee));
+}
+
+/*
+    miss()
+        Print a message to indicate a poor swing
+*/
+
+void
+miss(char *ee)
+{
+    char *s;
+
+    if (fighting)
+        return;
+
+    switch (rnd(10))
+    {
+        default:  s = "miss";                          break;
+        case 1:   s = "swing and miss";                break;
+        case 2:   s = "barely miss";                   break;
+        case 3:   s = "don't hit";                     break;
+        case 4:   s = "wildly windmill around";        break;
+        case 5:   s = "almost fumble while missing";   break;
+    }
+
+    msg("You %s the %s.", s, prname(ee));
+}
+
+/*
+    save_throw()
+        See if a creature save against something
+*/
+
+int
+save_throw(int which, struct thing *tp)
+{
+    int need;
+    int ring_bonus = 0;
+    int armor_bonus = 0;
+    int class_bonus = 0;
+
+    if (tp == &player)
+    {
+        if (player.t_ctype == C_PALADIN)
+            class_bonus = 2;
+
+        ring_bonus = ring_value(R_PROTECT);
+
+        if (cur_armor != NULL && (which == VS_WAND ||
+            which == VS_MAGIC))
+        {
+            if (cur_armor->o_which == MITHRIL)
+                armor_bonus += 5;
+            armor_bonus += (armors[cur_armor->o_which].a_class
+                    - cur_armor->o_ac);
+        }
+    }
+
+    need = 14 + which - tp->t_stats.s_lvl / 2 - ring_bonus -
+        armor_bonus - class_bonus;
+
+    /* Roll of 1 always fails; 20 always saves */
+
+    if (need < 1)
+        need = 1;
+    else if (need > 20)
+        need = 20;
+
+    return(roll(1, 20) >= need);
+}
+
+/*
+    save()
+        See if he saves against various nasty things
+*/
+
+int
+save(int which)
+{
+    return save_throw(which, &player);
+}
+
+/*
+    dext_plus()
+       compute to-hit bonus for dexterity
+*/
+
+int
+dext_plus(int dexterity)
+{
+    return ((dexterity - 10) / 3);
+}
+
+/*
+ * dext_prot: compute armor class bonus for dexterity
+ */
+
+int
+dext_prot(int dexterity)
+{
+    return ((dexterity - 9) / 2);
+}
+
+/*
+    str_plus()
+       compute bonus/penalties for strength on the "to hit" roll
+*/
+
+static const int strtohit[] =
+{
+    0, 0, 0, -3, -2, -2, -1, -1,
+    0, 0, 0, 0, 0, 0, 0, 0, 0,
+    1, 1, 3, 3, 4, 4, 5, 6, 7
+};
+
+int
+str_plus(int str)
+{
+    int ret_val = str;
+
+    if (str < 3)
+        ret_val = 3;
+    else if (str > 25)
+        ret_val = 25;
+
+    return(strtohit[ret_val]);
+}
+
+/*
+    add_dam()
+        compute additional damage done for exceptionally high or low strength
+*/
+
+static const int str_damage[] =
+{
+    0, 0, 0, -1, -1, -1, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 1,
+    1, 2, 7, 8, 9, 10, 11, 12, 14
+};
+
+int
+add_dam(int str)
+{
+    int ret_val = str;
+
+    if (str < 3)
+        ret_val = 3;
+    else if (str > 25)
+        ret_val = 25;
+
+    return(str_damage[ret_val]);
+}
+
+/*
+    hung_dam()
+        Calculate damage depending on players hungry state
+*/
+
+int
+hung_dam(void)
+{
+    int howmuch = 0;
+
+    switch (hungry_state)
+    {
+        case F_OK:
+        case F_HUNGRY: howmuch =  0; break;
+        case F_WEAK:   howmuch = -1; break;
+        case F_FAINT:  howmuch = -2; break;
+    }
+
+    return(howmuch);
+}
+
+/*
+    raise_level()
+        The guy just magically went up a level.
+*/
+
+void
+raise_level(void)
+{
+    pstats.s_exp = max_stats.s_exp;
+    check_level();
+}
+
+/*
+    thunk()
+        A missile hits a monster
+*/
+
+void
+thunk(struct object *weap, char *mname)
+{
+    if (fighting)
+        return;
+
+    if (weap->o_type == WEAPON)
+        msg("The %s hits the %s.", weaps[weap->o_which].w_name, prname(mname));
+    else
+        msg("You hit the %s.", prname(mname));
+}
+
+/*
+    m_thunk()
+        A missile from a monster hits the player
+*/
+
+void
+m_thunk(struct object *weap, char *mname)
+{
+    if (fighting)
+        return;
+
+    if (weap != NULL && weap->o_type == WEAPON)
+        msg("The %s's %s hits you.",prname(mname),weaps[weap->o_which].w_name);
+    else
+        msg("The %s hits you.", prname(mname));
+}
+
+/*
+    bounce()
+        A missile misses a monster
+*/
+
+void
+bounce(struct object *weap, char *mname)
+{
+    if (fighting)
+        return;
+
+    if (weap->o_type == WEAPON)
+        msg("The %s misses the %s.",weaps[weap->o_which].w_name,prname(mname));
+    else
+        msg("You missed the %s.", prname(mname));
+}
+
+/*
+    m_bounce()
+        A missile from a monster misses the player
+*/
+
+void
+m_bounce(struct object *weap, char *mname)
+{
+    if (fighting)
+        return;
+
+    if (weap != NULL && weap->o_type == WEAPON)
+        msg("The %s's %s misses you.", prname(mname),
+                                       weaps[weap->o_which].w_name);
+    else
+        msg("The %s misses you.", prname(mname));
+}
+
+/*
+    remove_monster()
+        remove a monster from the screen
+*/
+
+void
+remove_monster(coord *mp, struct linked_list *item)
+{
+    struct thing *tp = THINGPTR(item);
+    char          ch = tp->t_oldch;
+
+    mvwaddch(mw, mp->y, mp->x, ' ');
+
+    if (ch < 33 || ch == ' ')
+        ch = CCHAR( mvwinch(stdscr, mp->y, mp->x) );
+
+    if (cansee(mp->y, mp->x))
+        mvwaddch(cw, mp->y, mp->x, ch);
+
+    detach(mlist, item);
+    discard(item);
+}
+
+/*
+    is_magic()
+        Returns true if an object radiates magic
+*/
+
+int
+is_magic(struct object *obj)
+{
+    switch (obj->o_type)
+    {
+        case ARMOR:
+            return(obj->o_ac != armors[obj->o_which].a_class);
+
+        case WEAPON:
+            return(obj->o_hplus != 0 || obj->o_dplus != 0);
+
+        case POTION:
+        case SCROLL:
+        case STICK:
+        case RING:
+        case ARTIFACT:
+            return(TRUE);
+    }
+
+    return(FALSE);
+}
+
+/*
+    killed()
+        Called to put a monster to death
+*/
+
+void
+killed(struct thing *killer, struct linked_list *item, int print_message,
+       int give_points)
+{
+    struct linked_list *pitem, *nitem;
+    struct thing       *tp        = THINGPTR(item);
+    int                 visible   = cansee(tp->t_pos.y, tp->t_pos.x);
+    int                 is_player = (killer == (&player));
+
+    if (item == curr_mons)
+        curr_mons = NULL;
+    else if (item == next_mons)
+        next_mons = next(next_mons);
+
+    if (on(*tp, WASSUMMONED))
+    {
+        extinguish_fuse(FUSE_UNSUMMON);
+        turn_off(player, HASSUMMONED);
+    }
+
+    if (print_message && visible)
+    {
+        if (is_player)
+            addmsg("You have defeated ");
+        else
+            addmsg("The %s has defeated ",
+                monsters[killer->t_index].m_name);
+
+        if (on(player, ISBLIND))
+            msg("it.");
+        else
+            msg("the %s.", monsters[tp->t_index].m_name);
+    }
+    debug("Removing %s", monsters[tp->t_index].m_name);
+    if (killer != NULL && item == fam_ptr)  /* The player's familiar died */
+    {
+        turn_off(player, HASFAMILIAR);
+        fam_ptr = NULL;
+        msg("An incredible wave of sadness sweeps over you.");
+    }
+
+    check_residue(tp);
+
+    if (is_player)
+    {
+        fighting = FALSE;
+
+        if (on(*tp, ISFRIENDLY))
+        {
+            msg("You feel a slight chill run up and down your spine.");
+            luck++;
+        }
+    }
+
+    if (give_points)
+    {
+        if (killer != NULL)
+        {
+            killer->t_stats.s_exp += tp->t_stats.s_exp;
+
+            if (on(*killer, ISFAMILIAR))
+                pstats.s_exp += tp->t_stats.s_exp;
+        }
+
+        if (is_player)
+        {
+            switch (player.t_ctype)
+            {
+                case C_CLERIC:
+                case C_PALADIN:
+                    if (on(*tp, ISUNDEAD) || on(*tp, ISUNIQUE))
+                    {
+                        pstats.s_exp += tp->t_stats.s_exp / 2;
+                        msg("You are to be commended for smiting the ungodly.");
+                    }
+                    break;
+
+                case C_DRUID:
+                case C_RANGER:
+                    if (on(*tp, ISLARGE))
+                    {
+                        pstats.s_exp += tp->t_stats.s_exp / 2;
+                        msg("Congratulations on smiting a dangerous monster.");
+                    }
+                    break;
+
+                case C_MAGICIAN:
+                case C_ILLUSION:
+                    if (on(*tp, DRAINBRAIN))
+                    {
+                        pstats.s_exp += tp->t_stats.s_exp / 2;
+                        msg("Congratulations on smiting a dangerous monster.");
+                    }
+
+            }
+        }
+        check_level();
+    }
+
+    /* Empty the monsters pack */
+
+    for (pitem = tp->t_pack; pitem != NULL; pitem = nitem)
+    {
+        struct object *obj = OBJPTR(pitem);
+
+        nitem = next(pitem);
+
+        obj->o_pos = tp->t_pos;
+        detach(tp->t_pack, pitem);
+
+        if (killer == NULL)
+            discard(pitem);
+        else
+            fall(killer, pitem, FALSE, FALSE);
+    }
+
+    remove_monster(&tp->t_pos, item);
+}
+
+
+/*
+    wield_weap()
+        Returns a pointer to the weapon the monster is wielding corresponding           to the given thrown weapon
+*/
+
+struct object *
+wield_weap(struct object *weapon, struct thing *mp)
+{
+    int look_for;
+    struct linked_list *pitem;
+
+    if (weapon == NULL)
+        return (NULL);
+
+    switch (weapon->o_which)
+    {
+        case BOLT:
+            look_for = CROSSBOW;
+            break;
+
+        case ARROW:
+            look_for = BOW;
+            break;
+
+        case SILVERARROW:
+        case FLAMEARROW:
+            look_for = BOW;
+            break;
+
+        case ROCK:
+        case BULLET:
+            look_for = SLING;
+            break;
+
+        default:
+            return(NULL);
+    }
+
+    for (pitem = mp->t_pack; pitem; pitem = next(pitem))
+        if ((OBJPTR(pitem))->o_which == look_for)
+            return(OBJPTR(pitem));
+
+    return (NULL);
+}
+
+/*
+    summon_help()
+        Summon - see whether to summon help Returns TRUE if help comes, FALSE
+        otherwise
+*/
+
+void
+summon_help(struct thing *mons, int force)
+{
+    char *helpname;
+    int   which, i;
+    char *mname = monsters[mons->t_index].m_name;
+
+    /* Try to summon if less than 1/3 max hit points */
+
+    if (on(*mons, CANSUMMON) &&
+      (force == FORCE ||
+      (mons->t_stats.s_hpt < mons->maxstats.s_hpt / 3) &&
+      (rnd(40 * 10) < (mons->t_stats.s_lvl * mons->t_stats.s_intel))))
+    {
+        turn_off(*mons, CANSUMMON);
+        msg("The %s summons its attendants!", mname);
+        helpname = monsters[mons->t_index].m_typesum;
+
+        for (which = 1; which < nummonst; which++)
+        {
+            if (strcmp(helpname, monsters[which].m_name) == 0)
+                break;
+        }
+
+        if (which >= nummonst)
+        {
+            debug("Couldn't find summoned one.");
+            return;
+        }
+
+        /* summoned monster was genocided */
+
+        if (!monsters[which].m_normal)
+        {
+            msg("The %s becomes very annoyed at you!", mname);
+
+            if (on(*mons, ISSLOW))
+                turn_off(*mons, ISSLOW);
+            else
+                turn_on(*mons, ISHASTE);
+
+            return;
+        }
+        else
+            for (i = 0; i < monsters[mons->t_index].m_numsum; i++)
+            {
+                struct linked_list  *ip;
+                struct thing    *tp;
+
+                if ((ip = creat_mons(mons, which, NOMESSAGE)) != NULL)
+                {
+                    tp = THINGPTR(ip);
+                    turn_off(*tp, ISFRIENDLY);
+                }
+            }
+    }
+
+    return;
+}
+
+/*
+    maxdamage()
+        return the max damage a weapon can do
+*/
+
+int
+maxdamage(char *cp)
+{
+    int ndice, nsides, nplus;
+
+    ndice = atoi(cp);
+
+    if (cp == NULL || (cp = strchr(cp, 'd')) == NULL)
+        return(0);
+
+    nsides = atoi(++cp);
+
+    if (cp != NULL && (cp = strchr(cp, '+')) != NULL)
+        nplus = atoi(++cp);
+    else
+        nplus = 0;
+
+    return(ndice * nsides + nplus);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/getplay.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,350 @@
+/*
+    getplay.c - Procedures for saving and retrieving a characters starting
+                attributes, armour, and weapon.
+  
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+/* 11/08/83  ???, S.A. Hester */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "rogue.h"
+
+#define I_STR       0
+#define I_INTEL     1
+#define I_WISDOM    2
+#define I_DEXT      3
+#define I_CONST     4
+#define I_CHARISMA  5
+#define I_HPT       6
+#define I_POWER     7
+#define I_CTYPE     8
+#define MAXPATT     9   /* Total Number of above defines. */
+#define MAXPDEF     10  /* Maximum number of pre-defined chars */
+
+static int def_array[MAXPDEF][MAXPATT];    /* Pre-def'd chars */
+
+static void get_chr_filename(char *filename, int size)
+{
+    const char *home;
+ 
+    home = getenv("HOME");
+
+    if (home) {
+        if ((int)strlen(home) < (size - 12) )
+        {
+            strcpy(filename, home);
+            strcat(filename,"/urogue.chr");
+        }
+        else
+	    strncpy(filename,"urogue.chr",size);
+    }    
+    else 
+        strcpy(filename, "urogue.chr");
+}
+
+int
+geta_player(void)
+{
+    int  i;
+    FILE *fd;
+    char pbuf[2 * LINELEN];
+    char filename[200];
+
+    get_chr_filename(filename, sizeof(filename));
+
+    if ((fd = fopen(filename, "r")) == NULL)
+        return(FALSE);
+
+    fread(def_array, sizeof(def_array), 1, fd);
+    fclose(fd);
+
+    wclear(hw);
+    touchwin(hw);
+
+    print_stored();
+    mvwaddstr(hw, 0, 0, "Do you wish to select a character? ");
+    wrefresh(hw);
+
+    if (readcharw(hw) != 'y')
+        return FALSE;
+
+    do
+    {
+        wmove(hw, LINES - 1, 0);
+        wclrtoeol(hw);
+        mvwaddstr(hw, 0, 0, "Enter the number of a pre-defined character: ");
+        wclrtoeol(hw);
+        wrefresh(hw);
+        get_string(pbuf, hw);
+        i = atoi(pbuf) - 1;
+
+        if (i < 0 || i > MAXPDEF - 1)
+        {
+            wstandout(hw);
+            mvwaddstr(hw, 1, 0, "Please use the range 1 to");
+            wprintw(hw, " %d.", MAXPDEF);
+            wstandend(hw);
+            wclrtoeol(hw);
+            wrefresh(hw);
+        }
+        else if (def_array[i][I_STR] == 0)
+        {
+            wstandout(hw);
+            mvwaddstr(hw,1,0,"Please enter the number of a known character: ");
+            wstandend(hw);
+            wclrtoeol(hw);
+        }
+        else
+        {
+            mvwaddstr(hw, 1, 0, "");
+            wclrtoeol(hw);
+        }
+
+    }
+    while (i < 0 || i > MAXPDEF - 1 || (def_array[i][I_STR] == 0));
+
+    pstats.s_str      = def_array[i][I_STR];
+    pstats.s_intel    = def_array[i][I_INTEL];
+    pstats.s_wisdom   = def_array[i][I_WISDOM];
+    pstats.s_dext     = def_array[i][I_DEXT];
+    pstats.s_const    = def_array[i][I_CONST];
+    pstats.s_charisma = def_array[i][I_CHARISMA];
+    pstats.s_hpt      = def_array[i][I_HPT];
+    pstats.s_power    = def_array[i][I_POWER];
+    player.t_ctype    = char_type = def_array[i][I_CTYPE];
+    max_stats         = pstats;
+
+    return(TRUE);
+}
+
+void
+puta_player(void)
+{
+    FILE *fd;
+    char    pbuf[2 * LINELEN];
+    char filename[200];
+    int   i;
+    char    *class = which_class(player.t_ctype);
+
+    sprintf(pbuf, "You have a %s with the following attributes:", class);
+    mvwaddstr(hw, 2, 0, pbuf);
+    wclrtoeol(hw);
+
+    sprintf(pbuf,
+        "Int: %d Str: %d Wis: %d Dex: %d Con: %d Cha: %d Pow: %d Hpt: %d",
+        pstats.s_intel,
+        pstats.s_str,
+        pstats.s_wisdom,
+        pstats.s_dext,
+        pstats.s_const,
+        pstats.s_charisma,
+        pstats.s_power,
+        pstats.s_hpt );
+
+    mvwaddstr(hw, 3, 0, "");
+    wclrtoeol(hw);
+    mvwaddstr(hw, 4, 0, pbuf);
+    wclrtoeol(hw);
+    mvwaddstr(hw, 5, 0, "");
+    wclrtoeol(hw);
+    mvwaddstr(hw, 0, 0, "Would you like to save this character?");
+    wclrtoeol(hw);
+
+
+    wrefresh(hw);
+
+    if ((readcharw(hw) & 0177) != 'y')
+        return;
+
+    do
+    {
+        mvwaddstr(hw, 0, 0, "Overwrite which number? ");
+        wclrtoeol(hw);
+        wrefresh(hw);
+        get_string(pbuf, hw);
+        i = atoi(pbuf) - 1;
+
+        if (i < 0 || i > MAXPDEF - 1)
+        {
+            wstandout(hw);
+            mvwaddstr(hw, 1, 0, "Use the range 1 to");
+            wprintw(hw, " %d!", MAXPDEF);
+            wstandend(hw);
+            wclrtoeol(hw);
+            wrefresh(hw);
+        }
+    }
+    while (i < 0 || i > MAXPDEF - 1);
+
+    /* Set some global stuff */
+
+    def_array[i][I_STR]      = pstats.s_str;
+    def_array[i][I_INTEL]    = pstats.s_intel;
+    def_array[i][I_WISDOM]   = pstats.s_wisdom;
+    def_array[i][I_DEXT]     = pstats.s_dext;
+    def_array[i][I_CONST]    = pstats.s_const;
+    def_array[i][I_CHARISMA] = pstats.s_charisma;
+    def_array[i][I_HPT]      = pstats.s_hpt;
+    def_array[i][I_POWER]    = pstats.s_power;
+    def_array[i][I_CTYPE]    = player.t_ctype;
+
+    /* OK. Now let's write this stuff out! */
+
+    get_chr_filename(filename, sizeof(filename));
+
+
+    if ((fd = fopen(filename, "w")) == NULL)
+    {
+        sprintf(pbuf, "I can't seem to open/create urogue.chr.");
+        mvwaddstr(hw, 5, 5, pbuf);
+        mvwaddstr(hw, 6, 5, "However I'll let you play it anyway!");
+        mvwaddstr(hw, LINES - 1, 0, spacemsg);
+        wrefresh(hw);
+        wait_for(' ');
+
+        return;
+    }
+
+    fwrite(def_array, sizeof(def_array), 1, fd);
+    fclose(fd);
+    return;
+}
+
+void
+do_getplayer(void)
+{
+	print_stored();
+
+    if (char_type == C_NOTSET)
+        do
+        {
+            /* See what type character will be */
+
+            mvwaddstr(hw, 3, 0, "[a] Fighter\t"
+                                "[b] Paladin\t"
+                                "[c] Ranger\n"
+                                "[d] Cleric\t"
+                                "[e] Druid\t"
+                                "[f] Magician\n"
+                                "[g] Illusionist\t"
+                                "[h] Thief\t"
+                                "[i] Assasin\t"
+                                "[j] Ninja");
+
+            mvwaddstr(hw, 0, 0, "What character class do you desire? ");
+            wrefresh(hw);
+            char_type = readcharw(hw) - 'a';
+
+            if (char_type < C_FIGHTER || char_type >= C_MONSTER)
+            {
+                wstandout(hw);
+                mvwaddstr(hw, 1, 0, "Please enter a letter from a - j");
+                wstandend(hw);
+                wclrtoeol(hw);
+                wrefresh(hw);
+            }
+            else
+            {
+                mvwaddstr(hw, 1, 0, "");
+                wclrtoeol(hw);
+            }
+        }
+        while (char_type < C_FIGHTER || char_type >= C_MONSTER);
+
+   player.t_ctype = char_type;
+}
+
+void
+print_stored(void)
+{
+    int i;
+    char    *class;
+    char    pbuf[2 * LINELEN];
+
+    wstandout(hw);
+    mvwaddstr(hw, 9, 0, "YOUR CURRENT CHARACTERS:");
+    wstandend(hw);
+    wclrtoeol(hw);
+
+    for (i = 0; i < MAXPDEF; i++)
+    {
+        if (def_array[i][I_STR])
+        {
+            class = which_class(def_array[i][I_CTYPE]);
+
+            sprintf(pbuf,
+                "%2d. (%s): Int: %d Str: %d Wis: %d Dex: %d Con: %d Cha: %d"
+                " Pow: %d Hpt: %d",
+                i + 1,
+                class,
+                def_array[i][I_INTEL],
+                def_array[i][I_STR],
+                def_array[i][I_WISDOM],
+                def_array[i][I_DEXT],
+                def_array[i][I_CONST],
+                def_array[i][I_CHARISMA],
+                def_array[i][I_POWER],
+                def_array[i][I_HPT]);
+
+            mvwaddstr(hw, 11 + i, 0, pbuf);
+
+        }
+        else
+        {
+            sprintf(pbuf, "%2d.  ### NONE ###", i + 1);
+            mvwaddstr(hw, 11 + i, 0, pbuf);
+        }
+    }
+}
+
+char *
+which_class(int c_class)
+{
+    char    *class;
+
+    switch (c_class)
+    {
+        case C_FIGHTER:   
+		    class = "Fighter"; 
+			break;
+        case C_MAGICIAN:  
+		    class = "Magician"; 
+			break;
+        case C_CLERIC:    
+		    class = "Cleric"; 
+			break;
+        case C_THIEF:     
+		    class = "Thief"; 
+			break;
+        case C_PALADIN:   
+		    class = "Paladin"; 
+			break;
+        case C_RANGER:    
+		    class = "Ranger"; 
+			break;
+        case C_DRUID:     
+		    class = "Druid"; 
+			break;
+        case C_ILLUSION:  
+		    class = "Illusionist"; 
+			break;
+        case C_ASSASIN:   
+		    class = "Assasin"; 
+			break;
+        case C_NINJA:     
+		    class = "Ninja"; 
+			break;
+        default:          
+		    class = "Monster"; 
+			break;
+    }
+
+    return (class);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/history.txt	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1469 @@
+#
+#   history.txt
+#
+#   UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+#   Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+#   All rights reserved.
+#
+#   See the file LICENSE.TXT for full copyright and licensing information.
+#
+
+2.01 - Dec 17/84
+1)	MAXTRAPS set to 20, up from 15.  the dungeon gets nastier
+2)	hitpoints gained per level change/loss increased by 50%.
+	this will be essential when new monsters added and amulet
+	level is increased to 50 or so.
+
+2.01 - Dec 21/84
+1)	MAXPDEF set to 4 (maximum number of saved characters).
+
+2.01 - Dec 23/84
+1)	all load control and time code now non-optional.  controlled
+	by external variables initialized in tunable.c.  load average
+	is now read by a separate program and obtained via popen(3).
+2)	2 new armors added, mithril and crystalline.
+3)	when wearing crystalline armor, a wielded weapon can be turned 
+	into a wand of lightning by bolts of lightning from monsters
+	(75% chance)
+4)	blessed (enchanted) food lasts 3 times as long as regular food
+	up to 6000 turns (regular food is 2000 max)
+5)	tidied up messages so they all have periods on the end, etc.
+6)	not being able to play because of holiday() code is distinguished
+	by a separate message
+7)	when wearing crystalline armor, monsters that normally hug won't
+
+2.01 - Dec 24/84
+1)	fixed handling of being hit by lightning shot by yourself
+2)	fixed inventory message for sticks with one charge
+3)	a highly charged (>50) stick or weapon of lightning can do extra damage
+
+2.01 - Dec 25/84
+1)	mithril armor decreases by 25% the chance of being hit by magic
+	or wands (VS_MAGIC and VS_WAND -5) except by silver arrows
+2)	all forms of teleportation cause confusion unless you are currently
+	affected by a clear thought potion.  wizard teleportation via ^X
+	is exempt
+3)	falling through a maze or normal trapdoor can cause damage and you can
+	die from it.  also, you are confused unless currently affected by a
+	clear thought potion
+4)	when askme is set, more prompting for names is made for scrolls and
+	potions
+
+2.01 - Dec 26/84
+1)	fixed bug for when wizard or after reading scroll of creation, making
+	an object of which there is only a single type does not redisplay the
+	level
+2)	ring of teleportation can also cause confusion.  oversight in changes
+	made in other code
+3)	19 new weapons added.  list of weapons used to start with has not
+	changed
+4)	calculation of worth of multiply occuring objects changed to include
+	multiplying by the count of the number of objects
+5)	silver arrows are aimed by magic and so miss only if monster saves
+	against magic and the arrow otherwise would have missed anyway
+6)	fixed bug if entering wizard's password from the command line and is
+	typed in wrong, then a game restore is attempted
+7)	changed format of asking for object creation to allow more objects
+	to be chosen
+8)	format of name being saved in the score file is changed to indicate
+	level number and level name of the person
+
+2.01 - Dec 27/84
+1)	added 17 new monsters.  the scorefile name of the monster that killed
+	you is incompatible in indexing, but that's life.
+
+2.01 - Dec 30/84
+1)	wererats can now summon giant rats, up to 4 of them
+2)	ogres are now greedy
+
+2.01 - Jan 2/85
+1)	elves that carry bows have a 10% chance of carrying silver arrows
+2)	slightly higher probabilities of traps being successfully set
+3)	format of top ten adventurers output changed to two lines for
+	neatness since more stuff added
+
+2.01 - Jan 3/85
+1)	a cursed scroll of create monster now creates 3 to 6 monsters
+	around you.  a normal one and a blessed one create just one
+
+2.01 - Jan 6/85
+1)	amulet moved up to level 50 for safety  :-)
+2)	added new weapons, including a claymore and a footbow
+3)	some of new weapons now available during initial selection
+
+2.01 - Jan 7/84
+1)	more weapons added
+2)	code to handle creation of objects completely rewritten to no longer
+	have a limit on the number of items 
+3)	fixed bug in wizard monster creation routine to allow ESC to terminate
+	without selection
+
+2.01 - Jan 11/85
+1)	fixed code in chase.c so that a monster can actually use a footbow
+	if it's carrying one
+2)	fixed bug in chase.c that wrong pointer is used to point to a
+	monster's silver arrow.  it turns out that the code executes as
+	expected but the comments are then wrong
+
+2.01 - Jan 13/85
+1)	added fire traps as another type of trap.  needed for burning oil
+2)	changed name of molotov cocktails to burning oil.  when thrown and
+	misses monster, it makes a fire trap and also lights up the room
+3)	6 new rings added - carrying - pack loses 1/3 of its weight
+			  - adornment - worth 1000 gp, but nothing else
+			  - levitation - avoids traps and things like that
+			  - fire resistance, lightning resistance, and
+			    cold resistance - obvious
+4)	certain monsters will die instantly when hit by burning oil
+
+2.01 - Jan 14/85
+1)	full damage is always done with burning oils except on fireproof
+	monsters
+2)	monsters that divide will not do so when hit by burning oil
+3)	fixed bugs in messages for firetraps
+
+0.00 Alpha - Jan 15/85
+1)	flameproof monsters aren't burnt by burning oil
+2)	version and name of game changed to UltraRogue.  hopefully,
+	it will live up to it's name
+3)	format of scoring output changed to remove redundant information
+4)	crysknife can poison now.  if the monster doesn't save against
+	poison, it loses half its hit points
+5)	flameproof monsters ignore firetraps and can run through them
+6)	many special properties of weapons changed from hardcoded names
+	to flags
+7)	boomerangs and other weapons that return do so now
+8)	maximum attempts to set traps per level changed from 8 to 16
+9)	maximum transactions at a trading post changed from 4 to 8
+
+0.00 Alpha - Jan 16/85
+1)	corrected code for handling of silver and poisoned weapons
+
+1.00 Alpha - Feb 1/85
+1)	it's now possible to roll crystalline armor at start
+2)	enchanting armor causes it to weigh 20% less for each + and 20% more
+	for each -
+
+1.00 Alpha - Feb 4/85
+1)	quitting uses experience point score instead of gold
+2)	corrected handling of weight of enchanted armor
+3)	discovering a firetrap lights the room
+4)	it's now possible to die from fire traps
+
+1.00 Alpha - Feb 5/85
+1)	changed weight of enchanted objects in wrong place.  now fixed
+2)	minor fix to messages in trader.c
+3)	changed the effect of a scroll of acquirement.  a blessed scroll
+	now works as in old version, a normal or cursed scroll will
+	allow acquirement of an object of random type.
+4)	split rogue.c into rogue.c and monsdata.c
+
+1.00 Alpha - Feb 10/85
+1)	armor doesn't rust if you're not wearing any
+2)	added 8 artifacts, now trying to make rogue compile again
+3)	time window for restored games changed to 60s instead of 25s.
+
+1.00 Alpha - Feb 13/85
+1)	misc. tidying up of messages.  some changed to be wizard only
+	messages
+2)	one unique monster added, have not yet tested nastiness of beast
+3)	changed chasing code to hopefully remove bug that stops running
+	in a room even though monster is invisible or can surprise
+4)	seeing distance is now a variable so that later enhancements can
+	be made
+5)	added apply command ('A') to make an artifact work (does nothing 
+	right now)
+6)	it is now possible to trip and fall down the stairs, and die
+	in the process
+7)	blessed objects weigh 20% less and cursed weigh 20% more
+8)	fighting (but not to death) allowed until 1/3 of max hit points
+9)	time of stiffening by basilisks, etc., is now randomized
+10)	tidied up code to handle signals and autosaving
+11)	poison pool traps implemented
+12)	quaffing a potion of haste self when already hasted lasts a
+	longer time than before
+13)	if strength is high enough, the hero can break free of 
+	a hold
+14)	creation of artifacts now supported (sort of)
+15)	scoring routines changed to track gold and experience separately.
+	now i have to figure out how to set the gold to zero without
+	resetting the score file
+16)	gold is counted (including worth of objects) even for quitting and
+	dying.  however, position in scorefile is determined by experience 
+	points only
+17)	three new scrolls 1) nothing - does nothing
+			  2) silver plating - magic aimed weapons seldom miss
+			  3) ownership - make weapons return
+18)	6 types of food now - details still to be fixed up
+19)	corrected handling of normal and cursed scrolls of acquirement
+
+1.00 Alpha Feb 14/85
+1)	creation of artifacts mostly working now.  no code to support
+	their special functions yet
+2)	corrected names of artifacts and food so the inventory routine
+	gives correct case and plural forms of names
+3)	handling of duration of enchanted food fixed
+
+1.00 Alpha Feb 15/85
+1)	creation, picking up, dropping, and throwing artifacts now apparently
+	correct.  no functions yet implemented yet
+2)	mad wizard changed to mad sorceress and is no longer confused.
+	level, intelligence, experience points and damage increased
+3)	nymphs try to steal the most valuable magic item carried now
+4)	picking up an artifact gives experience equal to 0.1 of it's
+	worth in gold
+5)	new wizard command 'V' added to find the worth of an object
+
+1.00 Alpha Feb 16/85
+1)	monsters that steal magic and gold no longer vanish when they've 
+	stolen an item.  instead, it turns invisible and tries to run away.
+	a nymph isn't so bad, but watch out for the mad sorceress.
+	the monster will carry around the item until killed
+2)	picking up things with a full pack in a trading post no longer
+	identifies it
+3)	falling into a poison trap does not automatically poison current 
+	weapon and there is a 75% probability of losing 1/3 hit points 
+	and 2 strength
+4)	buying anything in a trading post tells you what it is and all others
+	of the same type
+5)	quaffing a potion of healing at or near max hit points increases
+	maximum by more
+6)	a wand of nothing does nothing
+7)	cursed scroll of ownership causes thrown weapon to always disappear
+
+1.00 Alpha Feb 17/85
+1)	corrected handling of wizard scorefile manipulation commands
+2)	corrected code to create objects via the scroll of acquirement
+3)	a cursed scroll of acquirement creates a cursed object
+4)	wearing a ring of levitation allows you to move over any kind of
+	trap without being harmed
+5)	poisoned weapons now identified as such in inventory name
+
+1.00 Alpha Feb 25/85
+1)	corrected handling of scoring of gold for total winners
+2)	changed mad sorceress to be non-unique to make dungeon really nasty
+3)	added code to calculate cost of silver, poisoned, and owned weapons
+4)	code to stop running when a monster appears corrected for when
+	monster can surprise or is invisible
+
+1.00 Alpha Mar 1/85
+1)	cursed potion of see invisible does nothing when wearing ring
+	of see invisible.
+2)	putting on a ring of see invisible while blind cures blindness
+
+1.01 Alpha Mar 4/85
+1)	changed encryption scheme used by read/write routines to code
+	supplied by Michael Mauldin (mlm@cmu-cs-cad.arpa)
+2)	eating too much causes paralysis for a short time
+3)	changed rnd (random integer in a certain range) routine to use
+	a better algorithm
+4)	changed version string for internal checking to something more
+	useful
+
+1.01 Alpha Mar 8/85
+1)	changed inv_name to show silver weapons properly
+2)	changed name of "silver weapon" scroll to "magic hitting"
+3)	scrolls of ownership and magic hitting now prompt for weapon to
+	apply scroll to
+4)	rnd changed back to old algorithm because new one is SLOW
+
+1.01 Alpha Mar 20/85
+1)	picking up an artifact more than once does not add more experience
+	points
+2)      new unique and VERY NASTY monster added, Lucifer.  only appears
+	on level one when you have an artifact on you.  he is NOT
+	pleasant.  i am certain that he will prevent total winners until
+	i can tune his parameters.
+
+1.01 Alpha Mar 22/85
+1)	changed maximum objects per normal level from 9 to 5
+2)	changed monster window to half it's current value to stretch
+	out the levels new monsters can appear over
+3)	increased traps per level again from 20 to 25
+
+1.01 Alpha Mar 28/85
+1)	decreased abilities of Lucifer to try things out
+2)	changed probability of food up and other stuff down
+3)	changed probability of potion of gain level down
+
+1.01 Alpha Apr 1/85
+1)	changed traps per level up to 30
+2)	fixed bug in wearing ring of cold resistance
+3)	changed window for saving to 180s because save/restore with
+	new algorithm is much slower
+4)	added support for lairs of unique monsters, 1 in 15 chance of
+	being summoned while going up the stairs
+5)	trading posts can't appear until level 15, up from level 5
+6)	you can't be blinded when wearing a ring of extra sight
+7)	hit points per level gained/lost reduced to original values
+8)	deleted some wizard commands and re-arranged some of the rest
+9)	changed how wizard teleportation specifies type of level
+10)	modified parameters of sucessfully striking a monster
+11)	Lucifer devalued again
+
+1.02 Alpha Apr 2/85
+1)	reduced probability of being summoned at random while running around
+2)	restored probability of hitting parameter
+3)	doubled requirements for experience level changes
+
+1.02 Alpha Apr 4/85
+1)	restored requirements for experience level changes
+2)	increased probability that a monster hits on an attack
+3)	changed probability of food downwards and other stuff upwards
+4)	changed probability of some scroll's cursed and blessed probabilities
+
+1.02 Alpha Apr 5/85
+1)	throne room monsters no longer hasted
+2)	fixed messages for scrolls of magic hitting and ownership
+3)	infinite loops in wanderer() due to trying to place a monster
+	in a different room than the hero on a THRONE level
+4)	changed format of scorefile to include what artifacts were
+	retrieved
+5)	initial attributes of a fighter increased
+6)	Lucifer downgraded again (sigh)
+
+1.02 Alpha Apr 12/85
+1)	food probability adjusted upwards
+2)	size of string to hold fruit food name increased
+3)	monsters per treasure room increased to 20 from 15
+4)	maximum number of magic objects per level increased from 5 to 7
+5)	added code to differentiate a winner carrying all artifacts
+	and some
+6)	reduced probability of summoning
+
+1.02 Alpha Apr 16/85
+1)	monsters that can walk through stone are not affected by wand of
+	antimatter.  so much for an easy kill of Lucifer
+2)	throne rooms always contain treasure, up to 3 times as much as normal
+
+1.02 Alpha Apr 23/85
+1)	max monsters/treasures in a party room upped again from 20 to 30
+
+1.02 Alpha Apr 26/85
+1)	improved wizard outfitting command to start with more and better stuff
+2)	fighters gain and lose 12 instead of 10 hit points max per level
+3)	throne rooms always contain lots of treasure
+4)	fixed message in experience level changes to include period
+
+1.02 Alpha Apr 28/85
+1)	monsters that can breathe can do so more than once with 50% chance
+	after each use of losing (or retaining) ability
+2)	catch zapping and bolts into darkened rooms, passages, and phased
+	players in walls and flag as error for wizard
+3)	mad sorceress improved in ability
+4)	changing name of fruit in options now also changes name in rest of game
+5)	handling of SIGINT and SIGQUIT corrected for when escaping to shell
+	and returning.  used to exit with endit().  now does quit() to
+	prompt before exiting
+6)	options listing now includes name of option for the environment
+	variable
+7)	throne rooms made nastier by increasing hit points further and also
+	decreasing AC of monster even more
+8)	monsters below level 80 start getting nastier in a lot of ways
+	and is level dependent (deeper == nastier)
+
+1.02 Alpha Apr 29/85
+1)	all monsters in throne rooms can now walk through walls
+2)	past level 80, all monsters that can use breath weapons will never
+	lose that ability
+3)	Lucifer upgraded
+
+1.02 Alpha Apr 30/85
+1)	algorithm for nastier monsters below level 80 changed (nastier)
+2)	potion of raise level made much rarer
+3)	being drained a level is restored only half the time
+4)	monsters in thone rooms can see invisible heros
+5)	scrolls of acquirement are rarer and are more likely to be cursed
+
+1.02 Alpha May 1/85
+1)	Lucifer hit points upgraded
+2)	Lucifer never loses ability to zap with breath weapon
+3)	fixed bug in returning of weapons with blessed scroll of
+	ownership read on them
+4)	circular buffer implemented for messages and each line of buffer
+	increased in size
+5)	rings, weapons, sticks, and armor can explode if enchanted too much
+6)	owned things show up that way in inventory
+
+1.02 Alpha May 2/85
+1)	length of time that all food lasts increased
+2)	throwing a scare monster scroll curses it
+
+1.02 Alpha May 3/85
+1)	attacking rust monsters with bare hands causes segmentation faults
+	fixed by checking for whether hero wields a weapon or not
+2)	evil sorceresses (and nymphs) will steal anything, including
+	what you're wearing, below level 95
+3)	it's now imposssible to enchant a ring of slow digestion beyond 3
+	since food consumption code is not designed to handle it
+
+1.02 Alpha May 6/85
+1)	adjusted probability of things exploding when enchanted too much from
+	1 in 8 to 1 in 5
+2)	being summoned while just wandering in the dungeon is changed
+	to 1 in 99999 to make life interesting
+3)	stick of fire now kills monsters that are flammable
+4)	fixed bug in handling firetraps for monsters
+5)	corrected new code to handle monsters running through fire traps
+
+1.02 Alpha May 8/85
+1)	fixed bug in wizard dungeon level change command
+2)	total daemons changed from 30 to 60 to allow for new things
+3)	fighting while blinded changed from "it" to "the monster"
+4)	algorithm for making monsters nastier below level 80 made
+	even nastier
+5)	fire traps always burn even when levitated
+6)	fixed monster name lookup in shoot_bolt when bolt misses
+7)	monster lair traps implemented for levels below 50
+8)	rust traps implemented to rust armor
+9)	messages for CANRUST monsters hitting you after armor is
+	destroyed is changed
+10)	placement of player in a throne room corrected
+11)	unique monsters are always awakened by the hero entering the room
+12)	a monster with enough strength can shatter crystalline armor with
+	a single blow
+13)	a monster with enough strength can make the armor ring when hit,
+	aggravating all monsters on the level
+14)	monsters that can shriek can shatter crystalline armor
+15)	strength of monsters below level 80 also increases with level
+16)	check more often for null pointers when refering to current armor
+	in fight.c and monster.c
+17)	selling or dropping an artifact in a post loses it forever, but
+	you can still go up the stairs as if you did have it.  same with
+	it being stolen by a monster
+
+1.02 Alpha May 10/85
+1)	creation of firetraps done only when there is room in the traps array
+2)	potion of extra hearing - cursed, normal and blessed
+3)	potion of extra scent - cursed, normal, and blessed
+4)	hero can smell or hear monsters whenever they appear in dungeon
+	or possibly when he enters a room, always when potions have been
+	quaffed
+
+1.02 Alpha May 11/85
+1)	scroll of food detection implemented
+2)	corrected algorithm for blessed food and added message when
+	eating it so people trying will know to try it again
+3)	code to handle super food consumption added
+4)	changed algorithm for ring of slow digestion food consumption
+	to not use hardwired enchantment levels
+5)	hearing and smelling new monster messages changed to reflect
+	distance and rooms somewhat
+6)	partial implementation of artifact powers completed
+7)	many of minor malevolent and side effects implemented
+8)	some major malevolent effects implemented
+9)	Phial of Galadriel implemented
+10)	Palantir of Might implemented
+
+1.02 Alpha May 12/85
+1)	fixed dying by fire traps to remove seg fault while trying to
+	print reason for dying
+2)	selling an artifact or having it stolen and vanishing when
+	monster that stole it is killed loses the artifact permanently 
+	and the ability to go upwards is lost if it's the only artifact 
+	in the hero's possesion
+3)	login name included in scorefile
+4)	stick of invisibility - makes monsters appear or disappear
+	cursed (all in room), normal(one in direction), blessed(one
+	appears in direction)
+5)	implemented Amulet of Yendor, Silmaril of Ea, Sceptre of Might,
+	Wand of Orcus
+6)	partial implementation of Magic Purse of Yendor
+7)	20 units of food are consumed every time a artifact power is attempted
+8)	code for blessed scrolls of magic mapping, gold detection,
+	food detection, potions of magic detection and monster detection
+	in place
+9)	minimal code for wand of invisibility implemented
+
+1.02 Alpha May 13/85
+1)	minimal code for potions of super heroism and disguise added
+2)	no healing when phased and in rock
+3)	changed "owned" to "claimed" in inv_name() for weapons
+4)	wand of invisibility implemented
+5)	bug in removing rings of add ability fixed when unwearing one
+6)	leaving rooms when wearing ring of illumination darkens it
+
+1.02 Alpha May 14/85
+1)	rewrote all code to handle changes in the five major player
+	abilities
+2)	completed implementation of the Crown of Might
+3)	implemented blessed mapping and detection abilities
+4)	more minor effects
+5)	more major effects
+6)	copy over login name to scorefile name entry only if it's
+	not the same as the name entry started with
+7)	falling down stairs probability shifted according to encumberance
+8)	undead monsters are not affected by poison
+9)	ring of regeneration restores hit points faster
+10)	ring of sustain health stops disease and parasitic infections, but
+	doesn't cure them
+
+1.02 Alpha May 15/85
+1)	fixed bugs in handling power boosted strength and dexterity
+2)	implemented potions of disguise and superheroism
+
+1.02 Alpha May 16/85
+1)	changed potion of disguise to be like a scare monster scroll and
+	shortened length of time it lasts
+2)	implemented more minor effects
+3)	cursed scroll of magic mapping done - forgets map
+4)	fighting stops "hits" and "misses" messages to stop having to
+	hit the spacebar all the time
+5)	1 in 50 chance when fighting to stop fighting completely at random.
+	a neater way of stopping fighting when neither side is hitting the
+	other
+6)	moving over some traps using the 'm' command can result in no
+	trapping, especially if player is thief
+7)	asleep on top of a sleep trap doesn't print many messages
+	about what the trap is
+8)	reduced nastiness of level-dependent monster characteristics
+9)	make probability of losing breath weapon dungeon level dependent
+10)	fixed bug in stopping running when a monster enters room
+11)	Magic Purse of Yendor code in place but not tested
+
+1.02 Beta May 17/85
+1)	fixed bag of holding code for Magic Purse of Yendor
+2)	can't put Magic Purse inside itself
+3)	lowered probability of a nonthief moving over a trap successfully
+4)	add contents of Purse to score
+5)	added more major and minor effects
+6)	lowered probability of an artifact being deactivated by a minor
+	effect
+
+1.02 Beta May 18/85
+1)	check for no wielded weapon or no armor worn when being hit
+	by breath weapon
+2)	check for no wielded weapon when blasting it in default major
+	effect of artifact activation
+3)	changed many messages in minor effects to check for blindness
+4)	it is possible to trip and stumble over your weapon, and die in
+	the process.  poisoned weapons do a lot of damage to the hero
+5)	fighting or shooting some wands at the quartermaster increases
+	the cost of things and probability of things being cursed
+	by other quartermasters and in trading posts.  monsters on level
+	are aggravated
+6)	fighters using the 'f' or 'F' commands are get bonus number
+	of attacks dependent upon level per turn
+7)	when not under influence of potions of extra scent or extra hearing,
+	thieves have higher probability of hearing or smelling a monster
+8)	cursed detection scrolls and potions implemented
+9)	scroll of electrification implemented
+
+1.02 Beta May 19/85
+1)	five new rings added
+2)	worth of artifacts increased by a factor of 10
+3)	when msgline is blank and last message is requested via ^P,
+	don't decrement message buffer index the same way since it was 
+	not incremented to clear the line
+4)	initial hit point bonus for constitutions above 15
+5)	new command listen ('=') to listen for nearby monsters
+6)	ring of breathing - player is unaffected by gases
+7)	ring of free action - player can't be held or slowed except by an
+	artifact side effect
+8)	reduced duration of confusion after teleportation
+9)	ring of wizardry - doubles spell and prayer ability for players
+	who are not clerics nor magicians
+10)	listen for monsters nearby with higher probability for thief
+11)	ring of resurrection - you might come back from the grave: cursed,
+	normal, and blessed versions
+12)	ring of teleport control - get to choose position and might actually
+	end up there: cursed, normal, and blessed versions
+13)	corrected multi-attack code to allow only fighters
+14)	cursed detection magic identifies itself for later in the dungeon
+15)	silver weapons do twice damage to undead monsters
+16)	source frozen for version as reference.  further updates sent
+	out will be via context diffs
+
+1.02 Beta May 20/85
+1)	modified saving throw for resurrection to take into account current
+	constitution adjusted for luck and ring values
+2)	rings of resurrection and teleport control now has enchantment 
+	amount printed
+3)	a failed resurrection now waits for the user to read the message
+	before continuing with termination
+4)	off-by-one error in counting resurrection attempts
+5)	added diagonal moves to teleport control (sort of)
+6)	successful control of teleport modified by luck and ring values
+7)	corrected initialization of resurrection count
+8)	moved tripping, summoning, and other things inside the test for
+	valid commands
+9)	changed algorithm for determining successful resurection with
+	everything
+10)	bug in listen command changed you to a thief when using it
+
+1.02 Beta May 21/85
+
+1)	a blessed scroll acquirement allows creation of an artifact or
+	monster even if not wizard
+2)	infestation is not supposed to be immediately fatal
+
+1.02 Beta May 22/85
+1)	moved new.things (this file) into directory rogue to make updates
+	via context diffs more easy to apply
+2)	corrected message of deactivation of artifacts
+3)	changed definition of .rog_defs to an external variable in
+	tunable.c for customization purposes
+
+1.02 Beta May 23/85
+1)	termination after load average is too high does a save instead
+	of just quitting
+
+1.02 Beta May 25/85
+1)	corrected code for adding userid after name in scorefile
+2)	redisplaying of messages after being cleared by msg("") fixed
+
+1.02 Beta May 27/85
+1)	dungeon level dependent monster ability algorithm made less
+	nasty
+2)	throne room monster ability modification algorithm made less
+	nasty
+3)	some of Lucifer's abilities made less nasty
+4)	levitated and phased allows upward movement through rock
+5)	discovered trading post stays lit when exiting room
+
+1.02 Beta May 28/85
+1)	fixed firetraps combined with rings of levitation
+2)	fixed messages for major effects blasting of weapon
+3)	disguise can be seen through by monsters with high experience
+	for hitting, zapping, and throwing things at the hero
+4)	increased safe amount to enchant ring from 4 to 5
+
+1.02 Beta May 29/85
+1)	documented 'f' and 'F' commands under help command
+
+1.02 Beta June 1/85
+1)	increased the value of some items
+
+1.02 Beta June 3/85
+1)	made leprechauns and nymphs harder to kill and more likely
+	to stay around
+2)	nymphs now attack whenever possible
+3)	monsters ignore rust traps now
+4)	changed help for 'f' and 'F' commands slightly
+
+1.02 Beta June 3/85
+1)	missed change of ".rog_defs" to ROGDEFS 
+	(thanx jason%ucblilac.CC@berkeley.arpa)
+2)	anything can be claimed now.  inventory names and worth of objects
+	changed to reflect this
+
+1.02 Beta June 4/85
+1)	check for monster wielding a weapon didn't check for null pointer
+2)	changed #include "stdio.h" to <stdio.h> in save.c
+3)	include mach_dep.h in io.c, save.c, and wizard.c
+
+1.02 Beta June 6/85
+1)	shattering of crystalline armor when hit hard is less likely
+	when armor is well enchanted
+
+1.02 Beta June 7/85
+1)	check for null pointer to damage string in determining how much
+	damage a blow or weapon striking does
+2)	added code from jason@ucblilac.CC@berkeley.arpa for support
+	of job control and tty interfacing for 4.x bsd systems
+3)	quaffing non-cursed potion of super heroism removes fear and
+	also prevents it until super heroism wears off
+4)	corrected oversights in jason's code for when terminating
+	by various legal means
+5)	generalized message for selling/dropping artifact in trading post
+6)	prices of objects in trading posts are now fixed at object creation
+	time
+7)	algorithm for randomizing prices by quartermasters and in trading 
+	posts changed
+8)	prices as determined by bad luck made worse
+
+1.02 Beta June 8, 85
+1)	corrected tty and job control handling for urogue -s and
+	urogue restore of saved games option
+
+1.02 Beta June 9, 85
+1)	too much movement when disguised turns it off
+2)	reduced gain in monster strength below level 80
+3)	improved resistance of crystalline armor to shattering when hit
+4)	confused monsters can lose their confusion
+5)	food detection also looks in monster's packs too
+6)	evil sorceresses and nymphs can curse something in your pack
+	while they are looking through it
+7)	fix tty characteristics when restoring a game
+8)	improved chances of taking it with you when you are resurrected
+9)	corrected author and SIGQUIT handling
+
+1.02 Beta June 10, 85
+1)	selling an object in a trading post marks the value in a private
+	location in case hero wants to buy it back
+2)	reduced slightly the chance of nasty side effects when using
+	artifacts
+3)	shattering armor removal algorithm fixed
+4)	lightning proof and being zapped by lightning checks for no armor
+	and/or no wielded weapons
+5)	change Makefile to be more efficient when maintaining distribution
+	and private copies by linking only once instead of twice
+6)	going to a new level and not wearing any armor causes seg faults
+	when testing for greedy monsters
+7)	null pointers when calculating damage caused by weapons handled
+	incorrectly
+8)	setting traps, traps due to falling objects that create traps,
+	and artifact side effects have more room by making trap array 
+	bigger
+
+1.02 Gamma June 19, 85
+1)      put in changes and moved things around in preparation for
+	changes to be received from dan@ciprico for sys3 (aka USGV3)
+	unix.  generalized conditional compilation code to allow
+	further extension to multiple system source code versions.  no
+	recompilation is neccesary with these changes.
+
+1.02 Gamma June 21, 85
+1)	fixed bug in quaffing gain ability when dexterity or strength
+	has been lost
+2)	wearing a ring of wizardry doubles spell points for casting and
+	praying for all player classes provided that they have enough
+	ability to cast or pray
+
+1.02 Gamma June 24, 85
+1)	gazing monsters have no effect when hero is invisible
+2)	reduced probability of losing disguise when moving about
+3)	leprechauns now attack
+
+1.02 Gamma July 7, 85
+1)	can't read scrolls when blind
+2)	test for null pointers when refering to weapons and armor
+	in do_minor() in artifact.c
+3)	taking off armor removes stone from shoe
+
+1.02 Gamma July 8, 85
+1)	corrected flag handling for nymphs and evil sorceresses
+	cursing an object that hero is carrying
+
+1.02 Gamma July 10, 85
+1)	handling of ring of wizardry and spell points for clerics and
+	magicians fixed
+
+1.02 Gamma July 12, 85
+1)	fixed handling of wizard spell points because of limitations in
+	certain C compilers.  thanx to dan@ciprico
+2)	reset CBREAK mode in rip.c routine score() so that showpack() can 
+	prompt and wait for a blank to continue displaying items
+3)	reduced slightly the probability of a monster hitting back to
+	original values as received from edjames@ucbshadow
+4)	incomplete changes to handle the ring of wizardry in casting
+	and praying
+
+1.02 Gamma July 18, 85
+1)	make dexterity of a monster level dependent past level 60 of
+	dungeon
+
+1.02 Gamma July 21, 85
+1)	silver weapons can't rust no matter what
+2)	hitting a rusting monster with a non-metallic weapon no longer
+	tells you the rust vanishes
+3)	no message of rust vanishing from your armor if it is
+	inherently rustproof
+4)	fixed grammar on messages about falling through various traps
+
+1.02 Gamma July 23, 85
+1)	changed code to ensure quartermasters sell things at positive
+	cost only
+2)	quaffing a blessed potion of gain ability sometimes increases
+	the player's body AC as well
+3)	fixed initialization code for fighters to give them extra
+	body AC and also more damage from bare handed attack
+
+1.02 Gamma July 26, 85
+1)	wearing a ring of adornment also causes greedy monsters to run
+	after you
+2)	monster's level dependent attributes are dependent upon the maximum
+	level you have been
+3)	a blessed scroll of magic mapping show traps and such too
+4)	monsters stepping into firetraps while hero isn't in room
+	also marks the room as lit
+
+1.02 Delta July 28, 85
+1)	sys3 support added, courtesy dan@ciprico
+2)	new random number routines added to the optional files
+	for people without srandom and random
+
+1.02 Delta, July 29, 85
+1)	teleporting turns off being held by a bear trap
+2)	being hit by a breath weapon while running stops you running
+3)	replaced Makefile.install with one supplied by jason@ucblilac
+4)	fighting mummies with no weapon usually causes seg faults so
+	pointer must be checked  (dan@ciprico)
+5)	entering a room through a secret door while phased is supposed to
+	light the room (dan@ciprico)
+6)	trying to dip where there's no pool gives wrong message
+
+1.02 Delta, July 30, 85
+1)	added support for news option in command line
+2)	quit signals produce core files only in wizard mode
+3)	wearing a ring of adornment adds 4 to number of transactions
+	allowed in trading posts
+4)	ring of burden deleted and replaced by ring of vampiric regeneration
+5)	ring of carrying comes in various degrees now and cursed is like
+	the ring of burden used to be
+6)	ring of vampiric regeneration restores amount of damage done to
+	monster to player, sort of like a vampire does
+7)	ring of regeneration hit points now made somewhat experience
+	level dependent
+8)	food consumption of the regeneration rings make experience
+	level dependent
+9)	wand of blasting and grenades implemented
+
+1.02	August 9, 85
+1)	baseline release for urogue
+2)	friendly fiend wants a ring of adornment
+3)	player startup body AC initialized wrong
+4)	negative transaction count after selling ring of adornment fixed
+5)	fixed opening of authors file
+
+1.02	August 11, 85
+1)	inventory name of a claimed ring had blanks in wrong place
+2)	fixed printing of inventory and counting of things inside
+	the Magic Purse of Yendor
+
+1.02	August 12, 85
+1)	Closes PERMOK and PASSCTL after they are no longer needed.  This is
+	a good practice, and was part of the reason for screwing up our server.
+2)	Quaffing a restoration after superheroism had nasty effects.
+3)	Screen no longer clears right after score file is displayed on death.
+4)	Changing your Ac from 10 would not affect status line.
+5)	Expression tree overflowed on trader.c using the 4.1 compiler.
+
+	above changes by tecot@cmu-cs-k.arpa.  the system they run has
+	a "networked" filesystem under 4.1 bsd.
+
+6)	a thrown grenade hitting a monster also explodes and makes a lot
+	of noise
+7)	probabilities of magic items of various kinds changed to make
+	things harder
+8)	costs of things re-arranged to reflect value to player more
+	accurately
+
+1.02	August 13, 85
+1)	being zapped by a breath weapon while not wearing armor causes
+	core dumps
+
+1.03 Alpha, February 16, 86
+1)	added 100+ monsters to the monster table with new attributes
+	supported
+2)	added mike cooper's new character classes
+3)	added mike cooper's changes to inventory display management to
+	be more like Berkeley rogue 5.x
+4)	changed experience level management to allow effectively no
+	limit on experience level
+5)	spell and prayer points are now taken from the same pool
+6)	healing rate reduced to make life harder
+7)	code to correct sun compiler laziness that is handled by
+	other compilers
+8)	redo flag structure to extend to 400+ monster flags
+9)	display remaining spell points in menu of spells to cast/pray
+10)	healing rates reduced
+11)	control rewritten to do what it says in README
+12)	README updated to tell about the environment variable
+13)	MOTD, PAGER, NOPLAY, and NEWS files supported for various
+	messages and display of same
+14)	uptime output is used for load control
+15)	control uses the login name rather than uid for authorization
+16)	code for RTU2 and 4.2 RT PC versions added
+17)	fixed up some sun problems
+18)	FLYing and FAST monsters move twice as quickly when not next
+	to hero
+19)	melee attack bonus for various character classes computed
+	by a function instead of code in the if statement
+20)	CTRL-<dir> keys deleted and option used for determining
+	type of running
+21)	fixed saving throw modification for mithril armor
+22)	changed message for monsters stealing magic
+23)	changed environment variable to UROGUE
+24)	dungeon-level-dependent attributes start sooner now
+25)	more weapon flags
+26)	silver weapons become metal ones too
+27)	monsters appear more often
+
+1.03 Alpha, February 21, 86
+1)	added changes to circumvent compiler bug in 4.2BSD on the RT PC
+2)	corrected maximum number of levels displayed in player level
+	calculation
+3)	corrected calculation of needed experience points to gain a
+	new level after losing a level
+4)	thrown weapons at gas spores kill them
+5)	synchronized messages and experience level numbers when 
+	gaining levels
+
+1.03 Alpha, February 22, 86
+1)	Friendly Fiend appears in a trading post and follows you around
+2)	minimal code for support of CHARMED and FRIENDLY monsters
+3)	Friendly Fiend gets upset if you cast spells in his place
+
+1.03 Alpha, February 22, 86
+1)	fixed up Friendly Fiend handling when he has been hit or
+	"killed"
+2)	changed ninja experience level names
+3)	added paladin praying abilities at level 9 no matter what wisdom
+4)	reduced Friendly Fiends abilities
+5)	shops become normal levels for picking up objects when Friendly Fiend
+	is "killed"
+6)	handle a one room ordinary level properly
+7)	once Friendly is "dead", shop items are identified when picked up
+
+1.03 Alpha, February 28, 86
+1)	applied bug fix in inventory code sent by Mike Cooper
+2)	added AT&T 7300 sys5r2 support
+3)	implemented Jason Venner's improvements to handling getting the
+	load average
+
+1.03 Alpha, March 9, 86
+1)	applied fix to too many saves running out of file descriptors
+	submitted by Web Dove
+2)	applied fixes to messages and stuff for the quartermaster from
+	Mike Cooper
+
+1.03 Alpha, March 14, 86
+1)	applied bug fix by mike cooper in display of quartermaster's 
+	wares to sell
+2)	applied mike cooper's patches for sys5 curses support
+
+1.03 Alpha, March 15, 86
+1)	added flags for size of monster and size of weapon and initialization
+2)	changed whatis command to display all possible monsters that match
+	the characters
+
+1.03 Alpha, April 14, 86
+1)	incorporated random() and srandom() from 4.2BSD
+
+1.03 Alpha, April 18, 86
+1)	fixed segv in control.c using patch from mike cooper
+
+1.03 Alpha, April 19, 86
+1)	fixed screen clearing in initialization and termination for sys5
+2)	added option to print version number
+3)	doubled healing rate
+4)	potion of gain ability is much rarer now
+5)	Tiamat and Bahamut can now summon dragons (suggested by carl hommel)
+
+1.03 Alpha, April 20, 86
+1)	fixed up terminal state when exiting
+2)	removed wizard scorefile commands from rip.c
+3)	fixed testing for valid initialization of player class
+
+1.03 Alpha, April 28, 86
+1)	added SAVETIME and WARNTIME to allow installations to tune
+	how strict they are on load checking
+2)	changed treasure room generation and room darkness constants
+	to create them less often and starting deeper
+3)	require return at game termination to handle windowing
+	systems
+4)	changed #ifdef and #ifndef to #if defined() and #if !defined()
+
+1.03 Alpha, May 2, 86
+1)	fixed up missed #ifdef changes
+2)	fruit name initialization screws up on very long names
+3)	monsters with multiple turns getting killed on their first
+	turn should never get a second turn (Mike Laman fix)
+4)	dropping and picking up multiple stuff sometimes screws up count
+	(another Mike Laman fix)
+5)	enhancement by Carl Hommel to zapping: save = 1/2 damage, 
+	rather than no damage.  bolt damage peters off towards the end 
+	of the zap
+
+1.03 Alpha May 5, 86
+1)	changed order of message and flag clearing for normal scroll
+	of remove curse to have a more consistent message
+2)	the gold sense command has been removed and it is automatically
+	done for thieves whenever a new level is created
+
+1.03 Alpha May 11, 86
+1)	fixed minor formatting error in last prompt for carriage return
+	before exiting
+2)	tons of minor and major bug fixes by Mike Laman, some pointed to
+	by lint and others from looking at code, with more for me to fix
+	(sigh!), including sys5 curses things and temporary absence of
+	brain
+
+1.03 Alpha May 12, 86
+1)	putting on a ring of free action turns off being held and those
+	monsters can never hold hero again (ever)
+2)	diddled around some more with format of prompt before exiting
+3)	changed define of "reg" in curses.h to have less warning messages
+4)	added a single new monster
+5)	changed name of NUMUNIQUE define in rogue.h to NUMSUMMON
+6)	use vowelstr() in giving name of monster summoning hero
+
+1.03 ALpha May 19, 86
+1)	added a whole lot of things by Carl Hommel including different
+	algorithms for shooting bolts, new armor and weapons, and
+	general tidying up of things
+
+1.03 Alpha, May 20, 86
+1)	added 67 new monsters from Carl Hommel and miscellaneous bug fixes
+ 
+1.03 Alpha, May 21, 86
+1)	initial support for SCO/Microsoft Xenix implementation of sys5r2
+	supplied by Tom Haapanen
+2)	fixed monster flags in new monsters supplied by Carl
+3)	changed number of new monsters/level constant from 3 to 4
+	(this number is too high given the actual number of monsters in
+	the monster table and the levels one has to go down.  there
+	should be 320 non-summoning monsters to be about right)
+4)	healing rate restored to original value
+
+1.03 Alpha, May 22, 86
+1)	protected and claimed objects stay with the hero when he 
+	resurrects
+2)	no saving throw against magic missile
+3)	magic missile damage depends upon player exp level
+4)	electrification bug fixed and range depends on hero exp. level
+5)	stepping into a pool when electrified is painful
+6)	monsters summon only when low on hit points and damage taken
+	above changes by Carl Hommel
+7)	number of magic items per level increased
+8)	bunches of monsters created less frequently
+9)	summoning while running around reduced in probability
+10)	don't kick any daemons off when being summoned to give initiative
+	to the player
+11)	increase the number of objects in a throne room
+
+1.03 Alpha, May 24, 86
+1)	changed algorithm for creating monsters with CANSHOOT weapons
+	and increased probability slightly
+2)	added new monsters from Carl Hommel and a bunch of my own
+3)	rearranged the hero-summoning unique monsters to be strictly
+	in order of hit points
+4)	rearranged some of ordinary monsters to make progession of
+	experience points for killing monster more monotonic
+5)	fix handling of extra long monster names in wizard monster creation
+	and monster genocide
+
+1.03 Alpha, May 25, 86
+1)	more modifications in and around chase.c, command.c, and fight.c
+	to remove the electrification bug.  Carl's fixes removed one,
+	the one that Jason reported is still there.
+2)	maximum traps/dungeon level increased
+3)	massively rewrite Makefiles, installation procedure, and
+	various sources to reorganize sources
+
+1.03 Alpha, May 28, 86
+1)	charmed monsters, new spells for druid and illusionist,
+	monsters striking each other, etc.  by Nick Flor
+2)	save throw handling changed to be centralized in one routine,
+	blessed/cursed stick handling, and wizard ^O command improved
+	by Carl Hommel
+3)	fixed save throw test for monster and hero differentiation
+4)	monster is not allowed to hit itself
+
+1.03 Alpha, May 29, 86
+1)	fixed pointer to struct bug save_throw() in fight.c
+
+1.03 Alpha, June 4, 86
+1)	check for NULL pointer when zapping with wand
+2)	potions have some food value
+3)	fix body AC for ninja
+4)	fix ucount for RTU3
+	obove fixes by Carl Hommel
+5)	including files in wrong order in main.c and rip.c pointed
+	out by Mike Cooper
+
+1.03 Alpha, June 5, 86
+1)	new program to replace all the print_* commands by Mike Cooper
+2)	fixed bug in urprint to use right flag word size and to use
+	correct number of flag words in monster initialization structure
+3)	experiment with allowing many familiars but only one at a time
+
+1.03 Alpha, June 6, 86
+1)	fixed format of scorefile output
+2)	familiars are never confused
+3)	changed algorithm for generating a summoned familiar
+
+1.03 Alpha, June 7, 86
+1)	yet another change to generating summoned familiar
+2)	not clearing familiar_ptr when familiar is killed
+3)	handling of monsters that may be friendly with some
+	probability
+4)	handling of monsters that do not breathe air
+5)	algorithm for blessed scroll of charm monster changed
+6)	groups of monsters will all be friendly or none
+7)	all familiars can use armor and weapons
+8)	familiars have extra hit point and better ability scores
+	based upon the hero's experience level
+9)	fixed up a few messages here and there
+
+1.03 Alpha, June 9, 86
+1)	handling of quartermaster selling stuff that is overpriced fixed
+2)	enchanting a stick might bless/curse it
+3)	new potions and powers to go with them and other misc. modifications
+	such as food value for potions, change in damage done by a firetrap,
+	and other miscellaneous stuff
+	above by Carl Hommel
+4)	set familiar_ptr to NULL when going to a new level
+5)	use ISGOD flag in monsdata.c to give special abilities to gods
+	dynamically
+6)	move trading post and throne rooms display lower on screen
+7)	changed ISBIG flag to ISTWOH for weapons
+8)	added various degrees of friendliness into monster table
+9)	make temporary buffer in inventory() bigger
+
+1.03 Alpha, June 10, 86
+1)	added yet another fix for summoning when scroll of charm monster 
+	been read and monsters are still alive
+2)	handle passing of pack to next familiar when going to a new level
+3)	CANWIELD and CANSHOOT monsters pick up things on the dungeon
+	floor too if they are weapons or armor
+
+1.03 Alpha, June 11, 86
+1)	ISSCAVENGE is not turned on automatically for familiars
+2)	monsters created by a normal and cursed scroll of create monster
+	are not friendly
+3)	monsters summoned by another monster are never friendly
+4)	normal and blessed wand of polymorph leave friendly monsters
+	friendly
+
+1.03 Alpha, June 11, 86
+1)	fix for updating mw correctly by Pat Place
+2)	remove Dr. C. reference in vers.c
+3)	remove extra turn wizard message from do_chase()
+4)	fixed rogue/Makefile to find hdrs correctly for lint
+
+1.03 Alpha, June 13, 86
+1)	potion of continuous breathing R_BREATHE, turns on HASOXYGEN
+2)	potion of flying CANFLY. hero is levitated, and have rnd(2)
+	of getting an extra attack
+3)	CANFLY means never setting off non-fire traps
+4)	HASOXYGEN means never getting zapped by a pool or gas trap,
+	or breath weapons
+5)	NOSHARP not affected by arrow or dart damage but affected poison
+6)	ISUNDEAD and CANPOISON not affected by dart poison
+7)	you don't automatically know what cursed potions are
+8)	wizards get a higher chance to ressurect
+9)	prayer command changed
+	above by Carl Hommel
+
+1.03 Alpha, June 14, 86
+1)	wearing a ring of wizardry gives spell abilities no matter what
+	intelligence or wisdom ability is
+2)	implemented armor and weapon restrictions by player class
+3)	preparations for having shield/cloak/charms and eventually
+	rings as all objects to wear
+4)	renamed short pike to ranseur and long pike to pike to be more
+	historically accurate
+5)	corrected testing of genocided monsters in summon()
+6)	create lots of monsters when making them standing still in
+	the dungeon
+7)	use killed() to throw away the monster list when generating a
+	new level of the dungeon because it recovers storage from
+	objects that monsters are carrying
+
+1.03 Alpha, June 15, 86
+1)	changed startup procedure to enforce armor and weapon restrictions
+2)	hero goes through trading post at startup to outfit pack
+3)	no more rolling of player characteristics
+4)	druid charm monster prayer now a very early and cheap spell
+5)	hero may have more things in pack depending upon player class
+6)	charm monster depends slightly on hero experience level too
+
+1.03 Alpha, June 16, 86
+1)	fixed up pointer usage in discarding monster list
+2)	increased purse that hero starts up with
+3)	fixed up format of display of saved heros and new ones at startup
+4)	increased maximum number of saved heros
+5)	changed how wizard commands are started up to get around
+	all the control character restrictions (Mike Cooper)
+6)	added keypad support for terminals that have them (Mike Cooper)
+
+1.03 Alpha, June 17, 86
+1)	fixed up a lot of bugs in handling familiars (Nick Flor)
+2)	improved steal() routine from Carl Hommel
+
+1.03 Alpha, June 18, 86
+1)	fixed up garbage display on screen left over from throwing away 
+	monsters using killed()
+2)	fixed multiple messages for killing only one gas spore
+3)	added HASOXYGEN flags to monsters that are not affected by 
+	gas breath weapons
+
+1.03 Alpha, June 19, 86
+1)	removed code to curse all things bought from a quartermaster
+2)	fixed up FRIENDLY and CHARMED monsters not moving
+3)	fixed up monsters picking up things and their display
+4)	killed() called with NULL killer from shoot_bolt() shouldn't be
+5)	hopefully fixed up stuff for killing Friendly Fiend in new_level()
+6)	allow more than 1 digit to indicate saved player number
+
+1.03 Alpha, June 22, 86
+1)	check order of inclusion of rogue.h and mach_dep.h and curses.h
+2)	fixed up message in Friendly Fiend's place
+3)	simplified expression too complex in move.c
+4)	fixed up display of objects picked up by monsters
+5)	probability of major side effect of artifacts reduced
+6)	urogue save file name made definable by installer
+7)	prompting to save character done only when new one rolled
+8)	friendly monsters next to hero run around when '.' is being hit
+9)	character displayed when monster killed updated from dungeon
+	level map instead of using abritrary character '.'
+10)	lighting of room when monsters and weapons are just outside
+	doorway fixed
+11)	paladin's get better saving throws against anything
+12)	rangers and ninjas are hardly ever surprised
+13)	paladins never get diseases or infections
+	other misc player class enhancements by Carl Hommel
+
+1.03 Alpha June 24, 86
+1)	yet another null pointer usage bug when monster can't be found
+	fixed by Pat Place
+2)	when a missile fired by a monster misses another one, it wakes
+	up anyways
+3)	garbage characters when killing a monster are displayed using
+	unctrl() in wizard message
+4)	paladin's have no fear
+5)	fixed up setting of hero AC during startup
+6)	fixed up range of numbers testing in geta_player() and puta_player()
+7)	don't add anything to familiar's pack if there is nothing to add
+8)	& no longer used as suspend in BSD versions
+9)	more cash given to heros at startup time
+
+1.03 Alpha, June 25, 86
+1)	deleted some macros from rogue.h that are used only in a few places
+2)	turn off ISMEAN flag from familiars and friendly monsters
+
+1.03 Alpha, June 26, 86
+1)	changed deletion of monster in killed() to after monster's pack
+	has been deleted
+2)	fixed up room lighting problem permanently
+3)	minor bug fixes
+4)	yet more removal of macros
+
+1.03 Alpha, June 28, 86
+1)	created new include files and deleted some macros
+2)	implementation of ring of carrying changed to reduce weight
+	by 150 gold pieces per enchantment
+3)	amount of gold generated increased
+4)	backstabbing for thief, ninja and assassin character classes
+5)	monsters can wield weapons against hero
+6)	amount of gold that hero starts with increased again
+7)	initialization of sticks for hero at startup fixed
+8)	frequency of monster creation reduced
+9)	pluses of weapons used by monsters increased by a random
+	function of the experience level of the monster
+
+1.03 Alpha, June 29, 86
+1)	fixed fighting of monster carrying no weapons
+2)	message in wrong place for monster thrown weapon that misses
+3)	more fixing of room lighting and darkening bugs
+4)	fixed lighting of rooms during new level creation
+5)	increased starting gold once again
+
+1.03 Alpha, June 30, 86
+1)	changed monster that Friendly Fiend summons
+2)	monsters that CANSHOOT pick from a wider variety of weapons
+3)	monsters that CANWIELD don't always
+4)	monsters zapped run toward the hero
+5)	split creat_mons() into creat_mons() and place_mons() routines
+	so that other programs can use it too
+6)	renamed familiar_* to fam_*
+7)	reduced probability of monsters in a given room when level is
+	generated
+
+1.03 Alpha, July 1, 86
+1)	algorithm for assignment of wielded weapons changed
+2)	fixed stupid typo error in place_mons() in scrolls.c
+3)	monsters that CANTELEPORT do so when running away
+
+1.03 Alpha, July 2, 86
+1)	electricity zapping a friendly or charmed monster loses the
+	hero a friend
+2)	fixed bug in place_mons() in scrolls.c; stupid typo
+
+1.03 Alpha, July 5, 86
+1)	undid changes in killed() in fight.c to discard monster pack
+2)	corrected setting of fighting in killed()
+3)	removed useless variables in rogue.c
+4)	fixed initialization of character type in geta_player()
+5)	fixed typo in secretdoor() in misc.c causing them to show as 'p'
+6)	all remaining usage of cfree replaced with free
+7)	make a group of monsters all friendly or all non-friendly
+8)	removed debugging message in place_mons() in scrolls.c
+
+1.03 Alpha, July 6, 86
+1)	fixed up more bad pointer references in wanderer() in monsters.c
+2)	fixed bad test for player class in wield_ok() in weapons.c
+3)	make sure every new monster starts with ISRUN off
+
+1.03 Alpha, July 8, 86
+1)	new magic system installed.  magic.c, magic_item.c files.  Still buggy.
+2)	rogue.c and rogue.h worked over
+3)	various formatting improved
+4)	new wear_ok() that allows players to wear anything, but
+	penalizes their class-specific special abilities.  wield_ok() coming up.
+5)	scroll of regeneration duplicates monster's regenerative abilities
+6)	familiar summoning made a scroll
+7)	quaff(), read_scroll(), do_zap() calling changed.
+8)	the Artifacts of Might do something if you just have them
+9)	ring of piety analogous to ring of wizardry introduced
+	above by Carl Hommel
+
+1.03 Alpha, July 9, 86
+1)	changed format of status lines
+2)	fixed bug in increasing the hero's power and hpt in quaff()
+
+1.03 Alpha, July 10, 86
+1)	spiffed up message for familiar nearly hitting hero
+2)	changed when familiars are gotten rid of when changing dungeon levels
+3)	fix monsters getting attacks when dead
+	above by Henry Chai
+4)	fix nonagressive familiars to beat on unfriendly monsters
+5)	changed some weapons for ninja and ranger at startup
+
+1.03 Alpha, July 11, 86
+1)	some fixes for casting of spells for non-MU player classes by
+	Carl Hommel
+2)	fixed up replacement of familiar when going to a new dungeon
+	level by Henry Chai
+
+1.03 Alpha, July 12, 86
+1)	increased spell point regeneration rate
+2)	replaced testing code for whether hero wants to try a hard spell
+3)	fixed up the ranger's starting kit a bit
+4)	improved ninja capabilities slightly
+5)	increase duration of disguise spell
+6)	attempt to fix monsters and heros in same spot
+7)	moving through a friendly monster wakes it up
+
+1.03 Alpha, July 13, 86
+1)	fixed misc monster movement problems moving onto hero
+2)	some tidying up of formats
+3)	fixed up names of things carried by ranger
+4)	improved ninja character abilities and make experience level change
+	point higher
+
+1.03 Alpha, July 14, 86
+1)	fighters can stun their opponents by doing greater than 1/3 of
+	remaining hit points in one blow
+2)	fixed up messages in new hit() routine
+
+1.03 Alpha, July 24, 86
+1)	Change NUMMONST, MAXPOTIONS, etc to variables
+2)	Change some potion, stick, wand define names for spellcasting
+3)	P_SHIELD, S_MSHIELD WS_KNOCK, WS_CLOSE added
+4)	WS_MDEG changed to WS_XENOHEAL
+5)	Added defines to replace TRUE and FALSE values passed
+	to various subroutines)
+6)	Made P_REGEN cause SUPEREAT.  Made it fusable.
+7)	The usual formatting changes to artifact.c, maze.c, monsters.c, wizard.c
+8)	Dropping armor and weapon to avoid artifact major 
+	effects	is no longer so good an idea
+9)	PHIAL does total healing, not light spell
+10)	Low-level monsters might break a hold spell
+11)	Everyone gets their hpts/pow changed against their armor/weapon,
+	not just paladins
+12)	Changed summon() to summon_help(), and added FORCE flag
+13)	Reordered hpt/pow regeneration in doctor()
+14)	Changed effect of R_CARRYING  - still buggy
+15)	PURSE intinsically allows more carrying
+16)	Reworked logic in fight()
+17)	Reordered status line to put Pow after Hpt
+18)	Some monster spell casting implemented
+19)	Created nothing_message() to print cryptic failure messages
+20)	Twiddled do_throne() to create just UNIQUE monster + attendants
+21)	Clerics get bonus exp. for turning/destroying undead
+22)	do_zap() logic changed
+23)	D_GODWRATH, D_CLUMSY deaths added
+	above by Carl Hommel
+
+1.03 Alpha, July 27, 86
+1)	added wizard debug message flag as well as wizard mode (Henry Chai)
+2)	stunning of monsters only when struck for 1/3 or more of
+	max hpt in one blow
+3)	various bug fixes by Mike Laman and Mike Cooper
+4)	saving a game clears the screen after prompt
+
+1.03 Alpha, July 29, 86
+1)	checking for penalties for wrong armor and weapons fixed
+	by Carl Hommel
+
+1.03 Alpha, July 30, 86
+1)	monsters now have probabilities of being a MU
+2)	fixed up readchar() to handle errors in a saner way
+3)	a monster type that is capable of using magic and is part
+	of a group will always use have magical abilities
+4)	the leader of a group of monsters will always be a bit better 
+	than the run of the mill monster
+5)	patches by Mike Cooper to shorten names of variables and
+	various defines to support ATT 7300
+
+1.03 Alpha, Aug 5, 86
+1)	Len Picard's bag code is ready
+2)	changed ISWEARING to a function instead of a macro
+3)	fixed minor bugs in sticks.c
+
+1.03 Alpha, Aug 9, 86
+1)	yet another attempt at fixing monster killing flag fixes by Mike Laman
+2)	applied fix by Carl Hommel to magic casting code
+3)	changed inventory command display format
+4)	updated readchar() handling of read() system call
+
+1.03 Alpha, Aug 10, 86
+1)	added flag for summoned monsters that disappear
+2)	fixed up mapping of internal types of objects to things structure
+	in create_obj()
+3)	correct loop to pick object type to select in create_obj()
+4)	yet another attempt at getting rid of "invalid command ^@" message
+
+1.03 Alpha, Aug 11, 86
+1)	"leaders" of a group of monsters not so improved over others
+2)	remove last reference to namefinder in Makefile.INST
+
+1.03 Alpha, Aug 12, 86
+1)	The usual formatting changes in command.c, fight.c
+2)	Implemented '~' experience-to-next-level command.
+	Has next_exp_level() called from check_level)	
+3)	is_carrying(TR_AMULET) protects vs CANDRAIN.
+4)	Made more "hit" and "miss" messages.
+5)	Moved extra exp code for clerics from affect() to killed().
+6)	Reworked spell costs.
+7)	Give MUs extra exp for casting spells.
+8)	Made fumbles less frequent.
+9)	Created feel_message().
+10)	Renamed spell abbreviations.
+11)	Corrected R_PIETY ordering.
+12)	Made some extra-planar monsters undead, fixed some monster letters.
+13)	Thieves get extra exp for picking up gold.
+14)	'p'raying asks if you really want to, and always maxes your hpt 
+	and pow to max)	
+15)	Casting 'HEAL' no longer increases pow.
+16)	Reworked P_GAINABIL as they occur less frequently.
+17)	Fixed S_SUMFAMILIAR.
+18)	Prelim fix to helpful monsters casting spells.
+	above by Carl Hommel
+19)	upgraded leaders of packs a bit more and also added experience
+	points for killing them
+20)	BMAGICHIT now requires only a +3 weapon, not a +4
+21)	druids can wield silver weapons even if they are metallic
+
+1.03 Alpha, Aug 13, 86
+1)	fix up keypad code to allow daemons to run after each turn
+
+1.04 Alpha, October 24, 1992
+1)      Update for modern compilation with ANSI C friendly compilers
+
+1.05 Alpha, September 1, 1993
+1)      Update save/restore code to not be simple core dumps so
+        that they can work under modern memory management systems.
+
+1.06 Alpha, July 21, 1995
+
+1)      Many changes made to fix remaining parameter passing related bugs.
+2)      Also, changes made to toughen game. Entire dungeon is now only 50
+        levels deep instead of 100 so that monsters get harder faster.
+3)      No more trading posts except at beginning or if entrance to
+        trading post is found.
+4)      The hero now regains spell points more slowly, has a tougher time with
+        some things, and generally is weaker than he used to be.
+5)      The game is not as hard as it needs to be yet, although i can make it
+        to about level 20 or so most times I play it.
+
+1.06 Alpha, August 3, 1995
+
+1)      Many more changes to allow dropping of stuff even where monsters or the
+        hero is, so there should almost never be messages of objects vanishing
+        in a puff of smoke. Also more error checking, debugging messages, and
+        generally much more bullet proof.
+2)      Restored ability to zap with charged weapons.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/ident.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,136 @@
+/*
+    ident.c - routines to associate an identifier with an object
+ 
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1986, 1991, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+/*
+ * ident
+ *
+ * This file contains routines to associate an identifier with an object. The
+ * identifiers are organized by type. Once an identifier is attached to an
+ * object, it remains with that object until the object is removed from the
+ * game. The identifiers are small integers, and they are assigned merely by
+ * counting objects of the same type. Allocation picks the next available
+ * integer.
+ *
+ * It is required that the linked list be sorted within types so that gaps can
+ * easily be detected.
+ */
+
+#include "rogue.h"
+
+/*
+ * Index of 0 is invalid (unused state)
+ */
+
+char print_letters[] = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+linked_list *ident_list = NULL; /* master list of all items */
+
+/*
+    get_ident()
+
+    Gets the identifier for the given object. If an identifier exists, it is
+    returned. If not, one is allocated and returned to the user. The
+    identifier remains constant as long as the object is in the game.
+*/
+
+int
+get_ident(struct object *obj_p)
+{
+    int obj_type = obj_p->o_type;
+    linked_list *list_p;           /* pointer into ident_list */
+    int new_id = 1;                /* in case we have to allocate */
+    struct object *tmp_obj_p;
+    struct linked_list *new_place_p = NULL;
+
+    if (identifier(obj_p) != 0)
+        return (identifier(obj_p));
+
+    /* no identifier - must allocate one */
+
+    for (list_p = ident_list; list_p != NULL; list_p = next(list_p))
+    {
+        tmp_obj_p = OBJPTR(list_p);
+
+        if (tmp_obj_p->o_type == obj_type)
+        {
+            if (identifier(tmp_obj_p) == new_id)
+            {
+                /* if this id is taken, try next */
+                new_place_p = list_p;
+                new_id++;
+            }
+        }
+    }
+
+    /*
+     * If we get here, the object is not in the list, and we need to add
+     * it. The proper id is in new_id, and the place to put it is right
+     * after new_place_p.
+     */
+
+    list_p = new_list();
+    _attach_after(&ident_list, new_place_p, list_p);
+    identifier(obj_p) = new_id;
+    list_p->data.obj = obj_p;
+    return(new_id);
+}
+
+/*
+    free_ident()
+
+    Frees up an identifier by removing the list entry that contains that item.
+    If the item isn't found, nothing is done.
+*/
+
+void
+free_ident(struct object *obj_p)
+{
+    linked_list *list_p;
+
+    for (list_p = ident_list; list_p != NULL; list_p = next(list_p))
+    {
+        if (obj_p == OBJPTR(list_p))
+        {
+            _detach(&ident_list, list_p);   /* unlink it from the list */
+            ur_free(list_p);                /* release link structure */
+            break;
+        }
+    }
+}
+
+/*
+    unprint_id()
+
+    Converts a printable id from print_letters to the real thing by getting the
+    index.
+*/
+
+int
+unprint_id(char *print_id)
+{
+    char    *id_p;
+
+    for (id_p = print_letters; id_p != NULL; id_p++)
+        if (*id_p == *print_id)
+            break;
+
+    return( (int) (id_p - print_letters) );
+}
+
+/*
+    max_print()
+
+        returns the size of the print list
+*/
+
+int
+max_print(void)
+{
+    return(sizeof(print_letters) - 2); /* 1 for blank and 1 for EOS string */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/init.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1075 @@
+/*
+    init.c - global variable initializaton
+ 
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+/*
+    Notes
+
+        Need to add ring of maintain armor (same as ring of prot, armor only)
+        Resplit file into one just for data, one just for functions
+*/
+
+#define _ALL_SOURCE /* Need to remove need for this AIXism */
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "rogue.h"
+
+static char *rainbow[] =
+{
+    "Red", "Blue", "Green", "Yellow",
+    "Black", "Brown", "Orange", "Pink",
+    "Purple", "Grey", "White", "Silver",
+    "Gold", "Violet", "Clear", "Vermilion",
+    "Ecru", "Turquoise", "Magenta", "Amber",
+    "Topaz", "Plaid", "Tan", "Tangerine",
+    "Aquamarine", "Scarlet", "Khaki", "Crimson",
+    "Indigo", "Beige", "Lavender", "Saffron"
+};
+
+#define NCOLORS (sizeof rainbow / sizeof (char *))
+
+static char *sylls[] =
+{
+    "a", "ab", "ag", "aks", "ala", "an", "ankh", "app", "arg", "arze",
+    "ash", "ban", "bar", "bat", "bek", "bie", "bin", "bit", "bjor",
+    "blu", "bot", "bu", "byt", "comp", "con", "cos", "cre", "dalf",
+    "dan", "den", "do", "e", "eep", "el", "eng", "er", "ere", "erk",
+    "esh", "evs", "fa", "fid", "for", "fri", "fu", "gan", "gar",
+    "glen", "gop", "gre", "ha", "he", "hyd", "i", "ing", "ion", "ip",
+    "ish", "it", "ite", "iv", "jo", "kho", "kli", "klis", "la", "lech",
+    "man", "mar", "me", "mi", "mic", "mik", "mon", "mung", "mur",
+    "nej", "nelg", "nep", "ner", "nes", "nes", "nih", "nin", "o", "od",
+    "ood", "org", "orn", "ox", "oxy", "pay", "pet", "ple", "plu", "po",
+    "pot", "prok", "re", "rea", "rhov", "ri", "ro", "rog", "rok", "rol",
+    "sa", "san", "sat", "see", "sef", "seh", "shu", "ski", "sna",
+    "sne", "snik", "sno", "so", "sol", "sri", "sta", "sun", "ta",
+    "tab", "tem", "ther", "ti", "tox", "trol", "tue", "turs", "u",
+    "ulk", "um", "un", "uni", "ur", "val", "viv", "vly", "vom", "wah",
+    "wed", "werg", "wex", "whon", "wun", "xo", "y", "yot", "yu",
+    "zant", "zap", "zeb", "zim", "zok", "zon", "zum"
+};
+
+static char *stones[] =
+{
+    "Agate", "Alexandrite", "Amethyst",
+    "Azurite", "Carnelian", "Chrysoberyl",
+    "Chrysoprase", "Citrine", "Diamond",
+    "Emerald", "Garnet", "Hematite",
+    "Jacinth", "Jade", "Kryptonite",
+    "Lapus lazuli", "Malachite", "Moonstone",
+    "Obsidian", "Olivine", "Onyx",
+    "Opal", "Pearl", "Peridot",
+    "Quartz", "Rhodochrosite", "Ruby",
+    "Sapphire", "Sardonyx", "Serpentine",
+    "Spinel", "Tiger eye", "Topaz",
+    "Tourmaline", "Turquoise"
+};
+
+#define NSTONES (sizeof stones / sizeof (char *))
+
+static char *wood[] =
+{
+    "Avocado wood", "Balsa", "Banyan", "Birch",
+    "Cedar", "Cherry", "Cinnibar", "Dogwood",
+    "Driftwood", "Ebony", "Eucalyptus", "Hemlock",
+    "Ironwood", "Mahogany", "Manzanita", "Maple",
+    "Oak", "Pine", "Redwood", "Rosewood",
+    "Teak", "Walnut", "Zebra wood", "Persimmon wood"
+};
+
+#define NWOOD (sizeof wood / sizeof (char *))
+
+static char *metal[] =
+{
+    "Aluminium", "Bone", "Brass", "Bronze",
+    "Copper", "Chromium", "Iron", "Lead",
+    "Magnesium", "Pewter", "Platinum", "Steel",
+    "Tin", "Titanium", "Zinc", "Carbon",
+	"Plastic", "Glass", "Ice", "Chocolate", 
+	"Gold", "Silver", "Invisible"
+};
+
+#define NMETAL (sizeof metal / sizeof (char *))
+
+const char *monstern = "monster";
+char *spacemsg = "--Press SPACE to continue--";
+char *morestr  = "--More--";
+char *retstr   = "[Press RETURN to continue]";
+
+/* 15 named levels */
+
+const char *cnames[C_NOTSET][15] =
+{
+    {   "Veteran", "Warrior",
+        "Swordsman", "Hero",    /* Fighter */
+        "Swashbuckler", "Myrmidon",
+        "Champion", "Superhero",
+        "Lord", "Lord",
+        "Lord", "Lord",
+        "Lord", "Lord",
+        "Lord"
+    },
+
+    {   "Gallant", "Keeper",
+        "Protector", "Defender",    /* Paladin */
+        "Warder", "Guardian",
+        "Chevalier", "Justiciar",
+        "Paladin", "Paladin",
+        "Paladin", "Paladin",
+        "Paladin", "Paladin",
+        "Paladin"
+    },
+
+    {   "Runner", "Strider",
+        "Scout", "Courser", /* Ranger */
+        "Tracker", "Guide",
+        "Pathfinder", "Ranger",
+        "Ranger Knight", "Ranger Lord",
+        "Ranger Lord", "Ranger Lord",
+        "Ranger Lord", "Ranger Lord",
+        "Ranger Lord"
+    },
+
+    {   "Acolyte", "Adept",
+        "Priest", "Curate", /* Cleric */
+        "Prefect", "Canon",
+        "Lama", "Patriarch",
+        "High Priest", "High Priest",
+        "High Priest", "High Priest",
+        "High Priest", "High Priest",
+        "High Priest"
+    },
+
+    {   "Aspirant", "Ovate",   /* Druid */
+        "Initiate of the 1st Circle", "Initiate of the 2nd Circle",
+        "Initiate of the 3rd Circle", "Initiate of the 4th Circle",
+        "Initiate of the 5th Circle", "Initiate of the 6th Circle",
+        "Initiate of the 7th Circle", "Initiate of the 8th Circle",
+        "Initiate of the 9th Circle", "Druid",
+        "Archdruid", "The Great Druid",
+        "The Grand Druid"
+    },
+
+    {   "Prestidigitator", "Evoker",
+        "Conjurer", "Theurgist",    /* Magic User */
+        "Thaumaturgist", "Magician",
+        "Enchanter", "Warlock",
+        "Sorcerer", "Necromancer",
+        "Wizard", "Wizard",
+        "Wizard", "Wizard",
+        "Wizard"
+    },
+
+    {   "Prestidigitator", "Minor Trickster",
+        "Trickster", "Master Trickster",    /* Illusionist */
+        "Cabalist", "Visionist",
+        "Phantasmist", "Apparitionist",
+        "Spellbinder", "Illusionist",
+        "Illusionist", "Illusionist",
+        "Illusionist", "Illusionist",
+        "Illusionist"
+    },
+
+    {   "Rogue", "Footpad",
+        "Cutpurse", "Robber",   /* Thief */
+        "Burglar", "Filcher",
+        "Sharper", "Magsman",
+        "Thief", "Master Thief",
+        "Master Thief", "Master Thief",
+        "Master Thief", "Master Thief",
+        "Master Thief"
+    },
+
+    {   "Bravo", "Rutterkin",
+        "Waghalter", "Murderer",    /* Assasin */
+        "Thug", "Killer",
+        "Cutthroat", "Executioner",
+        "Assassin", "Expert Assassin",
+        "Senior Assassin", "Chief Assassin",
+        "Prime Assassin", "Guildmaster Assassin",
+        "Grandfather of Assassins"
+    },
+
+    {   "Ninja", "Ninja",
+        "Ninja", "Ninja",   /* Ninja */
+        "Ninja", "Ninja",
+        "Ninja", "Ninja",
+        "Ninja", "Ninja",
+        "Ninja", "Ninja",
+        "Ninja", "Ninja",
+        "Ninja"
+    }
+};
+
+const struct h_list helpstr[] =
+{
+    { '?',      "  prints help"                         },
+    { '/',      "  identify object"                     },
+    { 'h',      "  left"                                },
+    { 'j',      "  down"                                },
+    { 'k',      "  up"                                  },
+    { 'l',      "  right"                               },
+    { 'y',      "  up & left"                           },
+    { 'u',      "  up & right"                          },
+    { 'b',      "  down & left"                         },
+    { 'n',      "  down & right"                        },
+    { '<',      "SHIFT><dir> run that way"              },
+    { 'm',      "<dir> move onto without picking up"    },
+    { 't',       "<dir> throw something"                },
+    { 'z',      "<dir> zap a wand or staff"             },
+    { '>',      "  go down a staircase"                 },
+    { 's',      "  search for trap/secret door"         },
+    { '.',      "  rest for a while"                    },
+    { ',',      "  pick up an object"                   },
+    { 'i',      "  inventory all items"                 },
+    { 'I',      "  inventory type of item"              },
+    { 'q',      "  quaff potion"                        },
+    { 'r',      "  read paper"                          },
+    { 'e',      "  eat food"                            },
+    { 'w',      "  wield a weapon"                      },
+    { 'W',      "  wear armor"                          },
+    { 'T',      "  take armor off"                      },
+    { 'P',      "  put on ring"                         },
+    { 'R',      "  remove ring"                         },
+    { 'A',      "  activate/apply an artifact"          },
+    { 'd',      "  drop object"                         },
+    { 'C',      "  call object (generic)"               },
+    { 'M',      "  mark object (specific)"              },
+    { 'o',      "  examine/set options"                 },
+    { 'c',      "  cast a spell/say a prayer"           },
+    { 'p',      "  pray for help (risky)"               },
+    { 'a',      "  affect the undead"                   },
+    { '^',      "  set a trap"                          },
+    { 'D',      "  dip something (into a pool)"         },
+    { 20,       "<dir>  take (steal) from (direction)"  }, /* ctrl-t */
+    { 18,       "   redraw screen"                      }, /* ctrl-r */
+    { 16,       "   back up to 10 previous messages"    }, /* ctrl-p */
+    { ESCAPE,   "   cancel command"                     },
+    { 'v',      "  print program version number"        },
+    { 'S',      "  save game"                           },
+    { 'Q',      "  quit"                                },
+    { '=',      "  listen for monsters"                 },
+    { 'f',      "<dir> fight monster"                   },
+    { 'F',      "<dir> fight monster to the death"      },
+
+    /* Wizard commands.  Identified by (h_ch != 0 && h_desc == 0). */
+
+    {'-',       0                                       },
+    { 23,       "   enter wizard mode"                  }, /* ctrl-w */
+    { 23,       "v  toggle wizard verbose mode"         },
+    { 23,       "e  exit wizard mode"                   },
+    { 23,       "r  random number check"                },
+    { 23,       "s  system statistics"                  },
+    { 23,       "F  food statistics"                    },
+    { 23,       "f  floor map"                          },
+    { 23,       "m  see monster"                        },
+    { 23,       "M  create monster"                     },
+    { 23,       "c  create item"                        },
+    { 23,       "i  inventory level"                    },
+    { 23,       "I  identify item"                      },
+    { 23,       "t  random teleport"                    },
+    { 23,       "g  goto level"                         },
+    { 23,       "C  charge item"                        },
+    { 23,       "w  print worth of object"              },
+    { 23,       "o  improve stats and pack"             },
+    { 0,        0                                       }
+};
+
+struct magic_item things[] =
+{
+    {"potion",  "POTION",   250,    5}, /* potion           */
+    {"scroll",  "SCROLL",   260,    30},/* scroll           */
+    {"ring",    "RING",     70,     5}, /* ring             */
+    {"stick",   "STICK",    60,     0}, /* stick            */
+    {"food",    "FOOD",     210,    7}, /* food             */
+    {"weapon",  "WEAPON",   60,     0}, /* weapon           */
+    {"armor",   "ARMOR",    90,     0}, /* armor            */
+    {"artifact","ARTIFACT", 0,      0}  /* special artifacts*/
+};
+
+int numthings = NUMTHINGS;
+
+struct magic_item s_magic[] =
+{
+    {"monster confusion",   "CON",      50, 125,    0,  0   },
+    {"magic mapping",       "MAP",      45, 150,    20, 10  },
+    {"light",               "WATT",     0,  0,      0,  0   },
+    {"hold monster",        "HOLD",     25, 200,    33, 10  },
+    {"sleep",               "SNOOZE",   23, 50,     20, 10  },
+    {"enchantment",         "ENCHANT",  110,400,    15, 10  },
+    {"identify",            "ID",       150,50,     0,  15  },
+    {"scare monster",       "SCARE",    35, 250,    27, 21  },
+    {"detect gold",         "GOLD",     0,  0,      0,  0   },
+    {"teleportation",       "TELEP",    50, 165,    10, 20  },
+    {"create monster",      "CREATE",   25, 75,     30, 0   },
+    {"remove curse",        "REM",      75, 220,    10, 15  },
+    {"petrification",       "PET",      25, 285,    0,  0   },
+    {"genocide",            "GEN",      10, 1200,   0,  0   },
+    {"cure disease",        "CURE",     70, 80,     0,  0   },
+    {"acquirement",         "MAKE",     5,  2500,   50, 15  },
+    {"protection",          "PROT",     50, 1150,   0,  0   },
+    {"nothing",             "NOTHING",  75, 50,     50, 50  },
+    {"magic hitting",       "SILVER",   25, 1875,   45, 10  },
+    {"ownership",           "OWN",      15, 1550,   45, 10  },
+    {"detect food",         "FOOD",     0,  0,      0,  0   },
+    {"electrification",     "ELECTRIFY",20, 1450,   0,  0   },
+    {"charm monster",       "CHARM",    26, 1500,   25, 15  },
+    {"summon monster",      "SUMMON",   26, 1500,   25, 15  },
+    {"gaze reflection",     "REFLECT",  25, 400,    25, 15  },
+    {"summon familiar",     "SUMFAM",   0,  0,      0,  0   },
+    {"fear",                "FEAR",     20, 200,    20, 10  },
+    {"missile protection",  "MSHIELD",  20, 300,    20, 10  }
+};
+
+int maxscrolls = MAXSCROLLS;
+
+struct magic_item p_magic[] =
+{
+    {"clear thought",       "CLEAR",    90, 380,    27, 15  },
+    {"gain ability",        "GAINABIL", 40, 1250,   15, 15  },
+    {"see invisible",       "SEE",      0,  0,      0,  0   },
+    {"healing",             "HEAL",     120,330,    27, 27  },
+    {"detect monster",      "MON",      0,  0,      0,  0   },
+    {"detect magic",        "MAG",      0,  0,      0,  0   },
+    {"raise level",         "RAISE",    1,  1900,   11, 10  },
+    {"haste self",          "HASTE",    140,300,    30, 5   },
+    {"restore abilities",   "RESTORE",  130,120,    0,  0   },
+    {"phasing",             "PHASE",    45, 340,    21, 20  },
+    {"invisibility",        "INVIS",    30, 300,    0,  15  },
+    {"acute scent",         "SMELL",    30, 100,    20, 15  },
+    {"acute hearing",       "HEAR",     30, 100,    20, 15  },
+    {"super heroism",       "SUPER",    10, 800,    20, 15  },
+    {"disguise",            "DISGUISE", 30, 500,    0,  15  },
+    {"fire resistance",     "NOFIRE",   40, 350,    20, 15  },
+    {"cold resistance",     "NOCOLD",   40, 300,    20, 15  },
+    {"continuous breathing","BREATHE",  10, 200,    20, 15  },
+    {"flying",              "FLY",      30, 300,    20, 15  },
+    {"regeneration",        "REGEN",    20, 500,    20, 15  },
+    {"shield",              "SHIELD",   100,200,    20, 10  },
+    {"true sight",          "TRUESEE",  64, 570,    25, 15  }
+};
+
+int maxpotions = MAXPOTIONS;
+
+struct magic_item r_magic[] =
+{
+    {"protection",              "", 70, 500,    33, 25  },
+    {"add strength",            "", 65, 300,    33, 25  },
+    {"sustain ability",         "", 40, 380,    10, 0   },
+    {"searching",               "", 65, 250,    10, 0   },
+    {"see invisible",           "", 30, 175,    10, 0   },
+    {"alertness",               "", 40, 190,    10, 0   },
+    {"aggravate monster",       "", 35, 100,    100,0   },
+    {"dexterity",               "", 65, 220,    33, 25  },
+    {"increase damage",         "", 65, 320,    33, 25  },
+    {"regeneration",            "", 35, 860,    10, 0   },
+    {"slow digestion",          "", 40, 340,    15, 10  },
+    {"teleportation",           "", 35, 100,    100,0   },
+    {"stealth",                 "", 50, 700,    10, 0   },
+    {"add intelligence",        "", 60, 540,    33, 25  },
+    {"increase wisdom",         "", 60, 540,    33, 25  },
+    {"sustain health",          "", 60, 250,    10, 0   },
+    {"vampiric regeneration",   "", 20, 900,    25, 10  },
+    {"illumination",            "", 20, 300,    10, 0   },
+    {"delusion",                "", 20, 100,    75, 0   },
+    {"carrying",                "", 20, 400,    30, 30  },
+    {"adornment",               "", 15, 10000,  10, 0   },
+    {"levitation",              "", 20, 450,    30, 0   },
+    {"fire resistance",         "", 10, 750,    10, 0   },
+    {"cold resistance",         "", 10, 650,    10, 0   },
+    {"lightning resistance",    "", 10, 750,    10, 0   },
+    {"resurrection",            "", 1,  8000,   10, 0   },
+    {"breathing",               "", 10, 250,    10, 0   },
+    {"free action",             "", 10, 225,    10, 0   },
+    {"wizardry",                "", 2,  1950,   10, 0   },
+    {"piety",                   "", 2,  1950,   10, 0   },
+    {"teleport control",        "", 5,  450,    10, 0   },
+    {"true sight",              "", 10, 775,    10, 0   }
+};
+
+int maxrings = MAXRINGS;
+
+struct magic_item  ws_magic[] =
+{
+    {"light",           "LIGHT",        90, 150,    20, 20  },
+    {"striking",        "HIT",          58, 400,    0,  0   },
+    {"lightning",       "BOLT",         25, 800,    0,  0   },
+    {"fire",            "FIRE",         25, 600,    0,  0   },
+    {"cold",            "COLD",         30, 600,    0,  0   },
+    {"polymorph",       "POLY",         90, 210,    0,  0   },
+    {"magic missile",   "MLE",          90, 500,    0,  0   },
+    {"slow monster",    "SLOW",         76, 320,    25, 20  },
+    {"drain life",      "DRAIN",        90, 310,    20, 0   },
+    {"charging",        "CHARGE",       70, 1100,   0,  0   },
+    {"teleport monster","RANDOM",       90, 240,    25, 20  },
+    {"cancellation",    "CANCEL",       38, 230,    0,  0   },
+    {"confuse monster", "CONFMON",      50, 200,    0,  0   },
+    {"disintegration",  "KILL-O-ZAP",   10, 1550,   33, 0   },
+    {"anti-matter",     "BLACKHOLE",    30, 980,    0,  0   },
+    {"paralyze monster","PARAL",        38, 200,    0,  0   },
+    {"heal monster",    "XENOHEAL",     30, 200,    40, 10  },
+    {"nothing",         "NOTHING",      30, 100,    0,  0   },
+    {"invisibility",    "WS_INVIS",     30, 150,    30, 5   },
+    {"blasting",        "BLAST",        10, 220,    0,  0   },
+    {"webbing",         "WEB",          0,  0,      0,  0   },
+    {"door opening",    "KNOCK",        0,  0,      0,  0   },
+    {"hold portal",     "CLOSE",        0,  0,      0,  0   }
+};
+
+int maxsticks = MAXSTICKS;
+
+struct magic_item   fd_data[] =
+{
+    {"food ration", "RATION",   400,    20,     20, 20  },
+    {"random fruit","FRUIT", 300, 10, 0, 0},
+    {"cram",        "CRAM",     120,    30,     0,  0   },
+    {"honey cake",  "CAKES",    80,     10,     0,  0   },
+    {"lemba",       "LEMBA",    50,     80,     0,  0   },
+    {"miruvor",     "MIRUVOR",  50,     200,    0,  0   }
+};
+
+int maxfoods = MAXFOODS;
+
+/*
+ * weapons and their attributes
+ * Average Damage = (min_damage + max_damage) / 2)
+ * AD of 2D5+3 = (5 + 13) / 2 = 9
+ * AD of 3D6   = (3 + 18) / 2 = 10.5
+ */
+
+#define ISSHARPMETAL (ISSHARP | ISMETAL)
+#define ISCRYSKNIFE (ISSHARP | ISPOISON | ISMANY | ISLITTLE)
+
+struct init_weps weaps[] =
+{
+    /* Missile weapons */
+    {"sling",           "0d0", "0d0",   NONE,       5,  1,
+        ISLAUNCHER | ISLITTLE,                              },
+    {"rock",            "1d2", "1d4",   SLING,      5,  1,
+        ISMANY | ISMISL | ISLITTLE                          },
+    {"sling bullet",    "1d1", "1d8",   SLING,      3,  1,
+        ISSHARP | ISMANY | ISMISL | ISMETAL | ISLITTLE      },
+    {"short bow",       "1d1", "1d1",   NONE,       40, 75,
+        ISLAUNCHER                                          },
+    {"arrow",           "1d1", "2d3",   BOW,        5,  1,
+        ISSHARP | ISMANY | ISMISL | ISLITTLE                },
+    {"arrow",           "1d2", "2d8",   BOW,        10, 5,
+        ISSHARP | ISSILVER | ISMANY | ISMISL | ISLITTLE     },
+    {"fire arrow",      "1d2", "2d8",   BOW,        10, 3,
+        ISSHARP | CANBURN | ISMANY | ISMISL | ISLITTLE      },
+    {"footbow",         "1d1", "1d1",   NONE,       90, 125,
+        ISLAUNCHER                                          },
+    {"footbow bolt",    "1d2", "1d10",  FOOTBOW,    5,  1,
+        ISSHARP | ISMANY | ISMISL | ISLITTLE                },
+    {"crossbow",        "1d1", "1d1",   NONE,       100,175,
+        ISLAUNCHER                                          },
+    {"crossbow bolt",   "1d2", "2d5",  CROSSBOW,   7,  3,
+        ISSHARP | ISMANY | ISMISL | ISLITTLE                },
+
+    /* Useful throwing weapons */
+    {"dart",        "1d1", "1d3",       NONE,   5,  1,
+        ISSHARP | ISMANY | ISMISL | ISLITTLE            },
+    {"dagger",      "1d6", "1d4",       NONE,   10, 2,
+        ISSHARP | ISMETAL | ISMANY | ISMISL | ISLITTLE  },
+    {"hammer",      "1d3", "1d5",       NONE,   50, 3,
+        ISMETAL | ISMISL                                },
+    {"leuku",       "1d6", "1d5",       NONE,   40, 4,
+        ISSHARP | ISMETAL | ISTWOH                      },
+    {"javelin",     "1d4", "1d6",       NONE,   10, 5,
+        ISSHARP | ISMISL | ISTWOH                       },
+    {"tomahawk",    "1d6", "1d6",       NONE,   45, 7,
+        ISSHARP | ISMISL                                },
+    {"machete",     "1d7", "1d6",       NONE,   45, 4,
+        ISSHARP | ISMETAL | ISMISL                      },
+    {"throwing axe","1d3", "1d6+2",     NONE,   50, 8,
+        ISSHARP | ISMETAL | ISMISL                      },
+    {"spear",       "2d3", "1d6",       NONE,   50, 2,
+        ISSHARP | ISMETAL | ISMISL                      },
+    {"boomerang",   "1d1", "1d8",       NONE,   10, 13,
+        CANRETURN | ISMANY | ISMISL | ISLITTLE          },
+    {"long spear",  "1d8", "1d10",      NONE,   50, 20,
+        ISSHARP | ISMETAL | ISMISL | ISTWOH             },
+    {"shuriken",    "1d1", "2d5",       NONE,   4,  20,
+        ISSHARP | ISMETAL | ISMANY | ISMISL | ISLITTLE  },
+    {"burning oil", "0d0", "2d10+5",    NONE,   20, 30,
+        CANBURN | ISMANY | ISMISL | ISLITTLE            },
+    {"grenade",       "1d1", "1d2/4d8", NONE,   10, 50,
+        ISMANY | ISSMALL                                },
+
+    /* other weapons */
+    {"club",          "1d4",   "1d2", NONE, 30,  2,   0                     },
+    {"pitchfork",     "1d5",   "2d2", NONE, 15,  5,   ISSHARPMETAL          },
+    {"short sword",   "1d6",   "1d2", NONE, 50,  10,  ISSHARPMETAL          },
+    {"hand axe",      "1d6",   "1d2", NONE, 40,  15,  ISSHARPMETAL          },
+    {"partisan",      "1d6",   "1d2", NONE, 75,  4,   ISSHARPMETAL | ISTWOH },
+    {"grain flail",   "1d6",   "1d4", NONE, 100, 2,   ISSHARPMETAL          },
+    {"singlestick",   "1d4+2", "1d2", NONE, 30,  20,  0                     },
+    {"rapier",        "1d6+1", "1d2", NONE, 7,   75,  ISSHARPMETAL          },
+    {"sickle",        "1d6+1", "1d2", NONE, 30,  15,  ISSHARPMETAL          },
+    {"hatchet",       "1d6+1", "1d4", NONE, 50,  10,  ISSHARPMETAL          },
+    {"scimitar",      "1d8",   "1d2", NONE, 40,  10,  ISSHARPMETAL          },
+    {"mace",          "2d4",   "1d3", NONE, 100, 40,  0                     },
+    {"morning star",  "2d4",   "1d3", NONE, 125, 35,  ISMETAL               },
+    {"broad sword",   "2d4",   "1d3", NONE, 75,  50,  ISSHARPMETAL          },
+    {"miner's pick",  "2d4",   "1d2", NONE, 85,  40,  ISSHARPMETAL          },
+    {"guisarme",      "2d4",   "1d3", NONE, 100, 25,  ISSHARPMETAL | ISTWOH },
+    {"war flail",     "1d6+2", "1d4", NONE, 150, 50,  ISSHARPMETAL | ISTWOH },
+    {"crysknife",     "3d3",   "1d3", NONE, 12,  100, ISCRYSKNIFE           },
+    {"battle axe",    "1d8+2", "1d3", NONE, 80,  100, ISSHARPMETAL          },
+    {"cutlass",       "1d10",  "1d2", NONE, 55,  120, ISSHARPMETAL          },
+    {"glaive",        "1d10",  "1d3", NONE, 80,  80,  ISSHARPMETAL | ISTWOH },
+    {"pertuska",      "2d5",   "1d3", NONE, 130, 100, ISSHARPMETAL | ISTWOH },
+    {"long sword",    "3d4",   "1d2", NONE, 100, 150, ISSHARPMETAL          },
+    {"lance",         "1d12",  "1d8", NONE, 80,  140, ISSHARP | ISTWOH      },
+    {"ranseur",       "1d12",  "1d8", NONE, 100, 130, ISSHARPMETAL | ISTWOH },
+    {"sabre",         "2d6",   "1d3", NONE, 50,  200, ISSHARPMETAL          },
+    {"spetum",        "2d6",   "1d3", NONE, 50,  180, ISSHARPMETAL | ISTWOH },
+    {"halberd",       "2d6",   "1d3", NONE, 150, 125, ISSHARPMETAL | ISTWOH },
+    {"trident",       "3d4",   "1d4", NONE, 50,  200, ISSHARPMETAL | ISTWOH },
+    {"war pick",      "3d4",   "1d2", NONE, 75,  175, ISSHARPMETAL | ISTWOH },
+    {"bardiche",      "3d4",   "1d2", NONE, 125, 125, ISSHARPMETAL | ISTWOH },
+    {"heavy mace",    "3d4",   "1d3", NONE, 200, 50,  ISTWOH                },
+    {"great scythe",  "2d6+2", "1d2", NONE, 100, 200, ISSHARP | ISTWOH      },
+    {"quarter staff", "3d5",   "1d2", NONE, 70,  250, 0                     },
+    {"bastard sword", "2d8",   "1d2", NONE, 150, 300, ISSHARPMETAL          },
+    {"pike",          "2d8",   "2d6", NONE, 200, 275, ISSHARPMETAL | ISTWOH },
+    {"great flail",   "2d6+2", "1d4", NONE, 200, 275, ISSHARPMETAL | ISTWOH },
+    {"great maul",    "4d4",   "1d3", NONE, 400, 250, ISTWOH                },
+    {"great pick",    "2d9",   "1d2", NONE, 175, 330, ISSHARPMETAL | ISTWOH },
+    {"two handed sword","4d4", "1d2", NONE, 250, 300, ISSHARPMETAL | ISTWOH },
+    {"claymore",      "3d7",   "1d2", NONE, 200, 500, ISSHARPMETAL | ISTWOH }
+};
+
+int maxweapons = MAXWEAPONS;
+
+struct init_armor   armors[] =
+{
+    { "soft leather",         75, 20,  9,  50 },
+    { "cuirboilli",          150, 30,  8, 130 },
+    { "leather armor",       175, 40,  8, 100 },
+    { "ring mail",           350, 49,  7, 250 },
+    { "studded leather armor",400,58,  7, 200 },
+    { "scale mail",          500, 66,  6, 250 },
+    { "padded armor",        550, 72,  6, 150 },
+    { "chain mail",          750, 78,  5, 300 },
+    { "brigandine",          800, 84,  5, 280 },
+    { "splint mail",        1000, 88,  4, 350 },
+    { "banded mail",        1250, 90,  4, 300 },
+    { "superior chain",     1500, 93,  3, 350 },
+    { "plate mail",         1400, 96,  3, 400 },
+    { "plate armor",        1650, 98,  2, 450 },
+    { "mithril",           30000, 99,  2, 200 },
+    { "crystalline armor", 15000, 100, 0, 300 }
+};
+
+int     maxarmors = MAXARMORS;
+
+struct init_artifact    arts[] = {
+    { "Magic Purse of Yendor", 15, 1, 1, 1,  1,  4600L, 50 },
+    { "Phial of Galadriel",    20, 2, 2, 2,  1, 12500L, 10 },
+    { "Amulet of Yendor",      25, 4, 1, 1,  2, 16000L, 10 },
+    { "Palantir of Might",     30, 1, 4, 1,  2, 18500L, 70 },
+    { "Crown of Might",        35, 6, 2, 1,  1, 23500L, 50 },
+    { "Sceptre of Might",      40, 2, 2, 1,  6, 38000L, 50 },
+    { "Silmaril of Ea",        45, 4, 2, 5,  1, 50000L, 50 },
+    { "Wand of Yendor",        50, 4, 2, 3, 10, 80000L, 50 }
+};
+
+int     maxartifact = MAXARTIFACT;
+
+/*
+    init_player()
+        roll up the rogue
+*/
+
+void
+init_player(void)
+{
+    int special = rnd(100) < 20;
+    struct linked_list  *item;
+    struct object   *obj;
+    int which_armor = 0, which_weapon = 0;
+    int other_weapon_flags = 0;
+
+    pstats.s_lvl = 1;
+    pstats.s_exp = 0L;
+    pstats.s_arm = 10;
+
+    if (!geta_player())
+    {
+        do_getplayer(); /* get character class */
+        pstats.s_str = 8 + rnd(5);
+        pstats.s_intel = 8 + rnd(5);
+        pstats.s_wisdom = 8 + rnd(5);
+        pstats.s_dext = 8 + rnd(5);
+        pstats.s_const = 10 + rnd(8);
+        pstats.s_charisma = 8 + rnd(4);
+        pstats.s_power = 5 + rnd(5);
+        pstats.s_hpt = 15 + rnd(5);
+
+        switch (char_type)      /* Class-specific abilities */
+        {
+            case C_FIGHTER:
+                pstats.s_str = 17;
+                pstats.s_const += rnd(4) + 1;
+                if (special)
+                {
+                    pstats.s_str += rnd(3);
+                    pstats.s_dext += rnd(4);
+                }
+                pstats.s_const = max(pstats.s_const, 16);
+                break;
+
+            case C_PALADIN:
+                pstats.s_charisma = 17;
+
+                if (special)
+                {
+                    pstats.s_charisma += rnd(3);
+                    pstats.s_wisdom += rnd(4);
+                    pstats.s_str += rnd(5);
+                }
+
+                pstats.s_str = max(pstats.s_str, 16);
+                pstats.s_wisdom = max(pstats.s_wisdom, 16);
+                break;
+
+            case C_RANGER:
+                if (special)
+                {
+                    pstats.s_wisdom += rnd(4);
+                    pstats.s_intel += rnd(4);
+                    pstats.s_str += rnd(5);
+                }
+
+                pstats.s_str = max(pstats.s_str, 16);
+                pstats.s_wisdom = max(pstats.s_wisdom, 16);
+                pstats.s_const = max(pstats.s_const, 14);
+                break;
+
+            case C_MAGICIAN:
+                pstats.s_intel = (special) ? 18 : 16;
+                pstats.s_power += 5 + rnd(10);
+                break;
+
+            case C_ILLUSION:
+                pstats.s_intel = (special) ? 18 : 16;
+                pstats.s_dext = (special) ? 18 : 14;
+                pstats.s_power += 5 + rnd(10);
+                break;
+
+            case C_CLERIC:
+                pstats.s_wisdom = (special) ? 18 : 16;
+                pstats.s_str += rnd(4);
+                pstats.s_power += 5 + rnd(10);
+                break;
+
+            case C_DRUID:
+                if (special)
+                {
+                    pstats.s_wisdom += rnd(5);
+                    pstats.s_charisma += rnd(4);
+                }
+                pstats.s_str += rnd(4);
+                pstats.s_power += 5 + rnd(10);
+                pstats.s_wisdom = max(pstats.s_wisdom, 16);
+                break;
+
+            case C_THIEF:
+                pstats.s_dext = 18;
+                if (special)
+                    pstats.s_const += rnd(4) + 1;
+                break;
+
+            case C_ASSASIN:
+                pstats.s_dext = (special) ? 18 : 16;
+                pstats.s_intel = (special) ? 18 : 16;
+                break;
+
+            case C_NINJA:
+                if (special)
+                {
+                    pstats.s_dext += rnd(5);
+                    pstats.s_str += rnd(4);
+                    pstats.s_intel += rnd(3);
+                    pstats.s_wisdom += rnd(3);
+                }
+                pstats.s_dext = max(pstats.s_dext, 16);
+                pstats.s_str = max(pstats.s_str, 15);
+                pstats.s_wisdom = max(pstats.s_wisdom, 15);
+                pstats.s_const = max(pstats.s_const, 15);
+                pstats.s_charisma = max(pstats.s_charisma, 11);
+        }
+
+        puta_player();
+    }
+
+    if (char_type == C_ASSASIN || char_type == C_NINJA
+        || char_type == C_FIGHTER)
+        pstats.s_dmg = "2d6";
+    else
+        pstats.s_dmg = "1d4";
+
+    if (char_type == C_NINJA || char_type == C_FIGHTER)
+        pstats.s_arm = 8;
+
+    if (pstats.s_const > 15)
+        pstats.s_hpt += pstats.s_const - 15;
+
+    max_stats = pstats;
+    player.t_rest_hpt = player.t_rest_pow = 0;
+    player.t_praycnt = 0;
+    pstats.s_carry = totalenc();
+    pack = NULL;
+
+    switch (player.t_ctype)    /* now outfit pack */
+    {
+        case C_PALADIN:
+            purse        = roll(20, 60);
+            which_armor  = CHAIN_MAIL;
+            which_weapon = LONG_SWORD;
+            break;
+
+        case C_FIGHTER:
+            purse = roll(50, 60);
+            which_armor = SCALE_MAIL;
+            which_weapon = BROAD_SWORD;
+            break;
+
+        case C_RANGER:
+            purse        = roll(50, 60);
+            which_armor  = PADDED_ARMOR;
+            which_weapon = LONG_SPEAR;
+            other_weapon_flags |= ISOWNED | CANRETURN;
+            break;
+
+        case C_CLERIC:
+            purse        = roll(30, 80);
+            which_armor  = RING_MAIL;
+            which_weapon = MORNINGSTAR;
+            break;
+
+        case C_DRUID:
+            purse        = roll(30, 80);
+            which_armor  = STUDDED_LEATHER;
+            which_weapon = LIGHT_MACE;
+            break;
+
+        case C_THIEF:
+            purse        = roll(40, 80);
+            which_armor  = HEAVY_LEATHER;
+            which_weapon = CUTLASS;
+            break;
+
+        case C_ASSASIN:
+            purse        = roll(20, 80);
+            which_armor  = CUIRBOLILLI;
+            which_weapon = SABRE;
+            other_weapon_flags |= ISPOISON;
+            break;
+
+        case C_NINJA:
+            purse        = roll(20, 80);
+            which_armor  = CUIRBOLILLI;
+            which_weapon = CRYSKNIFE;
+            other_weapon_flags |= ISPOISON;
+            item = spec_item(WEAPON, SHURIKEN, 1, 1);
+            obj = OBJPTR(item);
+            obj->o_count = 1;
+            obj->o_flags |= ISKNOW | ISPOISON | ISOWNED | CANRETURN;
+            add_pack(item, NOMESSAGE);
+            break;
+
+        case C_MAGICIAN:
+        case C_ILLUSION:
+            purse        = roll(20, 60);
+            which_armor  = SOFT_LEATHER;
+            which_weapon = SINGLESTICK;
+            break;
+
+        default:
+            break;
+    }
+
+    /* Add weapon to pack */
+
+    item = spec_item(WEAPON, which_weapon, 1, 1);
+    obj  = OBJPTR(item);
+
+    obj->o_flags |= ISKNOW;
+    obj->o_flags |= other_weapon_flags;
+    obj->o_count = 1;
+    add_pack(item, NOMESSAGE);
+    cur_weapon = obj;
+
+    /* Add armor to pack */
+
+    item = spec_item(ARMOR, which_armor, 0, 0);
+    obj = OBJPTR(item);
+
+    obj->o_flags |= ISKNOW;
+    obj->o_weight = armors[which_armor].a_wght;
+    add_pack(item, NOMESSAGE);
+    cur_armor = obj;
+
+    /* Add some food to pack */
+
+    item = spec_item(FOOD, FD_CRAM, 0, 0);
+    obj = OBJPTR(item);
+
+    obj->o_weight = things[TYP_FOOD].mi_wght;
+    obj->o_count = 3;
+    add_pack(item, NOMESSAGE);
+}
+
+/*
+    init_flags()
+        Initialize flags on startup
+*/
+
+void
+init_flags(void)
+{
+    switch (player.t_ctype)
+    {
+        case C_MAGICIAN:
+        case C_ILLUSION:
+        case C_CLERIC:
+        case C_DRUID:
+        case C_RANGER:
+        case C_PALADIN:
+            turn_on(player, CANSUMMON);
+            break;
+
+        default:
+            break;
+    }
+
+    turn_on(player, CANCAST);
+    turn_on(player, CANWIELD);
+}
+
+/*
+ * Contains definitions and functions for dealing with things like potions
+ * and scrolls
+ */
+
+/*
+    init_things()
+        Initialize the probabilities for types of things
+*/
+
+void
+init_things(void)
+{
+    struct magic_item *mp;
+
+    for (mp = &things[1]; mp < &things[numthings]; mp++)
+        mp->mi_prob += (mp - 1)->mi_prob;
+
+    badcheck("things", things, numthings);
+}
+
+/*
+    init_fd()
+        Initialize the probabilities for types of food
+*/
+
+void
+init_fd(void)
+{
+    struct magic_item  *mp;
+
+    for (mp = &fd_data[1]; mp < &fd_data[maxfoods]; mp++)
+        mp->mi_prob += (mp - 1)->mi_prob;
+
+    badcheck("food", fd_data, maxfoods);
+}
+
+/*
+    init_colors()
+        Initialize the potion color scheme for this time
+*/
+
+void
+init_colors(void)
+{
+    int   i;
+    char *str;
+
+    for (i = 0; i < maxpotions; i++)
+    {
+        do
+            str = rainbow[rnd(NCOLORS)];
+        while( !isupper(*str) );
+
+        p_colors[i]    = md_strdup(str);
+        p_colors[i][0] = (char) tolower(p_colors[i][0]);
+
+        know_items[TYP_POTION][i]  = FALSE;
+        guess_items[TYP_POTION][i] = NULL;
+
+        if (i > 0)
+            p_magic[i].mi_prob += p_magic[i - 1].mi_prob;
+    }
+
+    badcheck("potions", p_magic, maxpotions);
+}
+
+/*
+    init_names()
+        Generate the names of the various scrolls
+*/
+
+void
+init_names(void)
+{
+    int    nsyl;
+    char   *cp, *sp;
+    int    i, nwords;
+
+    for (i = 0; i < maxscrolls; i++)
+    {
+        cp = prbuf;
+        nwords = rnd(COLS / 20) + 1 + (COLS > 40 ? 1 : 0);
+
+        while (nwords--)
+        {
+            nsyl = rnd(3) + 1;
+
+            while (nsyl--)
+            {
+                sp = sylls[rnd((sizeof sylls) /
+                    (sizeof(char *)))];
+
+                while (*sp)
+                    *cp++ = *sp++;
+            }
+            *cp++ = ' ';
+        }
+
+        *--cp = '\0';
+        s_names[i] = (char *) new_alloc(strlen(prbuf) + 1);
+
+        know_items[TYP_SCROLL][i] = FALSE;
+        guess_items[TYP_SCROLL][i] = 0;
+
+        strcpy(s_names[i], prbuf);
+
+        if (i > 0)
+            s_magic[i].mi_prob += s_magic[i - 1].mi_prob;
+    }
+
+    badcheck("scrolls", s_magic, maxscrolls);
+}
+
+/*
+    init_stones()
+        Initialize the ring stone setting scheme for this time
+*/
+
+void
+init_stones(void)
+{
+    int   i;
+    char *str;
+
+    for (i = 0; i < maxrings; i++)
+    {
+        do
+            str = stones[rnd(NSTONES)];
+        while(!isupper(*str));
+
+        r_stones[i]    = md_strdup(str);
+        r_stones[i][0] = (char) tolower( r_stones[i][0] );
+
+        know_items[TYP_RING][i]  = FALSE;
+        guess_items[TYP_RING][i] = NULL;
+
+        if (i > 0)
+            r_magic[i].mi_prob += r_magic[i - 1].mi_prob;
+    }
+
+    badcheck("rings", r_magic, maxrings);
+}
+
+/*
+    init_materials()
+        Initialize the construction materials for wands and staffs
+*/
+
+void
+init_materials(void)
+{
+    int   i;
+    char *str;
+
+    for (i = 0; i < maxsticks; i++)
+    {
+        do
+        {
+            if (rnd(100) > 50)
+            {
+                str = metal[rnd(NMETAL)];
+
+                if (isupper(*str))
+                    ws_type[i] = "wand";
+            }
+            else
+            {
+                str = wood[rnd(NWOOD)];
+
+                if (isupper(*str))
+                    ws_type[i] = "staff";
+            }
+        }
+        while(!isupper(*str));
+
+        ws_made[i] = md_strdup(str);
+        ws_made[i][0] = (char) tolower( ws_made[i][0] );
+
+        know_items[TYP_STICK][i]  = FALSE;
+        guess_items[TYP_STICK][i] = 0;
+
+        if (i > 0)
+            ws_magic[i].mi_prob += ws_magic[i - 1].mi_prob;
+    }
+
+    badcheck("sticks", ws_magic, maxsticks);
+}
+
+void
+badcheck(char *name, struct magic_item *magic, int bound)
+{
+    struct magic_item  *end;
+
+    if (magic[bound - 1].mi_prob == 1000)
+        return;
+
+    printf("\nBad percentages for %s:\n", name);
+
+    for (end = &magic[bound]; magic < end; magic++)
+        printf("%3d%% %s\n", magic->mi_prob, magic->mi_name);
+
+    printf("[Hit RETURN to continue]");
+    fflush(stdout);
+
+    while ((readchar() & 0177) != '\n')
+        continue;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/io.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,471 @@
+/*
+    io.c - Various input/output functions
+  
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include "rogue.h"
+
+char prbuf[2 * LINELEN];    /* Buffer for sprintfs                      */
+static char mbuf[2*LINELEN];  /* Current message buffer        */
+static int newpos = 0;       /* index in mbuf to end of msg   */
+
+int mpos = 0;                 /* 0  = Overwrite existing message */
+                              /* >0 = print --More-- at this pos */
+                              /*      and wait for key           */
+
+int line_cnt = 0;
+int newpage  = FALSE;
+
+/*
+    msg()
+        Display a message at the top of the screen.
+*/
+
+void
+msg(const char *fmt, ...)
+{
+    va_list ap;
+
+    /* if the string is "", just clear the line */
+
+    if (*fmt == '\0')
+    {
+        wmove(cw, 0, 0);
+        wclrtoeol(cw);
+        mpos = 0;
+        return;
+    }
+
+    /* otherwise add to the message and flush it out */
+
+    va_start(ap, fmt);
+    doadd(fmt, ap);
+    va_end(ap);
+
+    endmsg();
+}
+
+void
+vmsg(const char *fmt, va_list ap)
+{
+    /* if the string is "", just clear the line */
+
+    if (*fmt == '\0')
+    {
+        wmove(cw, 0, 0);
+        wclrtoeol(cw);
+        mpos = 0;
+        return;
+    }
+
+    /* otherwise add to the message and flush it out */
+
+    doadd(fmt, ap);
+    endmsg();
+}
+
+
+/*
+    addmsg()
+        add things to the current message
+*/
+
+void
+addmsg(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    doadd(fmt,ap);
+    va_end(ap);
+}
+
+/*
+    endmsg()
+        Display a new msg (giving him a chance to see the previous one
+        if it is up there with the --More--)
+*/
+
+void
+endmsg(void)
+{
+    strcpy(msgbuf[msg_index], mbuf);
+
+    msg_index = ++msg_index % 10;
+
+    if (mpos)
+    {
+        wmove(cw, 0, mpos);
+        wprintw(cw, (char *) morestr);
+        wrefresh(cw);
+        wait_for(' ');
+    }
+
+    mvwprintw(cw, 0, 0, mbuf);
+    wclrtoeol(cw);
+
+    mpos = newpos;
+    newpos = 0;
+
+    wrefresh(cw);
+}
+
+void
+doadd(const char *fmt, va_list ap)
+{
+    vsprintf(&mbuf[newpos], fmt, ap);
+    newpos = (int) strlen(mbuf);
+}
+
+/*
+    status()
+        Display the important stats line.  Keep the cursor where it was.
+*/
+
+void
+status(int display)
+{
+    static char buf[1024];             /* Temporary buffer */
+    struct stats *stat_ptr, *max_ptr;
+    int oy, ox;
+
+    stat_ptr = &pstats;
+    max_ptr = &max_stats;
+
+    getyx(cw, oy, ox);
+    sprintf(buf,
+    "Int:%d(%d) Str:%d(%d) Wis:%d(%d) Dex:%d(%d) Con:%d(%d) Carry:%d(%d) %d",
+        stat_ptr->s_intel, max_ptr->s_intel,
+        stat_ptr->s_str, max_ptr->s_str,
+        stat_ptr->s_wisdom, max_ptr->s_wisdom,
+        stat_ptr->s_dext, max_ptr->s_dext,
+        stat_ptr->s_const, max_ptr->s_const,
+        stat_ptr->s_pack / 10, stat_ptr->s_carry / 10, foodlev );
+
+    mvwaddstr(cw, LINES - 2, 0, buf);
+    wclrtoeol(cw);
+
+    sprintf(buf, "Lvl:%d Au:%d Hpt:%3d(%3d) Pow:%d(%d) Ac:%d  Exp:%d+%ld  %s",
+        level,
+        purse,
+        stat_ptr->s_hpt, max_ptr->s_hpt,
+        stat_ptr->s_power, max_ptr->s_power,
+        (cur_armor != NULL ? (cur_armor->o_ac - 10 + stat_ptr->s_arm)
+         : stat_ptr->s_arm) - ring_value(R_PROTECT),
+        stat_ptr->s_lvl,
+        stat_ptr->s_exp,
+        cnames[player.t_ctype][min(stat_ptr->s_lvl - 1, 14)]);
+
+    mvwaddstr(cw, LINES - 1, 0, buf);
+
+    switch(hungry_state)
+    {
+        case F_OK:     break;
+        case F_HUNGRY: waddstr(cw, " Hungry");
+                       break;
+        case F_WEAK:   waddstr(cw, " Weak");
+                       break;
+        case F_FAINT:  waddstr(cw, " Fainting");
+                       break;
+    }
+
+    wclrtoeol(cw);
+    wmove(cw, oy, ox);
+
+    if (display)
+        wrefresh(cw);
+}
+
+/*
+ * readchar:
+ *	Flushes stdout so that screen is up to date and then returns
+ *	getchar().
+ */
+
+char
+readcharw(WINDOW *win)
+{
+    char ch;
+
+    ch = (char) md_readchar(win);
+
+    if ((ch == 3) || (ch == 0))
+    {
+	quit();
+	return(27);
+    }
+
+    return(ch);
+}
+
+char
+readchar()
+{
+    return( readcharw(cw) );
+}
+
+/*
+    wait_for()
+        Sit around until the guy types the right key
+*/
+
+void
+w_wait_for(WINDOW *w, int ch)
+{
+    char    c;
+
+    if (ch == '\n')
+        while ((c = readcharw(w)) != '\n' && c != '\r')
+            continue;
+    else
+        while (readcharw(w) != ch)
+            continue;
+}
+
+void
+wait_for(int ch)
+{
+    w_wait_for(cw, ch);
+}
+
+/*
+    show_win()
+        function used to display a window and wait before returning
+*/
+
+void
+show_win(WINDOW *scr, char *message)
+{
+    mvwaddstr(scr, 0, 0, message);
+    touchwin(scr);
+    wmove(scr, hero.y, hero.x);
+    wrefresh(scr);
+    wait_for(' ');
+    clearok(cw, TRUE);
+    touchwin(cw);
+}
+
+/*
+    restscr()
+        Restores the screen to the terminal
+*/
+
+void
+restscr(WINDOW *scr)
+{
+    clearok(scr, TRUE);
+    touchwin(scr);
+}
+
+/*
+    add_line()
+        Add a line to the list of discoveries
+*/
+
+void
+add_line(const char *fmt, ...)
+{
+    WINDOW  *tw;
+    va_list ap;
+
+    va_start(ap, fmt);
+
+    if (line_cnt == 0)
+    {
+        wclear(hw);
+
+        if (inv_type == INV_SLOW)
+            mpos = 0;
+    }
+
+    if (inv_type == INV_SLOW)
+    {
+        if ( (fmt != NULL) && (*fmt != '\0') )
+            vmsg(fmt, ap);
+        line_cnt++;
+    }
+    else
+    {
+        if ( (line_cnt >= LINES - 2) || (fmt == NULL)) /* end 'o page */
+        {
+            if (fmt == NULL && !newpage && inv_type == INV_OVER)
+            {
+                tw = newwin(line_cnt + 2, COLS, 0, 0);
+                overwrite(hw, tw);
+                wstandout(tw);
+                mvwaddstr(tw, line_cnt, 0, spacemsg);
+                wstandend(tw);
+                touchwin(tw);
+                wrefresh(tw); 
+                wait_for(' ');
+                delwin(tw);
+                touchwin(cw);
+            }
+            else
+            {
+                wstandout(hw);
+                mvwaddstr(hw, LINES - 1, 0, spacemsg);
+                wstandend(hw);
+                wrefresh(hw);
+                w_wait_for(hw, ' ');
+                touchwin(cw);
+                wclear(hw);
+            }
+            newpage = TRUE;
+            line_cnt = 0;
+        }
+
+        /* draw line */
+        if (fmt != NULL && !(line_cnt == 0 && *fmt == '\0'))
+        {
+            static char tmpbuf[1024];
+			
+            vsprintf(tmpbuf, fmt, ap);
+            mvwprintw(hw, line_cnt++, 0, tmpbuf);
+        }
+    }
+}
+
+/*
+    end_line()
+        End the list of lines
+*/
+
+void
+end_line(void)
+{
+    if (inv_type != INV_SLOW)
+        add_line(NULL);
+
+    line_cnt = 0;
+    newpage = FALSE;
+}
+
+/*
+    hearmsg()
+        Call msg() only if you are not deaf
+*/
+
+void
+hearmsg(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+
+    if (off(player, ISDEAF))
+        vmsg(fmt, ap);
+    else if (wizard)
+    {
+        msg("Couldn't hear: ");
+        vmsg(fmt, ap);
+    }
+
+    va_end(ap);
+}
+
+/*
+    seemsg()
+        Call msg() only if you are not blind
+*/
+
+void
+seemsg(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+
+    if (off(player, ISBLIND))
+        vmsg(fmt, ap);
+    else if (wizard)
+    {
+        msg("Couldn't see: ");
+        vmsg(fmt, ap);
+    }
+
+    va_end(ap);
+}
+
+int
+get_string(char *buffer, WINDOW *win)
+{
+    char    *sp, c;
+    int oy, ox;
+    char    buf[2 * LINELEN];
+
+    wrefresh(win);
+    getyx(win, oy, ox);
+
+    /* loop reading in the string, and put it in a temporary buffer */
+
+    for (sp = buf; (c = readcharw(win)) != '\n' &&
+         c != '\r' &&
+         c != '\033' &&
+         c != '\007' &&
+         sp < &buf[LINELEN - 1];
+         wclrtoeol(win), wrefresh(win))
+    {
+	if ((c == '\b') || (c == 0x7f))
+        {
+            if (sp > buf)
+            {
+                size_t i;
+
+                sp--;
+
+                for (i = strlen(unctrl(*sp)); i; i--)
+                    waddch(win, '\b');
+            }
+            continue;
+        }
+        else if (c == '\0')
+        {
+            sp = buf;
+            wmove(win, oy, ox);
+            continue;
+        }
+        else if (sp == buf && c == '-' && win == hw)
+            break;
+
+        *sp++ = c;
+        waddstr(win, unctrl(c));
+    }
+
+    *sp = '\0';
+
+    if (sp > buf)       /* only change option if something has been typed */
+        strncpy(buffer, buf, strlen(buf)+1);
+
+    wmove(win, oy, ox);
+    waddstr(win, buffer);
+    waddch(win, '\n');
+    wrefresh(win);
+
+    if (win == cw)
+        mpos += (int)(sp - buf);
+
+    if (c == '-')
+        return(MINUS);
+    else if (c == '\033' || c == '\007')
+        return(QUIT);
+    else
+        return(NORM);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/lint-curses.h	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,69 @@
+/*
+    lint-curses.h
+
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1993, 1995 Herb Chong
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+
+/* Sufficient info to pass lint */
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#define getyx(win,y,x)   y = win->_cury, x = win->_curx
+struct screen { int opque_data_type; };
+typedef struct { int _cury; int _curx; } WINDOW;
+extern WINDOW *stdscr;
+extern WINDOW *curscr;
+extern int LINES;
+extern int COLS;
+extern char *unctrl(char c);
+extern void initscr(void);
+extern int wmove(WINDOW *window, int Line, int Column);
+extern int move(int Line, int Column);
+extern int addch(char c);
+extern int mvaddch(int y, int x, char c);
+extern int waddch(WINDOW *window, char c);
+extern int mvwaddch(WINDOW *window, int y, int x, char c);
+extern int mvwinch(WINDOW *window, int y, int x);
+extern int winch(WINDOW *window);
+extern int mvinch(int y, int x);
+extern int getch(void);
+extern int wgetch(WINDOW *window);
+extern void clear(void);
+extern void wclear(WINDOW *window);
+extern void refresh(void);
+extern void wrefresh(WINDOW *window);
+extern void clearok(WINDOW *window, int flag);
+extern void endwin(void);
+extern void touchwin(WINDOW *window);
+extern void overlay(WINDOW *w1, WINDOW *w2);
+extern void wclrtoeol(WINDOW *window);
+extern void wprintw(WINDOW *window, const char *fmt, ...);
+extern void mvprintw(int line, int col, char *fmt, ...);
+extern void mvwprintw(WINDOW *window, int line, int col, char *fmt, ...);
+extern int  mvwaddstr(WINDOW *window, int y, int x, const char *str);
+extern int  mvaddstr(int y, int x, char *str);
+extern int  waddstr(WINDOW *window, char *str);
+extern int  addstr(char *str);
+extern void standout(void);
+extern void wstandout(WINDOW *window);
+extern void standend(void);
+extern void wstandend(WINDOW *window);
+extern void noecho(void);
+extern void cbreak(void);
+extern void crmode(void);
+extern void nonl(void);
+extern void nl(void);
+extern int wgetch(WINDOW *window);
+extern WINDOW *newwin(int lines, int cols, int y, int x);
+extern void overwrite(WINDOW *w1, WINDOW *w2);
+extern void delwin(WINDOW *window);
+extern void printw(char *fmt, ...);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/list.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,222 @@
+/*
+    list.c - Functions for dealing with linked lists of goodies
+  
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "rogue.h"
+
+static char errbuf[2 * LINELEN];
+
+/*
+    ur_alloc()
+    ur_free()
+
+    These are just calls to the system alloc and free, and they also adjust
+    the totals. The buffer is cleared out because idents need to be zero
+    before going into the pack, or they will be used as indices!
+*/
+
+void *
+ur_alloc(size_t size)
+{
+    char *buf_p;
+
+    total++;
+
+    buf_p = mem_malloc(size);
+
+    if (buf_p == NULL)
+        return(NULL);
+
+    memset(buf_p,0,size);
+
+    return(buf_p);
+}
+
+void
+ur_free(void *buf_p)
+{
+    mem_free(buf_p);
+    total--;
+}
+
+/*
+    detach()
+        Takes an item out of whatever linked list it might be in
+        .... function needs to be renamed....
+*/
+
+void
+_detach(struct linked_list **list, struct linked_list *item)
+{
+    if (*list == item)
+        *list = next(item);
+
+    if (prev(item) != NULL)
+        item->l_prev->l_next = next(item);
+
+    if (next(item) != NULL)
+        item->l_next->l_prev = prev(item);
+
+    item->l_next = NULL;
+    item->l_prev = NULL;
+}
+
+/*
+    _attach()
+        add an item to the head of a list
+        ... this needs to be renamed as well ...
+*/
+
+void
+_attach(struct linked_list  **list, struct linked_list  *item)
+{
+    if (*list != NULL)
+    {
+        item->l_next = *list;
+        (*list)->l_prev = item;
+        item->l_prev = NULL;
+    }
+    else
+    {
+        item->l_next = NULL;
+        item->l_prev = NULL;
+    }
+
+    *list = item;
+}
+
+/*
+    _attach_after()
+
+    Attaches the given item after the supplied one in the list. If the listed
+    item is NULL, the new item is attached at the head of the list.
+*/
+
+void
+_attach_after(linked_list **list_pp, linked_list *list_p, linked_list *new_p)
+{
+    if (list_p == NULL)
+    {
+        _attach(list_pp, new_p);    /* stuff it at the beginning */
+        return;
+    }
+
+    if (next(list_p) != NULL)  /* something after this one? */
+    {
+        new_p->l_next = next(list_p);
+        list_p->l_next->l_prev = new_p;
+    }
+    else
+        new_p->l_next = NULL;
+
+    list_p->l_next = new_p;
+    new_p->l_prev = list_p;
+}
+
+/*
+    _free_list()
+        Throw the whole blamed thing away
+*/
+
+void
+_free_list(linked_list **ptr)
+{
+    linked_list *item;
+
+    while(*ptr != NULL)
+    {
+        item = *ptr;
+        *ptr = next(item);
+        discard(item);
+    }
+}
+
+/*
+    discard()
+        free up an item
+*/
+
+void
+discard(struct linked_list *item)
+{
+    throw_away(item->data.obj);
+    ur_free(item);
+}
+
+/*
+    throw_away()
+        toss out something (like discard, but without the link_list)
+*/
+
+void
+throw_away(struct object *ptr)
+{
+    free_ident(ptr);
+    ur_free(ptr);
+}
+
+/*
+    new_item()
+        get a new item with a specified size
+*/
+
+struct linked_list *
+new_item(int size)
+{
+    struct linked_list  *item;
+
+    if ((item = new_list()) == NULL)
+        msg("Ran out of memory for header after %d items.", total);
+
+    if ((item->data.l_data = new_alloc(size)) == NULL)
+        msg("Ran out of memory for data after %d items.", total);
+
+    item->l_next = item->l_prev = NULL;
+
+    return(item);
+}
+
+void *
+new_alloc(size_t size)
+{
+    void *space = ur_alloc(size);
+
+    if (space == NULL)
+    {
+        sprintf(errbuf, "Rogue ran out of memory.");
+        fatal(errbuf);
+    }
+
+    return(space);
+}
+
+struct linked_list *
+new_list(void)
+{
+    union /* ugly_lint_hack */
+    {
+        struct linked_list *ll;
+        void              *vptr;
+    } newp;
+
+    newp.vptr = mem_malloc(sizeof(struct linked_list));
+    memset(newp.vptr,0,sizeof(struct linked_list));
+    return(newp.ll);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/magic.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,878 @@
+/*
+    magic.c - This file contains functions for casting magic spells
+   
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+         Cost for each level of spells level:
+*/
+
+static const int spell_cost[] = {1, 5, 17, 29, 53, 91, 159, 247, 396};
+
+static struct spells monst_spells[] =
+{
+    {5, S_SELFTELEP, SCR_MAGIC},
+    {4, P_HEALING, POT_MAGIC | _TWO_},
+    {3, P_REGENERATE, POT_MAGIC},
+    {2, P_HEALING, POT_MAGIC},
+    {4, P_HASTE, POT_MAGIC},
+    {2, P_SEEINVIS, POT_MAGIC},
+    {3, P_SHERO, POT_MAGIC},
+    {5, P_PHASE, POT_MAGIC},
+    {4, P_INVIS, POT_MAGIC},
+    {4, WS_CANCEL, ZAP_MAGIC},
+
+    /* In reverse order of damage ability */
+    {6, WS_ELECT, ZAP_MAGIC | _TWO_},
+    {6, WS_FIRE, ZAP_MAGIC | _TWO_},
+    {6, WS_COLD, ZAP_MAGIC | _TWO_},
+    {6, WS_MISSILE, ZAP_MAGIC | _TWO_},
+    {5, WS_ELECT, ZAP_MAGIC},
+    {5, WS_FIRE, ZAP_MAGIC},
+    {5, WS_COLD, ZAP_MAGIC},
+    {4, WS_ELECT, ZAP_MAGIC | ISCURSED},
+    {4, WS_FIRE, ZAP_MAGIC | ISCURSED},
+    {4, WS_COLD, ZAP_MAGIC | ISCURSED},
+    {3, WS_MISSILE, ZAP_MAGIC},
+    {1, WS_MISSILE, ZAP_MAGIC | ISCURSED},
+
+    {-1, -1, 0}
+};
+
+/*
+    Spells that a player can cast Non-mus only know ISKNOW spells until found
+    in the dungeon. Special classes know their spells one level lower, and
+    blessed one above.
+*/
+
+static struct spells player_spells[] =
+{
+    {1, WS_KNOCK, ZAP_MAGIC | ISKNOW},
+    {1, S_SUMFAMILIAR, SCR_MAGIC | SP_DRUID | SP_MAGIC | SP_CLERIC, SP_ILLUSION },
+    {1, S_GFIND, SCR_MAGIC | ISKNOW},
+    {1, P_MONSTDET, POT_MAGIC | ISKNOW | SP_DRUID},
+    {1, P_TREASDET, POT_MAGIC | ISKNOW | SP_MAGIC},
+    {1, S_FOODDET, SCR_MAGIC | ISKNOW | SP_CLERIC},
+    {1, S_LIGHT, SCR_MAGIC | ISKNOW | SP_ILLUSION},
+
+    {2, WS_CLOSE, ZAP_MAGIC | ISKNOW},
+    {2, S_IDENTIFY, SCR_MAGIC | ISKNOW},
+    {2, WS_HIT, ZAP_MAGIC | ISKNOW | SP_PRAYER},
+    {2, P_SHIELD, POT_MAGIC | ISKNOW | SP_MAGIC},
+    {2, P_COLDRESIST, POT_MAGIC | SP_WIZARD},
+    {2, P_SEEINVIS, POT_MAGIC | SP_ILLUSION},
+    {2, S_CONFUSE, SCR_MAGIC | SP_CLERIC},
+    {2, P_SMELL, POT_MAGIC | SP_DRUID},
+    {2, WS_MISSILE, ZAP_MAGIC | SP_MAGIC},
+    {2, P_HEAR, POT_MAGIC},
+
+    {3, P_CLEAR, POT_MAGIC | ISKNOW},
+    {3, P_HEALING, POT_MAGIC | ISKNOW | SP_PRAYER},
+    {3, S_CURING, SCR_MAGIC | ISKNOW | SP_PRAYER},
+    {3, WS_MONSTELEP, ZAP_MAGIC | SP_MAGIC},
+    {3, WS_CANCEL, ZAP_MAGIC | SP_WIZARD},
+    {3, S_SELFTELEP, SCR_MAGIC | SP_WIZARD},
+    {3, P_FIRERESIST, POT_MAGIC | SP_WIZARD | SP_DRUID},
+    {3, S_MAP, SCR_MAGIC | SP_ILLUSION | SP_DRUID},
+    {3, S_REMOVECURSE, SCR_MAGIC | SP_PRAYER},
+    {3, S_HOLD, SCR_MAGIC | SP_CLERIC},
+    {3, S_SLEEP, SCR_MAGIC | SP_DRUID},
+    {3, P_HASOXYGEN, POT_MAGIC | SP_DRUID},
+    {3, WS_XENOHEALING, ZAP_MAGIC | SP_DRUID},
+    {3, P_RESTORE, POT_MAGIC},
+
+    {4, S_MSHIELD, SCR_MAGIC | ISKNOW | SP_ILLUSION},
+    {4, P_INVIS, POT_MAGIC | SP_ILLUSION},
+    {4, S_REFLECT, SCR_MAGIC | SP_ILLUSION},
+    {4, P_TRUESEE, POT_MAGIC | SP_ILLUSION},
+    {4, P_REGENERATE, POT_MAGIC | SP_CLERIC},
+    {4, WS_DRAIN, ZAP_MAGIC | SP_CLERIC},
+    {4, P_HASTE, POT_MAGIC | SP_ILLUSION | SP_CLERIC},
+    {4, P_LEVITATION, POT_MAGIC | SP_WIZARD | SP_DRUID},
+    {4, WS_WEB, ZAP_MAGIC | SP_MAGIC},
+    {4, P_PHASE, POT_MAGIC},
+
+    {5, P_SHERO, POT_MAGIC | ISKNOW},
+    {5, S_PETRIFY, SCR_MAGIC | SP_MAGIC},
+    {5, S_SCARE, SCR_MAGIC | _TWO_ | SP_PRAYER},
+    {5, WS_COLD, ZAP_MAGIC | SP_DRUID},
+    {5, WS_FIRE, ZAP_MAGIC | SP_CLERIC},
+    {5, WS_ELECT, ZAP_MAGIC | SP_WIZARD},
+    {5, WS_ANTIMATTER, ZAP_MAGIC | SP_ILLUSION},
+    {5, S_ELECTRIFY, SCR_MAGIC | SP_ILLUSION},
+
+    {6, WS_DISINTEGRATE, ZAP_MAGIC | ISKNOW},
+    {6, S_OWNERSHIP, SCR_MAGIC | SP_ALL},
+
+    {7, S_ENCHANT, SCR_MAGIC | SP_MAGIC},
+
+    {-1, -1, 0}
+};
+
+/*
+    incant()
+       Cast a spell
+*/
+
+void
+incant(struct thing *caster, coord dir)
+{
+    int i;
+    struct stats    *curp;
+    struct stats    *maxp;
+    int is_player = (caster == &player);
+    int points_casters;
+    char    *casters_name = (on(player, ISBLIND)) ? "it" :
+            monsters[caster->t_index].m_name;
+    struct spells   *sp;
+    char *cast_name;                      /* = spell_name(sp)           */
+    char *spell_type;                     /* spell or prayer            */
+    int   casting_cost;                   /* from spell_cost[]          */
+    int   spell_roll;                     /* sucess/fail 1D100 die roll */
+    int   fumble_chance;                  /* Spell fumble chance        */
+    int   num_fumbles = 0;                /* for fumble_spell()         */
+    int   bless_or_curse = ISNORMAL;      /* blessed or cursed?         */
+    int   message_flags = CAST_NORMAL;    /* which message to print out */
+    int   class_casters;                  /* For determining ISKNOW     */
+    int   stat_casters;                   /* s_intel or s_wisdom        */
+    int   level_casters;                  /* spellcasting level         */
+    char  buf[2 * LINELEN];
+    struct spells sorted_spells[MAX_SPELLS];
+    char  spellbuf[2 * LINELEN];
+    char  spellbuf2[2 * LINELEN];
+
+    curp = &(caster->t_stats);
+    maxp = &(caster->maxstats);
+    points_casters = curp->s_power;
+
+    if (points_casters <= 0)
+    {
+        if (is_player)
+            msg("You don't have any spell points.");
+
+        return;
+    }
+
+    /*
+     * Paladins, Rangers, ringwearers, and monsters cast at 4 levels
+     * below. Other non-specialists at 8 below
+    */
+
+    level_casters = curp->s_lvl;
+
+    switch (caster->t_ctype)
+    {
+        case C_PALADIN:
+            level_casters -= 4;
+            /* fallthrough */
+        case C_CLERIC:
+            class_casters = SP_CLERIC;
+            stat_casters = curp->s_wisdom;
+            break;
+        case C_RANGER:
+            level_casters -= 4;
+            /* fallthrough */
+        case C_DRUID:
+            class_casters = SP_DRUID;
+            stat_casters = curp->s_wisdom;
+            break;
+        case C_MAGICIAN:
+            class_casters = SP_WIZARD;
+            stat_casters = curp->s_intel;
+            break;
+        case C_ILLUSION:
+            class_casters = SP_ILLUSION;
+            stat_casters = curp->s_intel;
+            break;
+        case C_MONSTER:
+            if (off(*caster, ISUNIQUE))
+                level_casters -= 4;
+            class_casters = 0x0;
+            stat_casters = curp->s_intel;
+            break;
+
+        default:
+            if (is_wearing(R_WIZARD))
+            {
+                level_casters -= 4;
+                class_casters = (rnd(4) ? SP_WIZARD : SP_ILLUSION);
+                stat_casters = curp->s_intel;
+            }
+            else if (is_wearing(R_PIETY))
+            {
+                level_casters -= 4;
+                class_casters = (rnd(4) ? SP_CLERIC : SP_DRUID);
+                stat_casters = curp->s_wisdom;
+            }
+            else
+            {
+                level_casters -= 8;
+                class_casters = 0x0;
+                stat_casters = (rnd(2) ? curp->s_wisdom : curp->s_intel);
+            }
+    }
+
+    /* Bug - What about when WIS == INT? */
+
+    spell_type = (stat_casters == curp->s_intel) ? "spell" : "prayer";
+
+    if (!is_player && (sp = pick_monster_spell(caster)) == NULL)
+            return;
+    else if (is_player)
+    {
+        int num_spells = -1;    /* num of spells cheap enough */
+
+        sorted_spells[0].sp_cost = -1;
+
+        for (sp = player_spells; sp->sp_level != -1; sp++)
+        {
+            if (sp->sp_flags & class_casters)  /* Does class know spell? */
+            {
+                int rnd_number = rnd(2 * sp->sp_level) - sp->sp_level;
+
+                /* Knows normal spell one level below others */
+
+                casting_cost = spell_cost[sp->sp_level - 1] + rnd_number;
+
+                if (points_casters >= casting_cost)
+                {
+                    sorted_spells[++num_spells] = *sp;
+                    sorted_spells[num_spells].sp_cost = casting_cost;
+                    sorted_spells[num_spells].sp_level = sp->sp_level - 1;
+                }
+
+                /* Knows blessed spell one level above others */
+
+                casting_cost = spell_cost[sp->sp_level + 1] + rnd_number;
+
+                if (points_casters >= casting_cost)
+                {
+                    sorted_spells[++num_spells] = *sp;
+                    sorted_spells[num_spells].sp_level = sp->sp_level + 1;
+                    sorted_spells[num_spells].sp_cost = casting_cost;
+                    sorted_spells[num_spells].sp_flags |= ISBLESSED;
+                }
+            } /* If class doesn't know spell, see if its a ISKNOW */
+            else if (sp->sp_flags & ISKNOW)
+            {
+                int rnd_number = rnd(4 * sp->sp_level) - sp->sp_level;
+
+                casting_cost = spell_cost[sp->sp_level] + rnd_number;
+
+                if (points_casters >= casting_cost)
+                {
+                    sorted_spells[++num_spells] = *sp;
+                    sorted_spells[num_spells].sp_cost = casting_cost;
+                }
+            }
+            /* else this spell is unknown */
+        }
+
+        if (sorted_spells[0].sp_cost == -1)
+        {
+            msg("You don't have enough %s points.", spell_type);
+            after = FALSE;
+            return;
+        }
+
+        qsort(sorted_spells,num_spells + 1,sizeof(struct spells),sort_spells);
+
+        do         /* Prompt for spells */
+        {
+            struct spells   *which_spell = NULL;
+
+            buf[0] = '\0';
+            msg("");/* Get rid of --More-- */
+            msg("Which %s are you casting [%d points left] (* for list)? ",
+                spell_type, points_casters);
+
+            switch(get_string(buf, cw))
+            {
+                case NORM:  break;
+                case QUIT:  return; /* ESC - lose turn */
+                default:    continue;
+            }
+
+            if (buf[0] == '*')    /* print list */
+            {
+                add_line("Cost  Abbreviation    Full Name");
+
+                for (i = 0; i <= num_spells; i++)
+                {
+                    sp = &sorted_spells[i];
+                    sprintf(buf, "[%3d] %-12s\t%s",
+                        sp->sp_cost, spell_abrev(sp,spellbuf2),
+                        spell_name(sp,spellbuf));
+                    add_line(buf);
+                }
+                end_line();
+                sp = NULL;
+                continue;
+            }
+
+            if (isupper(buf[0])) /* Uppercase Abbreviation */
+            {
+                for (i = 0; i <= num_spells; i++)
+                {
+                    sp = &sorted_spells[i];
+
+                    if ((strcmp(spell_abrev(sp,spellbuf2), buf) == 0))
+                    {
+                        which_spell = sp;
+                        break;
+                    }
+                }
+            }
+            else /* Full Spell Name */
+            {
+                for (i = 0; i <= num_spells; i++)
+                {
+                    sp = &sorted_spells[i];
+
+                    if ((strcmp(spell_name(sp,spellbuf), buf) == 0))
+                    {
+                        which_spell = sp;
+                        break;
+                    }
+                }
+            }
+
+            sp = which_spell;
+        }
+        while (sp == NULL);
+    }
+
+    /* Common monster and player code */
+
+    cast_name = spell_name(sp,spellbuf);
+
+    fumble_chance = (10 * sp->sp_level / 4 - 10 * level_casters / 13) * 5;
+
+    if (cur_weapon != NULL && wield_ok(caster, cur_weapon, FALSE) == FALSE)
+    {
+        switch (caster->t_ctype)
+        {
+            case C_MAGICIAN:
+            case C_ILLUSION:
+                msg("You should have both hands free.");
+                fumble_chance += rnd(level_casters) * 5;
+                break;
+
+            case C_CLERIC:
+            case C_DRUID:
+            case C_PALADIN:
+                msg("Your god looks askance at the weapon you wield.");
+                fumble_chance += rnd(level_casters) * 5;
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    if (fumble_chance >= MAX_FUMBLE_CHANCE)
+        fumble_chance = MAX_FUMBLE_CHANCE;
+    else if (fumble_chance <= MIN_FUMBLE_CHANCE + sp->sp_level)
+        fumble_chance = MIN_FUMBLE_CHANCE + sp->sp_level;
+
+    if (fumble_chance > (30 + rnd(50)))
+    {
+        if (is_player)
+        {
+            int  answer;
+
+            msg("Are you sure you want to try for that hard a %s? [n]",
+                spell_type);
+
+            answer = readchar();
+
+            if (tolower(answer) != 'y')
+            {
+                after = FALSE;
+                return;
+            }
+            else
+                msg("Here goes...");
+        }
+        else  /* Only if the monster is desperate */
+        {
+            if (curp->s_hpt > maxp->s_hpt / 2)
+                return;
+        }
+    }
+    
+	/* casting costs food energy */
+	
+	food_left -= sp->sp_cost;
+	
+    spell_roll = rnd(100);
+
+    debug("%s(%d) cast '%s' fumble %%%d (rolled %d) ",
+          monsters[caster->t_index].m_name, curp->s_power, cast_name,
+          fumble_chance, spell_roll);
+
+    caster->t_rest_hpt = caster->t_rest_pow = 0;
+
+    if (!is_player)    /* Stop running. */
+    {
+        running = FALSE;
+        msg("The %s is casting '%s'.", casters_name, cast_name);
+    }
+
+    /* The Crown of Might insures that your spells never fumble */
+
+    if (spell_roll < fumble_chance)
+    {
+        if (is_carrying(TR_CROWN))
+            message_flags |= CAST_CROWN;
+        else
+        {
+            message_flags |= CAST_CURSED;
+
+            curp->s_power -= min(curp->s_power,
+                (2 * sp->sp_cost)); /* 2x cost */
+            num_fumbles = rnd(((fumble_chance - spell_roll) / 10)
+                 + 1) + rnd(sp->sp_level) + rnd(curp->s_lvl);
+            num_fumbles = min(10, max(0, num_fumbles));
+
+            if (num_fumbles >= 6 && rnd(1) == 0)
+                bless_or_curse = ISCURSED;
+            else if (num_fumbles < 4)
+            {
+                if (is_player)
+                    msg("Your %s fails.", spell_type);
+                return;
+            }
+        }
+    }
+    else if (spell_roll > MAX_FUMBLE_CHANCE)
+    {
+        if (is_player)
+        {
+            message_flags |= CAST_BLESSED;
+            pstats.s_exp += 3 * sp->sp_cost * curp->s_lvl;
+            check_level();
+        }
+
+        maxp->s_power += sp->sp_cost;
+        bless_or_curse = ISBLESSED;
+    }
+    else
+    {
+        if (is_player) /* extra exp for sucessful spells */
+        {
+            if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_ILLUSION)
+            {
+                pstats.s_exp += sp->sp_cost * curp->s_lvl;
+                check_level();
+            }
+        }
+
+        bless_or_curse = sp->sp_flags & ISBLESSED;
+        curp->s_power -= sp->sp_cost;
+    }
+
+    /* The Sceptre of Might blesses all your spells */
+
+    if (is_player && ((bless_or_curse & ISBLESSED) == 0) &&
+        is_carrying(TR_SCEPTRE))
+    {
+        message_flags |= CAST_SEPTRE;
+        bless_or_curse = ISBLESSED;
+    }
+
+    if (sp->sp_flags & POT_MAGIC)
+        quaff(caster, sp->sp_which, bless_or_curse);
+    else if (sp->sp_flags & SCR_MAGIC)
+            read_scroll(caster, sp->sp_which, bless_or_curse);
+    else if (sp->sp_flags & ZAP_MAGIC)
+    {
+        if (is_player)
+        {
+            do     /* Must pick a direction */
+            {
+                msg("Which direction?");
+            }
+            while (get_dir() == FALSE);
+        }
+        else
+        {
+            delta.x = dir.x;
+            delta.y = dir.y;
+        }
+        do_zap(caster, sp->sp_which, bless_or_curse);
+    }
+    else
+        msg("What a strange %s!", spell_type);
+
+    /*
+     * Print messages and take fumbles *after* spell has gone off. This
+     * makes ENCHANT, etc more dangerous
+    */
+
+    if (is_player)
+    {
+        if (message_flags & CAST_SEPTRE)
+            msg("The Sceptre enhanced your %s.", spell_type);
+        if (message_flags & CAST_CROWN)
+            msg("The Crown wordlessly corrected your %s.",
+                spell_type);
+
+        switch (message_flags & 0x1)
+        {
+            case CAST_CURSED:
+                msg("You botched your '%s' %s.", cast_name,
+                    spell_type);
+                fumble_spell(caster, num_fumbles);
+                break;
+            case CAST_NORMAL:
+                msg("You sucessfully cast your '%s' %s.",
+                    cast_name, spell_type);
+                break;
+
+            case CAST_BLESSED:
+                msg("Your '%s' %s went superbly.", cast_name,
+                    spell_type);
+                break;
+        }
+    }
+}
+
+/*
+    spell_name()
+        returns pointer to spell name
+*/
+
+char *
+spell_name(struct spells *sp, char *buf)
+{
+    if (buf == NULL)
+        return("UltraRogue Bug #105");
+
+    if (sp->sp_flags & POT_MAGIC)
+        strcpy(buf, p_magic[sp->sp_which].mi_name);
+    else if (sp->sp_flags & SCR_MAGIC)
+        strcpy(buf, s_magic[sp->sp_which].mi_name);
+    else if (sp->sp_flags & ZAP_MAGIC)
+        strcpy(buf, ws_magic[sp->sp_which].mi_name);
+    else
+        strcpy(buf, "unknown spell type");
+
+    if (sp->sp_flags & ISBLESSED)
+        strcat(buf, " 2");
+
+    return(buf);
+}
+
+/*
+    spell_abrev()
+        returns pointer to capital letter spell abbreviation
+*/
+
+char *
+spell_abrev(struct spells *sp, char *buf)
+{
+    if (buf == NULL)
+         return("UltraRogue Bug #106");
+
+    if (sp->sp_flags & POT_MAGIC)
+        strcpy(buf, p_magic[sp->sp_which].mi_abrev);
+    else if (sp->sp_flags & SCR_MAGIC)
+        strcpy(buf, s_magic[sp->sp_which].mi_abrev);
+    else if (sp->sp_flags & ZAP_MAGIC)
+        strcpy(buf, ws_magic[sp->sp_which].mi_abrev);
+    else
+        strcpy(buf, "?????");
+
+    if (sp->sp_flags & ISBLESSED)
+        strcat(buf, " 2");
+
+    return(buf);
+}
+
+/*
+    fumble_spell()
+        he blew it.  Make him pay
+*/
+
+void
+fumble_spell(struct thing *caster, int num_fumbles)
+{
+    struct stats    *curp = &(caster->t_stats);
+    struct stats    *maxp = &(caster->maxstats);
+    int    is_player = (caster == &player);
+
+    debug("Taking %d fumbles.", num_fumbles);
+
+    switch (num_fumbles)
+    {
+        case 10: /* Lose ability */
+            if (rnd(5) == 0)
+                quaff(caster, P_GAINABIL, ISCURSED);
+            break;
+
+        case 9: /* Lose max spell points */
+
+            if (rnd(4) == 0)
+            {
+                maxp->s_power -= rnd(10);
+
+                if (maxp->s_power <= 5)
+                    maxp->s_power = 5;
+            }
+            break;
+
+        case 8: /* Lose all current spell points */
+
+            if (rnd(3) == 0)
+                curp->s_power = 0;
+            else
+                curp->s_power /= 2;
+            break;
+
+        case 7: /* Freeze */
+
+            if (rnd(2) == 0)
+            {
+                if (is_player)
+                    no_command++;
+                else
+                    caster->t_no_move++;
+            }
+            break;
+
+        case 6: /* Cast a cursed spell - see below */
+            break;
+
+        case 5: /* Become dazed and confused */
+
+            if (rnd(5) == 0)
+                quaff(caster, P_CLEAR, ISCURSED);
+            break;
+
+        case 4: /* Lose hit points */
+
+            if (is_player)
+                feel_message();
+            if ((curp->s_hpt -= rnd(10)) <= 0)
+            {
+                if (is_player)
+                    death(D_SPELLFUMBLE);
+                else
+                    killed(caster, find_mons(caster->t_pos.y, caster->t_pos.x),
+                       NOMESSAGE, NOPOINTS);
+                return;
+            }
+            break;
+
+        case 3: /* Spell fails */
+            break;
+
+        case 2: /* Freeze */
+
+            if (is_player)
+                no_command++;
+            else
+                caster->t_no_move++;
+
+            break;
+
+        default:
+        case 1: /* Take double spell points - handled in incant() */
+            break;
+    }
+}
+
+/*
+    learn_new_spells()
+        go through player_spells and ISKNOW identified potions,
+        scrolls, and sticks
+*/
+
+void
+learn_new_spells(void)
+{
+    struct spells   *sp;
+    int kludge = 0;
+    char spellbuf[2*LINELEN];
+
+    for (sp = player_spells; sp->sp_level != -1; sp++)
+    {
+        if (sp->sp_flags & POT_MAGIC)
+            kludge = TYP_POTION;
+        else if (sp->sp_flags & SCR_MAGIC)
+            kludge = TYP_SCROLL;
+        else if (sp->sp_flags & ZAP_MAGIC)
+            kludge = TYP_STICK;
+
+        if (know_items[kludge][sp->sp_which])
+        {
+            if ((sp->sp_flags & ISKNOW) == FALSE)
+                debug("Learned new spell '%s'", spell_name(sp,spellbuf));
+            sp->sp_flags |= ISKNOW;
+        }
+    }
+}
+
+/*
+    pick_monster_spell()
+        decide which spell from monst_spells will be cast
+        returns pointer to spell in monst_spells
+*/
+
+struct spells *
+pick_monster_spell(struct thing *caster)
+{
+    struct spells   *sp = NULL;
+    struct stats    *curp = &(caster->t_stats);
+    int points_casters = curp->s_power;
+
+    /* Discover castable spells */
+
+    for (sp = monst_spells; sp->sp_level != -1; sp++)
+    {
+        int rnd_number = rnd(2 * sp->sp_level) - sp->sp_level;
+        int casting_cost = spell_cost[sp->sp_level] + rnd_number;
+
+        if (points_casters >= casting_cost)
+            sp->sp_flags |= ISKNOW;
+    }
+
+    /* Decide which spell to cast */
+
+    if (curp->s_hpt < rnd(caster->maxstats.s_hpt))  /* think defense */
+    {
+        int i;
+        static const int run_or_heal[NUM_RUN] =
+            { M_SELFTELEP, M_HLNG2, M_HLNG, M_REGENERATE };
+
+        for (i = 0; i < NUM_RUN; i++)
+        {
+            sp = &monst_spells[run_or_heal[i]];
+
+            if ((sp->sp_flags & ISKNOW) && rnd(1))
+                return(sp);
+        }
+    }
+
+    if (on(*caster, ISSLOW))   /* cancel a slow */
+    {
+        sp = &monst_spells[M_HASTE];
+
+        if (sp->sp_flags & ISKNOW)
+            return (sp);
+    }
+
+    if (on(*caster, ISFLEE))   /* stop running away */
+    {
+        sp = &monst_spells[M_SHERO];
+
+        if (sp->sp_flags & ISKNOW)
+            return (sp);
+    }
+
+    if (on(player, ISINVIS) || on(player, ISDISGUISE))
+    {
+        if (off(*caster, CANSEE))  /* look for him */
+        {
+            sp = &monst_spells[M_SEEINVIS];
+
+            if (sp->sp_flags & ISKNOW)
+                return (sp);
+        }
+        else if (off(*caster, ISINVIS))    /* go invisible */
+        {
+            sp = &monst_spells[M_INVIS];
+
+            if (sp->sp_flags & ISKNOW)
+                return (sp);
+        }
+    }
+
+    if (on(player, CANINWALL) && (off(*caster, CANINWALL)) &&
+       (rnd(5) == 0))
+    {
+        sp = &monst_spells[M_PHASE];
+
+        if (sp->sp_flags & ISKNOW)
+            return (sp);
+    }
+
+    if (rnd(5) == 0 && has_defensive_spell(player))
+    {
+        sp = &monst_spells[M_CANCEL];
+
+        if (sp->sp_flags & ISKNOW)
+            return (sp);
+    }
+
+    /* Cast an offensive spell */
+
+    for (sp = &monst_spells[M_OFFENSE]; sp->sp_level != 1; sp++)
+    {
+        if ((rnd(3) == 0) && (sp->sp_flags & ISKNOW))
+            return (sp);
+
+        if ((rnd(3) == 0) && (sp->sp_flags & ISKNOW))
+        {
+            if (sp->sp_which != WS_MISSILE &&
+                DISTANCE(caster->t_pos, hero) > BOLT_LENGTH)
+                continue;
+            else
+                return(sp);
+        }
+    }
+
+    return(NULL);
+}
+
+/*
+    sort_spells()
+       called by qsort()
+*/
+
+int
+sort_spells(const void *a, const void *b)
+{
+    struct spells *sp1, *sp2;
+    int diff;
+    char  spellbuf[2 * LINELEN];
+    char  spellbuf2[2 * LINELEN];
+
+    union /* hack to prevent 'lint' from complaining */
+    {
+        struct spells *s;
+        const void          *vptr;
+    } s1,s2;
+
+    s1.vptr = a;
+    s2.vptr = b;
+
+    sp1 = s1.s;
+    sp2 = s2.s;
+
+    diff = sp1->sp_cost - sp2->sp_cost;
+
+    if (diff != 0)
+        return(diff);
+    else
+        return(strcmp(spell_name(sp1,spellbuf), spell_name(sp1,spellbuf2)));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/main.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,278 @@
+/*
+    main.c  -  setup code
+ 
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#define _ALL_SOURCE
+
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <stdlib.h>
+#include "rogue.h"
+
+FILE *fd_score = NULL;
+
+/* Command line options */
+
+int prscore;        /* Print scores */
+int prversion;      /* Print version info */
+
+int
+main(int argc, char *argv[])
+{
+    int x;
+    char    *env;
+    time_t lowtime;
+    time_t    now;
+    int rflag = 0;
+    char *nm;
+	float scale;
+
+    for (x = 1; x < argc; x++)
+    {
+        if (argv[x][0] != '-')
+            break;
+
+        switch (argv[x][1])
+        {
+            case 's':
+                prscore = TRUE;
+                break;
+
+            case 'v':
+                prversion = TRUE;
+                break;
+
+            case 'r':
+                rflag = TRUE;
+                break;
+
+            default:
+                fprintf(stderr,"%s: Unknown option '%c'.\n",argv[0],argv[x][1]);
+                exit(1);
+        }
+    }
+
+    if (!rflag)
+    {
+        argc -= (x - 1);
+        argv += (x - 1);
+    }
+
+    /* Get default score file */
+
+    strcpy(score_file, "urogue.scr");
+
+    fd_score = fopen(score_file, "r+");
+
+    if (fd_score == NULL)
+        fd_score = fopen(score_file, "a+");
+
+    if ((env = getenv("OPTIONS")) != NULL)
+        parse_opts(env);
+
+    nm = getenv("USER");
+
+    if (nm != NULL)
+        strcpy(whoami,nm);
+    else
+        strcpy(whoami,"anonymous");
+		
+	lowtime = time(&now);
+	
+	dnum = (wizard && getenv("SEED") != NULL ? atoi( getenv("SEED")) : (int)lowtime);
+	
+	ur_srandom(dnum);
+
+    if (env == NULL || fruit[0] == '\0')
+    {
+        static const char *funfruit[] =
+        {
+            "candleberry", "caprifig", "dewberry", "elderberry",
+            "gooseberry", "guanabana", "hagberry", "ilama", "imbu",
+            "jaboticaba", "jujube", "litchi", "mombin", "pitanga",
+            "prickly pear", "rambutan", "sapodilla", "soursop",
+            "sweetsop", "whortleberry"
+        };
+
+        strcpy(fruit, funfruit[rnd(sizeof(funfruit) / sizeof(funfruit[0]))]);
+    }
+
+    /* put a copy of fruit in the right place */
+
+    fd_data[1].mi_name = md_strdup(fruit); 
+
+    /* print scores */
+
+    if (prscore)
+    {
+        waswizard = TRUE;
+        score(0L, 0, SCOREIT, 0);
+        exit(0);
+    }
+
+    /* check for version option */
+
+    if (prversion)
+    {
+        printf("UltraRogue Version %s.\n", release);
+        exit(0);
+    }
+
+    if (wizard)
+        printf("Hello %s, welcome to dungeon #%d", whoami, dnum);
+    else
+        printf("Hello %s, just a moment while I dig the dungeon...", whoami);
+
+    mem_debug(2);
+	mem_tracking(1);
+
+    fflush(stdout);
+
+    init_things();      /* Set up probabilities of things */
+    init_fd();          /* Set up food probabilities */
+    init_colors();      /* Set up colors of potions */
+    init_stones();      /* Set up stone settings of rings */
+    init_materials();   /* Set up materials of wands */
+    initscr();          /* Start up cursor package */
+    refresh();
+    init_names();       /* Set up names of scrolls */
+    cbreak();
+    crmode();           /* Cbreak mode */
+    noecho();           /* Echo off */
+    nonl();
+	
+    scale = (float) (LINES * COLS) / (80.0F * 25.0F); /* get food right for     */
+	                                              /* different screen sizes */
+												  
+    food_left = (int) (food_left * scale);
+
+    /* Set up windows */
+
+    cw = newwin(LINES, COLS, 0, 0);
+    mw = newwin(LINES, COLS, 0, 0);
+    hw = newwin(LINES, COLS, 0, 0);
+
+    if (argc == 2 && argv[1][0] != '\0' && !restore(argv[1]))
+        /* Note: restore returns on error only */
+        exit(1);
+
+    waswizard = wizard; /* set wizard flags */
+
+    init_player();      /* look up things and outfit pack */
+
+    resurrect = pstats.s_const;
+    init_exp();         /* set first experience level change */
+    init_flags();       /* set initial flags */
+    wclear(hw);
+    wrefresh(hw);
+    new_level(POSTLEV,0); /* Draw current level */
+
+    /* Start up daemons and fuses */
+
+    start_daemon(DAEMON_DOCTOR, &player, AFTER);
+
+    light_fuse(FUSE_SWANDER, 0, WANDERTIME, AFTER);
+
+    start_daemon(DAEMON_STOMACH, 0, AFTER);
+    start_daemon(DAEMON_RUNNERS, 0, AFTER);
+
+    char_type = player.t_ctype;
+    player.t_oldpos = hero;
+    oldrp = roomin(hero);
+    after = TRUE;
+
+    signal(SIGINT, quit_handler);
+
+    while(playing)
+    {
+        do_daemons(BEFORE);
+        do_fuses(BEFORE);
+
+        command();  /* Command execution */
+
+        if (after)
+            do_after_effects();
+    }
+
+    fatal("");
+
+    return(0);
+}
+
+/*
+    fatal()
+        Exit the program, printing a message.
+*/
+
+void
+fatal(char *s)
+{
+    clear();
+    move(LINES - 2, 0);
+    printw("%s", s);
+    wrefresh(stdscr);
+    endwin();
+    printf("\n");       /* So the cursor doesn't stop at the end of the line */
+    exit(100);
+}
+
+/*
+    rnd()
+        Pick a very random number.
+*/
+
+unsigned char
+ucrnd(unsigned char range)
+{
+    return (unsigned char)(range <= 0 ? 0 : (ur_random() & 0x7fffffffL) % range);
+}
+
+short
+srnd(short range)
+{
+    return (short)(range <= 0 ? 0 : (ur_random() & 0x7fffffffL) % range);
+}
+
+int
+rnd(int range)
+{
+    return (range <= 0 ? 0 : (ur_random() & 0x7fffffffL) % range);
+}
+
+unsigned long
+ulrnd(unsigned long range)
+{
+    return(range <= 0 ? 0 : (ur_random() & 0x7fffffffL) % range);
+}
+
+/*
+    roll()
+        roll a number of dice
+*/
+
+int
+roll(int number, int sides)
+{
+    int dtotal = 0;
+
+    while (number--)
+        dtotal += rnd(sides) + 1;
+
+    return(dtotal);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/maze.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,333 @@
+/*
+    maze.c  -  functions for dealing with armor
+    
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <stdlib.h>
+#include "rogue.h"
+
+static char *frontier;
+static char *bits;
+static int urlines;
+static int urcols;
+
+/*
+    domaze()
+        Draw the maze on this level.
+*/
+
+void
+do_maze(void)
+{
+    int     i, least;
+    struct room *rp;
+    struct linked_list  *item;
+    struct object   *obj;
+    struct thing    *mp;
+    int    treas;
+    coord  tp;
+
+    for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
+    {
+        rp->r_nexits = 0;       /* no exits         */
+        rp->r_flags = ISGONE;   /* kill all rooms   */
+        rp->r_fires = 0;        /* no fires         */
+    }
+
+    rp = &rooms[0];         /* point to only room */
+    rp->r_flags = ISDARK;   /* mazes always dark */
+    rp->r_pos.x = 0;        /* room fills whole screen */
+    rp->r_pos.y = 1;
+    rp->r_max.x = COLS - 1;
+    rp->r_max.y = LINES - 3;
+    draw_maze();            /* put maze into window */
+
+    /* add some gold to make it worth looking for */
+
+    item = spec_item(GOLD, 0, 0, 0);
+    obj  = OBJPTR(item);
+    obj->o_count *= (rnd(10) + 5);  /* add in one large hunk */
+	
+	do
+	{
+	    rnd_pos(rp, &tp);
+	}
+	while( mvwinch(stdscr, tp.y, tp.x) != FLOOR);
+	
+    obj->o_pos = tp;
+    add_obj(item, tp.y, tp.x);
+
+    /* add in some food to make sure he has enough */
+
+    item = spec_item(FOOD, 0, 0, 0);
+    obj  = OBJPTR(item);
+	
+	do
+	{
+	    rnd_pos(rp, &tp);
+	}
+	while( mvwinch(stdscr, tp.y, tp.x) != FLOOR);
+	
+    obj->o_pos = tp;
+    add_obj(item, tp.y, tp.x);
+
+    if (rnd(100) < 5)  /* 5% for treasure maze level */
+    {
+        treas = TRUE;
+        least = 20;
+        debug("Treasure maze.");
+    }
+    else           /* normal maze level */
+    {
+        least = 1;
+        treas = FALSE;
+    }
+
+    for (i = 0; i < level + least; i++)
+    {
+        if (!treas && rnd(100) < 50)    /* put in some little buggers */
+            continue;
+
+        /* Put the monster in */
+
+        item = new_item(sizeof *mp);
+
+        mp = THINGPTR(item);
+
+        do
+        {
+            rnd_pos(rp, &tp);
+        }
+        while(mvwinch(stdscr, tp.y, tp.x) != FLOOR);
+
+        new_monster(item, randmonster(NOWANDER, NOGRAB), &tp, NOMAXSTATS);
+
+        /* See if we want to give it a treasure to carry around. */
+
+        if (rnd(100) < monsters[mp->t_index].m_carry)
+            attach(mp->t_pack, new_thing());
+
+        /* If it carries gold, give it some */
+
+        if (on(*mp, CARRYGOLD))
+        {
+            item = spec_item(GOLD, 0, 0, 0);
+            obj = OBJPTR(item);
+            obj->o_count = GOLDCALC + GOLDCALC + GOLDCALC;
+            obj->o_pos = mp->t_pos;
+            attach(mp->t_pack, item);
+        }
+
+    }
+}
+
+/*
+    draw_maze()
+        Generate and draw the maze on the screen
+*/
+
+void
+draw_maze(void)
+{
+    int i, j, more;
+    char    *ptr;
+
+    urlines = (LINES - 3) / 2;
+    urcols = (COLS - 1) / 2;
+
+    bits     = ur_alloc((unsigned int) ((LINES - 3) * (COLS - 1)));
+    frontier = ur_alloc((unsigned int) (urlines * urcols));
+    ptr      = frontier;
+
+    while (ptr < (frontier + (urlines * urcols)))
+        *ptr++ = TRUE;
+
+    for (i = 0; i < LINES - 3; i++)
+    {
+        for (j = 0; j < COLS - 1; j++)
+        {
+            if (i % 2 == 1 && j % 2 == 1)
+                *moffset(i, j) = FALSE; /* floor */
+            else
+                *moffset(i, j) = TRUE;  /* wall */
+        }
+    }
+
+    for (i = 0; i < urlines; i++)
+    {
+        for (j = 0; j < urcols; j++)
+        {
+            do
+                more = findcells(i, j);
+            while (more != 0);
+        }
+    }
+
+    crankout();
+    ur_free(frontier);
+    ur_free(bits);
+}
+
+/*
+    moffset()
+        Calculate memory address for bits
+*/
+
+char *
+moffset(int y, int x)
+{
+    return (bits + (y * (COLS - 1)) + x);
+}
+
+/*
+    foffset()
+        Calculate memory address for frontier
+*/
+
+char    *
+foffset(int y, int x)
+{
+    return (frontier + (y * urcols) + x);
+}
+
+/*
+    findcells()
+        Figure out cells to open up
+*/
+
+int
+findcells(int y, int x)
+{
+    int rtpos, i;
+
+    struct
+    {
+       int    num_pos;        /* number of frontier cells next to you */
+
+       struct
+       {
+           int y_pos;
+           int x_pos;
+       } conn[4];              /* the y,x position of above cell       */
+    } mborder;
+
+    *foffset(y, x) = FALSE;
+    mborder.num_pos = 0;
+
+    if (y < urlines - 1) {    /* look below */
+        if (*foffset(y + 1, x))
+        {
+            mborder.conn[mborder.num_pos].y_pos = y + 1;
+            mborder.conn[mborder.num_pos].x_pos = x;
+            mborder.num_pos += 1;
+        }
+    }
+
+    if (y > 0)         /* look above */
+    {
+        if (*foffset(y - 1, x))
+        {
+            mborder.conn[mborder.num_pos].y_pos = y - 1;
+            mborder.conn[mborder.num_pos].x_pos = x;
+            mborder.num_pos += 1;
+        }
+    }
+
+    if (x < urcols - 1)  /* look right */
+    {
+        if (*foffset(y, x + 1))
+        {
+            mborder.conn[mborder.num_pos].y_pos = y;
+            mborder.conn[mborder.num_pos].x_pos = x + 1;
+            mborder.num_pos += 1;
+        }
+    }
+
+    if (x > 0)        /* look left */
+    {
+        if (*foffset(y, x - 1))
+        {
+            mborder.conn[mborder.num_pos].y_pos = y;
+            mborder.conn[mborder.num_pos].x_pos = x - 1;
+            mborder.num_pos += 1;
+        }
+    }
+
+    if (mborder.num_pos == 0)/* no neighbors available */
+        return(0);
+    else
+    {
+        i = rnd(mborder.num_pos);
+        rtpos = mborder.num_pos - 1;
+        rmwall(mborder.conn[i].y_pos, mborder.conn[i].x_pos, y, x);
+        return(rtpos);
+    }
+}
+
+/*
+    rmwall()
+        Removes appropriate walls from the maze
+*/
+
+void
+rmwall(int newy, int newx, int oldy, int oldx)
+{
+    int xdif, ydif;
+
+    xdif = newx - oldx;
+    ydif = newy - oldy;
+
+    *moffset((oldy * 2) + ydif + 1, (oldx * 2) + xdif + 1) = FALSE;
+
+    findcells(newy, newx);
+}
+
+
+/*
+    crankout()
+        Does actual drawing of maze to window
+*/
+
+void
+crankout(void)
+{
+    int x, y;
+
+    for (y = 0; y < LINES - 3; y++)
+    {
+        move(y + 1, 0);
+
+        for (x = 0; x < COLS - 1; x++)
+        {
+            if (*moffset(y, x))    /* here is a wall */
+            {
+                if (y == 0 || y == LINES - 4)       /* top or bottom line */
+                    addch('-');
+                else if (x == 0 || x == COLS - 2)   /* left | right side */
+                    addch('|');
+                else if (y % 2 == 0 && x % 2 == 0)
+                {
+                    if (*moffset(y, x - 1) || *moffset(y, x + 1))
+                        addch('-');
+                    else
+                        addch('|');
+                }
+                else if (y % 2 == 0)
+                    addch('-');
+                else
+                    addch('|');
+            }
+            else
+                addch(FLOOR);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/mdport.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1270 @@
+/*
+    mdport.c - Machine Dependent Code for Porting Unix/Curses games
+
+    Copyright (C) 2005 Nicholas J. Kisseberth
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+    3. Neither the name(s) of the author(s) nor the names of other contributors
+       may be used to endorse or promote products derived from this software
+       without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+    ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+*/
+
+#if defined(_WIN32)
+#include <Windows.h>
+#include <Lmcons.h>
+#include <process.h>
+#pragma warning( disable: 4201 ) 
+#include <shlobj.h>
+#pragma warning( default: 4201 ) 
+#include <conio.h>
+#include <sys/types.h>
+#include <io.h>
+#undef MOUSE_MOVED
+#elif defined(__DJGPP__)
+#include <process.h>
+#else
+#include <pwd.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+#include <utmpx.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+#define PATH_MAX MAX_PATH
+#endif
+
+#include <curses.h>
+
+#if defined(__INTERIX) || defined(__MSYS__)
+#include <term.h>
+#else
+#ifdef NCURSES_VERSION
+#include <ncurses/term.h>
+#endif
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <signal.h>
+
+#define MOD_MOVE(c) (toupper(c) )
+
+void
+md_init()
+{
+#ifdef __INTERIX
+    char *term;
+
+    term = getenv("TERM");
+
+    if (term == NULL)
+        setenv("TERM","interix");
+#endif
+#if defined(__DJGPP__) || defined(_WIN32)
+    _fmode = _O_BINARY;
+#endif
+#if defined(__CYGWIN__) || defined(__MSYS__)
+    ESCDELAY=250;
+#endif
+}
+
+int
+md_hasclreol()
+{
+#ifndef	attron
+    return(!CE);
+#elif !defined(__PDCURSES__)
+    return(clr_eol != NULL);
+#else
+    return(TRUE);
+#endif
+}
+
+#ifdef	attron
+# define	_puts(s)	tputs(s, 0, md_putchar);
+# define	SO		enter_standout_mode
+# define	SE		exit_standout_mode
+#endif
+
+void
+md_putchar(int c)
+{
+    putchar(c);
+}
+
+static int md_standout_mode = 0;
+
+void
+md_raw_standout()
+{
+#ifdef _WIN32
+    CONSOLE_SCREEN_BUFFER_INFO csbiInfo; 
+    HANDLE hStdout;
+    WORD fgattr,bgattr;
+
+    if (md_standout_mode == 0)
+    {
+        hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
+        GetConsoleScreenBufferInfo(hStdout, &csbiInfo);
+        fgattr = (csbiInfo.wAttributes & 0xF);
+        bgattr = (csbiInfo.wAttributes & 0xF0);
+        SetConsoleTextAttribute(hStdout,(fgattr << 4) | (bgattr >> 4));
+        md_standout_mode = 1;
+    }
+#elif !defined(__PDCURSES__)
+    _puts(SO);
+    fflush(stdout);
+#endif
+}
+
+void
+md_raw_standend()
+{
+#ifdef _WIN32
+    CONSOLE_SCREEN_BUFFER_INFO csbiInfo; 
+    HANDLE hStdout;
+    WORD fgattr,bgattr;
+
+    if (md_standout_mode == 1)
+    {
+        hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
+        GetConsoleScreenBufferInfo(hStdout, &csbiInfo);
+        fgattr = (csbiInfo.wAttributes & 0xF);
+        bgattr = (csbiInfo.wAttributes & 0xF0);
+        SetConsoleTextAttribute(hStdout,(fgattr << 4) | (bgattr >> 4));
+        md_standout_mode = 0;
+    }
+#elif !defined(__PDCURSES__)
+    _puts(SE);
+    fflush(stdout);
+#endif
+}
+
+int
+md_unlink_open_file(char *file, int inf)
+{
+#ifdef _WIN32
+    _close(inf);
+    _chmod(file, 0600);
+    return( _unlink(file) );
+#else
+    return(unlink(file));
+#endif
+}
+
+int
+md_unlink(char *file)
+{
+#ifdef _WIN32
+    _chmod(file, 0600);
+    return( _unlink(file) );
+#else
+    return(unlink(file));
+#endif
+}
+
+int
+md_creat(char *file, int mode)
+{
+    int fd;
+#ifdef _WIN32
+    mode = _S_IREAD | _S_IWRITE;
+    fd = _open(file,O_CREAT | O_EXCL | O_WRONLY, mode);
+#else
+    fd = open(file,O_CREAT | O_EXCL | O_WRONLY, mode);
+#endif
+
+    return(fd);
+}
+
+
+void
+md_normaluser()
+{
+#ifndef _WIN32
+    setuid(getuid());
+    setgid(getgid());
+#endif
+}
+
+int
+md_getuid()
+{
+#ifndef _WIN32
+    return( getuid() );
+#else
+    return(42);
+#endif
+}
+
+char *
+md_getusername(int uid)
+{
+    static char login[80];
+    char *l = NULL;
+#ifdef _WIN32
+    LPSTR mybuffer;
+    DWORD size = UNLEN + 1;
+    TCHAR buffer[UNLEN + 1];
+
+    mybuffer = buffer;
+    if (uid != md_getuid())
+	strcpy(mybuffer, "someone");
+    else
+	GetUserName(mybuffer,&size);
+    l = mybuffer;
+#endif
+#if !defined(_WIN32) && !defined(DJGPP)
+    struct passwd *pw;
+
+    pw = getpwuid(getuid());
+
+    l = pw->pw_name;
+#endif
+
+    if ((l == NULL) || (*l == '\0'))
+        if ( (l = getenv("USERNAME")) == NULL )
+            if ( (l = getenv("LOGNAME")) == NULL )
+                if ( (l = getenv("USER")) == NULL )
+                    l = "nobody";
+
+    strncpy(login,l,80);
+    login[79] = 0;
+
+    return(login);
+}
+
+char *
+md_gethomedir()
+{
+    static char homedir[PATH_MAX];
+    char *h = NULL;
+    size_t len;
+#if defined(_WIN32)
+    TCHAR szPath[PATH_MAX];
+#endif
+#if defined(_WIN32) || defined(DJGPP)
+        char slash = '\\';
+#else
+    char slash = '/';
+    struct passwd *pw;
+    pw = getpwuid(getuid());
+
+    h = pw->pw_dir;
+
+    if (strcmp(h,"/") == 0)
+        h = NULL;
+#endif
+    homedir[0] = 0;
+#ifdef _WIN32
+    if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, szPath)))
+        h = szPath;
+#endif
+
+    if ( (h == NULL) || (*h == '\0') )
+        if ( (h = getenv("HOME")) == NULL )
+            if ( (h = getenv("HOMEDRIVE")) == NULL)
+                h = "";
+            else
+            {
+                strncpy(homedir,h,PATH_MAX-1);
+                homedir[PATH_MAX-1] = 0;
+
+                if ( (h = getenv("HOMEPATH")) == NULL)
+                    h = "";
+            }
+
+
+    len = strlen(homedir);
+    strncat(homedir,h,PATH_MAX-len-1);
+    len = strlen(homedir);
+
+    if ((len > 0) && (homedir[len-1] != slash)) {
+        homedir[len] = slash;
+        homedir[len+1] = 0;
+    }
+
+    return(homedir);
+}
+
+void
+md_sleep(int s)
+{
+#ifdef _WIN32
+    Sleep(s);
+#else
+    sleep(s);
+#endif
+}
+
+char *
+md_getshell()
+{
+    static char shell[PATH_MAX];
+    char *s = NULL;
+#ifdef _WIN32
+    char *def = "C:\\WINDOWS\\SYSTEM32\\CMD.EXE";
+#elif defined(__DJGPP__)
+    char *def = "C:\\COMMAND.COM";
+#else
+    char *def = "/bin/sh";
+    struct passwd *pw;
+    pw = getpwuid(getuid());
+    s = pw->pw_shell;
+#endif
+    if ((s == NULL) || (*s == '\0'))
+        if ( (s = getenv("COMSPEC")) == NULL)
+            if ( (s = getenv("SHELL")) == NULL)
+                if ( (s = getenv("SystemRoot")) == NULL)
+                    s = def;
+
+    strncpy(shell,s,PATH_MAX);
+    shell[PATH_MAX-1] = 0;
+
+    return(shell);
+}
+
+int
+md_shellescape()
+{
+#if (!defined(_WIN32) && !defined(__DJGPP__))
+    int ret_status;
+    int pid;
+    void (*myquit)(int);
+    void (*myend)(int);
+#endif
+    char *sh;
+
+    sh = md_getshell();
+
+#if defined(_WIN32)
+    return((int)_spawnl(_P_WAIT,sh,"shell",NULL,0));
+#elif defined(__DJGPP__)
+    return ( spawnl(P_WAIT,sh,"shell",NULL,0) );
+#else
+    while((pid = fork()) < 0)
+        sleep(1);
+
+    if (pid == 0) /* Shell Process */
+    {
+        /*
+         * Set back to original user, just in case
+         */
+        setuid(getuid());
+        setgid(getgid());
+        execl(sh == NULL ? "/bin/sh" : sh, "shell", "-i", 0);
+        perror("No shelly");
+        _exit(-1);
+    }
+    else /* Application */
+    {
+	myend = signal(SIGINT, SIG_IGN);
+#ifdef SIGQUIT
+        myquit = signal(SIGQUIT, SIG_IGN);
+#endif  
+        while (wait(&ret_status) != pid)
+            continue;
+	    
+        signal(SIGINT, myquit);
+#ifdef SIGQUIT
+        signal(SIGQUIT, myend);
+#endif
+    }
+
+    return(ret_status);
+#endif
+}
+
+int
+directory_exists(char *dirname)
+{
+    struct stat sb;
+
+    if (stat(dirname, &sb) == 0) /* path exists */
+        return (sb.st_mode & S_IFDIR);
+
+    return(0);
+}
+
+char *
+md_getroguedir()
+{
+    static char path[1024];
+    char *end,*home;
+
+    if ( (home = getenv("ROGUEHOME")) != NULL)
+    {
+        if (*home)
+        {
+            strncpy(path, home, PATH_MAX - 20);
+
+            end = &path[strlen(path)-1];
+
+            while( (end >= path) && ((*end == '/') || (*end == '\\')))
+                *end-- = '\0';
+
+            if (directory_exists(path))
+                return(path);
+        }
+    }
+
+    if (directory_exists("/var/games/roguelike"))
+        return("/var/games/roguelike");
+    if (directory_exists("/var/lib/roguelike"))
+        return("/var/lib/roguelike");
+    if (directory_exists("/var/roguelike"))
+        return("/var/roguelike");
+    if (directory_exists("/usr/games/lib"))
+        return("/usr/games/lib");
+    if (directory_exists("/games/roguelik"))
+        return("/games/roguelik");
+    if (directory_exists(md_gethomedir()))
+	return(md_gethomedir());
+    return("");
+}
+
+char *
+md_getrealname(int uid)
+{
+    static char uidstr[20];
+#if !defined(_WIN32) && !defined(DJGPP)
+    struct passwd *pp;
+
+	if ((pp = getpwuid(uid)) == NULL)
+    {
+        sprintf(uidstr,"%d", uid);
+        return(uidstr);
+    }
+	else
+	    return(pp->pw_name);
+#else
+   sprintf(uidstr,"%d", uid);
+   return(uidstr);
+#endif
+}
+
+extern char *xcrypt(char *key, char *salt);
+
+char *
+md_crypt(char *key, char *salt)
+{
+    return( xcrypt(key,salt) );
+}
+
+char *
+md_getpass(char *prompt)
+{
+#ifdef _WIN32
+    static char password_buffer[9];
+    char *p = password_buffer;
+    int c, count = 0;
+    int max_length = 9;
+
+    fflush(stdout);
+    /* If we can't prompt, abort */
+    if (fputs(prompt, stderr) < 0)
+    {
+        *p = '\0';
+        return NULL;
+    }
+
+    for(;;)
+    {
+        /* Get a character with no echo */
+        c = _getch();
+
+        /* Exit on interrupt (^c or ^break) */
+        if (c == '\003' || c == 0x100)
+            exit(1);
+
+        /* Terminate on end of line or file (^j, ^m, ^d, ^z) */
+        if (c == '\r' || c == '\n' || c == '\004' || c == '\032')
+            break;
+
+        /* Back up on backspace */
+        if (c == '\b')
+        {
+            if (count)
+                count--;
+            else if (p > password_buffer)
+                p--;
+            continue;
+        }
+
+        /* Ignore DOS extended characters */
+        if ((c & 0xff) != c)
+            continue;
+
+        /* Add to password if it isn't full */
+        if (p < password_buffer + max_length - 1)
+            *p++ = (char) c;
+        else
+            count++;
+    }
+   *p = '\0';
+
+   fputc('\n', stderr);
+
+   return password_buffer;
+#else
+   return( (char *) getpass(prompt) );
+#endif
+}
+
+
+int md_endian = 0x01020304;
+
+unsigned long int
+md_ntohl(unsigned long int x)
+{
+#ifdef _WIN32
+    if ( *((char *)&md_endian) == 0x01 )
+        return(x);
+    else
+        return( ((x & 0x000000ffU) << 24) |
+                ((x & 0x0000ff00U) <<  8) |
+                ((x & 0x00ff0000U) >>  8) |
+                ((x & 0xff000000U) >> 24) );
+#else
+    return( ntohl(x) );
+#endif
+}
+
+unsigned long int
+md_htonl(unsigned long int x)
+{
+#ifdef _WIN32
+    if ( *((char *)&md_endian) == 0x01 )
+        return(x);
+    else
+        return( ((x & 0x000000ffU) << 24) |
+                ((x & 0x0000ff00U) <<  8) |
+                ((x & 0x00ff0000U) >>  8) |
+                ((x & 0xff000000U) >> 24) );
+#else
+    return( htonl(x) );
+#endif
+}
+
+int
+md_ucount()
+{
+#ifdef __DJGPP__
+    return(1);
+#elif defined(_WIN32)
+    return(1);
+#else
+    struct utmpx *up=NULL;
+    int count=0;
+
+    setutxent();    
+    do
+    {
+	up = getutxent();
+	if (up && up->ut_type == USER_PROCESS)
+	    count++;
+    } while(up != NULL);
+   
+   endutxent();
+
+   return(count);
+#endif
+}
+
+int
+md_getloadavg(double *avg)
+{
+#if defined(__GLIBC__) || defined(_BSD)
+    if (getloadavg(avg, 3) == -1)
+#endif
+    {
+	avg[0] = avg[1] = avg[2] = 0.0;
+	return -1;
+    }
+}
+
+long
+md_random()
+{
+#ifdef _WIN32
+    return(rand());
+#else
+    return( random() );
+#endif
+}
+
+void
+md_srandom(unsigned x)
+{
+#ifdef _WIN32
+    srand(x);
+#else
+    srandom(x);
+#endif
+}
+
+int
+md_rand()
+{
+#ifdef _WIN32
+    return(rand());
+#else
+    return(lrand48() & 0x7fffffff);
+#endif
+}
+
+void
+md_srand(int seed)
+{
+#ifdef _WIN32
+    srand(seed);
+#else
+    srand48(seed);
+#endif
+}
+
+char *
+md_strdup(const char *s)
+{
+#ifdef _WIN32
+    return( _strdup(s) );
+#else
+    return(strdup(s));
+#endif
+}
+
+long
+md_memused()
+{
+#ifdef _WIN32
+    MEMORYSTATUS stat;
+
+    GlobalMemoryStatus(&stat);
+
+    return((long)stat.dwTotalPageFile);
+#else
+    return( (long)sbrk(0) );
+#endif
+}
+
+char *
+md_gethostname()
+{
+    static char nodename[80];
+    char *n = NULL;
+#if !defined(_WIN32) && !defined(__DJGPP__)
+    struct utsname ourname;
+
+    if (uname(&ourname) == 0)
+        n = ourname.nodename;
+#endif
+    if ((n == NULL) || (*n == '\0'))
+        if ( (n = getenv("COMPUTERNAME")) == NULL)
+            if ( (n = getenv("HOSTNAME")) == NULL)
+                n = "localhost";
+
+    strncpy(nodename, n, 80);
+    nodename[79] = 0;
+
+    return(nodename);
+}
+
+int
+md_erasechar()
+{
+#ifdef BSD
+    return(_tty.sg_erase); /* process erase character */
+#elif defined(USG5_0)
+    return(_tty.c_cc[VERASE]); /* process erase character */
+#else /* USG5_2 .... curses */
+    return( erasechar() ); /* process erase character */
+#endif
+}
+
+int
+md_killchar()
+{
+#ifdef BSD
+    return(_tty.sg_kill);
+#elif defined(USG5_0)
+    return(_tty.c_cc[VKILL]);
+#else /* USG5_2 ..... curses */
+    return( killchar() );
+#endif
+}
+
+/*
+ * unctrl:
+ *	Print a readable version of a certain character
+ */
+
+char *
+md_unctrl(char ch)
+{
+#if USG5_0
+    extern char *_unctrl[];		/* Defined in curses library */
+
+    return _unctrl[ch&0177];
+#else
+    return( unctrl(ch) );
+#endif
+}
+
+void
+md_flushinp()
+{
+#ifdef BSD
+    ioctl(0, TIOCFLUSH);
+#elif defined(USG5_0)
+    ioctl(_tty_ch,TCFLSH,0)
+#else /* USG5_2.... curses */
+    flushinp();
+#endif
+}
+
+/*
+    Cursor/Keypad Support
+
+    Sadly Cursor/Keypad support is less straightforward than it should be.
+
+    The various terminal emulators/consoles choose to differentiate the
+    cursor and keypad keys (with modifiers) in different ways (if at all!).
+    Furthermore they use different code set sequences for each key only
+    a subset of which the various curses libraries recognize. Partly due
+    to incomplete termcap/terminfo entries and partly due to inherent
+    limitations of those terminal capability databases.
+
+    I give curses first crack at decoding the sequences. If it fails to decode
+    it we check for common ESC-prefixed sequences.
+
+    All cursor/keypad results are translated into standard rogue movement
+    commands.
+
+    Unmodified keys are translated to walk commands: hjklyubn
+    Modified (shift,control,alt) are translated to run commands: HJKLYUBN
+
+    Console and supported (differentiated) keys
+    Interix:  Cursor Keys, Keypad, Ctl-Keypad
+    Cygwin:   Cursor Keys, Keypad, Alt-Cursor Keys
+    MSYS:     Cursor Keys, Keypad, Ctl-Cursor Keys, Ctl-Keypad
+    Win32:    Cursor Keys, Keypad, Ctl/Shift/Alt-Cursor Keys, Ctl/Alt-Keypad
+    DJGPP:    Cursor Keys, Keypad, Ctl/Shift/Alt-Cursor Keys, Ctl/Alt-Keypad
+
+    Interix Console (raw, ncurses)
+    ==============================
+    normal      shift           ctrl        alt
+    ESC [D,     ESC F^,         ESC [D,     ESC [D          /# Left         #/
+    ESC [C,     ESC F$,         ESC [C,     ESC [C          /# Right        #/
+    ESC [A,     ESC F-,         local win,  ESC [A          /# Up           #/
+    ESC [B,     ESC F+,         local win,  ESC [B          /# Down         #/
+    ESC [H,     ESC [H,         ESC [H,     ESC [H          /# Home         #/
+    ESC [S,     local win,      ESC [S,     ESC [S          /# Page Up      #/
+    ESC [T,     local win,      ESC [T,     ESC [T          /# Page Down    #/
+    ESC [U,     ESC [U,         ESC [U,     ESC [U          /# End          #/
+    ESC [D,     ESC F^,         ESC [D,     O               /# Keypad Left  #/
+    ESC [C,     ESC F$,         ESC [C,     O               /# Keypad Right #/
+    ESC [A,     ESC [A,         ESC [-1,    O               /# Keypad Up    #/
+    ESC [B,     ESC [B,         ESC [-2,    O               /# Keypad Down  #/
+    ESC [H,     ESC [H,         ESC [-263,  O               /# Keypad Home  #/
+    ESC [S,     ESC [S,         ESC [-19,   O               /# Keypad PgUp  #/
+    ESC [T,     ESC [T,         ESC [-20,   O               /# Keypad PgDn  #/
+    ESC [U,     ESC [U,         ESC [-21,   O               /# Keypad End   #/
+    nothing,    nothing,        nothing,    O               /# Kaypad 5     #/
+
+    Interix Console (term=interix, ncurses)
+    ==============================
+    KEY_LEFT,   ESC F^,         KEY_LEFT,   KEY_LEFT        /# Left         #/
+    KEY_RIGHT,  ESC F$,         KEY_RIGHT,  KEY_RIGHT       /# Right        #/
+    KEY_UP,     0x146,          local win,  KEY_UP          /# Up           #/
+    KEY_DOWN,   0x145,          local win,  KEY_DOWN        /# Down         #/
+    ESC [H,     ESC [H,         ESC [H,     ESC [H          /# Home         #/
+    KEY_PPAGE,  local win,      KEY_PPAGE,  KEY_PPAGE       /# Page Up      #/
+    KEY_NPAGE,  local win,      KEY_NPAGE,  KEY_NPAGE       /# Page Down    #/
+    KEY_LL,     KEY_LL,         KEY_LL,     KEY_LL          /# End          #/
+    KEY_LEFT,   ESC F^,         ESC [-4,    O               /# Keypad Left  #/
+    KEY_RIGHT,  ESC F$,         ESC [-3,    O               /# Keypad Right #/
+    KEY_UP,     KEY_UP,         ESC [-1,    O               /# Keypad Up    #/
+    KEY_DOWN,   KEY_DOWN,       ESC [-2,    O               /# Keypad Down  #/
+    ESC [H,     ESC [H,         ESC [-263,  O               /# Keypad Home  #/
+    KEY_PPAGE,  KEY_PPAGE,      ESC [-19,   O               /# Keypad PgUp  #/
+    KEY_NPAGE,  KEY_NPAGE,      ESC [-20,   O               /# Keypad PgDn  #/
+    KEY_LL,     KEY_LL,         ESC [-21,   O               /# Keypad End   #/
+    nothing,    nothing,        nothing,    O               /# Keypad 5     #/
+
+    Cygwin Console (raw, ncurses)
+    ==============================
+    normal      shift           ctrl        alt
+    ESC [D,     ESC [D,         ESC [D,     ESC ESC [D      /# Left         #/
+    ESC [C,     ESC [C,         ESC [C,     ESC ESC [C      /# Rght         #/
+    ESC [A,     ESC [A,         ESC [A,     ESC ESC [A      /# Up           #/
+    ESC [B,     ESC [B,         ESC [B,     ESC ESC [B      /# Down         #/
+    ESC [1~,    ESC [1~,        ESC [1~,    ESC ESC [1~     /# Home         #/
+    ESC [5~,    ESC [5~,        ESC [5~,    ESC ESC [5~     /# Page Up      #/
+    ESC [6~,    ESC [6~,        ESC [6~,    ESC ESC [6~     /# Page Down    #/
+    ESC [4~,    ESC [4~,        ESC [4~,    ESC ESC [4~     /# End          #/
+    ESC [D,     ESC [D,         ESC [D,     ESC ESC [D,O    /# Keypad Left  #/
+    ESC [C,     ESC [C,         ESC [C,     ESC ESC [C,O    /# Keypad Right #/
+    ESC [A,     ESC [A,         ESC [A,     ESC ESC [A,O    /# Keypad Up    #/
+    ESC [B,     ESC [B,         ESC [B,     ESC ESC [B,O    /# Keypad Down  #/
+    ESC [1~,    ESC [1~,        ESC [1~,    ESC ESC [1~,O   /# Keypad Home  #/
+    ESC [5~,    ESC [5~,        ESC [5~,    ESC ESC [5~,O   /# Keypad PgUp  #/
+    ESC [6~,    ESC [6~,        ESC [6~,    ESC ESC [6~,O   /# Keypad PgDn  #/
+    ESC [4~,    ESC [4~,        ESC [4~,    ESC ESC [4~,O   /# Keypad End   #/
+    ESC [-71,   nothing,        nothing,    O               /# Keypad 5     #/
+
+    Cygwin Console (term=cygwin, ncurses)
+    ==============================
+    KEY_LEFT,   KEY_LEFT,       KEY_LEFT,   ESC-260         /# Left         #/
+    KEY_RIGHT,  KEY_RIGHT,      KEY_RIGHT,  ESC-261         /# Rght         #/
+    KEY_UP,     KEY_UP,         KEY_UP,     ESC-259         /# Up           #/
+    KEY_DOWN,   KEY_DOWN,       KEY_DOWN,   ESC-258         /# Down         #/
+    KEY_HOME,   KEY_HOME,       KEY_HOME,   ESC-262         /# Home         #/
+    KEY_PPAGE,  KEY_PPAGE,      KEY_PPAGE,  ESC-339         /# Page Up      #/
+    KEY_NPAGE,  KEY_NPAGE,      KEY_NPAGE,  ESC-338         /# Page Down    #/
+    KEY_END,    KEY_END,        KEY_END,    ESC-360         /# End          #/
+    KEY_LEFT,   KEY_LEFT,       KEY_LEFT,   ESC-260,O       /# Keypad Left  #/
+    KEY_RIGHT,  KEY_RIGHT,      KEY_RIGHT,  ESC-261,O       /# Keypad Right #/
+    KEY_UP,     KEY_UP,         KEY_UP,     ESC-259,O       /# Keypad Up    #/
+    KEY_DOWN,   KEY_DOWN,       KEY_DOWN,   ESC-258,O       /# Keypad Down  #/
+    KEY_HOME,   KEY_HOME,       KEY_HOME,   ESC-262,O       /# Keypad Home  #/
+    KEY_PPAGE,  KEY_PPAGE,      KEY_PPAGE,  ESC-339,O       /# Keypad PgUp  #/
+    KEY_NPAGE,  KEY_NPAGE,      KEY_NPAGE,  ESC-338,O       /# Keypad PgDn  #/
+    KEY_END,    KEY_END,        KEY_END,    ESC-360,O       /# Keypad End   #/
+    ESC [G,     nothing,        nothing,    O               /# Keypad 5     #/
+
+    MSYS Console (raw, ncurses)
+    ==============================
+    normal      shift           ctrl        alt
+    ESC OD,     ESC [d,         ESC Od      nothing         /# Left         #/
+    ESC OE,     ESC [e,         ESC Oe,     nothing         /# Right        #/
+    ESC OA,     ESC [a,         ESC Oa,     nothing         /# Up           #/
+    ESC OB,     ESC [b,         ESC Ob,     nothing         /# Down         #/
+    ESC [7~,    ESC [7$,        ESC [7^,    nothing         /# Home         #/
+    ESC [5~,    local window,   ESC [5^,    nothing         /# Page Up      #/
+    ESC [6~,    local window,   ESC [6^,    nothing         /# Page Down    #/
+    ESC [8~,    ESC [8$,        ESC [8^,    nothing         /# End          #/
+    ESC OD,     ESC [d,         ESC Od      O               /# Keypad Left  #/
+    ESC OE,     ESC [c,         ESC Oc,     O               /# Keypad Right #/
+    ESC OA,     ESC [a,         ESC Oa,     O               /# Keypad Up    #/
+    ESC OB,     ESC [b,         ESC Ob,     O               /# Keypad Down  #/
+    ESC [7~,    ESC [7$,        ESC [7^,    O               /# Keypad Home  #/
+    ESC [5~,    local window,   ESC [5^,    O               /# Keypad PgUp  #/
+    ESC [6~,    local window,   ESC [6^,    O               /# Keypad PgDn  #/
+    ESC [8~,    ESC [8$,        ESC [8^,    O               /# Keypad End   #/
+    11,         11,             11,         O               /# Keypad 5     #/
+
+    MSYS Console (term=rxvt, ncurses)
+    ==============================
+    normal      shift           ctrl        alt
+    KEY_LEFT,   KEY_SLEFT,      514         nothing         /# Left         #/
+    KEY_RIGHT,  KEY_SRIGHT,     516,        nothing         /# Right        #/
+    KEY_UP,     518,            519,        nothing         /# Up           #/
+    KEY_DOWN,   511,            512,        nothing         /# Down         #/
+    KEY_HOME,   KEY_SHOME,      ESC [7^,    nothing         /# Home         #/
+    KEY_PPAGE,  local window,   ESC [5^,    nothing         /# Page Up      #/
+    KEY_NPAGE,  local window,   ESC [6^,    nothing         /# Page Down    #/
+    KEY_END,    KEY_SEND,       KEY_EOL,    nothing         /# End          #/
+    KEY_LEFT,   KEY_SLEFT,      514         O               /# Keypad Left  #/
+    KEY_RIGHT,  KEY_SRIGHT,     516,        O               /# Keypad Right #/
+    KEY_UP,     518,            519,        O               /# Keypad Up    #/
+    KEY_DOWN,   511,            512,        O               /# Keypad Down  #/
+    KEY_HOME,   KEY_SHOME,      ESC [7^,    O               /# Keypad Home  #/
+    KEY_PPAGE,  local window,   ESC [5^,    O               /# Keypad PgUp  #/
+    KEY_NPAGE,  local window,   ESC [6^,    O               /# Keypad PgDn  #/
+    KEY_END,    KEY_SEND,       KEY_EOL,    O               /# Keypad End   #/
+    11,         11,             11,         O               /# Keypad 5     #/
+
+    Win32 Console (raw, pdcurses)
+   DJGPP Console (raw, pdcurses)
+   ==============================
+   normal      shift           ctrl        alt
+   260,        391,            443,        493             /# Left         #/
+   261,        400,            444,        492             /# Right        #/
+   259,        547,            480,        490             /# Up           #/
+   258,        548,            481,        491             /# Down         #/
+   262,        388,            447,        524             /# Home         #/
+   339,        396,            445,        526             /# Page Up      #/
+   338,        394,            446,        520             /# Page Down    #/
+   358,        384,            448,        518             /# End          #/
+   452,        52('4'),        511,        521             /# Keypad Left  #/
+   454,        54('6'),        513,        523             /# Keypad Right #/
+   450,        56('8'),        515,        525             /# Keypad Up    #/
+   456,        50('2'),        509,        519             /# Keypad Down  #/
+   449,        55('7'),        514,        524             /# Keypad Home  #/
+   451,        57('9'),        516,        526             /# Keypad PgUp  #/
+   457,        51('3'),        510,        520             /# Keypad PgDn  #/
+   455,        49('1'),        508,        518             /# Keypad End   #/
+   453,        53('5'),        512,        522             /# Keypad 5     #/
+
+   Win32 Console (pdcurses, MSVC/MingW32)
+   DJGPP Console (pdcurses)
+   ==============================
+   normal      shift           ctrl        alt
+   KEY_LEFT,   KEY_SLEFT,      CTL_LEFT,   ALT_LEFT        /# Left         #/
+   KEY_RIGHT,  KEY_SRIGHT,     CTL_RIGHT,  ALT_RIGHT       /# Right        #/
+   KEY_UP,     KEY_SUP,        CTL_UP,     ALT_UP          /# Up           #/
+   KEY_DOWN,   KEY_SDOWN,      CTL_DOWN,   ALT_DOWN        /# Down         #/
+   KEY_HOME,   KEY_SHOME,      CTL_HOME,   ALT_HOME        /# Home         #/
+   KEY_PPAGE,  KEY_SPREVIOUS,  CTL_PGUP,   ALT_PGUP        /# Page Up      #/
+   KEY_NPAGE,  KEY_SNEXTE,     CTL_PGDN,   ALT_PGDN        /# Page Down    #/
+   KEY_END,    KEY_SEND,       CTL_END,    ALT_END         /# End          #/
+   KEY_B1,     52('4'),        CTL_PAD4,   ALT_PAD4        /# Keypad Left  #/
+   KEY_B3,     54('6'),        CTL_PAD6,   ALT_PAD6        /# Keypad Right #/
+   KEY_A2,     56('8'),        CTL_PAD8,   ALT_PAD8        /# Keypad Up    #/
+   KEY_C2,     50('2'),        CTL_PAD2,   ALT_PAD2        /# Keypad Down  #/
+   KEY_A1,     55('7'),        CTL_PAD7,   ALT_PAD7        /# Keypad Home  #/
+   KEY_A3,     57('9'),        CTL_PAD9,   ALT_PAD9        /# Keypad PgUp  #/
+   KEY_C3,     51('3'),        CTL_PAD3,   ALT_PAD3        /# Keypad PgDn  #/
+   KEY_C1,     49('1'),        CTL_PAD1,   ALT_PAD1        /# Keypad End   #/
+   KEY_B2,     53('5'),        CTL_PAD5,   ALT_PAD5        /# Keypad 5     #/
+
+   Windows Telnet (raw)
+   ==============================
+   normal      shift           ctrl        alt
+   ESC [D,     ESC [D,         ESC [D,     ESC [D          /# Left         #/
+   ESC [C,     ESC [C,         ESC [C,     ESC [C          /# Right        #/
+   ESC [A,     ESC [A,         ESC [A,     ESC [A          /# Up           #/
+   ESC [B,     ESC [B,         ESC [B,     ESC [B          /# Down         #/
+   ESC [1~,    ESC [1~,        ESC [1~,    ESC [1~         /# Home         #/
+   ESC [5~,    ESC [5~,        ESC [5~,    ESC [5~         /# Page Up      #/
+   ESC [6~,    ESC [6~,        ESC [6~,    ESC [6~         /# Page Down    #/
+   ESC [4~,    ESC [4~,        ESC [4~,    ESC [4~         /# End          #/
+   ESC [D,     ESC [D,         ESC [D,     ESC [D          /# Keypad Left  #/
+   ESC [C,     ESC [C,         ESC [C,     ESC [C          /# Keypad Right #/
+   ESC [A,     ESC [A,         ESC [A,     ESC [A          /# Keypad Up    #/
+   ESC [B,     ESC [B,         ESC [B,     ESC [B          /# Keypad Down  #/
+   ESC [1~,    ESC [1~,        ESC [1~,    ESC [1~         /# Keypad Home  #/
+   ESC [5~,    ESC [5~,        ESC [5~,    ESC [5~         /# Keypad PgUp  #/
+   ESC [6~,    ESC [6~,        ESC [6~,    ESC [6~         /# Keypad PgDn  #/
+   ESC [4~,    ESC [4~,        ESC [4~,    ESC [4~         /# Keypad End   #/
+   nothing,    nothing,        nothing,    nothing         /# Keypad 5     #/
+
+   Windows Telnet (term=xterm)
+   ==============================
+   normal      shift           ctrl        alt
+   KEY_LEFT,   KEY_LEFT,       KEY_LEFT,   KEY_LEFT        /# Left         #/
+   KEY_RIGHT,  KEY_RIGHT,      KEY_RIGHT,  KEY_RIGHT       /# Right        #/
+   KEY_UP,     KEY_UP,         KEY_UP,     KEY_UP          /# Up           #/
+   KEY_DOWN,   KEY_DOWN,       KEY_DOWN,   KEY_DOWN        /# Down         #/
+   ESC [1~,    ESC [1~,        ESC [1~,    ESC [1~         /# Home         #/
+   KEY_PPAGE,  KEY_PPAGE,      KEY_PPAGE,  KEY_PPAGE       /# Page Up      #/
+   KEY_NPAGE,  KEY_NPAGE,      KEY_NPAGE,  KEY_NPAGE       /# Page Down    #/
+   ESC [4~,    ESC [4~,        ESC [4~,    ESC [4~         /# End          #/
+    KEY_LEFT,   KEY_LEFT,       KEY_LEFT,   O               /# Keypad Left  #/
+    KEY_RIGHT,  KEY_RIGHT,      KEY_RIGHT,  O               /# Keypad Right #/
+    KEY_UP,     KEY_UP,         KEY_UP,     O               /# Keypad Up    #/
+    KEY_DOWN,   KEY_DOWN,       KEY_DOWN,   O               /# Keypad Down  #/
+    ESC [1~,    ESC [1~,        ESC [1~,    ESC [1~         /# Keypad Home  #/
+    KEY_PPAGE,  KEY_PPAGE,      KEY_PPAGE,  KEY_PPAGE       /# Keypad PgUp  #/
+    KEY_NPAGE,  KEY_NPAGE,      KEY_NPAGE,  KEY_NPAGE       /# Keypad PgDn  #/
+    ESC [4~,    ESC [4~,        ESC [4~,    O               /# Keypad End   #/
+    ESC [-71,   nothing,        nothing,    O               /# Keypad 5     #/
+
+    PuTTY
+    ==============================
+    normal      shift           ctrl        alt
+    ESC [D,     ESC [D,         ESC OD,     ESC [D          /# Left         #/
+    ESC [C,     ESC [C,         ESC OC,     ESC [C          /# Right        #/
+    ESC [A,     ESC [A,         ESC OA,     ESC [A          /# Up           #/
+    ESC [B,     ESC [B,         ESC OB,     ESC [B          /# Down         #/
+    ESC [1~,    ESC [1~,        local win,  ESC [1~         /# Home         #/
+    ESC [5~,    local win,      local win,  ESC [5~         /# Page Up      #/
+    ESC [6~,    local win,      local win,  ESC [6~         /# Page Down    #/
+    ESC [4~,    ESC [4~,        local win,  ESC [4~         /# End          #/
+    ESC [D,     ESC [D,         ESC [D,     O               /# Keypad Left  #/
+    ESC [C,     ESC [C,         ESC [C,     O               /# Keypad Right #/
+    ESC [A,     ESC [A,         ESC [A,     O               /# Keypad Up    #/
+    ESC [B,     ESC [B,         ESC [B,     O               /# Keypad Down  #/
+    ESC [1~,    ESC [1~,        ESC [1~,    O               /# Keypad Home  #/
+    ESC [5~,    ESC [5~,        ESC [5~,    O               /# Keypad PgUp  #/
+    ESC [6~,    ESC [6~,        ESC [6~,    O               /# Keypad PgDn  #/
+    ESC [4~,    ESC [4~,        ESC [4~,    O               /# Keypad End   #/
+    nothing,    nothing,        nothing,    O               /# Keypad 5     #/
+
+    PuTTY
+    ==============================
+    normal      shift           ctrl        alt
+    KEY_LEFT,   KEY_LEFT,       ESC OD,     ESC KEY_LEFT    /# Left         #/
+    KEY_RIGHT   KEY_RIGHT,      ESC OC,     ESC KEY_RIGHT   /# Right        #/
+    KEY_UP,     KEY_UP,         ESC OA,     ESC KEY_UP      /# Up           #/
+    KEY_DOWN,   KEY_DOWN,       ESC OB,     ESC KEY_DOWN    /# Down         #/
+    ESC [1~,    ESC [1~,        local win,  ESC ESC [1~     /# Home         #/
+    KEY_PPAGE   local win,      local win,  ESC KEY_PPAGE   /# Page Up      #/
+    KEY_NPAGE   local win,      local win,  ESC KEY_NPAGE   /# Page Down    #/
+    ESC [4~,    ESC [4~,        local win,  ESC ESC [4~     /# End          #/
+    ESC Ot,     ESC Ot,         ESC Ot,     O               /# Keypad Left  #/
+    ESC Ov,     ESC Ov,         ESC Ov,     O               /# Keypad Right #/
+    ESC Ox,     ESC Ox,         ESC Ox,     O               /# Keypad Up    #/
+    ESC Or,     ESC Or,         ESC Or,     O               /# Keypad Down  #/
+    ESC Ow,     ESC Ow,         ESC Ow,     O               /# Keypad Home  #/
+    ESC Oy,     ESC Oy,         ESC Oy,     O               /# Keypad PgUp  #/
+    ESC Os,     ESC Os,         ESC Os,     O               /# Keypad PgDn  #/
+    ESC Oq,     ESC Oq,         ESC Oq,     O               /# Keypad End   #/
+    ESC Ou,     ESC Ou,         ESC Ou,     O               /# Keypad 5     #/
+*/
+
+#define M_NORMAL 0
+#define M_ESC    1
+#define M_KEYPAD 2
+#define M_TRAIL  3
+
+int
+md_readchar(WINDOW *win)
+{
+    int ch = 0;
+    int lastch = 0;
+    int mode = M_NORMAL;
+    int mode2 = M_NORMAL;
+
+    for(;;)
+    {
+        ch = wgetch(win);
+
+        if (ch == ERR)      /* timed out waiting for valid sequence */
+        {                   /* flush input so far and start over    */
+            mode = M_NORMAL;
+            nocbreak();
+            raw();
+            ch = 27;
+            break;
+        }
+
+        if (mode == M_TRAIL)
+        {
+            if (ch == '^')              /* msys console  : 7,5,6,8: modified*/
+                ch = MOD_MOVE( toupper(lastch) );
+
+            if (ch == '~')              /* cygwin console: 1,5,6,4: normal  */
+                ch = tolower(lastch);   /* windows telnet: 1,5,6,4: normal  */
+                                        /* msys console  : 7,5,6,8: normal  */
+
+            if (mode2 == M_ESC)         /* cygwin console: 1,5,6,4: modified*/
+                ch = MOD_MOVE( toupper(ch) );
+
+            break;
+        }
+
+        if (mode == M_ESC)
+        {
+            if (ch == 27)
+            {
+                mode2 = M_ESC;
+                continue;
+            }
+
+            if ((ch == 'F') || (ch == 'O') || (ch == '['))
+            {
+                mode = M_KEYPAD;
+                continue;
+            }
+
+
+            switch(ch)
+            {
+                /* Cygwin Console   */
+                /* PuTTY            */
+                case KEY_LEFT : ch = MOD_MOVE('H'); break;
+                case KEY_RIGHT: ch = MOD_MOVE('L'); break;
+                case KEY_UP   : ch = MOD_MOVE('K'); break;
+                case KEY_DOWN : ch = MOD_MOVE('J'); break;
+                case KEY_HOME : ch = MOD_MOVE('Y'); break;
+                case KEY_PPAGE: ch = MOD_MOVE('U'); break;
+                case KEY_NPAGE: ch = MOD_MOVE('N'); break;
+                case KEY_END  : ch = MOD_MOVE('B'); break;
+
+                default: break;
+            }
+
+            break;
+        }
+
+        if (mode == M_KEYPAD)
+        {
+            switch(ch)
+            {
+                /* ESC F - Interix Console codes */
+                case   '^': ch = MOD_MOVE('H'); break;      /* Shift-Left       */
+                case   '$': ch = MOD_MOVE('L'); break;      /* Shift-Right      */
+
+                /* ESC [ - Interix Console codes */
+                case   'H': ch = 'y'; break;            /* Home             */
+                case     1: ch = MOD_MOVE('K'); break;      /* Ctl-Keypad Up    */
+                case     2: ch = MOD_MOVE('J'); break;      /* Ctl-Keypad Down  */
+                case     3: ch = MOD_MOVE('L'); break;      /* Ctl-Keypad Right */
+                case     4: ch = MOD_MOVE('H'); break;      /* Ctl-Keypad Left  */
+                case   263: ch = MOD_MOVE('Y'); break;      /* Ctl-Keypad Home  */
+                case    19: ch = MOD_MOVE('U'); break;      /* Ctl-Keypad PgUp  */
+                case    20: ch = MOD_MOVE('N'); break;      /* Ctl-Keypad PgDn  */
+                case    21: ch = MOD_MOVE('B'); break;      /* Ctl-Keypad End   */
+
+                /* ESC [ - Cygwin Console codes */
+                case   'G': ch = '.'; break;            /* Keypad 5         */
+                case   '7': lastch = 'Y'; mode=M_TRAIL; break;  /* Ctl-Home */
+                case   '5': lastch = 'U'; mode=M_TRAIL; break;  /* Ctl-PgUp */
+                case   '6': lastch = 'N'; mode=M_TRAIL; break;  /* Ctl-PgDn */
+
+                /* ESC [ - Win32 Telnet, PuTTY */
+                case   '1': lastch = 'y'; mode=M_TRAIL; break;  /* Home     */
+                case   '4': lastch = 'b'; mode=M_TRAIL; break;  /* End      */
+
+                /* ESC O - PuTTY */
+                case   'D': ch = MOD_MOVE('H'); break;
+                case   'C': ch = MOD_MOVE('L'); break;
+                case   'A': ch = MOD_MOVE('K'); break;
+                case   'B': ch = MOD_MOVE('J'); break;
+                case   't': ch = 'h'; break;
+                case   'v': ch = 'l'; break;
+                case   'x': ch = 'k'; break;
+                case   'r': ch = 'j'; break;
+                case   'w': ch = 'y'; break;
+                case   'y': ch = 'u'; break;
+                case   's': ch = 'n'; break;
+                case   'q': ch = 'b'; break;
+                case   'u': ch = '.'; break;
+            }
+
+            if (mode != M_KEYPAD)
+                continue;
+        }
+
+        if (ch == 27)
+        {
+            halfdelay(1);
+            mode = M_ESC;
+            continue;
+        }
+
+        switch(ch)
+        {
+            case KEY_LEFT   : ch = 'h'; break;
+            case KEY_DOWN   : ch = 'j'; break;
+            case KEY_UP     : ch = 'k'; break;
+            case KEY_RIGHT  : ch = 'l'; break;
+            case KEY_HOME   : ch = 'y'; break;
+            case KEY_PPAGE  : ch = 'u'; break;
+            case KEY_END    : ch = 'b'; break;
+#ifdef KEY_LL
+            case KEY_LL     : ch = 'b'; break;
+#endif
+            case KEY_NPAGE  : ch = 'n'; break;
+
+#ifdef KEY_B1
+            case KEY_B1     : ch = 'h'; break;
+            case KEY_C2     : ch = 'j'; break;
+            case KEY_A2     : ch = 'k'; break;
+            case KEY_B3     : ch = 'l'; break;
+#endif
+            case KEY_A1     : ch = 'y'; break;
+            case KEY_A3     : ch = 'u'; break;
+            case KEY_C1     : ch = 'b'; break;
+            case KEY_C3     : ch = 'n'; break;
+            /* next should be '.', but for problem with putty/linux */
+            case KEY_B2     : ch = 'u'; break;
+
+#ifdef KEY_SLEFT
+            case KEY_SRIGHT  : ch = MOD_MOVE('L'); break;
+            case KEY_SLEFT   : ch = MOD_MOVE('H'); break;
+#ifdef KEY_SUP
+            case KEY_SUP     : ch = MOD_MOVE('K'); break;
+            case KEY_SDOWN   : ch = MOD_MOVE('J'); break;
+#endif
+            case KEY_SHOME   : ch = MOD_MOVE('Y'); break;
+            case KEY_SPREVIOUS:ch = MOD_MOVE('U'); break;
+            case KEY_SEND    : ch = MOD_MOVE('B'); break;
+            case KEY_SNEXT   : ch = MOD_MOVE('N'); break;
+#endif
+            case 0x146       : ch = MOD_MOVE('K'); break;   /* Shift-Up     */
+            case 0x145       : ch = MOD_MOVE('J'); break;   /* Shift-Down   */
+
+#ifdef CTL_RIGHT
+            case CTL_RIGHT   : ch = MOD_MOVE('L'); break;
+            case CTL_LEFT    : ch = MOD_MOVE('H'); break;
+            case CTL_UP      : ch = MOD_MOVE('K'); break;
+            case CTL_DOWN    : ch = MOD_MOVE('J'); break;
+            case CTL_HOME    : ch = MOD_MOVE('Y'); break;
+            case CTL_PGUP    : ch = MOD_MOVE('U'); break;
+            case CTL_END     : ch = MOD_MOVE('B'); break;
+            case CTL_PGDN    : ch = MOD_MOVE('N'); break;
+#endif
+#ifdef KEY_EOL
+            case KEY_EOL     : ch = MOD_MOVE('B'); break;
+#endif
+
+#ifndef CTL_PAD1
+            /* MSYS rxvt console */
+            case 511         : ch = MOD_MOVE('J'); break; /* Shift Dn */
+            case 512         : ch = MOD_MOVE('J'); break; /* Ctl Down */
+            case 514         : ch = MOD_MOVE('H'); break; /* Ctl Left */
+            case 516         : ch = MOD_MOVE('L'); break; /* Ctl Right*/
+            case 518         : ch = MOD_MOVE('K'); break; /* Shift Up */
+            case 519         : ch = MOD_MOVE('K'); break; /* Ctl Up   */
+#endif
+
+#ifdef CTL_PAD1
+            case CTL_PAD1   : ch = MOD_MOVE('B'); break;
+            case CTL_PAD2   : ch = MOD_MOVE('J'); break;
+            case CTL_PAD3   : ch = MOD_MOVE('N'); break;
+            case CTL_PAD4   : ch = MOD_MOVE('H'); break;
+            case CTL_PAD5   : ch = '.'; break;
+            case CTL_PAD6   : ch = MOD_MOVE('L'); break;
+            case CTL_PAD7   : ch = MOD_MOVE('Y'); break;
+            case CTL_PAD8   : ch = MOD_MOVE('K'); break;
+            case CTL_PAD9   : ch = MOD_MOVE('U'); break;
+#endif
+
+#ifdef ALT_RIGHT
+            case ALT_RIGHT  : ch = MOD_MOVE('L'); break;
+            case ALT_LEFT   : ch = MOD_MOVE('H'); break;
+            case ALT_DOWN   : ch = MOD_MOVE('J'); break;
+            case ALT_HOME   : ch = MOD_MOVE('Y'); break;
+            case ALT_PGUP   : ch = MOD_MOVE('U'); break;
+            case ALT_END    : ch = MOD_MOVE('B'); break;
+            case ALT_PGDN   : ch = MOD_MOVE('N'); break;
+#endif
+
+#ifdef ALT_PAD1
+            case ALT_PAD1   : ch = MOD_MOVE('B'); break;
+            case ALT_PAD2   : ch = MOD_MOVE('J'); break;
+            case ALT_PAD3   : ch = MOD_MOVE('N'); break;
+            case ALT_PAD4   : ch = MOD_MOVE('H'); break;
+            case ALT_PAD5   : ch = '.'; break;
+            case ALT_PAD6   : ch = MOD_MOVE('L'); break;
+            case ALT_PAD7   : ch = MOD_MOVE('Y'); break;
+            case ALT_PAD8   : ch = MOD_MOVE('K'); break;
+            case ALT_PAD9   : ch = MOD_MOVE('U'); break;
+#endif
+        }
+
+        break;
+    }
+
+    nocbreak();     /* disable halfdelay mode if on */
+    raw();
+
+    return(ch & 0x7F);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/memory.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,420 @@
+/*
+    memory.c
+
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1995 Herb Chong
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "dict.h"
+#include "memory.h"
+#include "rogue.h"
+
+static char sccsid[] = "%W%\t%G%";
+
+/*	Debugging memory allocation code that tries to trap common memory problems
+	like overwriting storage and stepping on memory pointer chains. If code
+	doesn't use malloc, free, and realloc a lot, these routines can be left in
+	as added protection against undetected storage bugs.
+*/
+
+/* 	FENCE_SIZE should be a multiple of sizeof(size_t) to prevent alignment problems.
+	The code assumes that malloc and realloc return pointers aligned at least on size_t
+	sized boundaries and that a pointer needs alignment no more strict than that of an
+	object needed to hold a size_t.
+*/
+
+#define FENCE_SIZE (sizeof(size_t) * 1024)
+
+static int memdebug_level = 0;
+static DICTIONARY *allocations = NULL;
+static FILE *trace_file = NULL;
+
+/* set the debug level */
+void mem_debug(const int level)
+{
+	memdebug_level = level;
+
+	if (trace_file == NULL)
+		trace_file = fopen("trace", "w");
+
+	/* all except 0, 1, and unknown fall through */
+	switch(memdebug_level) {
+	case 2:
+		fprintf(trace_file, "+++ Memory tracking possible, ");
+	case 1:
+		fprintf(trace_file, "+++ Memory debugging enabled, ");
+		break;
+	case 0:
+		fprintf(trace_file, "+++ Memory debugging disabled, ");
+		break;
+	default:
+		fprintf(trace_file, "!!! Unknown memory debug level set, enabling level 1, ");
+		memdebug_level = 1;
+		break;
+	}
+	fprintf(trace_file, "fence size = %d\n", FENCE_SIZE);
+}
+
+/* set memory tracking on or off */
+/* turning it off deletes all tracking data */
+void mem_tracking(int flag)
+{
+	/* do nothing if debuglevel is too low */
+	if (memdebug_level < 2)
+		return;
+
+	/* turn on tracking */
+	if (flag > 0) {
+		if (allocations != NULL) {
+			dict_destroy(allocations);
+			allocations = NULL;
+		}
+		allocations = dict_create(8, 100, 4, 20);
+		if (allocations == NULL) {
+			fprintf(trace_file, "!!! Unable to allocate tracking table!\n");
+			abort();
+		}
+	}
+	/* turn off tracking */
+	else if (allocations != NULL) {
+		dict_destroy(allocations);
+		allocations = NULL;
+	}
+}
+
+/* go through all pointers and see if they are OK, aborting if not */
+/* always returns 1 if not aborting so that it can be included in  */
+/* if statement boolean expressions */
+int mem_check(char *fname, int linenum)
+{
+	STRING_ENTRY *se;
+
+	/* scan of a NULL dictionary always succeeds */
+	if (allocations == NULL)
+		return TRUE;
+
+	if (!dict_scan_begin(allocations)) {
+		fprintf(trace_file, "!!! Dictionary scan initialization failed!\n");
+		abort();
+	}
+
+	fprintf(trace_file, "\n+++ --- Starting pointer scan\n");
+	fprintf(trace_file, "+++ --- At %s, %d\n", fname, linenum);
+
+	/* mem_validate aborts if there is a problem */
+	while((se = dict_scan_next(allocations)) != NULL)
+		mem_validate(se->any_ptr);
+
+	fprintf(trace_file, "+++ --- Done pointer scan\n\n");
+
+	/* always return a good value if execution arrives here */
+	return 1;
+}
+
+/* allocate some memory and initialize header and trailer */
+void *mem_malloc(const size_t bytes)
+{
+	char *mem_temp;
+	size_t real_size = bytes + (FENCE_SIZE << 1);
+
+	/* allocate including guard bytes to detect some ways of overwriting of memory areas */
+	mem_temp = (void *)malloc(real_size);
+	if (memdebug_level > 0) {
+		fprintf(trace_file, "+++ Requested size of %ld bytes\n", bytes);
+		fprintf(trace_file, "+++ Actual malloc of %ld bytes located at %p\n", real_size, mem_temp);
+	}
+
+	/* if allocation succeeded, set management data */
+	if (mem_temp != NULL) {
+		size_t i;
+		char *end;
+
+		/* do beginning marker bytes */
+		for (i = 0; i < FENCE_SIZE - sizeof(size_t); i++)
+			*mem_temp++ = 145;
+
+		/* save size in header too */
+		if (memdebug_level > 0)
+			fprintf(trace_file, "*** Requested memory size stored at %p\n", mem_temp);
+		*(size_t *)mem_temp = bytes;
+
+		/* finally, point to storage we are going to hand out */
+		mem_temp += sizeof(size_t);
+
+		/* now, point to trailer bytes and do them */
+		end = mem_temp + bytes;
+		for (i = 0; i < FENCE_SIZE; i++)
+			*end++ = 145;
+
+		/* now zap contents to zero */
+		for (i = 0; i < bytes; i++)
+			mem_temp[i] = 0;
+	}
+
+	/* track pointer if needed */
+	if (memdebug_level > 1 && allocations != NULL) {
+		char key[16];
+		long temp;
+
+		sprintf(key, "%p", mem_temp);
+		if (dict_insert(allocations, key, 1, (const unsigned long) bytes, mem_temp, &temp) == NULL) {
+			fprintf(trace_file, "!!! Insert of pointer tracking info failed\n");
+			abort();
+		}
+	}
+
+	/* allow caller to do error handling */
+	if (memdebug_level > 0) {
+		fprintf(trace_file, "--- Returning pointer of %p\n", mem_temp);
+		fflush(trace_file);
+	}
+	return (void *)mem_temp;
+}
+
+/* release some memory, making sure that it was properly allocated */
+void mem_free(const void *ptr)
+{
+	char *mem_temp;
+	size_t mem_size;
+	size_t i;
+
+	if (memdebug_level > 0)
+		fprintf(trace_file, "+++ Free of memory located at %p\n", ptr);
+	if (ptr == NULL) {
+		if (memdebug_level > 0) {
+			fprintf(trace_file, "!!! Freeing NULL pointer\n");
+			fflush(trace_file);
+		}
+		abort();
+	}
+
+	mem_validate(ptr);	/* doesn't return on error */
+
+	/* get location of size of area */
+	mem_temp = (char *)ptr - sizeof(size_t);
+
+	/* get and calculate real size */
+	mem_size = *(size_t *)mem_temp + (FENCE_SIZE << 1);
+
+	/* if doing memory tracking */
+	if (memdebug_level > 1 && allocations != NULL) {
+		char key[16];
+		STRING_ENTRY *se;
+		long temp;
+
+		sprintf(key, "%p", ptr);
+
+		if ((se = dict_search(allocations, key, &temp)) == NULL) {
+			fprintf(trace_file, "!!! Deleting pointer not found in tracking info\n");
+			abort();
+		}
+
+		if (se->count == 0) {
+			fprintf(trace_file, "!!! Freeing a pointer that has already been freed!\n");
+			abort();
+		}
+		else if (se->flags != mem_size - (FENCE_SIZE << 1)) {
+			fprintf(trace_file, "!!! Stored size different from tracking size!\n");
+			abort();
+		}
+
+		/* remember deleted stuff by zeroing the allocation count */
+		se->count = 0;
+		se->flags = 0;
+	}
+
+	/* zap bytes being freed */
+	for (i = 0, mem_temp = (char *)ptr - FENCE_SIZE; i < mem_size; i++, mem_temp++)
+		*mem_temp = 243;
+
+	if (memdebug_level > 0)
+		fflush(trace_file);
+
+	mem_temp = (char *)ptr - FENCE_SIZE;
+	free((void *)mem_temp);
+}
+
+/* reallocate some memory, making sure that it was properly allocated */
+void *mem_realloc(const void *ptr, const size_t new_size)
+{
+	char *mem_temp = (char *)ptr;
+	size_t real_size = new_size + (FENCE_SIZE << 1);
+	size_t mem_size;
+	long i;
+
+	if (memdebug_level > 0) {
+		fprintf(trace_file, "+++ Requested size of %ld bytes\n", new_size);
+		fprintf(trace_file, "+++ Actual realloc of %ld bytes located at %p\n", real_size, mem_temp);
+	}
+	if (ptr == NULL) {
+		if (memdebug_level > 0) {
+			fprintf(trace_file, "!!! Reallocating NULL pointer\n");
+			fflush(trace_file);
+		}
+		abort();
+	}
+
+	mem_validate(ptr);	/* doesn't return on error */
+
+	/* if doing memory tracking */
+	if (memdebug_level > 1 && allocations != NULL) {
+		char key[16];
+		STRING_ENTRY *se;
+		long temp;
+
+		sprintf(key, "%p", ptr);
+
+		if ((se = dict_search(allocations, key, &temp)) == NULL) {
+			fprintf(trace_file, "!!! Deleting a pointer not found in tracking info!\n");
+			abort();
+		}
+
+		/* point to size bytes */
+		mem_temp = (char *)ptr - sizeof(size_t);
+
+		/* get user size */
+		mem_size = *(size_t *)mem_temp;
+
+		if (se->count == 0) {
+			fprintf(trace_file, "!!! Freeing a pointer that has already been freed!\n");
+			abort();
+		}
+		else if (se->flags != mem_size) {
+			fprintf(trace_file, "!!! Stored size different from tracking size!\n");
+			abort();
+		}
+
+		/* remember deleted stuff by zeroing the allocation count */
+		se->count = 0;
+		se->flags = 0;
+	}
+
+
+	/* header marker bytes will be copied by the realloc */
+	mem_temp = (char *)ptr - FENCE_SIZE;
+	mem_temp = realloc((void *)mem_temp, real_size);
+
+	if (mem_temp != NULL) {
+		char *end;
+
+		/* save size in header too */
+		mem_temp += FENCE_SIZE - sizeof(size_t);
+		if (memdebug_level > 0)
+			fprintf(trace_file, "*** Requested memory size stored at %p\n", mem_temp);
+		*(size_t *)mem_temp = new_size;
+
+		/* finally, point to storage we are going to hand out */
+		mem_temp += sizeof(size_t);
+
+		/* now, point to trailer bytes and do them */
+		end = mem_temp + new_size;
+		for (i = 0; i < FENCE_SIZE; i++)
+			*end++ = 145;
+	}
+
+	if (memdebug_level > 1 && allocations != NULL) {
+		char key[16];
+		long temp;
+
+		sprintf(key, "%p", mem_temp);
+		if (dict_insert(allocations, key, 1, (const unsigned long)new_size, mem_temp, &temp) == NULL) {
+			fprintf(trace_file, "!!! Insert of pointer tracking info failed\n");
+			abort();
+		}
+	}
+
+	if (memdebug_level > 0) {
+		fprintf(trace_file, "--- Returning pointer of %p\n", mem_temp);
+		fflush(trace_file);
+	}
+	return (void *)mem_temp;
+}
+
+/* check a pointer to be sure all check bytes are OK. abort if not */
+/* always returns 1 if not aborting so that it can be included in  */
+/* if statement boolean expressions */
+int mem_validate(void *ptr)
+{
+	unsigned char *mem_temp = (unsigned char *)ptr;
+	size_t mem_size;
+	size_t i;
+
+	/* NULL pointers are always valid */
+	if (ptr == NULL)
+		return 1;
+
+	if (memdebug_level > 0)
+		fprintf(trace_file, "+++ Checking %p as pointer\n", ptr);
+
+
+	if (memdebug_level > 1 && allocations != NULL) {
+		char key[16];
+		STRING_ENTRY *se;
+		long temp;
+
+		sprintf(key, "%p", ptr);
+
+		if ((se = dict_search(allocations, key, &temp)) == NULL) {
+			fprintf(trace_file, "!!! Pointer not found in tracking info!\n");
+			abort();
+		}
+
+		/* point to size bytes */
+		mem_temp = (unsigned char *)ptr - sizeof(size_t);
+
+		/* get user size */
+		mem_size = *(size_t *)mem_temp;
+
+		if (se->count == 0) {
+			fprintf(trace_file, "!!! Checking pointer has been freed!\n");
+			abort();
+		}
+		else if (se->flags != mem_size) {
+			fprintf(trace_file, "!!! Stored size different from tracking size!\n");
+			abort();
+		}
+	}
+
+	/* check the header bytes */
+	mem_temp = (unsigned char *) ptr - FENCE_SIZE;
+	if (memdebug_level > 0)
+		fprintf(trace_file, "+++ Real pointer at %p\n", mem_temp);
+
+
+	for (i = 0; i < FENCE_SIZE - sizeof(size_t); i++)
+		if (*mem_temp++ != 145) {
+			if (memdebug_level > 0) {
+				fprintf(trace_file, "!!! The user pointer at %p has been overwritten\n", ptr);
+				fprintf(trace_file, "!!! Header offset %ld has been changed\n", i - 1);
+				fflush(trace_file);
+			}
+			abort();
+		}
+
+	/* check size */
+	i = *(size_t *)mem_temp;
+	if (memdebug_level > 0)
+		fprintf(trace_file, "*** Stored memory size of %ld bytes in header\n", i);
+
+
+	/* now point to where trailer should be */
+	mem_temp = (unsigned char *)ptr + i;
+	for (i = 0; i < FENCE_SIZE; i++)
+		if (*mem_temp++ != 145) {
+			if (memdebug_level > 0) {
+				fprintf(trace_file, "!!! The user pointer at %p has been overwritten\n", ptr);
+				fprintf(trace_file, "!!! Trailer offset %ld has been changed\n", i - 1);
+				fflush(trace_file);
+			}
+			abort();
+		}
+	if (memdebug_level > 0)
+		fflush(trace_file);
+	return 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/misc.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1208 @@
+/*
+    misc.c - all sorts of miscellaneous routines
+  
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+    tr_name()
+        print the name of a trap
+*/
+
+char *
+tr_name(char ch, char *trname)
+{
+    const char *s = NULL;
+
+    if (trname == NULL)
+        return(" Your found an error in UltraRogue #100.");
+
+    switch(ch)
+    {
+        case TRAPDOOR:
+            s = "trapdoor.";
+            break;
+        case BEARTRAP:
+            s = "beartrap.";
+            break;
+        case SLEEPTRAP:
+            s = "sleeping gas trap.";
+            break;
+        case ARROWTRAP:
+            s = "arrow trap.";
+            break;
+        case TELTRAP:
+            s = "teleport trap.";
+            break;
+        case DARTTRAP:
+            s = "dart trap.";
+            break;
+        case POOL:
+            s = "shimmering pool.";
+            break;
+        case MAZETRAP:
+            s = "maze entrance.";
+            break;
+        case FIRETRAP:
+            s = "fire trap.";
+            break;
+        case POISONTRAP:
+            s = "poison pool trap.";
+            break;
+        case LAIR:
+            s = "monster lair.";
+            break;
+        case RUSTTRAP:
+            s = "rust trap.";
+            break;
+        default:
+            ;
+    }
+
+    sprintf(trname, "You found a %s.", s);
+
+    return(trname);
+}
+
+/*
+    look()
+        A quick glance all around the player
+*/
+
+void
+look(int wakeup)
+{
+    int     x, y;
+    char   ch, och;
+    int  oldx, oldy;
+    int inpass, horizontal, vertical, do_light = FALSE, do_blank = FALSE;
+    int passcount = 0;
+    struct room *rp;
+    int ey, ex;
+
+    /* Are we moving vertically or horizontally? */
+
+    if (runch == 'h' || runch == 'l')
+        horizontal = TRUE;
+    else
+        horizontal = FALSE;
+
+    if (runch == 'j' || runch == 'k')
+        vertical = TRUE;
+    else
+        vertical = FALSE;
+
+    getyx(cw, oldy, oldx);  /* Save current position */
+
+    /*
+     * Blank out the floor around our last position and check for moving
+     * out of a corridor in a maze.
+    */
+
+    if (oldrp != NULL && (oldrp->r_flags & ISDARK) &&
+        !(oldrp->r_flags & HASFIRE) && off(player, ISBLIND))
+        do_blank = TRUE;
+
+    for (x = player.t_oldpos.x - 1; x <= player.t_oldpos.x + 1; x++)
+        for (y = player.t_oldpos.y - 1; y <= player.t_oldpos.y + 1;
+                y++)
+        {
+            ch = show(y, x);
+
+            if (do_blank && (y != hero.y || x != hero.x) && ch == FLOOR)
+                mvwaddch(cw, y, x, ' ');
+
+            /* Moving out of a corridor? */
+
+            if (levtype == MAZELEV &&
+                (ch != '|' && ch != '-') && /* Not a wall */
+                ((vertical && x != player.t_oldpos.x &&
+                y == player.t_oldpos.y) ||
+                 (horizontal && y != player.t_oldpos.y &&
+                x == player.t_oldpos.x)))
+                do_light = TRUE;    /* Just came to a turn */
+        }
+
+    inpass = ((rp = roomin(hero)) == NULL);    /* Are we in a passage? */
+
+    /* Are we coming out of a wall into a corridor in a maze? */
+    och = show(player.t_oldpos.y, player.t_oldpos.x);
+    ch = show(hero.y, hero.x);
+
+    if (levtype == MAZELEV && (och == '|' || och == '-' ||
+        och == SECRETDOOR) && (ch != '|' && ch != '-' && ch != SECRETDOOR))
+    {
+        do_light = off(player, ISBLIND);    /* Light it up if not blind */
+    }
+
+    /* Look around the player */
+
+    ey = hero.y + 1;
+    ex = hero.x + 1;
+
+    for (x = hero.x - 1; x <= ex; x++)
+        if (x >= 0 && x < COLS)
+            for (y = hero.y - 1; y <= ey; y++)
+            {
+                if (y <= 0 || y >= LINES - 2)
+                    continue;
+
+                if (isalpha(mvwinch(mw, y, x)))
+                {
+                    struct linked_list  *it;
+                    struct thing    *tp;
+
+                    if (wakeup)
+                        it = wake_monster(y, x);
+                    else
+                        it = find_mons(y, x);
+
+                    if (it == NULL)
+                        continue;
+
+                    tp = THINGPTR(it);
+                    tp->t_oldch = CCHAR( mvinch(y, x) );
+
+                    if (isatrap(tp->t_oldch))
+                    {
+                        struct trap *trp = trap_at(y, x);
+
+                        tp->t_oldch = (trp->tr_flags & ISFOUND) ? tp->t_oldch
+                            : trp->tr_show;
+                    }
+
+                    if (tp->t_oldch == FLOOR &&
+                        (rp->r_flags & ISDARK)
+                        && !(rp->r_flags & HASFIRE) &&
+                        off(player, ISBLIND))
+                        tp->t_oldch = ' ';
+                }
+
+                /* Secret doors show as walls */
+
+                if ((ch = show(y, x)) == SECRETDOOR)
+                    ch = secretdoor(y, x);
+
+                /*
+                 * Don't show room walls if he is in a
+                 * passage and check for maze turns
+                */
+
+                if (off(player, ISBLIND))
+                {
+                    if (y == hero.y && x == hero.x || (inpass && (ch == '-' ||
+                        ch == '|')))
+                        continue;
+
+                    /* Are we at a crossroads in a maze? */
+
+                    if (levtype == MAZELEV && (ch != '|' && ch != '-') &&
+                        /* Not a wall */
+                        ((vertical && x != hero.x && y == hero.y) ||
+                         (horizontal && y != hero.y && x == hero.x)))
+                        do_light = TRUE;
+                        /* Just came to a turn */
+                }
+                else if (y != hero.y || x != hero.x)
+                    continue;
+
+                wmove(cw, y, x);
+                waddch(cw, ch);
+
+                if (door_stop && !firstmove && running)
+                {
+                    switch (runch)
+                    {
+                        case 'h':
+                            if (x == ex)
+                                continue;
+                            break;
+                        case 'j':
+                            if (y == hero.y - 1)
+                                continue;
+                            break;
+                        case 'k':
+                            if (y == ey)
+                                continue;
+                            break;
+                        case 'l':
+                            if (x == hero.x - 1)
+                                continue;
+                            break;
+                        case 'y':
+                            if ((x + y) - (hero.x + hero.y) >= 1)
+                                continue;
+                            break;
+                        case 'u':
+                            if ((y - x) - (hero.y - hero.x) >= 1)
+                                continue;
+                            break;
+                        case 'n':
+                            if ((x + y) - (hero.x + hero.y) <= -1)
+                                continue;
+                            break;
+                        case 'b':
+                            if ((y - x) - (hero.y - hero.x) <= -1)
+                                continue;
+                            break;
+                    }
+
+                    switch (ch)
+                    {
+                        case DOOR:
+                            if (x == hero.x || y == hero.y)
+                                running = FALSE;
+                            break;
+                        case PASSAGE:
+                            if (x == hero.x || y == hero.y)
+                                passcount++;
+                            break;
+                        case FLOOR:
+
+                        /*
+                         * Stop by new passages in a
+                         * maze (floor next to us)
+                         */
+                            if ((levtype == MAZELEV) &&
+                                ((horizontal && x == hero.x && y != hero.y) ||
+                                (vertical &&   y == hero.y && x != hero.x)))
+                                running = FALSE;
+
+                        case '|':
+                        case '-':
+                        case ' ':
+                            break;
+
+                        default:
+                            running = FALSE;
+                            break;
+                    }
+                }
+            }
+
+    if (door_stop && !firstmove && passcount > 1)
+        running = FALSE;
+
+    /*
+     * Do we have to light up the area (just stepped into a new
+     * corridor)?
+     */
+
+    if (do_light && wakeup &&   /* wakeup will be true on a normal move */
+        !(rp->r_flags & ISDARK) &&  /* We have some light */
+        !ce(hero, player.t_oldpos)) /* Don't do anything if we didn't move */
+        light(&hero);
+
+    mvwaddch(cw, hero.y, hero.x, PLAYER);
+    wmove(cw, oldy, oldx);
+
+    if (wakeup)
+    {
+        player.t_oldpos = hero; /* Don't change if we didn't move */
+        oldrp = rp;
+    }
+}
+
+/*
+    secret_door()
+        Figure out what a secret door looks like.
+*/
+
+char
+secretdoor(int y, int x)
+{
+    struct room *rp;
+    coord cp;
+
+    cp.x = x;
+    cp.y = y;
+
+    if ((rp = roomin(cp)) != NULL)
+    {
+        if (y == rp->r_pos.y || y == rp->r_pos.y + rp->r_max.y - 1)
+            return ('-');
+        else
+            return ('|');
+    }
+    return ('p');
+}
+
+/*
+    find_obj()
+        find the unclaimed object at y, x
+*/
+
+struct linked_list  *
+find_obj(int y, int x)
+{
+    struct linked_list  *obj, *sobj;
+    struct object   *op;
+
+    sobj = lvl_obj;
+
+    for (obj = sobj; obj != NULL; obj = next(obj))
+    {
+        op = OBJPTR(obj);
+
+        if (op && op->o_pos.y == y && op->o_pos.x == x)
+            return(obj);
+    }
+
+    return(NULL);
+}
+
+/*
+    eat()
+        He wants to eat something, so let him try
+*/
+
+void
+eat(void)
+{
+    struct object   *obj;
+    int amount;
+    float scale = (float) (LINES * COLS) / (25.0F * 80.0F);
+
+    if ((obj = get_object(pack, "eat", FOOD, NULL)) == NULL)
+        return;
+
+    switch (obj->o_which)
+    {
+        case FD_RATION:
+            amount = (int)(scale * (HUNGERTIME + rnd(400) - 200));
+
+            if (rnd(100) > 70)
+            {
+                msg("Yuk, this food tastes awful.");
+                pstats.s_exp++;
+                check_level();
+            }
+            else
+                msg("Yum, that tasted good.");
+            break;
+
+        case FD_FRUIT:
+            amount = (int)(scale * (200 + rnd(HUNGERTIME)));
+            msg("My, that was a yummy %s.", fruit);
+            break;
+
+        case FD_CRAM:
+            amount = (int)(scale * (rnd(HUNGERTIME / 2) + 600));
+            msg("The cram tastes dry in your mouth.");
+            break;
+
+        case FD_CAKES:
+            amount = (int)(scale * ((HUNGERTIME / 3) + rnd(600)));
+            msg("Yum, the honey cakes tasted good.");
+            break;
+
+        case FD_LEMBA:
+            amount = (int)(scale * ((HUNGERTIME / 2) + rnd(900)));
+            quaff(&player, P_HEALING, ISNORMAL);
+            break;
+
+        case FD_MIRUVOR:
+            amount = (int)(scale * ((HUNGERTIME / 3) + rnd(500)));
+            quaff(&player, P_HEALING, ISNORMAL);
+            quaff(&player, P_RESTORE, ISNORMAL);
+            break;
+
+        default:
+            msg("What a strange thing to eat!");
+            amount = (int)(scale * HUNGERTIME);
+    }
+    
+    food_left += amount;
+
+    if (obj->o_flags & ISBLESSED)
+    {
+        food_left += 2 * amount;
+        msg("You have a tingling feeling in your mouth.");
+    }
+    else if (food_left > scale * STOMACHSIZE)
+    {
+        food_left = (int)(scale * STOMACHSIZE);
+        msg("You feel satiated and too full to move.");
+        no_command = HOLDTIME;
+    }
+
+    hungry_state = F_OK;
+    updpack();
+
+    if (obj == cur_weapon)
+        cur_weapon = NULL;
+
+    if (--obj->o_count <= 0) /* Remove this pack entry if last of food */
+        discard_pack(obj);
+}
+
+/*
+ * Used to modify the player's strength it keeps track of the highest it has
+ * been, just in case
+ */
+
+void
+chg_str(int amt, int both, int lost)
+{
+    int           ring_str; /* ring strengths */
+    struct stats *ptr;      /* for speed */
+
+    ptr = &pstats;
+
+    ring_str = ring_value(R_ADDSTR) + (on(player, POWERSTR) ? 10 : 0) +
+        (on(player, SUPERHERO) ? 10 : 0);
+
+    ptr->s_str -= ring_str;
+    ptr->s_str += amt;
+
+    if (ptr->s_str < 3)
+    {
+        ptr->s_str = 3;
+        lost = FALSE;
+    }
+    else if (ptr->s_str > 25)
+        ptr->s_str = 25;
+
+    if (both)
+        max_stats.s_str = ptr->s_str;
+
+    if (lost)
+        lost_str -= amt;
+
+    ptr->s_str += ring_str;
+
+    if (ptr->s_str < 0)
+        ptr->s_str = 0;
+
+    updpack();
+}
+
+/*
+ * Used to modify the player's dexterity it keeps track of the highest it has
+ * been, just in case
+ */
+
+void
+chg_dext(int amt, int both, int lost)
+{
+    int ring_dext;      /* ring strengths   */
+    struct stats *ptr;  /* for speed        */
+
+    ptr = &pstats;
+
+    ring_dext = ring_value(R_ADDHIT) + (on(player, POWERDEXT) ? 10 : 0) +
+        (on(player, SUPERHERO) ? 5 : 0);
+
+    ptr->s_dext -= ring_dext;
+    ptr->s_dext += amt;
+
+    if (ptr->s_dext < 3)
+    {
+        ptr->s_dext = 3;
+        lost = FALSE;
+    }
+    else if (ptr->s_dext > 25)
+        ptr->s_dext = 25;
+
+    if (both)
+        max_stats.s_dext = ptr->s_dext;
+
+    if (lost)
+        lost_dext -= amt;
+
+    ptr->s_dext += ring_dext;
+
+    if (ptr->s_dext < 0)
+        ptr->s_dext = 0;
+}
+
+/*
+    add_haste()
+        add a haste to the player
+*/
+
+void
+add_haste(int blessed)
+{
+    short   hasttime;
+
+    if (blessed)
+        hasttime = 10;
+    else
+        hasttime = 6;
+
+    if (on(player, ISSLOW))    /* Is person slow? */
+    {
+        extinguish_fuse(FUSE_NOSLOW);
+        noslow(NULL);
+
+        if (blessed)
+            hasttime = 4;
+        else
+            return;
+    }
+
+    if (on(player, ISHASTE))
+    {
+        msg("You faint from exhaustion.");
+        no_command += rnd(hasttime);
+        lengthen_fuse(FUSE_NOHASTE, rnd(hasttime) + (roll(1, 4) * hasttime));
+    }
+    else
+    {
+        turn_on(player, ISHASTE);
+        light_fuse(FUSE_NOHASTE, 0, roll(hasttime, hasttime), AFTER);
+    }
+}
+
+/*
+    aggravate()
+        aggravate all the monsters on this level
+*/
+
+void
+aggravate(void)
+{
+    struct linked_list *mi;
+    struct thing *tp;
+
+    for (mi = mlist; mi != NULL; mi = next(mi))
+    {
+        tp = THINGPTR(mi);
+        chase_it(&tp->t_pos, &player);
+    }
+}
+
+/*
+    vowelstr()
+        for printfs: if string starts with a vowel, return "n" for an "an"
+*/
+
+char *
+vowelstr(char *str)
+{
+    switch (*str)
+    {
+        case 'a':
+        case 'A':
+        case 'e':
+        case 'E':
+        case 'i':
+        case 'I':
+        case 'o':
+        case 'O':
+        case 'u':
+        case 'U':
+            return "n";
+        default:
+            return "";
+    }
+}
+
+/*
+    is_object()
+        see if the object is one of the currently used items
+*/
+
+int
+is_current(struct object *obj)
+{
+    if (obj == NULL)
+        return FALSE;
+
+    if (obj == cur_armor || obj == cur_weapon ||
+        obj == cur_ring[LEFT_1] || obj == cur_ring[LEFT_2] ||
+        obj == cur_ring[LEFT_3] || obj == cur_ring[LEFT_4] ||
+        obj == cur_ring[LEFT_5] ||
+        obj == cur_ring[RIGHT_1] || obj == cur_ring[RIGHT_2] ||
+        obj == cur_ring[RIGHT_3] || obj == cur_ring[RIGHT_4] ||
+        obj == cur_ring[RIGHT_5]) {
+        msg("That's already in use.");
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+/*
+    get_dir()
+        set up the direction co_ordinate for use in varios "prefix" commands
+*/
+
+int
+get_dir(void)
+{
+    char *prompt;
+    int   gotit;
+
+    prompt = "Which direction? ";
+    msg(prompt);
+
+    do
+    {
+        gotit = TRUE;
+
+        switch (readchar())
+        {
+            case 'h':
+            case 'H':
+                delta.y = 0;
+                delta.x = -1;
+                break;
+
+            case 'j':
+            case 'J':
+                delta.y = 1;
+                delta.x = 0;
+                break;
+
+            case 'k':
+            case 'K':
+                delta.y = -1;
+                delta.x = 0;
+                break;
+
+            case 'l':
+            case 'L':
+                delta.y = 0;
+                delta.x = 1;
+                break;
+
+            case 'y':
+            case 'Y':
+                delta.y = -1;
+                delta.x = -1;
+                break;
+
+            case 'u':
+            case 'U':
+                delta.y = -1;
+                delta.x = 1;
+                break;
+				
+            case 'b':
+            case 'B':
+                delta.y = 1;
+                delta.x = -1;
+                break;
+				
+            case 'n':
+            case 'N':
+                delta.y = 1;
+                delta.x = 1;
+                break;
+				
+            case  ESCAPE:
+                return FALSE;
+
+            default:
+                mpos = 0;
+                msg(prompt);
+                gotit = FALSE;
+        }
+    }
+    while(!gotit);
+
+    if (on(player, ISHUH) && rnd(100) > 80)
+        do
+        {
+            delta.y = rnd(3) - 1;
+            delta.x = rnd(3) - 1;
+        }
+        while (delta.y == 0 && delta.x == 0);
+
+    mpos = 0;
+
+    return(TRUE);
+}
+
+/*
+    is_wearing()
+        is the hero wearing a particular ring
+*/
+
+int
+is_wearing(int type)
+{
+#define ISRING(h, r) (cur_ring[h] != NULL && cur_ring[h]->o_which == r)
+
+    return(
+        ISRING(LEFT_1,  type) || ISRING(LEFT_2, type) ||
+        ISRING(LEFT_3,  type) || ISRING(LEFT_4, type) ||
+        ISRING(LEFT_5,  type) ||
+        ISRING(RIGHT_1, type) || ISRING(RIGHT_2, type) ||
+        ISRING(RIGHT_3, type) || ISRING(RIGHT_4, type) ||
+        ISRING(RIGHT_5, type)  );
+}
+
+/*
+    maze_view()
+        Returns true if the player can see the specified location
+        within the confines of a maze (within one column or row)
+*/
+
+int
+maze_view(int y, int x)
+{
+    int start, goal, delt, ycheck = 0, xcheck = 0, absy, absx;
+    int row;
+
+    /* Get the absolute value of y and x differences */
+
+    absy = hero.y - y;
+    absx = hero.x - x;
+
+    if (absy < 0)
+        absy = -absy;
+
+    if (absx < 0)
+        absx = -absx;
+
+    /* Must be within one row or column */
+
+    if (absy > 1 && absx > 1)
+        return(FALSE);
+
+    if (absy <= 1)      /* Go along row */
+    {
+        start = hero.x;
+        goal = x;
+        row = TRUE;
+        ycheck = hero.y;
+    }
+    else            /* Go along column */
+    {
+        start = hero.y;
+        goal = y;
+        row = FALSE;
+        xcheck = hero.x;
+    }
+
+    if (start <= goal)
+        delt = 1;
+    else
+        delt = -1;
+
+    while (start != goal)
+    {
+        if (row)
+            xcheck = start;
+        else
+            ycheck = start;
+
+        switch(CCHAR(winat(ycheck, xcheck)))
+        {
+            case '|':
+            case '-':
+            case WALL:
+            case DOOR:
+            case SECRETDOOR:
+                return(FALSE);
+
+            default:
+                break;
+        }
+        start += delt;
+    }
+
+    return(TRUE);
+}
+
+/*
+    listen()
+        listen for monsters less than 5 units away
+*/
+
+void
+listen(void)
+{
+    struct linked_list  *item;
+    struct thing    *tp;
+    int thief_bonus = -50;
+    int mcount = 0;
+
+    if (player.t_ctype == C_THIEF)
+        thief_bonus = 10;
+
+    for (item = mlist; item != NULL; item = next(item))
+    {
+        tp = THINGPTR(item);
+
+        if (DISTANCE(hero, tp->t_pos) < 81
+            && rnd(70) < (thief_bonus + 4 * pstats.s_dext +
+            6 * pstats.s_lvl))
+        {
+            msg("You hear a%s %s nearby.",
+                vowelstr(monsters[tp->t_index].m_name),
+                monsters[tp->t_index].m_name);
+            mcount++;
+        }
+    }
+
+    if (mcount == 0)
+        msg("You hear nothing.");
+}
+
+/*
+ * nothing_message - print out "Nothing <adverb> happens."
+ */
+
+static const char *nothings[] =
+{
+    "",
+    "unusual ",
+    "seems to ",
+    "at all ",
+    "really ",
+    "noticeable ",
+    "different ",
+    "strange ",
+    "wierd ",
+    "bizzare ",
+    "wonky ",
+    ""
+};
+
+void
+nothing_message(int flags)
+{
+    int adverb = rnd(sizeof(nothings) / sizeof(char *));
+
+    NOOP(flags);   
+
+    msg("Nothing %shappens.", nothings[adverb]);
+}
+
+/*
+    feel_message()
+        print out "You feel <description>."
+*/
+
+void
+feel_message(void)
+{
+    char *charp;
+
+    switch (rnd(25))
+    {
+        case 1:  charp = "bad";      break;
+        case 2:  charp = "hurt";     break;
+        case 3:  charp = "sick";     break;
+        case 4:  charp = "faint";    break;
+        case 5:  charp = "yucky";    break;
+        case 6:  charp = "wonky";    break;
+        case 7:  charp = "wierd";    break;
+        case 8:  charp = "queasy";   break;
+        case 9:  charp = "wounded";  break;
+        case 11: charp = "unusual";  break;
+        case 12: charp = "no pain";  break;
+        case 13: charp = "strange";  break;
+        case 14: charp = "noticable"; break;
+        case 15: charp = "bizzare";   break;
+        case 16: charp = "distressed";break;
+        case 17: charp = "different"; break;
+        case 18: charp = "a touch of ague"; break;
+        case 19: charp = "a migrane coming on"; break;
+        case 20: charp = "Excedrin headache #666"; break;
+        case 21: charp = "a disturbance in the force"; break;
+        case 22: charp = "like someone dropped a house on you"; break;
+        case 23: charp = "as if every nerve in your body is on fire"; break;
+        case 24: charp = "like thousands of red-hot army ants are crawling under your skin";
+                    break;
+
+        default:
+            charp = "ill";
+            break;
+    }
+    msg("You feel %s.", charp);
+}
+
+/*
+    const_bonus()
+        Hit point adjustment for changing levels
+*/
+
+int
+const_bonus(void)
+{
+    int ret_val = -2;
+
+    if (pstats.s_const > 12)
+        ret_val = pstats.s_const - 12;
+    else if (pstats.s_const > 6)
+        ret_val = 0;
+    else if (pstats.s_const > 3)
+        ret_val = -1;
+
+    return(ret_val);
+}
+
+/*
+    int_wis_bonus()
+        Spell point adjustment for changing levels
+*/
+
+int
+int_wis_bonus(void)
+{
+    int ret_val = -2;
+    int casters_stat;
+
+    switch (player.t_ctype)
+    {
+        case C_PALADIN:
+        case C_CLERIC:
+            casters_stat = pstats.s_wisdom;
+            break;
+        case C_RANGER:
+        case C_DRUID:
+            casters_stat = pstats.s_wisdom;
+            break;
+        case  C_MAGICIAN:
+            casters_stat = pstats.s_intel;
+            break;
+        case  C_ILLUSION:
+            casters_stat = pstats.s_intel;
+            break;
+
+        default:
+            if (is_wearing(R_WIZARD))
+                casters_stat = pstats.s_intel;
+            else if (is_wearing(R_PIETY))
+                casters_stat = pstats.s_wisdom;
+            else
+                casters_stat = (rnd(2) ? pstats.s_wisdom :
+                    pstats.s_intel);
+    }
+
+    if (casters_stat > 12)
+        ret_val = casters_stat - 12;
+    else if (casters_stat > 6)
+        ret_val = 0;
+    else if (casters_stat > 3)
+        ret_val = -1;
+
+    return(ret_val);
+}
+
+void
+electrificate(void)
+{
+    int affect_dist = 4 + player.t_stats.s_lvl / 4;
+    struct linked_list  *item, *nitem;
+
+    for (item = mlist; item != NULL; item = nitem)
+    {
+        struct thing *tp = THINGPTR(item);
+        char *mname = monsters[tp->t_index].m_name;
+
+        nitem = next(item);
+
+        if (DISTANCE(tp->t_pos, hero) < affect_dist)
+        {
+            int damage = roll(2, player.t_stats.s_lvl);
+
+            debug("Charge does %d (%d)", damage, tp->t_stats.s_hpt - damage);
+
+            if (on(*tp, NOBOLT))
+                continue;
+
+            if ((tp->t_stats.s_hpt -= damage) <= 0)
+            {
+                msg("The %s is killed by an electric shock.", mname);
+                killed(&player, item, NOMESSAGE, POINTS);
+                continue;
+            }
+
+            if (rnd(tp->t_stats.s_intel / 5) == 0)
+            {
+                turn_on(*tp, ISFLEE);
+                msg("The %s is shocked by electricity.", mname);
+            }
+            else
+                msg("The %s is zapped by your electricity.", mname);
+
+            summon_help(tp, NOFORCE);
+            turn_off(*tp, ISFRIENDLY);
+            turn_off(*tp, ISCHARMED);
+            turn_on(*tp, ISRUN);
+            turn_off(*tp, ISDISGUISE);
+            chase_it(&tp->t_pos, &player);
+            fighting = after = running = FALSE;
+        }
+    }
+}
+
+/*
+    feed_me -    Print out interesting messages about food consumption
+*/
+
+static char *f_hungry[] =
+{
+    "want a cookie",
+    "feel like a snack",
+    "feel like some fruit",
+    "start having the munchies",
+    "are starting to get hungry"
+};
+
+static char *f_weak[] =
+{
+    "are really hungry",
+    "could eat a horse",
+    "want some food - now",
+    "are starting to feel weak",
+    "feel a gnawing in your stomach",
+    "are even willing to eat up cram",
+    "feel lightheaded from not eating"
+};
+
+static char *f_faint[] =
+{
+    "get dizzy from not eating",
+    "are starving for nutrients",
+    "feel too weak from lack of food",
+    "see a mirage of an incredible banquet",
+    "have incredible cramps in your stomach"
+};
+
+static char *f_plop[] =
+{
+    "faint",
+    "pass out",
+    "keel over",
+    "black out"
+};
+
+void
+feed_me(int hunger)
+{
+    char    *charp = NULL, *charp2 = NULL;
+
+    switch (hunger)
+    {
+        case F_OK:
+        default:
+            debug("feed_me(%d) called.", hunger);
+            break;
+
+        case  F_HUNGRY:
+            charp = f_hungry[rnd(sizeof(f_hungry) /
+                sizeof(char *))];
+            break;
+
+        case  F_WEAK:
+            charp = f_weak[rnd(sizeof(f_weak) / sizeof(char *))];
+            break;
+
+        case F_FAINT:
+            charp = f_faint[rnd(sizeof(f_faint) / sizeof(char *))];
+            charp2 = f_plop[rnd(sizeof(f_plop) / sizeof(char *))];
+            break;
+    }
+
+    msg("You %s.", charp);
+
+    if (hunger == F_FAINT)
+        msg("You %s.", charp2);
+}
+
+
+/*
+    get_monster_number()
+        prompt player for a monster on list returns 0 if none selected
+*/
+
+int
+get_monster_number(char *message)
+{
+    int  i;
+    int  pres_monst = 1;
+    int  ret_val = -1;
+    char buf[2 * LINELEN];
+    char monst_name[2 * LINELEN];
+
+    while (ret_val == -1)
+    {
+        msg("Which monster do you wish to %s? (* for list)", message);
+
+        if ((get_string(buf, cw)) != NORM)
+            return(0);
+
+        if ((i = atoi(buf)) != 0)
+            ret_val = i;
+        else if (buf[0] != '*')
+        {
+            for (i = 1; i < nummonst; i++)
+                if ((strcmp(monsters[i].m_name, buf) == 0))
+                    ret_val = i;
+        }
+        /* The following hack should be redone by the windowing code */
+        else
+            while (pres_monst < nummonst)   /* Print out the monsters */
+            {
+                int num_lines = LINES - 3;
+
+                wclear(hw);
+                touchwin(hw);
+
+                wmove(hw, 2, 0);
+
+                for (i = 0; i < num_lines && pres_monst < nummonst; i++)
+                {
+                    sprintf(monst_name, "[%d] %s\n", pres_monst,
+                        monsters[pres_monst].m_name);
+                    waddstr(hw, monst_name);
+                    pres_monst++;
+                }
+
+                if (pres_monst < nummonst)
+                {
+                    mvwaddstr(hw, LINES - 1, 0, morestr);
+                    wrefresh(hw);
+                    wait_for(' ');
+                }
+                else
+                {
+                    mvwaddstr(hw, 0, 0, "Which monster");
+                    waddstr(hw, "? ");
+                    wrefresh(hw);
+                }
+            }
+
+get_monst:
+        get_string(monst_name, hw);
+        ret_val = atoi(monst_name);
+
+        if ((ret_val < 1 || ret_val > nummonst - 1))
+        {
+            mvwaddstr(hw, 0, 0, "Please enter a number in the displayed range -- ");
+            wrefresh(hw);
+            goto get_monst;
+        }
+
+        /* Set up for redraw */
+
+        clearok(cw, TRUE);
+        touchwin(cw);
+    }
+
+    return(ret_val);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/monsdata.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,2878 @@
+/*
+    monsdata.c - monster data initializer
+   
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include "rogue.h"
+
+#define HPT(x) x
+
+/* {"Name",
+        CARRY_PROB, NORMAL, WANDER, SYMBOL, INTELLIGENCE,
+        {ATTRIBUTE_FLAGS},
+        CREATURE_SUMMONED, NUMBER_SUMMONED,
+        ADDED_EXPERIENCE_PER_HIT_POINT,
+        {str,   exp_pts, exp_level, armor_class, hit_points,
+        "damage"}
+},
+*/
+
+struct monster monsters[] =
+{
+{"the player",
+        0,  FALSE,  FALSE,  '\0',   "",
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+        0, 0,
+        0,
+        {10,    0,  0,  0,  HPT(""), ""}
+},
+{"bat",
+        0,  TRUE,   FALSE,  'B',    "2-4",
+        {ISMEAN, CANFLY, ISHUH, CANDISEASE, ISFLOCK, ISSMALL},
+        0, 0,
+        0,
+        {10,    5,  2,  1,  HPT("1d4"), "1d2"}
+},
+{"xvart",
+        0,  TRUE,   TRUE,   'x',    "8-12",
+        {ISMEAN, ISSWARM, ISSMALL, CANWIELD},
+        0, 0,
+        1,
+        {8, 5,  1,  7,  HPT("1d4"), "1d4+1"}
+},
+{"giant rat",
+        0,  TRUE,   TRUE,   'R',    "2-4",
+        {ISMEAN, CANDISEASE, ISFLOCK, ISSMALL},
+        0, 0,
+        1,
+        {10,    7,  1,  7,  HPT("1d4"), "1d3"}
+},
+{"jackal",
+        0,  TRUE,   TRUE,   'J',    "2-5",
+        {ISMEAN, ISSMALL},
+        0, 0,
+        1,
+        {8, 5,  1,  7,  HPT("1d4"), "1d2"}
+},
+{"snake",
+        0,  TRUE,   FALSE,   'S',    "2-5",
+        {ISMEAN, ISSMALL},
+        0, 0,
+        1,
+        {8, 5,  1,  5,  HPT("1d4"), "1d3"}
+},
+{"kobold",
+        0,  TRUE,   TRUE,   'K',    "8-8",
+        {ISMEAN, CANSHOOT, CANWIELD, ISSWARM, ISSMALL},
+        0, 0,
+        1,
+        {9, 5,  1,  7,  HPT("1d4"), "1d4"}
+},
+{"vilstrak",
+        5,  TRUE,   FALSE,  'V',    "5-8",
+        {ISMEAN, CANINWALL},
+        0, 0,
+        1,
+        {10,    7,  1,  2,  HPT("1d6"), "1d4+1/1d4+1"}
+},
+{"gnome",
+        10, TRUE,   TRUE,   'G',    "11-12",
+        {CANSHOOT, CANWIELD, ISSWARM, ISSMALL, MEDFRIENDLY},
+        0, 0,
+        1,
+        {10,    8,  1,  5,  HPT("1d6"), "1d6"}
+},
+{"halfling",
+        10, TRUE,   TRUE,   'H',    "11-12",
+        {CANSHOOT, CANWIELD, ISSWARM, ISSMALL, HIGHFRIENDLY},
+        0, 0,
+        1,
+        {8, 9,  1,  4,  HPT("1d6"), "1d6"}
+},
+{"dwarf",
+        15, TRUE,   TRUE,   'D',    "11-12",
+        {CANSHOOT, CANWIELD, ISSMALL, ISSWARM, MEDFRIENDLY},
+        0, 0,
+        1,
+        {14,    10, 1,  4,  HPT("1d8"), "1d8"}
+},
+{"orc",
+        15, TRUE,   TRUE,   'O',    "8-8",
+        {ISMEAN, CANSHOOT, CANWIELD, ISSWARM},
+        0, 0,
+        1,
+        {12,    10, 1,  6,  HPT("1d8"), "1d8"}
+},
+{"larva",
+        0,  TRUE,   TRUE,   'l',    "5-8",
+        {ISMEAN, ISFLOCK},
+        0, 0,
+        1,
+        {6, 10, 1,  7,  HPT("1d8"), "1d4+1"}
+},
+{"skeleton",
+        0,  TRUE,   TRUE,   's',    "0-0",
+        {ISMEAN, ISSWARM, ISUNDEAD},
+        0, 0,
+        1,
+        {6, 14, 1,  7,  HPT("1d8"), "1d6"}
+},
+{"carrion crawler",
+        0,  TRUE,   TRUE,   'c',    "2-4",
+        {ISMEAN, CANPARALYZE, ISLARGE},
+        0, 0,
+        1,
+        {8, 20, 1,  7,  HPT("1d8+1"), "1d2"}
+},
+{"manes",
+        0,  TRUE,   TRUE,   'M',    "2-4",
+        {ISMEAN, MAGICHIT, ISUNDEAD, ISSMALL},
+        0, 0,
+        1,
+        {10,    18, 1,  7,  HPT("1d8"), "1d2/1d2/1d4"}
+},
+{"elf",
+        50, TRUE,   TRUE,   'E',    "13-20",
+        {CANSHOOT, CANWIELD, CANBARGAIN, ISSWARM, HIGHFRIENDLY},
+        0, 0,
+        2,
+        {12,    20, 1,  5,  HPT("1d8+1"), "1d10"}
+},
+{"hobgoblin",
+        0,  TRUE,   TRUE,   'H',    "8-10",
+        {ISMEAN, CANSHOOT, CANWIELD, ISSWARM},
+        0, 0,
+        2,
+        {14,    20, 1,  5,  HPT("1d8+1"), "1d8"}
+},
+{"wild dog",
+        0,  TRUE,   TRUE,   'w',    "2-5",
+        {ISMEAN, ISFAST, ISSMALL, ISFLOCK},
+        0, 0,
+        2,
+        {10,    20, 1,  7,  HPT("1d8+1"), "1d4"}
+},
+{"baboon",
+        0,  TRUE,   TRUE,   'b',    "4-7",
+        {ISMEAN, ISSMALL, ISSWARM},
+        0, 0,
+        2,
+        {10,    20, 1,  7,  HPT("1d8+1"), "1d4"}
+},
+{"fire beetle",
+        0,  TRUE,   TRUE,   'B',    "0-0",
+        {ISMEAN, HASFIRE, ISFLOCK, ISSMALL},
+        0, 0,
+        2,
+        {10,    20, 1,  4,  HPT("1d8+2"), "2d4"}
+},
+{"badger",
+        0,  TRUE,   TRUE,   'k',    "4-6",
+        {CANSURPRISE, ISSMALL},
+        0, 0,
+        3,
+        {10,    30, 2,  4,  HPT("1d8+2"), "2d2/1d3"}
+},
+{"giant ant",
+        0,  TRUE,   TRUE,   'A',    "1-1",
+        {ISMEAN, CANPOISON, ISSMALL, ISSWARM},
+        0, 0,
+        3,
+        {10,    40, 2,  3,  HPT("2d8"), "1d6"}
+},
+{"war dog",
+        0,  TRUE,   TRUE,   'D',    "3-5",
+        {ISMEAN, ISFAST},
+        0, 0,
+        3,
+        {10,    35, 2,  6,  HPT("2d8+2"), "2d4"}
+},
+{"zombie",
+        0,  TRUE,   TRUE,   'Z',    "0-0",
+        {ISMEAN, ISUNDEAD, ISFLOCK},
+        0, 0,
+        2,
+        {10,    20, 2,  8,  HPT("2d8"), "1d8"}
+},
+{"wuccubi",
+        0,  TRUE,   TRUE,   'w',    "0-0",
+        {ISMEAN},
+        0, 0,
+        2,
+        {10,    20, 2,  8,  HPT("2d8"), "1d4/1d10"}
+},
+{"aarakocra",
+        5,  TRUE,   TRUE,   'a',    "8-12",
+        {CANFLY, CANWIELD, ISFLOCK, LOWFRIENDLY},
+        0, 0,
+        2,
+        {11,    28, 2,  7,  "1d8+2", "1d3/1d3"}
+},
+{"gnoll",
+        0,  TRUE,   TRUE,   'g',    "7-11",
+        {ISMEAN, CANWIELD, CANSHOOT, ISLARGE, ISSWARM},
+        0, 0,
+        2,
+        {10,    28, 2,  5,  HPT("2d8"), "2d4"}
+},
+{"warthog",
+        0,  TRUE,   TRUE,   'w',    "3-5",
+        {ISMEAN},
+        0, 0,
+        3,
+        {14,    35, 2,  7,  HPT("3d8"), "2d8/2d8"}
+},
+{"black bear",
+        0,  TRUE,   FALSE,  'U',    "5-8",
+        {CANHUG},
+        0, 0,
+        3,
+        {10,    30, 3,  7,  HPT("2d8+3"), "2d3"}
+},
+{"ear seeker",
+        0,  TRUE,   TRUE,   'e',    "0-0",
+        {ISMEAN, CANINFEST, ISSMALL},
+        0, 0,
+        0,
+        {10,    0,  1,  9,  HPT("1d1"), "0d0"}
+},
+{"floating eye",
+        0,  TRUE,   TRUE,   'E',    "0-0",
+        {CANHUH, ISSMALL},
+        0, 0,
+        1,
+        {7, 30, 1,  9,  HPT("1d4"), "0d0"}
+},
+{"brownie",
+        0,  TRUE,   TRUE,   'B',    "12-15",
+        {LOWCAST, CANSHOOT, CANWIELD, CANSURPRISE, STEALGOLD, CANBARGAIN, ISSMALL, ISFLOCK, HIGHFRIENDLY},
+        0, 0,
+        0,
+        {6, 31, 10, 3,  HPT("1d4"), "1d3"}
+},
+{"shrieker",
+        0,  TRUE,   FALSE,  'S',    "0-0",
+        {CANSHRIEK, NOMOVE, ISFLOCK},
+        0, 0,
+        1,
+        {10,    5,  3,  7,  HPT("3d8"), "0d0"}
+},
+{"gas spore",
+        0,  TRUE,   FALSE,  'g',    "0-0",
+        {CANSPORE, NOMOVE, ISLARGE},
+        0, 0,
+        0,
+        {8, 33, 2,  9,  HPT("1d1"), "0d0"}
+},
+{"hyena",
+        0,  TRUE,   TRUE,   'h',    "3-5",
+        {ISMEAN},
+        0, 0,
+        3,
+        {10,    35, 2,  7,  HPT("3d8"), "2d4"}
+},
+{"mind maggot",
+        0,  TRUE,   TRUE,   'm',    "1-1",
+        {ISMEAN, NOMOVE, DRAINBRAIN, ISFLOCK, CANSURPRISE, ISSMALL},
+        0, 0,
+        3,
+        {10,    40, 4,  8,  HPT("1d8+1"), "1d3"}
+},
+{"giant beetle",
+        0,  TRUE,   FALSE,  'b',    "0-0",
+        {ISFLOCK},
+        0, 0,
+        4,
+        {10,    40, 3,  4,  HPT("2d8"), "4d4"}
+},
+{"bombadier beetle",
+        0,  TRUE,   FALSE,  'B',    "0-0",
+        {CANBACID, ISFLOCK},
+        0, 0,
+        4,
+        {10,    40, 2,  4,  HPT("2d8+2"), "2d6"}
+},
+{"stirge",
+        0,  TRUE,   TRUE,   's',    "1-1",
+        {ISMEAN, CANFLY, CANDRAW, ISSMALL},
+        0, 0,
+        2,
+        {10,    36, 4,  8,  HPT("1d8+1"), "1d3"}
+},
+{"wild camel",
+        0,  TRUE,   TRUE,   'w',    "3-7",
+        {ISMEAN, CANTRAMPLE, ISLARGE, ISFLOCK},
+        0, 0,
+        3,
+        {12,    35, 2,  7,  HPT("3d8"), "1d4"}
+},
+{"wolf",
+        0,  TRUE,   TRUE,   'W',    "3-7",
+        {ISMEAN, ISLARGE, ISSWARM, ISFAST},
+        0, 0,
+        3,
+        {12,    35, 2,  7,  HPT("2d8+2"), "1d4+1"}
+},
+{"troglodyte",
+        5,  TRUE,   TRUE,   'T',    "5-7",
+        {ISMEAN, CANSMELL, CANSHOOT, CANWIELD, ISSWARM},
+        0, 0,
+        2,
+        {10,    36, 2,  5,  HPT("2d8"), "1d3/1d3/2d5"}
+},
+{"killer frog",
+        0,  TRUE,   FALSE,  'f',    "2-4",
+        {ISMEAN},
+        0, 0,
+        4,
+        {10,    40, 3,  6,  HPT("3d8"), "2d3/1d4"}
+},
+{"axe beak",
+        0,  TRUE,   FALSE,  'a',    "2-4",
+        {ISMEAN, ISLARGE},
+        0, 0,
+        4,
+        {10,    40, 3,  6,  HPT("3d8"), "2d3/2d4"}
+},
+{"spinning tick",  
+        0,  TRUE,   TRUE,   't',    "2-6",
+        {ISMEAN, CANFRIGHTEN, ISSMALL, ISFAST, ISFLOCK},
+        0, 0,
+        5,
+        {10,    50, 2,  3,  HPT("2d8+2"), "1d2/1d2/1d4"}
+},
+{"giant centipede",
+        0,  TRUE,   TRUE,   'c',    "1-2",
+        {ISMEAN, CANPOISON, ISLARGE, ISFLOCK},
+        0, 0,
+        1,
+        {6, 40, 2,  9,  HPT("2d2"), "2d3"}
+},
+{"pegasus",
+        0,  TRUE,   TRUE,   'p',    "9-12",
+        {CANFLY, ISFAST, ISLARGE, LOWFRIENDLY},
+        0, 0,
+        4,
+        {15,    50, 3,  6,  HPT("4d8"), "1d3/1d8/1d8"}
+},
+{"lemure",
+        0,  TRUE,   FALSE,  'L',    "2-4",
+        {ISMEAN, ISREGEN, MAGICHIT, ISUNDEAD, ISFLOCK},
+        0, 0,
+        3,
+        {10,    65, 3,  7,  HPT("3d8"), "1d3"}
+},
+{"zemure",
+        0,  TRUE,   FALSE,  'z',    "2-4",
+        {ISMEAN, ISREGEN, MAGICHIT, ISUNDEAD, ISFLOCK},
+        0, 0,
+        3,
+        {10,    65, 4,  7,  HPT("3d8"), "1d4"}
+},
+{"giant beaver",
+        0,  TRUE,   TRUE,   'B',    "6-9",
+        {ISMEAN, CANSWIM, ISSWARM},
+        0, 0,
+        4,
+        {10,    60, 1,  6,  HPT("4d8"), "4d4"}
+},
+{"crocodile",
+        0,  TRUE,   TRUE,   'c',    "2-5",
+        {ISMEAN, CANSWIM, CANSURPRISE, ISFLOCK, ISLARGE},
+        0, 0,
+        4,
+        {15,    60, 3,  5,  HPT("3d8"), "1d3/2d4"}
+},
+{"hipogriff",
+        0,  TRUE,   TRUE,   'h',    "3-6",
+        {CANFLY, ISMEAN},
+        0, 0,
+        4,
+        {12,    60, 3,  5,  HPT("3d8+3"), "1d6/1d6/1d10"}
+},
+{"giant goat",
+        0,  TRUE,   TRUE,   'G',    "3-5",
+        {ISMEAN, ISFAST, ISLARGE},
+        0, 0,
+        4,
+        {10,    85, 3,  7,  HPT("3d8+1"), "2d8"}
+},
+{"wererat",
+        20, TRUE,   TRUE,   'r',    "11-12",
+        {ISMEAN, CANSUMMON, MAGICHIT, ISFLOCK},
+        "giant rat", 4,
+        4,
+        {10,    90, 3,  6,  HPT("3d8+1"), "1d8"}
+},
+{"ulodyte",
+        0,  TRUE,   TRUE,   'u',    "5-8",
+        {ISLARGE},
+        0, 0,
+        3,
+        {10,    80, 3,  6,  HPT("3d8"), "1d3/1d3"}
+},
+{"brown bear",
+        0,  TRUE,   TRUE,   'U',    "5-8",
+        {CANHUG, ISLARGE},
+        0, 0,
+        3,
+        {10,    80, 3,  6,  HPT("4d8+5"), "2d6/1d8"}
+},
+{"ghoul",
+        0,  TRUE,   TRUE,   'g',    "5-7",
+        {ISMEAN, CANPARALYZE, ISUNDEAD, ISFLOCK},
+        0, 0,
+        2,
+        {10,    65, 2,  6,  HPT("2d8"), "1d3/1d3/1d6"}
+},
+{"giant hyena",
+        0,  TRUE,   TRUE,   'H',    "3-5",
+        {ISMEAN, ISLARGE},
+        0, 0,
+        5,
+        {10,    90, 2,  7,  HPT("3d8"), "3d4"}
+},
+{"huorn",
+        0,  TRUE,   TRUE,   'h',    "6-10",
+        {CANBBURN, ISSHADOW, CANHUG},
+        0, 0,
+        3,
+        {18,    60, 3,  7,  HPT("5d6"), "3d3"}
+},
+{"piercer",
+        0,  TRUE,   FALSE,  'P',    "0-0",
+        {NOMOVE, CANSURPRISE, ISSWARM},
+        0, 0,
+        4,
+        {10,    60, 3,  3,  HPT("4d8"), "4d6"}
+},
+{"ape",
+        0,  TRUE,   FALSE,  'A',    "4-6",
+        {CANHUG},
+        0, 0,
+        1,
+        {10,    50, 3,  6,  HPT("4d8+1"), "2d3"}
+},
+{"homonculous",
+        0,  TRUE,   TRUE,   'H',    "9-15",
+        {CANFLY, ISSMALL, LOWFRIENDLY},
+        0, 0,
+        2,
+        {10,    81, 3,  6,  HPT("2d8"), "1d3"}
+},
+{"leprechaun",
+        0,  TRUE,   FALSE,  'L',    "15-16",
+        {ISMEAN, CARRYGOLD, STEALGOLD, CANBARGAIN, MEDFRIENDLY},
+        0, 0,
+        1,
+        {10,    80, 8,  -6, HPT("4d8+1"), "1d1"}
+},
+{"ogre",
+        50, TRUE,   TRUE,   'o',    "5-7",
+        {ISMEAN, ISGREED, ISLARGE, ISFLOCK},
+        0, 0,
+        5,
+        {18,    90, 4,  5,  HPT("4d8+1"), "2d6"}
+},
+{"bull",
+        0,  TRUE,   TRUE,   'B',    "3-5",
+        {ISMEAN, CANTRAMPLE, ISFLOCK, ISLARGE},
+        0, 0,
+        4,
+        {14,    85, 2,  7,  HPT("4d8"), "1d6"}
+},
+{"wild boar",
+        0,  TRUE,   TRUE,   'w',    "3-5",
+        {ISMEAN, ISFLOCK},
+        0, 0,
+        4,
+        {15,    85, 3,  7,  HPT("3d8+3"), "3d4"}
+},
+{"centaur",
+        15, TRUE,   TRUE,   'C',    "5-10",
+        {CANSHOOT, CANWIELD, ISFLOCK, ISLARGE, LOWFRIENDLY},
+        0, 0,
+        4,
+        {10,    85, 4,  4,  HPT("4d8"), "1d6/1d6"}
+},
+{"pseudo dragon",
+        10, TRUE,   FALSE,  'p',    "15-16",
+        {ISMEAN, ISGREED},
+        0, 0,
+        9,
+        {10,    100,    3,  -1, HPT("3d9"), "2d3/1d6"}
+},
+{"very young dragon",
+        10, TRUE,   FALSE,  'd',    "15-16",
+        {ISMEAN, CANBRANDOM, ISGREED},
+        0, 0,
+        9,
+        {10,    100,    3,  -1, HPT("3d9"), "1d8/1d8/3d10"}
+},
+{"batarang",
+        20, TRUE,   TRUE,   'B',    "4-6",
+        {ISMEAN, CANFRIGHTEN, CANFLY, CANSUMMON, ISFLOCK, ISSMALL},
+        "bat", 4,
+        5,
+        {10,    100,    3,  1,  HPT("3d8"), "1d4/1d4"}
+},
+{"carnivorous ape",
+        5,  TRUE,   FALSE,  'A',    "7-10",
+        {CANHUG, ISMEAN, ISLARGE},
+        0, 0,
+        4,
+        {12,    120,    4,  6,  HPT("5d8"), "2d4"}
+},
+{"pixie",
+        0,  TRUE,   TRUE,   'p',    "12-15",
+        {LOWCAST, CANSHOOT, CANWIELD, ISINVIS, ISSMALL, ISFLOCK, LOWFRIENDLY},
+        0, 0,
+        1,
+        {6, 105,    3,  3,  HPT("1d4"), "1d2"}
+},
+{"mountain lion",
+        0,  TRUE,   TRUE,   'L',    "3-5",
+        {ISMEAN, ISFAST},
+        0, 0,
+        6,
+        {12,    110,    3,  6,  HPT("3d8+1"), "1d3/1d3/1d6"}
+},
+{"bugbear",
+        5,  TRUE,   TRUE,   'U',    "5-8",
+        {ISMEAN, CANSHOOT, CANWIELD, CANSURPRISE, ISFLOCK, ISLARGE},
+        "black bear", 2,
+        6,
+        {16,    135,    3,  5,  HPT("3d8+1"), "2d4"}
+},
+{"giant lizard",
+        0,  TRUE,   TRUE,   'G',    "2-4",
+        {ISFAST, ISLARGE},
+        0, 0,
+        4,
+        {13,    125,    4,  5,  HPT("3d8+1"), "1d8"}
+},
+{"harpy",
+        0,  TRUE,   TRUE,   'H',    "6-9",
+        {CANFLY, CANWIELD},
+        0, 0,
+        3,
+        {10,    145,    4,  7,  HPT("3d8"), "1d3/1d3/1d6"}
+},
+{"iguanadon",
+        0,  TRUE,   TRUE,   'i',    "0-0",
+        {ISMEAN, ISLARGE, ISFLOCK},
+        0, 0,
+        6,
+        {12,    150,    4,  4,  HPT("6d8"), "1d3/1d3/2d4"}
+},
+{"leopard",
+        0,  TRUE,   TRUE,   'L',    "3-5",
+        {ISMEAN, ISFAST, CANSURPRISE},
+        0, 0,
+        4,
+        {10,    150,    4,  6,  HPT("3d8+2"), "1d3/1d3/1d6"}
+},
+{"nymph",
+        100,    TRUE,   FALSE,  'N',    "15-16",
+        {STEALMAGIC, MEDCAST, LOWFRIENDLY},
+        0, 0,
+        3,
+        {10,    350,    8,  -5, HPT("3d8"), "0d0"}
+},
+{"giant ram",
+        0,  TRUE,   TRUE,   'R',    "3-5",
+        {ISFLOCK, CANSUMMON, ISFAST},
+        "giant goat", 1,
+        4,
+        {10,    285,    3,  6,  HPT("4d8"), "2d6"}
+},
+{"rot grub",
+        0,  TRUE,   TRUE,   'r',    "0-0",
+        {ISMEAN, CANINFEST, ISSWARM, ISSMALL, ISSLOW},
+        0, 0,
+        0,
+        {10,    0,  1,  9,  HPT("1d1"), "0d0"}
+},
+{"triffid",
+        0,  TRUE,   FALSE,  'T',    "12-18",
+        {ISMEAN, CANHOLD, ISSLOW, CANBBURN, CANPOISON},
+        "huorn", 1,
+        4,
+        {10,    135,    10, 7,  HPT("2d8"), "1d6"}
+},
+{"violet fungi",
+        0,  TRUE,   FALSE,  'F',    "0-0",
+        {ISMEAN, CANHOLD, NOMOVE, CANROT, CANINFEST, CANPOISON},
+        0, 0,
+        4,
+        {10,    135,    3,  7,  HPT("3d8"), "5d1"}
+},
+{"giant tick",
+        0,  TRUE,   TRUE,   't',    "0-0",
+        {ISMEAN, CANDRAW, CANDISEASE, ISSMALL},
+        0, 0,
+        2,
+        {10,    105,    3,  3,  HPT("3d8"), "1d4"}
+},
+{"giant eagle",
+        0,  TRUE,   TRUE,   'e',    "0-0",
+        {ISMEAN, CANFLY, CANSPEAK, ISFLOCK, MEDFRIENDLY},
+        0, 0,
+        4,
+        {10,    150,    3,  7,  HPT("4d8"), "1d6/1d6/2d6"}
+},
+{"peryton",
+        0,  TRUE,   TRUE,   'P',    "0-0",
+        {ISMEAN, CANFLY, CANSPEAK, ISFLOCK},
+        0, 0,
+        4,
+        {10,    150,    3,  7,  HPT("4d8"), "4d4"}
+},
+{"gelatinous cube",
+        90, TRUE,   TRUE,   'c',    "0-0",
+        {ISSLOW, ISMEAN, ISSCAVENGE, CANPARALYZE, ISLARGE},
+        0, 0,
+        4,
+        {10,    150,    4,  8,  HPT("4d8"), "2d4"}
+},
+{"giant owl",
+        0,  TRUE,   TRUE,   'O',    "0-0",
+        {ISMEAN, CANFLY},
+        0, 0,
+        4,
+        {10,    150,    4,  6,  HPT("4d8"), "2d4/2d4/1d4+1"}
+},
+{"giant skunk",
+        0,  TRUE,   TRUE,   's',    "3-5",
+        {CANSTINK, ISFLEE},
+        0, 0,
+        5,
+        {10,    165,    4,  7,  HPT("5d8"), "1d6"}
+},
+{"blink dog",
+        0,  TRUE,   TRUE,   'B',    "8-10",
+        {ISMEAN, CANBLINK, ISFLOCK, HIGHFRIENDLY},
+        0, 0,
+        5,
+        {10,    170,    4,  5,  HPT("4d8"), "1d6"}
+},
+{"rust monster",
+        0,  TRUE,   TRUE,   'R',    "1-1",
+        {ISMEAN, CANRUST},
+        0, 0,
+        4,
+        {10,    185,    5,  2,  HPT("3d8"), "0d0/0d0"}
+},
+{"ghast",
+        0,  TRUE,   TRUE,   'G',    "11-12",
+        {CANPARALYZE, CANSTINK, ISMEAN, ISUNDEAD},
+        0, 0,
+        4,
+        {10,    190,    4,  4,  HPT("4d8"), "1d4/1d4/1d8"}
+},
+{"blindheim",
+        0,  TRUE,   FALSE,  'b',    "1",
+        {ISMEAN, CANBLIND},
+        0, 0,
+        4,
+        {8, 200,    2,  1,  HPT("4d8+2"), "1d8"}
+},
+{"jaguar",
+        0,  TRUE,   TRUE,   'j',    "3-5",
+        {ISMEAN, CANSURPRISE, ISLARGE},
+        0, 0,
+        5,
+        {12,    205,    2,  7,  HPT("4d8+1"), "2d3/2d5"}
+},
+{"dryad",
+        100,    TRUE,   FALSE,  'D',    "15-16",
+        {STEALMAGIC, LOWFRIENDLY},
+        0, 0,
+        3,
+        {8, 325,    8,  -2, HPT("2d8"), "1d1"}
+},
+{"anhkheg",
+        5,  TRUE,   FALSE,  'a',    "2-4",
+        {ISMEAN,CANSURPRISE, ISLARGE},
+        0, 0,
+        2,
+        {10,    300,    3,  2,  HPT("1d6+2"), "3d6"}
+},
+{"shadow",
+        0,  TRUE,   TRUE,   's',    "5-7",
+        {ISSHADOW, ISMEAN, CANCHILL, ISUNDEAD, ISFLOCK},
+        0, 0,
+        4,
+        {10,    255,    3,  7,  HPT("3d8+3"), "1d6"}
+},
+{"gargoyle",
+        5,  TRUE,   TRUE,   'g',    "5-7",
+        {ISMEAN, MAGICHIT, ISFLOCK},
+        0, 0,
+        5,
+        {10,    165,    4,  5,  HPT("4d8+4"), "1d3/1d3/1d6/1d4"}
+},
+{"su-monster",
+        10, TRUE,   TRUE,   's',    "8-10",
+        {ISMEAN},
+        0, 0,
+        6,
+        {10,    225,    5,  6,  HPT("5d8+5"), "4d4/2d4"}
+},
+{"gray ooze",
+        50, TRUE,   FALSE,  'o',    "1-1",
+        {ISMEAN, NOMOVE, CANRUST, ISSCAVENGE, BOLTDIVIDE, BLOWDIVIDE, NOFIRE, NOCOLD},
+        0, 0,
+        5,
+        {10,    200,    3,  8,  HPT("3d8+3"), "2d8"}
+},
+{"psuedo-dragon",
+        0,  TRUE,   TRUE,   'P',    "8-12",
+        {CANSURPRISE, CANSEE, CANFLY, CANPOISON, LOWFRIENDLY},
+        0, 0,
+        2,
+        {10,    200,    3,  2,  HPT("2d8"), "1d3"}
+},
+{"lava child",
+        0,  TRUE,   TRUE,   'l',    "8-12",
+        {NOMETAL, NOFIRE, LOWFRIENDLY},
+        0, 0,
+        5,
+        {11,    205,    4,  4,  HPT("5d8"), "1d6/1d6/2d6"}
+},
+{"hell hound",
+        0,  TRUE,   TRUE,   'h',    "5-8",
+        {ISMEAN, NOFIRE, CANBFIRE, CANSURPRISE, CANSEE},
+        0, 0,
+        8,
+        {10,    250,    4,  4,  HPT("5d8+4"), "1d10"}
+},
+{"pech",
+        60, TRUE,   FALSE,  'p',    "8-14",
+        {CANINWALL, LOWFRIENDLY},
+        0, 0,
+        4,
+        {10,    240,    4,  3,  HPT("4d8"), "1d6"}
+},
+{"winter wolf",
+        0,  TRUE,   TRUE,   'w',    "8-12",
+        {ISMEAN, ISFAST, CANBICE, NOCOLD, ISFLOCK},
+        "wolf", 6,
+        5,
+        {10,    245,    4,  5,  HPT("6d8"), "2d4"}
+},
+{"sylph",
+        100,    TRUE,   FALSE,  's',    "15-16",
+        {STEALMAGIC, LOWFRIENDLY},
+        0, 0,
+        3,
+        {8, 325,    8,  -2, HPT("2d8"), "1d1"}
+},
+{"lion",
+        0,  TRUE,   TRUE,   'L',    "3-5",
+        {ISMEAN, ISLARGE},
+        0, 0,
+        6,
+        {12,    300,    4,  6,  HPT("5d8+2"), "1d4/1d4/1d10"}
+},
+{"undine",
+        30, TRUE,   TRUE,   'u',    "12-18",
+        {ISMEAN, MAGICHIT, NOBOLT, NOCOLD, CANSUMMON, CANSEE, CANSWIM, ISFAST},
+        "crocodile", 3,
+        10,
+        {10,    200,    9,  7,  HPT("7d8+3"), "1d6/1d6/1d6/1d4"}
+},
+{"ochre jelly",
+        0,  TRUE,   FALSE,  'O',    "1-1",
+        {ISMEAN, ISSLOW, BOLTDIVIDE, CANROT},
+        "gelatinous cube", 2,
+        10,
+        {10,    250,    4,  8,  HPT("6d8"), "3d4"}
+},
+{"phoenix",
+        5,  TRUE,   FALSE,  'X',    "5-7",
+        {NOFIRE, NOBOLT, CANSPEAK, CANBFIRE, ISLARGE, MEDFRIENDLY},
+        0, 0,
+        8,
+        {10,    200,    4,  2,  HPT("4d8"), "1d4/1d8"}
+},
+{"owlbear",
+        5,  TRUE,   TRUE,   'U',    "5-7",
+        {ISMEAN, CANHUG, CANSUMMON, ISLARGE},
+        "giant owl", 2,
+        12,
+        {10,    225,    5,  5,  HPT("5d8+2"), "1d6/1d6/2d6"}
+},
+{"phycomid",
+        3,  TRUE,   FALSE,  'P',    "0-0",
+        {CANPOISON, CANINFEST, CANBACID},
+        0, 0,
+        5,
+        {10,    280,    5,  5,  HPT("4d8"), "3d2/3d2"}
+},
+{"slithering tracker",
+        90, TRUE,   TRUE,   't',    "0-0",
+        {ISMEAN, ISSCAVENGE, CANPARALYZE, ISSMALL, ISSHADOW, CANDRAW},
+        0, 0,
+        5,
+        {10,    280,    5,  5,  HPT("5d8"), "2d4"}
+},
+{"satyr",
+        0,  TRUE,   TRUE,   's',    "10-14",
+        {CANSURPRISE, LOWFRIENDLY},
+        0, 0,
+        5,
+        {10,    280,    5,  5,  HPT("5d8"), "2d4"}
+},
+{"imp",
+        25, TRUE,   TRUE,   'i',    "8-10",
+        {ISMEAN, ISREGEN, MAGICHIT, CANPOISON, CANSURPRISE, ISSMALL, ISUNDEAD},
+        0, 0,
+        3,
+        {10,    275,    2,  2,  HPT("2d8+2"), "1d4"}
+},
+{"quellit",
+        30, TRUE,   TRUE,   'q',    "7-11",
+        {ISMEAN, ISREGEN, MAGICHIT },
+        0, 0,
+        3,
+        {10,    400,    7,  2,  HPT("4d8"), "2d10/2d6"}
+},
+{"quasit",
+        30, TRUE,   TRUE,   'Q',    "5-7",
+        {ISMEAN, ISREGEN, MAGICHIT, CANSURPRISE, CANITCH, ISSMALL, ISUNDEAD},
+        0, 0,
+        3,
+        {10,    325,    7,  2,  HPT("3d8"), "1d2/1d2/1d4"}
+},
+{"doppleganger",
+        0,  TRUE,   TRUE,   'D',    "11-12",
+        {ISMEAN, CANSURPRISE},
+        0, 0,
+        4,
+        {10,    330,    10, 5,  HPT("4d8"), "1d12"}
+},
+{"subterranean lizard",
+        0,  TRUE,   TRUE,   's',    "0-0",
+        {ISFAST, ISLARGE},
+        0, 0,
+        6,
+        {14,    350,    6,  5,  HPT("6d8"), "2d6"}
+},
+{"giant porcupine",
+        0,  TRUE,   FALSE,  'p',    "0-0",
+        {ISFLEE, CANSTICK},
+        0, 0,
+        6,
+        {10,    350,    6,  5,  HPT("6d8"), "2d4"}
+},
+{"plateosaurus",
+        0,  TRUE,   TRUE,   'P',    "0-0",
+        {ISFLEE, CANTRAMPLE, ISLARGE},
+        0, 0,
+        10,
+        {18,    375,    9,  5,  HPT("8d8"), "0d0"}
+},
+{"buffalo",
+        0,  TRUE,   TRUE,   'b',    "3-5",
+        {ISMEAN, CANTRAMPLE, ISSWARM, ISLARGE},
+        0, 0,
+        8,
+        {16,    350,    2,  7,  HPT("5d8"), "1d8"}
+},
+{"cockatrice",
+        0,  TRUE,   TRUE,   'c',    "1-1",
+        {ISMEAN, CANFLY, TOUCHSTONE, ISSMALL},
+        0, 0,
+        5,
+        {10,    315,    5,  6,  HPT("5d8"), "1d3"}
+},
+{"yeti",
+        30, TRUE,   TRUE,   'Y',    "8-10",
+        {ISMEAN, CANPARALYZE,CANHUG, NOCOLD, CANSURPRISE, ISLARGE, LOWFRIENDLY},
+        "winter wolf", 2,
+        12,
+        {13,    500,    6,  6,  HPT("4d8+4"), "1d6/1d6"}
+},
+{"lonchu",
+        0,  TRUE,   FALSE,  'l',    "8-10",
+        {ISMEAN},
+        0, 0,
+        8,
+        {10,    475,    6,  4,  HPT("6d8+1"), "1d4/1d4"}
+},
+{"leucrotta",
+        0,  TRUE,   FALSE,  'L',    "8-10",
+        {ISMEAN, ISLARGE},
+        0, 0,
+        8,
+        {10,    475,    6,  4,  HPT("6d8+1"), "3d6/1d6/1d6"}
+},
+{"giant crocodile",
+        0,  TRUE,   TRUE,   'g',    "2-4",
+        {CANSWIM, CANSUMMON, CANSURPRISE, ISLARGE},
+        "undine", 1,
+        8,
+        {18,    400,    5,  4,  HPT("7d8"), "3d6/2d10"}
+},
+{"griffon",
+        0,  TRUE,   TRUE,   'g',    "0-0",
+        {CANFLY, ISMEAN, ISLARGE},
+        0, 0,
+        10,
+        {12,    375,    4,  3,  HPT("7d8"), "1d4/1d4/2d8"}
+},
+{"warg",
+        10, TRUE,   TRUE,   'W',    "5-9",
+        {ISFAST, CANSUMMON, ISFLOCK},
+        "wolf", 3,
+        8,
+        {12,    400,    6,  4,  HPT("3d8+3"), "1d4+4"}
+},
+{"unicorn",
+        10, TRUE,   TRUE,   'u',    "8-12",
+        {ISFAST, CANSURPRISE, CANBLINK, ISLARGE, MEDFRIENDLY},
+        0, 0,
+        5,
+        {12,    400,    6,  2,  HPT("4d8+4"), "1d6/1d6/1d12"}
+},
+{"entwife",
+        35, TRUE,   FALSE,  'w',    "13-15",
+        {CANSUMMON, CANBBURN, ISSWARM, ISLARGE, HIGHFRIENDLY},
+        "ent", 1,
+        8,
+        {16,    400,    6,  4,  HPT("3d8+3"), "1d4+4"}
+},
+{"minotaur",
+        0,  TRUE,   TRUE,   'm',    "7-9",
+        {ISMEAN, CANWIELD, ISLARGE},
+        0, 0,
+        8,
+        {14,    400,    5,  6,  HPT("6d8+3"), "1d3/2d4"}
+},
+{"displacer beast",
+        0,  TRUE,   TRUE,   'D',    "3-5",
+        {CANBLINK, ISSHADOW, ISLARGE},
+        0, 0,
+        8,
+        {12,    475,    6,  4,  HPT("6d8"), "2d4/2d4"}
+},
+{"giant lynx",
+        0,  TRUE,   TRUE,   'L',    "9-13",
+        {ISMEAN, CANSURPRISE},
+        0, 0,
+        3,
+        {10,    420,    4,  2,  HPT("2d8+2"), "1d2/1d2/1d4"}
+},
+{"young dragon",
+        25, TRUE,   FALSE,  'd',    "12-15",
+        {ISMEAN, CANBRANDOM, ISGREED, ISLARGE, LOWFRIENDLY},
+        0, 0,
+        9,
+        {10,    800,    6,  1,  HPT("30d1"), "1d4/1d4/3d8"}
+},
+{"ceratosaurus",
+        0,  TRUE,   TRUE,   'c',    "0-0",
+        {ISMEAN, ISFAST, ISLARGE},
+        0, 0,
+        12,
+        {18,    600,    4,  5,  HPT("8d8"), "1d6/1d6/4d4"}
+},
+{"wight",
+        35, TRUE,   TRUE,   'W',    "8-10",
+        {ISMEAN, CANSUMMON, CANDRAIN, MAGICHIT, ISUNDEAD, ISFLOCK},
+        "skeleton", 2,
+        7,
+        {10,    540,    4,  5,  HPT("4d8+3"), "1d4"}
+},
+{"monoclonius",
+        0,  TRUE,   TRUE,   'M',    "0-0",
+        {ISMEAN, ISFAST, CANTRAMPLE, ISLARGE},
+        0, 0,
+        18,
+        {18,    550,    4,  3,  HPT("8d8"), "2d8"}
+},
+{"olog-hai troll",
+        45, TRUE,   TRUE,   'T',    "12-18",
+        {ISMEAN, ISFLOCK, NOCOLD, CANWIELD, ISREGEN,  CANSUMMON},
+        "troll", 2,
+        6,
+        {15,    640,    5,  3,  HPT("5d6"), "2d8+4"}
+},
+{"manticore",
+        20, TRUE,   TRUE,   'm',    "7-9",
+        {ISMEAN, CANFLY},
+        0, 0,
+        6,
+        {12,    525,    4,  4,  HPT("6d8+3"), "1d3/1d3/1d8"}
+},
+{"uruk-hai orc",
+        45, TRUE,   TRUE,   'O',    "12-18",
+        {ISMEAN, ISSWARM, CANWIELD, CANSHOOT, CANSUMMON},
+        "orc", 3,
+        6,
+        {15,    540,    3,  5,  HPT("5d4+3"), "3d4"}
+},
+{"kazad dwarf",
+        75, TRUE,   FALSE,  'D',    "12-18",
+        {ISFLOCK, CANWIELD, CANSHOOT, CANSUMMON, LOWFRIENDLY},
+        "dwarf", 3,
+        6,
+        {17,    540,    5,  3,  HPT("5d8+3"), "3d4"}
+},
+{"noldor elf",
+        75, TRUE,   FALSE,  'E',    "18-20",
+        {ISFLOCK, CANWIELD, MEDCAST, CANSHOOT, CANSUMMON, LOWFRIENDLY},
+        "elf", 3,
+        6,
+        {14,    600,    6,  2,  HPT("5d8+3"), "3d4"}
+},
+{"ent",
+        80, TRUE,   FALSE,  'e',    "15-17",
+        {ISREGEN, CANSUMMON, CANBBURN, HIGHCAST, ISLARGE, HIGHFRIENDLY},
+        "huorn", 3,
+        10,
+        {22,    600,    6,  4,  HPT("6d8+6"), "1d4+4/1d4+4/2d6"}
+},
+{"nightmare",
+        0,  TRUE,   FALSE,  'n',    "11-13",
+        {ISMEAN, ISFAST, NOFIRE, ISLARGE, ISUNDEAD},
+        0, 0,
+        8,
+        {14,    600,    6,  -4, HPT("6d8+6"), "2d4/1d6+4/1d6+4"}
+},
+{"troll",
+        50, TRUE,   FALSE,  'T',    "5-7",
+        {ISMEAN, ISREGEN, ISLARGE},
+        0, 0,
+        8,
+        {18,    600,    6,  4,  HPT("6d8+6"), "1d8/1d8/2d6"}
+},
+{"wraith",
+        0,  TRUE,   TRUE,   'W',    "11-12",
+        {ISMEAN, CANDRAIN, CANSUMMON, MAGICHIT, ISUNDEAD},
+        "zombie", 2,
+        8,
+        {10,    575,    5,  4,  HPT("5d8+3"), "1d6"}
+},
+{"archer bush",
+        50, TRUE,   FALSE,  'a',    "0-0",
+        {ISMEAN, CANPOISON, CANSUMMON, ISFLOCK, NOMOVE, CANBBURN, ISLARGE},
+        "dryad", 2,
+        20,
+        {10,    600,    8,  8,  HPT("2d8"), "1d10"}
+},
+{"green slime",
+        0,  TRUE,   TRUE,   's',    "0-0",
+        {NOMOVE, ISSCAVENGE, BOLTDIVIDE, BLOWDIVIDE, CANRUST, NOMOVE, CANINFEST, CANROT, ISSMALL},
+        0, 0,
+        2,
+        {8, 610,    5,  9,  HPT("2d8"), "1d1"}
+},
+{"blink saber tooth tiger",
+        0,  TRUE,   TRUE,   'T',    "8-10",
+        {ISMEAN, CANSUMMON, CANBLINK, ISLARGE},
+        "blink dog", 2,
+        10,
+        {10,    670,    8,  3,  HPT("8d8+6"), "1d10/1d10/1d8/1d8"}
+},
+{"djinni",
+        0,  TRUE,   TRUE,   'd',    "10-15",
+        {CANCAST, ISFAST, CANSPEAK, ISLARGE, MEDFRIENDLY},
+        0, 0,
+        5,
+        {12,    725,    6,  4,  HPT("7d8+3"), "2d8"}
+},
+{"stag beetle",
+        0,  TRUE,   TRUE,   'B',    "0-0",
+        {ISMEAN, ISFLOCK},
+        0, 0,
+        8,
+        {10,    700,    5,  3,  HPT("7d8"), "4d4/2d10"}
+},
+{"gibbering ghoul",
+        15, TRUE,   TRUE,   'g',    "3-15",
+        {ISMEAN, CANPARALYZE, CANDRAIN, ISUNDEAD, CANSUMMON},
+        "ghoul", 2,
+        10,
+        {10,    750,    6,  4,  HPT("6d10"), "1d6+2/1d4+1/1d4+1/1d8"}
+},
+{"catoblepas",
+        10, TRUE,   TRUE,   'c',    "3-5",
+        {ISMEAN, LOOKSTONE, CANSTINK, ISLARGE},
+        0, 0,
+        8,
+        {16,    700,    6,  7,  HPT("6d8+2"), "1d6/1d8"}
+},
+{"jackalwere",
+        50, TRUE,   TRUE,   'J',    "11-12",
+        {ISMEAN, CANSHOOT, CANWIELD, CANSNORE, MAGICHIT, CANSUMMON},
+        "jackal", 2,
+        4,
+        {10,    800,    4,  4,  HPT("4d8"), "2d4"}
+},
+{"werebear",
+        10, TRUE,   TRUE,   'U',    "14-16",
+        {ISMEAN, CANHUG, ISLARGE, MAGICHIT, CANSUMMON},
+        "brown bear", 2,
+        10,
+        {16,    825,    6,  2,  HPT("7d8+3"), "1d3/1d3/2d8"}
+},
+{"salamander",
+        50, TRUE,   TRUE,   's',    "14-16",
+        {ISMEAN, NOFIRE, CANHUG, MAGICHIT, CANWIELD},
+        "fire beetle", 2,
+        14,
+        {13,    825,    6,  4,  HPT("7d8+7"), "2d6/1d6"}
+},
+{"ankylosaurus",
+        0,  TRUE,   TRUE,   'a',    "0-0",
+        {ISMEAN, CANTRAMPLE, ISLARGE},
+        0, 0,
+        12,
+        {18,    900,    9,  0,  HPT("9d8"), "3d6"}
+},
+{"yeenoghu",
+        0,  TRUE,   TRUE,   'y',    "5-10",
+        {ISMEAN, CANTRAMPLE, ISLARGE},
+        0, 0,
+        12,
+        {18,    900,    11,  0,  HPT("9d8"), "3d6"}
+},
+{"erinyes",
+        25, TRUE,   TRUE,   'E',    "8-10",
+        {ISMEAN, CANFRIGHTEN, CANSUMMON, ISUNDEAD},
+        "lemure", 3,
+        8,
+        {10,    875,    7,  2,  HPT("6d8+6"), "2d4"}
+},
+{"spotted lion",
+        0,  TRUE,   TRUE,   'L',    "3-5",
+        {ISMEAN, ISLARGE},
+        "lion", 2,
+        10,
+        {12,    700,    6,  5,  HPT("6d8+2"), "1d4/1d4/1d12"}
+},
+{"killer bee",
+        0,  TRUE,   TRUE,   'z',    "2-4",
+        {ISMEAN, CANPOISON, CANFLY, ISMANY, ISSMALL},
+        0, 0,
+        20,
+        {6, 800,    4,  0,  HPT("3d8"), "1d10"}
+},
+{"minotaur lizard",
+        40, TRUE,   TRUE,   'm',    "0-0",
+        {ISMEAN, ISLARGE},
+        0, 0,
+        10,
+        {14,    875,    7,  5,  HPT("8d8"), "2d6/2d6/3d6"}
+},
+{"lammasu",
+        0,  TRUE,   TRUE,   'l',    "14-18",
+        {CANFLY, MEDCAST, CANSPEAK, CANBARGAIN, ISLARGE, HIGHFRIENDLY},
+        0, 0,
+        10,
+        {10,    850,    7,  6,  HPT("7d8+7"), "1d6/1d6"}
+},
+{"teratosaurus",
+        0,  TRUE,   TRUE,   'T',    "0-0",
+        {ISMEAN, ISFAST, ISLARGE},
+        0, 0,
+        14,
+        {18,    900,    8,  5,  HPT("10d8"), "1d3/1d3/3d6"}
+},
+{"rhynosphinx",
+        0,  TRUE,   TRUE,   'r',    "3-5",
+        {ISMEAN, ISFAST, CANTRAMPLE, ISLARGE},
+        0, 0,
+        12,
+        {18,    925,    8,  6,  HPT("9d8"), "2d10/2d8"}
+},
+{"rhinoceros",
+        0,  TRUE,   TRUE,   'R',    "3-5",
+        {ISMEAN, ISFAST, CANTRAMPLE, ISLARGE},
+        0, 0,
+        12,
+        {18,    900,    8,  6,  HPT("8d8"), "2d4/2d6"}
+},
+{"slyph",
+        30, TRUE,   TRUE,   'S',    "12-18",
+        {ISMEAN, HALFDAMAGE, MAGICHIT, CANSUMMON, NOBOLT, NOCOLD, CANSEE, CANFLY, ISSHADOW},
+        "giant crocodile", 3,
+        10,
+        {10,    800,    9,  7,  HPT("6d8+3"), "1d6/1d6/1d6/1d4"}
+},
+{"rakshasa",
+        20, TRUE,   TRUE,   'r',    "12-14",
+        {ISMEAN, MEDCAST, BMAGICHIT},
+        0, 0,
+        8,
+        {13,    925,    8,  -4, HPT("7d8"), "1d3/1d3/1d4+1"}
+},
+{"wyvern",
+        5,  TRUE,   TRUE,   'w',    "6-8",
+        {ISMEAN, CANSURPRISE, CANSEE, CANFLY, CANPOISON},
+        0, 0,
+        10,
+        {14,    925,    8,  3,  HPT("7d8+7"), "1d6/2d8"}
+},
+{"mummy",
+        20, TRUE,   FALSE,  'm',    "5-7",
+        {ISMEAN, CANINFEST, CANSUMMON, MAGICHIT, CANFRIGHTEN, HALFDAMAGE, CANBBURN, ISUNDEAD},
+        "ghast", 2,
+        8,
+        {10,    1150,   6,  3,  HPT("6d8+3"), "1d12"}
+},
+{"basilisk",
+        0,  TRUE,   TRUE,   'B',    "1-1",
+        {ISMEAN, LOOKSTONE},
+        0, 0,
+        8,
+        {10,    1000,   6,  4,  HPT("6d8+1"), "1d10"}
+},
+{"medusa",
+        0,  TRUE,   FALSE,  'M',    "11-14",
+        {LOOKSTONE, CANPOISON},
+        0, 0,
+        10,
+        {10,    1000,   7,  5,  HPT("6d8"), "1d4"}
+},
+{"polar bear",
+        0,  TRUE,   TRUE,   'U',    "5-8",
+        {ISMEAN, CANSUMMON, CANHUG, ISLARGE},
+        "winter wolf", 2,
+        12,
+        {10,    900,    6,  6,  HPT("8d8"), "2d6/2d10"}
+},
+{"otyugh",
+        0,  TRUE,   TRUE,   'o',    "5-10",
+        {ISMEAN, CANDISEASE},
+        0, 0,
+        8,
+        {10,    700,    7,  3,  HPT("7d8"), "1d8/1d8/1d4+1"}
+},
+{"adult dragon",
+        30, TRUE,   FALSE,  'd',    "15-16",
+        {ISMEAN, CANBRANDOM, ISGREED, CANFRIGHTEN, ISLARGE, MEDFRIENDLY},
+        0, 0,
+        9,
+        {10,    1000,   8,  -1, HPT("45d1"), "1d8/1d8/3d10"}
+},
+{"invisible stalker",
+        0,  TRUE,   TRUE,   'I',    "13-14",
+        {ISMEAN, ISINVIS, ISLARGE},
+        0, 0,
+        10,
+        {10,    1090,   8,  3,  HPT("8d8"), "4d4"}
+},
+{"xorn",
+        0,  TRUE,   TRUE,   'X',    "8-10",
+        {ISMEAN, CANINWALL, CANSUMMON, NOCOLD, NOFIRE, CANSURPRISE},
+        "vilstrak", 2,
+        10,
+        {10,    1275,   7,  -2, HPT("7d8+7"), "1d3/1d3/1d3/4d6"}
+},
+{"will-o-wisp",
+        100,    TRUE,   FALSE,  'W',    "15-16",
+        {ISMEAN, BMAGICHIT, CANSURPRISE, ISSMALL},
+        0, 0,
+        12,
+        {10,    1200,   9,  -8, HPT("9d8"), "2d8"}
+},
+{"chimera",
+        0,  TRUE,   FALSE,  'c',    "2-4",
+        {ISMEAN, CANFLY, NOFIRE, CANBFIRE, ISLARGE},
+        0, 0,
+        12,
+        {10,    1000,   9,  6,  HPT("9d8"), "1d3/1d3/1d4/1d4/2d4/3d4"}
+},
+{"barrow wight",
+        100,    TRUE,   FALSE,  'W',    "14-18",
+        {ISMEAN, CANPARALYZE, CANSUMMON, CANDRAIN, BMAGICHIT, ISUNDEAD},
+        "wight", 2,
+        10,
+        {10,    975,    10, 0,  HPT("10d6"), "3d6/1d8"}
+},
+{"anatosaurus",
+        0,  TRUE,   FALSE,  'a',    "0-0",
+        {ISFLEE, CANTRAMPLE, ISLARGE},
+        0, 0,
+        16,
+        {18,    1300,   9,  5,  HPT("12d8"), "1d4"}
+},
+{"wooly rhinoceros",
+        0,  TRUE,   TRUE,   'R',    "3-5",
+        {ISMEAN, ISFAST, CANSUMMON, CANTRAMPLE, ISLARGE},
+        "rhinoceros", 2,
+        14,
+        {18,    1350,   9,  5,  HPT("10d8"), "2d6"}
+},
+{"air squid",
+        40, TRUE,   TRUE,   'S',    "2-8",
+        {ISMEAN, CANHUG, CANFLY, CANBBURN, ISLARGE, LOWFRIENDLY},
+        0, 0,
+        16,
+        {10,    1400,   9,  7,  HPT("12d8"), "1d8/1d8/1d8/1d8/1d8/1d8/1d8/1d8/1d10"}
+},
+{"octorilla (snake ape)",
+        80, TRUE,   TRUE,   'o',    "2-8",
+        {ISMEAN, CANSUMMON, CANHUG, ISFLOCK},
+        "carnivorous ape", 2,
+        20,
+        {14,    1500,   6,  6,  HPT("6d8"), "1d10/1d10/1d10/1d10/2d6"}
+},
+{"cave bear",
+        0,  TRUE,   TRUE,   'U',    "5-8",
+        {ISMEAN, CANSUMMON, CANHUG, ISLARGE},
+        "bugbear", 2,
+        14,
+        {10,    850,    6,  6,  HPT("6d8+6"), "2d8/1d12"}
+},
+{"elasmosaurus",
+        0,  TRUE,   TRUE,   'e',    "4-6",
+        {ISMEAN},
+        0, 0,
+        10,
+        {10,    1700,   4,  -4, HPT("4d7"), "4d6"}
+},
+{"electric eel",
+        0,  TRUE,   TRUE,   'E',    "4-6",
+        {ISMEAN, CANBBOLT, NOBOLT, NOFIRE, CANSWIM},
+        0, 0,
+        10,
+        {10,    1700,   4,  -4, HPT("4d8"), "4d6"}
+},
+{"remorhaz",
+        0,  TRUE,   TRUE,   'r',    "4-6",
+        {ISMEAN, CANBFIRE, CANSUMMON, NOFIRE, ISFAST, ISLARGE},
+        "winter wolf", 2,
+        16,
+        {18,    1700,   6,  0,  HPT("9d8"), "6d6"}
+},
+{"airfang",
+        0,  TRUE,   TRUE,   'S',    "2-8",
+        {ISMEAN, CANFLY, ISMANY, ISSMALL},
+        0, 0,
+        10,
+        {10,    1200,   3,  -4, HPT("8d6"), "3d4/3d4"}
+},
+{"megalosaurus",
+        0,  TRUE,   TRUE,   'M',    "0-0",
+        {ISMEAN, ISFAST, ISLARGE},
+        0, 0,
+        16,
+        {18,    1300,   9,  5,  HPT("12d8"), "3d6"}
+},
+{"lambeosaurus",
+        0,  TRUE,   FALSE,  'l',    "0-0",
+        {ISFLEE, CANTRAMPLE, ISFLOCK, ISLARGE},
+        0, 0,
+        16,
+        {18,    1300,   9,  5,  HPT("12d8"), "2d6"}
+},
+{"dragonne",
+        15, TRUE,   TRUE,   'd',    "6-8",
+        {ISMEAN, CANFLY, CANSHRIEK, ISLARGE},
+        0, 0,
+        14,
+        {13,    1400,   9,  4,  HPT("9d8"), "1d8/1d8/3d6"}
+},
+{"giant slug",
+        0,  TRUE,   TRUE,   's',    "0-0",
+        {ISMEAN, CANPOISON},
+        0, 0,
+        15,
+        {10,    1500,   9,  8,  HPT("10d8"), "1d12"}
+},
+{"fire lizard",
+        25, TRUE,   TRUE,   'F',    "2-4",
+        {NOFIRE, CANBFIRE, ISLARGE},
+        0, 0,
+        14,
+        {13,    1350,   9,  3,  HPT("10d8"), "1d8/1d8/2d8"}
+},
+{"paleoscincus",
+        0,  TRUE,   TRUE,   'p',    "0-0",
+        {ISMEAN, CANTRAMPLE, ISLARGE},
+        0, 0,
+        12,
+        {18,    1300,   9,  -3, HPT("9d8"), "2d6"}
+},
+{"bulette",
+        0,  TRUE,   TRUE,   'u',    "2-4",
+        {ISMEAN, CANSURPRISE, ISLARGE},
+        0, 0,
+        10,
+        {10,    1300,   5,  -2, HPT("9d8"), "4d12/6d6"}
+},
+{"mimic",
+        30, TRUE,   FALSE,  'M',    "2-10",
+        {ISDISGUISE, CANHOLD, ISLARGE},
+        0, 0,
+        12,
+        {10,    1300,   9,  7,  HPT("9d8"), "3d4"}
+},
+{"xonoclon",
+        30, TRUE,   FALSE,  'x',    "2-10",
+        {ISDISGUISE, ISLARGE},
+        0, 0,
+        12,
+        {10,    1300,   15,  7,  HPT("9d8"), "3d8"}
+},
+{"achaierai",
+        0,  TRUE,   TRUE,   'A',    "8-12",
+        {ISLARGE},
+        0, 0,
+        14,
+        {15,    1300,   7,  8,  HPT("0d8+100"), "1d8/1d8/1d10"}
+},
+{"succubus (Servant of Errtu)",
+        10, TRUE,   TRUE,   's',    "15-18",
+        {ISMEAN, HIGHCAST, CANSUMMON, BMAGICHIT, CANDARKEN, CANBARGAIN},
+        "lesser demon (Errtu)", 1,
+        6,
+        {11,    2100,   13, 0,  HPT("6d8"), "1d3/1d3"}
+},
+{"horned devil",
+        5,  TRUE,   TRUE,   'H',    "13-14",
+        {ISMEAN, CANFLY, CANFRIGHTEN, CANINFEST, CANPOISON, MAGICHIT, CANSUMMON, ISLARGE, ISUNDEAD},
+        "imp", 3,
+        6,
+        {10,    1320,   7,  -3, HPT("5d8+5"), "1d4/1d4/1d4+1/1d3"}
+},
+{"pentacerotops",
+        0,  TRUE,   TRUE,   'P',    "0-0",
+        {ISMEAN, CANTRAMPLE, ISLARGE},
+        0, 0,
+        18,
+        {18,    1300,   9,  4,  HPT("12d8"), "1d6/1d10/1d10"}
+},
+{"spectre",
+        0,  TRUE,   TRUE,   'S',    "13-14",
+        {ISMEAN, CANSUMMON, DOUBLEDRAIN, ISUNDEAD, ISSHADOW},
+        "shadow", 2,
+        10,
+        {10,    1650,   7,  2,  HPT("7d8+3"), "1d8"}
+},
+{"neotyugh",
+        0,  TRUE,   TRUE,   'n',    "10-12",
+        {ISMEAN, CANDISEASE, ISLARGE},
+        0, 0,
+        10,
+        {12,    1500,   10, 0,  HPT("12d8"), "1d8/1d8/2d3"}
+},
+{"intellect devourer",
+        0,  TRUE,   TRUE,   'r',    "11-13",
+        {ISMEAN, DRAINBRAIN, CANSURPRISE, ISFAST},
+        0, 0,
+        8,
+        {14,    1510,   10, 4,  HPT("6d8+6"), "1d4/1d4/1d4/1d4"}
+},
+{"heffalump",
+        0,  TRUE,   TRUE,   'h',    "4-6",
+        {ISMEAN, CANTRAMPLE, NOBOLT, NOFIRE, CANHUG, ISFLOCK, ISLARGE},
+        0, 0,
+        14,
+        {18,    1500,   9,  1,  HPT("10d8"), "3d10/3d10/2d8"}
+},
+{"elephant",
+        0,  TRUE,   TRUE,   'e',    "4-6",
+        {ISMEAN, CANTRAMPLE, CANHUG, ISFLOCK, ISLARGE},
+        0, 0,
+        14,
+        {18,    1500,   9,  6,  HPT("10d8"), "2d6/2d6/2d6/2d6/2d6"}
+},
+{"succubus (Servant of Ndulu)",
+        10, TRUE,   TRUE,   's',    "15-18",
+        {ISMEAN, HIGHCAST, CANSUMMON, BMAGICHIT, CANDARKEN, CANBARGAIN},
+        "lesser demon (Ndulu)", 1,
+        6,
+        {11,    2100,   13, 0,  HPT("6d8"), "1d3/1d3"}
+},
+{"barbed devil",
+        0,  TRUE,   TRUE,   'B',    "11-12",
+        {ISMEAN, CANFLY, TOUCHFEAR, CANSUMMON, CANHOLD, ISUNDEAD},
+        "quasit", 3,
+        10,
+        {10,    1425,   8,  0,  HPT("8d8"), "2d4/2d4/3d4"}
+},
+{"vrock",
+        10, TRUE,   TRUE,   'v',    "5-7",
+        {ISMEAN, CANSUMMON, CANSEE, ISLARGE},
+        "vilstrak", 2,
+        10,
+        {10,    1500,   8,  0,  HPT("8d8"), "1d4/1d6"}
+},
+{"lamia",
+        20, TRUE,   TRUE,   'L',    "11-14",
+        {CANFLY, MEDCAST, DRAINWISDOM, CANSPEAK, CANBARGAIN},
+        0, 0,
+        12,
+        {12,    1700,   8,  3,  HPT("9d8"), "1d4"}
+},
+{"shambling mound",
+        25, TRUE,   TRUE,   's',    "5-7",
+        {ISSLOW, ISMEAN, CANSUFFOCATE, NOCOLD, NOFIRE, CANHOLD, ISLARGE},
+        0, 0,
+        10,
+        {10,    1800,   9,  0,  HPT("9d8"), "2d8/2d8"}
+},
+{"succubus (Servant of Bilwhr)",
+        10, TRUE,   TRUE,   's',    "15-18",
+        {ISMEAN, HIGHCAST, CANSUMMON, BMAGICHIT, CANDARKEN, CANBARGAIN},
+        "lesser demon (Bilwhr)", 1,
+        6,
+        {11,    2100,   13, 0,  HPT("6d8"), "1d3/1d3"}
+},
+{"mind flayer",
+        25, TRUE,   TRUE,   'M',    "15-17",
+        {ISMEAN, DRAINBRAIN},
+        0, 0,
+        12,
+        {10,    1800,   9,  5,  HPT("8d8+4"), "2d2/2d2"}
+},
+{"gorgon",
+        5,  TRUE,   TRUE,   'g',    "3-5",
+        {ISMEAN, CANTRAMPLE, NOFIRE, CANBFIRE, ISLARGE},
+        0, 0,
+        10,
+        {14,    1750,   9,  2,  HPT("8d8"), "2d6"}
+},
+{"night hag",
+        5,  TRUE,   TRUE,   'n',    "13-15",
+        {ISMEAN, CANSNORE, CANSUMMON, ISINVIS, BMAGICHIT, NOFIRE, NOCOLD, ISUNDEAD},
+        "nightmare", 2,
+        12,
+        {14,    1750,   9,  9,  HPT("8d8"), "2d6"}
+},
+{"umber hulk",
+        40, TRUE,   TRUE,   'U',    "8-10",
+        {ISSLOW, ISMEAN, CANHUH, ISLARGE},
+        0, 0,
+        12,
+        {10,    1700,   8,  2,  HPT("8d8+8"), "3d4/3d4/2d5"}
+},
+{"old dragon",
+        30, TRUE,   FALSE,  'd',    "15-16",
+        {ISMEAN, CANBRANDOM, CANSUMMON, ISGREED, CANFRIGHTEN, ISLARGE, LOWFRIENDLY},
+        "very young dragon", 1,
+        11,
+        {10,    1800,   8,  2,  HPT("55d1"), "1d10/1d10/3d12"}
+},
+{"succubus (Servant of Nalfeshnee)",
+        10, TRUE,   TRUE,   's',    "15-18",
+        {ISMEAN, HIGHCAST, CANSUMMON, BMAGICHIT, CANDARKEN, CANBARGAIN},
+        "lesser demon (Nalfeshnee)", 1,
+        6,
+        {11,    2100,   13, 0,  HPT("6d8"), "1d3/1d3"}
+},
+{"gorgosaurus",
+        0,  TRUE,   TRUE,   'G',    "0-0",
+        {ISMEAN, ISFAST, ISLARGE},
+        0, 0,
+        18,
+        {18,    1800,   9,  5,  HPT("13d8"), "1d3/1d3/7d4"}
+},
+{"efreeti",
+        10, TRUE,   TRUE,   'E',    "0-0",
+        {NOFIRE, ISMEAN, CANBFIRE, CANFLY, CANSPEAK, ISLARGE},
+        0, 0,
+        14,
+        {18,    1950,   9,  2,  HPT("10d8"), "3d8"}
+},
+{"succubus (Servant of Johud)",
+        10, TRUE,   TRUE,   's',    "15-18",
+        {ISMEAN, HIGHCAST, CANSUMMON, BMAGICHIT, CANDARKEN, CANBARGAIN},
+        "lesser demon (Johud)", 1,
+        6,
+        {11,    2100,   13, 0,  HPT("6d8"), "1d3/1d3"}
+},
+{"treant",
+        0,  TRUE,   TRUE,   'T',    "10-13",
+        {CANBBURN, CANSUMMON, CANSPEAK, ISLARGE, LOWFRIENDLY},
+        "ent", 3,
+        14,
+        {18,    1950,   9,  0,  HPT("10d8"), "2d8/3d6/4d6"}
+},
+{"giant toad",
+        0,  TRUE,   TRUE,   't',    "1-4",
+        {ISMEAN, CANPOISON, ISLARGE},
+        0, 0,
+        14,
+        {10,    3950,   15, 6,  HPT("15d8"), "15d4"}
+},
+{"ettin",
+        0,  TRUE,   TRUE,   'e',    "0-0",
+        {ISMEAN, CANSHOOT, CANWIELD, ISLARGE},
+        0, 0,
+        14,
+        {10,    1950,   10, 3,  HPT("10d8"), "2d8/3d6"}
+},
+{"succubus (Servant of Alzoll)",
+        10, TRUE,   TRUE,   's',    "15-18",
+        {ISMEAN, HIGHCAST, CANSUMMON, BMAGICHIT, CANDARKEN, CANBARGAIN},
+        "lesser demon (Alzoll)", 1,
+        6,
+        {11,    2100,   13, 0,  HPT("6d8"), "1d3/1d3"}
+},
+{"hero-mage (Keoghtom)",
+        100,    TRUE,   TRUE,   'k',    "19",
+        {CANCAST, ISUNIQUE, CANBARGAIN, CANWIELD, CANSHOOT, CANSUMMON, ISFAST, HIGHFRIENDLY},
+        "lesser god (Celestian the Far Wanderer)", 1,
+        45,
+        {12,    42000L, 25, -8, HPT("0d8+77"), "3d4"}
+},
+{"arch-mage (Heward)",
+        100,    TRUE,   TRUE,   'H',    "20",
+        {CANCAST, ISUNIQUE, CANBARGAIN, CANWIELD, CANSHOOT, CANSUMMON, ISFAST, HIGHFRIENDLY},
+        "arch-mage (Mordenkainen)", 1,
+        50,
+        {18,    50000L, 25, -3, HPT("0d8+96"), "3d4"}
+},
+{"arch-mage (Mordenkainen)",
+        100,    TRUE,   TRUE,   'M',    "20",
+        {CANCAST, ISUNIQUE, CANBARGAIN, CANWIELD, CANSHOOT, CANSUMMON, ISFAST, HIGHFRIENDLY},
+        "hero-mage (Murlynd)", 1,
+        50,
+        {18,    50000L, 25, -3, HPT("0d8+96"), "3d4"}
+},
+{"hero-mage (Murlynd)",
+        100,    TRUE,   TRUE,   'm',    "20",
+        {CANCAST, ISUNIQUE, CANBARGAIN, CANWIELD, CANSHOOT, CANSUMMON, ISFAST, HIGHFRIENDLY},
+        "hero-mage (Keoghtom)", 1,
+        50,
+        {19,    56000L, 25, -2, HPT("0d8+135"), "3d4"}
+},
+{"hero (Kelanen, Prince of Swords)",
+        100,    TRUE,   TRUE,   'k',    "17",
+        {ISUNIQUE, CANBARGAIN, CANWIELD, CANSHOOT, CANSUMMON, ISFAST, HIGHFRIENDLY},
+        "lesser goddess (Xan Yae, Lady of Perfection)", 1,
+        50,
+        {19,    53000L, 25, -5, HPT("0d8+159"), "3d4"}
+},
+{"styracosaurus",
+        0,  TRUE,   TRUE,   'S',    "0-0",
+        {ISMEAN, CANTRAMPLE, ISLARGE},
+        0, 0,
+        14,
+        {18,    1950,   9,  3,  HPT("10d8"), "2d8"}
+},
+{"shedu",
+        0,  TRUE,   TRUE,   's',    "13-18",
+        {CANFLY, MEDCAST, CANBARGAIN, ISFRIENDLY},
+        0, 0,
+        14,
+        {13,    1950,   9,  4,  HPT("9d8+9"), "1d6/1d6"}
+},
+{"black pudding",
+        70, TRUE,   FALSE,  'P',    "0-0",
+        {ISSLOW, ISMEAN, CANRUST, NOCOLD, BOLTDIVIDE, BLOWDIVIDE, ISSCAVENGE},
+        0, 0,
+        14,
+        {10,    2000,   10, 6,  HPT("10d8"), "3d8"}
+},
+{"mastadon",
+        0,  TRUE,   TRUE,   'm',    "4-6",
+        {ISMEAN, CANTRAMPLE, CANHUG, ISFLOCK, ISLARGE},
+        0, 0,
+        16,
+        {19,    2000,   9,  6,  HPT("12d8"), "2d8/2d8/2d6/2d6/2d6"}
+},
+{"succubus (Servant of Aishapra)",
+        10, TRUE,   TRUE,   's',    "15-18",
+        {ISMEAN, HIGHCAST, CANSUMMON, BMAGICHIT, CANDARKEN, CANBARGAIN},
+        "lesser demon (Aishapra)", 1,
+        6,
+        {11,    2100,   13, 0,  HPT("6d8"), "1d3/1d3"}
+},
+{"giant scorpion",
+        30, TRUE,   FALSE,  'S',    "0-0",
+        {ISFAST, CANPOISON, ISLARGE},
+        0, 0,
+        10,
+        {12,    2000,   8,  4,  HPT("8d8"), "1d10/1d10/1d4"}
+},
+{"genii",
+        30, TRUE,   TRUE,   'g',    "12-18",
+        {HIGHCAST, CANSUMMON, ISFAST, CANSPEAK, MAGICHIT, ISLARGE, LOWFRIENDLY},
+        "djinni", 2,
+        10,
+        {12,    3000,   7,  3,  HPT("7d8+3"), "2d6/2d6"}
+},
+{"mammoth",
+        0,  TRUE,   TRUE,   'M',    "4-6",
+        {ISMEAN, CANTRAMPLE, CANHUG, ISFLOCK, ISLARGE},
+        0, 0,
+        18,
+        {20,    3000,   8,  5,  HPT("13d8"), "3d6/3d6/2d8/2d6/2d6"}
+},
+{"gelatinous blue horror",
+        100,    TRUE,   TRUE,   'g',    "0-0",
+        {ISMEAN, CANBACID, NOSHARP, HALFDAMAGE, NOBOLT, ISLARGE},
+        0, 0,
+        55,
+        {10,    7000,   10, 6,  HPT("10d8"), "1d5+4"}
+},
+{"stone gargoyle",
+        25, TRUE,   TRUE,   'g',    "6-12",
+        {ISMEAN, CANSUMMON, MAGICHIT, NOBOLT, NOCOLD, NOFIRE},
+        "gargoyle", 3,
+        10,
+        {18,    2500,   7,  1,  HPT("4d8+4"), "1d6/1d6/2d6/2d4"}
+},
+{"succubus (Servant of Kevokulli)",
+        10, TRUE,   TRUE,   's',    "15-18",
+        {ISMEAN, HIGHCAST, CANSUMMON, BMAGICHIT, CANDARKEN, CANBARGAIN},
+        "lesser demon (Kevokulli)", 1,
+        6,
+        {11,    2100,   13, 0,  HPT("6d8"), "1d3/1d3"}
+},
+{"koppleganger",
+        10, TRUE,   TRUE,   'k',    "5-8",
+        {ISMEAN, CANSURPRISE, CANSEE},
+        0, 0,
+        10,
+        {7, 2000,   15, 2,  HPT("4d4"), "1d12"}
+},
+{"kittyhawk",
+        10, TRUE,   TRUE,   'K',    "5-8",
+        {ISMEAN, CANFLY, CANSURPRISE, ISSMALL, ISMANY, CANSEE},
+        0, 0,
+        10,
+        {7, 2000,   15, 2,  HPT("4d4"), "1d2/1d2/1d2/1d3/1d3/1d3"}
+},
+{"rock hound",
+        0,  TRUE,   TRUE,   'R',    "5-8",
+        {ISMEAN, CANINWALL, CANSUMMON, TOUCHSTONE, CANSURPRISE, CANSEE},
+        "vilstrak", 1,
+        20,
+        {10,    2250,   5,  3,  HPT("7d8"), "3d10"}
+},
+{"succubus (Servant of Balor)",
+        10, TRUE,   TRUE,   's',    "15-18",
+        {ISMEAN, HIGHCAST, CANSUMMON, BMAGICHIT, CANDARKEN, CANBARGAIN},
+        "lesser demon (Balor)", 1,
+        6,
+        {11,    2100,   13, 0,  HPT("6d8"), "1d3/1d3"}
+},
+{"kodiac bear",
+        0,  TRUE,   TRUE,   'U',    "5-8",
+        {ISMEAN, CANSUMMON, CANHUG, ISLARGE},
+        "cave bear", 2,
+        20,
+        {18,    2000,   10, -1, HPT("12d8"), "3d8/2d6/2d6"}
+},
+{"very old dragon",
+        30, TRUE,   FALSE,  'd',    "15-16",
+        {ISMEAN, CANBRANDOM, CANSUMMON, ISGREED, CANFRIGHTEN, ISLARGE, LOWFRIENDLY},
+        "young dragon", 1,
+        11,
+        {10,    2000,   8,  2,  HPT("55d1"), "1d10/1d10/3d12"}
+},
+{"hezrou",
+        15, TRUE,   TRUE,   'h',    "5-7",
+        {ISMEAN, CANFRIGHTEN, CANSEE, CANSUMMON, ISUNDEAD, ISLARGE},
+        "horned devil", 2,
+        12,
+        {10,    2000,   9,  -2, HPT("9d8"), "1d3/1d3/4d4"}
+},
+{"loxodant",
+        0,  TRUE,   TRUE,   'L',    "4-6",
+        {ISMEAN, CANTRAMPLE, CANHUG, ISFAST},
+        0, 0,
+        16,
+        {18,    2150,   9,  6,  HPT("11d8"), "2d8/2d8/2d6/2d6/2d6"}
+},
+{"flesh golem",
+        0,  TRUE,   TRUE,   'f',    "0-0",
+        {ISMEAN, MAGICHIT, ISLARGE},
+        0, 0,
+        0,
+        {18,    2380,   9,  9,  HPT("0d0+40"), "2d8/2d8"}
+},
+{"glabrezu",
+        25, TRUE,   FALSE,  'G',    "8-10",
+        {ISMEAN, CANFRIGHTEN, CANSEE, CANSUMMON, ISUNDEAD, ISLARGE},
+        "barbed devil", 2,
+        14,
+        {10,    2400,   10, -4, HPT("10d8"), "2d6/2d6/1d3/1d3/1d4+1"}
+},
+{"succubus (Servant of Ter-soth)",
+        10, TRUE,   TRUE,   's',    "15-18",
+        {ISMEAN, HIGHCAST, CANSUMMON, BMAGICHIT, CANDARKEN, CANBARGAIN},
+        "lesser demon (Ter-soth)", 1,
+        6,
+        {11,    2100,   13, 0,  HPT("6d8"), "1d3/1d3"}
+},
+{"allosaurus",
+        0,  TRUE,   TRUE,   'a',    "0-0",
+        {ISMEAN, CANTRAMPLE, ISFAST, ISLARGE},
+        0, 0,
+        20,
+        {18,    2400,   10, 5,  HPT("15d8"), "1d4/1d4/6d4"}
+},
+{"couatl",
+        15, TRUE,   FALSE,  'c',    "15-18",
+        {ISMEAN, HIGHCAST, CANHUG, CANPOISON, HIGHFRIENDLY},
+        0, 0,
+        12,
+        {16,    2400,   10, 5,  HPT("9d8"), "2d4/1d3"}
+},
+{"succubus (Servant of Rehnaremme)",
+        10, TRUE,   TRUE,   's',    "15-18",
+        {ISMEAN, HIGHCAST, CANSUMMON, BMAGICHIT, CANDARKEN, CANBARGAIN},
+        "lesser demon (Rehnaremme)", 1,
+        6,
+        {11,    2100,   13, 0,  HPT("6d8"), "1d3/1d3"}
+},
+{"banshee",
+        0,  TRUE,   FALSE,  'B',    "15-20",
+        {ISSHADOW, CANSUMMON, CANSHRIEK, CANSURPRISE, CANFRIGHTEN, NOCOLD, NOBOLT, MAGICHIT, ISUNDEAD},
+        "shrieker", 10,
+        10,
+        {10,    2450,   10, 0,  HPT("7d8"), "1d8"}
+},
+{"spirit naga",
+        25, TRUE,   FALSE,  's',    "13-16",
+        {ISMEAN, CANPOISON, CANSNORE, HIGHCAST, ISUNDEAD},
+        0, 0,
+        14,
+        {10,    2700,   10, 4,  HPT("9d8"), "1d3"}
+},
+{"dire wolf",
+        10, TRUE,   TRUE,   'w',    "3-9",
+        {ISMEAN, CANSUMMON, ISLARGE},
+        "warg", 3,
+        5,
+        {10,    1440,   8,  0,  HPT("8d8"), "1d8"}
+},
+{"succubus (Servant of Wendonai)",
+        10, TRUE,   TRUE,   's',    "15-18",
+        {ISMEAN, HIGHCAST, CANSUMMON, BMAGICHIT, CANDARKEN, CANBARGAIN},
+        "lesser demon (Wendonai)", 1,
+        6,
+        {11,    2100,   13, 0,  HPT("6d8"), "1d3/1d3"}
+},
+{"roper",
+        80, TRUE,   FALSE,  'r',    "13-16",
+        {ISMEAN, ISSLOW, CANHUG, CANHOLD, NOBOLT, CANBBURN, ISLARGE},
+        0, 0,
+        16,
+        {19,    2750,   10, 0,  HPT("11d8"), "5d4"}
+},
+{"bone devil",
+        0,  TRUE,   TRUE,   'd',    "11-12",
+        {ISMEAN, CANFLY, CANFRIGHTEN, CANSEE, CANSUMMON, CANSURPRISE, CANCHILL, ISUNDEAD, ISLARGE},
+        "hezrou", 2,
+        12,
+        {10,    2800,   9,  -1, HPT("9d8"), "5d4"}
+},
+{"air elemental",
+        0,  TRUE,   TRUE,   'a',    "3-5",
+        {ISMEAN, CANFLY, ISSHADOW, BMAGICHIT, ISLARGE},
+        0, 0,
+        15,
+        {18,    2850,   9,  2,  HPT("12d8"), "2d10"}
+},
+{"earth elemental",
+        0,  TRUE,   TRUE,   'e',    "3-5",
+        {ISMEAN, CANINWALL, CANSURPRISE, ISSLOW, BMAGICHIT, ISLARGE},
+        0, 0,
+        15,
+        {18,    2850,   9,  2,  HPT("12d8"), "4d8"}
+},
+{"fire elemental",
+        0,  TRUE,   TRUE,   'f',    "3-5",
+        {ISMEAN, NOFIRE, CANBFIRE, BMAGICHIT, ISLARGE},
+        0, 0,
+        15,
+        {18,    2850,   9,  2,  HPT("12d8"), "3d8"}
+},
+{"cold elemental",
+        0,  TRUE,   TRUE,   'c',    "3-5",
+        {ISMEAN, NOCOLD, CANBICE, BMAGICHIT, ISLARGE},
+        0, 0,
+        15,
+        {18,    2850,   9,  2,  HPT("12d8"), "3d8"}
+},
+{"succubus (Servant of Marilith)",
+        10, TRUE,   TRUE,   's',    "15-18",
+        {ISMEAN, HIGHCAST, CANSUMMON, BMAGICHIT, CANDARKEN, CANBARGAIN},
+        "lesser demon (Marilith)", 1,
+        6,
+        {11,    2100,   13, 0,  HPT("6d8"), "1d3/1d3"}
+},
+{"tarry demodand (farastu)",
+        0,  TRUE,   TRUE,   'T',    "18",
+        {ISMEAN, MAGICHIT, CANSTICK},
+        0, 0,
+        16,
+        {19,    2850,   9,  -1,     HPT("11d8"), "1d6+1/1d6+1/3d4"}
+},
+{"wood elemental",
+        0,  TRUE,   TRUE,   'w',    "3-5",
+        {ISMEAN, CANBBURN, CANSUMMON, BMAGICHIT, ISLARGE},
+        "entwife", 1,
+        15,
+        {18,    2850,   9,  2,  HPT("12d8"), "3d8"}
+},
+{"greater basilisk",
+        70, TRUE,   FALSE,  'B',    "5-8",
+        {ISGREED, CANSUMMON, LOOKSTONE, CANPOISON, LOOKSTONE},
+        "basilisk", 2,
+        16,
+        {10,    3000,   7,  2,  HPT("10d8"), "2d6/2d8"}
+},
+{"lesser demon (Bilwhr)",
+        0,  TRUE,   TRUE,   'b',    "12-14",
+        {ISUNIQUE, CANFLY, ISMEAN, CANWIELD, CANCAST, CANFRIGHTEN, BMAGICHIT, CANSUMMON, CANDARKEN, ISLARGE},
+        "hezrou", 3,
+        16,
+        {14,    3000,   8,  -1, HPT("11d8"), "1d4/1d4/2d4"}
+},
+{"lesser demon (Johud)",
+        0,  TRUE,   TRUE,   'j',    "12-14",
+        {ISUNIQUE, CANFLY, ISMEAN, CANWIELD, CANCAST, CANFRIGHTEN, BMAGICHIT, CANSUMMON, CANDARKEN, ISLARGE},
+        "hezrou", 3,
+        16,
+        {14,    3000,   8,  -1, HPT("11d8"), "1d4/1d4/2d4"}
+},
+{"lesser demon (Nalfeshnee)",
+        0,  TRUE,   TRUE,   'b',    "12-14",
+        {ISUNIQUE, CANFLY, ISMEAN, CANWIELD, CANCAST, CANFRIGHTEN, BMAGICHIT, CANSUMMON, CANDARKEN, ISLARGE},
+        "hezrou", 3,
+        16,
+        {14,    3000,   8,  -1, HPT("11d8"), "1d4/1d4/2d4"}
+},
+{"stegosaurus",
+        0,  TRUE,   TRUE,   'S',    "0-0",
+        {ISMEAN, ISLARGE},
+        0, 0,
+        25,
+        {18,    3000,   9,  3,  HPT("18d8"), "5d4"}
+},
+{"lesser demon (Aishapra)",
+        0,  TRUE,   TRUE,   'a',    "12-14",
+        {ISUNIQUE, CANFLY, ISMEAN, CANWIELD, CANSEE, BMAGICHIT, CANSUMMON, ISLARGE},
+        "hezrou", 3,
+        12,
+        {12,    3000,   8,  -7, HPT("7d8+7"), "2d4"}
+},
+{"lesser demon (Kevokulli)",
+        0,  TRUE,   TRUE,   'k',    "12-14",
+        {ISUNIQUE, CANFLY, ISMEAN, CANWIELD, CANSEE, BMAGICHIT, CANSUMMON, ISLARGE},
+        "hezrou", 3,
+        12,
+        {12,    3000,   8,  -7, HPT("7d8+7"), "2d4"}
+},
+{"lesser demon (Marilith)",
+        0,  TRUE,   TRUE,   'm',    "12-14",
+        {ISUNIQUE, CANFLY, ISMEAN, CANWIELD, CANSEE, BMAGICHIT, CANSUMMON, ISLARGE},
+        "hezrou", 3,
+        12,
+        {12,    3000,   8,  -7, HPT("7d8+7"), "2d4"}
+},
+{"lesser demon (Rehnaremme)",
+        0,  TRUE,   TRUE,   'r',    "12-14",
+        {ISUNIQUE, CANFLY, ISMEAN, CANWIELD, CANSEE, BMAGICHIT, CANSUMMON, ISLARGE},
+        "hezrou", 3,
+        12,
+        {12,    3000,   8,  -7, HPT("7d8+7"), "2d4"}
+},
+{"guardian naga",
+        100,    TRUE,   FALSE,  'G',    "16-18",
+        {CANPOISON, NOMOVE, HIGHCAST, HIGHFRIENDLY},
+        0, 0,
+        16,
+        {10,    3550,   8,  3,  HPT("11d8+4"), "1d6/2d4"}
+},
+{"lesser demon (Alzoll)",
+        0,  TRUE,   TRUE,   'A',    "14-16",
+        {ISUNIQUE, CANFLY, ISMEAN, CANWIELD, CANCAST, CANFRIGHTEN, BMAGICHIT, CANSUMMON, CANDARKEN, ISLARGE},
+        "glabrezu", 3,
+        12,
+        {16,    3600,   8,  -2, HPT("8d8+8"), "1d12+1"}
+},
+{"clay golem",
+        0,  TRUE,   TRUE,   'C',    "0-0",
+        {NOSHARP, ISMEAN, ISLARGE},
+        0, 0,
+        0,
+        {18,    3600,   8,  7,  HPT("0d0+50"), "3d10"}
+},
+{"shade",
+        0,  TRUE,   TRUE,   's',    "15-20",
+        {ISSHADOW, CANSUMMON, ISUNDEAD, ISMEAN, CANDRAIN, MAGICHIT},
+        "night hag", 2,
+        15,
+        {10,    4250,   4,  4,  HPT("4d10"), "1d6"}
+},
+{"lesser demon (Balor)",
+        0,  TRUE,   TRUE,   'B',    "14-16",
+        {ISUNIQUE, CANFLY, ISMEAN, CANWIELD, CANCAST, CANFRIGHTEN, BMAGICHIT, CANSUMMON, CANDARKEN, ISLARGE},
+        "glabrezu", 3,
+        12,
+        {16,    3600,   8,  -2, HPT("8d8+8"), "1d12+1"}
+},
+{"lesser demon (Errtu)",
+        0,  TRUE,   TRUE,   'E',    "14-16",
+        {ISUNIQUE, CANFLY, ISMEAN, CANWIELD, CANCAST, CANFRIGHTEN, BMAGICHIT, CANSUMMON, CANDARKEN, ISLARGE},
+        "glabrezu", 3,
+        12,
+        {16,    3600,   8,  -2, HPT("8d8+8"), "1d12+1"}
+},
+{"wyvergon",
+        5,  TRUE,   TRUE,   'w',    "3-10",
+        {ISMEAN, CANPOISON, LOOKSTONE, NOFIRE, ISLARGE},
+        0, 0,
+        10,
+        {14,    1750,   9,  2,  HPT("8d8+1"), "2d8/2d6/1d6"}
+},
+{"lesser demon (Ndulu)",
+        0,  TRUE,   TRUE,   'N',    "14-16",
+        {ISUNIQUE, CANFLY, ISMEAN, CANWIELD, CANCAST, CANFRIGHTEN, BMAGICHIT, CANSUMMON, CANDARKEN, ISLARGE},
+        "glabrezu", 3,
+        12,
+        {16,    3600,   8,  -2, HPT("8d8+8"), "1d12+1"}
+},
+{"lesser demon (Ter-soth)",
+        0,  TRUE,   TRUE,   'T',    "14-16",
+        {ISUNIQUE, CANFLY, ISMEAN, CANWIELD, CANCAST, CANFRIGHTEN, BMAGICHIT, CANSUMMON, CANDARKEN, ISLARGE},
+        "glabrezu", 3,
+        12,
+        {16,    3600,   8,  -2, HPT("8d8+8"), "1d12+1"}
+},
+{"lesser demon (Wendonai)",
+        0,  TRUE,   TRUE,   'T',    "14-16",
+        {ISUNIQUE, CANFLY, ISMEAN, CANWIELD, CANCAST, CANFRIGHTEN, BMAGICHIT, CANSUMMON, CANDARKEN, ISLARGE},
+        "glabrezu", 3,
+        12,
+        {16,    3600,   8,  -2, HPT("8d8+8"), "1d12+1"}
+},
+{"lesser demon (Cerberus)",     /* Three heads - fire, clorine, acid */
+        0,  TRUE,   TRUE,   'T',    "14-16",
+        {ISUNIQUE, ISMEAN, MAGICHIT, CANSUMMON, CANBPGAS, CANBACID, CANBFIRE, CANSEE, NOFIRE, ISLARGE, HASOXYGEN},
+        "hell hound", 6,
+        15,
+        {16,    3600,   9,  1,  HPT("8d8+8"), "2d4/2d4/2d4"}
+},
+{"slime demodand (kelubar)",
+        0,  TRUE,   TRUE,   'S',    "14-20",
+        {MAGICHIT, CANPOISON, CANWIELD, CANBARGAIN},
+        0, 0,
+        18,
+        {20,    3959,   9,  -2,     HPT("13d8"), "2d4/2d4/4d4"}
+},
+{"nazgul (Ringwraith)",
+        0,  TRUE,   TRUE,   'z',    "14-16",
+        {ISMEAN, CANPOISON, ISSHADOW, CANRUST, CANHUH, CANFRIGHTEN, CANDRAIN, MAGICHIT, ISFLOCK, CANSUMMON},
+        "dire wolf", 2,
+        15,
+        {16,    4000,   10, 0,  HPT("8d8+8"), "1d10"}
+},
+{"vampire",
+        20, TRUE,   TRUE,   'V',    "15-16",
+        {ISMEAN, CANFLY, CANSUMMON, ISREGEN, CANSUCK, ISUNDEAD},
+        "barrow wight", 2,
+        16,
+        {20,    3800,   8,  1,  HPT("8d8+3"), "1d10"}
+},
+{"camarasaurus",
+        0,  TRUE,   FALSE,  'c',    "0-0",
+        {ISFLEE, CANTRAMPLE, ISLARGE},
+        0, 0,
+        30,
+        {24,    4000,   9,  6,  HPT("20d8"), "3d4"}
+},
+{"triceratops",
+        0,  TRUE,   TRUE,   'T',    "0-0",
+        {ISMEAN, CANTRAMPLE, ISLARGE},
+        0, 0,
+        20,
+        {18,    4000,   9,  3,  HPT("16d8"), "1d8/1d12/1d12"}
+},
+{"ghost",
+        0,  TRUE,   TRUE,   'g',    "12-14",
+        {ISSHADOW, CANSUMMON, ISMEAN, CANFRIGHTEN, MAGICHIT, ISUNDEAD},
+        "spectre", 2,
+        14,
+        {10,    4050,   9,  0,  HPT("10d8"), "1d4"}
+},
+{"baluchitherium",
+        0,  TRUE,   TRUE,   'B',    "3-5",
+        {ISMEAN, CANTRAMPLE, ISLARGE},
+        0, 0,
+        18,
+        {18,    4200,   9,  5,  HPT("14d8"), "4d5"}
+},
+{"nazgul (Witch-King of Angmar)",
+        0,  TRUE,   FALSE,  'z',    "19",
+        {ISUNIQUE, ISMEAN, CANINFEST, ISSHADOW, CANRUST, CANHUH, CANFRIGHTEN, DOUBLEDRAIN, BMAGICHIT, CANCAST, CANBARGAIN, CANSUMMON},
+        "nazgul (Ringwraith)", 8,
+        30,
+        {18,    50000L, 30, -2, HPT("0d8+100"), "2d10"}
+},
+{"maiar (Melian, wife of Thingol)",
+        0,  TRUE,   FALSE,  'M',    "19",
+        {ISUNIQUE, BMAGICHIT, CANSEE, CANSUMMON, MEDFRIENDLY},
+        "noldor elf", 10,
+        30,
+        {10,    55000L, 45, 4,  HPT("0d8+60"), "1d10"}
+},
+{"maiar (Eonwe, Herald of Manwe)",
+        0,  TRUE,   FALSE,  'E',    "19",
+        {ISUNIQUE, BMAGICHIT, CANSEE, CANSUMMON, MEDFRIENDLY},
+        "valar (Manwe, Lord of Arda)", 1,
+        0,
+        {20,    55000L, 45, 4,  HPT("0d8+120"), "2d10"}
+},
+{"maiar (Sauron, Lord of the Rings)",
+        0,  TRUE,   FALSE,  'S',    "19",
+        {ISUNIQUE, ISMEAN, ISSHADOW, BMAGICHIT, CANSEE, CANSUMMON},
+        "nazgul (Witch-King of Angmar)", 1,
+        0,
+        {20,    55000L, 35, -1, HPT("0d8+120"), "2d10"}
+},
+{"maiar (Irmo, Master of Spirit)",
+        0,  TRUE,   FALSE,  'I',    "19",
+        {ISUNIQUE, ISMEAN, BMAGICHIT, CANSEE, CANSUMMON, MEDFRIENDLY},
+        "spectre", 3,
+        0,
+        {20,    55000L, 35, 5,  HPT("0d8+120"), "2d10"}
+},
+{"maiar (Namo, Master of Spirit)",
+        0,  TRUE,   FALSE,  'N',    "19",
+        {ISUNIQUE, ISMEAN, BMAGICHIT, CANSEE, CANSUMMON, MEDFRIENDLY},
+        "ghost", 3,
+        0,
+        {20,    55000L, 35, 5,  HPT("0d8+120"), "2d10"}
+},
+{"maiar (Uinen, Lady of the Seas)",
+        0,  TRUE,   FALSE,  'U',    "19",
+        {ISUNIQUE, BMAGICHIT, CANSEE, CANSUMMON, MEDFRIENDLY},
+        "valar (Ulmo, God of Waters)", 1,
+        0,
+        {10,    55000L, 35, 5,  HPT("0d8+120"), "2d10"}
+},
+{"maiar (Ilmare, Handmaiden of Varda)",
+        0,  TRUE,   FALSE,  'I',    "19",
+        {ISUNIQUE, BMAGICHIT, CANSEE, CANSUMMON, MEDFRIENDLY},
+        "valar (Varda, Elbereth Gilthoniel)", 1,
+        0,
+        {10,    55000L, 35, 5,  HPT("0d8+60"), "1d10"}
+},
+{"maiar (Balrog)",
+        100,    TRUE,   TRUE,   'B',    "20",
+        {ISMEAN,  BMAGICHIT, CANWIELD, CANCAST, HASFIRE, ISUNDEAD},
+        "pit fiend", 3,
+        50,
+        {22,    39000L, 20, 0,  HPT("16d8"), "4d8"}
+},
+{"ice devil",
+        30, TRUE,   FALSE,  'I',    "13-14",
+        {CANFLY, ISMEAN, CANSEE, ISREGEN, CANFRIGHTEN, CANSUMMON, CANBICE, NOCOLD, ISLARGE, ISUNDEAD},
+        "glabrezu", 2,
+        16,
+        {20,    4400,   11, -4, HPT("11d8"), "1d4/1d4/2d4/3d4"}
+},
+{"purple worm",
+        70, TRUE,   FALSE,  'P',    "0-0",
+        {ISMEAN, ISLARGE},
+        0, 0,
+        20,
+        {10,    4900,   15, 6,  HPT("15d8"), "2d12/2d4"}
+},
+{"diplodocus",
+        0,  TRUE,   TRUE,   'd',    "0-0",
+        {CANTRAMPLE, ISLARGE},
+        0, 0,
+        35,
+        {23,    5000,   15, 5,  HPT("24d8"), "3d6"}
+},
+{"brontosaurus",
+        0,  TRUE,   TRUE,   'b',    "0-0",
+        {CANTRAMPLE, ISLARGE},
+        0, 0,
+        35,
+        {23,    5000,   15, 5,  HPT("30d8"), "3d6"}
+},
+{"roc",
+        0,  TRUE,   TRUE,   'r',    "3-5",
+        {ISMEAN, CANFLY, ISLARGE},
+        0, 0,
+        25,
+        {23,    5000,   15, 4,  HPT("18d8"), "3d6/3d6/4d6"}
+},
+{"silver cloud",
+        100,    TRUE,   TRUE,   'c',    "0-0",
+        {CANFLY, HALFDAMAGE, CANBBOLT, NOBOLT, ISLARGE},
+        0, 0,
+        10,
+        {10,    4000,   13, 9,  HPT("6d8"), "1d4"}
+},
+{"coachman of death",
+        100,    TRUE,   TRUE,   'C',    "12-22",
+        {ISMEAN, ISUNDEAD, CANFRIGHTEN, MAGICHIT },
+        0, 0,
+        50,
+        {10,    4000,   10, -2, HPT("10d8"), "1d8+2"}
+},
+{"blue pool horror",
+        100,    TRUE,   FALSE,  'b',    "0-0",
+        {ISMEAN, CANBACID, NOMETAL, NOSHARP, HALFDAMAGE, NOBOLT, ISLARGE},
+        0, 0,
+        35,
+        {10,    5000,   8,  8,  HPT("8d8"), "1d5+4"}
+},
+{"cetiosaurus",
+        0,  TRUE,   TRUE,   'c',    "0-0",
+        {CANTRAMPLE, ISLARGE},
+        0, 0,
+        35,
+        {23,    5000,   15, 6,  HPT("24d8"), "3d6"}
+},
+{"brachiosaurus",
+        0,  TRUE,   TRUE,   'B',    "0-0",
+        {CANTRAMPLE, ISLARGE},
+        0, 0,
+        35,
+        {23,    5000,   15, 5,  HPT("36d8"), "5d4"}
+},
+{"shaggy demodand (shator)",
+        0,  TRUE,   TRUE,   's',    "14-25",
+        {CANSUMMON, BMAGICHIT, LOWCAST, CANWIELD, CANSEE, CANSTINK},
+        "tarry demodand (farastu)", 8,
+        20,
+        {21,    5250,   13, -3,     HPT("15d8"), "1d8+1/1d8+1/5d4"}
+},
+{"tyranosaurus rex",
+        0,  TRUE,   TRUE,   'T',    "0-0",
+        {ISMEAN, ISFAST, ISLARGE},
+        0, 0,
+        25,
+        {18,    6550,   12, 5,  HPT("18d8"), "1d6/1d6/5d8"}
+},
+{"pit fiend",
+        100,    TRUE,   TRUE,   'f',    "15-16",
+        {ISMEAN, CANSEE, BMAGICHIT, CANFRIGHTEN, CANHOLD, CANSUMMON, CANBFIRE, NOFIRE, ISLARGE, ISUNDEAD},
+        "erinyes", 6,
+        18,
+        {22,    7900,   13, -3, HPT("13d8"), "1d4+4/1d6+6"}
+},
+{"hound (Nemoud, Servant of Trithereon)",
+        0,  TRUE,   TRUE,   'N',    "5",
+        {ISFAST, MAGICHIT, ISUNIQUE, ISLARGE, ISFRIENDLY},
+        "lesser god (Trithereon the Summoner)", 1,
+        16,
+        {18,    8100,   13, 0,  HPT("0d8+64"), "4d4"}
+},
+{"ki-rin",
+        25, TRUE,   TRUE,   'k',    "16-22",
+        {CANFLY, MEDCAST, CANSPEAK, DRAINBRAIN, CANBARGAIN, ISLARGE, ISFRIENDLY},
+        0, 0,
+        16,
+        {13,    8500,   13, -5, HPT("12d8"), "2d4/2d4/3d6"}
+},
+{"stone golem",
+        0,  TRUE,   TRUE,   'S',    "0-0",
+        {ISMEAN, CANBSGAS, BMAGICHIT, ISLARGE, HASOXYGEN},
+        0, 0,
+        0,
+        {22,    8950,   13, 5,  HPT("0d0+60"), "3d8"}
+},
+{"titanothere",
+        100,    TRUE,   FALSE,  't',    "17-20",
+        {ISLARGE},
+        0, 0,
+        30,
+        {10,    9000,   19, 0,  HPT("9d8"), "2d8/1d6"}
+},
+{"titan",
+        100,    TRUE,   FALSE,  't',    "17-20",
+        {ISSHADOW, ISLARGE, LOWFRIENDLY},
+        0, 0,
+        30,
+        {10,    9000,   19, 0,  HPT("19d8"), "7d6"}
+},
+{"diamond golem",
+        0,  TRUE,   TRUE,   'D',    "0-0",
+        {ISMEAN, NOBOLT, CANBLIND, BMAGICHIT, ISLARGE},
+        0, 0,
+        0,
+        {22,    9500,   13, -2, HPT("0d0+80"), "3d8"}
+},
+{"lich",
+        100,    TRUE,   TRUE,   'l',    "19-20",
+        {ISMEAN, CANSUMMON, CANPARALYZE, CANFRIGHTEN, MAGICHIT, ISUNDEAD, NOBOLT, CANCAST},
+        "vampire", 4,
+        16,
+        {10,    10500,  11, 0,  HPT("11d8"), "1d10"}
+},
+{"falcon (Harrus, Servant of Trithereon)",
+        0,  TRUE,   TRUE,   'H',    "6",
+        {CANFLY, MAGICHIT, ISUNIQUE, ISLARGE, ISFRIENDLY},
+        "lesser god (Trithereon the Summoner)", 1,
+        16,
+        {18,    11000,  12, 2,  HPT("0d8+72"), "1d4+4/1d4+4"}
+},
+{"beholder",
+        0,  TRUE,   FALSE,  'b',    "14-16",
+        {ISMEAN, ISSLOW, LOOKSTONE, CANFRIGHTEN, LOOKSLOW, CANSNORE, ISLARGE},
+        0, 0,
+        20,
+        {6, 12900,  18, 1,  HPT("5d8+35"), "2d4"}
+},
+{"hill giant",
+        30, TRUE,   TRUE,   'h',    "6-8",
+        {ISMEAN, CANSUMMON, ISLARGE},
+        "ogre", 4,
+        30,
+        {25,    13000,  10, 4,  HPT("8d8+2"), "2d8"}
+},
+{"cyclops",
+        50, TRUE,   TRUE,   'c',    "9-18",
+        {ISMEAN, LOWCAST, CANWIELD, CANSUMMON, ISLARGE},
+        "cave bear", 3,
+        45,
+        {28,    15000,  14, 3,  HPT("12d8"), "2d8"}
+},
+{"stone giant",
+        50, TRUE,   TRUE,   's',    "9-13",
+        {ISMEAN, CANSURPRISE, CANSUMMON, ISLARGE, LOWFRIENDLY},
+        "werebear", 3,
+        35,
+        {28,    14000,  13, 4,  HPT("9d8+3"), "2d8"}
+},
+{"iron golem",
+        0,  TRUE,   TRUE,   'i',    "0-0",
+        {ISMEAN, BMAGICHIT, CANBPGAS, ISLARGE, HASOXYGEN},
+        0, 0,
+        0,
+        {25,    14550,  13, 3,  HPT("0d0+80"), "4d10"}
+},
+{"ancient brass dragon",
+        100,    TRUE,   FALSE,  'r',    "13-14",
+        {CANBSGAS, CANBFGAS, ISGREED, CANBARGAIN, CANFLY, ISLARGE, LOWFRIENDLY, HASOXYGEN},
+        0, 0,
+        50,
+        {10,    20000,  13, 2,  HPT("0d8+64"), "1d4/1d4/4d4"}
+},
+{"ancient chrome dragon",
+        100,    TRUE,   TRUE,   'C',    "8-20",
+        {CANCAST, CANBPGAS, CANBARGAIN, NOBOLT, NOCOLD, NOFIRE, CANFLY, ISLARGE, HASOXYGEN},
+        0, 0,
+        50,
+        {10,    20000,  13, 0,  HPT("0d8+75"), "4d8/1d6/1d6"}
+},
+{"ancient crystal dragon",
+        100,    TRUE,   TRUE,   'C',    "6-12",
+        {ISMEAN, ISGREED, CANCAST, CANBBOLT, NOBOLT, CANFLY, ISLARGE},
+        0, 0,
+        50,
+        {10,    20000,  13, 0,  HPT("0d8+75"), "4d8/1d6/1d6"}
+},
+{"ancient white dragon",
+        100,    TRUE,   TRUE,   'W',    "8-9",
+        {ISMEAN, CANBICE, ISGREED, CANBARGAIN, NOCOLD, CANFLY, ISLARGE},
+        0, 0,
+        50,
+        {10,    20000,  13, 3,  HPT("0d8+56"), "1d4/1d4/2d8"}
+},
+{"ancient black dragon",
+        100,    TRUE,   TRUE,   'a',    "8-10",
+        {ISMEAN, CANBACID, ISGREED, CANBARGAIN, CANFLY, ISLARGE},
+        0, 0,
+        50,
+        {10,    20000,  14, 3,  HPT("0d8+64"), "1d4/1d4/3d6"}
+},
+{"ancient copper dragon",
+        100,    TRUE,   FALSE,  'c',    "13-14",
+        {CANBACID, CANBSLGAS, ISGREED, CANBARGAIN, CANFLY, ISLARGE, MEDFRIENDLY, HASOXYGEN},
+        0, 0,
+        50,
+        {10,    20000,  15, 1,  HPT("0d8+72"), "1d4/1d4/5d4"}
+},
+{"ancient green dragon",
+        100,    TRUE,   TRUE,   'g',    "8-12",
+        {ISMEAN, CANBGAS, ISGREED, CANBARGAIN, CANFLY, ISLARGE, HASOXYGEN},
+        0, 0,
+        50,
+        {10,    20000,  15, 2,  HPT("0d8+72"), "1d6/1d6/2d10"}
+},
+{"ancient bronze dragon",
+        100,    TRUE,   FALSE,  'L',    "15-16",
+        {CANBBOLT, CANBFGAS, ISGREED, CANBARGAIN, NOBOLT, CANFLY, ISLARGE, MEDFRIENDLY, HASOXYGEN},
+        0, 0,
+        50,
+        {10,    20000,  16, 0,  HPT("0d8+80"), "1d6/1d6/4d6"}
+},
+{"ancient blue dragon",
+        100,    TRUE,   TRUE,   'u',    "11-12",
+        {ISMEAN, CANBBOLT, ISGREED, CANBARGAIN, NOBOLT, CANFLY, ISLARGE},
+        0, 0,
+        50,
+        {10,    20000,  16, 2,  HPT("0d8+80"), "1d6/1d6/3d8"}
+},
+{"ancient silver dragon",
+        100,    TRUE,   FALSE,  'S',    "15-16",
+        {CANBICE, NOCOLD, CANBPGAS, ISGREED, CANBARGAIN, CANFLY, ISLARGE, MEDFRIENDLY, HASOXYGEN},
+        0, 0,
+        50,
+        {10,    20000,  17, -1, HPT("0d8+88"), "1d6/1d6/5d6"}
+},
+{"frost giant",
+        50, TRUE,   TRUE,   'F',    "5-10",
+        {ISMEAN, CARRYGOLD, NOCOLD, ISLARGE},
+        0, 0,
+        40,
+        {25,    20000,  15, 4,  HPT("10d8+4"), "4d6"}
+},
+{"ancient red dragon",
+        100,    TRUE,   TRUE,   'D',    "15-16",
+        {ISMEAN, CANBFIRE, ISGREED, CANBARGAIN, NOFIRE, CANFLY, ISLARGE},
+        0, 0,
+        50,
+        {10,    20000,  17, -1, HPT("0d8+88"), "1d8/1d8/3d10"}
+},
+{"ancient gold dragon",
+        100,    TRUE,   FALSE,  'G',    "17-18",
+        {CANBFIRE, CANBGAS, ISGREED, CANBARGAIN, NOFIRE, CANFLY, ISLARGE, HIGHFRIENDLY, HASOXYGEN},
+        0, 0,
+        50,
+        {10,    20000,  18, -2, HPT("0d8+96"), "1d8/1d8/6d6"}
+},
+{"ancient night dragon",  /* Dragon #74 */
+        100,    TRUE,   TRUE,   'N',    "13-15",
+        {CANBRANDOM, CANBLIND, ISLARGE, ISGREED, CANFLY, CANCAST, CANBARGAIN},
+        0, 0,
+        50,
+        {10,    20000,  18, 2,  HPT("8d8"), "4d8"}
+},
+{"ancient electrum dragon",  /* Dragon #74 */
+        100,    TRUE,   TRUE,   'E',    "17-18",
+        {CANBPGAS, CANHUH, ISLARGE, CANFLY, CANCAST, CANBARGAIN, HASOXYGEN},
+        0, 0,
+        50,
+        {10,    20000,  18, 2,  HPT("9d8"), "1d4/1d4/3d8"}
+},
+{"fire giant",
+        50, TRUE,   TRUE,   'f',    "6-10",
+        {ISMEAN, CARRYGOLD, NOFIRE, ISLARGE},
+        0, 0,
+        45,
+        {27,    26000,  15, 3,  HPT("11d8+5"), "5d6"}
+},
+{"cloud giant",
+        30, TRUE,   TRUE,   'c',    "8-14",
+        {ISMEAN,  NOBOLT, CANBBOLT, CANBARGAIN, ISLARGE, MEDFRIENDLY},
+        0, 0,
+        45,
+        {30,    27000,  15, 2,  HPT("12d8+8"), "6d6"}
+},
+{"aerial servant",
+        0,  TRUE,   TRUE,   'a',    "3-5",
+        {ISMEAN, BMAGICHIT, ISSHADOW, LOWFRIENDLY},
+        0, 0,
+        50,
+        {22,    29000,  10, 3,  HPT("16d8"), "4d8"}
+},
+{"storm giant",
+        50, TRUE,   TRUE,   's',    "8-10",
+        {ISMEAN,  NOBOLT, CANBBOLT, CANCAST, CANBARGAIN, ISLARGE, MEDFRIENDLY},
+        0, 0,
+        50,
+        {30,    30000,  15, 1,  HPT("15d8+8"), "7d6"}
+},
+{"valkyrie",
+        0,  TRUE,   FALSE,  'v',    "14-16",
+        {CANFLY, CANSHOOT, CANWIELD, CANFRIGHTEN, MAGICHIT, ISFLOCK, CANSUMMON},
+        "greater god (Odin, All Father)", 1,
+        50,
+        {21,    27000,  25, -2, HPT("0d8+100"), "3d6+3"}
+},
+{"evil sorceress",
+        95, TRUE,   TRUE,   'z',    "17-19",
+        {ISMEAN, STEALGOLD, STEALMAGIC, ISREGEN, CARRYGOLD, ISSCAVENGE, CANSUMMON, CANCAST, CANBARGAIN},
+        "nymph", 4,
+        60,
+        {10,    42000L, 25, -10,    HPT("10d8+50"), "3d8"}
+},
+{"evil sorcerer",
+        95, TRUE,   TRUE,   'Z',    "17-19",
+        {ISMEAN, ISREGEN, CARRYGOLD, ISSCAVENGE, CANSUMMON, CANCAST, CANBARGAIN, STEALGOLD, STEALMAGIC},
+        "evil sorceress", 1,
+        40,
+        {10,    44000L, 25, -10,    HPT("10d9+50"), "3d10"}
+},
+{"time elemental",  /* Dragon #69  - a recursive monster... */
+        50, TRUE,   TRUE,   'T',    "10-30",
+        {ISMEAN, BMAGICHIT, ISFAST, CANBSLGAS, ISSMALL, HALFDAMAGE, NOBOLT, NOFIRE, NOCOLD, NOSHARP, NOMETAL, HASOXYGEN},
+        "time elemental", 2,
+        100,
+        {10,    62000L, 21, 2,  HPT("15d8"), "4d8"}
+},
+{"demon prince (Jubilex)",
+        100,    TRUE,   FALSE,  'J',    "17-18",
+        {ISMEAN, ISUNIQUE, ISREGEN, ISSHADOW, CANHOLD, CANDISEASE, CANSUMMON, ISGOD},
+        "black pudding", 3,
+        0,
+        {10,    47280L, 20, -7, HPT("0d8+88"), "4d10"}
+},
+{"demon prince (Yeenoghu)",
+        100,    TRUE,   FALSE,  'Y',    "15-16",
+        {ISMEAN, ISREGEN, ISUNIQUE, ISSHADOW, CANHOLD, CANPARALYZE, CANSUMMON, ISGOD},
+        "ghoul", 10,
+        0,
+        {10,    54500L, 23, -5, HPT("0d8+100"), "3d6/3d6"}
+},
+{"demon prince (Orcus)",
+        100,    TRUE,   FALSE,  'O',    "19-20",
+        {ISMEAN, ISUNIQUE, CANPOISON, CANBBOLT, CANSUMMON, ISGOD},
+        "vampire", 4,
+        0,
+        {13,    63900L, 27, -6, HPT("0d8+120"), "1d10+3/2d4"}
+},
+{"demi-god (Zagyg the Unpredictable)",  /* Dragon #70 */
+        100,    TRUE,   TRUE,   'Z',    "23",
+        {ISUNIQUE, CANBRANDOM, CANSUMMON, CANWIELD, HIGHFRIENDLY, ISGOD},
+        "greater god (Boccob)", 1,
+        110,
+        {23,    59000L, 26, -2,     HPT("0d8+121"), "4d8"}
+},
+{"demi-god (Wastri, the Hopping Prophet)",  /* Dragon # 71 */
+        100,    TRUE,   TRUE,   'W',    "10",
+        {ISUNIQUE, CANSWIM, CANSUMMON, CANPOISON, CANWIELD, LOWFRIENDLY, ISGOD},
+        "giant toad", 4,
+        100,
+        {18,    61000L, 20, -3,     HPT("0d8+121"), "2d6/1d6/3d8"}
+},
+{"chromatic dragon (Tiamat)",
+        100,    TRUE,   FALSE,  'T',    "17-18",
+        {ISMEAN, ISUNIQUE, CANBFIRE, CANBACID, CANBBOLT, CANBICE, CANBGAS, ISGREED, CANSUMMON, ISGOD, HASOXYGEN},
+        "adult dragon", 5,
+        0,
+        {10,    63580L, 29, 0,  HPT("0d8+128"), "2d8/3d6/2d10/3d8/3d10/1d6"}
+},
+{"arch devil (Geryon)",
+        100,    TRUE,   FALSE,  'g',    "15-16",
+        {ISMEAN, ISUNIQUE, ISSHADOW, CANHUH, CANPOISON, CANSUMMON, ISGOD},
+        "ice devil", 2,
+        0,
+        {13,    61500L, 30, -3, HPT("0d8+133"), "3d6/3d6/2d4"}
+},
+{"lesser god (Ralishaz the Unlooked For)",  /* Dragon # 71 */
+        100,    TRUE,   TRUE,   'R',    "20",
+        {ISUNIQUE, CANSNORE, CANWIELD, ISFAST, LOWFRIENDLY, ISGOD},
+        0, 0,
+        100,
+        {18,    65000L, 22, -6,     HPT("5d10+140"), "1d20/1d20/1d20/1d20"}
+},
+{"lesser god (Obad-hai the Shalm)",  /* Dragon #69 */
+        100,    TRUE,   TRUE,   'O',    "17",
+        {ISUNIQUE, ISREGEN, CANSUMMON, LOWFRIENDLY, ISGOD},
+        "centaur", 10,
+        100,
+        {18,    62000L, 18, -2,     HPT("0d8+144"), "4d8"}
+},
+{"arch devil (Dispater)",
+        100,    TRUE,   FALSE,  'd',    "17-18",
+        {ISMEAN, ISUNIQUE, CANHUH, CANSUMMON, ISGOD},
+        "pit fiend", 2,
+        0,
+        {10,    48040L, 36, -2, HPT("0d8+144"), "4d6"}
+},
+{"lesser god (Trithereon the Summoner)",
+        100,    TRUE,   TRUE,   'T',    "18",
+        {ISUNIQUE, CANWIELD, CANSUMMON, ISFRIENDLY, ISGOD},
+        "hound (Nemoud, Servant of Trithereon)", 1,
+        0,
+        {19,    55000L, 35, -4, HPT("0d8+163"), "1d8+12"}
+},
+{"demi-god (Iuz the Old)",  /* Dragon #67 - enemy of St Cuthbert */
+        100,    TRUE,   TRUE,   'I',    "18",
+        {ISMEAN, CANHUH, CANBPGAS, ISUNIQUE, CANSUMMON, ISGOD, HASOXYGEN},
+        "shade", 2,
+        0,
+        {21,    55000L, 35, -8, HPT("0d8+165"), "1d8+12"}
+},
+{"arch devil (Baalzebul)",
+        100,    TRUE,   FALSE,  'B',    "17-18",
+        {ISMEAN, ISSHADOW, ISUNIQUE, CANHOLD, CANPOISON, CANHUH, CANSUMMON, ISGOD},
+        "horned devil", 4,
+        0,
+        {10,    61410L, 37, -5, HPT("0d8+166"), "2d6"}
+},
+{"platinum dragon (Bahamut)",
+        100,    TRUE,   FALSE,  'B',    "19-20",
+        {ISUNIQUE, CANBICE, CANBGAS, CANBBOLT, ISGREED, CANSUMMON, ISFRIENDLY, ISGOD, HASOXYGEN},
+        "ancient gold dragon", 7,
+        0,
+        {10,    58080L, 38, -3, HPT("0d8+168"), "2d6/2d6/6d8"}
+},
+{"lesser goddess (Xan Yae, Lady of Perfection)",    /* Dragon #68 */
+        100,    TRUE,   FALSE,  'X',    "19",
+        {CANSHOOT, ISUNIQUE, ISGOD, LOWFRIENDLY},
+        0, 0,
+        0,
+        {22,    55000L, 35, -4, HPT("0d8+172"), "6d6"}
+},
+{"lesser goddess (Ehlonna of the Forests)",     /* Dragon #68 */
+        100,    TRUE,   FALSE,  'E',    "19",
+        {CANHUH, CANSHOOT, ISUNIQUE, CANSUMMON, ISGOD, HIGHFRIENDLY},
+        "noldor elf", 30,
+        0,
+        {22,    65000L, 35, -6, HPT("0d8+180"), "3d6+6/1d10"}
+},
+{"lesser god (Pholtus of the Blinding Light)",  /* Dragon #68 */
+        100,    TRUE,   FALSE,  'P',    "19",
+        {HASFIRE, CANBLIND, CANSHOOT, ISUNIQUE, CANWIELD, CANSUMMON, ISGOD, ISFRIENDLY},
+        "phoenix", 2,
+        0,
+        {22,    65000L, 35, -6, HPT("0d8+180"), "3d6+6/1d10"}
+},
+{"demi-god (Vaprak \"The Destroyer\")",
+        0,  TRUE,   TRUE,   'v',    "18",
+        {ISMEAN, ISUNIQUE, ISREGEN, CANSUMMON, ISGOD},
+        "troll", 5,
+        0,
+        {16,    56000L, 26, 0,  HPT("0d8+198"), "2d10/2d10/1d12"}
+},
+{"lesser god (Olidammara the Laughing Rogue)",  /* Dragon #70 */
+        100,    TRUE,   TRUE,   'O',    "18",
+        {ISUNIQUE, CANINWALL, CANSUMMON, ISGOD, LOWFRIENDLY},
+        "halfling", 10,
+        110,
+        {21,    59000L, 30, -9,     HPT("0d8+199"), "4d8"}
+},
+{"devil Asmodeus",
+        100,    TRUE,   FALSE,  'A',    "19-20",
+        {ISMEAN, ISUNIQUE, ISSHADOW, CANHOLD, CANHUH, CANCHILL, CANSUMMON, ISGOD},
+        "pit fiend", 3,
+        0,
+        {10,    80965L, 45, -7, HPT("0d8+199"), "4d10/4d10"}
+},
+{"valar (Yavanna, Giver of Fruits)",
+        100,    TRUE,   FALSE,  'Y',    "20",
+        {ISUNIQUE, CANSUMMON, ISGOD, ISFRIENDLY},
+        "entwife", 10,
+        0,
+        {15,    64000L, 45, -8, HPT("0d8+200"), "1d8+4"}
+},
+{"valar (Varda, Elbereth Gilthoniel)",
+        100,    TRUE,   FALSE,  'V',    "30",
+        {ISUNIQUE, HASFIRE, CANSUMMON, ISGOD, ISFRIENDLY},
+        "noldor elf", 20,
+        0,
+        {15,    64000L, 45, -8, HPT("0d8+200"), "1d8+4"}
+},
+{"lesser god (Hextor, Champion of Evil)",
+        100,    TRUE,   FALSE,  'H',    "18",
+        {ISMEAN, CANHUH, ISUNIQUE, CANWIELD, CANSUMMON, ISGOD},
+        "zombie", 5,
+        0,
+        {25,    64000L, 45, -8, HPT("0d8+200"), "2d6/2d6"}
+},
+{"demon prince (Demogorgon)",
+        100,    TRUE,   FALSE,  'D',    "19-20",
+        {ISMEAN, CANHUH, DOUBLEDRAIN, CANINFEST, ISUNIQUE, CANSUMMON, ISGOD},
+        "glabrezu", 3,
+        0,
+        {10,    74000L, 45, -8, HPT("0d8+200"), "1d6/1d6"}
+},
+{"lesser god (Heironeous the Invincible)",  /* Dragon #67 - enemy of Hextor */
+        100,    TRUE,   FALSE,  'H',    "18",
+        {CANHUH, ISUNIQUE, CANWIELD, CANSUMMON, NOBOLT, CANBBOLT, ISGOD, ISFRIENDLY},
+        "ki-rin", 2,
+        0,
+        {21,    64000L, 45, -9, HPT("0d8+217"), "1d4+8/1d4+8"}
+},
+{"lesser god (Kurtulmak)",
+        50, TRUE,   TRUE,   'K',    "19",
+        {ISMEAN, CANPOISON, ISUNIQUE, ISGOD},
+        0, 0,
+        0,
+        {16,    55000L, 27, 0,  HPT("0d8+219"), "2d12/1d6"}
+},
+{"lesser god (Hruggek)",
+        50, TRUE,   FALSE,  'H',    "17",
+        {ISMEAN, ISUNIQUE, CANSUMMON, ISGOD},
+        "bugbear", 9,
+        0,
+        {13,    55000L, 25, 0,  HPT("0d8+221"), "2d8/2d8"}
+},
+{"lesser god (St Cuthbert of the Cudgel)",  /* Dragon #67 */
+        100,    TRUE,   FALSE,  'C',    "10",
+        {CANHUH, ISUNIQUE, CANWIELD, CANSUMMON, ISGOD, ISFRIENDLY},
+        "lammasu", 2,
+        0,
+        {20,    65000L, 45, -8, HPT("0d8+224"), "2d6+5/1d10+5"}
+},
+{"lesser god (Celestian the Far Wanderer)",     /* Dragon #68 */
+        100,    TRUE,   FALSE,  'c',    "20",
+        {CANHUH, CANSHOOT, CANBFIRE, CANBBOLT, CANBICE, ISUNIQUE, CANSUMMON, ISGOD, ISFRIENDLY},
+        "air squid", 2,
+        0,
+        {23,    65000L, 45, -5, HPT("0d8+242"), "1d6+20"}
+},
+{"lesser god (Raxivort, Night Flutterer)",
+        100,    TRUE,   TRUE,   'R',    "18",
+        {CANSHOOT, ISUNIQUE, CANBACID, CANWIELD, CANSUMMON, LOWFRIENDLY, ISGOD},
+        "xvart", 50,
+        0,
+        {18,    65000L, 45, -1, HPT("0d8+246"), "3d6+6"}
+},
+{"lesser god (Fharlanghn, Dweller on the Horizon)", /* Dragon #68 - brother to Celestian */
+        100,    TRUE,   FALSE,  'f',    "18",
+        {CANHUH, CANBLINK, HASFIRE, ISUNIQUE, CANWIELD, CANSUMMON, ISGOD, ISFRIENDLY},
+        "earth elemental", 1,
+        0,
+        {18,    65000L, 45, -6, HPT("0d8+262"), "3d6+6"}
+},
+{"lesser god (Nyarlathotep)",
+        50, TRUE,   FALSE,  'N',    "25",
+        {ISMEAN, ISUNIQUE, ISGOD},
+        "kodiac bear", 9,
+        0,
+        {15,    49000L, 25, -5, HPT("0d8+284"), "2d8/2d8"}
+},
+{"lesser god (Erythnul the Many)",  /* Dragon # 71 */
+        100,    TRUE,   TRUE,   'E',    "16",
+        {ISMEAN, ISUNIQUE, CANSUMMON, ISGOD},
+        "troll", 4,
+        100,
+        {22,    62000L, 45, -3,     HPT("0d8+320"), "4d6+10"}
+},
+{"greater goddess (Ulaa, Mistress of the Mountains)",
+        100,    TRUE,   FALSE,  'U',    "18",
+        {ISUNIQUE, CANSUMMON, CANWIELD, ISREGEN, ISGOD, HIGHFRIENDLY},
+        "kazad dwarf", 15,
+        110,
+        {24,    85000L, 45, -7,     HPT("0d8+321"), "4d8"}
+},
+{"greater god (Maglubiyet)",
+        0,  TRUE,   FALSE,  'M',    "19",
+        {ISMEAN, ISUNIQUE, ISGOD},
+        0, 0,
+        0,
+        {10,    80000L, 45, -1, HPT("0d8+350"), "4d10"}
+},
+{"greater god (Gruumsh)",
+        100,    TRUE,   FALSE,  'G',    "19",
+        {ISMEAN, ISUNIQUE, ISGOD},
+        0, 0,
+        0,
+        {22,    82000L, 45, -1, HPT("0d8+350"), "4d10"}
+},
+{"greater god (Boccob the Uncaring)",
+        100,    TRUE,   FALSE,  'B',    "26",
+        {ISUNIQUE, CANWIELD, ISGOD, LOWFRIENDLY},
+        0, 0,
+        0,
+        {18,    95000L, 45, -8, HPT("0d8+354"), "4d10"}
+},
+{"greater goddess (Istus, Lady of Fate)",  /* Dragon #69 */
+        100,    TRUE,   FALSE,  'I',    "23",
+        {ISUNIQUE, CANSUMMON, CANWIELD, CANHOLD, ISGOD, LOWFRIENDLY},
+        "time elemental", 3,
+        110,
+        {15,    88000L, 45, -8,     HPT("0d8+377"), "4d8"}
+},
+{"lesser god (Skoraeus Stonebones)",
+        0,  TRUE,   FALSE,  'S',    "19",
+        {ISUNIQUE, ISREGEN, ISGOD, LOWFRIENDLY},
+        0, 0,
+        0,
+        {10,    85000L, 45, -1, HPT("0d8+380"), "6d10"}
+},
+{"greater god (Incabulos, God of Evil Sendings)",  /* Dragon # 71 */
+        100,    TRUE,   TRUE,   'I',    "20",
+        {ISMEAN, ISUNIQUE, CANSUMMON, CANWIELD, CANSNORE, ISGOD},
+        "night hag", 4,
+        100,
+        {18,    92000L, 25, -9,     HPT("0d8+383"), "5d6"}
+},
+{"greater god (Nerull the Grim Reaper)",  /* Dragon # 71 */
+        100,    TRUE,   TRUE,   'N',    "21",
+        {ISMEAN, ISUNIQUE, CANBACID, CANSUMMON, ISGOD},
+        "shaggy demodand (shator)", 2,
+        100,
+        {14,    92000L, 30, -6,     HPT("0d8+400"), "10d6"}
+},
+{"greater god (Odin, All Father)",
+        100,    TRUE,   TRUE,   'O',    "25",
+        {ISUNIQUE, CANSUMMON, CANWIELD, ISGOD, LOWFRIENDLY},
+        "valkyrie", 50,
+        100,
+        {25,    105000L,    30, -6,     HPT("0d8+400"), "5d8"}
+},
+{"valar (Orome, Lord of Forests)",
+        100,    TRUE,   FALSE,  'o',    "36",
+        {ISUNIQUE, CANSUMMON, ISGOD, LOWFRIENDLY},
+        "elephant", 10,
+        0,
+        {18,    95000L, 45, -5, HPT("0d8+460"), "4d8+10"}
+},
+{"valar (Aule, Lord of Smithing)",
+        100,    TRUE,   FALSE,  'A',    "36",
+        {ISUNIQUE, CANSUMMON, ISGOD, LOWFRIENDLY},
+        "kazad dwarf", 15,
+        0,
+        {20,    95000L, 45, -5, HPT("0d8+460"), "4d8+10"}
+},
+{"valar (Ulmo, God of Waters)",
+        100,    TRUE,   FALSE,  'U',    "36",
+        {ISUNIQUE, CANSUMMON, CANWIELD, ISGOD, LOWFRIENDLY},
+        "giant crocodile", 15,
+        0,
+        {18,    95000L, 45, -5, HPT("0d8+460"), "4d8+10"}
+},
+{"valar (Melkor, the Dark Lord)",
+        100,    TRUE,   FALSE,  'M',    "36",
+        {ISMEAN, ISUNIQUE, CANHUH, CANSUMMON, ISGOD},
+        "maiar (Balrog)", 15,
+        0,
+        {18,    95000L, 45, -10,    HPT("0d8+460"), "4d8+10"}
+},
+{"valar (Manwe, Lord of Arda)",
+        100,    TRUE,   FALSE,  'M',    "36",
+        {ISUNIQUE, CANSUMMON, CANWIELD, ISGOD, LOWFRIENDLY},
+        "aerial servant", 15,
+        0,
+        {18,    95000L, 45, -10,    HPT("0d8+460"), "4d8+10"}
+},
+{"valar (Tulkas the Valiant)",
+        100,    TRUE,   FALSE,  'T',    "36",
+        {ISUNIQUE, CANSUMMON, ISGOD, LOWFRIENDLY},
+        "noone, haste anyway", 1,
+        0,
+        {28,    145000L,    65, -15,    HPT("0d8+800"), "10d4/4d10"}
+},
+{"quartermaster",
+        0, FALSE, TRUE, 'q', "18-20",
+        {CANSELL},
+        0, 0,
+        2,
+        {12,    20, 100,    -11,    HPT("1d8+1"), "1d10"}
+},
+{"Lord of All Darkness (Lucifer)",
+        100, TRUE, TRUE, 'L', "40-60",
+        {ISMEAN, ISUNIQUE, CANSUMMON, ISGOD},
+        "evil sorcerer", 15,
+        225,
+        {45,    1465000L,   100,    -13,    HPT("18d60+700"), "3d8/3d8/3d8"}}
+};
+
+int nummonst = NUMMONST;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/monsters.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1497 @@
+/*
+    monsters.c - File with various monster functions in it
+ 
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+    summon_monster()
+        Summon a monster.
+*/
+
+struct linked_list *
+summon_monster(int type, int familiar, int print_message)
+{
+    struct linked_list  *mp;
+    struct thing    *tp;
+    int   monster;
+
+    if (familiar && !is_wearing(R_WIZARD) && off(player, CANSUMMON))
+    {
+        msg("Only spellcasters can summon familiars!");
+        return(NULL);
+    }
+
+    if (type == 0)    /* Random monster modified by level */
+    {
+        int ndice = min(pstats.s_lvl, (nummonst - NUMSUMMON) / 8);
+
+        monster = min(nummonst, roll(ndice, pstats.s_charisma));
+        
+		/*
+         * if a familiar exists, and it is higher in level, make it
+         * again 
+         */
+
+        if (fam_ptr != NULL) 
+		{
+            struct thing   *fp = THINGPTR(fam_ptr);
+
+            monster = max(fp->t_index, monster);
+        }
+	}
+    else
+        monster = type;
+
+    turn_on(player, SUMMONING);
+
+    mp = creat_mons(&player, monster, NOMESSAGE);
+
+    if (!mp)
+    {
+        msg("Summon failed.");
+        turn_off(player, SUMMONING);
+        return(NULL);
+    }
+
+    if (print_message == MESSAGE)
+    {
+        msg("A %s appears out of nowhere!", monsters[monster].m_name);
+
+        if (familiar)
+            msg("I am here to serve %s.", whoami);
+        else
+        {
+            msg("My goodness, are you Yendor?");
+            ++mons_summoned;
+            debug("%d monsters now summoned.", mons_summoned);
+        }
+    }
+
+    tp = THINGPTR(mp);
+    turn_on(*tp, ISCHARMED);    /* Summoned monsters are always charmed */
+
+    if (familiar)
+    {
+        int i;
+        static const unsigned long fam_on[]= {ISREGEN,CANSHOOT,CANWIELD,HASARMOR,ISFAMILIAR,0};
+        static const unsigned long fam_off[]={ISMEAN, ISHUH, ISINVIS,
+                    CANSURPRISE, NOMOVE,
+                    ISSLOW, ISSHADOW, ISGREED, ISFAST,
+                    CANFLY, ISFLEE, 0};
+
+        for (i = 0; fam_on[i]; i++)
+            turn_on(*tp, fam_on[i]);
+
+        for (i = 0; fam_off[i]; i++)
+            turn_off(*tp, fam_off[i]);
+
+        if (fam_ptr != NULL)    /* Get rid of old familiar */
+        {
+            struct thing    *fp = THINGPTR(fam_ptr);
+            struct linked_list  *fpack = fp->t_pack;
+            struct linked_list  *item;
+
+            if (fpack != NULL)  /* Transfer pack */
+            {
+                if (tp->t_pack == NULL)
+                    tp->t_pack = fpack;
+                else
+                {
+                    for(item=tp->t_pack; item->l_next != NULL; item=next(item))
+                        ;   /* find last item in list */
+
+                    item->l_next = fpack;
+                    fpack->l_prev = item;
+                }
+            }
+
+            fpack = NULL;
+            killed(NULL, fam_ptr, NOMESSAGE, NOPOINTS);
+        }
+
+        fam_ptr = mp;
+        fam_type = monster;
+
+        /* improve their abilities a bit */
+
+        tp->t_stats.s_hpt += roll(2, pstats.s_lvl);
+        tp->t_stats.s_lvl += roll(2, (pstats.s_lvl / 4) + 1);
+        tp->t_stats.s_arm -= roll(2, (pstats.s_lvl / 4) + 1);
+        tp->t_stats.s_str += roll(2, (pstats.s_lvl / 4) + 1);
+        tp->t_stats.s_intel += roll(2, (pstats.s_lvl / 4) + 1);
+        tp->t_stats.s_wisdom += roll(2, (pstats.s_lvl / 4) + 1);
+        tp->t_stats.s_dext += roll(2, (pstats.s_lvl / 4) + 1);
+        tp->t_stats.s_const += roll(2, (pstats.s_lvl / 4) + 1);
+        tp->t_stats.s_charisma += roll(2, (pstats.s_lvl / 4) + 1);
+		
+		/* some monsters do no damage by default */
+		
+		if (strcmp(tp->t_stats.s_dmg, "0d0") == 0)
+            tp->t_stats.s_dmg = "1d8";
+			
+        tp->maxstats = tp->t_stats; /* structure assignment */
+    }
+
+    turn_off(player, SUMMONING);
+
+    return(mp);
+}
+
+/*
+     randmonster()
+        wander - wandering monster allowed
+        grab - a throne room monster allowed
+*/
+
+int
+randmonster(int wander, int grab)
+{
+    int mons_number, cur_level, range, i;
+
+    /* Do we want a merchant? */
+
+    if (wander == WANDER && monsters[nummonst].m_wander && rnd(5000) < 3)
+        return(nummonst);
+
+    cur_level = level;
+    range = 4 * NLEVMONS;
+    i = 0;
+
+    do
+    {
+        if (i++ > range * 10)   /* just in case all have be genocided */
+        {
+            i = 0;
+
+            if (--cur_level <= 0)
+                fatal("Rogue could not find a monster to make");
+        }
+
+        mons_number = NLEVMONS * (cur_level - 1) +
+            (rnd(range) - (range - 1 - NLEVMONS));
+
+        if (mons_number < 1)
+            mons_number = rnd(NLEVMONS) + 1;
+        else if (mons_number > nummonst - NUMSUMMON - 1)
+        {
+            if (grab == GRAB)
+                mons_number = rnd(range + NUMSUMMON) +
+                    (nummonst - 1) -
+                    (range + NUMSUMMON - 1);
+            else if (mons_number > nummonst - 1)
+                mons_number = rnd(range) +
+                (nummonst - NUMSUMMON - 1) -
+                (range - 1);
+        }
+    }
+    while (wander == WANDER ? !monsters[mons_number].m_wander ||
+        !monsters[mons_number].m_normal :
+        !monsters[mons_number].m_normal);
+
+    return((short)mons_number);
+}
+
+/*
+    new_monster()
+        Pick a new monster and add it to the list
+*/
+
+void
+new_monster(struct linked_list *item, int type, coord *cp, int max_monster)
+{
+    struct thing    *tp;
+    struct monster  *mp;
+    char    *ip, *hitp;
+    int   i, min_intel, max_intel;
+    int   num_dice, num_sides = 8, num_extra = 0;
+    int eff_charisma = pstats.s_charisma;
+    int eff_intel = pstats.s_intel;
+
+    attach(mlist, item);
+    tp = THINGPTR(item);
+    tp->t_index = type;
+    tp->t_wasshot = FALSE;
+    tp->t_type = monsters[type].m_appear;
+    tp->t_ctype = C_MONSTER;
+    tp->t_no_move = 0;
+    tp->t_doorgoal = -1;
+    tp->t_pos = *cp;
+    tp->t_oldpos = *cp;
+    tp->t_oldch = CCHAR( mvwinch(cw, cp->y, cp->x) );
+    mvwaddch(mw, cp->y, cp->x, tp->t_type);
+    mp = &monsters[tp->t_index];
+
+    /* Figure out monster's hit points */
+
+    hitp = mp->m_stats.s_hpt;
+    num_dice = atoi(hitp);
+
+    if ((hitp = strchr(hitp, 'd')) != NULL)
+    {
+        num_sides = atoi(++hitp);
+
+        if ((hitp = strchr(hitp, '+')) != NULL)
+            num_extra = atoi(++hitp);
+    }
+
+    if (max_monster == MAXSTATS)
+        tp->t_stats.s_hpt = num_dice * num_sides + num_extra;
+    else
+        tp->t_stats.s_hpt = roll(num_dice, num_sides) + num_extra;
+
+    tp->t_stats.s_lvl = mp->m_stats.s_lvl;
+    tp->t_stats.s_arm = mp->m_stats.s_arm;
+    tp->t_stats.s_dmg = mp->m_stats.s_dmg;
+    tp->t_stats.s_exp = mp->m_stats.s_exp + mp->m_add_exp * tp->t_stats.s_hpt;
+    tp->t_stats.s_str = mp->m_stats.s_str;
+
+    if (max_level > 30)
+    {
+        tp->t_stats.s_hpt += roll(4, (max_level - 60) * 2);
+        tp->t_stats.s_lvl += roll(4, (max_level - 60) / 8);
+        tp->t_stats.s_arm -= roll(2, (max_level - 60) / 8);
+        tp->t_stats.s_str += roll(2, (max_level - 60) / 12);
+        tp->t_stats.s_exp += roll(4, (max_level - 60) * 2) * mp->m_add_exp;
+    }
+
+    /*
+     * just initailize others values to something reasonable for now
+     * maybe someday will *really* put these in monster table
+     */
+
+    tp->t_stats.s_wisdom = 8 + rnd(4);
+    tp->t_stats.s_dext = 8 + rnd(4);
+    tp->t_stats.s_const = 8 + rnd(4);
+    tp->t_stats.s_charisma = 8 + rnd(4);
+
+    if (max_level > 45)
+        tp->t_stats.s_dext += roll(2, (max_level - 50) / 8);
+
+    /* Set the initial flags */
+
+    for (i = 0; i < 16; i++)
+        tp->t_flags[i] = 0;
+
+    for (i = 0; i < 16; i++)
+        turn_on(*tp, mp->m_flags[i]);
+
+    /* suprising monsters don't always surprise you */
+
+    if (!max_monster && on(*tp, CANSURPRISE) && rnd(100) < 20)
+        turn_off(*tp, CANSURPRISE);
+
+    /* If this monster is unique, genocide it */
+
+    if (on(*tp, ISUNIQUE))
+        mp->m_normal = FALSE;
+
+    /* gods automatically get special abilities */
+
+    if (on(*tp, ISGOD))
+    {
+        turn_on(*tp, CANFRIGHTEN);
+        turn_on(*tp, CANCAST);
+        turn_on(*tp, CANFLY);
+        turn_on(*tp, CANBARGAIN);
+        turn_on(*tp, ISLARGE);
+        turn_on(*tp, CANTELEPORT);
+        turn_on(*tp, CANSPEAK);
+        turn_on(*tp, CANDARKEN);
+        turn_on(*tp, CANSEE);
+        turn_on(*tp, CANLIGHT);
+        turn_on(*tp, BMAGICHIT);
+    }
+
+    tp->t_turn = TRUE;
+    tp->t_pack = NULL;
+
+    /* Figure intelligence */
+
+    min_intel = atoi(mp->m_intel);
+
+    if ((ip = (char *) strchr(mp->m_intel, '-')) == NULL)
+        tp->t_stats.s_intel = min_intel;
+    else
+    {
+        max_intel = atoi(++ip);
+
+        if (max_monster)
+            tp->t_stats.s_intel = max_intel;
+        else
+            tp->t_stats.s_intel = min_intel + rnd(max_intel - min_intel);
+    }
+
+    tp->t_stats.s_power = (rnd(tp->t_stats.s_lvl / 5) + 1) * tp->t_stats.s_intel;
+
+    tp->maxstats = tp->t_stats; /* structure assignment */
+
+    /* If the monster can shoot, it may have a weapon */
+
+    if (on(*tp, CANSHOOT) && (max_monster || rnd(9) < 6))
+    {
+        struct linked_list  *thrower_item, *missile_item;
+        struct object *thrower, *a_missile;
+
+        thrower_item = new_item(sizeof *thrower);
+        thrower = OBJPTR(thrower_item);
+        carried_weapon(tp, thrower);
+
+        missile_item = new_item(sizeof *a_missile);
+        a_missile = OBJPTR(missile_item);
+        carried_weapon(tp, a_missile);
+
+        /* The monster may use a crossbow, sling, footbow, or an arrow */
+        /* Take racial preferences into account */
+
+        if ((strcmp(mp->m_name, "elf") == 0) ||
+            (strcmp(mp->m_name, "noldor elf") == 0))
+        {
+            thrower->o_which = BOW;
+
+            if (rnd(5) == 0)
+                a_missile->o_which = SILVERARROW;
+            else
+                a_missile->o_which = ARROW;
+        }
+        else if ((strcmp(mp->m_name, "dwarf") == 0) ||
+                (strcmp(mp->m_name, "kazad dwarf") == 0))
+        {
+            thrower->o_which = CROSSBOW;
+            a_missile->o_which = BOLT;
+        }
+        else if (on(*tp, ISSMALL))
+        {
+            switch (rnd(3))
+            {
+                case 0:
+                    thrower->o_which = SLING;
+                    a_missile->o_which = BULLET;
+                    break;
+                default:
+                    thrower->o_which = SLING;
+                    a_missile->o_which = ROCK;
+            }
+        }
+        else if (on(*tp, ISLARGE))
+        {
+            switch (rnd(4))
+            {
+                case 0:
+                    thrower->o_which = CROSSBOW;
+                    a_missile->o_which = BOLT;
+                    break;
+
+                case 1:
+                    thrower->o_which = FOOTBOW;
+                    a_missile->o_which = FBBOLT;
+                    break;
+
+                default:
+                    thrower->o_which = BOW;
+
+                    if (rnd(5) == 0)
+                        a_missile->o_which = FLAMEARROW;
+                    else
+                        a_missile->o_which = ARROW;
+
+                    break;
+            }
+        }
+        else
+        {
+            switch (rnd(6))
+            {
+                case 1:
+                    thrower->o_which = SLING;
+                    a_missile->o_which = ROCK;
+                    break;
+
+                case 2:
+                    thrower->o_which = CROSSBOW;
+                    a_missile->o_which = BOLT;
+                    break;
+
+                case 3:
+                    thrower->o_which = FOOTBOW;
+                    a_missile->o_which = FBBOLT;
+                    break;
+
+                case 4:
+                    thrower->o_which = BOW;
+                    a_missile->o_which = ARROW;
+                    break;
+
+                default:
+                    thrower->o_which = SLING;
+                    a_missile->o_which = BULLET;
+                    break;
+            }
+        }
+
+        init_weapon(thrower, thrower->o_which);
+        init_weapon(a_missile, a_missile->o_which);
+
+        attach(tp->t_pack, thrower_item);
+        attach(tp->t_pack, missile_item);
+    }
+
+    /* monsters that wield weapons */
+
+    if (on(*tp, CANWIELD))
+    {
+        if (max_monster || rnd(3))
+        {
+            struct linked_list  *wield_item;
+            struct object   *wielded;
+
+            wield_item = new_item(sizeof *wielded);
+            wielded = OBJPTR(wield_item);
+            carried_weapon(tp, wielded);
+
+            i = rnd(CLAYMORE - CLUB) + rnd(2 * tp->t_stats.s_lvl);
+            i = min(i, CLAYMORE);
+            wielded->o_which = i;
+            init_weapon(wielded, wielded->o_which);
+
+            /* Is it too heavy? */
+
+            if (itemweight(wielded) > 8 * tp->t_stats.s_str)
+                discard(wield_item);
+            else
+                attach(tp->t_pack, wield_item);
+        }
+    }
+
+    if (is_wearing(R_AGGR))
+        chase_it(cp, &player);
+    else
+    {
+        turn_off(*tp, ISRUN);
+
+        if (on(*tp, ISFLEE) && (rnd(4) == 0))
+            turn_off(*tp, ISFLEE);
+
+        if (rnd(luck) == 0)
+            switch (player.t_ctype)
+            {
+                case C_MAGICIAN:
+                case C_ILLUSION:
+                    eff_intel = 2 * pstats.s_intel;
+                    break;
+                case C_DRUID:
+                    eff_intel = 2 * pstats.s_intel;
+                case C_RANGER:
+                    eff_charisma = 2 * pstats.s_charisma;
+                    break;
+                case C_ASSASIN:
+                case C_THIEF:
+                case C_NINJA:
+                    eff_charisma = pstats.s_charisma / 2;
+                    break;
+            }
+
+        /* LOWFRIENDLY monsters might be friendly */
+
+        i = roll(1,100);
+
+        if (i == 0 || (on(*tp, LOWFRIENDLY) && i < eff_charisma) ||
+            (on(*tp, MEDFRIENDLY) && i < 3 * eff_charisma) ||
+            (on(*tp, HIGHFRIENDLY) && i < 5 * eff_charisma))
+        {
+            turn_on(*tp, ISFRIENDLY);
+            turn_off(*tp, ISMEAN);
+        }
+
+        i = roll(1,100);
+
+        if (i == 0 || (on(*tp, LOWCAST) && i < eff_intel) ||
+            (on(*tp, MEDCAST) && i < 3 * eff_intel) ||
+            (on(*tp, HIGHCAST) && i < 5 * eff_intel))
+        {
+            turn_on(*tp, CANCAST);
+        }
+
+        if (on(*tp, ISDISGUISE))
+        {
+            char    mch = 0;
+
+            if (tp->t_pack != NULL)
+                mch = (OBJPTR(tp->t_pack))->o_type;
+            else
+                switch (rnd(level > arts[0].ar_level ? 10 : 9))
+                {
+                    case 0: mch = GOLD;     break;
+                    case 1: mch = POTION;   break;
+                    case 2: mch = SCROLL;   break;
+                    case 3: mch = FOOD;     break;
+                    case 4: mch = WEAPON;   break;
+                    case 5: mch = ARMOR;    break;
+                    case 6: mch = RING;     break;
+                    case 7: mch = STICK;    break;
+                    case 8: mch = monsters[randmonster(NOWANDER, NOGRAB)].m_appear;
+                                break;
+                    case 9: mch = ARTIFACT; break;
+                }
+
+            tp->t_disguise = mch;
+        }
+    }
+}
+
+/*
+    wanderer()
+        A wandering monster has awakened and is headed for the player
+*/
+
+void
+wanderer(void)
+{
+    int i, cnt = 0;
+    struct room *hr = roomin(hero);
+    struct linked_list  *item;
+    struct thing    *tp;
+    coord   cp;
+    char    *loc;
+    int which;
+
+    /* Find a place for it -- avoid the player's room */
+
+    do
+    {
+        do
+        {
+            cnt++;
+            i = rnd_room();
+        }
+        while (!(hr != &rooms[i] || levtype == MAZELEV
+               || levtype == THRONE || cnt > 5000));
+
+        rnd_pos(&rooms[i], &cp);
+    }
+    while(!step_ok(cp.y, cp.x, NOMONST, NULL));
+
+    /* Create a new wandering monster */
+
+    item = new_item(sizeof *tp);
+    which = randmonster(TRUE, FALSE);
+    new_monster(item, which, &cp, FALSE);
+
+    tp = THINGPTR(item);
+    tp->t_pos = cp;     /* Assign the position to the monster */
+
+    chase_it(&tp->t_pos, &player);
+
+    i = rnd(7);
+
+    if (on(*tp, ISSWARM) && i < 5)
+        cnt = roll(2, 4);
+    else if (on(*tp, ISFLOCK) && i < 5)
+        cnt = roll(1, 4);
+    else
+        cnt = 0;
+
+    for (i = 1; i <= cnt; i++)
+    {
+        struct linked_list  *ip = creat_mons(tp, which, NOMESSAGE);
+
+        if (ip != NULL)
+        {
+            struct thing    *mp = THINGPTR(ip);
+
+            if (on(*tp, ISFRIENDLY))
+                turn_on(*mp, ISFRIENDLY);
+            else
+                turn_off(*mp, ISFRIENDLY);
+        }
+    }
+
+    if (cnt > 0)
+    {
+        if (on(*tp, LOWCAST) || on(*tp, MEDCAST) || on(*tp, HIGHCAST))
+            turn_on(*tp, CANCAST);
+
+        tp->t_stats.s_hpt += roll(2, 8);
+        tp->t_stats.s_lvl += roll(2, 3);
+        tp->t_stats.s_arm -= roll(1, 6);
+        tp->t_stats.s_str += roll(2, 3);
+        tp->t_stats.s_intel += roll(2, 3);
+        tp->t_stats.s_exp += roll(2, 8) * monsters[which].m_add_exp;
+    }
+
+    i = DISTANCE(cp, hero);
+
+    if (i < 20)
+        loc = "very close to you";
+    else if (i < 400)
+        loc = "nearby";
+    else
+        loc = "in the distance";
+
+    if (wizard)
+        msg("Started a wandering %s.", monsters[tp->t_index].m_name);
+    else if (on(*tp, ISUNDEAD) && (player.t_ctype == C_CLERIC ||
+            player.t_ctype == C_PALADIN || is_wearing(R_PIETY)))
+        msg("You sense a new ungodly monster %s.", loc);
+    else if (on(player, CANHEAR) || (player.t_ctype == C_THIEF &&
+            rnd(20) == 0))
+        msg("You hear a new %s moving %s.",
+            monsters[tp->t_index].m_name, loc);
+    else if (on(player, CANSCENT) || (player.t_ctype == C_THIEF &&
+            rnd(20) == 0))
+        msg("You smell a new %s %s.", monsters[tp->t_index].m_name,
+            loc);
+}
+
+/*
+    wake_monster
+	
+        what to do when the hero steps next to a monster
+*/
+
+struct linked_list *
+wake_monster(int y, int x)
+{
+    struct thing    *tp;
+    struct linked_list  *it;
+    struct room *trp;
+    char    *mname;
+
+    if ((it = find_mons(y, x)) == NULL)
+    {
+        debug("Can't find monster in show.");
+        return(NULL);
+    }
+
+    tp = THINGPTR(it);
+
+    if ((good_monster(*tp)) || on(player, SUMMONING))
+    {
+        chase_it(&tp->t_pos, &player);
+        turn_off(*tp, ISINVIS);
+        turn_off(*tp, CANSURPRISE);
+        return(it);
+    }
+
+    trp = roomin(tp->t_pos);   /* Current room for monster */
+    mname = monsters[tp->t_index].m_name;
+
+    /* Let greedy ones guard gold */
+
+    if (on(*tp, ISGREED) && off(*tp, ISRUN))
+        if ((trp != NULL) && (lvl_obj != NULL))
+        {
+            struct linked_list  *item;
+            struct object   *cur;
+
+            for (item = lvl_obj; item != NULL; item = next(item))
+            {
+                cur = OBJPTR(item);
+
+                if ((cur->o_type == GOLD) &&
+                    (roomin(cur->o_pos) == trp))
+                {
+                    /* Run to the gold */
+                    tp->t_horde = cur;
+                    turn_on(*tp, ISRUN);
+                    turn_off(*tp, ISDISGUISE);
+                    tp->t_ischasing = FALSE;
+                    /* Make it worth protecting */
+                    cur->o_count += roll(2, 3) * GOLDCALC;
+                    break;
+                }
+            }
+        }
+
+    /*
+     * Every time he sees mean monster, it might start chasing him unique
+     * monsters always do
+     */
+
+    if (  (on(*tp, ISUNIQUE)) ||
+          ( (rnd(100) > 33) &&
+            on(*tp, ISMEAN) &&
+            off(*tp, ISHELD) &&
+            off(*tp, ISRUN) &&
+            !is_stealth(&player) &&
+            (off(player, ISINVIS) || on(*tp, CANSEE))
+          )
+       )
+    {
+        chase_it(&tp->t_pos, &player);
+    }
+
+    /* Handle gaze attacks */
+
+    if (on(*tp, ISRUN) && cansee(tp->t_pos.y, tp->t_pos.x) &&
+            off(player, ISINVIS))
+    {
+        if (on(*tp, CANHUH))    /* Confusion */
+        {
+            if (on(player, CANREFLECT))
+            {
+                msg("You reflect the bewildering stare of the %s.", mname);
+
+                if (save_throw(VS_MAGIC, tp))
+                {
+                    msg("The %s is confused!", mname);
+                    turn_on(*tp, ISHUH);
+                }
+                else
+                    msg("The %s staggers for a moment.", mname);
+            }
+            else if (save(VS_MAGIC))
+            {
+                msg("You feel dizzy for a moment, but it quickly passes.");
+
+                if (rnd(100) < 67)
+                    turn_off(*tp, CANHUH);
+            }
+            else if (off(player, ISCLEAR))
+            {
+                if (off(player, ISHUH))
+                {
+                    light_fuse(FUSE_UNCONFUSE, 0, rnd(20) + HUHDURATION, AFTER);
+                    msg("The %s's gaze has confused you.", mname);
+                    turn_on(player, ISHUH);
+                }
+                else
+                    lengthen_fuse(FUSE_UNCONFUSE, rnd(20) + HUHDURATION);
+            }
+        }
+
+        if (on(*tp, CANSNORE))      /* Sleep */
+        {
+            if (on(player, CANREFLECT))
+            {
+                msg("You reflect the lethargic glance of the %s", mname);
+
+                if (save_throw(VS_PARALYZATION, tp))
+                {
+                    msg("The %s falls asleep!", mname);
+                    tp->t_no_move += SLEEPTIME;
+                }
+            }
+            else if (no_command == 0 && !save(VS_PARALYZATION))
+            {
+                if (is_wearing(R_ALERT))
+                    msg("You feel slightly drowsy for a moment.");
+                else
+                {
+                    msg("The %s's gaze puts you to sleep.", mname);
+                    no_command = SLEEPTIME;
+
+                    if (rnd(100) < 50)
+                        turn_off(*tp, CANSNORE);
+                }
+            }
+        }
+
+        if (on(*tp, CANFRIGHTEN))   /* Fear */
+        {
+            turn_off(*tp, CANFRIGHTEN);
+
+            if (on(player, CANREFLECT))
+            {
+                msg("The %s sees its reflection. ", mname);
+
+                if (save_throw(VS_MAGIC,tp))
+                {
+                    msg("The %s is terrified by its reflection!", mname);
+                    turn_on(*tp, ISFLEE);
+                }
+            }
+            else
+            {
+                if (!save(VS_WAND) && !(on(player, ISFLEE) &&
+                       (player.t_chasee==tp)))
+                {
+                    if ((player.t_ctype != C_PALADIN) &&
+                        off(player, SUPERHERO))
+                    {
+                        turn_on(player, ISFLEE);
+                        player.t_ischasing = FALSE;
+                        player.t_chasee    = tp;
+                        msg("The sight of the %s terrifies you.", mname);
+                    }
+                    else
+                        msg("My, the %s looks ugly.", mname);
+                }
+            }
+        }
+
+        if (on(*tp, LOOKSLOW))     /* Slow */
+        {
+            turn_off(*tp, LOOKSLOW);
+
+            if (on(player, CANREFLECT))
+            {
+                msg("You reflect the mournful glare of the %s.", mname);
+
+                if (save_throw(VS_MAGIC,tp))
+                {
+                    msg("The %s is slowing down!", mname);
+                    turn_on(*tp, ISSLOW);
+                }
+            }
+            else if (is_wearing(R_FREEDOM) || save(VS_MAGIC))
+                msg("You feel run-down for a moment.");
+            else
+            {
+                if (on(player, ISHASTE))    /* Already sped up */
+                {
+                    extinguish_fuse(FUSE_NOHASTE);
+                    nohaste(NULL);
+                }
+                else
+                {
+                    msg("You feel yourself moving %sslower.",
+                     on(player, ISSLOW) ? "even " : "");
+
+                    if (on(player, ISSLOW))
+                        lengthen_fuse(FUSE_NOSLOW, rnd(4) + 4);
+                    else
+                    {
+                        turn_on(player, ISSLOW);
+                        player.t_turn = TRUE;
+                        light_fuse(FUSE_NOSLOW, 0, rnd(4) + 4, AFTER);
+                    }
+                }
+            }
+        }
+
+        if (on(*tp, CANBLIND))  /* Blinding */
+        {
+            turn_off(*tp, CANBLIND);
+
+            if (on(player, CANREFLECT))
+            {
+                msg("You reflect the blinding stare of the %s.", mname);
+
+                if (save_throw(VS_WAND, tp))
+                {
+                    msg("The %s is blinded!", mname);
+                    turn_on(*tp, ISHUH);
+                }
+            }
+            else if (off(player, ISBLIND))
+                if (save(VS_WAND) || is_wearing(R_TRUESEE) || is_wearing(R_SEEINVIS))
+                    msg("Your eyes film over for a moment.");
+                else
+                {
+                    msg("The gaze of the %s blinds you.", mname);
+                    turn_on(player, ISBLIND);
+                    light_fuse(FUSE_SIGHT, 0, rnd(30) + 20, AFTER);
+                    look(FALSE);
+                }
+        }
+
+        if (on(*tp, LOOKSTONE))  /* Stoning */
+        {
+            turn_off(*tp, LOOKSTONE);
+
+            if (on(player, CANREFLECT))
+            {
+                msg("You reflect the flinty look of the %s.", mname);
+
+                if (save_throw(VS_PETRIFICATION,tp))
+                {
+                    msg("The %s suddenly stiffens", mname);
+                    tp->t_no_move += STONETIME;
+                }
+                else
+                {
+                    msg("The %s is turned to stone!", mname);
+                    killed(&player, it, NOMESSAGE, POINTS);
+                }
+            }
+            else
+            {
+                if (on(player, CANINWALL))
+                    msg("The %s cannot focus on you.", mname);
+                else
+                {
+                    msg("The gaze of the %s stiffens your limbs.", mname);
+
+                    if (save(VS_PETRIFICATION))
+                        no_command = STONETIME;
+                    else if (rnd(100))
+                        no_command = STONETIME * 3;
+                    else
+                    {
+                        msg("The gaze of the %s petrifies you.", mname);
+                        msg("You are turned to stone!!! --More--");
+                        wait_for(' ');
+                        death(D_PETRIFY);
+                        return(it);
+                    }
+                }
+            }
+        }
+    }
+
+    /*
+     * True Sight sees all Never see ISINWALL or CANSURPRISE See ISSHADOW
+     * 80% See ISINVIS with See Invisibilty
+     */
+
+    if (off(player, CANTRUESEE) &&
+        on(*tp, ISINWALL) || on(*tp, CANSURPRISE) ||
+        (on(*tp, ISSHADOW) && rnd(100) < 80) ||
+        (on(*tp, ISINVIS) && off(player, CANSEE)))
+	{
+	    /* 
+	    TODO: incomplete - need to finish logic
+	    int ch = mvwinch(stdscr, y, x); 
+	    */
+	}
+	
+
+    /* hero might be able to hear or smell monster if he can't see it */
+
+    if ((rnd(player.t_ctype == C_THIEF ? 40 : 200) == 0 ||
+            on(player, CANHEAR)) && !cansee(tp->t_pos.y, tp->t_pos.x))
+        msg("You hear a %s nearby.", mname);
+    else if ((rnd(player.t_ctype == C_THIEF ? 40 : 200) == 0 ||
+            on(player, CANSCENT)) && !cansee(tp->t_pos.y, tp->t_pos.x))
+        msg("You smell a %s nearby.", mname);
+
+    return(it);
+}
+
+/*
+    genocide()
+        wipe out hated monsters flags:    ISBLESSED, ISCURSED
+*/
+
+void
+genocide(int flags)
+{
+    struct linked_list  *ip;
+    struct thing    *mp;
+    struct linked_list  *nip;
+    int    which_monst;
+    int    blessed = flags & ISBLESSED;
+    int    cursed = flags & ISCURSED;
+
+    while ((which_monst = get_monster_number("genocide")) == 0)
+        ;
+
+    if (cursed)    /* oops... */
+    {
+        new_level(THRONE, which_monst);
+        msg("What's this I hear about you trying to wipe me out?");
+        fighting = running = after = FALSE;
+        return;
+    }
+
+    /* Remove this monster from the present level */
+
+    for (ip = mlist; ip; ip = nip)
+    {
+        mp = THINGPTR(ip);
+        nip = next(ip);
+
+        if (mp->t_index == which_monst)
+        {
+            check_residue(mp);  /* Check for special features before removing */
+            remove_monster(&mp->t_pos, ip);
+        }
+    }
+
+    /* Remove from available monsters */
+
+    monsters[which_monst].m_normal = FALSE;
+    monsters[which_monst].m_wander = FALSE;
+    mpos = 0;
+    msg("You have wiped out the %s.", monsters[which_monst].m_name);
+
+    if (blessed)
+        genocide(ISNORMAL);
+}
+
+
+/*
+    id_monst()
+        lists the monsters with the displayed by the character unless
+        there is only one in which case it is returned as the string
+*/
+
+void
+id_monst(int monster)
+{
+    int i;
+
+    for (i = 1; i <= nummonst + 2; i++)
+        if (monsters[i].m_appear == monster)
+            add_line("A %s ", monsters[i].m_name);
+
+    end_line();
+}
+
+
+/*
+    check_residue()
+        takes care of any effect of the monster
+*/
+
+void
+check_residue(struct thing *tp)
+{
+    /* Take care of special abilities */
+
+    if (on(*tp, DIDHOLD) && (--hold_count == 0))
+        turn_off(player, ISHELD);
+
+    /* If it has lowered player, give him back a level, maybe */
+
+    if (on(*tp, DIDDRAIN) && rnd(3) == 0)
+        raise_level();
+
+    /* If frightened of this monster, stop */
+
+    if (on(player, ISFLEE) && (player.t_chasee==tp))
+        turn_off(player, ISFLEE);
+
+    /* If monster was suffocating player, stop it */
+    if (on(*tp, DIDSUFFOCATE))
+        extinguish_fuse(FUSE_SUFFOCATE);
+
+    /* If something with fire, may darken */
+    if (on(*tp, HASFIRE))
+    {
+        struct room *rp = roomin(tp->t_pos);
+
+        if (rp && (--(rp->r_fires) <= 0))
+        {
+            rp->r_flags &= ~HASFIRE;
+            light(&tp->t_pos);
+        }
+    }
+}
+
+/*
+    sell()
+        displays a menu of goods from which the player may choose to
+        purchase something.
+*/
+
+#define SELL_ITEMS 10       /* How many things 'q' might carry */
+
+void
+sell(struct thing *tp)
+{
+    struct linked_list  *item;
+    int i, j, min_worth, nitems, chance, which_item, w;
+    char goods;
+    struct object   *obj;
+    char    buffer[2 * LINELEN];
+    char    dbuf[2 * LINELEN];
+
+    struct
+    {
+        int which;
+        int plus1, plus2;
+        int count;
+        int worth;
+        int flags;
+        char    *name;
+    }
+    selection[SELL_ITEMS];
+
+    int effective_purse = ((player.t_ctype == C_PALADIN) ?
+                   (9 * purse / 10) : purse);
+
+    min_worth = -1;     /* hope item is never worth less than this */
+    item = find_mons(tp->t_pos.y, tp->t_pos.x); /* Get pointer to monster */
+
+    /* Select the items */
+
+    nitems = rnd(6) + 5;
+
+    switch (rnd(6))
+    {
+        /* Armor */
+        case 0:
+        case 1:
+            goods = ARMOR;
+            for (i = 0; i < nitems; i++)
+            {
+                chance = rnd(100);
+
+                for (j = 0; j < maxarmors; j++)
+                    if (chance < armors[j].a_prob)
+                        break;
+
+                if (j == maxarmors)
+                {
+                    debug("Picked a bad armor %d", chance);
+                    j = 0;
+                }
+
+                selection[i].which = j;
+                selection[i].count = 1;
+
+                if (rnd(100) < 40)
+                    selection[i].plus1 = rnd(5) + 1;
+                else
+                    selection[i].plus1 = 0;
+
+                selection[i].name = armors[j].a_name;
+
+                switch (luck)
+                {
+                    case 0: break;
+                    case 1:
+                        if (rnd(3) == 0)
+                        {
+                            selection[i].flags |=  ISCURSED;
+                            selection[i].plus1 =  -1 - rnd(5);
+                        }
+                        break;
+
+                    default:
+                        if (rnd(luck))
+                        {
+                            selection[i].flags |= ISCURSED;
+                            selection[i].plus1 =  -1 - rnd(5);
+                        }
+                        break;
+                }
+
+                /* Calculate price */
+
+                w = armors[j].a_worth;
+                w *= (1 + luck + (10 * selection[i].plus1));
+                w = (w / 2) + (roll(6, w) / 6);
+                selection[i].worth = max(w, 25);
+
+                if (min_worth > selection[i].worth || i == 1)
+                    min_worth = selection[i].worth;
+            }
+            break;
+
+            /* Weapon */
+        case 2:
+        case 3:
+            goods = WEAPON;
+            for (i = 0; i < nitems; i++)
+            {
+                selection[i].which = rnd(maxweapons);
+                selection[i].count = 1;
+
+                if (rnd(100) < 35)
+                {
+                    selection[i].plus1 = rnd(3);
+                    selection[i].plus2 = rnd(3);
+                }
+                else
+                {
+                    selection[i].plus1 = 0;
+                    selection[i].plus2 = 0;
+                }
+
+                if (weaps[selection[i].which].w_flags & ISMANY)
+                    selection[i].count = rnd(15) + 8;
+
+                selection[i].name = weaps[selection[i].which].w_name;
+
+                switch (luck)
+                {
+                    case 0: break;
+                    case 1:
+                        if (rnd(3) == 0)
+                        {
+                            selection[i].flags |= ISCURSED;
+                            selection[i].plus1 =  -rnd(3);
+                            selection[i].plus2 =  -rnd(3);
+                        }
+                        break;
+
+                    default:
+                        if (rnd(luck))
+                        {
+                            selection[i].flags |= ISCURSED;
+                            selection[i].plus1 =  -rnd(3);
+                            selection[i].plus2 =  -rnd(3);
+                        }
+                        break;
+                }
+
+                w = weaps[selection[i].which].w_worth * selection[i].count;
+                w *= (1 + luck + (10 * selection[i].plus1 +
+                          10 * selection[i].plus2));
+                w = (w / 2) + (roll(6, w) / 6);
+                selection[i].worth = max(w, 25);
+
+                if (min_worth > selection[i].worth || i == 1)
+                    min_worth = selection[i].worth;
+            }
+            break;
+
+            /* Staff or wand */
+        case 4:
+            goods = STICK;
+
+            for (i = 0; i < nitems; i++)
+            {
+                selection[i].which = pick_one(ws_magic, maxsticks);
+                selection[i].plus1 = rnd(11) + 5;
+                selection[i].count = 1;
+                selection[i].name = ws_magic[selection[i].which].mi_name;
+
+                switch (luck)
+                {
+                    case 0: break;
+                    case 1:
+                        if (rnd(3) == 0)
+                        {
+                            selection[i].flags |= ISCURSED;
+                            selection[i].plus1 = 1;
+                        }
+                        break;
+
+                    default:
+                        if (rnd(luck))
+                        {
+                            selection[i].flags |= ISCURSED;
+                            selection[i].plus1 = 1;
+                        }
+                }
+
+                w = ws_magic[selection[i].which].mi_worth;
+                w += (luck + 1) * 20 * selection[i].plus1;
+                w = (w / 2) + (roll(6, w) / 6);
+                selection[i].worth = max(w, 25);
+
+                if (min_worth > selection[i].worth || i == 1)
+                    min_worth = selection[i].worth;
+            }
+            break;
+
+            /* Ring */
+
+        case 5:
+            goods = RING;
+            for (i = 0; i < nitems; i++)
+            {
+                selection[i].which = pick_one(r_magic, maxrings);
+                selection[i].plus1 = rnd(2) + 1;
+                selection[i].count = 1;
+
+                if (rnd(100) < r_magic[selection[i].which].mi_bless + 10)
+                    selection[i].plus1 += rnd(2) + 1;
+
+                selection[i].name = r_magic[selection[i].which].mi_name;
+
+                switch (luck)
+                {
+                    case 0: break;
+                    case 1:
+                        if (rnd(3) == 0)
+                        {
+                            selection[i].flags |= ISCURSED;
+                            selection[i].plus1 =  -1 - rnd(2);
+                        }
+                        break;
+
+                    default:
+                        if (rnd(luck))
+                        {
+                            selection[i].flags |= ISCURSED;
+                            selection[i].plus1 =  -1 - rnd(2);
+                        }
+                }
+
+                w = r_magic[selection[i].which].mi_worth;
+
+                switch(selection[i].which)
+                {
+                    case R_DIGEST:
+                        if (selection[i].plus1 > 2)
+                            selection[i].plus1 = 2;
+                        else if (selection[i].plus1 < 1)
+                            selection[i].plus1 = 1;
+                    /* fall thru here to other cases */
+                    case R_ADDSTR:
+                    case R_ADDDAM:
+                    case R_PROTECT:
+                    case R_ADDHIT:
+                    case R_ADDINTEL:
+                    case R_ADDWISDOM:
+                        if (selection[i].plus1 > 0)
+                            w += selection[i].plus1 * 50;
+                }
+
+                w *= (1 + luck);
+                w = (w / 2) + (roll(6, w) / 6);
+                selection[i].worth = max(w, 25);
+
+                if (min_worth > selection[i].worth * selection[i].count)
+                    min_worth = selection[i].worth;
+            }
+    }
+
+    /* See if player can afford an item */
+
+    if (min_worth > effective_purse)
+    {
+        msg("The %s eyes your small purse and departs.",
+            monsters[nummonst].m_name);
+
+        /* Get rid of the monster */
+
+        killed(NULL, item, NOMESSAGE, NOPOINTS);
+
+        return;
+    }
+
+    /* Display the goods */
+
+    msg("The %s shows you his wares.", monsters[nummonst].m_name);
+    wstandout(cw);
+    mvwaddstr(cw, 0, mpos, morestr);
+    wstandend(cw);
+    wrefresh(cw);
+    wait_for(' ');
+    msg("");
+    clearok(cw, TRUE);
+    touchwin(cw);
+
+    wclear(hw);
+    touchwin(hw);
+
+    for (i = 0; i < nitems; i++)
+    {
+        if (selection[i].worth > effective_purse)
+            continue;
+
+        wmove(hw, i + 2, 0);
+        sprintf(dbuf, "[%c] ", ('a' + i));
+
+        switch(goods)
+        {
+            case ARMOR:
+                strcat(dbuf, "Some ");
+                break;
+            case WEAPON:
+                if (selection[i].count == 1)
+                    strcat(dbuf, "A ");
+                else
+                {
+                    sprintf(buffer, "%2d ", selection[i].count);
+                    strcat(dbuf, buffer);
+                }
+                break;
+
+            case STICK:
+                strcat(dbuf, "A ");
+                strcat(dbuf, ws_type[selection[i].which]);
+                strcat(dbuf, " of ");
+                break;
+
+            case RING:
+                strcat(dbuf, "A ring of ");
+                break;
+        }
+
+        strcat(dbuf, selection[i].name);
+
+        if (selection[i].count > 1)
+            strcat(dbuf, "s");
+
+        sprintf(buffer, "%-50s Price:  %d", dbuf, selection[i].worth);
+        waddstr(hw, buffer);
+    }
+
+    sprintf(buffer, "Purse:  %d", purse);
+    mvwaddstr(hw, nitems + 3, 0, buffer);
+    mvwaddstr(hw, 0, 0, "How about one of the following goods? ");
+    wrefresh(hw);
+
+    /* Get rid of the monster */
+
+    killed(NULL, item, NOMESSAGE, NOPOINTS);
+
+    which_item = (short) ((readchar() & 0177) - 'a');
+
+    while (which_item < 0 || which_item >= nitems ||
+        selection[which_item].worth > effective_purse)
+    {
+        if (which_item == (short) ESCAPE - (short) 'a')
+            return;
+
+        mvwaddstr(hw, 0, 0, "Please enter one of the listed items: ");
+        wrefresh(hw);
+        which_item = (short) ((readchar() & 0177) - 'a');
+    }
+
+    if (purse > selection[which_item].worth)
+         purse -= selection[which_item].worth;
+    else
+         purse = 0L;
+
+    item = spec_item(goods, selection[which_item].which,
+          selection[which_item].plus1, selection[which_item].plus2);
+
+    obj = OBJPTR(item);
+
+    if (selection[which_item].count > 1)
+    {
+        obj->o_count = selection[which_item].count;
+        obj->o_group = ++group;
+    }
+
+    /* If a stick or ring, let player know the type */
+
+    switch (goods)
+    {
+        case STICK: know_items[TYP_STICK][selection[which_item].which] = TRUE;
+                    break;
+        case RING:  know_items[TYP_RING][selection[which_item].which] = TRUE;
+                    break;
+    }
+
+    if (add_pack(item, MESSAGE) == FALSE)
+    {
+        obj->o_pos = hero;
+        fall(&player, item, TRUE, FALSE);
+    }
+}
+
+void
+carried_weapon(struct thing *owner, struct object *weapon)
+{
+    weapon->o_hplus = (rnd(4) < 3) ? 0 : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
+    weapon->o_dplus = (rnd(4) < 3) ? 0 : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1);
+    weapon->o_hplus += rnd(owner->t_stats.s_lvl / 3 + 1);
+    weapon->o_hplus += rnd(owner->t_stats.s_lvl / 3 + 1);
+    weapon->o_damage = weapon->o_hurldmg = "0d0";
+    weapon->o_ac = 11;
+    weapon->o_count = 1;
+    weapon->o_group = 0;
+
+    if ((weapon->o_hplus <= 0) && (weapon->o_dplus <= 0))
+        weapon->o_flags = ISCURSED;
+
+    weapon->o_flags = 0;
+    weapon->o_type = WEAPON;
+    weapon->o_mark[0] = '\0';
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/move.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1837 @@
+/*
+    move.c - Hero movement commands
+      
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <stdlib.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+    do_run()
+        Start the hero running
+*/
+
+void
+do_run(char ch)
+{
+    running = TRUE;
+    after = FALSE;
+    runch = ch;
+
+    if (doorstop && !on(player, ISBLIND))
+    {
+        door_stop = TRUE;
+        firstmove = TRUE;
+    }
+}
+
+/*
+    step_ok()
+        returns true if it is ok for type to step on ch flgptr will be
+        NULL if we don't know what the monster is yet!
+*/
+
+int
+step_ok(int y, int x, int can_on_monst, struct thing *flgptr)
+{
+    struct linked_list *item;
+    char ch;
+
+    /* What is here?  Don't check monster window if MONSTOK is set */
+
+    if (can_on_monst == MONSTOK)
+        ch = CCHAR( mvinch(y, x) );
+    else
+        ch = winat(y, x);
+
+    switch (ch)
+    {
+        case ' ':
+        case '|':
+        case '-':
+        case SECRETDOOR:
+            if (flgptr && on(*flgptr, CANINWALL))
+                return(TRUE);
+
+            return(FALSE);
+
+        case SCROLL:
+            /*
+             * If it is a scroll, it might be a scare monster scroll so
+             * we need to look it up to see what type it is.
+             */
+
+            if (flgptr && flgptr->t_ctype == C_MONSTER)
+            {
+                item = find_obj(y, x);
+
+                if (item != NULL && (OBJPTR(item))->o_type == SCROLL
+                     && (OBJPTR(item))->o_which == S_SCARE
+                     && rnd(flgptr->t_stats.s_intel) < 12)
+                return(FALSE); /* All but smart ones are scared */
+            }
+            return(TRUE);
+
+        default:
+            return(!isalpha(ch));
+    }
+}
+
+/*
+    corr_move()
+        Check to see that a move is legal.  If so, return correct
+        character. If not, if player came from a legal place, then try to turn
+        him.
+*/
+
+void
+corr_move(int dy, int dx)
+{
+    char    ch;
+    short   legal = 0;  /* Number of legal alternatives */
+    int     y = 0, x = 0;   /* Holds legal new position */
+    int    *ny, *nx;    /* Point to which direction to change */
+
+    /* New position */
+
+    player.t_nxtpos.y = hero.y + dy;
+    player.t_nxtpos.x = hero.x + dx;
+
+    /* A bad diagonal move is illegal */
+
+    if (!diag_ok(&hero, &player.t_nxtpos, &player))
+        return;
+
+    /* If it is a legal move, just return */
+
+    if (player.t_nxtpos.x >= 0 && player.t_nxtpos.x < COLS && player.t_nxtpos.y > 0 && player.t_nxtpos.y < LINES - 2)
+    {
+        ch = winat(player.t_nxtpos.y, player.t_nxtpos.x);
+
+        switch (ch)
+        {
+            case ' ':
+            case '|':
+            case '-':
+                break;
+            default:
+                return;
+        }
+    }
+
+    /* Check the legal alternatives */
+
+    if (dy == 0)
+    {
+        ny = &dy;
+        nx = &dx;
+    }
+    else
+    {
+        ny = &dx;
+        nx = &dy;
+    }
+
+    for (*nx = 0, *ny = -1; *ny < 2; *ny += 2)
+    {
+        /* New position */
+        player.t_nxtpos.y = hero.y + dy;
+        player.t_nxtpos.x = hero.x + dx;
+
+        if (player.t_nxtpos.x < 0 || player.t_nxtpos.x > COLS - 1 || player.t_nxtpos.y < 1 || player.t_nxtpos.y > LINES - 3)
+            continue;
+
+        ch = winat(player.t_nxtpos.y, player.t_nxtpos.x);
+
+        switch (ch)
+        {
+            case ' ':
+            case '|':
+            case '-':
+                break;
+            default:
+                legal++;
+                y = dy;
+                x = dx;
+        }
+    }
+
+    /* If we have 2 legal moves, make no change */
+
+    if (legal != 1)
+        return;
+
+    /* Make the change */
+
+    if (y == 0)         /* Move horizontally */
+    {
+        if (x == 1)
+            runch = 'l';
+        else
+            runch = 'h';
+    }
+    else            /* Move vertically */
+    {
+        if (y == 1)
+            runch = 'j';
+        else
+            runch = 'k';
+    }
+
+    return;
+}
+
+
+/*
+    do_move()
+        Check to see that a move is legal.  If it is handle the
+        consequences (fighting, picking up, etc.)
+*/
+
+void
+do_move(int dy, int dx)
+{
+    char    ch;
+    coord   old_hero;
+    char    hch;
+
+    firstmove = FALSE;
+
+    if (player.t_no_move)
+    {
+        player.t_no_move--;
+        msg("You are still stuck in the bear trap.");
+        return;
+    }
+
+    /* Do a confused move (maybe) */
+
+    if ((rnd(100) < 80 && on(player, ISHUH)) ||
+        (is_wearing(R_DELUSION) && rnd(100) < 25) ||
+        on(player, STUMBLER) && rnd(40) == 0)
+        player.t_nxtpos = rndmove(&player);
+    else
+    {
+        player.t_nxtpos.y = hero.y + dy;
+        player.t_nxtpos.x = hero.x + dx;
+    }
+
+    /*
+     * Check if he tried to move off the screen or make an illegal
+     * diagonal move, and stop him if he did.
+     */
+
+    if (player.t_nxtpos.x < 0 || player.t_nxtpos.x > COLS - 1 || player.t_nxtpos.y < 1 || player.t_nxtpos.y >= LINES - 2
+        || !diag_ok(&hero, &player.t_nxtpos, &player))
+    {
+        after = fighting = running = FALSE;
+        return;
+    }
+
+    if (running && ce(hero, player.t_nxtpos))
+        after = running = FALSE;
+
+    ch = winat(player.t_nxtpos.y, player.t_nxtpos.x);
+
+	if (isalpha(ch))
+	    debug("Moving onto monster %c",ch);
+    
+	/* Take care of hero trying to move close to something frightening */
+    
+	if (on(player, ISFLEE))
+    {
+        if (rnd(10) < 1)
+        {
+            turn_off(player, ISFLEE);
+            msg("You regain your composure.");
+        }
+        else if (DISTANCE(player.t_nxtpos, player.t_chasee->t_pos) <
+                 DISTANCE(hero,player.t_chasee->t_pos))
+            return;
+    }
+
+    /* Take care of hero being held */
+
+    if (on(player, ISHELD) && !isalpha(ch))
+    {
+        if (rnd(pstats.s_str) > 14)
+        {
+            msg("You break free of the hold.");
+
+            if (--hold_count == 0)
+                turn_off(player, ISHELD);
+        }
+        else
+        {
+            msg("You are being held.");
+            return;
+        }
+    }
+ 
+    /* Might lose disguise */
+
+    if (on(player, ISDISGUISE) && rnd(11 * pstats.s_dext) == 0)
+    {
+        extinguish_fuse(FUSE_UNDISGUISE);
+        undisguise(NULL);
+    }
+
+    /* assume he's not in a wall */
+
+    if (!isalpha(ch))
+        turn_off(player, ISINWALL);
+
+    hch = CCHAR( mvinch(hero.y, hero.x) );   /* Where hero was */
+    old_hero = hero;    /* Save hero's old position */
+
+    switch (ch)
+    {
+        case ' ':
+        case '|':
+        case '-':
+        case SECRETDOOR:
+            if (off(player, CANINWALL))
+            {
+                after = running = FALSE;
+                return;
+            }
+            else if (running)
+            {
+                after = running = FALSE;
+                return;
+            }
+            turn_on(player, ISINWALL);
+            break;
+
+        case TRAPDOOR:
+        case TELTRAP:
+        case BEARTRAP:
+        case SLEEPTRAP:
+        case ARROWTRAP:
+        case DARTTRAP:
+        case POOL:
+        case MAZETRAP:
+        case FIRETRAP:
+        case POISONTRAP:
+        case LAIR:
+        case RUSTTRAP:
+            ch = be_trapped(&player, player.t_nxtpos);
+
+            if (!is_wearing(R_LEVITATION) && off(player, CANFLY) &&
+                (old_hero.x != hero.x || old_hero.y != hero.y
+                 || pool_teleport))
+            {
+                pool_teleport = FALSE;
+                return;
+            }
+
+            break;
+
+        case GOLD:
+        case POTION:
+        case SCROLL:
+        case FOOD:
+        case WEAPON:
+        case ARMOR:
+        case RING:
+        case ARTIFACT:
+        case STICK:
+            running = FALSE;
+            take = ch;
+            break;
+
+        default:
+            break;
+    }
+
+    if (ch == FIRETRAP)
+        light(&hero);
+
+    hero = player.t_nxtpos;      /* Move the hero */
+	
+	/* adjust lighting */
+
+    if (roomin(hero) == NULL && (hch == '-' || hch == '|' ||
+        hch == DOOR || hch == SECRETDOOR))
+    {
+        /* Leaving a room -- darken it */
+        struct room *rp = roomin(old_hero);
+        int    is_lit = FALSE;
+
+        if (!(rp->r_flags & ISDARK))
+            is_lit = TRUE;
+
+        rp->r_flags |= ISDARK;  /* Fake darkness */
+        light(&old_hero);
+
+        if (is_lit)
+            rp->r_flags &= ~ISDARK; /* Restore light state */
+    }
+    else if (ch == DOOR || ch == SECRETDOOR || ch == '|' || ch == '-')
+    {
+        /* Entering a room */
+        running = FALSE;
+        if (hch != '|' && hch != '-')
+            light(&hero);   /* knows whether the hero can see things in */
+    }	
+	
+	/* handle other situations */
+	
+    if (ch == STAIRS)
+        running = FALSE;
+    else if (ch == POST)
+    {
+        running = FALSE;
+        new_level(POSTLEV,0);
+        return;
+    }
+    else if (isalpha(ch))
+    {
+        struct linked_list  *mp;
+        struct thing    *tp;
+        char t;
+
+        running = FALSE;
+
+        mp = find_mons(hero.y, hero.x);
+
+        if (mp == NULL)
+            return;
+
+        tp = THINGPTR(mp);
+
+        if (good_monster(*tp))  /* Exchange places with your buddy */
+        {
+            mvwaddch(cw, old_hero.y, old_hero.x, ch);
+            mvwaddch(mw, old_hero.y, old_hero.x, ch);
+            mvwaddch(mw, hero.y, hero.x, ' ');
+            mvwaddch(cw, hero.y, hero.x, tp->t_oldch);
+
+            (*tp).t_pos.x = old_hero.x; /* Update monster position variables */
+            (*tp).t_pos.y = old_hero.y;
+            (*tp).t_oldpos.x = old_hero.x;
+            (*tp).t_oldpos.y = old_hero.y;
+
+            t = (*tp).t_oldch;
+            (*tp).t_oldch = player.t_oldch;
+            player.t_oldch = t;
+
+            turn_on(*tp, ISRUN);
+
+            mvwaddch(cw, hero.y, hero.x, PLAYER);
+			
+			/* make sure that the room shows OK */
+			
+			light(&hero);
+			
+            wrefresh(cw);
+            return;
+        }
+        else
+        {
+            hero = old_hero; /* Restore hero -- we'll fight instead of move */
+
+			/* make sure that the room shows OK */
+    		light(&hero);
+
+            fight(&player.t_nxtpos, cur_weapon, NOTHROWN);
+
+            return;
+        }
+    }
+    else
+        fighting = FALSE;
+
+    ch = winat(old_hero.y, old_hero.x);
+    mvwaddch(cw, old_hero.y, old_hero.x, ch);
+    mvwaddch(cw, hero.y, hero.x, PLAYER);
+}
+
+/*
+    light()
+        Called to illuminate a room. If it is dark, remove anything that might
+        move.
+*/
+
+void
+light(coord *cp)
+{
+    struct room *rp;
+    int j, k, x, y;
+    char    ch, rch;
+    struct linked_list  *item;
+    int jlow, jhigh, klow, khigh;   /* Boundaries of lit area */
+
+    if ((rp = roomin(*cp)) != NULL && !on(player, ISBLIND))
+    {
+
+        /* is he wearing ring of illumination and in same room? */
+
+        if ((is_wearing(R_LIGHT) || on(player, ISELECTRIC)) &&
+            cp == &hero)
+            rp->r_flags &= ~ISDARK;
+
+        /* If we are in a maze, don't look at the whole room (level) */
+
+        if (levtype == MAZELEV)
+        {
+            jlow = max(0, hero.y - 2 - rp->r_pos.y);
+            jhigh = min(rp->r_max.y, hero.y + 2 - rp->r_pos.y + 1);
+            klow = max(0, hero.x - 2 - rp->r_pos.x);
+            khigh = min(rp->r_max.x, hero.x + 2 - rp->r_pos.x + 1);
+        }
+        else
+        {
+            jlow = klow = 0;
+            jhigh = rp->r_max.y;
+            khigh = rp->r_max.x;
+        }
+
+        for (j = 0; j < rp->r_max.y; j++)
+        {
+            for (k = 0; k < rp->r_max.x; k++)
+            {
+                /* Is this in the given area -- needed for maze */
+
+                if ((j < jlow || j >= jhigh) && (k < klow || k >= khigh))
+                    continue;
+
+                y = rp->r_pos.y + j;
+                x = rp->r_pos.x + k;
+
+                ch = show(y, x);
+                wmove(cw, y, x);
+
+                /* Figure out how to display a secret door */
+
+                if (ch == SECRETDOOR)
+                {
+                    if (j == 0 || j == rp->r_max.y - 1)
+                        ch = '-';
+                    else
+                        ch = '|';
+                }
+
+                /*
+                 * For monsters, if they were previously not
+                 * seen and now can be seen, or vice-versa,
+                 * make sure that will happen.
+                 */
+
+                if (isalpha(ch))
+                {
+                    struct thing    *tp;
+
+                    item = wake_monster(y, x);
+
+                    if (item == NULL)
+                        continue;
+
+                    tp = THINGPTR(item);
+
+                    /* Previously not seen -- now can see it */
+
+                    if (tp->t_oldch == ' ' && cansee(tp->t_pos.y, tp->t_pos.x))
+                        tp->t_oldch = CCHAR( mvinch(y, x) );
+
+                    /* Previously seen -- now can't see it */
+
+                    else if (off(player, ISBLIND) && tp->t_oldch != ' ' &&
+                         !cansee(tp->t_pos.y, tp->t_pos.x))
+                        tp->t_oldch = ' ';
+                }
+
+                /*
+                 * If the room is a dark room, we might want
+                 * to remove monsters and the like from it
+                 * (since they might move). A dark room or
+                 * not in line-of-sight in a maze.
+                 */
+
+                if (((rp->r_flags & ISDARK) &&
+                    !(rp->r_flags & HASFIRE)) ||
+                    (levtype == MAZELEV &&
+                     !maze_view(y, x)))
+                {
+                    rch = CCHAR( mvwinch(cw, y, x) );
+
+                    switch (rch)
+                    {
+                        case DOOR:
+                        case STAIRS:
+                        case TRAPDOOR:
+                        case TELTRAP:
+                        case BEARTRAP:
+                        case SLEEPTRAP:
+                        case ARROWTRAP:
+                        case DARTTRAP:
+                        case POOL:
+                        case MAZETRAP:
+                        case FIRETRAP:
+                        case POISONTRAP:
+                        case LAIR:
+                        case RUSTTRAP:
+                        case POST:
+                        case '|':
+                        case '-':
+                        case ' ':
+                            ch = rch;
+                            break;
+
+                        case    FLOOR:
+                            ch = (on(player, ISBLIND) ? FLOOR : ' ');
+                            break;
+                        default:
+                            ch = ' ';
+                            break;
+                    }
+                }
+                mvwaddch(cw, y, x, ch);
+            }
+        }
+    }
+}
+
+/*
+    blue_light()
+        magically light up a room (or level or make it dark)
+*/
+
+int
+blue_light(int flags)
+{
+    struct room *rp;
+    int  blessed = (flags & ISBLESSED);
+    int  cursed = (flags & ISCURSED);
+    int  ret_val = FALSE;   /* Whether or not affect is known */
+
+    rp = roomin(hero); /* What room is hero in? */
+
+    /* Darken the room if the magic is cursed */
+
+    if (cursed)
+    {
+        if ((rp == NULL) || (rp->r_flags & ISDARK))
+            nothing_message(flags);
+        else
+        {
+            if (!(rp->r_flags & HASFIRE))
+                msg("The room suddenly goes dark.");
+            else
+                nothing_message(flags);
+
+            rp->r_flags |= ISDARK;
+            ret_val = TRUE;
+        }
+    }
+    else
+    {
+        ret_val = TRUE;
+
+        if (rp && (rp->r_flags & ISDARK) && !(rp->r_flags & HASFIRE))
+        {
+            msg("The room is lit by a %s blue light.",
+                 blessed ? "bright" : "shimmering");
+        }
+        else if (winat(hero.y, hero.x) == PASSAGE)
+            msg("The corridor glows %sand then fades.", blessed ? "brightly " : "");
+        else
+        {
+            ret_val = FALSE;
+            nothing_message(flags);
+        }
+
+        if (blessed)
+        {
+            short   i;  /* Index through rooms */
+
+            for (i = 0; i < MAXROOMS; i++)
+                rooms[i].r_flags &= ~ISDARK;
+        }
+        else if (rp)
+            rp->r_flags &= ~ISDARK;
+    }
+
+    /* Light the room and put the player back up */
+
+    light(&hero);
+    mvwaddch(cw, hero.y, hero.x, PLAYER);
+
+    return (ret_val);
+}
+
+/*
+    show()
+        returns what a certain thing will display as to the un-initiated
+*/
+
+char
+show(int y, int x)
+{
+    char    ch = winat(y, x);
+    struct linked_list  *it;
+    struct thing    *tp;
+
+    if (isatrap(ch))
+    {
+        struct trap *trp = trap_at(y, x);
+        return (trp->tr_flags & ISFOUND) ? ch : trp->tr_show;
+    }
+    else if (isalpha(ch))
+    {
+        if ((it = find_mons(y, x)) == NULL)
+        {
+            debug("Can't find monster in move.");
+            return ' ';
+        }
+        tp = THINGPTR(it);
+
+        if (on(*tp, ISDISGUISE))
+            ch = tp->t_disguise;    /* As a mimic */
+        else if (on(*tp, ISINVIS) || (on(*tp, ISSHADOW) &&
+            rnd(100) < 90) || on(*tp, CANSURPRISE))
+        {
+            if (off(player, CANSEE) || on(*tp, CANSURPRISE))
+                ch = CCHAR( mvwinch(stdscr, y, x) ); /* Invisible */
+        }
+        else if (on(*tp, CANINWALL))
+        {
+            char    tch;
+
+            tch = CCHAR( mvwinch(stdscr, y, x) );
+
+            if (tch == WALL || tch == '-' || tch == '|')
+                ch = CCHAR( winch(stdscr) ); /* As Xorn */
+        }
+    }
+    return(ch);
+}
+
+/*
+    be_trapped()
+        The guy stepped on a trap.... Make him pay.
+*/
+
+char
+be_trapped(struct thing *th, coord tc)
+{
+    struct trap *tp;
+    char   ch, *mname = NULL;
+    int    is_player = (th == &player), can_see = cansee(tc.y, tc.x);
+    struct linked_list  *mitem = NULL;
+
+    tp = trap_at(tc.y, tc.x);
+    ch = tp->tr_type;
+
+    if (!is_player)
+    {
+        mitem = find_mons(th->t_pos.y, th->t_pos.x);
+        mname = monsters[th->t_index].m_name;
+
+        /* Flying monsters do not set off traps */
+
+        if (!mitem || (on(*th, CANFLY) &&
+             (ch == BEARTRAP || ch == MAZETRAP || ch == TRAPDOOR
+              || ch == ARROWTRAP || ch == DARTTRAP)))
+        {
+            debug("%s avoided trap.", mname);
+            return(ch);
+        }
+    }
+    else
+    {
+        short   thief_bonus = -50;
+
+        count = running = FALSE;
+        mvwaddch(cw, tp->tr_pos.y, tp->tr_pos.x, tp->tr_type);
+
+        if (no_command)
+            return(ch);
+
+        if (player.t_ctype == C_THIEF || player.t_ctype == C_NINJA)
+            thief_bonus = 10;
+
+        if (((is_wearing(R_LEVITATION) || on(player, CANFLY)) &&
+            (ch != FIRETRAP ||
+                 (ch == FIRETRAP && !(tp->tr_flags & ISFOUND))))
+            || (moving && (tp->tr_flags & ISFOUND) && rnd(100) <
+              thief_bonus + 2 * pstats.s_dext + 5 * pstats.s_lvl) &&
+            (ch == BEARTRAP || ch == MAZETRAP || ch == TRAPDOOR
+             || ch == ARROWTRAP || ch == DARTTRAP))
+        {
+            static char trname[1024];
+            msg(tr_name(ch,trname));
+            tp->tr_flags |= ISFOUND;
+            return(ch);
+        }
+
+        if (moving)
+            msg("Your attempt fails.");
+    }
+
+    tp->tr_flags |= ISFOUND;
+
+    switch(ch)
+    {
+        case TRAPDOOR:
+            if (is_player)
+            {
+                level++;
+                new_level(NORMLEV,0);
+                addmsg("You fell into a trap");
+
+                if (player.t_ctype != C_THIEF
+                    && player.t_ctype != C_ASSASIN
+                    && player.t_ctype != C_NINJA
+                    && rnd(pstats.s_dext) < 4)
+                {
+                    addmsg(" and were damaged by the fall");
+
+                    if ((pstats.s_hpt -= roll(1, 6)) <= 0)
+                    {
+                        addmsg("!  The fall killed you.");
+                        endmsg();
+                        death(D_FALL);
+
+                        return(ch);
+                    }
+                }
+
+                addmsg("!");
+                endmsg();
+
+                if (off(player, ISCLEAR) && rnd(4) < 3)
+                {
+                    if (on(player, ISHUH))
+                        lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION);
+                    else
+                        light_fuse(FUSE_UNCONFUSE,0,rnd(8)+HUHDURATION, AFTER);
+
+                    turn_on(player, ISHUH);
+                }
+                else
+                    msg("You feel dizzy for a moment, but it quickly passes.");
+            }
+            else
+            {
+                if (can_see)
+                    msg("The %s fell into a trap!", mname);
+
+                if (on(*th, ISFAMILIAR))
+				    turn_off(player, HASFAMILIAR);
+
+                killed(NULL,mitem,NOMESSAGE,NOPOINTS);
+            }
+            break;
+
+        case BEARTRAP:
+            if (is_stealth(th))
+            {
+                if (is_player)
+                    msg("You pass a bear trap.");
+                else if (can_see)
+                    msg("The %s passes a bear trap.", mname);
+            }
+            else
+            {
+                th->t_no_move += BEARTIME;
+
+                if (is_player)
+                    msg("You are caught in a bear trap.");
+                else if (can_see)
+                    msg("The %s is caught in a bear trap.", mname);
+            }
+            break;
+
+        case SLEEPTRAP:
+            if (is_player)
+            {
+                msg("A strange white mist envelops you.");
+
+                if (!is_wearing(R_ALERT))
+                {
+                    if (!is_wearing(R_BREATHE) && off(player, HASOXYGEN))
+                    {
+                        msg("You fall asleep.");
+                        no_command += SLEEPTIME;
+                    }
+                }
+            }
+            else
+            {
+                if (can_see)
+                    msg("A strange white mist envelops the %s.", mname);
+
+                if (on(*th, ISUNDEAD))
+                {
+                    if (can_see)
+                        msg("The mist doesn't seem to affect the %s.", mname);
+                }
+
+                if (on(*th, ISUNDEAD) || on(*th, HASOXYGEN))
+                {
+                    if (can_see)
+                        msg("The mist doesn't seem to affect the %s.", mname);
+                }
+                else
+                {
+                    th->t_no_move += SLEEPTIME;
+                }
+            }
+            break;
+
+        case ARROWTRAP:
+            if (swing(th->t_ctype, th->t_stats.s_lvl - 1, th->t_stats.s_arm, 1))
+            {
+                if (is_player)
+                {
+                    msg("Oh no! An arrow shot you.");
+
+                    if ((pstats.s_hpt -= roll(1, 6)) <= 0)
+                    {
+                        msg("The arrow killed you.");
+                        death(D_ARROW);
+                        return(ch);
+                    }
+                }
+                else
+                {
+                    if (can_see)
+                        msg("An arrow shot the %s.", mname);
+
+                    if (on(*th, NOSHARP))
+                    {
+                        if (can_see)
+                            msg("The arrow has no effect!");
+                    }
+                    else
+                    {
+                        if ((th->t_stats.s_hpt -= roll(1, 6)) <= 0)
+                        {
+                            if (can_see)
+                                msg("The arrow killed the %s.", mname);
+								
+							if (on(*th, ISFAMILIAR))
+							    turn_off(player, HASFAMILIAR);
+
+                            killed(NULL, mitem, NOMESSAGE, NOPOINTS);
+                        }
+                    }
+                }
+            }
+            else
+            {
+                struct linked_list  *itm;
+                struct object *an_arrow;
+
+                if (is_player)
+                    msg("An arrow shoots past you.");
+                else if (can_see)
+                    msg("An arrow shoots by the %s.", mname);
+
+                itm = new_item(sizeof *an_arrow);
+                an_arrow = OBJPTR(itm);
+                an_arrow->o_type = WEAPON;
+                an_arrow->o_which = ARROW;
+                an_arrow->o_hplus = rnd(3) - 1;
+                an_arrow->o_dplus = rnd(3) - 1;
+                init_weapon(an_arrow, ARROW);
+                an_arrow->o_count = 1;
+                an_arrow->o_pos = tc;
+                an_arrow->o_mark[0] = '\0';
+                fall(&player, itm, FALSE, FALSE);
+            }
+            break;
+
+        case TELTRAP:
+            if (is_player)
+            {
+                teleport();
+
+                if (off(player, ISCLEAR))
+                {
+                    msg("Wait, what's going on here. Huh? What? Who?");
+
+                    if (on(player, ISHUH))
+                        lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION);
+                    else
+                        light_fuse(FUSE_UNCONFUSE,0,rnd(8)+HUHDURATION, AFTER);
+
+                    turn_on(player, ISHUH);
+                }
+                else
+                    msg("You feel dizzy for a moment, but it quickly passes.");
+            }
+            else
+            {
+                int rm;
+
+                /* Erase the monster from the old position */
+
+                if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x)))
+                    mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch);
+
+                mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
+
+                /* Get a new position */
+
+                do
+                {
+                    rm = rnd_room();
+                    rnd_pos(&rooms[rm], &th->t_pos);
+                }
+                while(winat(th->t_pos.y, th->t_pos.x) != FLOOR);
+
+                /* Put it there */
+
+                mvwaddch(mw, th->t_pos.y, th->t_pos.x, th->t_type);
+                th->t_oldch = CCHAR( mvwinch(cw, th->t_pos.y, th->t_pos.x) );
+
+                if (can_see)
+                    msg("The %s seems to have disappeared!", mname);
+            }
+            break;
+
+        case DARTTRAP:
+
+            if (swing(th->t_ctype, th->t_stats.s_lvl + 1,th->t_stats.s_arm, 1))
+            {
+                if (is_player)
+                {
+                    msg("A small dart just hit you in the shoulder.");
+
+                    if ((pstats.s_hpt -= roll(1, 4)) <= 0)
+                    {
+                        msg("The dart killed you.");
+                        death(D_DART);
+                        return(ch);
+                    }
+
+                    /* Now the poison */
+
+                    if (player.t_ctype != C_PALADIN
+                        && !(player.t_ctype == C_NINJA &&
+                        pstats.s_lvl > 12) && !save(VS_POISON))
+                    {
+
+                        /*
+                         * 75% chance it will do point
+                         * damage - else strength
+                         */
+
+                        if (rnd(100) < 75)
+                        {
+                            pstats.s_hpt /= 2;
+
+                            if (pstats.s_hpt == 0)
+                            {
+                                death(D_POISON);
+                                return(ch);
+                            }
+                        }
+                        else if (!is_wearing(R_SUSABILITY))
+                            chg_str(-1, FALSE, FALSE);
+                    }
+                }
+                else
+                {
+                    int orig_hp = th->t_stats.s_hpt;
+
+                    if (can_see)
+                        msg("A small dart just hit the %s.", mname);
+
+                    /*
+                     * Poison has no effect on poisonous or
+                     * undead monsters
+                     */
+
+                    if (off(*th, CANPOISON) &&
+                        off(*th, ISUNDEAD) &&
+                        !save_throw(VS_POISON, th))
+                        th->t_stats.s_hpt /= 2;
+
+                    /* Now the dart damage */
+
+                    if (off(*th, NOSHARP))
+                        th->t_stats.s_hpt -= roll(1, 4);
+
+                    if (orig_hp == th->t_stats.s_hpt)
+                        if (can_see)
+                            msg("The dart has not effect!");
+                        else if (th->t_stats.s_hpt < 0)
+                        {
+                            if (can_see)
+                                msg("The dart killed the %s.", mname);
+								
+							if (on(*th, ISFAMILIAR))
+							    turn_off(player, HASFAMILIAR);
+
+                            killed(NULL, mitem, NOMESSAGE, NOPOINTS);
+                        }
+                }
+            }
+            else
+            {
+                if (is_player)
+                    msg("A small dart whizzes by your ear and vanishes.");
+                else if (can_see)
+                    msg("A small dart whizzes by the %s and vanishes.", mname);
+            }
+            break;
+
+        case POOL:
+        {
+            int i;
+
+            i = rnd(100);
+
+            if (is_player)
+            {
+                if (on(player, ISELECTRIC))
+                {
+                    msg("Oh no!!! The water shorts you out");
+                    extinguish_fuse(FUSE_UNELECTRIFY);
+                    turn_off(player, ISELECTRIC);
+
+                    if (!is_wearing(R_ELECTRESIST))
+                    {
+                        if ((pstats.s_hpt -= roll(1, 10)) <= 0)
+                        {
+                            addmsg("!  The shock killed you.");
+                            endmsg();
+                            death(D_DROWN);
+                            return(ch);
+                        }
+                    }
+                }
+
+                if ((tp->tr_flags & ISGONE))
+                {
+                    if (i < 30)
+                    {
+                        teleport(); /* teleport away */
+
+                        if (off(player, ISCLEAR))
+                        {
+                            if (on(player, ISHUH))
+                               lengthen_fuse(FUSE_UNCONFUSE,rnd(8)+HUHDURATION);
+                            else
+                               light_fuse(FUSE_UNCONFUSE,0,rnd(8)+HUHDURATION,AFTER);
+                            turn_on(player, ISHUH);
+                        }
+                        else
+                            msg("You feel dizzy for a moment, but it quickly passes.");
+
+                        pool_teleport = TRUE;
+                    }
+                    else if ((i < 45) && level > 2)
+                    {
+                        level -= rnd(2) + 1;
+                        new_level(NORMLEV,0);
+                        pool_teleport = TRUE;
+                        msg("You here a faint groan from below.");
+
+                        if (off(player, ISCLEAR))
+                        {
+                            if (on(player, ISHUH))
+                                lengthen_fuse(FUSE_UNCONFUSE,rnd(8)+HUHDURATION);
+                            else
+                                light_fuse(FUSE_UNCONFUSE, 0, rnd(8) + HUHDURATION, AFTER);
+
+                            turn_on(player, ISHUH);
+                        }
+                        else
+                            msg("You feel dizzy for a moment, but it quickly passes.");
+                    }
+                    else if (i < 70)
+                    {
+                        level += rnd(4) + 1;
+                        new_level(NORMLEV,0);
+                        pool_teleport = TRUE;
+                        msg("You find yourself in strange surroundings.");
+
+                        if (off(player, ISCLEAR))
+                        {
+                            if (on(player, ISHUH))
+                                lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION);
+                            else
+                                light_fuse(FUSE_UNCONFUSE, 0, rnd(8) + HUHDURATION, AFTER);
+
+                            turn_on(player, ISHUH);
+                        }
+                        else
+                            msg("You feel dizzy for a moment, but it quickly passes.");
+                    }
+                    else if (i > 95)
+                    {
+                        if (is_wearing(R_BREATHE) || on(player, HASOXYGEN))
+                            msg("You splash in the pool unharmed.");
+                        else
+                        {
+                            msg("Oh no!!! You drown in the pool!!! --More--");
+                            wait_for(' ');
+                            death(D_DROWN);
+                            return(ch);
+                        }
+                    }
+                }
+            }
+            else
+            {
+                if (can_see)
+                    msg("The %s fell into the pool!", mname);
+
+                if (i < 15)
+                {
+                    if (off(*th, HASOXYGEN))
+                    {
+                        if (can_see)
+                            msg("The %s has drowned!", mname);
+							
+                        if (on(*th, ISFAMILIAR))
+						    turn_off(player, HASFAMILIAR);
+							
+                        killed(NULL, mitem, NOMESSAGE, NOPOINTS);
+                    }
+                }
+            }
+        }
+        break;
+
+        case MAZETRAP:
+
+            if (is_player)
+            {
+                level++;
+                new_level(MAZELEV,0);
+                addmsg("You are surrounded by twisty passages");
+
+                if (rnd(4) < 1)
+                {
+                    addmsg(" and were damaged by the fall");
+
+                    if ((pstats.s_hpt -= roll(1, 6)) <= 0)
+                    {
+                        addmsg("!  The fall killed you.");
+                        endmsg();
+                        death(D_FALL);
+                        return(ch);
+                    }
+                }
+
+                addmsg("!");
+                endmsg();
+
+                if (off(player, ISCLEAR))
+                {
+                    if (on(player, ISHUH))
+                        lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION);
+                    else
+                    {
+                        light_fuse(FUSE_UNCONFUSE, 0, rnd(8) + HUHDURATION, AFTER);
+                        turn_on(player, ISHUH);
+                    }
+                }
+                else
+                    msg("You feel dizzy for a moment, but it quickly passes.");
+            }
+            else
+            {
+                if (can_see)
+                    msg("The %s fell into a trap!", mname);
+
+                if (on(*th, ISFAMILIAR))
+					turn_off(player, HASFAMILIAR);
+
+                killed(NULL, mitem, NOMESSAGE, NOPOINTS);
+            }
+            break;
+
+        case FIRETRAP:
+        {
+            struct room *rp = roomin(hero);
+
+            if (is_player)
+            {
+                if (is_wearing(R_FIRERESIST) || on(player, NOFIRE))
+                    msg("You pass through the flames unharmed.");
+                else
+                {
+                    addmsg("You are burned by the flames");
+
+                    if ((pstats.s_hpt -= roll(pstats.s_lvl, 2)) <= 0)
+                    {
+                        addmsg("!  The flames killed you.");
+                        endmsg();
+                        death(D_FIRE);
+                        return(ch);
+                    }
+
+                    addmsg("!");
+
+                    endmsg();
+                }
+            }
+            else
+            {
+                if (on(*th, CANBBURN))
+                {
+                    if (can_see)
+                        msg("The %s is burned to death by the flames.", mname);
+
+                    killed(NULL, mitem, NOMESSAGE, NOPOINTS);
+                }
+                else if (on(*th, NOFIRE))
+                {
+                    if (can_see)
+                        msg("The %s passes through the flames unharmed.", mname);
+                }
+                else
+                {
+                    if (can_see)
+                        msg("The %s is burned by the flames.", mname);
+
+                    if ((th->t_stats.s_hpt -= roll(th->t_stats.s_lvl, 3)) < 0)
+                    {
+                        if (can_see)
+                            msg("The %s is burned to death by the flames.", mname);
+
+                        if (on(*th, ISFAMILIAR))
+						    turn_off(player, HASFAMILIAR);
+							
+						killed(NULL, mitem, NOMESSAGE, NOPOINTS);
+                    }
+                    else if (th->t_stats.s_intel < rnd(20))
+                    {
+                        if (can_see)
+                            msg("The %s turns and runs away in fear.", mname);
+
+                        turn_on(*th, ISFLEE);
+                    }
+                }
+            }
+
+            if (rp != NULL)
+            {
+                rp->r_flags &= ~ISDARK;
+                light(&hero);
+            }
+        }
+        break;
+
+        case POISONTRAP:
+            if (is_player)
+            {
+                msg("You fall into a pool of poison.");
+
+                if (rnd(4) > 0)
+                {
+                    msg("You swallow some of the liquid and feel very sick.");
+                    pstats.s_hpt -= pstats.s_hpt / 3;
+
+                    if (player.t_ctype != C_PALADIN
+                        && !(player.t_ctype == C_NINJA &&
+                        pstats.s_lvl > 12)
+                            && !is_wearing(R_SUSABILITY))
+                        chg_str(-2, FALSE, FALSE);
+                }
+                else
+                    msg("The stuff tastes horrible.");
+            }
+            else
+            {
+                if (can_see)
+                    msg("The %s falls into the pool of poison.", mname);
+
+                if (rnd(4) > 0 && off(*th, ISUNDEAD))
+                    if (th->t_stats.s_hpt *= 2.0 / 3.0 < 0)
+					{
+					    if (can_see)
+						    msg("The %s dies from the poison.", mname);
+						
+						if (on(*th, ISFAMILIAR))
+						    turn_off(player, HASFAMILIAR);
+							
+						killed(NULL, mitem, NOMESSAGE, NOPOINTS);
+					}
+            }
+            break;
+
+        case LAIR:
+            if (is_player)
+            {
+                msg("You found a monster lair!");
+                mpos = 0;
+                new_level(THRONE,0);
+            }
+            else
+            {
+                if (can_see)
+                    msg("The %s fell into a trap!", mname);
+
+                if (on(*th, ISFAMILIAR))
+				    turn_off(player, HASFAMILIAR);
+
+                killed(NULL, mitem, NOMESSAGE, NOPOINTS);
+            }
+            break;
+
+        case RUSTTRAP:
+            if (is_player)
+            {
+                msg("You are splashed by water.");
+
+                if (cur_armor != NULL &&
+                    cur_armor->o_which != SOFT_LEATHER &&
+                    cur_armor->o_which != HEAVY_LEATHER &&
+                    cur_armor->o_which != CUIRBOLILLI &&
+                    cur_armor->o_which != PADDED_ARMOR &&
+                    cur_armor->o_which != CRYSTAL_ARMOR &&
+                    cur_armor->o_which != MITHRIL &&
+                    !(cur_armor->o_flags & ISPROT) &&
+                    cur_armor->o_ac < pstats.s_arm + 1)
+                {
+                    msg("Your armor weakens!");
+                    cur_armor->o_ac++;
+                }
+                else if (cur_armor != NULL && (cur_armor->o_flags & ISPROT))
+                    msg("The rust vanishes instantly!");
+            }
+            else
+            {
+                if (can_see)
+                    msg("The %s is splashed by water.", mname);
+            }
+    }
+
+    return(ch);
+}
+
+/*
+    dip_it()
+        Dip an object into a magic pool
+*/
+
+void
+dip_it(void)
+{
+    struct linked_list  *what;
+    struct object   *ob;
+    struct trap *tp;
+    int wh, i;
+
+    tp = trap_at(hero.y, hero.x);
+
+    if (tp == NULL || !(tp->tr_type == POOL || tp->tr_type == POISONTRAP))
+    {
+        msg("I see no pools here.");
+        return;
+    }
+
+    if (tp->tr_flags & ISGONE)
+    {
+        msg("This %s appears to have been used once already.",
+         (tp->tr_type == POOL ? "shimmering pool" : "poison pool"));
+        return;
+    }
+
+    if ((what = get_item("dip", 0)) == NULL)
+    {
+        msg("");
+        after = FALSE;
+        return;
+    }
+
+    ob = OBJPTR(what);
+    mpos = 0;
+
+    if (ob == cur_armor)
+    {
+        msg("You have to take off your armor before you can dip it.");
+        return;
+    }
+    else if (ob == cur_ring[LEFT_1] || ob == cur_ring[LEFT_2] ||
+         ob == cur_ring[LEFT_3] || ob == cur_ring[LEFT_4] ||
+         ob == cur_ring[RIGHT_1] || ob == cur_ring[RIGHT_2] ||
+         ob == cur_ring[RIGHT_3] || ob == cur_ring[RIGHT_4])
+    {
+        msg("You have to take that ring off before you can dip it.");
+        return;
+    }
+
+    tp->tr_flags |= ISGONE;
+
+    if (ob != NULL && tp->tr_type == POOL)
+    {
+        wh = ob->o_which;
+        ob->o_flags |= ISKNOW;
+        i = rnd(100);
+
+        switch (ob->o_type)
+        {
+            case WEAPON:
+                if (i < 50)
+                {
+                    if (!(ob->o_flags & ISCURSED))
+                    {
+                        ob->o_hplus += 1;
+                        ob->o_dplus += 1;
+                    }
+                    else
+                    {
+                        ob->o_hplus = rnd(2);
+                        ob->o_dplus = rnd(2);
+                    }
+
+                    ob->o_flags &= ~ISCURSED;
+                    msg("The %s glows blue for a moment.", weaps[wh].w_name);
+                }
+                else if (i < 70)    /* curse weapon here */
+                {
+                    if (!(ob->o_flags & ISCURSED))
+                    {
+                        ob->o_hplus = -(rnd(2) + 1);
+                        ob->o_dplus = -(rnd(2) + 1);
+                    }
+                    else    /* if already cursed */
+                    {
+                        ob->o_hplus--;
+                        ob->o_dplus--;
+                    }
+
+                    ob->o_flags |= ISCURSED;
+                    msg("The %s glows red for a moment.", weaps[wh].w_name);
+                }
+                else
+                    msg("Nothing seems to happen.");
+                break;
+
+            case ARMOR:
+
+                if (i < 50)     /* enchant armor */
+                {
+                    if (!(ob->o_flags & ISCURSED))
+                        ob->o_ac -= rnd(2) + 1;
+                    else
+                        ob->o_ac = -rnd(3) + armors[wh].a_class;
+
+                    ob->o_flags &= ~ISCURSED;
+                    msg("The %s glows blue for a moment.", armors[wh].a_name);
+                }
+                else if (i < 75)   /* curse armor */
+                {
+                    if (!(ob->o_flags & ISCURSED))
+                        ob->o_ac = rnd(3) + armors[wh].a_class;
+                    else
+                        ob->o_ac += rnd(2) + 1;
+
+                    ob->o_flags |= ISCURSED;
+                    msg("The %s glows red for a moment.", armors[wh].a_name);
+                }
+                else
+                    msg("Nothing seems to happen");
+                break;
+
+            case STICK:
+            {
+                int j;
+
+                j = rnd(8) + 1;
+
+                if (i < 50)     /* add charges */
+                {
+                    ob->o_charges += j;
+                    know_items[TYP_STICK][wh] = TRUE;
+
+                    if (ob->o_flags & ISCURSED)
+                        ob->o_flags &= ~ISCURSED;
+
+                    msg("The %s %s glows blue for a moment.",
+                        ws_made[wh], ws_type[wh]);
+                }
+                else if (i < 65)    /* remove charges */
+                {
+                    if ((ob->o_charges -= i) < 0)
+                        ob->o_charges = 0;
+
+                    know_items[TYP_STICK][wh] = TRUE;
+
+                    if (ob->o_flags & ISBLESSED)
+                        ob->o_flags &= ~ISBLESSED;
+                    else
+                        ob->o_flags |= ISCURSED;
+
+                    msg("The %s %s glows red for a moment.",
+                        ws_made[wh], ws_type[wh]);
+                }
+                else
+                    msg("Nothing seems to happen.");
+            }
+            break;
+
+            case SCROLL:
+
+                know_items[TYP_SCROLL][wh] = TRUE;
+                msg("The '%s' scroll unfurls.", s_names[wh]);
+                break;
+
+            case POTION:
+
+                know_items[TYP_POTION][wh] = TRUE;
+                msg("The %s potion bubbles for a moment.", p_colors[wh]);
+                break;
+
+            case RING:
+                if (i < 50)     /* enchant ring */
+                {
+                    if (!(ob->o_flags & ISCURSED))
+                        ob->o_ac += rnd(2) + 1;
+                    else
+                        ob->o_ac = rnd(2) + 1;
+
+                    ob->o_flags &= ~ISCURSED;
+                }
+                else if (i < 80)    /* curse ring */
+                {
+                    if (!(ob->o_flags & ISCURSED))
+                        ob->o_ac = -(rnd(2) + 1);
+                    else
+                        ob->o_ac -= (rnd(2) + 1);
+
+                    ob->o_flags |= ISCURSED;
+                }
+
+                know_items[TYP_RING][wh] = TRUE;
+                msg("The %s ring vibrates for a moment.", r_stones[wh]);
+                break;
+
+            default:
+                msg("The pool bubbles for a moment.");
+        }
+    }
+    else if (ob != NULL && tp->tr_type == POISONTRAP)
+    {
+        if ((player.t_ctype == C_PALADIN) ||
+            (player.t_ctype == C_CLERIC && rnd(2)))
+        {
+            msg("Trying to use poison is evil.");
+            luck += 2;
+        }
+
+        if (ob->o_type != WEAPON || rnd(10) > 0)
+            msg("Nothing seems to happen.");
+        else
+        {
+            msg("Your %s is covered with a black sticky liquid.",
+                weaps[ob->o_which].w_name);
+            ob->o_flags |= ISPOISON;
+        }
+    }
+    else
+        msg("Nothing seems to happen.");
+}
+
+/*
+    trap_at()
+        find the trap at (y,x) on screen.
+*/
+
+struct trap *
+trap_at(int y, int x)
+{
+    struct trap *tp, *ep;
+
+    ep = &traps[ntraps];
+
+    for (tp = traps; tp < ep; tp++)
+        if (tp->tr_pos.y == y && tp->tr_pos.x == x)
+            break;
+
+    if (tp == ep)
+    {
+        debug((sprintf(prbuf, "Trap at %d,%d not in array", y, x), prbuf));
+        tp = NULL;
+    }
+
+    return(tp);
+}
+
+/*
+    set_trap()
+        set a trap at (y, x) on screen.
+*/
+
+void
+set_trap(struct thing *tp, int y, int x)
+{
+    int is_player = (tp == &player);
+    int selection = rnd(7) + 1;
+    char  ch = 0, och;
+    int  thief_bonus = 0;
+
+    switch(och = CCHAR( mvinch(y, x) ))
+    {
+        case WALL:
+        case FLOOR:
+        case PASSAGE:
+            break;
+        default:
+            msg("The trap failed!");
+            return;
+    }
+
+    if (is_player && (player.t_ctype == C_THIEF ||
+        player.t_ctype == C_NINJA))
+        thief_bonus = 10;
+
+    if (ntraps >= 2 * MAXTRAPS || ++trap_tries >= MAXTRPTRY ||
+        rnd(60) >= (tp->t_stats.s_dext + tp->t_stats.s_lvl / 2 +
+        thief_bonus))
+    {
+        if (is_player)
+            msg("The trap failed!");
+
+        return;
+    }
+
+    /* Set up for redraw */
+
+    clearok(cw, TRUE);
+    touchwin(cw);
+
+    if (is_player)
+    {
+        add_line("[1] Trap Door");
+        add_line("[2] Bear Trap");
+        add_line("[3] Sleep Trap");
+        add_line("[4] Arrow Trap");
+        add_line("[5] Teleport Trap");
+        add_line("[6] Dart Trap");
+        add_line("[7] Fire Trap");
+        end_line();
+        msg("Which trap? ");
+
+        selection = (short) ((readchar() & 0177) - '0');
+
+        while (selection < 1 || selection > 7)
+        {
+            if (selection == (short) ESCAPE - (short) '0')
+            {
+                after = FALSE;
+                return;
+            }
+
+            msg("");
+            msg("Please enter a selection between 1 and 7:  ");
+            selection = (short) ((readchar() & 0177) - '0');
+        }
+    }
+
+    switch (selection)
+    {
+        case 1: ch = TRAPDOOR; break;
+        case 2: ch = BEARTRAP; break;
+        case 3: ch = SLEEPTRAP;break;
+        case 4: ch = ARROWTRAP;break;
+        case 5: ch = TELTRAP;   break;
+        case 6: ch = DARTTRAP;  break;
+        case 7: ch = FIRETRAP;  break;
+    }
+
+    mvaddch(y, x, ch);
+
+    traps[ntraps].tr_type = ch;
+    traps[ntraps].tr_flags = ISTHIEFSET;
+    traps[ntraps].tr_show = och;
+    traps[ntraps].tr_pos.y = y;
+    traps[ntraps++].tr_pos.x = x;
+}
+
+
+/*
+    rndmove()
+        move in a random direction if the monster/person is confused
+*/
+
+coord
+rndmove(struct thing *who)
+{
+    int x, y;
+    int ex, ey, nopen = 0;
+    coord    ret;    /* what we will be returning */
+    coord    dest;
+
+    ret = who->t_pos;
+
+    /*
+     * Now go through the spaces surrounding the player and set that
+     * place in the array to true if the space can be moved into
+     */
+
+    ey = ret.y + 1;
+    ex = ret.x + 1;
+
+    for (y = who->t_pos.y - 1; y <= ey; y++)
+        if (y > 0 && y < LINES - 2)
+            for (x = who->t_pos.x - 1; x <= ex; x++)
+            {
+                if (x < 0 || x >= COLS)
+                    continue;
+
+                if (step_ok(y, x, NOMONST, who))
+                {
+                    dest.y = y;
+                    dest.x = x;
+
+                    if (!diag_ok(&who->t_pos, &dest, who))
+                        continue;
+
+                    if (rnd(++nopen) == 0)
+                        ret = dest;
+                }
+            }
+
+    return(ret);
+}
+
+/*
+    isatrap()
+        Returns TRUE if this character is some kind of trap
+*/
+
+int
+isatrap(int ch)
+{
+    switch(ch)
+    {
+        case DARTTRAP:
+        case TELTRAP:
+        case TRAPDOOR:
+        case ARROWTRAP:
+        case SLEEPTRAP:
+        case POOL:
+        case MAZETRAP:
+        case FIRETRAP:
+        case POISONTRAP:
+        case LAIR:
+        case RUSTTRAP:
+        case BEARTRAP:
+            return (TRUE);
+        default:
+            return (FALSE);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/newlvl.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,676 @@
+/*
+    newlvl.c - Dig and draw a new level
+
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+/*
+    Notes
+
+        Add treasure room code from Rogue 5.2,
+        put in #ifdef 0/#endif bracket at end of code
+*/
+
+#include "rogue.h"
+
+/*
+    new_level()
+        Dig and draw a new level
+*/
+
+void
+new_level(LEVTYPE ltype, int special)
+{
+    int rm, i, cnt;
+    struct linked_list  *item, *nitem;
+    struct thing    *tp;
+    struct linked_list  *fpack = NULL;
+    int     going_down = TRUE;
+    coord   stairs;
+
+    /* Start player off right */
+
+    turn_off(player, ISHELD);
+    turn_off(player, ISFLEE);
+    extinguish_fuse(FUSE_SUFFOCATE);
+    hold_count = 0;
+    trap_tries = 0;
+    no_food++;
+
+    if (level >= max_level)
+        max_level = level;
+    else
+        going_down = FALSE;
+
+    /* Free up the monsters on the last level */
+
+    if (fam_ptr != NULL)    /* save what familiar is carrying */
+    {
+        fpack = (THINGPTR(fam_ptr))->t_pack;
+        (THINGPTR(fam_ptr))->t_pack = NULL;
+        fam_ptr = NULL; /* just in case */
+    }
+
+    for (i = 1; i <= mons_summoned; i++)
+        extinguish_fuse(FUSE_UNSUMMON);
+
+    mons_summoned = 0;
+
+    for (item = mlist; item != NULL; item = nitem)
+    {
+        tp = THINGPTR(item);
+        nitem = next(item);
+
+        if (on(*tp, ISUNIQUE))  /* Put alive UNIQUE on next level */
+            monsters[tp->t_index].m_normal = TRUE;
+
+        killed(NULL, item, NOMESSAGE, NOPOINTS);
+    }
+
+    free_list(lvl_obj); /* Free up previous objects (if any) */
+
+    wclear(cw);
+    wclear(mw);
+    clear();
+    refresh();
+    levtype = ltype;
+
+    switch (ltype)
+    {
+        case THRONE:
+            do_throne(special);    /* do monster throne stuff */
+            break;
+
+        case MAZELEV:
+            do_maze();
+            break;
+
+        case POSTLEV:
+			do_post();
+			levtype = ltype = NORMLEV;
+			level++;
+			
+        default:
+            do_rooms(); /* Draw rooms */
+            do_passages();  /* Draw passages */
+			break;
+    }
+
+    /* Place the staircase down. */
+
+    cnt = 0;
+
+    do
+    {
+        rm = rnd_room();
+        rnd_pos(&rooms[rm], &stairs);
+    }
+    while (!(mvinch(stairs.y, stairs.x) == FLOOR || cnt++ > 5000));
+
+    addch(STAIRS);
+
+    put_things(ltype);  /* Place objects (if any) */
+
+    if (has_artifact && level == 1)
+        create_lucifer(&stairs);
+
+    /* Place the traps */
+
+    ntraps = 0;     /* No traps yet */
+
+    if (levtype == NORMLEV)
+    {
+        if (rnd(10) < level)
+        {
+            char    ch = 0;
+
+            i = ntraps = min(MAXTRAPS, rnd(level / 2) + 1);
+
+            /* maybe a lair */
+
+            if (level > 35 && ltype == NORMLEV && rnd(wizard ? 3 : 10) == 0)
+            {
+                cnt = 0;
+
+                do
+                {
+                    rm = rnd_room();
+
+                    if (rooms[rm].r_flags & ISTREAS)
+                        continue;
+
+                    rnd_pos(&rooms[rm], &stairs);
+                }
+                while (!(mvinch(stairs.y, stairs.x) == FLOOR || cnt++ > 5000));
+
+                addch(LAIR);
+                i--;
+                traps[i].tr_flags = 0;
+                traps[i].tr_type = LAIR;
+                traps[i].tr_show = FLOOR;
+                traps[i].tr_pos = stairs;
+            }
+
+            while (i--)
+            {
+                cnt = 0;
+
+                do
+                {
+                    rm = rnd_room();
+
+                    if (rooms[rm].r_flags & ISTREAS)
+                        continue;
+
+                    rnd_pos(&rooms[rm], &stairs);
+                }
+                while (!(mvinch(stairs.y, stairs.x) == FLOOR || cnt++ > 5000));
+
+                traps[i].tr_flags = 0;
+
+                switch (rnd(11))
+                {
+                    case 0:
+                        ch = TRAPDOOR;
+                        break;
+
+                    case 1:
+                        ch = BEARTRAP;
+                        break;
+
+                    case 2:
+                        ch = SLEEPTRAP;
+                        break;
+
+                    case 3:
+                        ch = ARROWTRAP;
+                        break;
+
+                    case 4:
+                        ch = TELTRAP;
+                        break;
+
+                    case 5:
+                        ch = DARTTRAP;
+                        break;
+
+                    case 6:
+                        ch = POOL;
+
+                        if (rnd(10))
+                            traps[i].tr_flags = ISFOUND;
+
+                        break;
+
+                    case 7:
+                        ch = MAZETRAP;
+                        break;
+
+                    case 8:
+                        ch = FIRETRAP;
+                        break;
+
+                    case 9:
+                        ch = POISONTRAP;
+                        break;
+
+                    case 10:
+                        ch = RUSTTRAP;
+                        break;
+                }
+
+                addch(ch);
+                traps[i].tr_type = ch;
+                traps[i].tr_show = FLOOR;
+                traps[i].tr_pos = stairs;
+            }
+        }
+    }
+
+    do              /* Position hero */
+    {
+        rm = rnd_room();
+
+        if (levtype != THRONE && (rooms[rm].r_flags & ISTREAS))
+            continue;
+
+        rnd_pos(&rooms[rm], &hero);
+    }
+    while(!(winat(hero.y, hero.x) == FLOOR &&
+           DISTANCE(hero, stairs) > 16));
+
+    oldrp = &rooms[rm]; /* Set the current room */
+    player.t_oldpos = player.t_pos; /* Set the current position */
+
+    if (levtype != POSTLEV && levtype != THRONE)
+    {
+        if (on(player, BLESSMAP) && rnd(5) == 0)
+        {
+            read_scroll(&player, S_MAP, ISNORMAL);
+
+            if (rnd(3) == 0)
+                turn_off(player, BLESSMAP);
+        }
+
+        if (player.t_ctype == C_THIEF || on(player, BLESSGOLD) && rnd(5) == 0)
+        {
+            read_scroll(&player, S_GFIND, ISNORMAL);
+
+            if (rnd(3) == 0)
+                turn_off(player, BLESSGOLD);
+        }
+
+        if (player.t_ctype == C_RANGER || on(player, BLESSFOOD) && rnd(5) == 0)
+        {
+            read_scroll(&player, S_FOODDET, ISNORMAL);
+
+            if (rnd(3) == 0)
+                turn_off(player, BLESSFOOD);
+        }
+
+        if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_ILLUSION ||
+            on(player, BLESSMAGIC) && rnd(5) == 0)
+        {
+            quaff(&player, P_TREASDET, ISNORMAL);
+
+            if (rnd(3) == 0)
+                turn_off(player, BLESSMAGIC);
+        }
+
+        if (player.t_ctype == C_DRUID || on(player, BLESSMONS) && rnd(5) == 0)
+        {
+            quaff(&player, P_MONSTDET, ISNORMAL);
+
+            if (rnd(3) == 0)
+                turn_off(player, BLESSMONS);
+        }
+        else if (player.t_ctype == C_CLERIC ||
+            player.t_ctype == C_PALADIN || is_wearing(R_PIETY))
+            undead_sense();
+    }
+
+    if (is_wearing(R_AGGR))
+        aggravate();
+
+    if (is_wearing(R_ADORNMENT) ||
+        cur_armor != NULL && cur_armor->o_which == MITHRIL)
+    {
+        int greed = FALSE;
+
+        for (item = mlist; item != NULL; item = next(item))
+        {
+            tp = THINGPTR(item);
+
+            if (on(*tp, ISGREED))
+            {
+                turn_on(*tp, ISRUN);
+                turn_on(*tp, ISMEAN);
+                tp->t_ischasing = TRUE;
+                tp->t_chasee = &player;
+                greed = TRUE;
+            }
+        }
+
+        if (greed)
+            msg("An uneasy feeling comes over you.");
+    }
+
+    if (is_carrying(TR_PALANTIR))   /* Palantir shows all */
+    {
+        msg("The Palantir reveals all!");
+
+        overlay(stdscr, cw);    /* Wizard mode 'f' command */
+        overlay(mw, cw);        /* followed by 'm' command */
+    }
+
+    if (is_carrying(TR_PHIAL))  /* Phial lights your way */
+    {
+        if (!is_carrying(TR_PALANTIR))
+            msg("The Phial banishes the darkness!");
+
+        for (i = 0; i < MAXROOMS; i++)
+            rooms[i].r_flags &= ~ISDARK;
+    }
+
+    if (is_carrying(TR_AMULET)) /* Amulet describes the level */
+    {
+        level_eval();
+    }
+
+
+    wmove(cw, hero.y, hero.x);
+    waddch(cw, PLAYER);
+    light(&hero);
+
+    /* Summon familiar if player has one */
+
+    if (on(player, HASFAMILIAR))
+    {
+        summon_monster((short) fam_type, FAMILIAR, MESSAGE);
+
+        if (fam_ptr != NULL)    /* add old pack to new */
+        {
+            tp = THINGPTR(fam_ptr);
+
+            if (tp->t_pack == NULL)
+                tp->t_pack = fpack;
+            else if (fpack != NULL)
+            {
+                for (item = tp->t_pack; item->l_next != NULL;item = next(item))
+                    ;
+
+                item->l_next = fpack;
+                debug("new_level: l_prev = %p",item);
+                fpack->l_prev = item;
+            }
+        }
+        else
+            free_list(fpack);
+    }
+
+    mem_check(__FILE__,__LINE__);
+    status(TRUE);
+}
+
+/*
+    put_things()
+        put potions and scrolls on this level
+*/
+
+void
+put_things(LEVTYPE ltype)
+{
+    int i, rm, cnt;
+    struct linked_list  *item;
+    struct object   *cur;
+    int    got_unique = FALSE;
+    int length, width, maxobjects;
+    coord   tp;
+
+    /*
+     * Once you have found an artifact, the only way to get new stuff is
+     * go down into the dungeon.
+     */
+
+    if (has_artifact && level < max_level && ltype != THRONE)
+        return;
+
+    /*
+     * There is a chance that there is a treasure room on this level
+     * Increasing chance after level 10
+     */
+
+    if (ltype != MAZELEV && rnd(50) < level - 10)
+    {
+        int n, j;
+        struct room *rp;
+
+        /* Count the number of free spaces */
+        n = 0;      /* 0 tries */
+
+        do
+        {
+            rp = &rooms[rnd_room()];
+            width = rp->r_max.y - 2;
+            length = rp->r_max.x - 2;
+        }
+        while(!((width * length <= MAXTREAS) || (n++ > MAXROOMS * 4)));
+
+        /* Mark the room as a treasure room */
+
+        rp->r_flags |= ISTREAS;
+
+        /* Make all the doors secret doors */
+
+        for (n = 0; n < rp->r_nexits; n++)
+        {
+            move(rp->r_exit[n].y, rp->r_exit[n].x);
+            addch(SECRETDOOR);
+        }
+
+        /* Put in the monsters and treasures */
+
+        for (j = 1; j < rp->r_max.y - 1; j++)
+            for (n = 1; n < rp->r_max.x - 1; n++)
+            {
+                coord   trp;
+
+                trp.y = rp->r_pos.y + j;
+                trp.x = rp->r_pos.x + n;
+
+                /* Monsters */
+
+                if ((rnd(100) < (MAXTREAS * 100) /
+                    (width * length)) &&
+                    (mvwinch(mw, rp->r_pos.y + j,
+                    rp->r_pos.x + n) == ' '))
+                {
+                    struct thing    *th;
+
+                    /* Make a monster */
+
+                    item = new_item(sizeof *th);
+                    th = THINGPTR(item);
+
+                    /*
+                     * Put it there and aggravate it
+                     * (unless it can escape) only put
+                     * one UNIQUE per treasure room at
+                     * most
+                     */
+
+                    if (got_unique)
+                        new_monster(item, randmonster(NOWANDER, GRAB), &trp,
+                            NOMAXSTATS);
+                    else
+                    {
+                        new_monster(item, randmonster(NOWANDER, NOGRAB), &trp,
+                            NOMAXSTATS);
+
+                        if (on(*th, ISUNIQUE))
+                            got_unique = TRUE;
+                    }
+
+                    turn_off(*th, ISFRIENDLY);
+                    turn_on(*th, ISMEAN);
+
+                    if (off(*th, CANINWALL))
+                    {
+                        th->t_ischasing = TRUE;
+                        th->t_chasee = &player;
+                        turn_on(*th, ISRUN);
+                    }
+                }
+
+                /* Treasures */
+
+                if ((rnd(100) < (MAXTREAS * 100) /
+                    (width * length)) &&
+                    (mvinch(rp->r_pos.y + j,
+                    rp->r_pos.x + n) == FLOOR))
+                {
+                    item = new_thing();
+                    cur = OBJPTR(item);
+                    cur->o_pos = trp;
+                    add_obj(item, trp.y, trp.x);
+                }
+            }
+    }
+
+    /* Do MAXOBJ attempts to put things on a level, maybe  */
+
+    maxobjects = (ltype == THRONE) ? rnd(3 * MAXOBJ) + 35 : MAXOBJ;
+
+    for (i = 0; i < maxobjects; i++)
+        if (rnd(100) < 40 || ltype == THRONE)
+        {
+            /* Pick a new object and link it in the list */
+
+            item = new_thing();
+            cur = OBJPTR(item);
+
+            /* Put it somewhere */
+
+            cnt = 0;
+
+            do
+            {
+                rm = rnd_room();
+                rnd_pos(&rooms[rm], &tp);
+            }
+            while(!(winat(tp.y, tp.x) == FLOOR || cnt++ > 500));
+
+            cur->o_pos = tp;
+            add_obj(item, tp.y, tp.x);
+        }
+
+    /*
+     * If he is really deep in the dungeon and he hasn't found an
+     * artifact yet, put it somewhere on the ground
+     */
+
+    if (make_artifact())
+    {
+        item = new_item(sizeof *cur);
+        cur = OBJPTR(item);
+        new_artifact(-1, cur);
+        cnt = 0;
+
+        do
+        {
+            rm = rnd_room();
+            rnd_pos(&rooms[rm], &tp);
+        }
+        while(!(winat(tp.y, tp.x) == FLOOR || cnt++ > 500));
+
+        cur->o_pos = tp;
+        add_obj(item, tp.y, tp.x);
+    }
+}
+
+/*
+    do_throne()
+        Put a monster's throne room and monsters on the screen
+*/
+
+void
+do_throne(int special)
+{
+    coord   mp;
+    int save_level;
+    int i;
+    struct room *rp;
+    struct thing    *tp;
+    struct linked_list  *item;
+    int throne_monster;
+
+    for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
+    {
+        rp->r_nexits = 0;   /* no exits */
+        rp->r_flags = ISGONE;   /* kill all rooms */
+    }
+
+    rp = &rooms[0];     /* point to only room */
+    rp->r_flags = 0;    /* this room NOT gone */
+    rp->r_max.x = 40;
+    rp->r_max.y = 10;   /* 10 * 40 room */
+    rp->r_pos.x = (COLS - rp->r_max.x) / 2; /* center horizontal */
+    rp->r_pos.y = 3;    /* 2nd line */
+    draw_room(rp);      /* draw the only room */
+
+    save_level = level;
+    level = max(2 * level, level + roll(4, 6));
+
+    if (special == 0)    /* Who has he offended? */
+        do
+            throne_monster = nummonst - roll(1, NUMSUMMON);
+        while(!monsters[throne_monster].m_normal);
+    else
+        throne_monster = special;
+
+    /* Create summoning monster */
+
+    item = new_item(sizeof *tp);
+
+    tp = THINGPTR(item);
+
+    do
+    {
+        rnd_pos(rp, &mp);
+    }
+    while(mvwinch(stdscr, mp.y, mp.x) != FLOOR);
+
+    new_monster(item, throne_monster, &mp, MAXSTATS);
+    turn_on(*tp, CANSEE);
+    turn_off(*tp, ISFRIENDLY);
+
+    if (on(*tp, CANSUMMON)) /* summon his helpers */
+        summon_help(tp, FORCE);
+    else
+    {
+        for (i = roll(4, 10); i >= 0; i--)
+        {
+            item = new_item(sizeof *tp);
+            tp = THINGPTR(item);
+
+            do
+            {
+                rnd_pos(rp, &mp);
+            }
+            while(mvwinch(stdscr, mp.y, mp.x) != FLOOR);
+
+            new_monster(item, randmonster(NOWANDER, NOGRAB), &mp, MAXSTATS);
+            turn_on(*tp, CANSEE);
+            turn_off(*tp, ISFRIENDLY);
+        }
+    }
+
+    level = save_level + roll(2, 3);    /* send the hero down */
+    aggravate();
+}
+
+/*
+    create_lucifer()
+        special surprise on the way back up create Lucifer
+        with more than the usual god abilities
+*/
+
+void
+create_lucifer(coord *stairs)
+{
+    struct linked_list  *item = new_item(sizeof(struct thing));
+    struct thing    *tp = THINGPTR(item);
+
+    new_monster(item, nummonst + 1, stairs, MAXSTATS);
+    turn_on(*tp, CANINWALL);
+    turn_on(*tp, CANHUH);
+    turn_on(*tp, CANBLINK);
+    turn_on(*tp, CANSNORE);
+    turn_on(*tp, CANDISEASE);
+    turn_on(*tp, NOCOLD);
+    turn_on(*tp, TOUCHFEAR);
+    turn_on(*tp, BMAGICHIT);
+    turn_on(*tp, NOFIRE);
+    turn_on(*tp, NOBOLT);
+    turn_on(*tp, CANBLIND);
+    turn_on(*tp, CANINFEST);
+    turn_on(*tp, CANSMELL);
+    turn_on(*tp, CANPARALYZE);
+    turn_on(*tp, CANSTINK);
+    turn_on(*tp, CANCHILL);
+    turn_on(*tp, CANFRIGHTEN);
+    turn_on(*tp, CANHOLD);
+    turn_on(*tp, CANBRANDOM);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/options.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,519 @@
+/*
+    options.c - This file has all the code for the option command
+        
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <string.h>
+#include <ctype.h>
+#include "rogue.h"
+
+#define NUM_OPTS    (sizeof optlist / sizeof (OPTION))
+#define EQSTR(a, b, c)  (strncmp(a, b, c) == 0)
+
+/* description of an option and what to do with it */
+static OPTION optlist[] =
+{
+{"jump","Show position only at end of run (jump): ", &jump,put_bool,get_bool},
+{"inven","Style of inventories (inven): ", &inv_type, put_inv, get_inv},
+{"askme","Ask me about unidentified things (askme): ",&askme,put_bool,get_bool},
+{"doorstop","Stop running when adjacent (doorstop): ",&doorstop,put_bool,get_bool},
+{"name", "Name (name): ",               &whoami, put_str, get_str},
+{"fruit", "Fruit (fruit): ",            &fruit, put_str, get_str},
+{"file", "Save file (file): ",          &file_name, put_str, get_str},
+{"score", "Score file (score): ",       &score_file, put_str, get_str},
+{"class", "Character class (class): ",&char_type, put_abil, get_abil}
+};
+
+/*
+    option()
+        print and then set options from the terminal
+*/
+
+void
+option(void)
+{
+    OPTION  *op;
+    int retval;
+
+    wclear(hw);
+    touchwin(hw);
+
+    /* Display current values of options */
+
+    for (op = optlist; op < &optlist[NUM_OPTS]; op++)
+    {
+        waddstr(hw, op->o_prompt);
+        (*op->o_putfunc)(&op->o_opt, hw);
+        waddch(hw, '\n');
+    }
+
+    /* Set values */
+
+    wmove(hw, 0, 0);
+
+    for (op = optlist; op < &optlist[NUM_OPTS]; op++)
+    {
+        waddstr(hw, op->o_prompt);
+
+	retval = (*op->o_getfunc)(&op->o_opt, hw);
+
+        if (retval)
+            if (retval == QUIT)
+                break;
+            else if (op > optlist)      /* MINUS */
+            {
+                wmove(hw, (int)(op - optlist) - 1, 0);
+                op -= 2;
+            }
+            else    /* trying to back up beyond the top */
+            {
+                putchar('\007');
+                wmove(hw, 0, 0);
+                op--;
+            }
+    }
+
+    /* Switch back to original screen */
+
+    mvwaddstr(hw, LINES - 1, 0, spacemsg);
+    wrefresh(hw);
+    wait_for(' ');
+    clearok(cw, TRUE);
+    touchwin(cw);
+}
+
+/*
+    put_bool()
+        put out a boolean
+*/
+
+void
+put_bool(opt_arg *opt, WINDOW *win)
+{
+    waddstr(win, *opt->iarg ? "True" : "False");
+}
+
+/*
+    put_str()
+        put out a string
+*/
+
+void
+put_str(opt_arg *opt, WINDOW *win)
+{
+    waddstr(win, opt->str);
+}
+
+/*
+    put_abil()
+        print the character type
+*/
+
+void
+put_abil(opt_arg *opt, WINDOW *win)
+{
+    char    *abil;
+
+    switch(*opt->iarg)
+    {
+        case C_FIGHTER:
+            abil = "Fighter";
+            break;
+        case C_MAGICIAN:
+            abil = "Magic User";
+            break;
+        case C_CLERIC:
+            abil = "Cleric";
+            break;
+        case C_THIEF:
+            abil = "Thief";
+            break;
+        case C_PALADIN:
+            abil = "Paladin";
+            break;
+        case C_RANGER:
+            abil = "Ranger";
+            break;
+        case C_ILLUSION:
+            abil = "Illusionist";
+            break;
+        case C_ASSASIN:
+            abil = "Assasin";
+            break;
+        case C_NINJA:
+            abil = "Ninja";
+            break;
+        case C_DRUID:
+            abil = "Druid";
+            break;
+        default:
+            abil = "(unknown)";
+    }
+    waddstr(win, abil);
+}
+
+
+/*
+    get_bool()
+        allow changing a boolean option and print it out
+*/
+
+int
+get_bool(opt_arg *opt, WINDOW *win)
+{
+    int oy, ox;
+    int op_bad;
+
+    op_bad = TRUE;
+    getyx(win, oy, ox);
+    waddstr(win, *opt->iarg ? "True" : "False");
+
+    while(op_bad)
+    {
+        wmove(win, oy, ox);
+        wrefresh(win);
+
+        switch (readcharw(win))
+        {
+            case 't':
+            case 'T':
+                *opt->iarg = TRUE;
+                op_bad = FALSE;
+                break;
+
+            case 'f':
+            case 'F':
+                *opt->iarg = FALSE;
+                op_bad = FALSE;
+                break;
+
+            case '\n':
+            case '\r':
+                op_bad = FALSE;
+                break;
+
+            case '\033':
+            case '\007':
+                return QUIT;
+
+            case '-':
+                return MINUS;
+
+            default:
+                mvwaddstr(win, oy, ox + 10, "(T or F)");
+        }
+    }
+
+    wmove(win, oy, ox);
+    wclrtoeol(win);
+    waddstr(win, *opt->iarg ? "True" : "False");
+    waddch(win, '\n');
+
+    return(NORM);
+}
+
+/*
+    get_str()
+        set a string option
+*/
+
+int
+get_str(opt_arg *opt, WINDOW *win)
+{
+    return( get_string(opt->str, win) );
+}
+
+/*
+    get_abil()
+        The ability field is read-only
+*/
+
+int
+get_abil(opt_arg *opt, WINDOW *win)
+{
+    int oy, ox, ny, nx;
+    int op_bad;
+
+    op_bad = TRUE;
+    getyx(win, oy, ox);
+    put_abil(opt, win);
+    getyx(win, ny, nx);
+
+    while(op_bad)
+    {
+        wmove(win, oy, ox);
+        wrefresh(win);
+
+        switch(readcharw(win))
+        {
+            case '\n':
+            case '\r':
+                op_bad = FALSE;
+                break;
+
+            case '\033':
+            case '\007':
+                return(QUIT);
+
+            case '-':
+                return(MINUS);
+
+            default:
+                mvwaddstr(win, ny, nx + 5, "(no change allowed)");
+        }
+    }
+
+    wmove(win, ny, nx + 5);
+    wclrtoeol(win);
+    wmove(win, ny, nx);
+    waddch(win, '\n');
+
+    return(NORM);
+}
+
+
+/*
+    parse_opts()
+        parse options from string, usually taken from the environment. the
+        string is a series of comma seperated values, with booleans being
+        stated as "name" (true) or "noname" (false), and strings being
+        "name=....", with the string being defined up to a comma or the
+        end of the entire option string.
+ */
+
+void
+parse_opts(char *str)
+{
+    char    *sp;
+    const OPTION  *op;
+    size_t len;
+
+    while (*str)
+    {
+        for (sp = str; isalpha(*sp); sp++)
+            continue;
+
+        len = sp - str;
+
+        /* Look it up and deal with it */
+
+        for (op = optlist; op < &optlist[NUM_OPTS]; op++)
+            if (EQSTR(str, op->o_name, len))
+            {
+                if (op->o_putfunc == put_bool)
+                    *op->o_opt.iarg = TRUE;
+                else    /* string option */
+                {
+                    char    *start;
+                    char    value[80];
+
+                    /* Skip to start of string value */
+
+                    for (str = sp + 1; *str == '='; str++)
+                        continue;
+
+                    start = (char *) value;
+
+                    /* Skip to end of string value */
+
+                    for (sp = str + 1; *sp && *sp != ','; sp++)
+                        continue;
+
+                    strncpy(start, str, sp - str);
+
+                    /* Put the value into the option field */
+
+                    if (op->o_putfunc != put_abil &&
+                        op->o_putfunc != put_inv)
+                        strcpy(op->o_opt.str, value);
+
+                    if (op->o_putfunc == put_inv)
+                    {
+                        int *opt = op->o_opt.iarg;
+
+                        len = strlen(value);
+
+                        if (isupper(value[0]))
+                            value[0] = (char) tolower(value[0]);
+                        if (EQSTR(value, "overwrite",len))
+                            *opt = INV_OVER;
+                        if (EQSTR(value, "slow", len))
+                            *opt = INV_SLOW;
+                        if (EQSTR(value, "clear", len))
+                            *opt = INV_CLEAR;
+                    }
+                    else if (*op->o_opt.iarg == -1)
+                    {
+                        int *opt = op->o_opt.iarg;
+
+                        len = strlen(value);
+
+                        if (isupper(value[0]))
+                            value[0] = (char) tolower(value[0]);
+                        if (EQSTR(value, "fighter", len))
+                            *opt = C_FIGHTER;
+                        else if (EQSTR(value, "magic", min(len, 5)))
+                            *opt = C_MAGICIAN;
+                        else if (EQSTR(value, "illus", min(len, 5)))
+                            *opt = C_ILLUSION;
+                        else if (EQSTR(value, "cleric", len))
+                            *opt = C_CLERIC;
+                        else if (EQSTR(value, "thief",  len))
+                            *opt = C_THIEF;
+                        else if (EQSTR(value, "paladin", len))
+                            *opt = C_PALADIN;
+                        else if (EQSTR(value, "ranger",  len))
+                            *opt = C_RANGER;
+                        else if (EQSTR(value, "assasin", len))
+                            *opt = C_ASSASIN;
+                        else if (EQSTR(value, "druid",   len))
+                            *opt = C_DRUID;
+                        else if (EQSTR(value, "ninja",   len))
+                            *opt = C_NINJA;
+                    }
+                }
+                break;
+            }
+            else if (op->o_putfunc == put_bool
+                 && EQSTR(str, "no", 2) &&
+                EQSTR(str + 2, op->o_name, len - 2))
+            {
+                *op->o_opt.iarg = FALSE;
+                break;
+            }
+
+        /* skip to start of next option name  */
+
+        while (*sp && !isalpha(*sp))
+            sp++;
+
+        str = sp;
+    }
+}
+
+/*
+    put_inv()
+        print the inventory type
+*/
+
+void
+put_inv(opt_arg *opt, WINDOW *win)
+{
+    char    *style;
+
+    switch(*opt->iarg)
+    {
+        case INV_OVER:
+            style = "Overwrite";
+            break;
+
+        case INV_SLOW:
+            style = "Slow";
+            break;
+
+        case INV_CLEAR:
+            style = "Clear Screen";
+            break;
+
+        default:
+            style = "(unknown)";
+    }
+
+    waddstr(win, style);
+}
+
+/*
+    get_inv()
+        The inventory field.
+*/
+
+int
+get_inv(opt_arg *opt, WINDOW *win)
+{
+    int oy, ox, ny, nx;
+    int op_bad;
+
+    op_bad = TRUE;
+    getyx(win, oy, ox);
+    put_inv(opt, win);
+    getyx(win, ny, nx);
+
+    while(op_bad)
+    {
+        wmove(win, oy, ox);
+        wrefresh(win);
+
+        switch(readcharw(win))
+        {
+            case '\n':
+            case '\r':
+                op_bad = FALSE;
+                break;
+
+            case '\033':
+            case '\007':
+                return(QUIT);
+
+            case '-':
+                return(MINUS);
+
+            case 'O':
+            case 'o':
+                *opt->iarg = INV_OVER;
+                op_bad = FALSE;
+                break;
+
+            case 'S':
+            case 's':
+                *opt->iarg = INV_SLOW;
+                op_bad = FALSE;
+                break;
+
+            case 'C':
+            case 'c':
+                *opt->iarg = INV_CLEAR;
+                op_bad = FALSE;
+                break;
+
+            default:
+                mvwaddstr(win, ny, nx + 5, "(Use: o, s, or c)");
+        }
+    }
+
+    wmove(win, oy, ox);
+    wclrtoeol(win);
+
+    switch(*opt->iarg)
+    {
+        case INV_SLOW:
+            waddstr(win, "Slow\n");
+            break;
+
+        case INV_CLEAR:
+            waddstr(win, "Clear Screen\n");
+            break;
+
+        case INV_OVER:
+            waddstr(win, "Overwrite\n");
+            break;
+
+        default:
+            waddstr(win, "Unknown\n");
+            break;
+    }
+
+    return(NORM);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/pack.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,683 @@
+/*
+    pack.c - Routines to deal with the pack.
+     
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+/*
+    Notes
+
+        The new pack is implemented through the use of bags,
+        and items are classed by their types (see rogue.h) which also
+        happen to be their display character.
+*/
+
+#include <stdlib.h>
+#include <ctype.h>
+#include "rogue.h"
+
+#define ESCAPE_EXIT(x) if (x == ESCAPE) {after = FALSE; msg(""); return(NULL);}
+#define BAD_NEWS    -1
+#define BAD_LIST ((struct linked_list *) BAD_NEWS)
+#define GOOD_NEWS   0
+
+static char type_list[] = "!?])/=:,";   /* things to inventory */
+
+/*
+    swap_top()
+        Takes an stacked object and exchanges places with the top
+        object. <node> must belong to the <top>'s stacked object list.
+*/
+
+void
+swap_top(struct linked_list *top, struct linked_list *node)
+{
+    struct object   *obt, *obn;
+
+    obt = OBJPTR(top);
+    obn = OBJPTR(node);
+
+    detach((obt->next_obj), node);  /* Take it out of the stack */
+    attach(lvl_obj, node);  /* and put it into the level */
+    detach(lvl_obj, top);   /* Remove item from level */
+
+    obn->next_obj = obt->next_obj;
+
+    if (obn->next_obj)
+        obn->next_obj->l_prev = NULL;
+
+    attach((obn->next_obj), top);
+}
+
+
+/*
+    get_all()
+        Get as many stacked items as possible.
+*/
+
+void
+get_all(struct linked_list *top)
+{
+    struct linked_list  *node;
+    struct object   *obt;
+
+    while (top)
+    {
+        obt = OBJPTR(top);
+        node = obt->next_obj;
+
+        rem_obj(top, FALSE);
+
+        if (!add_pack(top, FALSE))
+            return;
+
+        top = node;
+    }
+}
+
+
+/*
+    get_stack()
+        Allows the user to chose from a stack of items.
+*/
+
+struct linked_list *
+get_stack(struct linked_list *item)
+{
+    struct object   *obj;
+    char    buf[2 * LINELEN];
+    int i = 0, j;
+    struct linked_list  *ll;
+mpos = 0;
+    obj = OBJPTR(item);
+
+	ll = obj->next_obj;
+
+    sprintf(buf, "You are standing on top of the following items: ");
+    add_line(buf);
+    sprintf(buf, "%d) -- %s", i, inv_name(obj, TRUE));
+    add_line(buf);
+
+    while (ll)
+    {
+        i++;
+        obj = OBJPTR(ll);
+        sprintf(buf, "%d) -- %s", i, inv_name(obj, TRUE));
+        add_line(buf);
+        ll = next(ll);
+    }
+
+    end_line();
+	
+    msg("Which one do you want to pick up? [* for all] ");
+
+    switch(get_string(buf, cw))
+    {
+        case NORM:
+            break;
+        case QUIT:  /* pick up nothing */
+            msg("");
+            return (NULL);
+    }
+
+    if (buf[0] == '*')
+    {
+        get_all(item);
+		msg("");
+        return(NULL);
+    }
+    else
+    {
+        i = atoi(buf);
+
+        if (i)
+        {
+            obj = OBJPTR(item);
+            ll = obj->next_obj;
+            j = 1;
+
+            while (ll && (j != i))
+            {
+                ll = next(ll);
+                j++;
+            }
+
+            if (ll)
+            {
+                swap_top(item, ll);
+                return(ll);
+            }
+            else
+            {
+                debug("Got past last item while picking up.");
+                return(item);
+            }
+        }
+        else
+            return (item);
+    }
+}
+
+/*
+    add_pack()
+        Pick up an object and add it to the pack.  If the argument is
+        non-null use it as the linked_list pointer instead of getting it off the
+        ground.
+*/
+
+int
+add_pack(struct linked_list *item, int print_message)
+{
+    struct object   *obj, *op;
+    int from_floor;
+
+    if (item == NULL)
+    {
+        from_floor = TRUE;
+
+        if ((item = find_obj(hero.y, hero.x)) == NULL)
+        {
+            msg("Nothing to pick up.");
+            return(FALSE);
+        }
+    }
+    else
+        from_floor = FALSE;
+
+    if (from_floor)
+    {
+        item = get_stack(item);
+
+        if (!item)
+            return(FALSE);
+    }
+
+    obj = OBJPTR(item);
+
+    /* If it is gold, just add its value to rogue's purse and get rid of */
+
+    if (obj->o_type == GOLD)
+    {
+        struct linked_list  *mitem;
+        struct thing    *tp;
+
+        if (print_message)
+        {
+            if (!terse)
+                addmsg("You found ");
+
+            msg("%d gold pieces.", obj->o_count);
+        }
+
+        /*
+         * First make sure no greedy monster is after this gold. If
+         * so, make the monster run after the rogue instead.
+         */
+
+        for (mitem = mlist; mitem != NULL; mitem = next(mitem))
+        {
+            tp = THINGPTR(mitem);
+
+            if (tp->t_horde==obj)
+            {
+                tp->t_ischasing = TRUE;
+                tp->t_chasee = &player;
+                tp->t_horde  = NULL;
+            }
+        }
+
+        /*
+         * This will cause problems if people are able to drop and
+         * pick up gold, or when GOLDSTEAL monsters are killed.
+         */
+
+        /* Thieves get EXP for gold they pick up */
+
+        if (player.t_ctype == C_THIEF)
+        {
+            pstats.s_exp += obj->o_count / 4;
+            check_level();
+        }
+
+        purse += obj->o_count;
+
+        if (from_floor)
+            rem_obj(item, TRUE);    /* Remove object from the level */
+
+        return (TRUE);
+    }
+
+    /* see if he can carry any more weight */
+
+    if (itemweight(obj) + pstats.s_pack > pstats.s_carry)
+    {
+        msg("Too much for you to carry.");
+
+        if (print_message)
+        {
+            msg("%s onto %s", terse ? "Moved" : "You moved",
+                inv_name(obj, LOWERCASE));
+        }
+
+        return(FALSE);
+    }
+
+    /*
+     * Link it into the pack. If the item can be grouped, try to find its
+     * neighbors and bump the count. A special case is food, which can't
+     * be grouped, but an exact match allows the count to get
+     * incremented.
+     */
+	 
+    if ((op = apply_to_bag(pack, obj->o_type, bff_group, NULL, obj)) != NULL)
+    {
+        op->o_count += obj->o_count;    /* add it to the rest */
+
+        if (from_floor)
+            rem_obj(item, FALSE);
+
+        pack_report(op, print_message, "You now have ");
+
+        return(TRUE);
+    }
+
+    /* Check for and deal with scare monster scrolls */
+
+    if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
+        if (obj->o_flags & ISCURSED)
+        {
+            msg("The scroll turns to dust as you pick it up.");
+            rem_obj(item, TRUE);
+            return(TRUE);
+        }
+
+    /* Check if there is room */
+
+    if (count_bag(pack, obj->o_type, NULL) == max_print())
+    {
+        msg("You have no room for more %s.", name_type(obj->o_type));
+
+        if (print_message)
+        {
+            obj = OBJPTR(item);
+            msg("%s onto %s.", terse ? "Moved" : "You moved",
+                inv_name(obj, LOWERCASE));
+        }
+
+        return(FALSE);
+    }
+
+    /*
+     * finally, add the new item to the bag, and free up the linked list
+     * on top of it.
+     */
+
+    if (from_floor)
+        rem_obj(item, FALSE);
+
+    push_bag(&pack, obj);
+    pack_report(obj, print_message, "You now have ");
+    ur_free(item);
+
+    return(TRUE);      /* signal success */
+}
+
+/*
+    pack_report()
+        Notify the user about the results of the pack operation and do some
+        post processing.
+*/
+
+void
+pack_report(object *obj, int print_message, char *message)
+{
+    /* Notify the user */
+
+    if (print_message)
+    {
+        if (!terse)
+            addmsg(message);
+
+        msg("(%c%c) %s.", obj->o_type, print_letters[get_ident(obj)],
+            inv_name(obj, !terse));
+    }
+
+    if (obj->o_type == ARTIFACT)
+    {
+        has_artifact |= (1 << obj->o_which);
+        picked_artifact |= (1 << obj->o_which);
+
+        if (!(obj->ar_flags & ISUSED))
+        {
+            obj->ar_flags |= ISUSED;
+            pstats.s_exp += arts[obj->o_which].ar_worth / 10;
+            check_level();
+        }
+    }
+
+    updpack();
+
+    return;
+}
+
+/*
+    inventory()
+        list what is in the pack
+*/
+
+void
+inventory(struct linked_list *container, int type)
+{
+    int cnt;
+
+    if (type == 0)
+    {
+        msg("What kind of item <%s> to inventory (* for all)?",  type_list);
+
+        type = readchar();
+
+        if (type == ESCAPE)
+        {
+            after = FALSE;
+            msg("");
+            return;
+        }
+    }
+
+    /*
+     * Get a list of items to print out. If the user selects '*', list
+     * them all.
+     */
+
+    if (type == '*')
+        type = 0;   /* no type passed ->use them all */
+
+    mpos = 0;
+
+    if ((cnt = count_bag(container, type, NULL)) == 0)
+        msg("You don't have any %s.", name_type(type));
+    else
+    {
+        apply_to_bag(container, type, NULL, baf_print_item, &type);
+        end_line();
+        msg("");
+    }
+
+    return;
+}
+
+/*
+    pick_up()
+        Add something to characters pack.
+*/
+
+void
+pick_up(char ch)
+{
+    switch(ch)
+    {
+        default:
+            debug("Where did you pick that up???");
+            break;
+
+        case GOLD:
+        case ARMOR:
+        case POTION:
+        case FOOD:
+        case WEAPON:
+        case SCROLL:
+        case ARTIFACT:
+        case RING:
+        case STICK:
+            add_pack(NULL, MESSAGE);
+            break;
+    }
+}
+
+/*
+    get_object()
+
+        Pick something out of a pack for a purpose. The basic idea is to
+        list all the possibilities, let the user select one, get that item
+        from the container, and pass it back to the calling routine.
+*/
+
+struct object *
+get_object(struct linked_list *container, char *purpose, int type, int (*bff_p)(struct object *obj, bag_arg *junk))
+/* char    *container;    what container has what we want               */
+/* char    *purpose;      a message (verb) to print if we cant find any */
+/* char    type;          type (o_type) to pick out (NULL = any)        */
+/* int     (*bff_p) ();   bag filter function to test item              */
+{
+    struct object   *obj_p = NULL;
+    char sel_id;   /* selected type and id */
+    int  sel_type;
+    char response;
+
+    if (container == NULL)
+    {
+        msg("There isn't anything in there.");
+        after = FALSE;
+        return(NULL);
+    }
+
+    /* Make sure we have at least one item that qualifies! */
+
+    if (apply_to_bag(container, type, bff_p, NULL, NULL) == NULL)
+    {
+        msg("You seem to have nothing to %s.", purpose);
+        after = FALSE;
+        return(NULL);
+    }
+
+    while (obj_p == NULL)
+    {
+        if (type == 0)
+        {
+            msg("What kind of item <%s> do you want to %s (* for list)?", type_list, purpose);
+
+            response = readchar();
+            ESCAPE_EXIT(response);
+            msg("");
+
+            if (response == '*')
+            {
+                add_line("! Potion");
+                add_line("? Scroll");
+                add_line("= Ring");
+                add_line("/ Stick");
+                add_line("] Armor");
+                add_line(") Weapon");
+                add_line(": Food");
+                end_line();
+                continue;
+            }
+
+
+            if (!is_member(type_list, response)) { beep();
+               continue; }
+
+
+            if (count_bag(container, response, NULL) == 0)
+            {
+                msg("You don't have any %s.", name_type(response));
+                continue;
+            }
+
+            type = response;
+        }
+
+        while(obj_p == NULL)
+        {
+            msg("What item do you want to %s (* for list)?", purpose);
+            response = readchar();
+            msg("");
+            ESCAPE_EXIT(response);
+
+            if (response == '*')
+            {
+                mpos = 0;
+                apply_to_bag(container, type, bff_p, baf_print_item, &type);
+                end_line();
+                continue;
+            }
+
+            sel_type = type;
+            sel_id = response;
+
+            obj_p = scan_bag(container, sel_type,unprint_id(&sel_id));
+        }
+    }
+
+    mpos = 0;
+    msg("");
+    return(obj_p);
+}
+
+/*
+    get_item()
+
+        This is only an interim function that serves as an interface to
+        the old function get_item and its replacement get_object. It
+        assumes a NULL action routine and allocates a linked_list
+        structure on top of the object pointer.
+*/
+
+struct linked_list *
+get_item(char *purpose, int type)
+{
+    struct object   *obj_p;
+
+    if ((obj_p = get_object(pack, purpose, type, NULL)) == NULL)
+        return(NULL);
+
+    return(make_item(obj_p));
+}
+
+/*
+    del_pack()
+        Take something out of the hero's pack and throw it away.
+*/
+
+void
+del_pack(struct linked_list *what)
+{
+    rem_pack(OBJPTR(what));
+    discard(what);
+}
+
+/*
+    discard_pack
+        take an object from the pack and throw it away (like del_pack,
+        but without the linked_list structure)
+*/
+
+void
+discard_pack(struct object *obj_p)
+{
+    rem_pack(obj_p);
+    throw_away(obj_p);
+}
+
+/*
+    rem_pack()
+        Removes an item from the pack.
+*/
+
+void
+rem_pack(struct object *obj_p)
+{
+    cur_null(obj_p);    /* check for current stuff */
+    pop_bag(&pack, obj_p);
+    updpack();
+    return;      /* tell caller an item has been removed */
+}
+
+/*
+    cur_null()
+        This updates cur_weapon etc for dropping things
+*/
+
+void
+cur_null(struct object *op)
+{
+    if (op == cur_weapon)
+        cur_weapon = NULL;
+    else if (op == cur_armor)
+        cur_armor = NULL;
+    else if (op == cur_ring[LEFT_1])
+        cur_ring[LEFT_1] = NULL;
+    else if (op == cur_ring[LEFT_2])
+        cur_ring[LEFT_2] = NULL;
+    else if (op == cur_ring[LEFT_3])
+        cur_ring[LEFT_3] = NULL;
+    else if (op == cur_ring[LEFT_4])
+        cur_ring[LEFT_4] = NULL;
+    else if (op == cur_ring[LEFT_5])
+        cur_ring[LEFT_5] = NULL;
+    else if (op == cur_ring[RIGHT_1])
+        cur_ring[RIGHT_1] = NULL;
+    else if (op == cur_ring[RIGHT_2])
+        cur_ring[RIGHT_2] = NULL;
+    else if (op == cur_ring[RIGHT_3])
+        cur_ring[RIGHT_3] = NULL;
+    else if (op == cur_ring[RIGHT_4])
+        cur_ring[RIGHT_4] = NULL;
+    else if (op == cur_ring[RIGHT_5])
+        cur_ring[RIGHT_5] = NULL;
+}
+
+/*
+    idenpack()
+        Identify all the items in the pack
+*/
+
+void
+idenpack(void)
+{
+    apply_to_bag(pack, 0, NULL, baf_identify, NULL);
+}
+
+/*
+    show_floor()
+        Print out the item on the floor.  Used by the move command.
+*/
+
+void
+show_floor(void)
+{
+    struct linked_list  *item;
+    struct object   *obj;
+
+    item = find_obj(hero.y, hero.x);
+
+    if (item != NULL)
+    {
+        addmsg("%s onto ", terse ? "Moved" : "You moved");
+
+        obj = OBJPTR(item);
+
+        if (obj->next_obj != NULL)
+		    msg("a stack of things.");
+		else if (obj->o_type == GOLD)
+            msg("%d gold pieces.", obj->o_count);
+        else
+        {
+            addmsg(inv_name(obj, TRUE));
+            addmsg(".");
+            endmsg();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/passages.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,320 @@
+/*
+    passages.c - Draw the connecting passages
+       
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <stdlib.h>
+#include "rogue.h"
+
+#define cmov(xy) move((xy).y, (xy).x)
+
+/*
+    do_passages()
+        Draw all the passages on a level.
+*/
+
+void
+do_passages(void)
+{
+    struct rdes *r1, *r2 = NULL;
+    int i, j;
+    int roomcount;
+
+    static struct rdes rdes[MAXROOMS] =
+    {
+        {{ 0, 1, 0, 1, 0, 0, 0, 0, 0},
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0},
+        {{ 1, 0, 1, 0, 1, 0, 0, 0, 0},
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0},
+        {{ 0, 1, 0, 0, 0, 1, 0, 0, 0},
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0},
+        {{ 1, 0, 0, 0, 1, 0, 1, 0, 0},
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0},
+        {{ 0, 1, 0, 1, 0, 1, 0, 1, 0},
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0},
+        {{ 0, 0, 1, 0, 1, 0, 0, 0, 1},
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0},
+        {{ 0, 0, 0, 1, 0, 0, 0, 1, 0},
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0},
+        {{ 0, 0, 0, 0, 1, 0, 1, 0, 1},
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0},
+        {{ 0, 0, 0, 0, 0, 1, 0, 1, 0},
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0}
+    };
+
+    /* reinitialize room graph description */
+
+    for (r1 = rdes; r1 < &rdes[MAXROOMS]; r1++)
+    {
+        for (j = 0; j < MAXROOMS; j++)
+            r1->isconn[j] = FALSE;
+
+        r1->ingraph = FALSE;
+    }
+
+    /*
+     * starting with one room, connect it to a random adjacent room and
+     * then pick a new room to start with.
+     */
+
+    roomcount = 1;
+    r1 = &rdes[rnd(MAXROOMS)];
+    r1->ingraph = TRUE;
+
+    do
+    {
+        j = 0;
+
+        for (i = 0; i < MAXROOMS; i++)
+            if (r1->conn[i] && !rdes[i].ingraph && rnd(++j) == 0)
+                r2 = &rdes[i];
+
+        /*
+         * if no adjacent rooms are outside the graph, pick a new
+         * room to look from
+         */
+
+        if (j == 0)
+            do
+            {
+                r1 = &rdes[rnd(MAXROOMS)];
+            }
+            while (!r1->ingraph);
+
+        /*
+         * otherwise, connect new room to the graph, and draw a
+         * tunnel to it
+         */
+        else
+        {
+            r2->ingraph = TRUE;
+            i = (int)(r1 - rdes);
+            j = (int)(r2 - rdes);
+            conn(i, j);
+            r1->isconn[j] = TRUE;
+            r2->isconn[i] = TRUE;
+            roomcount++;
+        }
+    }
+    while (roomcount < MAXROOMS);
+
+    /*
+     * attempt to add passages to the graph a random number of times so
+     * that there isn't just one unique passage through it.
+     */
+
+    for (roomcount = rnd(5); roomcount > 0; roomcount--)
+    {
+        r1 = &rdes[rnd(MAXROOMS)];  /* a random room to look from */
+
+        /*
+         * find an adjacent room not already connected
+         */
+
+        j = 0;
+        for (i = 0; i < MAXROOMS; i++)
+            if (r1->conn[i] && !r1->isconn[i] && rnd(++j) == 0)
+                r2 = &rdes[i];
+
+        /*
+         * if there is one, connect it and look for the next added
+         * passage
+         */
+
+        if (j != 0)
+        {
+            i = (int)(r1 - rdes);
+            j = (int)(r2 - rdes);
+            conn(i, j);
+            r1->isconn[j] = TRUE;
+            r2->isconn[i] = TRUE;
+        }
+    }
+}
+
+/*
+    conn()
+        Draw a corridor from a room in a certain direction.
+*/
+
+void
+conn(int r1, int r2)
+{
+    struct room *rpf, *rpt = NULL;
+    int    rmt;
+    int distance = 0, turn_spot = 0, turn_distance = 0;
+    int rm;
+    char    direc;
+    coord   delt = {0,0}, curr, turn_delta = {0,0}, spos = {0,0}, epos = {0,0};
+
+    if (r1 < r2)
+    {
+        rm = r1;
+
+        if (r1 + 1 == r2)
+            direc = 'r';
+        else
+            direc = 'd';
+    }
+    else
+    {
+        rm = r2;
+
+        if (r2 + 1 == r1)
+            direc = 'r';
+        else
+            direc = 'd';
+    }
+
+    rpf = &rooms[rm];
+
+    /*
+     * Set up the movement variables, in two cases: first drawing one
+     * down.
+     */
+
+    if (direc == 'd')
+    {
+        rmt = rm + 3;   /* room # of dest */
+        rpt = &rooms[rmt];  /* room pointer of dest */
+        delt.x = 0;    /* direction of move */
+        delt.y = 1;
+        spos.x = rpf->r_pos.x;  /* start of move */
+        spos.y = rpf->r_pos.y;
+        epos.x = rpt->r_pos.x;  /* end of move */
+        epos.y = rpt->r_pos.y;
+
+        if (!(rpf->r_flags & ISGONE)) /* if not gone pick door pos */
+        {
+            spos.x += rnd(rpf->r_max.x - 2) + 1;
+            spos.y += rpf->r_max.y - 1;
+        }
+
+        if (!(rpt->r_flags & ISGONE))
+            epos.x += rnd(rpt->r_max.x - 2) + 1;
+
+        distance = abs(spos.y - epos.y) - 1;    /* distance to move */
+        turn_delta.y = 0;   /* direction to turn */
+        turn_delta.x = (spos.x < epos.x ? 1 : -1);
+        turn_distance = abs(spos.x - epos.x);   /* how far to turn */
+        turn_spot = rnd(distance - 1) + 1;  /* where turn starts */
+    }
+    else if (direc == 'r') /* setup for moving right */
+    {
+        rmt = rm + 1;
+        rpt = &rooms[rmt];
+        delt.x = 1;
+        delt.y = 0;
+        spos.x = rpf->r_pos.x;
+        spos.y = rpf->r_pos.y;
+        epos.x = rpt->r_pos.x;
+        epos.y = rpt->r_pos.y;
+
+        if (!(rpf->r_flags & ISGONE))
+        {
+            spos.x += rpf->r_max.x - 1;
+            spos.y += rnd(rpf->r_max.y - 2) + 1;
+        }
+
+        if (!(rpt->r_flags & ISGONE))
+            epos.y += rnd(rpt->r_max.y - 2) + 1;
+
+        distance = abs(spos.x - epos.x) - 1;
+        turn_delta.y = (spos.y < epos.y ? 1 : -1);
+        turn_delta.x = 0;
+        turn_distance = abs(spos.y - epos.y);
+        turn_spot = rnd(distance - 1) + 1;
+    }
+    else
+        debug("Error in connection tables.");
+
+    /*
+     * Draw in the doors on either side of the passage or just put #'s if
+     * the rooms are gone.
+     */
+
+    if (!(rpf->r_flags & ISGONE))
+        door(rpf, &spos);
+    else
+    {
+        cmov(spos);
+        addch('#');
+    }
+
+    if (!(rpt->r_flags & ISGONE))
+        door(rpt, &epos);
+    else
+    {
+        cmov(epos);
+        addch('#');
+    }
+
+    /* Get ready to move... */
+
+    curr.x = spos.x;
+    curr.y = spos.y;
+
+    while (distance)
+    {
+        /* Move to new position */
+
+        curr.x += delt.x;
+        curr.y += delt.y;
+
+        /* Check if we are at the turn place, if so do the turn */
+
+        if (distance == turn_spot && turn_distance > 0)
+            while (turn_distance--)
+            {
+                cmov(curr);
+                addch(PASSAGE);
+                curr.x += turn_delta.x;
+                curr.y += turn_delta.y;
+            }
+
+        /* Continue digging along */
+
+        cmov(curr);
+        addch(PASSAGE);
+        distance--;
+    }
+
+    curr.x += delt.x;
+    curr.y += delt.y;
+
+    if (!ce(curr, epos))
+        msg("Warning, connectivity problem on this level.");
+}
+
+/*
+    door()
+        Add a door or possibly a secret door also enters the door in the exits
+        array of the room.
+*/
+
+void
+door(struct room *rm, coord *cp)
+{
+    char a_door;
+
+    cmov(*cp);
+
+    a_door = (rnd(10)<level - 1 && rnd(100) < 20) ? SECRETDOOR : DOOR;
+
+    addch(a_door);
+
+    rm->r_exit[rm->r_nexits++] = *cp;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/player.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,538 @@
+/*
+    player.c - functions for dealing with special player abilities
+   
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <stdlib.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+ * Pray to a deity
+ *
+ * 00-10 Good stuff happens
+ * 11-40 A good deity answers
+ * 41-60 Nothing happens
+ * 61-90 A bad deity answers, but with good results
+ * 91-99 You were better off before
+ */
+
+void
+prayer(void)
+{
+    int chance, i, times;
+    char num_str[20];
+    int ch;
+    struct linked_list  *item;
+    struct thing    *tp;
+    int  is_godly;
+
+    if (player.t_praycnt > pstats.s_lvl)
+    {
+        msg("Are you sure you want to bother the gods?");
+        ch = readchar();
+
+        if (tolower(ch) != 'y')
+        {
+            after = FALSE;
+            return;
+        }
+        else
+            msg("Here goes...");
+    }
+
+    msg("You are surrounded by orange smoke...");
+
+    if (rnd(3) == 0)
+        luck--;
+
+    if (is_wearing(R_PIETY) || (rnd(luck) == 0 &&
+         (player.t_ctype == C_DRUID || player.t_ctype == C_CLERIC ||
+        ((player.t_ctype == C_PALADIN || player.t_ctype == C_RANGER)
+         && pstats.s_lvl > 8))))
+        is_godly = ISBLESSED;
+    else
+        is_godly = ISNORMAL;
+
+    if (is_wearing(R_PIETY))
+        player.t_praycnt += rnd(2);
+    else
+        player.t_praycnt++;
+
+    if (wizard)
+    {
+        msg("What roll?[0..%d] ", 99);
+        ch = get_string(num_str, cw);
+
+        if (ch == QUIT)
+        {
+            msg("");
+            return;
+        }
+        chance = atoi(num_str);
+    }
+    else
+    {
+        chance = rnd(100) + roll(10, luck) - 5;
+
+        if (player.t_praycnt > pstats.s_lvl)
+            chance += 50;
+
+        if (is_godly)
+            chance -= 50;
+    }
+
+    chance = max(0, min(chance, 100));
+
+    if (chance == 0)
+    {
+        msg("The heavens open and glorious radiance surrounds you!");
+
+        pstats.s_hpt = max_stats.s_hpt;
+        pstats.s_power = max_stats.s_power;
+
+        if (is_godly)
+            times = 8;
+        else
+            times = 1;
+
+        /*
+         * kill all monsters surrounding the hero except unique ones
+         * This will change when I implement the deity option.  If
+         * The deity is "stronger" than the unique monster, then the
+         * monster will be killed.
+         */
+
+        for (i = 0; i < times; i++)
+        {
+            item = f_mons_a(player.t_pos.y, player.t_pos.x, TRUE);
+
+            if (item)
+            {
+                tp = THINGPTR(item);
+
+                msg("A bolt of eldritch energy strikes down the %s!",
+                    monsters[tp->t_index].m_name);
+
+                killed(NULL, item, NOMESSAGE, POINTS);
+            }
+        }
+    }
+    else if (chance == 2)
+    {
+        msg("Aule, Lord of Crafts, hears your call.");
+        read_scroll(&player, S_MAKEITEMEM, is_godly);
+    }
+
+    /* Save 3-9 for other wonderful stuff */
+    else if (chance < 15)
+    {
+        msg("Orome, Lord of Forests, hears your call.");
+        read_scroll(&player, S_SUMMON, is_godly);
+    }
+    else if (chance < 20)
+    {
+        msg("Hermes, the Winged Messenger, hears your call.");
+        quaff(&player, P_HASTE, is_godly);
+    }
+    else if (chance < 25)
+    {
+        msg("Lorien, Master of Dreams, hears your call.");
+        read_scroll(&player, S_SLEEP, is_godly);
+    }
+    else if (chance < 30)
+    {
+        msg("Este, Lady of Healing, hears your call.");
+        quaff(&player, P_RESTORE, is_godly);
+        quaff(&player, P_HEALING, is_godly);
+    }
+    else if (chance < 35)
+    {
+        msg("Thor, God of Thunder, hears your call.");
+        msg("A bolt of lighting strikes you!");
+        read_scroll(&player, S_ELECTRIFY, is_godly);
+    }
+    else if (chance < 40)
+    {
+        msg("Lorien, Master of Illusion, hears your call.");
+        quaff(&player, P_DISGUISE, is_godly);
+    }
+    else if (chance < 60)   /* Nothing happens */
+    {
+        msg("Boccob, the Uncaring, ignores you.");
+    }
+
+    /* You don't really want one of these gods answering your call */
+
+    else if (chance < 65)
+    {
+        msg("Jubilex, Master of Slimes and Oozes, hears your call.");
+        read_scroll(&player, S_HOLD, is_godly);
+        luck++;
+    }
+    else if (chance < 70)
+    {
+        msg("Sauron, Lord of the Ring, hears your call.");
+        quaff(&player, P_INVIS, is_godly);
+        luck++;
+    }
+    else if (chance < 75)
+    {
+        msg("Orcus, Lord of Undead, hears your call.");
+        quaff(&player, P_PHASE, is_godly);
+        luck++;
+    }
+    else if (chance < 80)
+    {
+        msg("Incabulos, God of Evil Sendings, hears your call.");
+        quaff(&player, P_CLEAR, is_godly);
+        luck++;
+    }
+    else if (chance < 85)
+    {
+        msg("Raxivort, Night Flutterer, hears your call.");
+        quaff(&player, P_SEEINVIS, is_godly);
+        luck++;
+    }
+    else if (chance < 90)
+    {
+        msg("Morgoth, Lord of Fire, hears your call.");
+        quaff(&player, P_FIRERESIST, is_godly);
+        luck++;
+    }
+    else if (chance < 100)  /* You are in for it now! */
+    {
+        msg("You fall into a horrible trance-like state.");
+        no_command += SLEEPTIME;
+    }
+    if (chance == 100)
+    {
+        msg("The heavens open - but wait!");
+        msg("A bolt of eldritch energy strikes you!");
+
+        if (pstats.s_hpt > 1)
+            pstats.s_hpt /= 2;
+
+        msg("The gods must be angry with you.");
+    }
+}
+
+/* Routines for thieves */
+
+/*
+    gsense()
+        Sense gold returns TRUE if gold was detected
+*/
+
+int
+gsense(void)
+{
+    if (lvl_obj != NULL)
+    {
+        struct linked_list  *gitem;
+        struct object   *cur;
+        int gtotal = 0;
+
+        wclear(hw);
+
+        for (gitem = lvl_obj; gitem != NULL; gitem = next(gitem))
+        {
+            cur = OBJPTR(gitem);
+
+            if (cur->o_type == GOLD)
+            {
+                gtotal += cur->o_count;
+                mvwaddch(hw, cur->o_pos.y, cur->o_pos.x, GOLD);
+
+            }
+        }
+
+        if (gtotal)
+        {
+            msg("You sense gold!");
+            overlay(hw, cw);
+            return(TRUE);
+        }
+    }
+
+    nothing_message(ISNORMAL);
+
+    return(FALSE);
+}
+
+
+/*
+    is_stealth()
+        is player quiet about something
+*/
+
+int
+is_stealth(struct thing *tp)
+{
+    return (rnd(25) < tp->t_stats.s_dext ||
+        (tp == &player && is_wearing(R_STEALTH)));
+}
+
+/*
+    steal()
+        Steal in direction given in delta
+*/
+
+void
+steal(void)
+{
+    struct linked_list  *item;
+    struct thing    *tp;
+    coord   new_pos;
+    short   thief_bonus;
+    char    *unsuccess = "";
+    char    *gain = "";
+    char    *notice = "is not";
+
+    new_pos.y = hero.y + delta.y;
+    new_pos.x = hero.x + delta.x;
+
+    /* Anything there? */
+
+    if (new_pos.y < 0 || new_pos.y > LINES - 3 ||
+        new_pos.x < 0 || new_pos.x > COLS - 1 ||
+        mvwinch(mw, new_pos.y, new_pos.x) == ' ')
+    {
+        msg("There is no one to steal from.");
+        return;
+    }
+
+    if ((item = find_mons(new_pos.y, new_pos.x)) == NULL)
+        return;
+
+    tp = THINGPTR(item);
+
+    /* Can player steal something unnoticed? */
+
+    if (player.t_ctype == C_THIEF || player.t_ctype == C_NINJA)
+        thief_bonus = 10;
+    else
+        thief_bonus = -50;
+
+    if (rnd(50) >= 3 * pstats.s_dext + thief_bonus)
+    {
+        chase_it(&new_pos, &player);
+        turn_off(*tp, ISFRIENDLY);
+        notice = "is";
+    }
+
+    if (rnd(100) <
+        (thief_bonus + 2 * pstats.s_dext + 5 * pstats.s_lvl -
+         5 * (tp->t_stats.s_lvl - 3)))
+    {
+        struct linked_list  *s_item, *pack_ptr;
+        int   cnt = 0;
+
+        s_item = NULL;  /* Start stolen goods out as nothing */
+
+        /* Find a good item to take */
+
+        if (tp->t_pack != NULL)
+        {
+            /* Count up the number of items in the monster's pack */
+
+            for (pack_ptr = tp->t_pack; pack_ptr != NULL; pack_ptr = next(pack_ptr))
+                cnt++;
+
+            /* Pick one */
+            cnt = rnd(cnt);
+
+            /* Take it from the monster */
+
+            for (pack_ptr = tp->t_pack; --cnt == 0; pack_ptr = next(pack_ptr))
+                ;
+
+            s_item = pack_ptr;
+            detach(tp->t_pack, s_item);
+
+            /* Give it to player */
+
+            if (add_pack(s_item, MESSAGE) == FALSE)
+            {
+                (OBJPTR(s_item))->o_pos = hero;
+                fall(&player, s_item, TRUE, FALSE);
+            }
+
+            /* Get points for stealing from unfriendly monsters */
+
+            if (off(*tp, ISFRIENDLY))
+            {
+                if (player.t_ctype == C_THIEF)
+                    pstats.s_exp += 2 * tp->t_stats.s_exp / 3;
+                else
+                    pstats.s_exp += tp->t_stats.s_exp / min(pstats.s_lvl, 10);
+
+                check_level();
+            }
+        }
+        else
+        {
+            gain = " gains you nothing and";
+        }
+    }
+    else
+    {
+        unsuccess = " unsuccessful";
+    }
+
+    msg("Your%s attempt%s %s noticed.", unsuccess, gain, notice);
+}
+
+/*
+    affect()
+        cleric affecting undead
+*/
+
+void
+affect(void)
+{
+    struct linked_list  *item;
+    struct thing    *tp;
+    char    *mname;
+    coord   new_pos;
+    int    is_godly;
+    int effective_level;
+
+    if (player.t_ctype != C_CLERIC && player.t_ctype != C_PALADIN &&
+        !is_wearing(R_PIETY))
+    {
+        msg("Only clerics and paladins can affect undead.");
+        return;
+    }
+
+    is_godly = (player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN);
+
+    if (is_godly && is_wearing(R_PIETY))
+        effective_level = 2 * pstats.s_lvl;
+    else
+        effective_level = pstats.s_lvl;
+
+    new_pos.y = hero.y + delta.y;
+    new_pos.x = hero.x + delta.x;
+
+    /* Anything there? */
+
+    if (new_pos.y < 0 || new_pos.y > LINES - 3 ||
+        new_pos.x < 0 || new_pos.x > COLS - 1 ||
+        mvwinch(mw, new_pos.y, new_pos.x) == ' ')
+    {
+        msg("Nothing to affect.");
+        return;
+    }
+
+    if ((item = find_mons(new_pos.y, new_pos.x)) == NULL)
+    {
+        debug("Affect what @ %d,%d?", new_pos.y, new_pos.x);
+        return;
+    }
+
+    tp = THINGPTR(item);
+    mname = monsters[tp->t_index].m_name;
+
+    if (off(*tp, ISUNDEAD))
+    {
+        msg("Your holy symbol has no effect on the %s.", mname);
+        goto annoy;
+    }
+
+    if (on(*tp, WASTURNED))
+    {
+        msg("Your holy symbol merely enrages the %s.", mname);
+        goto annoy;
+    }
+
+    /* Can cleric destroy it? */
+
+    if (effective_level >= 3 * tp->t_stats.s_lvl)
+    {
+        msg("You have destroyed the %s.", mname);
+        killed(&player, item, NOMESSAGE, POINTS);
+        return;
+    }
+
+    /* Can cleric turn it? */
+
+    if (rnd(100) + 1 >
+        (100 * ((2 * tp->t_stats.s_lvl) - effective_level)) /
+            effective_level)
+    {
+        msg("You have turned the %s.", mname);
+        turn_on(*tp, WASTURNED);    /* One turn per monster */
+        turn_on(*tp, ISRUN);
+        turn_on(*tp, ISFLEE);
+
+        /* If monster was suffocating, stop it */
+        if (on(*tp, DIDSUFFOCATE))
+        {
+            turn_off(*tp, DIDSUFFOCATE);
+            extinguish_fuse(FUSE_SUFFOCATE);
+        }
+
+        /* If monster held us, stop it */
+        if (on(*tp, DIDHOLD) && (--hold_count == 0))
+            turn_off(player, ISHELD);
+
+        turn_off(*tp, DIDHOLD);
+
+        return;
+    }
+
+    msg("The %s momentarily recoils from your holy symbol.", mname);
+
+annoy:
+
+    if (off(*tp, WASTURNED))
+        chase_it(&new_pos, &player);
+}
+
+/*
+    undead_sense()
+        cleric or paladin finding the ungodly
+*/
+
+void
+undead_sense(void)
+{
+    struct linked_list  *item;
+    struct thing    *tp;
+    int showit = FALSE;
+
+    wclear(hw);
+
+    for (item = mlist; item != NULL; item = next(item))
+    {
+        tp = THINGPTR(item);
+
+        if (on(*tp, ISUNDEAD))
+        {
+            mvwaddch(hw, tp->t_pos.y, tp->t_pos.x, '&');
+            showit = TRUE;
+        }
+    }
+
+    if (showit)
+    {
+        msg("You feel the presense of the ungodly.");
+        overlay(hw, cw);
+        wrefresh(cw);
+        wclear(hw);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/potions.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1516 @@
+/*
+    potions.c - Functions for dealing with potions
+      
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <string.h>
+#include <stdlib.h>
+#include "rogue.h"
+
+/*
+    quaff - drink a potion (or effect a potion-like spell)
+
+    quaffer: who does it
+    which:   which P_POTION (-1 means ask from pack)
+    flags:   ISBLESSED, ISCURSED
+*/
+
+void
+quaff(struct thing *quaffer, int which, int flags)
+{
+    struct object   *obj;
+    struct thing    *th;
+    struct stats    *curp = &(quaffer->t_stats);
+    struct stats    *maxp = &(quaffer->maxstats);
+    int    blessed = flags & ISBLESSED;
+    int    cursed = flags & ISCURSED;
+    int    is_potion = (which < 0 ? TRUE : FALSE);
+
+    struct linked_list  *item, *titem;
+    char    buf[2 * LINELEN];
+
+    if (quaffer != &player)
+    {
+        monquaff(quaffer, which, flags);
+        return;
+    }
+
+    if (is_potion)      /* A regular potion */
+    {
+        if ((item = get_item("quaff", POTION)) == NULL)
+            return;
+
+        obj = OBJPTR(item);
+
+        if (obj->o_type != POTION)
+        {
+            msg("You can't drink that!");
+            return;
+        }
+
+        /* Calculate its effect */
+
+        flags = obj->o_flags;
+        cursed = obj->o_flags & ISCURSED;
+        blessed = obj->o_flags & ISBLESSED;
+        which = obj->o_which;
+
+        /* remove it from the pack */
+
+        rem_pack(obj);
+        discard(item);
+        updpack();
+    }
+
+    switch(which)
+    {
+        case P_CLEAR:
+            if (cursed)
+            {
+                if (off(player, ISCLEAR))
+                {
+                    msg("Wait, what's going on here. Huh? What? Who?");
+
+                    if (on(player, ISHUH))
+                        lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION);
+                    else
+                        light_fuse(FUSE_UNCONFUSE, 0, rnd(8) + HUHDURATION, AFTER);
+
+                    turn_on(player, ISHUH);
+                }
+                else
+                    msg("You feel dizzy for a moment, but it passes.");
+            }
+            else
+            {
+                if (blessed) /* Make player immune for the whole game */
+                {
+                    extinguish_fuse(FUSE_UNCLRHEAD);  /* If we have a fuse, put it out */
+                    msg("A strong blue aura surrounds your head.");
+                }
+                else  /* Just light a fuse for how long player is safe */
+                {
+                    if (off(player, ISCLEAR))
+                    {
+                        light_fuse(FUSE_UNCLRHEAD, 0, CLRDURATION, AFTER);
+                        msg("A faint blue aura surrounds your head.");
+                    }
+                    else  /* If have fuse lengthen, else permanently clear */
+                    {
+                        if (find_slot(FUSE_UNCLRHEAD,FUSE) == NULL)
+                            msg("Your blue aura continues to glow strongly.");
+                        else
+                        {
+                            lengthen_fuse(FUSE_UNCLRHEAD, CLRDURATION);
+                            msg("Your blue aura brightens for a moment.");
+                        }
+                    }
+                }
+
+                turn_on(player, ISCLEAR);
+
+                /* If player is confused, unconfuse him */
+
+                if (on(player, ISHUH))
+                {
+                    extinguish_fuse(FUSE_UNCONFUSE);
+                    unconfuse(NULL);
+                }
+            }
+            break;
+
+        case P_HEALING:
+            if (cursed)
+            {
+                if (player.t_ctype != C_PALADIN
+                    && !(player.t_ctype == C_NINJA
+                    && curp->s_lvl > 12)
+                    && !save(VS_POISON))
+                {
+                    feel_message();
+                    curp->s_hpt /= 2;
+                    curp->s_power /= 2;
+
+                    if ((curp->s_hpt -= 1) <= 0)
+                    {
+                        death(D_POISON);
+                        return;
+                    }
+                }
+                else
+                    msg("You feel momentarily sick.");
+            }
+            else
+            {
+                int nsides = (blessed ? 8 : 4);
+                int hpt_gain = roll(curp->s_lvl, nsides);
+                int power_gain = roll(curp->s_lvl, nsides);
+
+                if (blessed && on(player, ISHUH))
+                {
+                    extinguish_fuse(FUSE_UNCONFUSE);
+                    unconfuse(NULL);
+                }
+
+                curp->s_hpt = min(curp->s_hpt + hpt_gain, maxp->s_hpt);
+
+                if (is_potion)  /* Do not bump power or maximums if spell */
+                {
+                    know_items[TYP_POTION][P_HEALING] = TRUE;
+                    curp->s_power = min(curp->s_power + power_gain, maxp->s_power);
+
+                    if (maxp->s_hpt == curp->s_hpt)
+                        maxp->s_hpt = curp->s_hpt += roll(1, nsides);
+
+                    if (maxp->s_power == curp->s_power)
+                        maxp->s_power = curp->s_power += roll(1, nsides);
+                }
+
+                msg("You begin to feel %sbetter.", blessed ? "much " : "");
+
+                if (off(player, PERMBLIND))
+                    sight(NULL);
+            }
+            break;
+
+        case P_GAINABIL:
+        {
+            int   ctype;
+
+            if (!is_potion || pstats.s_arm <= 0)
+                feel_message();
+            else
+            {
+                if (blessed)    /* add to all attributes */
+                {
+                    add_intelligence(FALSE);
+                    add_dexterity(FALSE);
+                    add_strength(FALSE);
+                    add_wisdom(FALSE);
+                    add_const(FALSE);
+                }
+                else
+                {
+                    if (rnd(100) < 70)
+                    /* probably change own ability */
+                        ctype = player.t_ctype;
+                    else
+                        switch(rnd(4))
+                        {
+                            case 0: ctype = C_FIGHTER;  break;
+                            case 1: ctype = C_MAGICIAN; break;
+                            case 2: ctype = C_CLERIC;   break;
+                            case 3: ctype = C_THIEF;    break;
+                        }
+                        switch (ctype)
+                        {
+                            case C_FIGHTER:add_strength(cursed);        break;
+                            case C_PALADIN:add_strength(cursed);        break;
+                            case C_RANGER:add_strength(cursed);         break;
+                            case C_MAGICIAN:add_intelligence(cursed);   break;
+                            case C_ILLUSION:add_intelligence(cursed);   break;
+                            case C_CLERIC:add_wisdom(cursed);           break;
+                            case C_DRUID:add_wisdom(cursed);            break;
+                            case C_THIEF:add_dexterity(cursed);         break;
+                            case C_ASSASIN:add_dexterity(cursed);       break;
+                            case C_NINJA:add_dexterity(cursed);         break;
+                            default: msg("You're a strange type!");     break;
+                        }
+                    }
+
+                    if (rnd(100) < 10)
+                        add_const(cursed);
+
+                    if (rnd(100) < 60)
+                        curp->s_arm += (cursed ? 1 : -1);
+
+                    if (!cursed)
+                        know_items[TYP_POTION][P_GAINABIL] = TRUE;
+                }
+            }
+            break;
+
+        case P_MONSTDET:
+
+            /*
+             * Potion of monster detection, if there are monsters,
+             * detect them
+             */
+
+            if (is_potion)
+                know_items[TYP_POTION][P_MONSTDET] = TRUE;
+
+            if (cursed)
+            {
+                int nm = roll(3, 6);
+                int i;
+                char    ch;
+                struct room *rp;
+                coord   pos;
+
+                msg("You begin to sense the presence of monsters.");
+                wclear(hw);
+
+                for (i = 1; i < nm; i++)
+                {
+                    rp = &rooms[rnd_room()];
+                    rnd_pos(rp, &pos);
+
+                    if (rnd(2))
+                        ch = 'a' + ucrnd(26);
+                    else
+                        ch = 'A' + ucrnd(26);
+
+                    mvwaddch(hw, pos.y, pos.x, ch);
+                }
+                waddstr(cw, morestr);
+                overlay(hw, cw);
+                wrefresh(cw);
+                wait_for(' ');
+                msg("");
+            }
+            else if (mlist != NULL)
+            {
+                msg("You begin to sense the presence of monsters.");
+                waddstr(cw, morestr);
+                overlay(mw, cw);
+                wrefresh(cw);
+                wait_for(' ');
+                msg("");
+
+                if (blessed)
+                    turn_on(player, BLESSMONS);
+            }
+            else
+                nothing_message(flags);
+            break;
+
+        case P_TREASDET:
+
+            /* Potion of magic detection.  Show the potions and scrolls */
+
+            if (cursed)
+            {
+                int nm = roll(3, 3);
+                int i;
+                char    ch;
+                struct room *rp;
+                coord   pos;
+
+                msg("You sense the presence of magic on this level.");
+                wclear(hw);
+
+                for (i = 1; i < nm; i++)
+                {
+                    rp = &rooms[rnd_room()];
+                    rnd_pos(rp, &pos);
+
+                    if (rnd(9) == 0)
+                        ch = BMAGIC;
+                    else if (rnd(9) == 0)
+                        ch = CMAGIC;
+                    else
+                        ch = MAGIC;
+
+                    mvwaddch(hw, pos.y, pos.x, ch);
+                }
+                waddstr(cw, morestr);
+
+                overlay(hw, cw);
+                wrefresh(cw);
+                wait_for(' ');
+                msg("");
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_TREASDET] = TRUE;
+
+                break;
+            }
+
+            if (blessed)
+                turn_on(player, BLESSMAGIC);
+
+            if (lvl_obj != NULL)
+            {
+                struct linked_list  *mobj;
+                struct object   *tp;
+                int showit;
+
+                showit = FALSE;
+                wclear(hw);
+
+                for (mobj = lvl_obj; mobj != NULL; mobj = next(mobj))
+                {
+                    tp = OBJPTR(mobj);
+
+                    if (is_magic(tp))
+                    {
+                        char    mag_type = MAGIC;
+
+                        if (blessed)
+                            if (tp->o_flags & ISCURSED)
+                                mag_type = CMAGIC;
+                            else if (tp->o_flags & ISBLESSED)
+                                mag_type = BMAGIC;
+
+                        showit = TRUE;
+                        mvwaddch(hw, tp->o_pos.y, tp->o_pos.x, mag_type);
+                    }
+                }
+
+                for (titem = mlist; titem != NULL; titem = next(titem))
+                {
+                    struct linked_list  *pitem;
+
+                    th = THINGPTR(titem);
+
+                    for (pitem = th->t_pack; pitem != NULL; pitem = next(pitem))
+                    {
+                        if (is_magic(OBJPTR(pitem)))
+                        {
+                            showit = TRUE;
+                            mvwaddch(hw, th->t_pos.y, th->t_pos.x,MAGIC);
+                        }
+                    }
+                }
+
+                if (showit)
+                {
+                    msg("You sense the presence of magic on this level.");
+
+                    if (is_potion)
+                        know_items[TYP_POTION][P_TREASDET] = TRUE;
+
+                    waddstr(cw, morestr);
+                    overlay(hw, cw);
+                    wrefresh(cw);
+                    wait_for(' ');
+                    msg("");
+                    break;
+                }
+            }
+            nothing_message(flags);
+            break;
+
+        case P_SEEINVIS:
+            if (cursed)
+            {
+                if (off(player, ISBLIND) && !is_wearing(R_SEEINVIS))
+                {
+                    msg("A cloak of darkness falls around you.");
+                    turn_on(player, ISBLIND);
+                    light_fuse(FUSE_SIGHT, 0, SEEDURATION, AFTER);
+                    look(FALSE);
+                }
+                else
+                    msg("Your eyes stop tingling for a moment.");
+            }
+            else if (off(player, PERMBLIND))
+            {
+                if (is_potion)
+                    know_items[TYP_POTION][P_SEEINVIS] = TRUE;
+
+                if (off(player, CANSEE))
+                {
+                    turn_on(player, CANSEE);
+                    msg("Your eyes begin to tingle.");
+                    light_fuse(FUSE_UNSEE, 0, blessed ? SEEDURATION * 3 : SEEDURATION, AFTER);
+                    light(&hero);
+                }
+                else if (find_slot(FUSE_UNSEE,FUSE) != NULL)
+                {
+                    nothing_message(ISNORMAL);
+                    lengthen_fuse(FUSE_UNSEE, blessed ? SEEDURATION * 3 : SEEDURATION);
+                }
+                sight(NULL);
+            }
+            break;
+
+        case P_PHASE:
+
+            if (cursed)
+            {
+                msg("You can't move.");
+                no_command = HOLDTIME;
+            }
+            else
+            {
+                short   duration = (blessed ? 3 : 1);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_PHASE] = TRUE;
+
+                if (on(player, CANINWALL))
+                    lengthen_fuse(FUSE_UNPHASE, duration * PHASEDURATION);
+                else
+                {
+                    light_fuse(FUSE_UNPHASE, 0, duration * PHASEDURATION, AFTER);
+                    turn_on(player, CANINWALL);
+                }
+                msg("You feel %slight-headed!", blessed ? "very " : "");
+            }
+            break;
+
+        case P_RAISELEVEL:
+
+            if (cursed || (!is_potion && pstats.s_lvl > 20))
+                lower_level(D_POTION);
+            else
+            {
+                msg("You suddenly feel %smore skillful.", blessed ? "much " : "");
+                know_items[TYP_POTION][P_RAISELEVEL] = TRUE;
+                raise_level();
+
+                if (blessed)
+                    raise_level();
+            }
+            break;
+
+        case P_HASTE:
+            if (cursed)     /* Slow player down */
+            {
+                if (on(player, ISHASTE))
+                {
+                    extinguish_fuse(FUSE_NOHASTE);
+                    nohaste(NULL);
+                }
+                else
+                {
+                    msg("You feel yourself moving %sslower.",
+                        on(player, ISSLOW) ? "even " : "");
+
+                    if (on(player, ISSLOW))
+                        lengthen_fuse(FUSE_NOSLOW, rnd(4) + 4);
+                    else if (!is_wearing(R_FREEDOM))
+                    {
+                        turn_on(player, ISSLOW);
+                        player.t_turn = TRUE;
+                        light_fuse(FUSE_NOSLOW, 0, rnd(4) + 4, AFTER);
+                    }
+                }
+            }
+            else
+            {
+                if (off(player, ISSLOW))
+                    msg("You feel yourself moving %sfaster.",
+                        blessed ? "much " : "");
+
+                add_haste(blessed);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_HASTE] = TRUE;
+            }
+            break;
+
+        case P_RESTORE:
+        {
+            int i;
+
+            msg("You are surrounded by an orange mist.");
+
+            if (is_potion)
+                know_items[TYP_POTION][P_RESTORE] = TRUE;
+
+            if (lost_str)
+            {
+                for (i = 0; i < lost_str; i++)
+                    extinguish_fuse(FUSE_RES_STRENGTH);
+
+                lost_str = 0;
+            }
+            res_strength(NULL);
+
+            if (lost_dext)
+            {
+                for (i = 0; i < lost_dext; i++)
+                    extinguish_fuse(FUSE_UNITCH);
+
+                lost_dext = 0;
+            }
+
+            res_dexterity();
+            res_wisdom();
+            res_intelligence();
+            curp->s_const = maxp->s_const;
+        }
+        break;
+
+        case P_INVIS:
+
+            if (cursed)
+            {
+                msg("You feel very noticable.");
+                quaff(&player, P_SHIELD, ISCURSED);
+            }
+            else if (off(player, ISINVIS))
+            {
+                turn_on(player, ISINVIS);
+
+                if (on(player, ISDISGUISE))
+                {
+                    turn_off(player, ISDISGUISE);
+                    extinguish_fuse(FUSE_UNDISGUISE);
+                    msg("Your skin feels itchy for a moment.");
+                }
+                msg("You have a tingling feeling all over your body.");
+                light_fuse(FUSE_APPEAR, 0, blessed ? WANDERTIME * 3 : WANDERTIME, AFTER);
+                PLAYER = IPLAYER;
+                light(&hero);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_INVIS] = TRUE;
+            }
+            else
+                lengthen_fuse(FUSE_APPEAR, blessed ? WANDERTIME * 3 : WANDERTIME);
+
+            break;
+
+        case P_SMELL:
+
+            if (cursed)
+            {
+                if (on(player, CANSCENT))
+                {
+                    turn_off(player, CANSCENT);
+                    extinguish_fuse(FUSE_UNSCENT);
+                    msg("You no longer smell monsters around you.");
+                }
+                else if (on(player, ISUNSMELL))
+                {
+                    lengthen_fuse(FUSE_UNSCENT, PHASEDURATION);
+                    msg("You feel your nose tingle.");
+                }
+                else
+                {
+                    turn_on(player, ISUNSMELL);
+                    light_fuse(FUSE_SCENT, 0, PHASEDURATION, AFTER);
+                    msg("You can't smell anything now.");
+                }
+            }
+            else
+            {
+                short   duration = (blessed ? 3 : 1);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_SMELL] = TRUE;
+
+                if (on(player, CANSCENT))
+                    lengthen_fuse(FUSE_UNSCENT, duration * PHASEDURATION);
+                else
+                {
+                    light_fuse(FUSE_UNSCENT, 0, duration * PHASEDURATION, AFTER);
+                    turn_on(player, CANSCENT);
+                }
+                msg("You begin to smell monsters all around you.");
+            }
+            break;
+
+        case P_HEAR:
+
+            if (cursed)
+            {
+                if (on(player, CANHEAR))
+                {
+                    turn_off(player, CANHEAR);
+                    extinguish_fuse(FUSE_HEAR);
+                    msg("You no longer hear monsters around you.");
+                }
+                else if (on(player, ISDEAF))
+                {
+                    lengthen_fuse(FUSE_HEAR, PHASEDURATION);
+                    msg("You feel your ears burn.");
+                }
+                else
+                {
+                    light_fuse(FUSE_HEAR, 0, PHASEDURATION, AFTER);
+                    turn_on(player, ISDEAF);
+                    msg("You are surrounded by a sudden silence.");
+                }
+            }
+            else
+            {
+                short   duration = (blessed ? 3 : 1);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_HEAR] = TRUE;
+
+                if (on(player, CANHEAR))
+                    lengthen_fuse(FUSE_UNHEAR, duration * PHASEDURATION);
+                else
+                {
+                    light_fuse(FUSE_UNHEAR, 0, duration * PHASEDURATION, AFTER);
+                    turn_on(player, CANHEAR);
+                }
+                msg("You begin to hear monsters all around you.");
+            }
+            break;
+
+        case P_SHERO:
+            if (cursed)
+            {
+                if (on(player, SUPERHERO))
+                {
+                    msg("You feel ordinary again.");
+                    turn_off(player, SUPERHERO);
+                    extinguish_fuse(FUSE_UNSHERO);
+                    extinguish_fuse(FUSE_UNBHERO);
+                }
+                else if (on(player, ISUNHERO))
+                {
+                    msg("Your feeling of vulnerability increases.");
+                    lengthen_fuse(FUSE_SHERO, 5 + rnd(5));
+                }
+                else
+                {
+                    msg("You feel suddenly vulnerable.");
+
+                    if (curp->s_hpt == 1)
+                    {
+                        death(D_POTION);
+                        return;
+                    }
+
+                    curp->s_hpt /= 2;
+                    chg_str(-2, FALSE, TRUE);
+                    chg_dext(-2, FALSE, TRUE);
+                    no_command = 3 + rnd(HEROTIME);
+                    turn_on(player, ISUNHERO);
+                    light_fuse(FUSE_SHERO, 0, HEROTIME + rnd(HEROTIME), AFTER);
+                }
+            }
+            else
+            {
+                if (on(player, ISFLEE))
+                {
+                    turn_off(player, ISFLEE);
+                    msg("You regain your composure.");
+                }
+
+                if (on(player, ISUNHERO))
+                {
+                    extinguish_fuse(FUSE_SHERO);
+                    shero(NULL);
+                }
+                else if (on(player, SUPERHERO))
+                {
+                    if (find_slot(FUSE_UNBHERO,FUSE))
+                        lengthen_fuse(FUSE_UNBHERO, HEROTIME+2*rnd(HEROTIME));
+                    else if (find_slot(FUSE_UNSHERO,FUSE) && !blessed)
+                        lengthen_fuse(FUSE_UNSHERO,HEROTIME+2*rnd(HEROTIME));
+                    else
+                    {
+                        extinguish_fuse(FUSE_UNSHERO);
+                        unshero(NULL);
+                        light_fuse(FUSE_UNBHERO,0, 2 * (HEROTIME + rnd(HEROTIME)), AFTER);
+                    }
+                    msg("Your feeling of invulnerablity grows stronger.");
+                }
+                else
+                {
+                    turn_on(player, SUPERHERO);
+                    chg_str(10, FALSE, FALSE);
+                    chg_dext(5, FALSE, FALSE);
+                    quaff(quaffer, P_HASTE, ISBLESSED);
+                    quaff(quaffer, P_CLEAR, ISNORMAL);
+
+                    if (blessed)
+                    {
+                        light_fuse(FUSE_UNBHERO, 0, HEROTIME + rnd(HEROTIME), AFTER);
+                        msg("You suddenly feel invincible.");
+                    }
+                    else
+                    {
+                        light_fuse(FUSE_UNSHERO, 0, HEROTIME + rnd(HEROTIME), AFTER);
+                        msg("You suddenly feel invulnerable.");
+                    }
+
+                    if (is_potion)
+                        know_items[TYP_POTION][P_SHERO] = TRUE;
+                }
+            }
+            break;
+
+        case P_DISGUISE:
+            if (off(player, ISDISGUISE) && off(player, ISINVIS))
+            {
+                turn_on(player, ISDISGUISE);
+                msg("Your body shimmers a moment and then changes.");
+                light_fuse(FUSE_UNDISGUISE, 0, blessed ? GONETIME * 3 : GONETIME, AFTER);
+
+                if (rnd(2))
+                    PLAYER = 'a' + ucrnd(26);
+                else
+                    PLAYER = 'A' + ucrnd(26);
+
+                light(&hero);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_DISGUISE] = TRUE;
+            }
+            else if (off(player, ISINVIS))
+                lengthen_fuse(FUSE_UNDISGUISE,blessed?GONETIME * 3 : GONETIME);
+            else
+                msg("You have an itchy feeling under your skin.");
+
+            break;
+
+        case P_FIRERESIST:
+            if (cursed)
+            {
+                if (!is_wearing(R_FIRERESIST))
+                {
+                    msg("Your teeth start clattering.");
+
+                    if (on(player, ISHASTE))
+                    {
+                        extinguish_fuse(FUSE_NOHASTE);
+                        nohaste(NULL);
+                    }
+                    else
+                    {
+                        msg("You feel yourself moving %sslower.",
+                            on(player, ISSLOW) ? "even "  : "");
+
+                        if (on(player, ISSLOW))
+                            lengthen_fuse(FUSE_NOSLOW, rnd(4) + 4);
+                        else if (!is_wearing(R_FREEDOM))
+                        {
+                            turn_on(player, ISSLOW);
+                            player.t_turn = TRUE;
+                            light_fuse(FUSE_NOSLOW, 0, rnd(4) + 4, AFTER);
+                        }
+                    }
+                }
+                else
+                    msg("You feel a brief chill.");
+            }
+            else
+            {
+                if (is_potion)
+                    know_items[TYP_POTION][P_FIRERESIST] = TRUE;
+
+                if (blessed)
+                {
+                    extinguish_fuse(FUSE_UNHOT);
+                    msg("You feel a strong continuous warm glow.");
+                }
+                else
+                {
+                    if (off(player, NOFIRE))
+                    {
+                        light_fuse(FUSE_UNHOT, 0, PHASEDURATION, AFTER);
+                        msg("You feel a warm glow.");
+                    }
+                    else
+                    {
+                        if (find_slot(FUSE_UNHOT,FUSE) == NULL)
+                            msg("Your warm glow continues.");
+                        else
+                        {
+                            lengthen_fuse(FUSE_UNHOT, PHASEDURATION);
+                            msg("Your feel a hot flush.");
+                        }
+                    }
+                }
+
+                turn_on(player, NOFIRE);
+
+                if (on(player, NOCOLD))
+                {
+                    turn_off(player, NOCOLD);
+                    extinguish_fuse(FUSE_UNCOLD);
+                }
+            }
+            break;
+
+        case P_COLDRESIST:
+            if (cursed)
+            {
+                if (!is_wearing(R_COLDRESIST))
+                {
+                    msg("Your feel feverishly hot.");
+
+                    if (on(player, ISHASTE))
+                    {
+                        extinguish_fuse(FUSE_NOHASTE);
+                        nohaste(NULL);
+                    }
+                    else
+                    {
+                        msg("You feel yourself moving %sslower.",
+                            on(player, ISSLOW)  ? "even " : "");
+
+                        if (on(player, ISSLOW))
+                            lengthen_fuse(FUSE_NOSLOW, rnd(4) + 4);
+                        else if (!is_wearing(R_FREEDOM))
+                        {
+                            turn_on(player, ISSLOW);
+                            player.t_turn = TRUE;
+                            light_fuse(FUSE_NOSLOW, 0, rnd(4) + 4, AFTER);
+                        }
+                    }
+                }
+                else
+                    msg("You feel a brief touch of heat rash.");
+            }
+            else
+            {
+                if (is_potion)
+                    know_items[TYP_POTION][P_COLDRESIST] = TRUE;
+
+                if (blessed)
+                {
+                    extinguish_fuse(FUSE_UNCOLD);
+                    msg("You feel a strong continuous cool breeze.");
+                }
+                else
+                {
+                    if (off(player, NOCOLD))
+                    {
+                        light_fuse(FUSE_UNCOLD, 0, PHASEDURATION, AFTER);
+                        msg("You feel a cool breeze.");
+                    }
+                    else
+                    {
+                        if (find_slot(FUSE_UNCOLD,FUSE) == NULL)
+                            msg("Your cool feeling continues.");
+                        else
+                        {
+                            lengthen_fuse(FUSE_UNCOLD, PHASEDURATION);
+                            msg("The cool breeze blows more strongly.");
+                        }
+                    }
+                }
+
+                turn_on(player, NOCOLD);
+
+                if (on(player, NOFIRE))
+                {
+                    extinguish_fuse(FUSE_UNHOT);
+                    turn_off(player, NOFIRE);
+                }
+            }
+            break;
+
+        case P_HASOXYGEN:
+            if (cursed)
+            {
+                if (!is_wearing(R_BREATHE))
+                {
+                    msg("You can't breathe.");
+                    no_command = HOLDTIME;
+                }
+                else
+                {
+                    msg("You feel a momentary shortness of breath.");
+                }
+            }
+            else
+            {
+                short   duration = (blessed ? 3 : 1);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_HASOXYGEN] = TRUE;
+
+                if (on(player, HASOXYGEN))
+                    lengthen_fuse(FUSE_UNBREATHE, duration * PHASEDURATION);
+                else
+                {
+                    light_fuse(FUSE_UNBREATHE, 0, duration * PHASEDURATION, AFTER);
+                    turn_on(player, HASOXYGEN);
+                }
+
+                if (!is_wearing(R_BREATHE))
+                    msg("The air seems %sless polluted.",
+                        blessed ? "much " : "");
+            }
+            break;
+
+        case P_LEVITATION:
+            if (cursed)
+            {
+                msg("You can't move.");
+                no_command = HOLDTIME;
+            }
+            else
+            {
+                short   duration = (blessed ? 3 : 1);
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_LEVITATION] = TRUE;
+
+                if (on(player, CANFLY))
+                    lengthen_fuse(FUSE_UNFLY, duration * WANDERTIME);
+                else
+                {
+                    light_fuse(FUSE_UNFLY, 0, duration * WANDERTIME, AFTER);
+                    turn_on(player, CANFLY);
+                }
+
+                if (!is_wearing(R_LEVITATION))
+                    msg("You %sbegin to float in the air!",
+                        blessed ? "quickly " : "");
+            }
+            break;
+
+        case P_REGENERATE:
+            if (cursed)
+            {
+                quaff(quaffer, P_HEALING, ISCURSED);
+                quaff(quaffer, P_HASTE, ISCURSED);
+            }
+            else
+            {
+                short   duration = (blessed ? 3 : 1) * HUHDURATION;
+
+                if (is_potion)
+                    know_items[TYP_POTION][P_REGENERATE] = TRUE;
+
+                if (on(player, SUPEREAT))
+                    lengthen_fuse(FUSE_UNSUPEREAT, duration);
+                else
+                {
+                    light_fuse(FUSE_UNSUPEREAT, 0, duration, AFTER);
+                    turn_on(player, SUPEREAT);
+                }
+
+                if (on(player, ISREGEN))
+                    lengthen_fuse(FUSE_UNREGEN, duration);
+                else
+                {
+                    light_fuse(FUSE_UNREGEN, 0, duration, AFTER);
+                    turn_on(player, ISREGEN);
+                }
+
+                if (!is_wearing(R_REGEN))
+                    msg("You feel %shealthier!", blessed ? "much " : "");
+            }
+
+        case P_SHIELD:
+        {
+            int adjustment = 0;
+
+            if (on(player, HASSHIELD))      /* cancel old spell */
+            {
+                extinguish_fuse(FUSE_UNSHIELD);
+                unshield(NULL);
+            }
+
+            if (cursed)
+                adjustment = 2;
+            else if (blessed)
+            {
+                msg("Your skin feels very rigid.");
+
+                switch (player.t_ctype)
+                {
+                    case C_FIGHTER:
+                    case C_PALADIN:
+                    case C_RANGER:
+                        adjustment = -3;
+                        break;
+                    default:
+                        adjustment = -5;
+                }
+            }
+            else
+            {
+                msg("Your skin hardens.");
+                adjustment = -2;
+            }
+
+            pstats.s_arm += adjustment;
+            pstats.s_acmod += adjustment;
+            turn_on(player, HASSHIELD);
+            light_fuse(FUSE_UNSHIELD,0,(blessed ? 3 : 1) * SEEDURATION, AFTER);
+
+            if (is_potion)
+                know_items[TYP_POTION][P_SHIELD] = TRUE;
+        }
+        break;
+
+        case P_TRUESEE:
+            if (cursed)
+            {
+                turn_on(player, PERMBLIND);
+
+                if (on(player, ISBLIND))
+                {
+                    msg("The gloom around you thickens.");
+                    lengthen_fuse(FUSE_SIGHT, SEEDURATION);
+                }
+                else
+                {
+                    msg("A mantle of darkness falls around you.");
+                    turn_on(player, ISBLIND);
+                    light_fuse(FUSE_SIGHT, 0, SEEDURATION, AFTER);
+                    look(FALSE);
+                }
+                look(FALSE);
+            }
+            else if (on(player, PERMBLIND))
+            {
+                if (blessed || is_potion)
+                {
+                    turn_off(player, PERMBLIND);
+                    sight(NULL);
+                    goto let_there_be_light;
+                }
+                else
+                    nothing_message(ISBLESSED);
+            }
+            else
+    let_there_be_light:
+                if (off(player, CANSEE))
+                {
+                    turn_on(player, CANSEE);
+                    msg("You feel especially perceptive.");
+                    light_fuse(FUSE_UNTRUESEE, 0, blessed ? SEEDURATION * 3
+                        : SEEDURATION, AFTER);
+                    light(&hero);
+                }
+                else if (find_slot(FUSE_UNSEE,FUSE) != NULL)
+                {
+                    nothing_message(ISNORMAL);
+                    lengthen_fuse(FUSE_UNTRUESEE, blessed ? SEEDURATION * 3
+                        : SEEDURATION);
+                }
+
+            break;
+
+        default:
+            msg("What an odd tasting potion!");
+            return;
+    }
+
+    status(FALSE);
+
+    if (is_potion)
+    {
+        if (!cursed && know_items[TYP_POTION][which] &&
+            guess_items[TYP_POTION][which])
+        {
+            ur_free(guess_items[TYP_POTION][which]);
+            guess_items[TYP_POTION][which] = NULL;
+        }
+        else if (askme && !know_items[TYP_POTION][which] &&
+            guess_items[TYP_POTION][which] == NULL)
+        {
+            msg(terse ? "Call it: " :  "What do you want to call it? ");
+
+            if (get_string(buf, cw) == NORM)
+            {
+                guess_items[TYP_POTION][which] =
+                    new_alloc(strlen(buf) + 1);
+                strcpy(guess_items[TYP_POTION][which], buf);
+            }
+        }
+        food_left += (blessed ? rnd(100) : (cursed ? -rnd(100) : rnd(50)));
+    }
+}
+
+/*
+    lower_level()
+        Lower a level of experience
+*/
+
+void
+lower_level(int who)
+{
+    int fewer, nsides = 0, i;
+
+    if (--pstats.s_lvl == 0)
+    {
+        death(who); /* All levels gone */
+        return;
+    }
+
+    msg("You suddenly feel less skillful.");
+    pstats.s_exp = 1L;
+    init_exp();
+
+    for (i = 2; i <= pstats.s_lvl; i++)
+    {
+        if (max_stats.s_exp < 0x3fffffffL)  /* 2^30 - 1 */
+            max_stats.s_exp *= 2L;  /* twice as many for next */
+    }
+
+    switch (player.t_ctype)
+    {
+        case C_FIGHTER: nsides = 12;break;
+        case C_PALADIN: nsides = 12;break;
+        case C_RANGER: nsides = 12; break;
+        case C_MAGICIAN: nsides = 4;break;
+        case C_ILLUSION: nsides = 4;break;
+        case C_CLERIC: nsides = 8;  break;
+        case C_DRUID: nsides = 8;   break;
+        case C_THIEF: nsides = 6;   break;
+        case C_ASSASIN: nsides = 6; break;
+        case C_NINJA: nsides = 6;   break;
+    }
+
+    fewer = max(1, roll(1, 16 - nsides) + int_wis_bonus());
+    pstats.s_power -= fewer;
+    max_stats.s_power -= fewer;
+
+    fewer = max(1, roll(1, nsides) + const_bonus());
+    pstats.s_hpt -= fewer;
+    max_stats.s_hpt -= fewer;
+
+    if (pstats.s_hpt < 1)
+        pstats.s_hpt = 1;
+
+    if (max_stats.s_hpt < 1)
+    {
+        death(who);
+        return;
+    }
+}
+
+void
+res_dexterity(void)
+{
+    if (lost_dext)
+    {
+        chg_dext(lost_dext, FALSE, FALSE);
+        lost_dext = 0;
+    }
+    else
+    {
+        pstats.s_dext = max_stats.s_dext + ring_value(R_ADDHIT) +
+            (on(player, POWERDEXT) ? 10 : 0) +
+            (on(player, SUPERHERO) ? 5 : 0);
+    }
+
+}
+
+
+/*
+    res_wisdom()
+        Restore player's wisdom
+*/
+
+void
+res_wisdom(void)
+{
+    int ring_str;
+
+    /* Discount the ring value */
+
+    ring_str = ring_value(R_ADDWISDOM) + (on(player, POWERWISDOM) ? 10 : 0);
+    pstats.s_wisdom -= ring_str;
+
+    if (pstats.s_wisdom < max_stats.s_wisdom)
+        pstats.s_wisdom = max_stats.s_wisdom;
+
+    /* Redo the rings */
+
+    pstats.s_wisdom += ring_str;
+}
+
+/*
+    res_intelligence()
+        Restore player's intelligence
+*/
+
+void
+res_intelligence(void)
+{
+    int ring_str;
+
+    /* Discount the ring value */
+
+    ring_str = ring_value(R_ADDINTEL) + (on(player, POWERINTEL) ? 10 : 0);
+    pstats.s_intel -= ring_str;
+
+    if (pstats.s_intel < max_stats.s_intel)
+        pstats.s_intel = max_stats.s_intel;
+
+    /* Redo the rings */
+
+    pstats.s_intel += ring_str;
+}
+
+
+/*
+    add_strength()
+        Increase player's strength
+*/
+
+void
+add_strength(int cursed)
+{
+
+    if (cursed)
+    {
+        msg("You feel slightly weaker now.");
+        chg_str(-1, FALSE, FALSE);
+    }
+    else
+    {
+        msg("You feel stronger now.  What bulging muscles!");
+
+        if (lost_str != 0)
+        {
+            lost_str--;
+            chg_str(1, FALSE, FALSE);
+        }
+        else
+            chg_str(1, TRUE, FALSE);
+    }
+}
+
+
+/*
+    add_intelligence()
+        Increase player's intelligence
+*/
+
+void
+add_intelligence(int cursed)
+{
+    int ring_str;   /* Value of ring strengths */
+
+    /* Undo any ring changes */
+
+    ring_str = ring_value(R_ADDINTEL) + (on(player, POWERINTEL) ? 10 : 0);
+    pstats.s_intel -= ring_str;
+
+    /* Now do the potion */
+
+    if (cursed)
+    {
+        msg("You feel slightly less intelligent now.");
+        pstats.s_intel = max(pstats.s_intel - 1, 3);
+    }
+    else
+    {
+        msg("You feel more intelligent now.  What a mind!");
+        pstats.s_intel = min(pstats.s_intel + 1, 25);
+    }
+
+    /* Adjust the maximum */
+
+    if (max_stats.s_intel < pstats.s_intel)
+        max_stats.s_intel = pstats.s_intel;
+
+    /* Now put back the ring changes */
+    pstats.s_intel += ring_str;
+}
+
+
+/*
+    add_wisdom()
+        Increase player's wisdom
+*/
+
+void
+add_wisdom(int cursed)
+{
+    int ring_str;   /* Value of ring strengths */
+
+    /* Undo any ring changes */
+
+    ring_str = ring_value(R_ADDWISDOM) + (on(player, POWERWISDOM) ? 10 : 0);
+    pstats.s_wisdom -= ring_str;
+
+    /* Now do the potion */
+
+    if (cursed)
+    {
+        msg("You feel slightly less wise now.");
+        pstats.s_wisdom = max(pstats.s_wisdom - 1, 3);
+    }
+    else
+    {
+        msg("You feel wiser now.  What a sage!");
+        pstats.s_wisdom = min(pstats.s_wisdom + 1, 25);
+    }
+
+    /* Adjust the maximum */
+
+    if (max_stats.s_wisdom < pstats.s_wisdom)
+        max_stats.s_wisdom = pstats.s_wisdom;
+
+    /* Now put back the ring changes */
+    pstats.s_wisdom += ring_str;
+}
+
+
+/*
+    add_dexterity()
+        Increase player's dexterity
+*/
+
+void
+add_dexterity(int cursed)
+{
+    /* Now do the potion */
+
+    if (cursed)
+    {
+        msg("You feel less dextrous now.");
+        chg_dext(-1, FALSE, TRUE);
+    }
+    else
+    {
+        msg("You feel more dextrous now.  Watch those hands!");
+
+        if (lost_dext != 0)
+        {
+            lost_dext--;
+            chg_dext(1, FALSE, FALSE);
+        }
+        else
+            chg_dext(1, TRUE, FALSE);
+    }
+}
+
+
+/*
+    Increase player's constitution
+*/
+
+void
+add_const(int cursed)
+{
+    /* Do the potion */
+
+    if (cursed)
+    {
+        msg("You feel slightly less healthy now.");
+        pstats.s_const = max(pstats.s_const - 1, 3) +
+            (on(player, POWERCONST) ? 10 : 0);
+    }
+    else
+    {
+        msg("You feel healthier now.");
+        pstats.s_const = min(pstats.s_const + 1, 25) +
+            (on(player, POWERCONST) ? 10 : 0);
+    }
+
+    /* Adjust the maximum */
+
+    if (max_stats.s_const < pstats.s_const - (on(player, POWERCONST) ? 10 : 0))
+        max_stats.s_const = pstats.s_const;
+}
+
+/*
+    monquaff()
+        monster gets the effect
+*/
+
+void
+monquaff(struct thing *quaffer, int which, int flags)
+{
+    struct stats *curp = &(quaffer->t_stats);
+    struct stats *maxp = &(quaffer->maxstats);
+    int blessed = flags & ISBLESSED;
+    int cursed = flags & ISCURSED;
+
+    switch(which)
+    {
+        case P_SEEINVIS:
+            if (cursed)
+                turn_on(*quaffer, ISHUH);
+            else
+                turn_on(*quaffer, CANSEE);
+            break;
+
+        case P_GAINABIL:
+            if (cursed)
+                curp->s_intel /= 2;
+            else
+                curp->s_power = maxp->s_power;
+            break;
+
+        case P_CLEAR:
+            if (cursed)
+                turn_on(*quaffer, ISHUH);
+            else
+                turn_on(*quaffer, ISHUH);
+            break;
+
+        case P_HEALING:
+            if (cursed)
+            {
+                curp->s_hpt /= 2;
+                curp->s_power /= 2;
+            }
+            else
+            {
+                int nsides = (blessed ? 8 : 4);
+                int hpt_gain = roll(curp->s_lvl, nsides);
+                int power_gain = roll(curp->s_lvl, nsides);
+
+                curp->s_hpt = min(curp->s_hpt + hpt_gain, maxp->s_hpt);
+                curp->s_power = min(curp->s_power + power_gain, maxp->s_power);
+            }
+            break;
+
+        case  P_HASTE:
+            if (cursed)
+            {
+                if (on(*quaffer, ISHASTE))
+                    turn_off(*quaffer, ISHASTE);
+                else
+                    turn_on(*quaffer, ISSLOW);
+            }
+            else
+                turn_on(*quaffer, ISHASTE);
+            break;
+
+        case P_INVIS:
+            turn_on(*quaffer, ISINVIS);
+
+            if (cansee(quaffer->t_pos.y, quaffer->t_pos.x))
+                seemsg("The monster dissappears!");
+
+            break;
+
+        case P_REGENERATE:
+            if (cursed)
+            {
+                quaff(quaffer, P_HEALING, ISCURSED);
+                quaff(quaffer, P_HASTE, ISCURSED);
+            }
+            else
+                turn_on(*quaffer, ISREGEN);
+            break;
+
+        case P_SHERO:
+            if (on(*quaffer, ISFLEE))
+                turn_off(*quaffer, ISFLEE);
+            else
+            {
+                turn_on(*quaffer, SUPERHERO);
+                quaff(quaffer, P_HASTE, ISBLESSED);
+                quaff(quaffer, P_CLEAR, ISNORMAL);
+            }
+            break;
+
+        case P_PHASE:
+            if (cursed)
+                quaffer->t_no_move += HOLDTIME;
+            else
+                turn_on(*quaffer, CANINWALL);
+            break;
+
+        default:
+            debug("'%s' is a strange potion for a monster to quaff!",
+                p_magic[which].mi_name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/random.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,23 @@
+/*
+    random.c - random and associated routines
+   
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include "rogue.h"
+
+void
+ur_srandom(unsigned x)
+{
+    md_srandom(x);
+}
+
+long
+ur_random(void)
+{
+    return( md_random() );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/rings.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,354 @@
+/*
+    rings.c - Routines dealing specificaly with rings
+        
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <string.h>
+#include <stdlib.h>
+#include "rogue.h"
+
+void
+ring_on(void)
+{
+    struct object   *obj;
+    struct linked_list  *item;
+    int ring;
+    char buf[2 * LINELEN];
+
+    if ((item = get_item("put on", RING)) == NULL)
+        return;
+
+    obj = OBJPTR(item);
+
+    if (obj->o_type != RING)
+    {
+        msg("You can't put that on!");
+        return;
+    }
+
+    /* find out which hand to put it on */
+
+    if (is_current(obj))
+    {
+        msg("Already wearing that!");
+        return;
+    }
+
+    if (cur_ring[LEFT_1] == NULL)
+        ring = LEFT_1;
+    else if (cur_ring[LEFT_2] == NULL)
+        ring = LEFT_2;
+    else if (cur_ring[LEFT_3] == NULL)
+        ring = LEFT_3;
+    else if (cur_ring[LEFT_4] == NULL)
+        ring = LEFT_4;
+    else if (cur_ring[LEFT_5] == NULL)
+        ring = LEFT_5;
+    else if (cur_ring[RIGHT_1] == NULL)
+        ring = RIGHT_1;
+    else if (cur_ring[RIGHT_2] == NULL)
+        ring = RIGHT_2;
+    else if (cur_ring[RIGHT_3] == NULL)
+        ring = RIGHT_3;
+    else if (cur_ring[RIGHT_4] == NULL)
+        ring = RIGHT_4;
+    else if (cur_ring[RIGHT_5] == NULL)
+        ring = RIGHT_5;
+    else
+    {
+        msg("You already have on ten rings.");
+        return;
+    }
+
+    cur_ring[ring] = obj;
+
+    /* Calculate the effect it has on the poor guy. */
+
+    switch (obj->o_which)
+    {
+        case R_ADDSTR:
+            pstats.s_str += obj->o_ac;
+            break;
+        case R_ADDHIT:
+            pstats.s_dext += obj->o_ac;
+            break;
+        case R_ADDINTEL:
+            pstats.s_intel += obj->o_ac;
+            break;
+        case R_ADDWISDOM:
+            pstats.s_wisdom += obj->o_ac;
+            break;
+        case R_FREEDOM:
+            turn_off(player, ISHELD);
+            hold_count = 0;
+            break;
+        case R_TRUESEE:
+            if (off(player, PERMBLIND))
+            {
+                turn_on(player, CANTRUESEE);
+                msg("You become more aware of your surroundings.");
+                sight(NULL);
+                light(&hero);
+                mvwaddch(cw, hero.y, hero.x, PLAYER);
+            }
+            break;
+
+        case R_SEEINVIS:
+            if (off(player, PERMBLIND))
+            {
+                turn_on(player, CANTRUESEE);
+                msg("Your eyes begin to tingle.");
+                sight(NULL);
+                light(&hero);
+                mvwaddch(cw, hero.y, hero.x, PLAYER);
+            }
+            break;
+
+        case R_AGGR:
+            aggravate();
+            break;
+
+        case R_CARRYING:
+            updpack();
+            break;
+
+        case R_LEVITATION:
+            msg("You begin to float in the air!");
+            break;
+
+        case R_LIGHT:
+            if (roomin(hero) != NULL)
+            {
+                light(&hero);
+                mvwaddch(cw, hero.y, hero.x, PLAYER);
+            }
+    }
+
+    status(FALSE);
+
+    if (know_items[TYP_RING][obj->o_which] &&
+        guess_items[TYP_RING][obj->o_which])
+    {
+        mem_free(guess_items[TYP_RING][obj->o_which]);
+        guess_items[TYP_RING][obj->o_which] = NULL;
+    }
+    else if (!know_items[TYP_RING][obj->o_which] &&
+         askme &&
+         (obj->o_flags & ISKNOW) == 0 &&
+         guess_items[TYP_RING][obj->o_which] == NULL)
+    {
+        mpos = 0;
+        msg("What do you want to call it? ");
+
+        if (get_string(buf, cw) == NORM)
+        {
+            guess_items[TYP_RING][obj->o_which] =
+                new_alloc(strlen(buf) + 1);
+            strcpy(guess_items[TYP_RING][obj->o_which], buf);
+        }
+        msg("");
+    }
+}
+
+void
+ring_off(void)
+{
+    struct object   *obj;
+    struct linked_list  *item;
+
+    if (cur_ring[LEFT_1] == NULL && cur_ring[LEFT_2] == NULL &&
+        cur_ring[LEFT_3] == NULL && cur_ring[LEFT_4] == NULL &&
+        cur_ring[LEFT_5] == NULL &&
+        cur_ring[RIGHT_1] == NULL && cur_ring[RIGHT_2] == NULL &&
+        cur_ring[RIGHT_3] == NULL && cur_ring[RIGHT_4] == NULL &&
+        cur_ring[RIGHT_5] == NULL)
+    {
+        msg("You aren't wearing any rings.");
+        return;
+    }
+    else if ((item = get_item("remove", RING)) == NULL)
+        return;
+
+    mpos = 0;
+    obj = OBJPTR(item);
+
+    if ((obj = OBJPTR(item)) == NULL)
+        msg("You are not wearing that!");
+
+    if (dropcheck(obj))
+    {
+        switch (obj->o_which)
+        {
+            case R_SEEINVIS:
+                msg("Your eyes stop tingling.");
+                break;
+
+            case R_CARRYING:
+                updpack();
+                break;
+
+            case R_LEVITATION:
+                msg("You float gently to the ground.");
+                break;
+
+            case R_LIGHT:
+                if (roomin(hero) != NULL)
+                {
+                    light(&hero);
+                    mvwaddch(cw, hero.y, hero.x, PLAYER);
+                }
+                break;
+
+            case R_TRUESEE:
+                msg("Your sensory perceptions return to normal.");
+                break;
+        }
+
+        msg("Was wearing %s.", inv_name(obj, LOWERCASE));
+    }
+}
+
+/*
+    ring_eat()
+        how much food does this ring use up?
+*/
+
+int
+ring_eat(int hand)
+{
+    int ret_val = 0;
+    int ac;
+
+    if (cur_ring[hand] != NULL)
+    {
+        switch (cur_ring[hand]->o_which)
+        {
+            case R_REGEN:
+            case R_VREGEN:
+                ret_val = rnd(pstats.s_lvl > 10 ? 10 : pstats.s_lvl);
+
+            case R_DIGEST:
+
+                ac = cur_ring[hand]->o_ac;
+
+                if (ac < 0 && rnd(1 - (ac / 3)) == 0)
+                    ret_val = -ac + 1;
+                else if (rnd((ac / 2) + 2) == 0)
+                    ret_val = -1 - ac;
+                break;
+
+            case R_SEARCH:
+                ret_val = rnd(100) < 33;
+                break;
+				
+			default:
+			    ret_val = 1;
+        }
+    }
+
+    ret_val += rnd(luck);
+
+    return(ret_val);
+}
+
+/*
+    ring_num()
+        print ring bonuses
+*/
+
+char *
+ring_num(struct object *obj, char *buf)
+{
+    char buffer[1024];
+
+    if (buf == NULL)
+        return("A bug in UltraRogue #101");
+
+    buf[0] = 0;
+
+    if (obj->o_flags & ISKNOW)
+    {
+        switch (obj->o_which)
+        {
+            case R_SEARCH:
+            case R_PROTECT:
+            case R_ADDSTR:
+            case R_ADDDAM:
+            case R_ADDHIT:
+            case R_ADDINTEL:
+            case R_ADDWISDOM:
+            case R_CARRYING:
+            case R_VREGEN:
+            case R_RESURRECT:
+            case R_TELCONTROL:
+            case R_REGEN:
+            case R_PIETY:
+            case R_WIZARD:
+                buf[0] = ' ';
+                strcpy(&buf[1], num(obj->o_ac, 0,buffer));
+                break;
+
+            case R_DIGEST:
+                buf[0] = ' ';
+                strcpy(&buf[1], num(obj->o_ac < 0 ?
+                obj->o_ac : obj->o_ac - 1, 0, buffer));
+                break;
+
+            default:
+                if (obj->o_flags & ISCURSED)
+                    strcpy(buf, " cursed");
+                break;
+        }
+    }
+
+    return(buf);
+}
+
+/*
+    ring_value()
+        Return the effect of the specified ring
+*/
+
+#define ISRING(h, r) (cur_ring[h] != NULL && cur_ring[h]->o_which == r)
+
+int
+ring_value(int type)
+{
+    int result = 0;
+
+    if (ISRING(LEFT_1, type))
+        result += cur_ring[LEFT_1]->o_ac;
+    if (ISRING(LEFT_2, type))
+        result += cur_ring[LEFT_2]->o_ac;
+    if (ISRING(LEFT_3, type))
+        result += cur_ring[LEFT_3]->o_ac;
+    if (ISRING(LEFT_4, type))
+        result += cur_ring[LEFT_4]->o_ac;
+    if (ISRING(LEFT_5, type))
+        result += cur_ring[LEFT_5]->o_ac;
+    if (ISRING(RIGHT_1, type))
+        result += cur_ring[RIGHT_1]->o_ac;
+    if (ISRING(RIGHT_2, type))
+        result += cur_ring[RIGHT_2]->o_ac;
+    if (ISRING(RIGHT_3, type))
+        result += cur_ring[RIGHT_3]->o_ac;
+    if (ISRING(RIGHT_4, type))
+        result += cur_ring[RIGHT_4]->o_ac;
+    if (ISRING(RIGHT_5, type))
+        result += cur_ring[RIGHT_5]->o_ac;
+
+    return(result);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/rip.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,661 @@
+/*
+    rip.c - File for the fun ends Death or a total win
+       
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+#include "rogue.h"
+
+static struct sc_ent
+{
+    int sc_lvl;
+    long    sc_score;
+    char    sc_name[76];
+    long    sc_gold;
+    int sc_flags;
+    int sc_level;
+    int   sc_artifacts;
+    int   sc_monster;
+} top_ten[10];
+
+
+static const char *rip[] =
+{
+    "                       __________",
+    "                      /          \\",
+    "                     /    REST    \\",
+    "                    /      IN      \\",
+    "                   /     PEACE      \\",
+    "                  /                  \\",
+    "                  |                  |",
+    "                  |                  |",
+    "                  |    killed by     |",
+    "                  |                  |",
+    "                  |       1993       |",
+    "                 *|     *  *  *      | *",
+    "       ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______",
+    0
+};
+
+/*
+    death()
+        Do something really fun when he dies
+*/
+
+void
+death(int monst)
+{
+    char **dp = (char **) rip, *killer;
+    struct tm   *lt;
+    time_t  date;
+    char    buf[80];
+	int c;
+
+    if (is_wearing(R_RESURRECT) || rnd(wizard ? 3 : 67) == 0)
+    {
+        int die = TRUE;
+
+        if (resurrect-- == 0)
+            msg("You've run out of lives.");
+        else if (!save_resurrect(ring_value(R_RESURRECT)))
+            msg("Your attempt to return from the grave fails.");
+        else
+        {
+            struct linked_list  *item;
+            struct linked_list  *next_item;
+            struct object   *obj;
+            int rm, flags;
+            coord   pos;
+
+            die = FALSE;
+            msg("You feel a sudden warmth and then nothingness.");
+            teleport();
+
+            if (ring_value(R_RESURRECT) > 1 && rnd(10))
+            {
+                pstats.s_hpt = 2 * pstats.s_const;
+                pstats.s_const = max(pstats.s_const - 1, 3);
+            }
+            else
+            {
+                for (item = pack; item != NULL; item = next_item)
+                {
+                    obj = OBJPTR(item);
+
+                    if (obj->o_flags & ISOWNED || obj->o_flags & ISPROT)
+                    {
+                        next_item = next(item);
+                        continue;
+                    }
+
+                    flags = obj->o_flags;
+                    obj->o_flags &= ~ISCURSED;
+                    dropcheck(obj);
+                    obj->o_flags = flags;
+                    next_item = next(item);
+                    rem_pack(obj);
+
+                    if (obj->o_type == ARTIFACT)
+                        has_artifact &= ~(1 << obj->o_which);
+
+                    do
+                    {
+                        rm = rnd_room();
+                        rnd_pos(&rooms[rm], &pos);
+                    }
+                    while(winat(pos.y, pos.x) != FLOOR);
+
+                    obj->o_pos = pos;
+                    add_obj(item, obj->o_pos.y, obj->o_pos.x);
+                }
+
+                pstats.s_hpt = pstats.s_const;
+                pstats.s_const = max(pstats.s_const - roll(2, 2), 3);
+            }
+
+            chg_str(roll(1, 4), TRUE, FALSE);
+            pstats.s_lvl = max(pstats.s_lvl, 1);
+            no_command += 2 + rnd(4);
+
+            if (on(player, ISHUH))
+                lengthen_fuse(FUSE_UNCONFUSE, rnd(8) + HUHDURATION);
+            else
+                light_fuse(FUSE_UNCONFUSE, 0, rnd(8) + HUHDURATION, AFTER);
+
+            turn_on(player, ISHUH);
+            light(&hero);
+        }
+
+        if (die)
+        {
+            wmove(cw, mpos, 0);
+            waddstr(cw, morestr);
+            wrefresh(cw);
+            wait_for(' ');
+        }
+        else
+            return;
+    }
+
+    time(&date);
+    lt = localtime(&date);
+    clear();
+    wclear(cw);
+    move(8, 0);
+
+    while (*dp)
+        printw("%s\n", *dp++);
+
+    mvaddstr(14, 28 - ((int)(strlen(whoami) + 1) / 2), whoami);
+    sprintf(buf, "%d+%ld Points", pstats.s_lvl, pstats.s_exp);
+    mvaddstr(15, 28 - ((int)(strlen(buf) + 1) / 2), buf);
+    killer = killname(monst,buf);
+    mvaddstr(17, 28 - ((int)(strlen(killer) + 1) / 2), killer);
+    mvaddstr(18, 28, (sprintf(prbuf, "%2d", lt->tm_year), prbuf));
+    move(LINES - 1, 0);
+
+    mvaddstr(LINES - 1, 0, retstr);
+
+    while ((c = readcharw(stdscr)) != '\n' && c != '\r')
+        continue;
+    idenpack();
+    wrefresh(cw);
+    refresh();
+
+    score(pstats.s_exp, pstats.s_lvl, KILLED, monst);
+    byebye();
+}
+
+/*
+    score()
+        figure score and post it.
+*/
+
+void
+score(long amount, int lvl, int flags, int monst) /*ARGSUSED*/
+{
+    struct sc_ent   *scp=NULL, *sc2=NULL;
+    int i;
+    char    *killer;
+    char buf[1024];
+
+    static const char *reason[] =
+    {
+        "killed",
+        "quit",
+        "a winner",
+        "a total winner"
+    };
+
+    char    *packend;
+
+    if (flags != WINNER && flags != TOTAL && flags != SCOREIT)
+    {
+        if (flags == CHICKEN)
+            packend = "when you quit";
+        else
+            packend = "at your untimely demise";
+
+        noecho();
+        nl();
+        refresh();
+        showpack(packend);
+    }
+
+    /* Open file and read list */
+
+    if (fd_score == NULL)
+    {
+        printf("No score file opened\n");
+        return;
+    }
+
+    for (scp = top_ten; scp < &top_ten[10]; scp++)
+    {
+        scp->sc_lvl = 0L;
+        scp->sc_score = 0L;
+
+        for (i = 0; i < 76; i++)
+            scp->sc_name[i] = ucrnd(255);
+
+        scp->sc_gold = 0L;
+        scp->sc_flags = rnd(10);
+        scp->sc_level = rnd(10);
+        scp->sc_monster = srnd(10);
+        scp->sc_artifacts = 0;
+    }
+
+    if (flags != SCOREIT)
+    {
+        mvaddstr(LINES - 1, 0, retstr);
+        refresh();
+        fflush(stdout);
+        wait_for('\n');
+    }
+
+    fseek(fd_score, 0L, SEEK_SET);
+    fread(top_ten, sizeof(top_ten), 1, fd_score);
+
+    /* Insert player in list if need be */
+
+    if (!waswizard)
+    {
+        for (scp = top_ten; scp < &top_ten[10]; scp++)
+        {
+            if (lvl > scp->sc_lvl)
+                break;
+
+            if (lvl == scp->sc_lvl && amount > scp->sc_score)
+                break;
+        }
+
+        if (scp < &top_ten[10])
+        {
+            if (flags == WINNER)
+                sc2 = &top_ten[9]; /* LAST WINNER ALWAYS MAKES IT */
+
+            while (sc2 > scp)
+            {
+                *sc2 = sc2[-1];
+                sc2--;
+            }
+            
+			scp->sc_lvl = lvl;
+			scp->sc_gold = purse;
+            scp->sc_score = amount;
+            strcpy(scp->sc_name, whoami);
+			strcat(scp->sc_name,", ");
+			strcat(scp->sc_name, which_class(player.t_ctype));
+            scp->sc_flags = flags;
+			
+            if (flags == WINNER)
+                scp->sc_level = max_level;
+            else
+                scp->sc_level = level;
+				
+            scp->sc_monster = monst;
+	    scp->sc_artifacts = has_artifact;
+
+            sc2 = scp;
+        }
+    }
+
+    if (flags != SCOREIT)
+    {
+        clear();
+        refresh();
+        endwin();
+    }
+
+    /* Print the list */
+
+    printf("\nTop Ten Adventurers:\n%4s %15s %10s %s\n",
+	    "Rank", "Score", "Gold", "Name");
+
+    for (scp = top_ten; scp < &top_ten[10]; scp++)
+    {
+        if (scp->sc_score)
+        {
+		    char lev[20];
+			
+			sprintf(lev, "%ld+%ld", scp->sc_lvl, scp->sc_score);
+            printf("%4d %15s %10ld %s:", scp - top_ten + 1, 
+			       lev,
+                   scp->sc_gold,
+                   scp->sc_name);
+
+            if (scp->sc_artifacts)
+            {
+                char  thangs[80];
+                int   n;
+                int   first = TRUE;
+
+                thangs[0] = '\0';
+
+                for (n = 0; n <= maxartifact; n++)
+                {
+                    if (scp->sc_artifacts & (1 << n))
+                    {
+                        if (strlen(thangs))
+                            strcat(thangs, ", ");
+
+                        if (first)
+                        {
+                            strcat(thangs, "retrieved ");
+                            first = FALSE;
+                        }
+
+                        if (45 - strlen(thangs) < strlen(arts[n].ar_name))
+                        {
+                            printf("%s\n%32s", thangs," ");
+                            thangs[0] = '\0';
+                        }
+                        strcat(thangs, arts[n].ar_name);
+                    }
+                }
+
+                if (strlen(thangs))
+                    printf("%s,", thangs);
+
+                printf("\n%32s"," ");
+            }
+
+            printf("%s on level %d",reason[scp->sc_flags],scp->sc_level);
+
+            if (scp->sc_flags == 0)
+            {
+                printf(" by \n%32s"," ");
+                killer = killname(scp->sc_monster, buf);
+                printf(" %s", killer);
+            }
+
+            putchar('\n');
+        }
+    }
+
+    if (sc2 != NULL)
+    {
+        fseek(fd_score, 0L, SEEK_SET);
+        /* Update the list file */
+        fwrite(top_ten, sizeof(top_ten), 1, fd_score);
+    }
+
+    fclose(fd_score);
+}
+
+void
+total_winner(void)
+{
+    struct linked_list  *item;
+    struct object   *obj;
+    int worth, oldpurse;
+    char    c;
+    struct linked_list  *bag = NULL;
+
+    clear();
+    standout();
+    addstr("                                                               \n");
+    addstr("  @   @               @   @           @          @@@  @     @  \n");
+    addstr("  @   @               @@ @@           @           @   @     @  \n");
+    addstr("  @   @  @@@  @   @   @ @ @  @@@   @@@@  @@@      @  @@@    @  \n");
+    addstr("   @@@@ @   @ @   @   @   @     @ @   @ @   @     @   @     @  \n");
+    addstr("      @ @   @ @   @   @   @  @@@@ @   @ @@@@@     @   @     @  \n");
+    addstr("  @   @ @   @ @  @@   @   @ @   @ @   @ @         @   @  @     \n");
+    addstr("   @@@   @@@   @@ @   @   @  @@@@  @@@@  @@@     @@@   @@   @  \n");
+    addstr("                                                               \n");
+    addstr("     Congratulations, you have made it to the light of day!    \n");
+    standend();
+    addstr("\nYou have joined the elite ranks of those who have \n");
+    addstr("escaped the Dungeons of Doom alive.  You journey home \n");
+    addstr("and sell all your loot at a great profit.\n");
+    addstr("The White Council approves the recommendation of\n");
+
+    if (player.t_ctype == C_FIGHTER)
+        addstr("the fighters guild and appoints you Lord Protector\n");
+    else if (player.t_ctype == C_ASSASIN)
+        addstr("the assassins guild and appoints you Master Murderer\n");
+    else if (player.t_ctype == C_NINJA)
+        addstr("the ninja guild and appoints you Master of the Wind\n");
+    else if (player.t_ctype == C_ILLUSION)
+        addstr("the illusionists guild and appoints you Master Wizard\n");
+    else if (player.t_ctype == C_MAGICIAN)
+        addstr("the magicians guild and appoints you Master Wizard\n");
+    else if (player.t_ctype == C_CLERIC)
+        addstr("the temple priests and appoints you Master of the Flowers\n");
+    else if (player.t_ctype == C_DRUID)
+        addstr("the temple priests and appoints you Master of the Flowers\n");
+    else if (player.t_ctype == C_RANGER)
+        addstr("the rangers guild and appoints you Master Ranger\n");
+    else if (player.t_ctype == C_PALADIN)
+        addstr("the paladins guild and appoints you Master Paladin\n");
+    else if (player.t_ctype == C_THIEF)
+    {
+        addstr("the thieves guild under protest and appoints you\n");
+        addstr("Master of the Highways\n");
+    }
+
+    addstr("of the Land Between the Mountains.\n");
+    mvaddstr(LINES - 1, 0, spacemsg);
+    refresh();
+    wait_for(' ');
+    clear();
+    idenpack();
+    oldpurse = purse;
+    mvaddstr(0, 0, "   Worth  Item");
+
+    for (c = 'a', item = pack; item != NULL; c++, item = next(item))
+    {
+        obj = OBJPTR(item);
+        worth = get_worth(obj);
+        purse += worth;
+
+        if (obj->o_type == ARTIFACT && obj->o_which == TR_PURSE)
+            bag = obj->o_bag;
+
+        mvprintw(c - 'a' + 1, 0, "%c) %8d  %s", c,
+             worth, inv_name(obj, UPPERCASE));
+    }
+
+    if (bag != NULL)
+    {
+        mvaddstr(LINES - 1, 0, morestr);
+        refresh();
+        wait_for(' ');
+        clear();
+        mvprintw(0, 0, "Contents of the Magic Purse of Yendor:\n");
+
+        for (c = 'a', item = bag; item != NULL; c++, item = next(item))
+        {
+            obj = OBJPTR(item);
+            worth = get_worth(obj);
+            whatis(item);
+            purse += worth;
+            mvprintw(c - 'a' + 1, 0, "%c) %8d %s\n", c,
+                 worth, inv_name(obj, UPPERCASE));
+        }
+    }
+
+    mvprintw(c - 'a' + 1, 0, "   %6d  Gold Pieces          ", oldpurse);
+    refresh();
+
+    if (has_artifact == 255)
+        score(pstats.s_exp, pstats.s_lvl, TOTAL, 0);
+    else
+        score(pstats.s_exp, pstats.s_lvl, WINNER, 0);
+
+    byebye();
+}
+
+char *
+killname(int monst, char *buf)
+{
+    if (buf == NULL)
+        return("A bug in UltraRogue #102");
+
+    if (monst >= 0)
+    {
+        switch (monsters[monst].m_name[0])
+        {
+            case 'a':
+            case 'e':
+            case 'i':
+            case 'o':
+            case 'u':
+                sprintf(buf, "an %s", monsters[monst].m_name);
+                break;
+            default:
+                sprintf(buf, "a %s", monsters[monst].m_name);
+        }
+
+        return(buf);
+    }
+    else
+        switch(monst)
+        {
+            case D_ARROW:
+                strcpy(buf, "an arrow"); break;
+            case D_DART:
+                strcpy(buf, "a dart"); break;
+            case D_BOLT:
+                strcpy(buf, "a bolt"); break;
+            case D_POISON:
+                strcpy(buf, "poison"); break;
+            case D_POTION:
+                strcpy(buf, "a cursed potion"); break;
+            case D_PETRIFY:
+                strcpy(buf, "petrification"); break;
+            case D_SUFFOCATION:
+                strcpy(buf, "suffocation"); break;
+            case D_INFESTATION:
+                strcpy(buf, "a parasite"); break;
+            case D_DROWN:
+                strcpy(buf, "drowning"); break;
+            case D_FALL:
+                strcpy(buf, "falling"); break;
+            case D_FIRE:
+                strcpy(buf, "slow boiling in oil"); break;
+            case D_SPELLFUMBLE:
+                strcpy(buf, "a botched spell"); break;
+            case D_DRAINLIFE:
+                strcpy(buf, "a drain life spell"); break;
+            case D_ARTIFACT:
+                strcpy(buf, "an artifact of the gods"); break;
+            case D_GODWRATH:
+                strcpy(buf, "divine retribution"); break;
+            case D_CLUMSY:
+                strcpy(buf, "excessive clumsyness"); break;
+            default:
+                strcpy(buf, "stupidity"); break;
+        }
+
+    return(buf);
+}
+
+/*
+    showpack()
+        Display the contents of the hero's pack
+*/
+
+void
+showpack(char *howso)
+{
+    char    *iname;
+    unsigned int worth;
+    int cnt, ch, oldpurse;
+    struct linked_list  *item;
+    struct object   *obj;
+    struct linked_list  *bag = NULL;
+
+    cnt = 1;
+    clear();
+    mvprintw(0, 0, "Contents of your pack %s:\n", howso);
+    ch = 0;
+    oldpurse = purse;
+    purse = 0;
+
+    for (item = pack; item != NULL; item = next(item))
+    {
+        obj = OBJPTR(item);
+        worth = get_worth(obj);
+        whatis(item);
+        purse += worth;
+
+        if (obj->o_type == ARTIFACT && obj->o_which == TR_PURSE)
+            bag = obj->o_bag;
+
+        iname = inv_name(obj, UPPERCASE);
+        mvprintw(cnt, 0, "%d) %s\n", ch, iname);
+        ch += 1;
+
+        if (++cnt > LINES - 5 && next(item) != NULL)
+        {
+            cnt = 1;
+            mvaddstr(LINES - 1, 0, morestr);
+            refresh();
+            wait_for(' ');
+            clear();
+        }
+    }
+
+    if (bag != NULL)
+    {
+        mvaddstr(LINES - 1, 0, morestr);
+        refresh();
+        wait_for(' ');
+        clear();
+        cnt = 1;
+        ch = 0;
+
+        mvprintw(0, 0, "Contents of the Magic Purse of Yendor %s:\n", howso);
+
+        for (item = bag; item != NULL; item = next(item))
+        {
+            obj = OBJPTR(item);
+            worth = get_worth(obj);
+            whatis(item);
+            purse += worth;
+            mvprintw(cnt, 0, "%d) %s\n", ch, inv_name(obj, UPPERCASE));
+            ch += 1;
+
+            if (++cnt > LINES - 5 && next(item) != NULL)
+            {
+                cnt = 1;
+                mvaddstr(LINES - 1, 0, morestr);
+                refresh();
+                wait_for(' ');
+                clear();
+            }
+        }
+    }
+
+    mvprintw(cnt + 1, 0, "Carrying %d gold pieces", oldpurse);
+    mvprintw(cnt + 2, 0, "Carrying objects worth %d gold pieces", purse);
+    purse += oldpurse;
+    refresh();
+}
+
+void
+byebye(void)
+{
+    endwin();
+    printf("\n");
+    exit(0);
+}
+
+/*
+    save_resurrect()
+        chance of resurrection according to modifed D&D probabilities
+*/
+
+int
+save_resurrect(int bonus)
+{
+    int need, adjust;
+
+    adjust = pstats.s_const + bonus - luck;
+
+    if (adjust > 17)
+        return(TRUE);
+    else if (adjust < 14)
+        need = 5 * (adjust + 5);
+    else
+        need = 90 + 2 * (adjust - 13);
+
+    return(roll(1, 100) < need);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/rogue.h	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1815 @@
+/*
+    rogue.h - A very large header file
+ 
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1984, 1991, 1997 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifndef LINT
+#include <curses.h>
+#else
+#include "lint-curses.h"
+#endif
+
+#define SHOTPENALTY 2       /* In line of sight of missile */
+#define DOORPENALTY 1       /* Moving out of current room */
+
+/* Maximum number of different things */
+#define MAXROOMS    9   /* max rooms per normal level */
+#define MAXDOORS    4   /* max doors to a room */
+#define MAXOBJ      6   /* max number of items to find on a level */
+#define MAXTREAS    30  /* max number monsters/treasure in treasure room */
+#define MAXTRAPS    80  /* max traps per level */
+#define MAXTRPTRY   16  /* max attempts/level allowed for setting traps */
+#define MAXPURCH    8   /* max purchases per trading post visit */
+#define NUMMONST    (sizeof(monsters) / sizeof(struct monster) - 2)
+#define NUMSUMMON   48  /* number of creatures that can summon hero */
+#define NLEVMONS    8   /* number of new monsters per level */
+#define LINELEN     512 /* characters in a buffer */
+
+/* The character types */
+#define C_FIGHTER    0
+#define C_PALADIN    1
+#define C_RANGER     2
+#define C_CLERIC     3
+#define C_DRUID      4
+#define C_MAGICIAN   5
+#define C_ILLUSION   6
+#define C_THIEF      7
+#define C_ASSASIN    8
+#define C_NINJA      9
+#define C_MONSTER   10
+#define C_NOTSET    11  /* Must not be a value from above */
+
+/* used for ring stuff */
+#define LEFT_1  0
+#define LEFT_2  1
+#define LEFT_3  2
+#define LEFT_4  3
+#define LEFT_5  4
+#define RIGHT_1 5
+#define RIGHT_2 6
+#define RIGHT_3 7
+#define RIGHT_4 8
+#define RIGHT_5 9
+
+/* All the fun defines */
+#define next(ptr) ((ptr)?(ptr->l_next):NULL)
+#define prev(ptr) ((ptr)?(ptr->l_prev):NULL)
+#define identifier(ptr) (ptr->o_ident)
+#define winat(y,x) ( (char) \
+ ((mvwinch(mw,y,x) == ' ') ? mvwinch(stdscr,y,x) : winch(mw))  )
+
+#define debug if (wizard && wiz_verbose) msg
+#define verify(b) if (b) verify_function(__FILE__, __LINE__);
+#define DISTANCE(c1, c2)  ( ((c2).x - (c1).x)*((c2).x - (c1).x) + \
+                            ((c2).y - (c1).y)*((c2).y - (c1).y) )
+
+#define xyDISTANCE(y1, x1, y2, x2) ((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1))
+#define OBJPTR(what)    ((*what).data.obj)
+#define THINGPTR(what)  ((*what).data.th)
+#define ce(a, b) ((a).x == (b).x && (a).y == (b).y)
+#define hero player.t_pos
+#define pstats player.t_stats
+#define max_stats player.maxstats
+#define pack player.t_pack
+#define attach(a, b) _attach(&a, b)
+#define detach(a, b) _detach(&a, b)
+#define free_list(a) _free_list(&a)
+#ifndef max
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#define GOLDCALC (rnd(50 + 30 * level) + 2)
+#define o_charges o_ac
+#define mi_wght mi_worth
+
+/* Things that appear on the screens */
+#define WALL        ' '
+#define PASSAGE     '#'
+#define DOOR        '+'
+#define FLOOR       '.'
+#define VPLAYER     '@'
+#define IPLAYER     '_'
+#define POST        '^'
+#define LAIR        '('
+#define RUSTTRAP    ';'
+#define TRAPDOOR    '>'
+#define ARROWTRAP   '{'
+#define SLEEPTRAP   '$'
+#define BEARTRAP    '}'
+#define TELTRAP     '~'
+#define DARTTRAP    '`'
+#define POOL        '"'
+#define MAZETRAP    '\\'
+#define FIRETRAP    '<'
+#define POISONTRAP  '['
+#define ARTIFACT    ','
+#define SECRETDOOR  '&'
+#define STAIRS      '%'
+#define GOLD        '*'
+#define POTION      '!'
+#define SCROLL      '?'
+#define MAGIC       '$'
+#define BMAGIC      '>' /* Blessed magic */
+#define CMAGIC      '<' /* Cursed  magic */
+#define FOOD        ':'
+#define WEAPON      ')'
+#define ARMOR       ']'
+#define RING        '='
+#define STICK       '/'
+
+/* Various constants */
+#define HOLDTIME      2
+#define BEARTIME      3
+#define SLEEPTIME     4
+#define FREEZETIME    6
+#define STINKTIME     6
+#define CHILLTIME     (roll(2, 4))
+#define STONETIME     8
+#define SICKTIME     10
+#define CLRDURATION  15
+#define HUHDURATION  20
+#define SMELLTIME    20
+#define HEROTIME     20
+#define HEALTIME     30
+#define WANDERTIME   140
+#define GONETIME    200
+#define PHASEDURATION   300
+#define SEEDURATION 850
+
+#define STPOS         0
+#define BEFORE        1
+#define AFTER         2
+
+#define MORETIME     150
+#define HUNGERTIME  1300
+#define STOMACHSIZE 2000
+
+#define BOLT_LENGTH 10
+#define MARKLEN     20
+
+#define LINEFEED    10
+#define CARRIAGE_RETURN 13
+#define ESCAPE      27
+
+/* Adjustments for save against things */
+#define VS_POISON       0
+#define VS_PARALYZATION     0
+#define VS_DEATH        0
+#define VS_PETRIFICATION    1
+#define VS_WAND         2
+#define VS_BREATH       3
+#define VS_MAGIC        4
+
+/*attributes for treasures in dungeon */
+#define ISNORMAL    0x00000000UL /* Neither blessed nor cursed */
+#define ISCURSED    0x00000001UL /* cursed */
+#define ISKNOW      0x00000002UL /* has been identified */
+#define ISPOST      0x00000004UL /* object is in a trading post */
+#define ISMETAL     0x00000008UL /* is metallic */
+#define ISPROT      0x00000010UL /* object is protected */
+#define ISBLESSED   0x00000020UL /* blessed */
+#define ISZAPPED    0x00000040UL /* weapon has been charged by dragon */
+#define ISVORPED    0x00000080UL /* vorpalized weapon */
+#define ISSILVER    0x00000100UL /* silver weapon */
+#define ISPOISON    0x00000200UL /* poisoned weapon */
+#define CANRETURN   0x00000400UL /* weapon returns if misses */
+#define ISOWNED     0x00000800UL /* weapon returns always */
+#define ISLOST      0x00001000UL /* weapon always disappears */
+#define ISMISL      0x00002000UL /* missile weapon */
+#define ISMANY      0x00004000UL /* show up in a group */
+#define CANBURN     0x00008000UL /* burns monsters */
+#define ISSHARP     0x00010000UL /* cutting edge */
+#define ISTWOH      0x00020000UL /* needs two hands to wield */
+#define ISLITTLE    0x00040000UL /* small weapon */
+#define ISLAUNCHER  0x00080000UL /* used to throw other weapons */
+#define TYP_MAGIC_MASK  0x0f000000UL
+#define POT_MAGIC   0x01000000UL
+#define SCR_MAGIC   0x02000000UL
+#define ZAP_MAGIC   0x04000000UL
+#define SP_WIZARD   0x10000000UL /* only wizards */
+#define SP_ILLUSION 0x20000000UL /* only illusionists */
+#define SP_CLERIC   0x40000000UL /* only clerics/paladins */
+#define SP_DRUID    0x80000000UL /* only druids/rangers */
+#define SP_MAGIC    0x30000000UL /* wizard or illusionist */
+#define SP_PRAYER   0xc0000000UL /* cleric or druid */
+#define SP_ALL      0xf0000000UL /* all special classes */
+#define _TWO_       ISBLESSED   /* more powerful spell */
+
+/* Various flag bits */
+#define ISDARK      0x00000001UL
+#define ISGONE      0x00000002UL
+#define ISTREAS     0x00000004UL
+#define ISFOUND     0x00000008UL
+#define ISTHIEFSET  0x00000010UL
+#define WASDARK     0x00000020UL
+
+/* struct thing t_flags (might include player) for monster attributes */
+#define ISBLIND     0x00000001UL
+#define ISINWALL    0x00000002UL
+#define ISRUN       0x00000004UL
+#define ISFLEE      0x00000008UL
+#define ISINVIS     0x00000010UL
+#define ISMEAN      0x00000020UL
+#define ISGREED     0x00000040UL
+#define CANSHOOT    0x00000080UL
+#define ISHELD      0x00000100UL
+#define ISHUH       0x00000200UL
+#define ISREGEN     0x00000400UL
+#define CANHUH      0x00000800UL
+#define CANSEE      0x00001000UL
+#define HASFIRE     0x00002000UL
+#define ISSLOW      0x00004000UL
+#define ISHASTE     0x00008000UL
+#define ISCLEAR     0x00010000UL
+#define CANINWALL   0x00020000UL
+#define ISDISGUISE  0x00040000UL
+#define CANBLINK    0x00080000UL
+#define CANSNORE    0x00100000UL
+#define HALFDAMAGE  0x00200000UL
+#define CANSUCK     0x00400000UL
+#define CANRUST     0x00800000UL
+#define CANPOISON   0x01000000UL
+#define CANDRAIN    0x02000000UL
+#define ISUNIQUE    0x04000000UL
+#define STEALGOLD   0x08000000UL
+#define STEALMAGIC  0x10000001UL
+#define CANDISEASE  0x10000002UL
+#define HASDISEASE  0x10000004UL
+#define CANSUFFOCATE    0x10000008UL
+#define DIDSUFFOCATE    0x10000010UL
+#define BOLTDIVIDE  0x10000020UL
+#define BLOWDIVIDE  0x10000040UL
+#define NOCOLD      0x10000080UL
+#define TOUCHFEAR   0x10000100UL
+#define BMAGICHIT   0x10000200UL
+#define NOFIRE      0x10000400UL
+#define NOBOLT      0x10000800UL
+#define CARRYGOLD   0x10001000UL
+#define CANITCH     0x10002000UL
+#define HASITCH     0x10004000UL
+#define DIDDRAIN    0x10008000UL
+#define WASTURNED   0x10010000UL
+#define CANSELL     0x10020000UL
+#define CANBLIND    0x10040000UL
+#define CANBBURN    0x10080000UL
+#define ISCHARMED   0x10100000UL
+#define CANSPEAK    0x10200000UL
+#define CANFLY      0x10400000UL
+#define ISFRIENDLY  0x10800000UL
+#define CANHEAR     0x11000000UL
+#define ISDEAF      0x12000000UL
+#define CANSCENT    0x14000000UL
+#define ISUNSMELL   0x18000000UL
+#define WILLRUST    0x20000001UL
+#define WILLROT     0x20000002UL
+#define SUPEREAT    0x20000004UL
+#define PERMBLIND   0x20000008UL
+#define MAGICHIT    0x20000010UL
+#define CANINFEST   0x20000020UL
+#define HASINFEST   0x20000040UL
+#define NOMOVE      0x20000080UL
+#define CANSHRIEK   0x20000100UL
+#define CANDRAW     0x20000200UL
+#define CANSMELL    0x20000400UL
+#define CANPARALYZE 0x20000800UL
+#define CANROT      0x20001000UL
+#define ISSCAVENGE  0x20002000UL
+#define DOROT       0x20004000UL
+#define CANSTINK    0x20008000UL
+#define HASSTINK    0x20010000UL
+#define ISSHADOW    0x20020000UL
+#define CANCHILL    0x20040000UL
+#define CANHUG      0x20080000UL
+#define CANSURPRISE 0x20100000UL
+#define CANFRIGHTEN 0x20200000UL
+#define CANSUMMON   0x20400000UL
+#define TOUCHSTONE  0x20800000UL
+#define LOOKSTONE   0x21000000UL
+#define CANHOLD     0x22000000UL
+#define DIDHOLD     0x24000000UL
+#define DOUBLEDRAIN 0x28000000UL
+#define ISUNDEAD    0x30000001UL
+#define BLESSMAP    0x30000002UL
+#define BLESSGOLD   0x30000004UL
+#define BLESSMONS   0x30000008UL
+#define BLESSMAGIC  0x30000010UL
+#define BLESSFOOD   0x30000020UL
+#define CANBRANDOM  0x30000040UL /* Types of breath */
+#define CANBACID    0x30000080UL
+#define CANBFIRE    0x30000100UL
+#define CANBBOLT    0x30000200UL
+#define CANBGAS     0x30000400UL
+#define CANBICE     0x30000800UL
+#define CANBPGAS    0x30001000UL /* Paralyze gas */
+#define CANBSGAS    0x30002000UL /* Sleeping gas */
+#define CANBSLGAS   0x30004000UL /* Slow gas */
+#define CANBFGAS    0x30008000UL /* Fear gas */
+#define CANBREATHE  0x3000ffc0UL /* Can it breathe at all? */
+#define STUMBLER    0x30010000UL
+#define POWEREAT    0x30020000UL
+#define ISELECTRIC  0x30040000UL
+#define HASOXYGEN   0x30080000UL /* Doesn't need to breath air */
+#define POWERDEXT   0x30100000UL
+#define POWERSTR    0x30200000UL
+#define POWERWISDOM 0x30400000UL
+#define POWERINTEL  0x30800000UL
+#define POWERCONST  0x31000000UL
+#define SUPERHERO   0x32000000UL
+#define ISUNHERO    0x34000000UL
+#define CANCAST     0x38000000UL
+#define CANTRAMPLE  0x40000001UL
+#define CANSWIM     0x40000002UL
+#define LOOKSLOW    0x40000004UL
+#define CANWIELD    0x40000008UL
+#define CANDARKEN   0x40000010UL
+#define ISFAST      0x40000020UL
+#define CANBARGAIN  0x40000040UL
+#define NOMETAL     0x40000080UL
+#define CANSPORE    0x40000100UL
+#define NOSHARP     0x40000200UL
+#define DRAINWISDOM 0x40000400UL
+#define DRAINBRAIN  0x40000800UL
+#define ISLARGE     0x40001000UL
+#define ISSMALL     0x40002000UL
+#define CANSTAB     0x40004000UL
+#define ISFLOCK     0x40008000UL
+#define ISSWARM     0x40010000UL
+#define CANSTICK    0x40020000UL
+#define CANTANGLE   0x40040000UL
+#define DRAINMAGIC  0x40080000UL
+#define SHOOTNEEDLE 0x40100000UL
+#define CANZAP      0x40200000UL
+#define HASARMOR    0x40400000UL
+#define CANTELEPORT 0x40800000UL
+#define ISBERSERK   0x41000000UL
+#define ISFAMILIAR  0x42000000UL
+#define HASFAMILIAR 0x44000000UL
+#define SUMMONING   0x48000000UL
+#define CANREFLECT  0x50000001UL
+#define LOWFRIENDLY 0x50000002UL
+#define MEDFRIENDLY 0x50000004UL
+#define HIGHFRIENDLY    0x50000008UL
+#define MAGICATTRACT    0x50000010UL
+#define ISGOD       0x50000020UL
+#define CANLIGHT    0x50000040UL
+#define HASSHIELD   0x50000080UL
+#define HASMSHIELD  0x50000100UL
+#define LOWCAST     0x50000200UL
+#define MEDCAST     0x50000400UL
+#define HIGHCAST    0x50000800UL
+#define WASSUMMONED 0x50001000UL
+#define HASSUMMONED 0x50002000UL
+#define CANTRUESEE  0x50004000UL
+
+
+#define FLAGSHIFT       28UL
+#define FLAGINDEX       0x0000000fL
+#define FLAGMASK        0x0fffffffL
+
+/* on - check if a monster flag is on */
+#define on(th, flag) \
+        ((th).t_flags[(flag >> FLAGSHIFT) & FLAGINDEX] & (flag & FLAGMASK))
+
+/* off - check if a monster flag is off */
+#define off(th, flag) \
+        (!((th).t_flags[(flag >> FLAGSHIFT) & FLAGINDEX] & (flag & FLAGMASK)))
+
+/* turn_on - turn on a monster flag */
+#define turn_on(th, flag) \
+        ( (th).t_flags[(flag >> FLAGSHIFT) & FLAGINDEX] |= (flag & FLAGMASK))
+
+/* turn_off - turn off a monster flag */
+#define turn_off(th, flag) \
+        ( (th).t_flags[(flag >> FLAGSHIFT) & FLAGINDEX] &= ~(flag & FLAGMASK))
+
+#define SAME_POS(c1,c2) ( (c1.x == c2.x) && (c1.y == c2.y) )
+
+/* types of things */
+/* All magic spells duplicate a potion, scroll, or stick effect */
+
+#define TYP_POTION  0
+#define TYP_SCROLL  1
+#define TYP_RING    2
+#define TYP_STICK   3
+#define MAXMAGICTYPES   4   /* max number of items in magic class */
+#define MAXMAGICITEMS   50  /* max number of items in magic class */
+#define TYP_FOOD    4
+#define TYP_WEAPON  5
+#define TYP_ARMOR   6
+#define TYP_ARTIFACT    7
+#define NUMTHINGS   (sizeof(things) / sizeof(struct magic_item))
+
+/* Artifact types */
+#define TR_PURSE    0
+#define TR_PHIAL    1
+#define TR_AMULET   2
+#define TR_PALANTIR 3
+#define TR_CROWN    4
+#define TR_SCEPTRE  5
+#define TR_SILMARIL 6
+#define TR_WAND     7
+#define MAXARTIFACT (sizeof(arts) / sizeof(struct init_artifact))
+
+/* Artifact flags */
+#define ISUSED      01
+#define ISACTIVE    02
+
+/* Potion types - add also to magic_item.c and potions.c */
+#define P_CLEAR     0
+#define P_GAINABIL  1
+#define P_SEEINVIS  2
+#define P_HEALING   3
+#define P_MONSTDET  4
+#define P_TREASDET  5
+#define P_RAISELEVEL    6
+#define P_HASTE     7
+#define P_RESTORE   8
+#define P_PHASE     9
+#define P_INVIS     10
+#define P_SMELL     11
+#define P_HEAR      12
+#define P_SHERO     13
+#define P_DISGUISE  14
+#define P_FIRERESIST    15
+#define P_COLDRESIST    16
+#define P_HASOXYGEN 17
+#define P_LEVITATION    18
+#define P_REGENERATE    19
+#define P_SHIELD    20
+#define P_TRUESEE   21
+#define MAXPOTIONS  22
+
+/* Scroll types - add also to magic_item.c and scrolls.c */
+#define S_CONFUSE   0
+#define S_MAP       1
+#define S_LIGHT     2
+#define S_HOLD      3
+#define S_SLEEP     4
+#define S_ENCHANT   5
+#define S_IDENTIFY  6
+#define S_SCARE     7
+#define S_GFIND     8
+#define S_SELFTELEP 9
+#define S_CREATE    10
+#define S_REMOVECURSE   11
+#define S_PETRIFY   12
+#define S_GENOCIDE  13
+#define S_CURING    14
+#define S_MAKEITEMEM    15
+#define S_PROTECT   16
+#define S_NOTHING   17
+#define S_SILVER    18
+#define S_OWNERSHIP 19
+#define S_FOODDET   20
+#define S_ELECTRIFY 21
+#define S_CHARM     22
+#define S_SUMMON    23
+#define S_REFLECT   24
+#define S_SUMFAMILIAR   25
+#define S_FEAR      26
+#define S_MSHIELD   27
+#define MAXSCROLLS  28
+
+/* Rod/Wand/Staff types - add also to magic_item.c and sticks.c */
+#define WS_LIGHT    0
+#define WS_HIT      1
+#define WS_ELECT    2
+#define WS_FIRE     3
+#define WS_COLD     4
+#define WS_POLYMORPH    5
+#define WS_MISSILE  6
+#define WS_SLOW_M   7
+#define WS_DRAIN    8
+#define WS_CHARGE   9
+#define WS_MONSTELEP    10
+#define WS_CANCEL   11
+#define WS_CONFMON  12
+#define WS_DISINTEGRATE 13
+#define WS_ANTIMATTER   14
+#define WS_PARALYZE 15
+#define WS_XENOHEALING  16
+#define WS_NOTHING  17
+#define WS_INVIS    18
+#define WS_BLAST    19
+#define WS_WEB      20
+#define WS_KNOCK    21
+#define WS_CLOSE    22
+#define MAXSTICKS   23
+
+/* Ring types */
+#define R_PROTECT   0
+#define R_ADDSTR    1
+#define R_SUSABILITY    2
+#define R_SEARCH    3
+#define R_SEEINVIS  4
+#define R_ALERT     5
+#define R_AGGR      6
+#define R_ADDHIT    7
+#define R_ADDDAM    8
+#define R_REGEN     9
+#define R_DIGEST    10
+#define R_TELEPORT  11
+#define R_STEALTH   12
+#define R_ADDINTEL  13
+#define R_ADDWISDOM 14
+#define R_HEALTH    15
+#define R_VREGEN    16
+#define R_LIGHT     17
+#define R_DELUSION  18
+#define R_CARRYING  19
+#define R_ADORNMENT 20
+#define R_LEVITATION    21
+#define R_FIRERESIST    22
+#define R_COLDRESIST    23
+#define R_ELECTRESIST   24
+#define R_RESURRECT 25
+#define R_BREATHE   26
+#define R_FREEDOM   27
+#define R_WIZARD    28
+#define R_PIETY     29
+#define R_TELCONTROL    30
+#define R_TRUESEE   31
+#define MAXRINGS    32
+
+/* Weapon types */
+#define SLING       0   /* sling */
+#define ROCK        1   /* rocks */
+#define BULLET      2   /* sling bullet */
+#define BOW     3   /* short bow */
+#define ARROW       4   /* arrow */
+#define SILVERARROW 5   /* silver arrows */
+#define FLAMEARROW  6   /* flaming arrows */
+#define FOOTBOW     7   /* footbow */
+#define FBBOLT      8   /* footbow bolt */
+#define CROSSBOW    9   /* crossbow */
+#define BOLT        10  /* crossbow bolt */
+
+#define DART        11  /* darts */
+#define DAGGER      12  /* dagger */
+#define HAMMER      13  /* hammer */
+#define LEUKU       14  /* leuku */
+#define JAVELIN     15  /* javelin */
+#define TOMAHAWK    16  /* tomahawk */
+#define MACHETE     17  /* machete */
+#define THROW_AXE   18  /* throwing axe */
+#define SHORT_SPEAR 19  /* spear */
+#define BOOMERANG   20  /* boomerangs */
+#define LONG_SPEAR  21  /* spear */
+#define SHURIKEN    22  /* shurikens */
+#define MOLOTOV     23  /* molotov cocktails */
+#define GRENADE     24  /* grenade for explosions */
+#define CLUB        25  /* club */
+#define PITCHFORK   26  /* pitchfork */
+#define SHORT_SWORD 27  /* short sword */
+#define HAND_AXE    28  /* hand axe */
+#define PARTISAN    29  /* partisan */
+#define GRAIN_FLAIL 30  /* grain flail */
+#define SINGLESTICK 31  /* singlestick */
+#define RAPIER      32  /* rapier */
+#define SICKLE      33  /* sickle */
+#define HATCHET     34  /* hatchet */
+#define SCIMITAR    35  /* scimitar */
+#define LIGHT_MACE  36  /* mace */
+#define MORNINGSTAR 37  /* morning star */
+#define BROAD_SWORD 38  /* broad sword */
+#define MINER_PICK  39  /* miner's pick */
+#define GUISARME    40  /* guisarme */
+#define WAR_FLAIL   41  /* war flail */
+#define CRYSKNIFE   42  /* crysknife */
+#define BATTLE_AXE  43  /* battle axe */
+#define CUTLASS     44  /* cutlass sword */
+#define GLAIVE      45  /* glaive */
+#define PERTUSKA    46  /* pertuska */
+#define LONG_SWORD  47  /* long sword */
+#define LANCE       48  /* lance */
+#define RANSEUR     49  /* ranseur */
+#define SABRE       50  /* sabre */
+#define SPETUM      51  /* spetum */
+#define HALBERD     52  /* halberd */
+#define TRIDENT     53  /* trident */
+#define WAR_PICK    54  /* war pick */
+#define BARDICHE    55  /* bardiche */
+#define HEAVY_MACE  56  /* mace */
+#define SCYTHE      57  /* great scythe */
+#define QUARTERSTAFF    58  /* quarter staff */
+#define BAST_SWORD  59  /* bastard sword */
+#define PIKE        60  /* pike */
+#define TWO_FLAIL   61  /* two-handed flail */
+#define TWO_MAUL    62  /* two-handed maul */
+#define TWO_PICK    63  /* two-handed pick */
+#define TWO_SWORD   64  /* two-handed sword */
+#define CLAYMORE    65  /* claymore sword */
+#define MAXWEAPONS  (sizeof(weaps) / sizeof(struct init_weps))
+#define NONE        100 /* no weapon */
+
+/* Armor types */
+#define SOFT_LEATHER    0
+#define CUIRBOLILLI 1
+#define HEAVY_LEATHER   2
+#define RING_MAIL   3
+#define STUDDED_LEATHER 4
+#define SCALE_MAIL  5
+#define PADDED_ARMOR    6
+#define CHAIN_MAIL  7
+#define BRIGANDINE  8
+#define SPLINT_MAIL 9
+#define BANDED_MAIL 10
+#define GOOD_CHAIN  11
+#define PLATE_MAIL  12
+#define PLATE_ARMOR 13
+#define MITHRIL     14
+#define CRYSTAL_ARMOR   15
+#define MAXARMORS   (sizeof(armors) / sizeof(struct init_armor))
+
+/* Food types */
+#define FD_RATION   0
+#define FD_FRUIT    1
+#define FD_CRAM     2
+#define FD_CAKES    3
+#define FD_LEMBA    4
+#define FD_MIRUVOR  5
+#define MAXFOODS    (sizeof(fd_data) / sizeof(struct magic_item))
+
+/* stuff to do with encumberance */
+#define F_OK        0   /* have plenty of food in stomach */
+#define F_HUNGRY    1   /* player is hungry */
+#define F_WEAK      2   /* weak from lack of food */
+#define F_FAINT     3   /* fainting from lack of food */
+
+/* return values for get functions */
+#define NORM    0       /* normal exit */
+#define QUIT    1       /* quit option setting */
+#define MINUS   2       /* back up one option */
+
+/* These are the types of inventory styles. */
+#define INV_SLOW    0
+#define INV_OVER    1
+#define INV_CLEAR   2
+
+/* These will eventually become enumerations */
+#define MESSAGE     TRUE
+#define NOMESSAGE   FALSE
+#define POINTS      TRUE
+#define NOPOINTS    FALSE
+#define LOWERCASE   TRUE
+#define UPPERCASE   FALSE
+#define WANDER      TRUE
+#define NOWANDER    FALSE
+#define GRAB        TRUE
+#define NOGRAB      FALSE
+#define FAMILIAR    TRUE
+#define NOFAMILIAR  FALSE
+#define MAXSTATS    TRUE
+#define NOMAXSTATS  FALSE
+#define FORCE       TRUE
+#define NOFORCE     FALSE
+#define THROWN      TRUE
+#define NOTHROWN    FALSE
+
+/* Ways to die */
+#define D_PETRIFY   -1
+#define D_ARROW     -2
+#define D_DART      -3
+#define D_POISON    -4
+#define D_BOLT      -5
+#define D_SUFFOCATION   -6
+#define D_POTION    -7
+#define D_INFESTATION   -8
+#define D_DROWN     -9
+#define D_FALL      -10
+#define D_FIRE      -11
+#define D_SPELLFUMBLE   -12
+#define D_DRAINLIFE -13
+#define D_ARTIFACT  -14
+#define D_GODWRATH  -15
+#define D_CLUMSY    -16
+
+/* values for games end */
+#define SCOREIT -1
+#define KILLED   0
+#define CHICKEN  1
+#define WINNER   2
+#define TOTAL    3
+
+/*
+ * definitions for function step_ok: MONSTOK indicates it is OK to step on a
+ * monster -- it is only OK when stepping diagonally AROUND a monster
+ */
+
+#define MONSTOK 1
+#define NOMONST 2
+
+
+
+#define good_monster(m) (on(m, ISCHARMED) || \
+            on(m, ISFRIENDLY) || \
+            on(m, ISFAMILIAR))
+
+/* Now we define the structures and types */
+
+/* level types */
+typedef enum
+{
+    NORMLEV,        /* normal level */
+    POSTLEV,        /* trading post level */
+    MAZELEV,        /* maze level */
+    THRONE          /* unique monster's throne room */
+}   LEVTYPE;
+
+/* Help list */
+
+struct h_list
+{
+    char        h_ch;
+    char        *h_desc;
+};
+
+/* Coordinate data type */
+typedef struct
+{
+    int     x;
+    int     y;
+} coord;
+
+/* Linked list data type */
+typedef struct linked_list
+{
+    struct linked_list  *l_next;
+    struct linked_list  *l_prev;
+
+    union
+    {
+        struct object *obj;
+        struct thing  *th;
+        void *l_data;
+    } data;
+
+} linked_list;
+
+/* Stuff about magic items */
+
+struct magic_item
+{
+    char   *mi_name;
+    char   *mi_abrev;
+    int     mi_prob;
+    long    mi_worth;
+    int     mi_curse;
+    int     mi_bless;
+};
+
+/* Room structure */
+struct room
+{
+    coord   r_pos;      /* Upper left corner */
+    coord   r_max;      /* Size of room */
+    coord   r_exit[MAXDOORS];   /* Where the exits are */
+    int     r_flags;    /* Info about the room */
+    int     r_nexits;   /* Number of exits */
+    short   r_fires;    /* Number of fires in room */
+};
+
+/* Initial artifact stats */
+struct init_artifact
+{
+    char   *ar_name;   /* name of the artifact */
+    int     ar_level;   /* first level where it appears */
+    int     ar_rings;   /* number of ring effects */
+    int     ar_potions; /* number of potion effects */
+    int     ar_scrolls; /* number of scroll effects */
+    int     ar_wands;   /* number of wand effects */
+    int     ar_worth;   /* gold pieces */
+    int     ar_weight;  /* weight of object */
+};
+
+/* Array of all traps on this level */
+
+struct trap
+{
+    coord       tr_pos;     /* Where trap is */
+    long        tr_flags;   /* Info about trap (i.e. ISFOUND) */
+    char        tr_type;    /* What kind of trap */
+    char        tr_show;    /* What disguised trap looks like */
+};
+
+/* Structure describing a fighting being */
+
+struct stats
+{
+    char   *s_dmg;     /* String describing damage done */
+    long    s_exp;      /* Experience */
+    long    s_hpt;      /* Hit points */
+    int     s_pack;     /* current weight of his pack */
+    int     s_carry;    /* max weight he can carry */
+    int     s_lvl;      /* Level of mastery */
+    int     s_arm;      /* Armor class */
+    int     s_acmod;    /* Armor clss modifier */
+    int     s_power;    /* Spell points */
+    int     s_str;      /* Strength */
+    int     s_intel;    /* Intelligence */
+    int     s_wisdom;   /* Wisdom */
+    int     s_dext;     /* Dexterity */
+    int     s_const;    /* Constitution */
+    int     s_charisma; /* Charisma */
+};
+
+/* Structure describing a fighting being (monster at initialization) */
+
+struct mstats
+{
+    short s_str;        /* Strength */
+    long  s_exp;        /* Experience */
+    int   s_lvl;        /* Level of mastery */
+    int   s_arm;    /* Armor class */
+    char *s_hpt;        /* Hit points */
+    char *s_dmg;        /* String describing damage done */
+};
+
+/* Structure for monsters and player */
+
+/*
+    NOTE: In initial v1.04 code the t_chasee variable will be
+          reset during the save/restore process. Eventually
+          need to implement a "thing" manager where I can
+          refer to "things" by number such that references
+          to them can be saved. Problems exist with regard
+          to removing references to "things" that have been
+          killed.
+*/
+
+typedef struct thing
+{
+    long   chasee_index, horde_index; /* Used in save/rest process */
+    struct linked_list  *t_pack;    /* What the thing is carrying */
+    struct stats    t_stats;    /* Physical description */
+    struct stats    maxstats;   /* maximum(or initial) stats */
+    int           t_ischasing;  /* Are we chasing someone? */
+    struct thing *t_chasee;     /* Who are we chasing */
+    struct object *t_horde;     /* What are we hordeing */
+    coord      t_pos;      /* Cuurent Position */
+    coord      t_oldpos;   /* Last Position    */
+    coord      t_nxtpos;   /* Next Position    */
+    long       t_flags[16];    /* State word */
+    int        t_praycnt;  /* Times prayed... */
+    int        t_trans;    /* # of transactions at post */
+    int        t_turn;     /* If slowed, is it a turn to move */
+    int        t_wasshot;  /* Was character shot last round? */
+    int        t_ctype;    /* Character type */
+    int        t_index;    /* Index into monster table */
+    int        t_no_move;  /* How long the thing can't move */
+    int        t_rest_hpt; /* used in hit point regeneration */
+    int        t_rest_pow; /* used in spell point regeneration */
+    int        t_doorgoal; /* What door are we heading to? */
+    char       t_type;     /* What it is */
+    char       t_disguise; /* What mimic looks like */
+    char       t_oldch;    /* Character that was where it was */
+} thing;
+
+/* Array containing information on all the various types of monsters */
+
+struct monster
+{
+    char         *m_name;    /* What to call the monster */
+    short         m_carry;    /* Probability of carrying something */
+    int           m_normal;   /* Does monster exist? */
+    int           m_wander;   /* Does monster wander? */
+    char          m_appear;   /* What does monster look like? */
+    char         *m_intel;   /* Intelligence range */
+    unsigned long          m_flags[16];    /* Things about the monster */
+    char         *m_typesum; /* type of creature can he summon */
+    short         m_numsum;   /* how many creatures can he summon */
+    short         m_add_exp;  /* Added experience per hit point */
+    struct mstats m_stats;    /* Initial stats */
+};
+
+/* Structure for a thing that the rogue can carry */
+
+typedef struct object
+{
+    coord       o_pos;      /* Where it lives on the screen */
+    struct linked_list  *next_obj;  /* The next obj. for stacked objects */
+    struct linked_list  *o_bag; /* bag linked list pointer */
+    char        *o_text;    /* What it says if you read it */
+    char        *o_damage;  /* Damage if used like sword */
+    char        *o_hurldmg; /* Damage if thrown */
+    long        o_flags;    /* Information about objects */
+    long        ar_flags;   /* general flags */
+    char     o_type;     /* What kind of object it is */
+    int     o_ident;    /* identifier for object */
+    unsigned int     o_count;    /* Count for plural objects */
+    int     o_which;    /* Which object of a type it is */
+    int     o_hplus;    /* Plusses to hit */
+    int     o_dplus;    /* Plusses to damage */
+    int     o_ac;       /* Armor class */
+    int     o_group;    /* Group number for this object */
+    int     o_weight;   /* weight of this object */
+    char        o_launch;   /* What you need to launch it */
+    char        o_mark[MARKLEN];    /* Mark the specific object */
+    long o_worth;
+}       object;
+
+/* weapon structure */
+
+struct init_weps
+{
+    char        *w_name;    /* name of weapon */
+    char        *w_dam;     /* hit damage */
+    char        *w_hrl;     /* hurl damage */
+    char        w_launch;   /* need to launch it */
+    int         w_wght;     /* weight of weapon */
+    long        w_worth;    /* worth of this weapon */
+    long        w_flags;    /* flags */
+};
+
+/* armor structure */
+
+struct init_armor
+{
+    char        *a_name;    /* name of armor */
+    long        a_worth;    /* worth of armor */
+    int     a_prob;     /* chance of getting armor */
+    int     a_class;    /* normal armor class */
+    int     a_wght;     /* weight of armor */
+};
+
+struct matrix
+{
+    int     base;   /* Base to-hit value (AC 10) */
+    int     max_lvl;/* Maximum level for changing value */
+    int     factor; /* Amount base changes each time */
+    int     offset; /* What to offset level */
+    int     range;  /* Range of levels for each offset */
+};
+
+/*
+    ANSI C Prototype Additions
+*/
+
+/* armor.c */
+extern void wear(void);
+extern void take_off(void);
+extern void waste_time(void);
+extern int  wear_ok(struct thing *th, struct object *obj, int print_message);
+
+/* artifact.c */
+extern void apply(void);
+extern int possessed(int artifact);
+extern int is_carrying(int artifact);
+extern int make_artifact(void);
+extern struct object *new_artifact(int which, struct object *cur);
+extern void do_minor(struct object *obj);
+extern void do_major(void);
+extern void do_phial(void);
+extern void do_palantir(void);
+extern void do_sceptre(void);
+extern void do_silmaril(void);
+extern void do_amulet(void);
+extern void do_bag(struct object *obj);
+extern void do_wand(void);
+extern void do_crown(void);
+extern void level_eval(void);
+
+/* bag.c */
+
+typedef union
+{
+    void *varg;
+    int  *iarg;
+    struct object *obj;
+} bag_arg;
+
+
+extern struct object *apply_to_bag(struct linked_list *bag_p, int type,
+                    int (*bff_p)(struct object *obj, bag_arg *arg),
+                    int (*baf_p)(struct object *obj, bag_arg *arg, int id),
+                    void *user_arg);
+extern int count_bag(linked_list *bag_p, int type,
+                    int (*bff_p)(struct object *obj, bag_arg *arg));
+extern void del_bag(linked_list *bag_p, object *obj_p);
+extern struct object *pop_bag(linked_list **bag_pp, object *obj_p);
+extern void push_bag(linked_list **bag_pp, object *obj_p);
+extern struct object *scan_bag(linked_list *bag_p, int type, int id);
+extern struct object *select_bag(linked_list *bag_p, int type,
+                    int (*bff_p)(struct object *obj, bag_arg *arg), int index);
+
+/* chase.c */
+
+extern void do_chase(struct thing *th, int flee);
+extern void chase_it(coord *runner, struct thing *th);
+extern void runto(void);/* coord *runner, coord *spot); */
+extern int chase(struct thing *tp, coord *ee, int flee);
+extern struct room *roomin(coord cp);
+extern struct linked_list *find_mons(int y, int x);
+extern struct linked_list *f_mons_a(int y, int x, int hit_bad);
+extern int diag_ok(coord *sp, coord *ep, struct thing *flgptr);
+extern int cansee(int y, int x);
+extern coord *find_shoot(struct thing *tp, coord *dir);
+extern coord *can_shoot(coord *er, coord *ee, coord *dir);
+extern int straight_shot(int ery, int erx, int eey, int eex, coord *dir);
+extern struct linked_list *get_hurl(struct thing *tp);
+extern struct object *pick_weap(struct thing *tp);
+extern int can_blink(struct thing *tp);
+
+/* command.c */
+
+extern char  fight_ch;
+extern char  countch;
+extern void command(void);
+extern void do_after_effects(void);
+extern void make_omnipotent(void);
+extern void quit_handler(int sig);
+extern void quit(void);
+extern void search(int is_thief);
+extern void help(void);
+extern void identify(void);
+extern void d_level(void);
+extern void u_level(void);
+extern void call(int mark);
+extern int  att_bonus(void);
+
+/* daemon.c */
+
+extern int demoncnt;
+
+struct delayed_action
+{
+    int d_type;
+    int d_when;
+    int d_id;
+    void *d_arg;
+    int d_time;
+};
+
+#define EMPTY  0
+#define DAEMON 1
+#define FUSE   2
+
+typedef void fuse;
+typedef void daemon;
+
+typedef union
+{
+    void *varg;
+    int  *iarg;
+    struct linked_list *ll;
+} fuse_arg;
+
+typedef union
+{
+    void *varg;
+    int  *iarg;
+    struct thing *thingptr;
+} daemon_arg;
+
+struct fuse
+{
+    int index;
+    fuse (*func)(fuse_arg *arg);
+};
+
+struct daemon
+{
+    int index;
+    daemon (*func)(daemon_arg *arg);
+};
+
+#define MAXDAEMONS 60
+
+#define FUSE_NULL          0
+#define FUSE_SWANDER       1
+#define FUSE_UNCONFUSE     2
+#define FUSE_UNSCENT       3
+#define FUSE_SCENT         4
+#define FUSE_UNHEAR        5
+#define FUSE_HEAR          6
+#define FUSE_UNSEE         7
+#define FUSE_UNSTINK       8
+#define FUSE_UNCLRHEAD     9
+#define FUSE_UNPHASE      10
+#define FUSE_SIGHT        11
+#define FUSE_RES_STRENGTH 12
+#define FUSE_NOHASTE      13
+#define FUSE_NOSLOW       14
+#define FUSE_SUFFOCATE    15
+#define FUSE_CURE_DISEASE 16
+#define FUSE_UNITCH       17
+#define FUSE_APPEAR       18
+#define FUSE_UNELECTRIFY  19
+#define FUSE_UNBHERO      20
+#define FUSE_UNSHERO      21
+#define FUSE_UNXRAY       22
+#define FUSE_UNDISGUISE   23
+#define FUSE_SHERO        24
+#define FUSE_WGHTCHK      25
+#define FUSE_UNSUMMON     26
+#define FUSE_UNGAZE       27
+#define FUSE_UNCOLD       28
+#define FUSE_UNHOT        29
+#define FUSE_UNFLY        30
+#define FUSE_UNBREATHE    31
+#define FUSE_UNREGEN      32
+#define FUSE_UNSUPEREAT   33
+#define FUSE_UNSHIELD     34
+#define FUSE_UNMSHIELD    35
+#define FUSE_UNTRUESEE    36
+#define FUSE_MAX          37
+
+#define DAEMON_NULL       0
+#define DAEMON_DOCTOR     1
+#define DAEMON_ROLLWAND   2
+#define DAEMON_STOMACH    3
+#define DAEMON_RUNNERS    4
+#define DAEMON_MAX        5
+
+extern struct delayed_action d_list[MAXDAEMONS];
+extern struct daemon daemons[DAEMON_MAX];
+extern struct fuse fuses[FUSE_MAX];
+
+extern struct delayed_action *d_slot(void);
+extern struct delayed_action *find_slot(int id, int type);
+extern void start_daemon(int id, void *arg, int whendo);
+extern void kill_daemon(int id);
+extern void do_daemons(int now);
+extern void light_fuse(int id, void *arg, int time, int whendo);
+extern void lengthen_fuse(int id, int xtime);
+extern void extinguish_fuse(int id);
+extern void do_fuses(int flag);
+extern void activity(void);
+
+/* daemons.c */
+
+extern void doctor_spell_points(struct thing *tp);
+extern daemon runners(daemon_arg *arg);
+extern daemon doctor(daemon_arg *tp);
+extern daemon rollwand(daemon_arg *arg);
+extern daemon stomach(daemon_arg *arg);
+extern fuse swander(fuse_arg *arg);
+extern fuse unconfuse(fuse_arg *arg);
+extern fuse unscent(fuse_arg *arg);
+extern fuse scent(fuse_arg *arg);
+extern fuse unhear(fuse_arg *arg);
+extern fuse hear(fuse_arg *arg);
+extern fuse unsee(fuse_arg *arg);
+extern fuse unstink(fuse_arg *arg);
+extern fuse unclrhead(fuse_arg *arg);
+extern fuse unphase(fuse_arg *arg);
+extern fuse sight(fuse_arg *arg);
+extern fuse res_strength(fuse_arg *arg);
+extern fuse nohaste(fuse_arg *arg);
+extern fuse noslow(fuse_arg *arg);
+extern fuse suffocate(fuse_arg *arg);
+extern fuse cure_disease(fuse_arg *arg);
+extern fuse un_itch(fuse_arg *arg);
+extern fuse appear(fuse_arg *arg);
+extern fuse unelectrify(fuse_arg *arg);
+extern fuse unshero(fuse_arg *arg);
+extern fuse unbhero(fuse_arg *arg);
+extern fuse undisguise(fuse_arg *arg);
+extern fuse unsummon(fuse_arg *monst);
+extern fuse ungaze(fuse_arg *arg);
+extern fuse shero(fuse_arg *arg);
+extern fuse uncold(fuse_arg *arg);
+extern fuse unhot(fuse_arg *arg);
+extern fuse unfly(fuse_arg *arg);
+extern fuse unbreathe(fuse_arg *arg);
+extern fuse unregen(fuse_arg *arg);
+extern fuse unsupereat(fuse_arg *arg);
+extern fuse unshield(fuse_arg *arg);
+extern fuse unmshield(fuse_arg *arg);
+extern fuse untruesee(fuse_arg *arg);
+extern fuse wghtchk(fuse_arg *arg);
+
+/* encumb.h */
+
+extern void updpack(void);
+extern int  packweight(void);
+extern int  itemweight(struct object *wh);
+extern int  playenc(void);
+extern int  totalenc(void);
+extern int  hitweight(void);
+
+/* fight.c */
+
+extern void do_fight(coord dir, int tothedeath);
+extern int  fight(coord *mp, struct object *weap, int thrown);
+extern int  attack(struct thing *mp, struct object *weapon, int thrown);
+extern int  mon_mon_attack(struct thing *attacker, struct linked_list *mon,
+                           struct object *weapon, int thrown);
+extern int  swing(int class, int at_lvl, int op_arm, int wplus);
+extern void init_exp(void);
+extern int  next_exp_level(int print_message);
+extern void check_level(void);
+extern int  roll_em(struct thing *att_er, struct thing *def_er,
+                    struct object *weap, int thrown, struct object *cur_weapon);
+extern const char *prname(char *who);
+extern void  hit(char *ee);
+extern void  miss(char *ee);
+extern int   save_throw(int which, struct thing *tp);
+extern int   save(int which);
+extern int   dext_plus(int dexterity);
+extern int   dext_prot(int dexterity);
+extern int   str_plus(int str);
+extern int   add_dam(int str);
+extern int   hung_dam(void);
+extern void  raise_level(void);
+extern void  thunk(struct object *weap, char *mname);
+extern void  m_thunk(struct object *weap, char *mname);
+extern void  bounce(struct object *weap, char *mname);
+extern void  m_bounce(struct object *weap, char *mname);
+extern void  remove_monster(coord *mp, struct linked_list *item);
+extern int   is_magic(struct object *obj);
+extern void  killed(struct thing *killer,struct linked_list *item,
+                    int print_message, int give_points);
+extern struct object *wield_weap(struct object *weapon, struct thing *mp);
+extern void  summon_help(struct thing *mons, int force);
+extern int   maxdamage(char *cp);
+
+/* getplay.c */
+
+extern int   geta_player(void);
+extern void  puta_player(void);
+extern void  do_getplayer(void);
+extern void  print_stored(void);
+extern char *which_class(int c_class);
+
+/* ident.c */
+
+extern char    print_letters[];
+extern int     get_ident(struct object *obj_p);
+extern void    free_ident(struct object *obj_p);
+extern int     unprint_id(char *print_id);
+extern int     max_print(void);
+
+/* init.c */
+
+extern void init_materials(void);
+extern void init_player(void);
+extern void init_flags(void);
+extern void init_things(void);
+extern void init_fd(void);
+extern void init_colors(void);
+extern void init_names(void);
+extern void init_stones(void);
+extern void badcheck(char *name, struct magic_item *magic, int bound);
+
+/* io.c */
+
+extern int get_string(char *buffer, WINDOW *win);
+extern void msg(const char *fmt, ...);
+extern void addmsg(const char *fmt, ...);
+extern void endmsg(void);
+extern void doadd(const char *fmt, va_list ap);
+extern char readchar(void);
+extern char readcharw(WINDOW *scr);
+extern void status(int display);
+extern void wait_for(int ch);
+extern void show_win(WINDOW *scr, char *message);
+extern void restscr(WINDOW *scr);
+extern void add_line(const char *fmt, ...);
+extern void end_line(void);
+extern void hearmsg(const char *fmt, ...);
+extern void seemsg(const char *fmt, ...);
+
+/* list.c */
+
+extern void *ur_alloc(size_t size);
+extern void  ur_free(void *buf_p);
+extern void  _detach(struct linked_list **list, struct linked_list *item);
+extern void  _attach(struct linked_list **list, struct linked_list *item);
+extern void  _attach_after(linked_list **list_pp, linked_list *list_p, linked_list *new_p);
+extern void  _free_list(struct linked_list **ptr);
+extern void  discard(struct linked_list *item);
+extern void  throw_away(struct object *ptr);
+extern struct linked_list *new_item(int size);
+extern void *new_alloc(size_t size);
+extern struct linked_list *new_list(void);
+
+/* magic.c */
+
+/* for printing out messages */
+
+#define CAST_NORMAL       0x000   /* cast normal version  */
+#define CAST_CURSED       0x001   /* cast cursed version  */
+#define CAST_BLESSED      0x002   /* cast blessed version */
+#define CAST_CROWN        0x010   /* crown helped out     */
+#define CAST_SEPTRE       0x020   /* septre helped out    */
+
+#define MAX_SPELLS          100   /* Max # sorted_spells  */
+#define MIN_FUMBLE_CHANCE     5
+#define MAX_FUMBLE_CHANCE    95
+
+/* Spells that a monster can cast */
+
+#define M_SELFTELEP    0
+#define M_HLNG2        1
+#define M_REGENERATE   2
+#define M_HLNG         3
+#define NUM_RUN        4
+#define M_HASTE        4
+#define M_SEEINVIS     5
+#define M_SHERO        6
+#define M_PHASE        7
+#define M_INVIS        8
+#define M_CANCEL       9
+#define M_OFFENSE     10
+
+
+struct spells
+{
+    int sp_level;   /* level of casting spell */
+    int sp_which;   /* which scroll or potion */
+    unsigned long sp_flags;   /* scroll, blessed, known */
+    int sp_cost;    /* generated in incant()  */
+};
+
+
+extern void incant(struct thing *caster, coord shoot_dir);
+extern char *spell_name(struct spells *sp, char *buf);
+extern char *spell_abrev(struct spells *sp, char *buf);
+extern void fumble_spell(struct thing *caster, int num_fumbles);
+extern void learn_new_spells(void);
+extern struct spells *pick_monster_spell(struct thing *caster);
+extern int sort_spells(const void *a, const void *b);
+
+/* magicitm.c */
+
+extern struct magic_item    things[];   /* Chances for each type of item*/
+extern struct magic_item    s_magic[];  /* Names and chances for scrolls*/
+extern struct magic_item    p_magic[];  /* Names and chances for potions*/
+extern struct magic_item    r_magic[];  /* Names and chances for rings  */
+extern struct magic_item    ws_magic[]; /* Names and chances for sticks */
+extern struct magic_item    fd_data[];  /* Names and chances for food   */
+extern struct init_weps     weaps[];    /* weapons and attributes   */
+extern struct init_armor    armors[];   /* armors and attributes    */
+extern struct init_artifact arts[];     /* artifacts and attributes     */
+extern int  maxarmors;
+extern int  maxartifact;
+extern int  maxfoods;
+extern int  maxpotions;
+extern int  maxrings;
+extern int  maxscrolls;
+extern int  maxsticks;
+extern int  maxweapons;
+extern int  numthings;
+extern char *s_names[];         /* Names of the scrolls */
+extern char *p_colors[];        /* Colors of the potions */
+extern char *r_stones[];        /* Stone settings of the rings */
+extern char *guess_items[MAXMAGICTYPES][MAXMAGICITEMS];
+                /* Players guess at what magic is */
+extern int know_items[MAXMAGICTYPES][MAXMAGICITEMS];
+                /* Does he know what a magic item does */
+extern char *ws_type[];     /* Is it a wand or a staff */
+extern char *ws_made[];     /* What sticks are made of */
+
+/* main.c */
+
+extern FILE *fd_score;
+extern int   summoned;
+extern coord dta;
+extern int   main(int argc, char *argv[]);
+extern void  fatal(char *s);
+extern int rnd(int range);
+extern unsigned char ucrnd(unsigned char range);
+extern short srnd(short range);
+extern unsigned long ulrnd(unsigned long range);
+extern int   roll(int number, int sides);
+
+/* maze.c */
+
+extern void do_maze(void);
+extern void draw_maze(void);
+extern char *moffset(int y, int x);
+extern char *foffset(int y, int x);
+extern int findcells(int y, int x);
+extern void rmwall(int newy, int newx, int oldy, int oldx);
+extern void crankout(void);
+
+/* memory.c */
+
+extern void  mem_debug(const int level);
+extern void  mem_tracking(int flag);
+extern int   mem_check(char *fname, int line);
+extern void *mem_malloc(const size_t bytes);
+extern void  mem_free(const void *ptr);
+extern void *mem_realloc(const void *ptr, const size_t new_size);
+extern int   mem_validate(const void *ptr);
+
+/* misc.c */
+
+extern char *tr_name(char ch, char *buf);
+extern void  look(int wakeup);
+extern char  secretdoor(int y, int x);
+extern struct linked_list *find_obj(int y, int x);
+extern void  eat(void);
+extern void  chg_str(int amt, int both, int lost);
+extern void  chg_dext(int amt, int both, int lost);
+extern void  add_haste(int blessed);
+extern void  aggravate(void);
+extern char  *vowelstr(char *str);
+extern int is_current(struct object *obj);
+extern int get_dir(void);
+extern int is_wearing(int type);
+extern int maze_view(int y, int x);
+extern void listen(void);
+extern void nothing_message(int flags);
+extern void feel_message(void);
+extern int const_bonus(void);
+extern int int_wis_bonus(void);
+extern void electrificate(void);
+extern void feed_me(int hungry_state);
+extern int get_monster_number(char *message);
+
+/* monsdata.c */
+
+extern struct monster monsters[];
+extern int nummonst;
+
+/* monsters.c */
+
+extern struct linked_list *summon_monster(int type, int familiar, int print_message);
+extern int randmonster(int wander, int grab);
+extern void new_monster(struct linked_list *item, int type, coord *cp, int max_monster);
+extern void wanderer(void);
+extern struct linked_list *wake_monster(int y, int x);
+extern void genocide(int flags);
+extern void id_monst(int monster);
+extern void check_residue(struct thing *tp);
+extern void sell(struct thing *tp);
+extern void carried_weapon(struct thing *owner, struct object *weapon);
+
+/* move.c */
+
+extern coord nh;
+extern void do_run(char ch);
+extern int  step_ok(int y, int x, int can_on_monst, struct thing *flgptr);
+extern void corr_move(int dy, int dx);
+extern void do_move(int dy, int dx);
+extern void light(coord *cp);
+extern int  blue_light(int flags);
+extern char  show(int y, int x);
+extern char be_trapped(struct thing *th, coord tc);
+extern void dip_it(void);
+extern struct trap *trap_at(int y, int x);
+extern void set_trap(struct thing *tp, int y, int x);
+extern coord rndmove(struct thing *who);
+extern int isatrap(int ch);
+
+/* newlvl.c */
+
+extern void new_level(LEVTYPE ltype, int special);
+extern void put_things(LEVTYPE ltype);
+extern int throne_monster;
+extern void do_throne(int special);
+extern void create_lucifer(coord *stairs);
+
+/* options.c */
+
+typedef union
+{
+    void *varg;
+    char *str;
+    int  *iarg;
+} opt_arg;
+
+struct optstruct
+{
+    char    *o_name;    /* option name */
+    char    *o_prompt;  /* prompt for interactive entry */
+    opt_arg o_opt;     /* pointer to thing to set */
+    void    (*o_putfunc)(opt_arg *arg,WINDOW *win);/* func to print value */
+    int     (*o_getfunc)(opt_arg *arg,WINDOW *win);/* func to get value  */
+};
+
+typedef struct optstruct    OPTION;
+
+extern void parse_opts(char *str);
+extern void option(void);
+extern void put_bool(opt_arg *iarg, WINDOW *win);
+extern void put_str(opt_arg *str, WINDOW *win);
+extern void put_abil(opt_arg *ability, WINDOW *win);
+extern void put_inv(opt_arg *inv, WINDOW *win);
+extern int  get_bool(opt_arg *bp, WINDOW *win);
+extern int  get_str(opt_arg *opt, WINDOW *win);
+extern int  get_abil(opt_arg *abil, WINDOW *win);
+extern int  get_inv(opt_arg *inv, WINDOW *win);
+
+/* pack.c */
+
+extern void swap_top(struct linked_list *top, struct linked_list *node);
+extern void get_all(struct linked_list *top);
+extern struct linked_list *get_stack(struct linked_list *item);
+extern int add_pack(struct linked_list  *item, int print_message);
+extern void pack_report(object *obj, int print_message, char *message);
+extern void inventory(struct linked_list *container, int type);
+extern void pick_up(char ch);
+extern struct object *get_object(struct linked_list *container, char *purpose, int type, int (*bff_p)(struct object *obj, bag_arg *junk) );
+extern struct linked_list *get_item(char *purpose, int type);
+extern void del_pack(struct linked_list *what);
+extern void discard_pack(struct object *obj_p);
+extern void rem_pack(struct object *obj_p);
+extern void cur_null(struct object *op);
+extern void idenpack(void);
+extern void show_floor(void);
+
+/* passages.c */
+
+struct rdes
+{
+    int conn[MAXROOMS];     /* possible to connect to room i? */
+    int isconn[MAXROOMS];   /* connection been made to room i? */
+    int ingraph;            /* this room in graph already? */
+};
+
+extern void do_passages(void);
+extern void conn(int r1, int r2);
+extern void door(struct room *rm, coord *cp);
+
+/* player.c */
+
+extern void prayer(void);
+extern int  gsense(void);
+extern int  is_stealth(struct thing *tp);
+extern void steal(void);
+extern void affect(void);
+extern void undead_sense(void);
+
+/* potions.c */
+
+extern void quaff(struct thing *quaffer, int which, int flag);
+extern void lower_level(int who);
+extern void res_dexterity(void);
+extern void res_wisdom(void);
+extern void res_intelligence(void);
+extern void add_strength(int cursed);
+extern void add_intelligence(int cursed);
+extern void add_wisdom(int cursed);
+extern void add_dexterity(int cursed);
+extern void add_const(int cursed);
+extern void monquaff(struct thing *quaffer, int which, int flag);
+
+/* properti.c */
+
+extern int baf_print_item(struct object *obj_p, bag_arg *type, int id);
+extern int baf_identify(struct object *obj_p, bag_arg *junk, int id);
+extern int baf_curse(struct object *obj_p, bag_arg *junk, int id);
+extern int baf_decrement_test(struct object *obj_p, bag_arg *count_p, int id);
+extern int baf_increment(struct object *obj_p, bag_arg *count_p, int id);
+extern int bafcweapon(struct object *obj_p, bag_arg *junk, int id);
+extern int bafcarmor(struct object *obj_p, bag_arg *junk, int id);
+extern int bff_group(struct object *obj_p, bag_arg *new_obj_p);
+extern int bff_callable(struct object *obj_p, bag_arg *junk);
+extern int bff_markable(struct object *obj_p, bag_arg *junk);
+extern int bffron(object *obj_p, bag_arg *junk);
+extern int bff_zappable(struct object *obj_p, bag_arg *junk);
+
+/* random.c */
+
+extern void ur_srandom(unsigned x);
+extern long ur_random(void);
+
+/* rings.c */
+
+extern void ring_on(void);
+extern void ring_off(void);
+extern int ring_eat(int hand);
+extern char *ring_num(struct object *obj, char *buf);
+extern int   ring_value(int type);
+
+/* rip.c */
+
+extern void death(int monst);
+extern void score(long amount, int lvl, int flags, int monst);
+extern void total_winner(void);
+extern char *killname(int monst, char *buf);
+extern void showpack(char *howso);
+extern void byebye(void);
+extern int  save_resurrect(int bonus);
+
+/* rogue.c */
+
+extern const char *monstern;
+extern const struct h_list helpstr[];
+extern const char *cnames[][15];      /* Character level names */
+extern char *spacemsg;
+extern char *morestr;
+extern char *retstr;
+
+/* state.c */
+
+extern int mpos;           /* Where cursor is on top line */
+extern struct trap    traps[];
+extern struct room    rooms[];      /* One for each room -- A level */
+extern struct thing   player;       /* The rogue */
+extern struct thing  *beast;        /* The last monster attacking */
+extern struct object *cur_armor;    /* What a well dresssed rogue wears */
+extern struct object *cur_weapon;   /* Which weapon he is wielding */
+extern struct object *cur_ring[];   /* What rings are being worn */
+extern struct linked_list *fam_ptr;     /* A ptr to the familiar */
+extern struct linked_list *lvl_obj;     /* List of objects on this level */
+extern struct linked_list *mlist;       /* List of monsters on the level */
+extern struct linked_list *curr_mons;   /* The mons. currently moving */
+extern struct linked_list *next_mons;   /* The mons. after curr_mons */
+
+extern int  prscore;    /* Print scores */
+extern int  prversion;  /* Print version info */
+
+extern WINDOW   *cw;            /* Window that the player sees */
+extern WINDOW   *hw;            /* Used for the help command */
+extern WINDOW   *mw;            /* Used to store mosnters */
+extern LEVTYPE  levtype;
+extern coord    delta;          /* Change indicated to get_dir() */
+
+extern char *release;       /* Release number of rogue */
+extern char *lastfmt;
+extern char *lastarg;
+extern unsigned long    total;      /* Total dynamic memory bytes */
+extern long purse;         /* How much gold the rogue has */
+extern int line_cnt;       /* Counter for inventory style */
+extern int newpage;
+extern int resurrect;      /* resurrection counter */
+extern int foodlev;        /* how fast he eats food */
+extern int see_dist;       /* (how far he can see)^2 */
+extern int level;          /* What level rogue is on */
+extern int ntraps;         /* Number of traps on this level */
+extern int no_command;     /* Number of turns asleep */
+extern int no_food;        /* Number of levels without food */
+extern int count;          /* Number of times to repeat command */
+extern int dnum;           /* Dungeon number */
+extern int max_level;      /* Deepest player has gone */
+extern int food_left;      /* Amount of food in hero's stomach */
+extern int group;          /* Current group number */
+extern int hungry_state;       /* How hungry is he */
+extern int infest_dam;     /* Damage from parasites */
+extern int lost_str;       /* Amount of strength lost */
+extern int lost_dext;      /* amount of dexterity lost */
+extern int hold_count;     /* Number of monsters holding player */
+extern int trap_tries;     /* Number of attempts to set traps */
+extern int has_artifact;       /* set for possesion of artifacts */
+extern int picked_artifact;    /* set for any artifacts picked up */
+extern int msg_index;      /* pointer to current message buffer */
+extern int luck;           /* how expensive things to buy thing */
+extern int fam_type;       /* Type of familiar */
+extern int times_prayed;       /* The number of time prayed */
+extern int mons_summoned;      /* Number of summoned monsters */
+extern int char_type;      /* what type of character is player */
+extern int pool_teleport;      /* just teleported from a pool */
+extern int inwhgt;         /* true if from wghtchk() */
+extern int running;        /* True if player is running */
+extern int fighting;       /* True if player is fighting */
+extern int playing;        /* True until he quits */
+extern int wizard;         /* True if allows wizard commands */
+extern int wiz_verbose;        /* True if show debug messages */
+extern int after;          /* True if we want after daemons */
+extern int fight_flush;        /* True if toilet input */
+extern int terse;          /* True if we should be short */
+extern int doorstop;       /* Stop running when we pass a door */
+extern int jump;           /* Show running as series of jumps */
+extern int door_stop;      /* Current status of doorstop */
+extern int firstmove;      /* First move after setting door_stop */
+extern int waswizard;      /* Was a wizard sometime */
+extern int canwizard;      /* Will be permitted to do this */
+extern int askme;          /* Ask about unidentified things */
+extern int moving;         /* move using 'm' command */
+
+extern int inv_type;       /* Inven style. Bool so options works */
+extern char take;           /* Thing the rogue is taking */
+extern char PLAYER;         /* what the player looks like */
+extern char prbuf[];        /* Buffer for sprintfs */
+extern char runch;          /* Direction player is running */
+extern char whoami[];       /* Name of player */
+extern char fruit[];        /* Favorite fruit */
+extern char msgbuf[10][2 * LINELEN];    /* message buffer */
+extern char file_name[];        /* Save file name */
+extern char score_file[];       /* Score file name */
+
+extern struct linked_list   *arrow, *bolt, *rock, *silverarrow, *fbbolt;
+extern struct linked_list   *bullet, *firearrow, *dart, *dagger, *shuriken;
+extern struct linked_list   *oil, *grenade;
+extern struct room  *oldrp;     /* Roomin(&oldpos) */
+
+extern void ur_write_thing(FILE *savef, struct thing *t);
+extern struct thing *ur_read_thing(FILE *savef);
+extern void ur_write_object_stack(FILE *savef, struct linked_list *l);
+extern void ur_write_bag(FILE *savef, struct linked_list *l);
+extern struct linked_list *ur_read_bag(FILE *savef);
+extern struct linked_list *ur_read_object_stack(FILE *savef);
+extern int restore_file(FILE *savef);
+
+/* rooms.c */
+
+extern void do_rooms(void);
+extern void draw_room(struct room *rp);
+extern void horiz(int cnt);
+extern void vert(int cnt);
+extern void rnd_pos(struct room *rp, coord *cp);
+extern int  rnd_room(void);
+
+/* save.c */
+
+extern int restore(char *file);
+extern int save_game(void);
+extern void save_file(FILE *savefd);
+
+/* scrolls.c */
+
+extern void read_scroll(struct thing *reader, int which, int flags);
+extern struct linked_list *creat_mons(struct thing *person,int monster,int message);
+extern int place_mons(int y, int x, coord *pos);
+extern int is_r_on(struct object *obj);
+extern void monread(struct thing *reader, int which, int flags);
+
+/* status.c */
+
+extern int has_defensive_spell(struct thing th);
+
+/* sticks.c */
+
+extern void fix_stick(struct object *cur);
+extern void do_zap(struct thing *zapper, int which, unsigned long flags);
+extern void drain(int ymin, int ymax, int xmin, int xmax);
+extern char *charge_str(struct object *obj, char *buf);
+extern void shoot_bolt(struct thing *shooter, coord start, coord dir, int get_points, int reason, char *name, int damage);
+extern void monster_do_zap(struct thing *zapper, int which, int flags);
+extern void cancel_player(int not_unique);
+
+/* things.c */
+
+extern char *inv_name(struct object *obj, int lowercase);
+extern void rem_obj(struct linked_list *item, int dis);
+extern void add_obj(struct linked_list *item, int y, int x);
+extern int  drop(struct linked_list *item);
+extern int dropcheck(struct object *op);
+extern struct linked_list *new_thing(void);
+extern struct linked_list *spec_item(char type, int which, int hit, int damage);
+extern int pick_one(struct magic_item *magic, int nitems);
+extern char *blesscurse(long flags);
+extern int extras(void);
+extern char *name_type(int type);
+extern linked_list *make_item(object *obj_p);
+extern int is_member(char *list_p, int member);
+
+/* trader.c */
+
+extern void do_post(void);
+extern void buy_it(char itemtype, int flags);
+extern void sell_it(void);
+extern void describe_it(struct object *obj);
+extern int  open_market(void);
+extern int  get_worth(struct object *obj);
+extern void trans_line(void);
+
+/* verify.c */
+
+extern void  verify_function(const char *file, const int line);
+
+/* vers.c */
+
+extern char *save_format;
+extern char *version;
+extern char *release;
+
+/* weapons.c */
+
+extern coord do_motion(int ob, int ydelta, int xdelta, struct thing *tp);
+extern void fall(struct thing *tp, struct linked_list *item, int pr, int
+player_owned);
+extern int hit_monster(int y, int x, struct object *weapon, struct thing *thrower);
+extern int wield_ok(struct thing *wieldee, struct object *obj, int print_message);
+extern int shoot_ok(int ch);
+extern int fallpos(coord pos, coord *newpos);
+extern void wield(void);
+extern char *num(int n1, int n2, char *buf);
+extern void init_weapon(struct object *weap, int type);
+extern void missile(int ydelta, int xdelta, struct linked_list *item, struct thing *tp);
+
+/* wizard.c */
+
+extern void whatis(struct linked_list *what);
+extern void teleport(void);
+extern int passwd(void);
+
+/* mdport.c */
+char *md_strdup(const char *s);
+long md_random(void);
+void md_srandom(long seed);
+int md_readchar(WINDOW *win);
+
+#define NOOP(x) (x += 0)
+#define CCHAR(x) ( (char) (x & A_CHARTEXT) )
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/rooms.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,315 @@
+/*
+    rooms.c - Draw the nine rooms on the screen
+   
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <stdlib.h>
+#include "rogue.h"
+
+void
+do_rooms(void)
+{
+    int i;
+    struct room *rp;
+    struct linked_list  *item;
+    struct thing    *tp;
+    int left_out;
+    coord   top;
+    coord   bsze;
+    coord   mp;
+
+    /* bsze is the maximum room size */
+
+    bsze.x = COLS / 3;
+    bsze.y = (LINES - 2) / 3;
+
+    /* Clear things for a new level */
+
+    for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
+        rp->r_nexits = rp->r_flags = rp->r_fires = 0;
+
+    /* Put the gone rooms, if any, on the level */
+
+    left_out = rnd(3);
+
+    for (i = 0; i < left_out; i++)
+        rooms[rnd_room()].r_flags |= ISGONE;
+
+    /* dig and populate all the rooms on the level */
+
+    for (i = 0, rp = rooms; i < MAXROOMS; rp++, i++)
+    {
+        int has_gold = FALSE;
+
+        /* Find upper left corner of box that this room goes in */
+
+        top.x = (i % 3) * bsze.x;
+        top.y = i / 3 * bsze.y + 1;
+
+        if (rp->r_flags & ISGONE)
+        {
+            /*
+             * Place a gone room.  Make certain that there is a
+             * blank line for passage drawing.
+             */
+
+            do
+            {
+                rp->r_pos.x = top.x + rnd(bsze.x - 2) + 1;
+                rp->r_pos.y = top.y + rnd(bsze.y - 2) + 1;
+                rp->r_max.x = -COLS;
+                rp->r_max.x = -LINES;
+            }
+            while (rp->r_pos.y < 1 || rp->r_pos.y > LINES - 3);
+
+            continue;
+        }
+
+        if (rnd(40) < level - 5)
+            rp->r_flags |= ISDARK;
+
+        /* Find a place and size for a random room */
+
+        do
+        {
+            rp->r_max.x = rnd(bsze.x - 4) + 4;
+            rp->r_max.y = rnd(bsze.y - 4) + 4;
+            rp->r_pos.x = top.x + rnd(bsze.x - rp->r_max.x);
+            rp->r_pos.y = top.y + rnd(bsze.y - rp->r_max.y);
+        }
+        while (rp->r_pos.y == 0);
+
+        /* Draw the room */
+
+        draw_room(rp);
+
+        /* Put the gold in */
+
+        if (rnd(10) < 3 && (!has_artifact || level >= max_level))
+        {
+            struct linked_list *itm;
+            struct object   *cur;
+            coord   tpos;
+
+            has_gold = TRUE;    /* This room has gold in it */
+
+            itm = spec_item(GOLD, 0, 0, 0);
+            cur = OBJPTR(itm);
+
+            /* Put it somewhere */
+
+            rnd_pos(rp, &tpos);
+            cur->o_pos = tpos;
+
+            /* Put the gold into the level list of items */
+
+            add_obj(itm, tpos.y, tpos.x);
+
+            if (roomin(tpos) != rp)
+            {
+                endwin();
+                abort();
+            }
+        }
+
+        /* Put the monster in */
+
+        if (rnd(100) < (has_gold ? 80 : 40))
+        {
+            int   which;
+            int n, cnt;
+
+            item = new_item(sizeof *tp);
+            tp = THINGPTR(item);
+
+            do
+                rnd_pos(rp, &mp);
+            while (mvwinch(stdscr, mp.y, mp.x) != FLOOR);
+
+            which = randmonster(NOWANDER, NOGRAB);
+            new_monster(item, which, &mp, NOMAXSTATS);
+
+            /* See if we want to give it a treasure to carry around. */
+
+            if (rnd(100) < monsters[tp->t_index].m_carry)
+                attach(tp->t_pack, new_thing());
+
+            /* If it has a fire, mark it */
+
+            if (on(*tp, HASFIRE))
+            {
+                rp->r_flags |= HASFIRE;
+                rp->r_fires++;
+            }
+
+            /* If it carries gold, give it some */
+
+            if (on(*tp, CARRYGOLD))
+            {
+                struct object   *cur;
+
+                item = spec_item(GOLD, 0, 0, 0);
+                cur = OBJPTR(item);
+                cur->o_count = GOLDCALC + GOLDCALC + GOLDCALC;
+                cur->o_pos = tp->t_pos;
+                attach(tp->t_pack, item);
+            }
+
+            n = rnd(7);
+
+            if (on(*tp, ISSWARM) && n < 5)
+                cnt = roll(2, 4);
+            else if (on(*tp, ISFLOCK) && n < 5)
+                cnt = roll(1, 4);
+            else
+                cnt = 0;
+
+            for (n = 1; n <= cnt; n++)
+            {
+                coord   pos;
+
+                if (place_mons(mp.y, mp.x, &pos)!= FALSE)
+                {
+                    struct linked_list  *nitem;
+
+                    nitem = new_item(sizeof(struct thing));
+                    new_monster(nitem, which, &pos, NOMAXSTATS);
+
+                    /* If the monster is on a trap, trap it */
+
+                    if (isatrap(mvinch(pos.y, pos.x)))
+                        be_trapped(THINGPTR(nitem), mp);
+
+                    if (on(*tp, ISFRIENDLY))
+                        turn_on(*(THINGPTR(nitem)), ISFRIENDLY);
+                    else
+                        turn_off(*(THINGPTR(nitem)), ISFRIENDLY);
+                }
+            }
+
+            if (cnt > 0)
+            {
+                int boost = rnd(3) + 1;
+
+                if (on(*tp, LOWCAST) || on(*tp, MEDCAST) || on(*tp, HIGHCAST))
+                    turn_on(*tp, CANCAST);
+
+                tp->t_stats.s_hpt += 3 * boost;
+                tp->t_stats.s_arm -= 2 * boost;
+                tp->t_stats.s_lvl += 2 * boost;
+                tp->t_stats.s_str += 2 * boost;
+                tp->t_stats.s_intel += 2 * boost;
+                tp->t_stats.s_exp += 4 * boost * monsters[which].m_add_exp;
+            }
+        }
+    }
+}
+
+/*
+    draw_room()
+        Draw a box around a room
+*/
+
+void
+draw_room(struct room *rp)
+{
+    int j, k;
+
+    move(rp->r_pos.y, rp->r_pos.x + 1);
+    vert(rp->r_max.y - 2);  /* Draw left side */
+    move(rp->r_pos.y + rp->r_max.y - 1, rp->r_pos.x);
+    horiz(rp->r_max.x); /* Draw bottom */
+    move(rp->r_pos.y, rp->r_pos.x);
+    horiz(rp->r_max.x); /* Draw top */
+    vert(rp->r_max.y - 2);  /* Draw right side */
+
+    /* Put the floor down */
+
+    for (j = 1; j < rp->r_max.y - 1; j++)
+    {
+        move(rp->r_pos.y + j, rp->r_pos.x + 1);
+
+        for (k = 1; k < rp->r_max.x - 1; k++)
+            addch(FLOOR);
+    }
+}
+
+/*
+    horiz()
+        draw a horizontal line
+*/
+
+void
+horiz(int cnt)
+{
+    while(cnt--)
+        addch('-');
+}
+
+/*
+    vert()
+        draw a vertical line
+*/
+
+void
+vert(int cnt)
+{
+    int x, y;
+
+    getyx(stdscr, y, x);
+
+    x--;
+
+    while(cnt--)
+    {
+        move(++y, x);
+        addch('|');
+    }
+}
+
+/*
+    rnd_pos()
+        pick a random spot in a room
+*/
+
+void
+rnd_pos(struct room *rp, coord *cp)
+{
+    cp->x = rp->r_pos.x + rnd(rp->r_max.x - 2) + 1;
+    cp->y = rp->r_pos.y + rnd(rp->r_max.y - 2) + 1;
+}
+
+/*
+    rnd_room()
+        Pick a room that is really there
+*/
+
+int
+rnd_room(void)
+{
+    int rm;
+
+    if (levtype != NORMLEV)
+        rm = 0;
+    else
+        do
+        {
+            rm = rnd(MAXROOMS);
+        }
+        while (rooms[rm].r_flags & ISGONE);
+
+    return(rm);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/save.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,135 @@
+/*
+    save.c - save and restore routines
+ 
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#define _ALL_SOURCE /* need to remove need for this AIXism */
+
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include "rogue.h"
+
+int
+save_game(void)
+{
+    FILE *savefd;
+    char    buf[2 * LINELEN];
+    char    oldfile[2*LINELEN];
+
+    /* get file name */
+
+    strcpy(oldfile,file_name);
+
+    do
+    {
+        mpos = 0;
+
+        if (oldfile[0] != '\0')
+            msg("Save file [%s]: ", file_name);
+        else
+            msg("Save file as: ");
+
+        mpos = 0;
+        buf[0] = '\0';
+
+        if (get_string(buf, cw) == QUIT)
+        {
+            msg("");
+            return(FALSE);
+        }
+
+        if ( (buf[0] == 0) && (oldfile[0] != 0) )
+            strcpy(file_name, oldfile);
+        else if (buf[0] != 0)
+            strcpy(file_name, buf);
+        else
+        {
+            msg("");
+            return(FALSE);
+        }
+
+        wclear(hw);
+        wmove(hw, LINES - 1, 0);
+        wrefresh(hw);
+
+        if ((savefd = fopen(file_name, "w")) == NULL)
+            msg(strerror(errno));    /* fake perror() */
+    }
+    while (savefd == NULL);
+
+    /* write out [compressed?] file */
+
+    save_file(savefd);
+    return(TRUE);
+}
+
+int
+restore(char *file)
+{
+    FILE *infd;
+    char    *sp;
+
+    if (strcmp(file, "-r") == 0)
+        file = file_name;
+
+    if ((infd = fopen(file, "r")) == NULL)
+    {
+        perror(file);
+        return(FALSE);
+    }
+
+    if ( restore_file(infd) == FALSE )
+        return(FALSE);
+
+    /*
+     * we do not close the file so that we will have a hold of the inode
+     * for as long as possible
+     */
+
+    if (remove(file) < 0)
+    {
+        printf("Cannot unlink file\n");
+        return(FALSE);
+    }
+
+    if ((sp = getenv("OPTIONS")) != NULL)
+        parse_opts(sp);
+
+    strcpy(file_name, file);
+
+    clearok(cw, TRUE);
+    touchwin(cw);
+    noecho();
+    nonl();
+
+    while(playing)
+    {
+        do_daemons(BEFORE);
+        do_fuses(BEFORE);
+
+        command();  /* Command execution */
+
+        if (after)
+            do_after_effects();
+    }
+
+    fatal("");
+
+    return(FALSE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/scrolls.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1491 @@
+/*
+    scrolls.c - Functions for dealing with scrolls
+  
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+    read_scroll - read a scroll (or effect a scroll-like spell)
+        reader:  who does it
+        which:   which S_SCROLL (-1 means ask from pack)
+        flags:   ISBLESSED, ISCURSED
+*/
+
+void
+read_scroll(struct thing *reader, int which, int flags)
+{
+    struct object   *obj;
+    struct linked_list  *item, *nitem;
+    int i, j, charm_power;
+    char    ch, nch;
+    int     blessed = flags & ISBLESSED;
+    int     cursed = flags & ISCURSED;
+    int     is_scroll = (which < 0 ? TRUE : FALSE);
+    char    buf[2 * LINELEN];
+
+    if (reader != &player)
+    {
+        monread(reader, which, flags);
+        return;
+    }
+
+    if (is_scroll)      /* A regular scroll */
+    {
+        if ((item = get_item("read", SCROLL)) == NULL)
+            return;
+
+        obj = OBJPTR(item);
+
+        if (obj->o_type != SCROLL)
+        {
+            msg("It says 'Made in Yugoslavia'!");
+            return;
+        }
+
+        if (on(player, ISBLIND))
+        {
+            msg("You can't see to read anything.");
+            return;
+        }
+
+        /* Calculate its effect */
+
+        cursed = obj->o_flags & ISCURSED;
+        blessed = obj->o_flags & ISBLESSED;
+        flags = obj->o_flags;
+        which = obj->o_which;
+
+        /* remove it from the pack */
+
+        rem_pack(obj);
+        discard(item);
+        updpack();
+    }
+
+    switch (which)
+    {
+        case S_CONFUSE:  /* Touch causes monster confusion.  */
+            if (cursed)
+                quaff(reader, P_CLEAR, ISCURSED);
+            else
+            {
+                msg("Your hands begin to glow red.");
+                turn_on(player, CANHUH);
+                /* if blessed... */
+            }
+            break;
+
+        case  S_CURING:   /* A cure disease spell */
+            if (on(player, HASINFEST) || on(player, HASDISEASE))
+            {
+                if (!cursed && on(player, HASDISEASE))
+                {
+                    extinguish_fuse(FUSE_CURE_DISEASE);
+                    cure_disease(NULL);
+                }
+
+                if (on(player, HASINFEST))
+                {
+                    msg("You begin to feel yourself improving again.");
+                    turn_off(player, HASINFEST);
+                    infest_dam = 0;
+                }
+
+                if (is_scroll)
+                    know_items[TYP_SCROLL][S_CURING] = TRUE;
+            }
+            else
+                nothing_message(flags);
+            break;
+
+        case S_LIGHT:
+            if (blue_light(flags) && is_scroll)
+                know_items[TYP_SCROLL][S_LIGHT] = TRUE;
+            break;
+
+        case S_HOLD:
+            if (cursed)
+            {
+                /*
+                 * This scroll aggravates all the monsters on the
+                 * current level and sets them running towards the
+                 * hero
+                 */
+                aggravate();
+                hearmsg("You hear a high pitched humming noise.");
+            }
+            else if (blessed)   /* Hold all monsters on level */
+            {
+                if (mlist == NULL)
+                    nothing_message(flags);
+                else
+                {
+                    struct linked_list  *mon;
+                    struct thing    *th;
+
+                    for (mon = mlist; mon != NULL; mon = next(mon))
+                    {
+                        th = THINGPTR(mon);
+                        turn_off(*th, ISRUN);
+                        turn_on(*th, ISHELD);
+                    }
+                    msg("A sudden peace comes over the dungeon.");
+                }
+            }
+            else
+            {
+                /*
+                 * Hold monster scroll.  Stop all monsters within two
+                 * spaces from chasing after the hero.
+                 */
+                int x, y;
+                struct linked_list  *mon;
+                int gotone = FALSE;
+
+                for (x = hero.x - 2; x <= hero.x + 2; x++)
+                {
+                    for (y = hero.y - 2; y <= hero.y + 2; y++)
+                    {
+                        if (y > 0 && x > 0 && isalpha(mvwinch(mw, y, x)))
+                        {
+                            if ((mon = find_mons(y, x)) != NULL)
+                            {
+                                struct thing    *th;
+
+                                gotone = TRUE;
+                                th = THINGPTR(mon);
+                                turn_off(*th, ISRUN);
+                                turn_on(*th, ISHELD);
+                            }
+                        }
+                    }
+                }
+
+                if (gotone)
+                    msg("A sudden peace surrounds you.");
+                else
+                    nothing_message(flags);
+            }
+            break;
+
+        case S_SLEEP:
+
+            /* if cursed, you fall asleep */
+
+            if (cursed)
+            {
+                if (is_wearing(R_ALERT))
+                    msg("You feel drowsy for a moment.");
+                else
+                {
+                    msg("You fall asleep.");
+                    no_command += 4 + rnd(SLEEPTIME);
+                }
+            }
+            else
+            {
+                /*
+                 * sleep monster scroll.  puts all monsters within 2
+                 * spaces asleep
+                 */
+                int x, y;
+                struct linked_list  *mon;
+                int gotone = FALSE;
+
+                for (x = hero.x - 2; x <= hero.x + 2; x++)
+                {
+                    for (y = hero.y - 2; y <= hero.y + 2; y++)
+                    {
+                        if (y > 0 && x > 0 && isalpha(mvwinch(mw, y, x)))
+                        {
+                            if ((mon = find_mons(y, x)) != NULL)
+                            {
+                                struct thing    *th;
+                                th = THINGPTR(mon);
+
+                                if (on(*th, ISUNDEAD))
+                                    continue;
+
+                                gotone = TRUE;
+                                th->t_no_move += SLEEPTIME;
+                            }
+                        }
+                    }
+                }
+
+                if (gotone)
+                    msg("The monster(s) around you seem to have fallen asleep.");
+                else
+                    nothing_message(flags);
+            }
+            break;
+
+        case S_CREATE:
+        {
+            /*
+             * Create a monster. First look in a circle around
+             * him, next try his room otherwise give up
+             */
+
+            struct thing    *tp;
+            struct linked_list  *ip;
+
+            if (blessed)
+                summon_monster((short) 0, NOFAMILIAR, MESSAGE);
+            else if (cursed)
+            {
+                i = rnd(4) + 3;
+                for (j = 0; j < i; j++)
+                {
+                    if ((ip = creat_mons(&player, (short) 0, MESSAGE)) != NULL)
+                    {
+                        tp = THINGPTR(ip);
+                        turn_off(*tp, ISFRIENDLY);
+                    }
+                }
+            }
+            else if ((ip = creat_mons(&player, (short) 0, MESSAGE)) != NULL)
+            {
+                tp = THINGPTR(ip);
+                turn_off(*tp, ISFRIENDLY);
+            }
+        }
+        break;
+
+        case S_IDENTIFY:
+            if (cursed)
+                msg("You identify this scroll as an identify scroll");
+            else if (blessed)   /* identify everything in the pack */
+            {
+                msg("You feel more Knowledgeable!");
+                idenpack();
+            }
+            else
+            {
+                /* Identify, let the rogue figure something out  */
+
+                if (is_scroll && know_items[TYP_SCROLL][S_IDENTIFY] != TRUE)
+                {
+                    msg("This scroll is an identify scroll.");
+                    know_items[TYP_SCROLL][S_IDENTIFY] = TRUE;
+                }
+                whatis(NULL);
+            }
+            break;
+
+        case S_MAP:
+
+            /* Scroll of magic mapping. */
+
+            if (cursed)
+            {
+                msg("Your mind goes blank for a moment.");
+                wclear(cw);
+                light(&hero);
+                status(TRUE);
+                break;
+            }
+
+            if (is_scroll && know_items[TYP_SCROLL][S_MAP] != TRUE)
+            {
+                msg("Oh! This scroll has a map on it!!");
+                know_items[TYP_SCROLL][S_MAP] = TRUE;
+            }
+
+            if (blessed)
+                turn_on(player, BLESSMAP);
+
+            overwrite(stdscr, hw);
+
+            /* Take all the things we want to keep hidden out of the window */
+
+            for (i = 0; i < LINES; i++)
+                for (j = 0; j < COLS; j++)
+                {
+                    switch (nch = ch = CCHAR(mvwinch(hw, i, j)))
+                    {
+                        case SECRETDOOR:
+                            nch = DOOR;
+                            mvaddch(i, j, nch);
+                            break;
+
+                        case '-':
+                        case '|':
+                        case DOOR:
+                        case PASSAGE:
+                        case ' ':
+                        case STAIRS:
+                            if (mvwinch(mw, i, j) != ' ')
+                            {
+                                struct thing    *it;
+                                struct linked_list  *lit;
+
+                                lit = find_mons(i, j);
+
+				if (lit) {
+				    it = THINGPTR(lit);
+
+				    if (it && it->t_oldch == ' ')
+					it->t_oldch = nch;
+				}
+                            }
+                            break;
+
+                        default:
+                            if (!blessed || !isatrap(ch))
+                                nch = ' ';
+                            else
+                            {
+                                struct trap *tp;
+                                struct room *rp;
+
+                                tp = trap_at(i, j);
+                                rp = roomin(hero);
+
+                                if (tp->tr_type == FIRETRAP && rp != NULL)
+                                {
+                                    rp->r_flags &= ~ISDARK;
+                                    light(&hero);
+                                }
+
+                                tp->tr_flags |= ISFOUND;
+                            }
+                    }
+                    if (nch != ch)
+                        waddch(hw, nch);
+                }
+
+            /* Copy in what he has discovered */
+            overlay(cw, hw);
+
+            /* And set up for display */
+            overwrite(hw, cw);
+
+            break;
+
+        case S_GFIND:
+            /* Scroll of gold detection */
+
+            if (cursed)
+            {
+                int n = roll(3, 6);
+                int k;
+                struct room *rp;
+                coord   pos;
+
+                msg("You begin to feel greedy and you sense gold.");
+                wclear(hw);
+
+                for (k = 1; k < n; k++)
+                {
+                    rp = &rooms[rnd_room()];
+                    rnd_pos(rp, &pos);
+                    mvwaddch(hw, pos.y, pos.x, GOLD);
+                }
+                overlay(hw, cw);
+
+                break;
+            }
+
+            if (blessed)
+                turn_on(player, BLESSGOLD);
+
+            if (gsense() && is_scroll)
+                know_items[TYP_SCROLL][S_GFIND] = TRUE;
+
+            break;
+
+        case S_SELFTELEP:
+
+            /* Scroll of teleportation: Make him disappear and reappear */
+
+            if (cursed)
+            {
+                level += 5 + rnd(5);
+                new_level(NORMLEV,0);
+                mpos = 0;
+                msg("You are banished to the lower regions.");
+            }
+            else if (blessed)
+            {
+                level -= rnd(3) + 1;
+
+                if (level < 1)
+                    level = 1;
+
+                mpos = 0;
+                new_level(NORMLEV,0); /* change levels */
+                status(TRUE);
+                msg("You are whisked away to another region.");
+            }
+            else
+            {
+                teleport();
+
+                if (is_scroll)
+                    know_items[TYP_SCROLL][S_SELFTELEP] = TRUE;
+            }
+
+            if (off(player, ISCLEAR))
+            {
+                if (on(player, ISHUH))
+                    lengthen_fuse(FUSE_UNCONFUSE, rnd(4) + 4);
+                else
+                {
+                    light_fuse(FUSE_UNCONFUSE, 0, rnd(4) + 4, AFTER);
+                    turn_on(player, ISHUH);
+                }
+            }
+            else
+                msg("You feel dizzy for a moment, but it quickly passes.");
+
+            break;
+
+        case S_SCARE:
+
+            /*
+             * A blessed scroll of scare monster automatically transports
+             * itself to the hero's feet
+             *
+             */
+
+            if (blessed)
+            {
+                ch = CCHAR( mvwinch(stdscr, hero.y, hero.x) );
+
+                if (ch != FLOOR && ch != PASSAGE)
+                {
+                    msg("Your feet tickle for a moment");
+                    return;
+                }
+
+                item = spec_item(SCROLL, S_SCARE, 0, 0);
+
+                obj = OBJPTR(item);
+                obj->o_flags = ISCURSED;
+                obj->o_pos = hero;
+                add_obj(item, hero.y, hero.x);
+                msg("A wave of terror sweeps throughout the room");
+            }
+            else
+            {
+                /*
+                 * A monster will refuse to step on a scare monster
+                 * scroll if it is dropped.  Thus reading it is a
+                 * mistake and produces laughter at the poor rogue's
+                 * boo boo.
+                 */
+
+                msg("You hear maniacal laughter in the distance.");
+
+                if (cursed) /* If cursed, monsters get mad */
+                    aggravate();
+            }
+            break;
+
+        case S_REMOVECURSE:
+            if (cursed)     /* curse a player's possession */
+            {
+                for (nitem = pack; nitem != NULL; nitem = next(nitem))
+                {
+                    obj = OBJPTR(nitem);
+
+                    if (rnd(5) == 0)
+                        if (obj->o_flags & ISBLESSED)
+                            obj->o_flags &= ~ISBLESSED;
+                        else
+                            obj->o_flags |= ISCURSED;
+                }
+                msg("The smell of fire and brimstone comes from your pack.");
+            }
+            else if (blessed)
+            {
+                for (nitem = pack; nitem != NULL; nitem = next(nitem))
+                    (OBJPTR(nitem))->o_flags &= ~ISCURSED;
+
+                msg("Your pack glistens brightly.");
+            }
+            else
+            {
+                if ((nitem = get_item("remove the curse on", 0)) != NULL)
+                {
+                    obj = OBJPTR(nitem);
+                    msg("Removed the curse from %s.", inv_name(obj, LOWERCASE));
+                    obj->o_flags &= ~ISCURSED;
+
+                    if (is_scroll)
+                        know_items[TYP_SCROLL][S_REMOVECURSE] = TRUE;
+                }
+            }
+            break;
+
+        case S_PETRIFY:
+            switch(CCHAR(mvinch(hero.y, hero.x)))
+            {
+                case TRAPDOOR:
+                case DARTTRAP:
+                case TELTRAP:
+                case ARROWTRAP:
+                case SLEEPTRAP:
+                case BEARTRAP:
+                case FIRETRAP:
+                {
+                    int n;
+
+                    /* Find the right trap */
+                    for (n = 0; n < ntraps && !ce(traps[n].tr_pos, hero); n++)
+                        ;
+
+                    ntraps--;
+
+                    if (!ce(traps[n].tr_pos, hero))
+                        msg("What a strange trap!");
+                    else
+                    {
+                        while (n < ntraps)
+                        {
+                            traps[n] = traps[n + 1];
+                            n++;
+                        }
+                    }
+
+                    msg("The dungeon begins to rumble and shake!");
+                    addch(WALL);
+
+                    if (on(player, CANINWALL))
+                    {
+                        extinguish_fuse(FUSE_UNPHASE);
+                        turn_off(player, CANINWALL);
+                        msg("Your dizzy feeling leaves you.");
+                    }
+
+                    turn_on(player, ISINWALL);
+                }
+                break;
+
+                case DOOR:
+                case SECRETDOOR:
+                {
+                    struct room *rp = roomin(hero);
+                    short   n;
+
+                    /* Find the right door */
+
+                    for (n=0; n<rp->r_nexits && !ce(rp->r_exit[n], hero); n++)
+                        /* do nothing */ ;
+
+                    rp->r_nexits--;
+
+                    if (!ce(rp->r_exit[n], hero))
+                        msg("What a strange door!");
+                    else
+                    {
+                        while (n < rp->r_nexits)
+                        {
+                            rp->r_exit[n] = rp->r_exit[n + 1];
+                            n++;
+                        }
+                    }
+                    /* No break - fall through */
+                }
+                case FLOOR:
+                case PASSAGE:
+                    msg("The dungeon begins to rumble and shake!");
+                    addch(WALL);
+
+                    if (on(player, CANINWALL))
+                    {
+                        extinguish_fuse(FUSE_UNPHASE);
+                        turn_off(player, CANINWALL);
+                        msg("Your dizzy feeling leaves you.");
+                    }
+
+                    turn_on(player, ISINWALL);
+                    break;
+
+                default:
+                    nothing_message(flags);
+                    break;
+            }
+            break;
+
+        case  S_GENOCIDE:
+            msg("You have been granted the boon of genocide!--More--");
+
+            wait_for(' ');
+            msg("");
+
+            genocide(flags);
+
+            if (is_scroll)
+                know_items[TYP_SCROLL][S_GENOCIDE] = TRUE;
+
+            break;
+
+        case S_PROTECT:
+            if (is_scroll && know_items[TYP_SCROLL][S_PROTECT] == FALSE)
+            {
+                msg("You can protect something from rusting or theft.");
+                know_items[TYP_SCROLL][S_PROTECT] = TRUE;
+            }
+
+            if ((item = get_item("protect", 0)) != NULL)
+            {
+                struct object   *lb = OBJPTR(item);
+
+                if (cursed)
+                {
+                    lb->o_flags &= ~ISPROT;
+                    mpos = 0;
+                    msg("Unprotected %s.", inv_name(lb, LOWERCASE));
+                }
+                else
+                {
+                    lb->o_flags |= ISPROT;
+                    mpos = 0;
+                    msg("Protected %s.", inv_name(lb, LOWERCASE));
+                }
+            }
+            break;
+
+        case S_MAKEITEMEM:
+            if (!is_scroll || rnd(luck))
+                feel_message();
+            else
+            {
+                char itemtype;
+
+                if (is_scroll)
+                    know_items[TYP_SCROLL][S_MAKEITEMEM] = TRUE;
+
+                msg("You have been endowed with the power of creation.");
+
+                if (blessed)
+                    itemtype = '\0';
+                else
+                    switch (rnd(6))
+                    {
+                        case 0: itemtype = RING;    break;
+                        case 1: itemtype = POTION;  break;
+                        case 2: itemtype = SCROLL;  break;
+                        case 3: itemtype = ARMOR;   break;
+                        case 4: itemtype = WEAPON;  break;
+                        case 5: itemtype = STICK;   break;
+                    }
+
+                flags |= SCR_MAGIC;
+                buy_it(itemtype, flags);
+            }
+            break;
+
+        case S_ENCHANT:
+        {
+            struct linked_list  *ll;
+            struct object   *lb;
+            int howmuch, flg=0;
+
+            if (is_scroll && know_items[TYP_SCROLL][S_ENCHANT] == FALSE)
+            {
+                msg("You are granted the power of enchantment.");
+                msg("You may enchant anything(weapon,ring,armor,scroll,potion)");
+                know_items[TYP_SCROLL][S_ENCHANT] = TRUE;
+            }
+
+            if ((ll = get_item("enchant", 0)) != NULL)
+            {
+                lb = OBJPTR(ll);
+                lb->o_flags &= ~ISCURSED;
+
+                if (blessed)
+                    howmuch = 2;
+                else if (cursed)
+                    howmuch = -1;
+                else
+                {
+                    howmuch = 1;
+                    flg |= ISBLESSED;
+                }
+
+                switch (lb->o_type)
+                {
+                    case RING:
+                        lb->o_ac += howmuch;
+
+                        if (lb->o_ac > 5 && rnd(5) == 0)
+                        {
+                            msg("Your ring explodes in a cloud of smoke.");
+                            lb->o_flags &= ~ISCURSED;
+                            dropcheck(lb);
+
+                            switch (lb->o_which)
+                            {
+                                case R_ADDSTR:
+                                    chg_str(-2, TRUE, FALSE);
+                                    break;
+                                case R_ADDHIT:
+                                    chg_dext(-2, TRUE, FALSE);
+                                    break;
+                                case R_ADDINTEL:
+                                    pstats.s_intel -= 2;
+                                    max_stats.s_intel -= 2;
+                                    break;
+                                case R_ADDWISDOM:
+                                    pstats.s_wisdom -= 2;
+                                    max_stats.s_wisdom -= 2;
+                                    break;
+                            }
+
+                            del_pack(ll);
+                            lb = NULL;
+                        }
+                        else if (is_r_on(lb))
+                            switch (lb->o_which)
+                            {
+                                case R_ADDSTR:
+                                    pstats.s_str += howmuch;
+                                    break;
+                                case R_ADDHIT:
+                                    pstats.s_dext += howmuch;
+                                    break;
+                                case R_ADDINTEL:
+                                    pstats.s_intel += howmuch;
+                                    break;
+                                case R_ADDWISDOM:
+                                    pstats.s_wisdom += howmuch;
+                                    break;
+                                case R_CARRYING:
+                                    updpack();
+                                    break;
+                            }
+
+                        break;
+
+                    case ARMOR:
+                        lb->o_ac -= howmuch;
+
+                        if (armors[lb->o_which].a_class - lb->o_ac > 5 && rnd(5) == 0)
+                        {
+                            msg("Your %s explodes in a cloud of dust.",
+                                inv_name(lb, LOWERCASE));
+
+                            lb->o_flags &= ~ISCURSED;
+
+                            if (lb == cur_armor)
+                                pstats.s_hpt /= 2;
+
+                            dropcheck(lb);
+                            del_pack(ll);
+                            lb = NULL;
+                        }
+                        break;
+
+                    case STICK:
+                        if (wizard || howmuch != 1 && rnd(5) == 0)
+                            lb->o_flags |= flg;
+
+                        lb->o_charges += howmuch + 10;
+
+                        if (lb->o_charges < 0)
+                            lb->o_charges = 0;
+
+                        if (lb->o_charges > 50 && rnd(5) == 0)
+                        {
+                            msg("Your %s explodes into splinters.",
+                                inv_name(lb, LOWERCASE));
+
+                            lb->o_flags &= ~ISCURSED;
+                            dropcheck(lb);
+                            del_pack(ll);
+                            lb = NULL;
+                        }
+                        break;
+
+                    case WEAPON:
+                        if (rnd(100) < 50)
+                            lb->o_hplus += howmuch;
+                        else
+                            lb->o_dplus += howmuch;
+
+                        if (lb->o_hplus + lb->o_dplus > 10 && rnd(5) == 0)
+                        {
+                            msg("Your %s explodes in a cloud of shrapnel",
+                                inv_name(lb, LOWERCASE));
+
+                            lb->o_flags &= ~ISCURSED;
+
+                            if (lb == cur_weapon)
+                                chg_dext(-2, FALSE, TRUE);
+
+                            dropcheck(lb);
+                            del_pack(ll);
+                            lb = NULL;
+
+                        }
+                        break;
+
+                    case POTION:
+                    case SCROLL:
+                    default:
+                        lb->o_flags |= flg;
+                        break;
+                }
+
+                mpos = 0;
+
+                if (lb != NULL)
+                    msg("Enchanted %s.", inv_name(lb, LOWERCASE));
+            }
+        }
+        break;
+
+        case S_NOTHING:
+            nothing_message(flags);
+            break;
+
+        case S_SILVER:
+        {
+            struct object   *lb;
+
+            if (is_scroll && know_items[TYP_SCROLL][S_SILVER] == FALSE)
+            {
+                msg("You are granted the power of magic hitting.");
+                know_items[TYP_SCROLL][S_SILVER] = TRUE;
+            }
+
+            if ((item = get_item("annoint", WEAPON)) != NULL)
+            {
+                lb = OBJPTR(item);
+
+                if (blessed && !(lb->o_flags & ISSILVER))
+                {
+                    lb->o_hplus += rnd(3) + 1;
+                    lb->o_flags |= ISSILVER;
+                    lb->o_flags |= ISMETAL;
+                    msg("Your weapon has turned to silver!");
+                }
+                else if (cursed && (lb->o_flags & ISSILVER))
+                {
+                    lb->o_hplus -= (rnd(3) + 1);
+                    lb->o_flags &= ~ISSILVER;
+                    msg("Your silver weapon has turned to steel.");
+                }
+                else if (lb->o_flags & ISSILVER)
+                {
+                    msg("Your silver weapon glitters briefly.");
+                    lb->o_hplus += rnd(2);
+                }
+                else
+                {
+                    lb->o_hplus += rnd(3);
+                    lb->o_flags |= ISSILVER;
+                    lb->o_flags |= ISMETAL;
+                    msg("Your weapon has turned to silver.");
+                }
+            }
+        }
+        break;
+        case S_OWNERSHIP:
+        {
+            struct linked_list  *ll;
+            struct object   *lb;
+
+            if (is_scroll && know_items[TYP_SCROLL][S_OWNERSHIP] == FALSE)
+            {
+                msg("You are granted the power of ownership.");
+                know_items[TYP_SCROLL][S_OWNERSHIP] = TRUE;
+            }
+
+            if ((ll = get_item("claim", 0)) != NULL)
+            {
+                lb = OBJPTR(ll);
+
+                if (cursed && lb->o_flags & (ISOWNED | CANRETURN))
+                {
+                    lb->o_flags &= ~(ISOWNED | CANRETURN);
+                    msg("The gods seem to have forgotten you.");
+                }
+                else if (cursed && !(lb->o_flags & ISLOST))
+                {
+                    lb->o_flags |= ISLOST;
+                    msg("The gods look the other way.");
+                }
+                else if (blessed && lb->o_flags & ISLOST)
+                {
+                    lb->o_flags |= CANRETURN;
+                    msg("The gods seem to have remembered you.");
+                }
+                else if (blessed && !(lb->o_flags & ISOWNED))
+                {
+                    lb->o_flags |= (ISOWNED | CANRETURN);
+                    msg("The gods smile upon you.");
+                }
+                else if (blessed | cursed)
+                {
+                    nothing_message(flags);
+                }
+                else
+                {
+                    lb->o_flags |= CANRETURN;
+                    msg("The gods look upon you.");
+                }
+            }
+        }
+        break;
+
+        case S_FOODDET:
+
+            /* Scroll of food detection */
+
+            if (cursed)
+            {
+                int n = roll(3, 6);
+                int k;
+                struct room *rp;
+                coord   pos;
+
+                msg("You begin to feel hungry and you smell food.");
+                wclear(hw);
+
+                for (k = 1; k < n; k++)
+                {
+                    rp = &rooms[rnd_room()];
+                    rnd_pos(rp, &pos);
+                    mvwaddch(hw, pos.y, pos.x, FOOD);
+                }
+
+                overlay(hw, cw);
+
+                if (is_scroll)
+                    know_items[TYP_SCROLL][S_FOODDET] = TRUE;
+
+                break;
+            }
+
+            if (blessed)
+                turn_on(player, BLESSFOOD);
+
+            if (off(player, ISUNSMELL) && lvl_obj != NULL)
+            {
+                struct linked_list  *itm;
+                struct object   *cur;
+                struct thing    *th;
+                int fcount = 0;
+                int  same_room = FALSE;
+                struct room *rp = roomin(hero);
+
+                wclear(hw);
+
+                for (itm = lvl_obj; itm != NULL; itm = next(itm))
+                {
+                    cur = OBJPTR(itm);
+
+                    if (cur->o_type == FOOD)
+                    {
+                        fcount += cur->o_count;
+                        mvwaddch(hw, cur->o_pos.y, cur->o_pos.x, FOOD);
+
+                        if (roomin(cur->o_pos) == rp)
+                            same_room = TRUE;
+                    }
+                }
+
+                for (itm = mlist; itm != NULL; itm = next(itm))
+                {
+                    struct linked_list  *pitem;
+
+                    th = THINGPTR(itm);
+
+                    for (pitem = th->t_pack; pitem != NULL; pitem = next(pitem))
+                    {
+                        cur = OBJPTR(pitem);
+
+                        if (cur->o_type == FOOD)
+                        {
+                            fcount += cur->o_count;
+                            mvwaddch(hw, th->t_pos.y, th->t_pos.x, FOOD);
+
+                            if (roomin(th->t_pos) == rp)
+                                same_room = TRUE;
+                        }
+                    }
+                }
+
+                if (fcount)
+                {
+                    if (is_scroll)
+                        know_items[TYP_SCROLL][S_FOODDET] = TRUE;
+
+                    if (same_room)
+                        msg("FOOOOD!!");
+                    else
+                        msg("You begin to feel hungry and you smell food.");
+
+                    overlay(hw, cw);
+                    break;
+                }
+            }
+
+            if (off(player, ISUNSMELL))
+                msg("You can't smell anything.");
+            else
+                nothing_message(flags);
+
+            break;
+
+        case S_ELECTRIFY:
+            if (on(player, ISELECTRIC))
+            {
+                msg("Your violet glow brightens for an instant.");
+                lengthen_fuse(FUSE_UNELECTRIFY, 4 + rnd(8));
+            }
+            else
+            {
+                msg("Your body begins to glow violet and shoot sparks.");
+                turn_on(player, ISELECTRIC);
+                light_fuse(FUSE_UNELECTRIFY,0,(blessed?3:1)*WANDERTIME, AFTER);
+                light(&hero);
+            }
+
+            if (is_scroll)
+                know_items[TYP_SCROLL][S_ELECTRIFY] = TRUE;
+
+            break;
+
+        case S_CHARM:
+
+            /*
+             * Beauty, brains and experience make a person charming.
+             * Unique monsters can never be charmed.
+             */
+
+            charm_power = pstats.s_charisma / 2 + pstats.s_lvl / 3 + max(0, pstats.s_intel - 15);
+
+            if (cursed)
+            {
+                msg("You hear harsh, dissonant twanging throughout the dungeon.");
+                aggravate();
+            }
+            else if (blessed)  /* Charm entire level */
+            {
+                struct linked_list  *mon;
+
+                msg("You hear ringingly meliflous music all around you.");
+
+                for (mon = mlist; mon != NULL; mon = next(mon))
+                {
+                    struct thing    *th = THINGPTR(mon);
+
+                    if (th->t_stats.s_intel < charm_power && off(*th, ISUNIQUE))
+                    {
+                        turn_on(*th, ISCHARMED);
+                        chase_it(&th->t_pos, &player);
+                    }
+                }
+            }
+            else        /* Charm all monsters within two spaces of the hero */
+            {
+                int x, y;
+                struct linked_list  *mon;
+
+                msg("You hear soft, lyrical music all around you.");
+
+                for (x = hero.x - 2; x <= hero.x + 2; x++)
+                    for (y = hero.y - 2; y <= hero.y + 2; y++)
+                        if (y > 0 && x > 0 && isalpha(mvwinch(mw, y, x)))
+                        {
+                            if ((mon = find_mons(y, x)) != NULL)
+                            {
+                                struct thing    *th;
+
+                                th = THINGPTR(mon);
+
+                                if (th->t_stats.s_intel < charm_power && off(*th, ISUNIQUE))
+                                {
+                                    turn_on(*th, ISCHARMED);
+                                    chase_it(&th->t_pos, &player);
+                                }
+                            }
+                        }
+            }
+            break;
+
+        case S_SUMMON:
+        {
+            struct linked_list  *llp;
+            struct thing    *tp;
+            int mon_type;
+
+            if (on(player, HASSUMMONED))
+            {
+                nothing_message(flags);
+                break;
+            }
+
+            if (cursed)
+            {
+                creat_mons(&player, (short) 0, MESSAGE);
+                break;
+            }
+
+            if (blessed)    /* Summon a possibly very high monster */
+            {
+                int nsides = max(2, max(pstats.s_lvl, 12) - luck);
+
+                mon_type = roll(nsides, rnd(pstats.s_charisma + 15) + 8);
+                mon_type = min(mon_type, nummonst);
+            }
+            else
+                mon_type = 0;
+
+	    llp = summon_monster((short) mon_type, NOFAMILIAR, NOMESSAGE);
+
+            if (llp)
+            {
+                tp = THINGPTR(llp);
+                turn_on(*tp, WASSUMMONED);
+                turn_on(player, HASSUMMONED);
+                msg("You have summoned a %s.", monsters[tp->t_index].m_name);
+                light_fuse(FUSE_UNSUMMON, llp, WANDERTIME + rnd(pstats.s_lvl), AFTER);
+            }
+        }
+        break;
+
+        case S_REFLECT:
+            if (on(player, CANREFLECT))
+            {
+                msg("The sparkling around you brightens momentarily.");
+                lengthen_fuse(FUSE_UNGAZE, 5 + rnd(10));
+            }
+            else
+            {
+                msg("Shiny particles sparkle all around you.");
+                turn_on(player, CANREFLECT);
+                light_fuse(FUSE_UNGAZE, 0, (blessed ? 3 : 1) * WANDERTIME, AFTER);
+            }
+            break;
+
+        case S_SUMFAMILIAR:
+        {
+            int type = 0;
+
+            if (on(player, HASFAMILIAR))
+            {
+                msg("But you already have a familiar - somewhere...");
+                return;
+            }
+
+            if (wizard)
+                type = get_monster_number("be your familiar");
+            else if (blessed)  /* Summon a possibly very high monster */
+            {
+                int nsides = max(2, max(pstats.s_lvl, 12) - luck);
+
+                type = roll(nsides, rnd(pstats.s_charisma + 15) + 8);
+                type = min(type, nummonst);
+            }
+            else if (cursed)    /* Summon a bat, maggot, eye, etc */
+            {
+                type = rnd(20) + 1; 
+				
+                if (summon_monster(type, FAMILIAR, MESSAGE))
+                    turn_on(player, HASFAMILIAR);
+            }
+        }
+        break;
+
+        case S_FEAR:
+
+            /* if cursed, you get frightened */
+
+            if (cursed)
+            {
+                if (off(player, SUPERHERO) && (player.t_ctype != C_PALADIN) && !save(VS_DEATH))
+                    msg("A momentary wave of panic sweeps over you.");
+                else
+                {
+                    msg("Panicstricken, you fall into a coma.");
+                    no_command += roll(2, SLEEPTIME);
+                }
+            }
+            else
+            {
+                /*
+                 * terrify monster scroll.  frightens all monsters
+                 * within 2 spaces
+                 */
+                int x, y;
+                struct linked_list  *mon;
+                int  gotone = FALSE;
+
+                for (x = hero.x - 2; x <= hero.x + 2; x++)
+                {
+                    for (y = hero.y - 2; y <= hero.y + 2; y++)
+                    {
+                        if (y > 0 && x > 0 && isalpha(mvwinch(mw, y, x)))
+                        {
+                            if ((mon = find_mons(y, x)) != NULL)
+                            {
+                                struct thing    *th;
+
+                                th = THINGPTR(mon);
+
+                                if (on(*th, ISUNDEAD) || on(*th, ISUNIQUE))
+                                    continue;
+
+                                gotone = TRUE;
+                                turn_on(*th, ISFLEE);
+                                th->t_chasee = &player;
+                                th->t_ischasing = FALSE;
+                                th->t_horde = NULL;
+                            }
+                        }
+                    }
+                }
+
+                if (gotone)
+                    seemsg("The monster(s) around you recoil in horror.");
+                else
+                    nothing_message(flags);
+            }
+            break;
+
+        case  S_MSHIELD:  /* deal with blessed/cursed later */
+            if (on(player, HASMSHIELD))
+            {
+                seemsg("The fog around you thickens.");
+                lengthen_fuse(FUSE_UNMSHIELD, (blessed ? 3 : 1) * HEROTIME);
+            }
+            else
+            {
+                seemsg("A fog forms around you.");
+                turn_on(player, HASMSHIELD);
+                light_fuse(FUSE_UNMSHIELD, 0, (blessed ? 3 : 1) * HEROTIME, AFTER);
+            }
+
+            if (is_scroll)
+                know_items[TYP_SCROLL][S_MSHIELD] = TRUE;
+
+            break;
+
+        default:
+            msg("What a puzzling scroll!");
+            return;
+    }
+
+    look(TRUE);     /* put the result of the scroll on the screen */
+    status(FALSE);
+
+    if (is_scroll)
+    {
+        if (know_items[TYP_SCROLL][which] && guess_items[TYP_SCROLL][which])
+        {
+            ur_free(guess_items[TYP_SCROLL][which]);
+            guess_items[TYP_SCROLL][which] = NULL;
+        }
+        else if (askme && !know_items[TYP_SCROLL][which] && guess_items[TYP_SCROLL][which] == NULL)
+        {
+            msg("What do you want to call it? ");
+
+            if (get_string(buf, cw) == NORM)
+            {
+                guess_items[TYP_SCROLL][which] = new_alloc(strlen(buf) + 1);
+                strcpy(guess_items[TYP_SCROLL][which], buf);
+            }
+        }
+    }
+}
+
+/*
+    creat_mons()
+        creates the specified monster -- any if 0
+*/
+
+struct linked_list  *
+creat_mons(struct thing *person, int monster, int message)
+{
+    coord   mp;
+
+    /* Search for an open place */
+
+    debug("Creator @(%d, %d) ", person->t_pos.y, person->t_pos.x);
+
+    if ((place_mons(person->t_pos.y, person->t_pos.x, &mp)) != FALSE)
+    {
+        struct linked_list *nitem;
+
+        nitem = new_item(sizeof(struct thing));
+        new_monster(nitem, monster == 0 ? randmonster(NOWANDER, NOGRAB)
+                : monster, &mp, MAXSTATS);
+        chase_it(&mp, &player);
+
+        /* If the monster is on a trap, trap it */
+
+        if (isatrap(mvinch(mp.y, mp.x)))
+        {
+            debug("Monster trapped during creat_mons.");
+            be_trapped(THINGPTR(nitem), mp);
+        }
+
+        light(&hero);
+        return(nitem);
+    }
+
+    if (message)
+        hearmsg("You hear a faint cry of anguish in the distance.");
+
+    return(NULL);
+}
+
+/*
+    place_mons()
+        finds a place to put the monster
+*/
+
+int
+place_mons(int y, int x, coord *pos)
+{
+    int distance, xx, yy, appears;
+
+    for (distance = 1; distance <= 10; distance++)
+    {
+        appears = 0;
+
+        for (yy = y - distance; yy <= y + distance; yy++)
+            for (xx = x - distance; xx <= x + distance; xx++)
+            {
+                /* Don't put a monster in top of the creator or player */
+
+                if (xx < 0 || yy < 0)
+                    continue;
+
+                if (yy == y && xx == x)
+                    continue;
+
+                if (yy == hero.y && xx == hero.x)
+                    continue;
+
+                /* Or anything else nasty */
+
+                if (step_ok(yy, xx, NOMONST, FALSE))
+                {
+                    if (rnd(max(1, (10 * distance - ++appears))) == 0)
+                    {
+                        pos->y = yy;
+                        pos->x = xx;
+                        debug("Make monster dist %d appear %d @(%d, %d) ",
+                              distance, appears, pos->y, pos->x);
+                        return(TRUE);
+                    }
+                }
+            }
+    }
+    return(FALSE);
+}
+
+/*
+    is_t_on()
+        This subroutine determines if an object that is a ring is being
+        worn by the hero  by Bruce Dautrich 4/3/84
+ */
+
+int
+is_r_on(struct object *obj)
+{
+    if (obj == cur_ring[LEFT_1] || obj == cur_ring[LEFT_2] ||
+        obj == cur_ring[LEFT_3] || obj == cur_ring[LEFT_4] ||
+        obj == cur_ring[LEFT_5] ||
+        obj == cur_ring[RIGHT_1] || obj == cur_ring[RIGHT_2] ||
+        obj == cur_ring[RIGHT_3] || obj == cur_ring[RIGHT_4] ||
+        obj == cur_ring[RIGHT_5])
+    {
+        return(TRUE);
+    }
+
+    return(FALSE);
+}
+
+/*
+    monread()
+        monster gets the effect
+*/
+
+void
+monread(struct thing *reader, int which, int flags)
+{
+    struct stats    *curp = &(reader->t_stats);
+    struct stats    *maxp = &(reader->maxstats);
+    int blessed = flags & ISBLESSED;
+    int cursed = flags & ISCURSED;
+
+    switch (which)
+    {
+        case S_SELFTELEP:
+            /* If monster was suffocating, stop it */
+            if (on(*reader, DIDSUFFOCATE))
+            {
+                turn_off(*reader, DIDSUFFOCATE);
+                extinguish_fuse(FUSE_SUFFOCATE);
+            }
+
+            /* If monster held us, stop it */
+
+            if (on(*reader, DIDHOLD) && (hold_count == 0))
+                turn_off(player, ISHELD);
+
+            turn_off(*reader, DIDHOLD);
+
+            if (cursed)
+                reader->t_no_move++;
+            else
+            {
+                int rm;
+
+                if (blessed)    /* Give him his hit points */
+                    curp->s_hpt = maxp->s_hpt;
+
+                /* Erase the monster from the old position */
+
+                if (isalpha(mvwinch(cw, reader->t_pos.y, reader->t_pos.x)))
+                    mvwaddch(cw, reader->t_pos.y, reader->t_pos.x, reader->t_oldch);
+
+                mvwaddch(mw, reader->t_pos.y, reader->t_pos.x, ' ');
+
+                /* Get a new position */
+
+                do
+                {
+                    rm = rnd_room();
+                    rnd_pos(&rooms[rm], &reader->t_pos);
+                }
+                while (winat(reader->t_pos.y, reader->t_pos.x) != FLOOR);
+
+                /* Put it there */
+
+                mvwaddch(mw, reader->t_pos.y, reader->t_pos.x, reader->t_type);
+                reader->t_oldch = CCHAR( mvwinch(cw, reader->t_pos.y, reader->t_pos.x) );
+            }
+            break;
+
+        default:
+            debug("'%s' is a strange scroll for a monster to read!",
+                  r_magic[which].mi_name);
+            break;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/state.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1445 @@
+/*
+    state.c - Portable Rogue Save State Code
+
+    Copyright (C) 1993, 1995 Nicholas J. Kisseberth
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+    3. Neither the name(s) of the author(s) nor the names of other contributors
+       may be used to endorse or promote products derived from this software
+       without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+    ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+*/
+
+/*
+    Notes
+
+        Should move all game variables into one place
+        Should move save/restore code into save.c or some such
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rogue.h"
+
+/*
+     Variables for global game state.
+
+     All variables that need to get saved when saving a game
+     are defined in this file. Long term goal is to move many
+     of these variables into a "struct level" data type of some
+     kind... perhaps not, maybe struct game...
+
+     Other global variables that don't need to get saved are
+     kept in main.c.
+
+     Other global variables that don't change during the course
+     of a game are kept in urogue.c, monsdata.c, data.c.
+*/
+
+#define _X_ { 0, 0, 0, 0, 0 }
+
+struct delayed_action
+d_list[MAXDAEMONS] =        /* daemon/fuse list                         */
+{
+        _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
+        _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
+        _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
+        _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
+        _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
+        _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
+};
+
+#undef _X_
+
+char *s_names[MAXSCROLLS];   /* Names of the scrolls         */
+char *p_colors[MAXPOTIONS];  /* Colors of the potions        */
+char *r_stones[MAXRINGS];    /* Stone settings of the rings  */
+char *ws_made[MAXSTICKS];    /* What sticks are made of      */
+char *ws_type[MAXSTICKS];    /* Is it a wand or a staff      */
+
+char *guess_items[MAXMAGICTYPES][MAXMAGICITEMS]; /* guess magic is          */
+int   know_items[MAXMAGICTYPES][MAXMAGICITEMS];  /* flag knowlede of magic  */
+                                                 /* object data             */
+
+struct trap          traps[2 * MAXTRAPS];   /* 2x for special effects       */
+struct room          rooms[MAXROOMS];       /* One for each room -- A level */
+struct room         *oldrp = NULL;          /* Roomin(&player.t_oldpos)     */
+struct thing         player;                /* The rogue                    */
+struct linked_list  *lvl_obj = NULL;        /* Treasure on this level       */
+struct linked_list  *fam_ptr = NULL;        /* A ptr to the familiar        */
+struct linked_list  *mlist = NULL;          /* Monsters on this level       */
+struct thing        *beast;                 /* The last beast that attacked */
+struct object       *cur_armor  = NULL;     /* what rogue  wears            */
+struct object       *cur_weapon = NULL;     /* ... and wields               */
+struct object       *cur_ring[10];          /* His rings                    */
+struct linked_list  *curr_mons  = NULL;     /* The mons. currently moving   */
+struct linked_list  *next_mons = NULL;      /* The mons. after curr_mons    */
+
+/* Misc. game state info */
+char dummybuf1[50000];
+char dummybuf2[50000];
+char msgbuf[10][2*LINELEN]; /* message buffer history                   */
+int  msg_index = 0;         /* index in msg history buffer for nxt msg  */
+int  foodlev         = 1;           /* how fast he eats food            */
+int  ntraps          = 0;           /* Number of traps on this level    */
+int  dnum            = 0;           /* Dungeon number                   */
+int  max_level       = 0;           /* Deepest player has gone          */
+int  lost_dext       = 0;           /* amount of lost dexterity         */
+int  no_command      = 0;
+int  level           = 0;
+int  see_dist        = 3;
+int  no_food         = 0;
+int  count           = 0;
+int  food_left       = HUNGERTIME;
+int  group           = 1;
+int  hungry_state    = F_OK;
+int  infest_dam      = 0;
+int  lost_str        = 0;
+int  hold_count      = 0;
+int  trap_tries      = 0;
+int  has_artifact    = 0;
+int  picked_artifact = 0;
+int  luck            = 0;
+int  resurrect       = 0;
+int  fam_type        = 0;           /* The type of familiar             */
+int  mons_summoned   = 0;           /* Number of summoned monsters      */
+char PLAYER          = VPLAYER;     /* what the player looks like       */
+char take            = 0;           /* Thing the rogue is taking        */
+char runch           = 0;           /* Direction player is running      */
+int  char_type       = C_NOTSET;    /* what type of character is player */
+int  inv_type        = INV_CLEAR;   /* Overwrite style of inventory     */
+int  pool_teleport   = FALSE;       /* just teleported from a pool      */
+int  inwhgt          = FALSE;       /* true if from wghtchk()           */
+int  after           = 0;           /* True if we want after daemons    */
+int  waswizard       = 0;           /* Was a wizard sometime            */
+int  canwizard       = 1;           /* Will be permitted to do this     */
+int  playing         = TRUE;
+int  running         = FALSE;
+int  fighting        = FALSE;
+int  wizard          = FALSE;
+int  wiz_verbose     = TRUE;
+int  moving          = FALSE;
+coord    delta;                     /* Change indicated to get_dir()    */
+LEVTYPE  levtype;                   /* type of level i'm on             */
+long purse  = 0;
+unsigned long total  = 0;
+
+WINDOW  *cw;                        /* Window that the player sees      */
+WINDOW  *hw;                        /* Used for the help command        */
+WINDOW  *mw;                        /* Used to store mosnters           */
+
+/* options.o    */
+/* game options */
+
+int  terse       = FALSE;
+int  door_stop   = FALSE;
+int  jump        = TRUE;
+int  doorstop    = TRUE;
+int  firstmove   = FALSE;
+int  askme       = FALSE;
+char whoami[2 * LINELEN];           /* Name of player  */
+char fruit[2 * LINELEN];            /* Favorite fruit  */
+char file_name[2 * LINELEN];        /* Save file name  */
+char score_file[2 * LINELEN];       /* Score file name */
+
+/****************************************************************************/
+/* Portable Save State Code                                                 */
+/*                                                                          */
+/*    UltraRogue v1.04                                                      */
+/****************************************************************************/
+
+#define URS_STATS        0xABCD0001
+#define URS_THING        0xABCD0002
+#define URS_OBJECT       0xABCD0003
+#define URS_MAGIC        0xABCD0004
+#define URS_KNOWS        0xABCD0005
+#define URS_GUESSES      0xABCD0006
+#define URS_STACKOBJECT  0xABCD0007
+#define URS_BAGOBJECT    0xABCD0008
+#define URS_MONSTERLIST  0xABCD0009
+#define URS_MONSTERSTATS 0xABCD000A
+#define URS_MONSTER      0xABCD000B
+#define URS_TRAP         0xABCD000C
+#define URS_WINDOW       0xABCD000D
+#define URS_DAEMONS      0xABCD000E
+
+void
+ur_write(FILE *savef, void *ptr, size_t size)
+{
+    if (size == 0)
+        return;
+
+    fwrite(ptr,size,1,savef);
+}
+
+void
+ur_read(FILE *savef, void *ptr, size_t size)
+{
+    if (size == 0)
+        return;
+
+    fread(ptr,size,1,savef);
+}
+
+void
+ur_write_int(FILE *savef, int c)
+{
+    ur_write(savef,&c,sizeof(int));
+}
+
+int
+ur_read_int(FILE *savef)
+{
+    int i;
+
+    ur_read(savef, &i, sizeof(int));
+
+    return(i);
+}
+
+void
+ur_write_short(FILE *savef, short c)
+{
+    ur_write(savef,&c,sizeof(short));
+}
+
+short
+ur_read_short(FILE *savef)
+{
+    short s;
+
+    ur_read(savef, &s, sizeof(short));
+
+    return(s);
+}
+
+void
+ur_write_long(FILE *savef, long c)
+{
+    ur_write(savef,&c,sizeof(long));
+}
+
+long
+ur_read_long(FILE *savef)
+{
+    long l;
+
+    ur_read(savef, &l, sizeof(long));
+
+    return(l);
+}
+
+void
+ur_write_ulong(FILE *savef, unsigned long c)
+{
+    ur_write(savef,&c,sizeof(unsigned long));
+}
+
+unsigned long
+ur_read_ulong(FILE *savef)
+{
+    long l;
+
+    ur_read(savef, &l, sizeof(unsigned long));
+
+    return(l);
+}
+
+void
+ur_unread_long(FILE *savef)
+{
+    fseek(savef, -(long)sizeof(long), SEEK_CUR);
+}
+
+void
+ur_write_char(FILE *savef, char c)
+{
+    ur_write(savef,&c,sizeof(char));
+}
+
+char
+ur_read_char(FILE *savef)
+{
+    char c;
+
+    ur_read(savef, &c, sizeof(char));
+
+    return(c);
+}
+
+void
+ur_write_string(FILE *savef, char *s)
+{
+    size_t len;
+
+    len = (s == NULL) ? 0L : strlen(s) + 1 ;
+
+    ur_write_long(savef, (long) len);
+    ur_write(savef,s,len);
+}
+
+
+char *
+ur_read_string(FILE *savef)
+{
+    size_t  len;
+    char   *buf;
+
+    len = ur_read_long(savef);
+
+    if (len == 0)
+        return(NULL);
+
+    buf = ur_alloc(len);
+
+    if (buf == NULL)     /* Should flag a global error condition... */
+        return(NULL);
+
+    ur_read(savef,buf,len);
+
+    return(buf);
+}
+
+void
+ur_write_coord(FILE *savef, coord c)
+{
+    ur_write_int(savef, c.x);
+    ur_write_int(savef, c.y);
+}
+
+coord
+ur_read_coord(FILE *savef)
+{
+    coord c;
+
+    c.x = ur_read_int(savef);
+    c.y = ur_read_int(savef);
+
+    return(c);
+}
+
+void
+ur_write_room(FILE *savef, struct room *r)
+{
+    int i;
+
+    ur_write_coord(savef, r->r_pos);
+    ur_write_coord(savef, r->r_max);
+
+    for(i=0; i<MAXDOORS; i++)
+        ur_write_coord(savef, r->r_exit[i]);
+
+    ur_write_int(savef, r->r_flags);
+    ur_write_int(savef, r->r_nexits);
+    ur_write_int(savef, r->r_flags);
+}
+
+struct room *
+ur_read_room(FILE *savef)
+{
+    struct room *r;
+    int i;
+
+    r = ur_alloc( sizeof(struct room) );
+
+    r->r_pos = ur_read_coord(savef);
+    r->r_max = ur_read_coord(savef);
+
+    for(i=0; i<MAXDOORS; i++)
+        r->r_exit[i] = ur_read_coord(savef);
+
+    r->r_flags = ur_read_int(savef);
+    r->r_nexits = ur_read_int(savef);
+    r->r_flags = ur_read_short(savef);
+
+    return(r);
+}
+
+void
+ur_write_object(FILE *savef, struct object *o)
+{
+    int other;
+
+    ur_write_long(savef,      URS_OBJECT);
+    ur_write_coord(savef,     o->o_pos);
+    ur_write_string(savef,    o->o_text);
+    ur_write_string(savef,    o->o_damage);
+    ur_write_string(savef,    o->o_hurldmg);
+    ur_write_long(savef,      o->o_flags);
+    ur_write_long(savef,      o->ar_flags);
+    ur_write_char(savef,       o->o_type);
+    ur_write_int(savef,       o->o_ident);
+    ur_write_int(savef,       o->o_count);
+    ur_write_int(savef,       o->o_which);
+    ur_write_int(savef,       o->o_hplus);
+    ur_write_int(savef,       o->o_dplus);
+    ur_write_int(savef,       o->o_ac);
+    ur_write_int(savef,       o->o_group);
+    ur_write_int(savef,       o->o_weight);
+    ur_write_char(savef,      o->o_launch);
+    ur_write(savef,          &o->o_mark[0], MARKLEN);
+    ur_write_long(savef,      o->o_worth);
+
+    other = 0;
+
+    if (o->o_bag)
+        other = 1;
+    else if (o->next_obj)
+        other |= 2;
+
+    ur_write_int(savef,other);
+
+    if (o->o_bag)
+        ur_write_bag(savef,o->o_bag);
+    if (o->next_obj && (o->next_obj->l_prev == NULL) )
+        ur_write_object_stack(savef, o->next_obj);
+}
+
+struct object *
+ur_read_object(FILE *savef)
+{
+    struct object *o;
+    long id;
+    int other;
+
+    o = ur_alloc(sizeof(struct object));
+
+    if (o == NULL)
+        return(NULL);
+
+    memset(o,0,sizeof(struct object));
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_OBJECT);
+
+    o->o_pos  = ur_read_coord(savef);
+    o->o_text = ur_read_string(savef);
+    o->o_damage = ur_read_string(savef);
+    o->o_hurldmg = ur_read_string(savef);
+    o->o_flags = ur_read_long(savef);
+    o->ar_flags = ur_read_long(savef);
+    o->o_type = ur_read_char(savef);
+    o->o_ident = ur_read_int(savef);
+    o->o_count = ur_read_int(savef);
+    o->o_which = ur_read_int(savef);
+    o->o_hplus = ur_read_int(savef);
+    o->o_dplus = ur_read_int(savef);
+    o->o_ac = ur_read_int(savef);
+    o->o_group = ur_read_int(savef);
+    o->o_weight = ur_read_int(savef);
+    o->o_launch = ur_read_char(savef);
+    ur_read(savef, &o->o_mark[0], MARKLEN);
+    o->o_worth = ur_read_long(savef);
+
+    other = ur_read_int(savef);
+
+    if (other & 1)
+        o->o_bag = ur_read_bag(savef);
+    if (other & 2)
+        o->next_obj = ur_read_object_stack(savef);
+
+    return(o);
+}
+
+int
+list_size(struct linked_list *l)
+{
+    int cnt=0;
+
+    if (l == NULL)
+        return(0);
+
+    while(l != NULL)
+    {
+        cnt++;
+        l = l->l_next;
+    }
+
+    return(cnt);
+}
+
+int
+find_thing_index(struct linked_list *l, struct thing *item)
+{
+    int cnt=0;
+
+    if (l == NULL)
+        return(-1);
+
+    while(l != NULL)
+    {
+        if (item == l->data.th)
+            return(cnt+1);
+
+        cnt++;
+        l = l->l_next;
+    }
+
+    return(0);
+}
+
+
+int
+find_list_index(struct linked_list *l, struct object *item)
+{
+    int cnt=0;
+
+    if (l == NULL)
+        return(-1);
+
+    while(l != NULL)
+    {
+        if (item == l->data.obj)
+            return(cnt+1);
+
+        cnt++;
+        l = l->l_next;
+    }
+
+    return(0);
+}
+
+struct object *
+find_object(struct linked_list *list, int num)
+{
+    int cnt = 0;
+    struct linked_list *l = list;
+	
+    if ( (num < 1) || (list == NULL) )
+        return(NULL);
+    
+	num--;
+
+    for(cnt = 0; cnt < num; cnt++)
+    {
+        if ( l == NULL )
+            return(NULL);
+
+        l = l->l_next;
+    }
+
+    return(l->data.obj);
+}
+
+struct thing *
+find_thing(struct linked_list *list, int num)
+{
+    int cnt = 0;
+    struct linked_list *l = list;
+
+    if ( (num < 1) || (list == NULL) )
+        return(NULL);
+    num--;
+
+    for(cnt = 0; cnt < num; cnt++)
+    {
+        if (l == NULL)
+            return(NULL);
+
+        l = l->l_next;
+    }
+
+    return(l->data.th);
+}
+
+
+void
+ur_write_object_stack(FILE *savef, struct linked_list *l)
+{
+    int cnt;
+
+    ur_write_long(savef, URS_STACKOBJECT);
+
+    ur_write_int(savef, cnt = list_size(l) );
+
+    if (cnt == 0)
+        return;
+
+    while(l != NULL)
+    {
+        ur_write_object(savef, l->data.obj);
+        l = l->l_next;
+    }
+}
+
+void
+ur_write_bag(FILE *savef, struct linked_list *l)
+{
+    int cnt;
+
+    ur_write_long(savef, URS_BAGOBJECT);
+
+    ur_write_int(savef, cnt = list_size(l) );
+
+    if (cnt == 0)
+        return;
+
+    while(l != NULL)
+    {
+        ur_write_object(savef, l->data.obj);
+        l = l->l_next;
+    }
+}
+
+struct linked_list *
+ur_read_object_stack(FILE *savef)
+{
+    long id;
+    int i,cnt;
+    struct linked_list *l = NULL, *previous = NULL, *head = NULL;
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_STACKOBJECT);
+
+    cnt = ur_read_int(savef);
+
+    for(i = 0; i < cnt; i++)
+    {
+        l         = new_list();
+        l->l_prev = previous;
+
+        if (previous != NULL)
+            previous->l_next = l;
+
+        l->data.obj = ur_read_object(savef);
+
+        if (previous == NULL)
+            head = l;
+
+        previous = l;
+    }
+
+    if (l != NULL)
+        l->l_next = NULL;
+
+    return(head);
+}
+
+
+struct linked_list *
+ur_read_bag(FILE *savef)
+{
+    long id;
+    int i,cnt;
+    struct linked_list *l = NULL, *previous = NULL, *head = NULL;
+
+    id = ur_read_long(savef);
+
+    assert( id == URS_BAGOBJECT );
+
+    cnt = ur_read_int(savef);
+
+    for(i = 0; i < cnt; i++)
+    {
+        l         = new_list();
+        l->l_prev = previous;
+
+        if (previous != NULL)
+            previous->l_next = l;
+
+        l->data.obj =  ur_read_object(savef);
+
+        if (previous == NULL)
+            head = l;
+
+        previous = l;
+    }
+
+    if (l != NULL)
+        l->l_next = NULL;
+
+    return(head);
+}
+
+void
+ur_fixup_monsters(struct linked_list *l)
+{
+    while(l != NULL)
+    {
+        if (l->data.th->t_chasee == (void *) -1L)
+            l->data.th->t_chasee = &player;
+        else
+            l->data.th->t_chasee = find_thing(mlist, l->data.th->chasee_index);
+
+        l->data.th->t_horde = find_object(lvl_obj, l->data.th->horde_index);
+
+        l = l->l_next;
+    }
+}
+
+void
+ur_write_monsters(FILE *savef, struct linked_list *l)
+{
+    int cnt;
+
+    ur_write_long(savef, URS_MONSTERLIST);
+
+    cnt = list_size(l);
+
+    ur_write_int(savef, cnt);
+
+    if (cnt < 1)
+        return;
+
+    while(l != NULL)
+    {
+        ur_write_thing(savef, l->data.th);
+        l = l->l_next;
+    }
+}
+
+struct linked_list *
+ur_read_monsters(FILE *savef)
+{
+    long id;
+    int i,cnt;
+    struct linked_list *l=NULL, *previous = NULL, *head = NULL;
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_MONSTERLIST);
+
+    cnt = ur_read_int(savef);
+
+    if (cnt == 0)
+        return(NULL);
+
+    for(i = 0; i < cnt; i++)
+    {
+        l = new_list();
+
+        l->l_prev = previous;
+
+        if (previous != NULL)
+            previous->l_next = l;
+
+        l->data.th = ur_read_thing(savef);
+
+        if (previous == NULL)
+            head = l;
+
+        previous = l;
+    }
+
+    if (l != NULL)
+        l->l_next = NULL;
+
+    return(head);
+}
+
+void
+ur_write_monster_stats(FILE *savef, struct mstats *m)
+{
+    ur_write_long(savef, URS_MONSTERSTATS);
+    ur_write_short(savef, m->s_str);
+    ur_write_long(savef, m->s_exp);
+    ur_write_int(savef, m->s_lvl);
+    ur_write_int(savef, m->s_arm);
+    ur_write_string(savef, m->s_hpt);
+    ur_write_string(savef, m->s_dmg);
+}
+
+struct mstats *
+ur_read_monster_stats(FILE *savef)
+{
+    long id;
+    struct mstats *m;
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_MONSTERSTATS);
+
+    m = ur_alloc( sizeof(struct mstats) );
+
+    m->s_str = ur_read_short(savef);
+    m->s_exp = ur_read_long(savef);
+    m->s_lvl = ur_read_int(savef);
+    m->s_arm = ur_read_int(savef);
+    m->s_hpt = ur_read_string(savef);
+    m->s_dmg = ur_read_string(savef);
+
+    return(m);
+}
+
+void
+ur_write_monster(FILE *savef, struct monster *m)
+{
+    int i;
+
+    ur_write_long(savef, URS_MONSTER);
+    ur_write_string(savef, m->m_name);
+    ur_write_short(savef, m->m_carry);
+    ur_write_int(savef, m->m_normal);
+    ur_write_int(savef, m->m_wander);
+    ur_write_char(savef, m->m_appear);
+    ur_write_string(savef, m->m_intel);
+
+    for(i = 0; i < 10; i++)
+        ur_write_long(savef, m->m_flags[i]);
+
+    ur_write_string(savef, m->m_typesum);
+    ur_write_short(savef, m->m_numsum);
+    ur_write_short(savef, m->m_add_exp);
+    ur_write_monster_stats(savef, &m->m_stats);
+}
+
+struct monster *
+ur_read_monster(FILE *savef)
+{
+    struct monster *m;
+    struct mstats *mstats;
+
+    m = ur_alloc( sizeof(struct monster) );
+
+    m->m_name = ur_read_string(savef);
+    m->m_carry = ur_read_short(savef);
+    m->m_normal = ur_read_int(savef);
+    m->m_wander = ur_read_int(savef);
+    m->m_appear = ur_read_char(savef);
+    m->m_intel = ur_read_string(savef);
+    ur_read(savef, &m->m_flags[0], 10*sizeof(long));
+    m->m_typesum = ur_read_string(savef);
+    m->m_numsum = ur_read_short(savef);
+    m->m_add_exp = ur_read_short(savef);
+
+    mstats = ur_read_monster_stats(savef);
+
+    m->m_stats = *mstats;
+    ur_free(mstats);
+
+    return(m);
+}
+
+void
+ur_write_trap(FILE *savef, struct trap *t)
+{
+    ur_write_long(savef, URS_TRAP);
+    ur_write_coord(savef, t->tr_pos);
+    ur_write_long(savef, t->tr_flags);
+    ur_write_char(savef, t->tr_type);
+    ur_write_char(savef, t->tr_show);
+}
+
+struct trap *
+ur_read_trap(FILE *savef)
+{
+    struct trap *t;
+    long id;
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_TRAP);
+
+    t = ur_alloc( sizeof(struct trap));
+
+    t->tr_pos = ur_read_coord(savef);
+    t->tr_flags = ur_read_long(savef);
+    t->tr_type = ur_read_char(savef);
+    t->tr_show = ur_read_char(savef);
+
+    return(t);
+}
+
+void
+ur_write_stats(FILE *savef, struct stats *s)
+{
+    ur_write_long(savef, URS_STATS);
+    ur_write_string(savef, s->s_dmg);
+    ur_write_long(savef, s->s_exp);
+    ur_write_int(savef, s->s_hpt);
+    ur_write_int(savef, s->s_pack);
+    ur_write_int(savef, s->s_carry);
+    ur_write_int(savef, s->s_lvl);
+    ur_write_int(savef, s->s_arm);
+    ur_write_int(savef, s->s_acmod);
+    ur_write_int(savef, s->s_power);
+    ur_write_int(savef, s->s_str);
+    ur_write_int(savef, s->s_intel);
+    ur_write_int(savef, s->s_wisdom);
+    ur_write_int(savef, s->s_dext);
+    ur_write_int(savef, s->s_const);
+    ur_write_int(savef, s->s_charisma);
+}
+
+struct stats *
+ur_read_stats(FILE *savef)
+{
+    struct stats *s;
+    long id;
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_STATS);
+
+    s = ur_alloc(sizeof(struct stats));
+
+    s->s_dmg = ur_read_string(savef);
+    s->s_exp = ur_read_long(savef);
+    s->s_hpt = ur_read_int(savef);
+    s->s_pack = ur_read_int(savef);
+    s->s_carry = ur_read_int(savef);
+    s->s_lvl = ur_read_int(savef);
+    s->s_arm = ur_read_int(savef);
+    s->s_acmod = ur_read_int(savef);
+    s->s_power = ur_read_int(savef);
+    s->s_str = ur_read_int(savef);
+    s->s_intel = ur_read_int(savef);
+    s->s_wisdom = ur_read_int(savef);
+    s->s_dext = ur_read_int(savef);
+    s->s_const = ur_read_int(savef);
+    s->s_charisma = ur_read_int(savef);
+
+    return(s);
+}
+
+void
+ur_write_thing(FILE *savef, struct thing *t)
+{
+    int i;
+
+    ur_write_long(savef, URS_THING);
+    ur_write_bag(savef, t->t_pack);
+    ur_write_stats(savef, &t->t_stats);
+    ur_write_stats(savef, &t->maxstats);
+    ur_write_int(savef, t->t_ischasing);
+
+    if (t->t_chasee == &player)
+        ur_write_long(savef, -1L);
+    else if (t->t_chasee == NULL)
+         ur_write_long(savef, 0L);
+    else
+    {
+        long m;
+		
+        m = find_thing_index(mlist, t->t_chasee);
+		
+        ur_write_long(savef,m);
+    }
+
+    ur_write_long(savef, find_list_index(lvl_obj, t->t_horde));
+    ur_write_coord(savef, t->t_pos);
+    ur_write_coord(savef, t->t_oldpos);
+    ur_write_coord(savef, t->t_nxtpos);
+
+    for(i = 0; i < 16; i++)
+        ur_write_long(savef, t->t_flags[i]);
+
+    ur_write_int(savef, t->t_praycnt);
+    ur_write_int(savef, t->t_trans);
+    ur_write_int(savef, t->t_turn);
+    ur_write_int(savef, t->t_wasshot);
+    ur_write_int(savef, t->t_ctype);
+    ur_write_int(savef, t->t_index);
+    ur_write_int(savef, t->t_no_move);
+    ur_write_int(savef, t->t_rest_hpt);
+    ur_write_int(savef, t->t_rest_pow);
+    ur_write_int(savef, t->t_doorgoal);
+    ur_write_char(savef, t->t_type);
+    ur_write_char(savef, t->t_disguise);
+    ur_write_char(savef, t->t_oldch);
+}
+
+struct thing *
+ur_read_thing(FILE *savef)
+{
+    long id;
+    int i;
+    struct thing *t;
+    struct stats *s;
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_THING);
+
+    t = ur_alloc( sizeof(struct thing) );
+
+    t->t_pack = ur_read_bag(savef);
+
+    s = ur_read_stats(savef);
+    t->t_stats = *s;
+    ur_free(s);
+
+    s = ur_read_stats(savef);
+    t->maxstats = *s;
+    ur_free(s);
+
+    t->t_ischasing = ur_read_int(savef);
+    t->chasee_index = ur_read_long(savef);
+    t->horde_index = ur_read_long(savef);
+    t->t_pos = ur_read_coord(savef);
+    t->t_oldpos = ur_read_coord(savef);
+    t->t_nxtpos = ur_read_coord(savef);
+
+    for(i = 0; i < 16; i++)
+        t->t_flags[i] = ur_read_long(savef);
+
+    t->t_praycnt = ur_read_int(savef);
+    t->t_trans = ur_read_int(savef);
+    t->t_turn = ur_read_int(savef);
+    t->t_wasshot = ur_read_int(savef);
+    t->t_ctype = ur_read_int(savef);
+    t->t_index = ur_read_int(savef);
+    t->t_no_move = ur_read_int(savef);
+    t->t_rest_hpt = ur_read_int(savef);
+    t->t_rest_pow = ur_read_int(savef);
+    t->t_doorgoal = ur_read_int(savef);
+    t->t_type = ur_read_char(savef);
+    t->t_disguise = ur_read_char(savef);
+    t->t_oldch = ur_read_char(savef);
+
+    return(t);
+}
+
+void
+ur_write_window(FILE *savef, WINDOW *win)
+{
+    int i,j;
+
+    ur_write_long(savef, URS_WINDOW);
+
+    ur_write_int(savef, win->_maxy);
+    ur_write_int(savef, win->_maxx);
+
+    for(i=0; i < win->_maxy; i++)
+        for(j = 0; j < win->_maxx; j++)
+            ur_write_ulong(savef, mvwinch(win,i,j));
+}
+
+void
+ur_read_window(FILE *savef, WINDOW *win)
+{
+    int i,j;
+    int maxy, maxx;
+    long id;
+
+    id = ur_read_long(savef);
+
+    assert(id == URS_WINDOW);
+
+    maxy = ur_read_int(savef);
+    maxx = ur_read_int(savef);
+
+    for(i=0; i < maxy; i++)
+        for(j = 0; j < maxx; j++)
+            mvwaddch(win,i,j,ur_read_long(savef));
+}
+
+void
+ur_write_daemons(FILE *savef)
+{
+    int i;
+    int id=0;
+
+    ur_write_long(savef, URS_DAEMONS);
+
+    for(i = 0; i < MAXDAEMONS; i++)
+    {
+        ur_write_int(savef, d_list[i].d_type );
+        ur_write_int(savef, d_list[i].d_when );
+        ur_write_int(savef, d_list[i].d_id);
+
+        if (d_list[i].d_id == FUSE_UNSUMMON)
+            id = find_thing_index(mlist, d_list[i].d_arg);
+
+        if (d_list[i].d_id == DAEMON_DOCTOR)
+            id = find_thing_index(mlist, d_list[i].d_arg);
+
+        ur_write_int(savef, id);
+        ur_write_int(savef, d_list[i].d_time );
+    }
+}
+
+void
+ur_read_daemons(FILE *savef)
+{
+    long id;
+    int i;
+    demoncnt = 0;
+	
+    id = ur_read_long(savef);
+
+    assert(id == URS_DAEMONS);
+
+    for(i = 0; i < MAXDAEMONS; i++)
+    {
+        d_list[i].d_type = ur_read_int(savef);
+        d_list[i].d_when = ur_read_int(savef);
+        d_list[i].d_id = ur_read_int(savef);
+        id = ur_read_int(savef);
+        d_list[i].d_time = ur_read_int(savef);
+
+        if ((d_list[i].d_type != EMPTY) && (d_list[i].d_id == FUSE_UNSUMMON))
+        {
+            d_list[i].d_arg = find_thing(mlist,id);
+
+            if (d_list[i].d_arg == NULL)
+                d_list[i].d_type = EMPTY;
+        }
+
+        if ((d_list[i].d_type != EMPTY) &&  (d_list[i].d_id == DAEMON_DOCTOR) )
+        {
+            if (id == 0)
+                d_list[i].d_arg = &player;
+            else
+                d_list[i].d_arg = find_thing(mlist, id);
+
+            if (d_list[i].d_arg == NULL)
+                d_list[i].d_type = EMPTY;
+        }
+
+        if (d_list[i].d_type != EMPTY)
+            demoncnt++;
+    }
+}
+
+void
+save_file(FILE *savef)
+{
+    int i,weapon,armor,ring=0,room= -1,monster;
+
+    ur_write_string(savef, save_format);
+
+    ur_write_string(savef,"\nScroll Names\n");
+    for(i = 0; i < MAXSCROLLS; i++)
+        ur_write_string(savef,s_names[i]);
+
+    ur_write_string(savef,"\nPotion Colors\n");
+    for(i = 0; i < MAXPOTIONS; i++)
+        ur_write_string(savef,p_colors[i]);
+
+    ur_write_string(savef,"\nRing Stones\n");
+    for(i = 0; i < MAXRINGS; i++)
+        ur_write_string(savef,r_stones[i]);
+
+    ur_write_string(savef,"\nStick types\n");
+    for(i = 0; i < MAXSTICKS; i++)
+        ur_write_string(savef,ws_made[i]);
+
+    ur_write_string(savef,"\nStick types\n");
+    for(i = 0; i < MAXSTICKS; i++)
+        ur_write_string(savef,ws_type[i]);
+
+    ur_write_string(savef, "\nTraps on this level\n");
+    ur_write_int(savef, MAXTRAPS);
+    for(i = 0; i < MAXTRAPS; i++)
+        ur_write_trap(savef, &traps[i]);
+
+    ur_write_string(savef,"\nRooms on this level\n");
+    ur_write_int(savef, MAXROOMS);
+    for(i = 0; i < MAXROOMS; i++)
+    {
+        ur_write_room(savef, &rooms[i]);
+
+        if (&rooms[i] == oldrp)
+            room = i;
+    }
+    ur_write_int(savef,room); /* save for recovery of oldrp */
+
+    ur_write_string(savef,"\nThe Rogue\n");
+    ur_write_thing(savef, &player);
+
+    ur_write_string(savef,"\nObjects on this level\n");
+    ur_write_bag(savef, lvl_obj);
+
+    ur_write_string(savef,"\nRogue's Familiar, if any \n");
+    ur_write_monsters(savef, fam_ptr);
+
+    ur_write_string(savef,"\nMonsters on this level\n");
+    ur_write_monsters(savef, mlist);
+
+    monster = find_thing_index(mlist, beast);
+    ur_write_int(savef, monster);
+
+    ur_write_string(savef,"\nItems in use by rogue\n");
+    weapon = find_list_index(player.t_pack, cur_weapon);
+    armor  = find_list_index(player.t_pack, cur_armor);
+    ur_write_int(savef, weapon);
+    ur_write_int(savef, armor);
+
+    for(i=0; i < 10; i++)
+    {
+        if (cur_ring[i] == NULL)
+            ring = find_list_index(player.t_pack, cur_ring[i]);
+
+        ur_write_int(savef, ring);
+    }
+
+    ur_write_string(savef,"\nActive Daemons and Fuses\n");
+    ur_write_daemons(savef);
+
+    ur_write_string(savef, "\nMisc\n");
+
+    for(i = 0; i < 10; i++)
+        ur_write_string(savef, msgbuf[i]);
+
+    ur_write_int(savef, msg_index);
+    ur_write_int(savef, foodlev);
+    ur_write_int(savef, ntraps);
+    ur_write_int(savef, dnum);
+    ur_write_int(savef, max_level);
+    ur_write_int(savef, lost_dext);
+    ur_write_int(savef, no_command);
+    ur_write_int(savef, level);
+    ur_write_int(savef, see_dist);
+    ur_write_int(savef, no_food);
+    ur_write_int(savef, count);
+    ur_write_int(savef, food_left);
+    ur_write_int(savef, group);
+    ur_write_int(savef, hungry_state);
+    ur_write_int(savef, infest_dam);
+    ur_write_int(savef, lost_str);
+    ur_write_int(savef, hold_count);
+    ur_write_int(savef, trap_tries);
+    ur_write_int(savef, has_artifact);
+    ur_write_int(savef, picked_artifact);
+    ur_write_int(savef, luck);
+    ur_write_int(savef, resurrect);
+    ur_write_int(savef, fam_type);
+    ur_write_int(savef, mons_summoned);
+    ur_write_char(savef, PLAYER);
+    ur_write_char(savef, take);
+    ur_write_char(savef, runch);
+    ur_write_int(savef, char_type);
+    ur_write_int(savef, inv_type);
+    ur_write_int(savef,  pool_teleport);
+    ur_write_int(savef, inwhgt);
+    ur_write_int(savef, after);
+    ur_write_int(savef, waswizard);
+    ur_write_int(savef, canwizard);
+    ur_write_int(savef, playing);
+    ur_write_int(savef, running);
+    ur_write_int(savef, fighting);
+    ur_write_int(savef, wizard);
+    ur_write_int(savef, wiz_verbose);
+    ur_write_int(savef, moving);
+    ur_write_coord(savef, delta);
+    ur_write_int(savef, levtype);
+    ur_write_int(savef, purse);
+    ur_write_int(savef, total);
+    ur_write_window(savef, cw);
+    ur_write_window(savef, hw);
+    ur_write_window(savef, mw);
+    ur_write_window(savef, stdscr);
+
+    ur_write_string(savef,"\nGame Options\n");
+    ur_write_int(savef, terse);
+    ur_write_int(savef, door_stop);
+    ur_write_int(savef, doorstop);
+    ur_write_int(savef, jump);
+    ur_write_int(savef, firstmove);
+    ur_write_int(savef, askme);
+    ur_write_string(savef,whoami);
+    ur_write_string(savef,fruit);
+    ur_write_string(savef,file_name);
+    ur_write_string(savef,score_file);
+
+    ur_write_string(savef,"\nEnd of UltraRogue Game State\n");
+}
+
+#define DUMPSTRING { str = ur_read_string(savef); /*printf("%s",str);*/ ur_free(str); }
+
+int
+restore_file(FILE *savef)
+{
+    int i,j;
+    char *str;
+    struct trap *t;
+    struct room *r;
+    struct thing *p;
+
+    str = ur_read_string(savef);
+
+    if (strcmp(str, save_format) != 0)
+    {
+        printf("Save Game Version: %s\n", str);
+        printf("Real Game Version: %s\n", save_format);
+        printf("Sorry, versions don't match.\n");
+        return(FALSE);
+    }
+
+    DUMPSTRING
+    for(i=0; i < MAXSCROLLS; i++)
+        s_names[i] = ur_read_string(savef);
+
+    DUMPSTRING
+    for(i=0; i < MAXPOTIONS; i++)
+        p_colors[i] = ur_read_string(savef);
+
+    DUMPSTRING
+    for(i=0; i < MAXRINGS; i++)
+        r_stones[i] = ur_read_string(savef);
+
+    DUMPSTRING
+    for(i=0; i < MAXSTICKS; i++)
+        ws_made[i] = ur_read_string(savef);
+
+    DUMPSTRING
+    for(i=0; i < MAXSTICKS; i++)
+        ws_type[i] = ur_read_string(savef);
+
+    DUMPSTRING
+    i = ur_read_int(savef);
+    assert(i == MAXTRAPS);
+
+    for(i=0;i<MAXTRAPS;i++)
+    {
+        t = ur_read_trap(savef);
+        traps[i] = *t;
+        ur_free(t);
+    }
+
+    DUMPSTRING
+    i = ur_read_int(savef);
+    assert(i == MAXROOMS);
+
+    for(i=0;i<MAXROOMS;i++)
+    {
+        r = ur_read_room(savef);
+        rooms[i] = *r;
+        ur_free(r);
+    }
+    i = ur_read_int(savef);
+    oldrp = &rooms[i];
+
+    DUMPSTRING
+    p = ur_read_thing(savef);
+    player = *p;
+    ur_free(p);
+
+    DUMPSTRING
+    lvl_obj = ur_read_bag(savef);
+
+    DUMPSTRING
+    fam_ptr = ur_read_monsters(savef);
+
+    DUMPSTRING
+    mlist = ur_read_monsters(savef);
+    i = ur_read_int(savef);
+    beast = find_thing(mlist, i);
+
+    ur_fixup_monsters(fam_ptr);
+    ur_fixup_monsters(fam_ptr);
+
+    DUMPSTRING
+    i = ur_read_int(savef);
+    cur_weapon = find_object(player.t_pack, i);
+
+    i = ur_read_int(savef);
+    cur_armor = find_object(player.t_pack, i);
+
+    for(j=0; j < 10; j++)
+    {
+        i = ur_read_int(savef);
+        if (i == -1)
+            cur_ring[j] = NULL;
+        else
+            cur_ring[j] = find_object(player.t_pack, i);
+    }
+
+    DUMPSTRING
+    ur_read_daemons(savef);
+
+    DUMPSTRING
+    for(i = 0; i < 10; i++)
+    {
+        str = ur_read_string(savef);
+        strcpy(&msgbuf[i][0],str);
+        ur_free(str);
+    }
+
+    msg_index = ur_read_int(savef);
+
+    foodlev  = ur_read_int(savef);
+    ntraps = ur_read_int(savef);
+    dnum = ur_read_int(savef);
+    max_level = ur_read_int(savef);
+    lost_dext = ur_read_int(savef);
+    no_command = ur_read_int(savef);
+    level = ur_read_int(savef);
+    see_dist  = ur_read_int(savef);
+    no_food = ur_read_int(savef);
+    count = ur_read_int(savef);
+    food_left = ur_read_int(savef);
+    group = ur_read_int(savef);
+    hungry_state = ur_read_int(savef);
+    infest_dam = ur_read_int(savef);
+    lost_str = ur_read_int(savef);
+    hold_count = ur_read_int(savef);
+    trap_tries = ur_read_int(savef);
+    has_artifact  = ur_read_int(savef);
+    picked_artifact  = ur_read_int(savef);
+    luck = ur_read_int(savef);
+    resurrect = ur_read_int(savef);
+    fam_type = ur_read_int(savef);
+    mons_summoned = ur_read_int(savef);
+    PLAYER = ur_read_char(savef);
+    take = ur_read_char(savef);
+    runch = ur_read_char(savef);
+    char_type = ur_read_int(savef);
+    inv_type = ur_read_int(savef);
+    pool_teleport = ur_read_int(savef);
+    inwhgt = ur_read_int(savef);
+    after = ur_read_int(savef);
+    waswizard = ur_read_int(savef);
+    canwizard = ur_read_int(savef);
+    playing = ur_read_int(savef);
+    running = ur_read_int(savef);
+    fighting = ur_read_int(savef);
+    wizard = ur_read_int(savef);
+    wiz_verbose = ur_read_int(savef);
+    moving = ur_read_int(savef);
+    delta = ur_read_coord(savef);
+    levtype = ur_read_int(savef);
+    purse = ur_read_int(savef);
+    total = ur_read_int(savef);
+    ur_read_window(savef, cw);
+    ur_read_window(savef, hw);
+    ur_read_window(savef, mw);
+    ur_read_window(savef, stdscr);
+
+    DUMPSTRING
+    terse = ur_read_int(savef);
+    door_stop = ur_read_int(savef);
+    doorstop = ur_read_int(savef);
+    jump = ur_read_int(savef);
+    firstmove = ur_read_int(savef);
+    askme = ur_read_int(savef);
+    str = ur_read_string(savef);
+    strcpy(whoami,str);
+    ur_free(str);
+    str = ur_read_string(savef);
+    strcpy(fruit,str);
+    ur_free(str);
+    str = ur_read_string(savef);
+    strcpy(file_name,str);
+    ur_free(str);
+    str = ur_read_string(savef);
+    strcpy(score_file,str);
+    ur_free(str);
+
+    DUMPSTRING
+    return(TRUE);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/status.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,52 @@
+/*
+    status.c - functions for complex status determination of monsters/objects
+         
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include "rogue.h"
+
+/*
+    has_defensive_spell()
+        has monster cast a defensive spell.
+        Any flags added here must also be in player_powers[].
+*/
+
+int
+has_defensive_spell(struct thing th)
+{
+    if (on(th, HASOXYGEN))
+        return(TRUE);
+    if (on(th, CANFLY))
+        return(TRUE);
+    if (on(th, CANINWALL))
+        return(TRUE);
+    if (on(th, CANREFLECT))
+        return(TRUE);
+    if (on(th, CANSEE))
+        return(TRUE);
+    if (on(th, HASMSHIELD))
+        return(TRUE);
+    if (on(th, HASSHIELD))
+        return(TRUE);
+    if (on(th, ISHASTE))
+        return(TRUE);
+    if (on(th, ISREGEN))
+        return(TRUE);
+    if (on(th, ISDISGUISE))
+        return(TRUE);
+    if (on(th, ISINVIS))
+        return(TRUE);
+    if (on(th, NOCOLD))
+        return(TRUE);
+    if (on(th, NOFIRE))
+        return(TRUE);
+    if (on(th, ISELECTRIC))
+        return(TRUE);
+
+    return(FALSE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/sticks.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,1796 @@
+/*
+    sticks.c - Functions to implement the various sticks one might find
+            
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/* for WS_HIT, WS_WEB, etc */
+
+static struct object null_stick =
+{
+    {0,0},NULL,NULL,"",0,"0d0",0,0,'X',0,0,0,0,0,0,0,0,0,{0}
+};
+
+/*
+ * Mask for cancelling special abilities The flags listed here will be the
+ * ones left on after the cancellation takes place
+ */
+
+#define CANC0MASK ( ISBLIND     | ISINWALL  | ISRUN     | \
+            ISFLEE      | ISMEAN    | ISGREED   | \
+            CANSHOOT    | ISHELD    | ISHUH     | \
+            ISSLOW      | ISHASTE   | ISCLEAR   | \
+            ISUNIQUE)
+
+#define CANC1MASK ( HASDISEASE  | DIDSUFFOCATE  | CARRYGOLD     | \
+            HASITCH     | CANSELL   | CANBBURN  | \
+            CANSPEAK    | CANFLY    | ISFRIENDLY)
+
+#define CANC2MASK ( HASINFEST   | NOMOVE    | ISSCAVENGE    | \
+            DOROT       | HASSTINK  | DIDHOLD)
+
+#define CANC3MASK ( ISUNDEAD    | CANBREATHE    | CANCAST   | \
+            HASOXYGEN)
+
+#define CANC4MASK ( CANTRAMPLE  | CANSWIM   | CANWIELD  | \
+            ISFAST      | CANBARGAIN    | CANSPORE  | \
+            ISLARGE     | ISSMALL   | ISFLOCK   | \
+            ISSWARM     | CANSTICK  | CANTANGLE | \
+            SHOOTNEEDLE | CANZAP    | HASARMOR  | \
+            CANTELEPORT | ISBERSERK | ISFAMILIAR    | \
+            HASFAMILIAR | SUMMONING)
+
+#define CANC5MASK ( CANREFLECT  | MAGICATTRACT  | HASSHIELD | HASMSHIELD)
+
+#define CANC6MASK ( 0 )
+#define CANC7MASK ( 0 )
+#define CANC8MASK ( 0 )
+#define CANC9MASK ( 0 )
+#define CANCAMASK ( 0 )
+#define CANCBMASK ( 0 )
+#define CANCCMASK ( 0 )
+#define CANCDMASK ( 0 )
+#define CANCEMASK ( 0 )
+#define CANCFMASK ( 0 )
+
+void
+fix_stick(struct object *cur)
+{
+    if (strcmp(ws_type[cur->o_which], "staff") == 0)
+    {
+        cur->o_weight = 100;
+        cur->o_charges = 5 + rnd(10);
+        cur->o_damage = "2d3";
+
+        switch (cur->o_which)
+        {
+            case WS_HIT:
+                cur->o_hplus = 3;
+                cur->o_dplus = 3;
+                cur->o_damage = "2d8";
+                break;
+
+            case WS_LIGHT:
+                cur->o_charges = 20 + rnd(10);
+                break;
+        }
+    }
+    else            /* A wand */
+    {
+        cur->o_damage = "1d3";
+        cur->o_weight = 60;
+        cur->o_charges = 3 + rnd(5);
+
+        switch (cur->o_which)
+        {
+            case WS_HIT:
+                cur->o_hplus = 3;
+                cur->o_dplus = 3;
+                cur->o_damage = "1d8";
+                break;
+
+            case WS_LIGHT:
+                cur->o_charges = 10 + rnd(10);
+                break;
+        }
+    }
+
+    cur->o_hurldmg = "1d1";
+}
+
+/*
+    do_zap()
+        zap a stick (or effect a stick-like spell)
+        zapper:  who does it
+        got_dir: need to ask for direction?
+        which:   which WS_STICK (-1 means ask from pack)
+        flags:   ISBLESSED, ISCURSED
+*/
+
+void
+do_zap(struct thing *zapper, int which, unsigned long flags)
+{
+    struct linked_list  *item = NULL, *nitem;
+    struct object   *obj, *nobj;
+    struct room *rp;
+    struct thing    *tp = NULL;
+    char *mname = NULL;
+    int y, x;
+    int blessed = flags & ISBLESSED;
+    int cursed = flags & ISCURSED;
+    int is_stick = (which < 0 ? TRUE : FALSE);
+    int got_one = TRUE;
+
+    if (zapper != &player)
+    {
+        monster_do_zap(zapper, which, flags);
+        return;
+    }
+
+    if (is_stick)
+    {
+        if ((obj = get_object(pack, "zap with", 0, bff_zappable)) == NULL)
+            return;
+
+        if (obj->o_type != STICK && !(obj->o_flags & ISZAPPED))
+        {
+            msg("You can't zap with that!");
+            return;
+        }
+
+        if (obj->o_type != STICK)   /* an electrified weapon */
+            which = WS_ELECT;
+        else
+            which = obj->o_which;
+
+        if (obj->o_charges < 1)
+        {
+            nothing_message(flags);
+            return;
+        }
+
+        obj->o_charges--;
+
+        if (delta.y == 0 && delta.x == 0)
+            do
+            {
+                delta.y = rnd(3) - 1;
+                delta.x = rnd(3) - 1;
+            }
+            while (delta.y == 0 && delta.x == 0);
+
+        flags = obj->o_flags;
+        cursed = obj->o_flags & ISCURSED;
+        blessed = obj->o_flags & ISBLESSED;
+    }
+    else
+        obj = &null_stick;
+
+    /* Find out who the target is */
+
+    y = hero.y;
+    x = hero.x;
+
+    while(shoot_ok(CCHAR(winat(y, x))))
+    {
+        y += delta.y;
+        x += delta.x;
+    }
+
+    if (x >= 0 && x < COLS && y >= 1 && y < LINES - 2 &&
+            isalpha(mvwinch(mw, y, x)))
+    {
+        item = find_mons(y, x);
+        tp = THINGPTR(item);
+        mname = on(player, ISBLIND) ? "monster" :
+            monsters[tp->t_index].m_name;
+
+        if (on(*tp, CANSELL))
+        {
+            luck++;
+            aggravate();
+        }
+    }
+    else
+        got_one = FALSE;
+
+    debug("Zapping with %d", which);
+
+    switch(which)
+    {
+        case WS_LIGHT:
+            /* Reddy Kilowat wand.  Light up the room */
+            if (blue_light(flags) && is_stick)
+                if (is_stick)
+                    know_items[TYP_STICK][WS_LIGHT] = TRUE;
+            break;
+
+        case WS_DRAIN:
+
+            /*
+             * Take away 1/2 of hero's hit points, then take it away
+             * evenly from the monsters in the room or next to hero if he
+             * is in a passage. Leave the monsters alone if the stick is
+             * cursed. Drain 1/3rd of hero's hit points if blessed.
+             */
+
+            if (pstats.s_hpt < 2)
+            {
+                death(D_DRAINLIFE);
+                return;
+            }
+
+            if (cursed)
+                pstats.s_hpt /= 2;
+            else if ((rp = roomin(hero)) == NULL)
+                drain(hero.y - 1, hero.y + 1, hero.x - 1, hero.x + 1);
+            else
+                drain(rp->r_pos.y, rp->r_pos.y + rp->r_max.y,
+                      rp->r_pos.x, rp->r_pos.x + rp->r_max.x);
+
+            if (blessed)
+                pstats.s_hpt = (int) (pstats.s_hpt * 2.0 / 3.0);
+
+            break;
+
+        case WS_POLYMORPH:
+        case WS_MONSTELEP:
+        case WS_CANCEL:
+        {
+            char    oldch;
+            int rm;
+            int save_adj = 0;
+
+            if (got_one)
+            {
+                /* if the monster gets the saving throw, leave the case */
+
+                if (blessed)
+                    save_adj = -5;
+
+                if (cursed)
+                    if (which == WS_POLYMORPH)
+                        save_adj = -5;  /* not save vs becoming tougher */
+                    else
+                        save_adj = 5;
+
+                if (save_throw(VS_MAGIC - save_adj, tp))
+                {
+                    nothing_message(flags);
+                    break;
+                }
+                else if (is_stick)
+                    know_items[TYP_STICK][which] = TRUE;
+
+                /* Unhold player */
+
+                if (on(*tp, DIDHOLD))
+                {
+                    turn_off(*tp, DIDHOLD);
+
+                    if (--hold_count == 0)
+                        turn_off(player, ISHELD);
+                }
+
+                /* unsuffocate player */
+
+                if (on(*tp, DIDSUFFOCATE))
+                {
+                    turn_off(*tp, DIDSUFFOCATE);
+                    extinguish_fuse(FUSE_SUFFOCATE);
+                }
+
+                if (which == WS_POLYMORPH)
+                {
+                    int which_new;
+                    int charmed;
+
+                    detach(mlist, item);
+                    charmed = on(*tp, ISCHARMED);
+                    oldch = tp->t_oldch;
+                    delta.y = y;
+                    delta.x = x;
+
+                    if (!blessed && !cursed)
+                        which_new = randmonster(WANDER, GRAB);
+                    else
+                    {
+                        /* duplicate randmonster() for now */
+                        /* Eventually fix to take level     */
+
+                        int cur_level = 0, range, i;
+
+                        if (blessed)
+                            cur_level = level / 2;
+
+                        if (cursed)
+                            cur_level = level * 2;
+
+                        range = 4 * NLEVMONS;
+                        i = 0;
+
+                        do
+                        {
+                            if (i++ > range * 10)   /* just in case all have */
+                            {                       /* been genocided */
+                                i = 0;
+
+                                if (--cur_level <= 0)
+                                    fatal("Rogue could not find a monster to make");
+                            }
+
+                            which_new = NLEVMONS * (cur_level - 1) + (rnd(range) - (range - 1 - NLEVMONS));
+
+                            if (which_new < 1)
+                                which_new = rnd(NLEVMONS) + 1;
+
+                            if (which_new > nummonst - NUMSUMMON - 1)
+                            {
+                                if (blessed)
+                                    which_new = rnd(range) + (nummonst - NUMSUMMON - 1) - (range - 1);
+                                else if (which_new > nummonst - 1)
+                                    which_new = rnd(range + NUMSUMMON) + (nummonst - 1) - (range + NUMSUMMON - 1);
+                            }
+                        }
+                        while (!monsters[which_new].m_normal);
+                    }
+
+                    new_monster(item, which_new, &delta, NOMAXSTATS);
+                    mname = on(player, ISBLIND) ? "monster" : monsters[tp->t_index].m_name;
+
+                    if (!cursed && charmed)
+                        turn_on(*tp, ISCHARMED);
+
+                    if (off(*tp, ISRUN))
+                        chase_it(&delta, &player);
+
+                    if (isalpha(mvwinch(cw, y, x)))
+                        mvwaddch(cw, y, x, tp->t_type);
+
+                    tp->t_oldch = oldch;
+                    seemsg("You have created a new %s!", mname);
+                }
+                else if (which == WS_CANCEL)
+                {
+                    tp->t_flags[0] &= CANC0MASK;
+                    tp->t_flags[1] &= CANC1MASK;
+                    tp->t_flags[2] &= CANC2MASK;
+                    tp->t_flags[3] &= CANC3MASK;
+                    tp->t_flags[4] &= CANC4MASK;
+                    tp->t_flags[5] &= CANC5MASK;
+                    tp->t_flags[6] &= CANC5MASK;
+                    tp->t_flags[7] &= CANC7MASK;
+                    tp->t_flags[8] &= CANC8MASK;
+                    tp->t_flags[9] &= CANC9MASK;
+                    tp->t_flags[10] &= CANCAMASK;
+                    tp->t_flags[11] &= CANCBMASK;
+                    tp->t_flags[12] &= CANCCMASK;
+                    tp->t_flags[13] &= CANCDMASK;
+                    tp->t_flags[14] &= CANCEMASK;
+                    tp->t_flags[15] &= CANCFMASK;
+                }
+                else    /* A teleport stick */
+                {
+                    if (cursed)     /* Teleport monster to */
+                    {               /*  player */
+                        if ((y == (hero.y + delta.y)) &&
+                          (x == (hero.x + delta.x)))
+                            nothing_message(flags);
+                        else
+                        {
+                            tp->t_pos.y = hero.y + delta.y;
+                            tp->t_pos.x = hero.x + delta.x;
+                        }
+                    }
+                    else if (blessed)   /* Get rid of monster */
+                    {
+                        killed(NULL, item, NOMESSAGE, NOPOINTS);
+                        return;
+                    }
+                    else
+                    {
+                        int i = 0;
+
+                        do      /* Move monster to */
+                        {       /* another room */
+                            rm = rnd_room();
+                            rnd_pos(&rooms[rm], &tp->t_pos);
+                        }
+                        while (winat(tp->t_pos.y, tp->t_pos.x) !=
+                             FLOOR && i++ < 500);
+                    }
+
+                    /* Now move the monster */
+
+                    if (isalpha(mvwinch(cw, y, x)))
+                        mvwaddch(cw, y, x, tp->t_oldch);
+
+                    chase_it(&tp->t_pos, &player);
+                    mvwaddch(mw, y, x, ' ');
+                    mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
+
+                    if (tp->t_pos.y != y || tp->t_pos.x != x)
+                        tp->t_oldch = CCHAR(mvwinch(cw, tp->t_pos.y, tp->t_pos.x));
+                }
+            }
+        }
+        break;
+		
+        case WS_MISSILE:
+        {
+            int damage;
+            int nsides = 4;
+            int  ch;
+            coord pos;
+
+            if (is_stick)
+                know_items[TYP_STICK][which] = TRUE;
+
+            /* Magic Missiles *always* hit, no saving throw */
+
+            pos = do_motion('*', delta.y, delta.x, &player);
+            ch  = winat(pos.y, pos.x);
+
+            if (cursed)
+                nsides /= 2;
+            else if (blessed)
+                nsides *= 2;
+
+            damage = roll(pstats.s_lvl, nsides);
+
+            if (isalpha(ch))
+            {
+                debug("Missiled %s for %d (%d)",
+                 mname, damage, tp->t_stats.s_hpt - damage);
+
+                if ((tp->t_stats.s_hpt -= damage) <= 0)
+                {
+                    seemsg("The missile kills the %s.", mname);
+                    killed(&player, item, NOMESSAGE, POINTS);
+                }
+                else
+                {
+                    seemsg("The missile hits the %s", mname);
+                    chase_it(&pos, &player);
+                    summon_help(tp, NOFORCE);
+                }
+            }
+
+            if (pos.y >= 0 && pos.x >= 0 &&
+                pos.y < LINES && pos.x < COLS)
+                mvwaddch(cw, pos.y, pos.x, show(pos.y, pos.x));
+        }
+        break;
+
+        case WS_HIT:
+        {
+            coord pos;
+            int ch;
+            struct object   strike; /* don't want to change sticks attributes */
+
+            if (is_stick)
+                know_items[TYP_STICK][which] = TRUE;
+
+            pos = do_motion('@', delta.y, delta.x, &player);
+            ch = winat(pos.y, pos.x);
+
+            if (isalpha(ch))
+            {
+                static char buf[20];
+                int nsides, ndice;
+
+                strike = *obj;
+
+                if (blessed)
+                    strike.o_hplus = 12;
+                else if (cursed)
+                    strike.o_hplus = 3;
+                else
+                    strike.o_hplus = 6;
+
+                if (!is_stick || strcmp(ws_type[which], "staff") == 0)
+                    ndice = 3;
+                else
+                    ndice = 2;
+
+                if (blessed)
+                    nsides = 16;
+                else if (cursed)
+                    nsides = 4;
+                else
+                    nsides = 8;
+
+                sprintf(buf, "%dd%d", ndice, nsides);
+
+                strike.o_damage = buf;
+                fight(&tp->t_pos, &strike, NOTHROWN);
+            }
+        }
+        break;
+
+        case  WS_SLOW_M:
+            if (got_one)
+            {
+                if (cursed)
+                {
+                    if (off(*tp, ISSLOW))
+                        turn_on(*tp, ISHASTE);
+                    else
+                        turn_off(*tp, ISSLOW);
+                }
+                else if (blessed)
+                {
+                    if (is_stick)
+                        know_items[TYP_STICK][which] = TRUE;
+
+                    turn_off(*tp, ISRUN);
+                    turn_on(*tp, ISHELD);
+                    return;
+                }
+                else
+                {
+                    if (is_stick)
+                        know_items[TYP_STICK][which] = TRUE;
+
+                    if (off(*tp, ISHASTE))
+                        turn_on(*tp, ISSLOW);
+                    else
+                        turn_off(*tp, ISHASTE);
+
+                    tp->t_turn = TRUE;
+                }
+
+                delta.y = y;
+                delta.x = x;
+                chase_it(&delta, &player);
+            }
+            break;
+
+        case WS_CHARGE:
+            if (know_items[TYP_STICK][which] != TRUE && is_stick)
+            {
+                msg("This is a wand of charging.");
+                know_items[TYP_STICK][which] = TRUE;
+            }
+
+            if ((nitem = get_item("charge", STICK)) != NULL)
+            {
+                nobj = OBJPTR(nitem);
+
+                if ((nobj->o_charges == 0) && (nobj->o_which != WS_CHARGE))
+                {
+                    fix_stick(nobj);
+
+                    if (blessed)
+                        nobj->o_charges *= 2;
+                    else if (cursed)
+                        nobj->o_charges /= 2;
+                }
+                else
+                {
+                    if (blessed)
+                        nobj->o_charges += 2;
+                    else if (cursed)
+                        nobj->o_charges -= 1;
+                    else
+                        nobj->o_charges += 1;
+                }
+            }
+            break;
+
+        case WS_ELECT:
+        case WS_FIRE:
+        case WS_COLD:
+        {
+            char    *name = NULL;
+            int damage;
+            int ndice = 3 + pstats.s_lvl;
+            int nsides;
+
+            if (is_stick)
+            {
+                know_items[TYP_STICK][which] = TRUE;
+
+                if (strcmp(ws_type[which], "staff") == 0)
+                    nsides = 8;
+                else
+                    nsides = 4;
+            }
+            else
+                nsides = 6;
+
+            if (cursed)
+                nsides /= 2;
+            else if (blessed)
+                nsides *= 2;
+
+            switch (which)
+            {
+                case WS_ELECT:
+                    name = "lightning bolt";
+
+                    if (rnd(2))
+                        ndice += rnd(obj->o_charges / 10);
+                    else
+                        nsides += rnd(obj->o_charges / 10);
+
+                    break;
+
+                case WS_FIRE:
+                    name = "flame";
+                    break;
+
+                case WS_COLD:
+                    name = "ice";
+                    break;
+            }
+
+            damage = roll(ndice, nsides);
+            shoot_bolt(&player, hero, delta, POINTS, D_BOLT, name, damage);
+        }
+        break;
+
+        case WS_ANTIMATTER:
+        {
+            int m1, m2, x1, y1;
+            char    ch;
+            struct linked_list  *ll;
+            struct thing    *lt;
+
+            if (is_stick)
+                know_items[TYP_STICK][which] = TRUE;
+
+            y1 = hero.y;
+            x1 = hero.x;
+
+            do
+            {
+                y1 += delta.y;
+                x1 += delta.x;
+                ch = winat(y1, x1);
+            }
+            while (ch == PASSAGE || ch == FLOOR);
+
+            for (m1 = x1 - 1; m1 <= x1 + 1; m1++)
+            {
+                for (m2 = y1 - 1; m2 <= y1 + 1; m2++)
+                {
+                    ch = winat(m2, m1);
+
+                    if (m1 == hero.x && m2 == hero.y)
+                        continue;
+
+                    if (ch != ' ')
+                    {
+                        ll = find_obj(m2, m1);
+
+                        while (ll != NULL)
+                        {
+                            rem_obj(ll, TRUE);
+                            ll = find_obj(m2, m1);
+                        }
+
+                        ll = find_mons(m2, m1);
+
+                        if (ll != NULL)
+                        {
+                            lt = THINGPTR(ll);
+                            if (on(*lt, CANSELL))
+                            {
+                                luck++;
+                                aggravate();
+                            }
+
+                            if (off(*lt, CANINWALL))
+                            {
+                                check_residue(lt);
+                                detach(mlist, ll);
+                                discard(ll);
+                                mvwaddch(mw, m2, m1, ' ');
+                            }
+                        }
+
+                        mvaddch(m2, m1, ' ');
+                        mvwaddch(cw, m2, m1, ' ');
+                    }
+                }
+            }
+
+            touchwin(cw);
+            touchwin(mw);
+        }
+        break;
+
+        case WS_CONFMON:
+        case WS_PARALYZE:
+            if (got_one)
+            {
+                if (save_throw(VS_MAGIC - (blessed ? 5 : (cursed ? -5 : 0)), tp))
+                    nothing_message(flags);
+                else
+                {
+                    if (is_stick)
+                        know_items[TYP_STICK][which] = TRUE;
+
+                    switch(which)
+                    {
+                        case WS_CONFMON:
+                            seemsg("The %s looks bewildered.", mname);
+                            turn_on(*tp, ISHUH);
+                            break;
+
+                        case WS_PARALYZE:
+                            seemsg("The %s looks stunned.", mname);
+                            tp->t_no_move = FREEZETIME;
+                            break;
+                    }
+                }
+
+                delta.y = y;
+                delta.x = x;
+                chase_it(&delta, &player);
+            }
+            else
+                nothing_message(flags);
+
+            break;
+
+        case WS_XENOHEALING:
+        {
+            int hpt_gain = roll(zapper->t_stats.s_lvl, (blessed ? 8 : 4));
+            int mons_hpt = tp->t_stats.s_hpt;
+
+            if (got_one)
+            {
+                if (cursed)
+                {
+                    if (!save_throw(VS_MAGIC, tp))
+                    {
+                        if ((mons_hpt -= hpt_gain) <= 0) {
+                            seemsg("The %s shrivels up and dies!", mname);
+                            killed(&player, item, NOMESSAGE, POINTS);
+                        }
+                        else
+                            seemsg("Wounds appear all over the %s.", mname);
+                    }
+                    else
+                        nothing_message(flags);
+
+                    delta.y = y;
+                    delta.x = x;
+                    chase_it(&delta, &player);
+                }
+                else
+                {
+                    if (is_stick)
+                        know_items[TYP_STICK][which] = TRUE;
+
+                    mons_hpt = min(mons_hpt + hpt_gain, tp->maxstats.s_hpt);
+                    seemsg("The %s appears less wounded!", mname);
+                }
+            }
+            else
+                nothing_message(flags);
+        }
+        break;
+
+        case WS_DISINTEGRATE:
+            if (got_one)
+            {
+                if (cursed)
+                {
+                    if (on(*tp, ISUNIQUE))
+                    {
+                        if (on(*tp, CANSUMMON))
+                            summon_help(tp, FORCE);
+                        else
+                            msg("The %s is very upset.", mname);
+
+                        turn_on(*tp, ISHASTE);
+                    }
+                    else
+                    {
+                        int m1, m2;
+                        coord   mp;
+                        struct linked_list  *titem;
+                        int ch;
+                        struct thing    *th;
+
+                        for (m1 = tp->t_pos.x - 1; m1 <= tp->t_pos.x + 1; m1++)
+                        {
+                            for (m2 = tp->t_pos.y - 1; m2 <= tp->t_pos.y + 1; m2++)
+                            {
+                                ch = winat(m2, m1);
+
+                                if (shoot_ok(ch) && ch != PLAYER)
+                                {
+                                    mp.x = m1;  /* create it */
+                                    mp.y = m2;
+                                    titem = new_item(sizeof(struct thing));
+                                    new_monster(titem, (short) tp->t_index, &mp, NOMAXSTATS);
+                                    th = THINGPTR(titem);
+                                    turn_on(*th, ISMEAN);
+                                    chase_it(&mp, &player);
+                                }
+                            }
+                        }
+                    }
+
+                    delta.y = y;
+                    delta.x = x;
+                    turn_on(*tp, ISMEAN);
+                    chase_it(&delta, &player);
+                }
+                else    /* if its a UNIQUE it might still live */
+                {
+                    if (is_stick)
+                        know_items[TYP_STICK][which] = TRUE;
+
+                    if (on(*tp, ISUNIQUE) &&
+                        save_throw(VS_MAGIC - (blessed ? -5 : 0), tp))
+                    {
+                        tp->t_stats.s_hpt = tp->t_stats.s_hpt / 2 - 1;
+
+                        if (tp->t_stats.s_hpt < 1)
+                        {
+                            killed(&player, item, NOMESSAGE, POINTS);
+                            seemsg("The %s fades away.", mname);
+                        }
+                        else
+                        {
+                            delta.y = y;
+                            delta.x = x;
+
+                            chase_it(&delta, &player);
+
+                            if (on(*tp, CANSUMMON))
+                                summon_help(tp, FORCE);
+                            else
+                                seemsg("The %s is very upset.", mname);
+                        }
+                    }
+                    else
+                    {
+                        if (on(*tp, CANSELL))
+                        {
+                            luck++;
+                            aggravate();
+                        }
+                        seemsg("The %s turns to dust and blows away.", mname);
+                        killed(&player, item, NOMESSAGE, POINTS);
+                    }
+                }
+            }
+            break;
+
+        case WS_NOTHING:
+            nothing_message(flags);
+            break;
+
+        case WS_INVIS:
+        {
+            if (cursed)
+            {
+                int x1, y1, x2, y2;
+                int  zapped = FALSE;
+
+                if ((rp = roomin(hero)) == NULL)
+                {
+                    x1 = max(hero.x - 1, 0);
+                    y1 = max(hero.y - 1, 0);
+                    x2 = min(hero.x + 1, COLS - 1);
+                    y2 = min(hero.y + 1, LINES - 3);
+                }
+                else
+                {
+                    x1 = rp->r_pos.x;
+                    y1 = rp->r_pos.y;
+                    x2 = rp->r_pos.x + rp->r_max.x;
+                    y2 = rp->r_pos.y + rp->r_max.y;
+                }
+
+                for (item = mlist; item != NULL; item = next(item))
+                {
+                    tp = THINGPTR(item);
+
+                    if (tp->t_pos.x >= x1 && tp->t_pos.x <= x2 &&
+                        tp->t_pos.y >= y1 && tp->t_pos.y <= y2)
+                    {
+                        turn_on(*tp, ISINVIS);
+                        turn_on(*tp, ISRUN);
+                        turn_off(*tp, ISDISGUISE);
+                        chase_it(&tp->t_pos, &player);
+                        zapped = TRUE;
+                    }
+                }
+
+                if (zapped)
+                    seemsg("The monsters seem to have all disappeared.");
+                else
+                    nothing_message(flags);
+            }
+            else
+            {
+                if (got_one)
+                {
+                    if (is_stick)
+                        know_items[TYP_STICK][which] = TRUE;
+
+                    if (blessed)
+                    {
+                        turn_off(*tp, ISINVIS);
+                        turn_off(*tp, ISSHADOW);
+                        seemsg("The %s appears.", mname);
+                    }
+                    else
+                    {
+                        turn_on(*tp, ISINVIS);
+                        seemsg("The %s disappears.", mname);
+                    }
+                }
+                else
+                    nothing_message(flags);
+            }
+            light(&hero);
+        }
+        break;
+
+        case WS_BLAST:
+        {
+            int                  ch;
+            struct linked_list  *itm, *ip;
+            struct object       *ob;
+            struct trap         *trp;
+
+            if (is_stick)
+                know_items[TYP_STICK][which] = TRUE;
+
+            itm = spec_item(WEAPON, GRENADE, 0, 0);
+            ob = OBJPTR(itm);
+            ob->o_count = 1;
+            ob->o_flags |= ISKNOW;
+            hearmsg("BOOOM!");
+            aggravate();
+            ob->o_pos.x = hero.x;
+            ob->o_pos.y = hero.y;
+
+            for (;;)
+            {
+                ob->o_pos.y += delta.y;
+                ob->o_pos.x += delta.x;
+
+                if (!ce(ob->o_pos, hero) &&
+                    cansee(ob->o_pos.y, ob->o_pos.x) &&
+                    mvwinch(cw, ob->o_pos.y, ob->o_pos.x) != ' ')
+                {
+                    mvwaddch(cw, ob->o_pos.y, ob->o_pos.x,
+                      show(ob->o_pos.y, ob->o_pos.x));
+                }
+
+                if (shoot_ok(ch = winat(ob->o_pos.y, ob->o_pos.x))
+                    && ch != DOOR && !ce(ob->o_pos, hero))
+                {
+                    if (cansee(ob->o_pos.y, ob->o_pos.x) &&
+                        ntraps + 1 < 2 * MAXTRAPS &&
+                        mvwinch(cw, ob->o_pos.y, ob->o_pos.x) != ' ')
+                    {
+                        mvwaddch(cw, ob->o_pos.y, ob->o_pos.x,TRAPDOOR);
+                        wrefresh(cw);
+                    }
+
+                    if (isatrap(ch))
+                    {
+                        trp = trap_at(ob->o_pos.y, ob->o_pos.x);
+
+                        if (trp != NULL)
+                        {
+                            trp->tr_type = TRAPDOOR;
+                            trp->tr_flags |= ISFOUND;
+                            trp->tr_show = TRAPDOOR;
+                        }
+                    }
+                    else if (isalpha(ch))
+                        hit_monster(ob->o_pos.y, ob->o_pos.x, ob, &player);
+                    else if ((ch == FLOOR || ch == PASSAGE)
+                         && ntraps + 1 < 2 * MAXTRAPS)
+                    {
+                        mvaddch(ob->o_pos.y, ob->o_pos.x, TRAPDOOR);
+                        traps[ntraps].tr_type = TRAPDOOR;
+                        traps[ntraps].tr_flags = ISFOUND;
+                        traps[ntraps].tr_show = TRAPDOOR;
+                        traps[ntraps].tr_pos.y = ob->o_pos.y;
+                        traps[ntraps++].tr_pos.x = ob->o_pos.x;
+                    }
+                    else if (ch == POTION || ch == SCROLL || ch == FOOD
+                         || ch == WEAPON || ch == RING || ch == ARMOR
+                         || ch == STICK || ch == ARTIFACT || ch == GOLD)
+                    {
+                        ip = find_obj(ob->o_pos.y, ob->o_pos.x);
+
+                        while (ip)     /* BOOM destroys all stacked objects */
+                        {
+                            rem_obj(ip, TRUE);
+                            ip = find_obj(ob->o_pos.y, ob->o_pos.x);
+                        }
+
+                        mvaddch(ob->o_pos.y, ob->o_pos.x,
+                            (roomin(ob->o_pos) == NULL ? PASSAGE : FLOOR) );
+                    }
+                    continue;
+                }
+                break;
+            }
+            discard(itm);
+        }
+        break;
+
+        case WS_WEB:
+        {
+            int ch;
+            coord pos;
+
+            if (is_stick)
+                know_items[TYP_STICK][which] = TRUE;
+
+            pos = do_motion('#', delta.y, delta.x, &player);
+            ch  = winat(pos.y, pos.x);
+
+            if (isalpha(ch))
+            {
+                if (save_throw(VS_MAGIC, tp))
+                    seemsg("The %s evades your web.", mname);
+                else
+                {
+                    seemsg("The %s is webbed.", mname);
+                    turn_off(*tp, ISRUN);
+                    turn_on(*tp, ISHELD);
+                }
+            }
+
+            if (pos.y >= 0 && pos.x >= 0 &&
+                pos.y < LINES && pos.x < COLS)
+                mvwaddch(cw, pos.y, pos.x, show(pos.y, pos.x));
+        }
+        break;
+
+        case WS_KNOCK:
+        case WS_CLOSE:
+            if (blessed)    /* Do all doors in room */
+            {
+                char    new_door = (which == WS_KNOCK ? DOOR : SECRETDOOR);
+                struct room *rmp = roomin(hero);
+
+                if (rmp != NULL)
+                    for (x = 0; x < rmp->r_nexits; x++)
+                    {
+                        move(rmp->r_exit[x].y, rmp->r_exit[x].x);
+                        addch(new_door);
+                    }
+                else    /* Do all adjacent doors */
+                    for (x = hero.x - 1; x <= hero.x + 1; x++)
+                        for (y = hero.y - 1; y <= hero.y + 1; y++)
+                            switch(CCHAR( winat(y, x) ))
+                            {
+                                case DOOR:
+                                case SECRETDOOR:
+                                    addch(new_door);
+                                    break;
+                            }
+                light(&hero);
+            }
+            else if (cursed)/* do opposite spell */
+                do_zap(zapper, (which == WS_KNOCK ? WS_CLOSE : WS_KNOCK), ISBLESSED);
+            else
+            {
+                coord   zap_loc;
+                char    loc;
+
+                zap_loc.y = hero.y + delta.y;
+                zap_loc.x = hero.x + delta.x;
+                loc = winat(zap_loc.y, zap_loc.x);
+
+                switch (loc)
+                {
+                    case SECRETDOOR:
+                        if (which == WS_KNOCK)
+                        {
+                            mvaddch(zap_loc.y, zap_loc.x, DOOR);
+                            seemsg("A secret door stands revealed before you!");
+
+                            if (is_stick)
+                                know_items[TYP_STICK][which] = TRUE;
+                        }
+                        else
+                            nothing_message(flags);
+                        break;
+
+                    case DOOR:
+
+                        if (which == WS_CLOSE)
+                        {
+                            mvaddch(zap_loc.y, zap_loc.x, SECRETDOOR);
+                            msg("You sucessfully block off the door.")
+;
+                            if (is_stick)
+                                know_items[TYP_STICK][which] = TRUE;
+                        }
+                        else
+                            nothing_message(flags);
+
+                        break;
+
+                    default:
+                        nothing_message(flags);
+                }
+            }
+
+        break;
+        default:
+            msg("What a bizarre schtick!");
+    }
+}
+
+/*
+    drain()
+        Do drain hit points from player shtick
+*/
+
+void
+drain(int ymin, int ymax, int xmin, int xmax)
+{
+    int i, j, cnt;
+    struct thing    *ick;
+    struct linked_list  *item;
+
+    /* First count how many things we need to spread the hit points among */
+
+    for (cnt = 0, i = ymin; i <= ymax; i++)
+        for (j = xmin; j <= xmax; j++)
+            if (isalpha(mvwinch(mw, i, j)))
+                cnt++;
+
+    if (cnt == 0)
+    {
+        msg("You have a tingling feeling.");
+        return;
+    }
+    else
+        msg("You feel weaker.");
+
+    cnt = pstats.s_hpt / cnt;
+    pstats.s_hpt /= 2;
+
+    /* Now zot all of the monsters */
+
+    for (i = ymin; i <= ymax; i++)
+        for (j = xmin; j <= xmax; j++)
+            if (isalpha(mvwinch(mw, i, j)) && ((item = find_mons(i, j)) != NULL))
+            {
+                ick = THINGPTR(item);
+
+                if (on(*ick, CANSELL))
+                {
+                    luck++;
+                    aggravate();
+                }
+
+                if ((ick->t_stats.s_hpt -= cnt) < 1)
+                    killed(&player, item,
+                           cansee(i, j) && !on(*ick, ISINVIS), POINTS);
+            }
+}
+
+/*
+    charge_str()
+        charge a wand for wizards.
+*/
+
+char *
+charge_str(struct object *obj, char *buf)
+{
+    if (buf == NULL)
+        return( "[UltraRogue Bug #103]" );
+
+    if (!(obj->o_flags & ISKNOW))
+        buf[0] = '\0';
+    else if (obj->o_charges == 1)
+        sprintf(buf, " [%d charge]", obj->o_charges);
+    else
+        sprintf(buf, " [%d charges]", obj->o_charges);
+
+    return(buf);
+}
+
+
+/*
+    shoot_bolt()
+        fires a bolt from the given starting point in the given direction
+        struct thing    *shooter;
+        coord   start, dir;
+        int    get_points;      should player get exp points?
+        short   reason;         reason for dying
+        char    *name;          fire, nerve, cold, etc
+        int damage;             make zapee suffer
+*/
+
+void
+shoot_bolt(struct thing *shooter, coord start, coord dir, int get_points, int reason, char *name, int damage)
+{
+    int     ch;
+    char    dirch;
+    int     change;
+    short   y, x;
+    coord   pos;
+    coord   spotpos[BOLT_LENGTH + 1];
+    int     ret_val = FALSE;/* True if breathing monster gets killed */
+    struct linked_list  *item;
+    struct thing    *tp;
+    char    *mname;
+    int bounced;    /* where along BOLT_LENGTH it hit a wall */
+    int player_damage;  /* damage if player saved */
+    int  no_effect;  /* zap does not effect zappee */
+    int take_that[BOLT_LENGTH + 1]; /* damage to each monster */
+
+    /* last spot for player */
+
+    debug("%s does %d damage", name, damage);
+
+    switch (dir.y + dir.x)
+    {
+        case 0:
+            dirch = '/';
+            break;
+
+        case 1:
+        case -1:
+            dirch = (dir.y == 0 ? '-' : '|');
+            break;
+
+        case 2:
+        case -2:
+            dirch = '\\';
+            break;
+    }
+
+    pos.y = start.y + dir.y;
+    pos.x = start.x + dir.x;
+    change = FALSE;
+
+    for (y = 0; y < BOLT_LENGTH + 1; y++)
+        take_that[y] = 0;
+
+    bounced = 0;
+
+    for (y = 0; y < BOLT_LENGTH; y++)
+    {
+        no_effect = FALSE;
+        ch = winat(pos.y, pos.x);
+        spotpos[y] = pos;
+
+        /* Bolt damage dimishes over space */
+
+        damage = max(1, damage - (y / 3));
+
+        /* Are we at hero? */
+
+        if (ce(pos, hero))
+            goto at_hero;
+
+        switch(ch)
+        {
+            case SECRETDOOR:
+            case '|':
+            case '-':
+            case ' ':
+                bounced = y;
+                if (dirch == '-' || dirch == '|')
+                {
+                    dir.y = -dir.y;
+                    dir.x = -dir.x;
+                }
+                else
+                    switch (ch)
+                    {
+                        case '|':
+                        case '-':
+                        case SECRETDOOR:
+                        {
+                            struct room *rp;
+
+                            rp = roomin(pos);
+
+                            if (pos.y == rp->r_pos.y ||
+                                pos.y == rp->r_pos.y + rp->r_max.y - 1)
+                            {
+                                dir.y = -dir.y;
+                                change ^= TRUE;
+                            }
+
+                            if (pos.x == rp->r_pos.x ||
+                                pos.x == rp->r_pos.x + rp->r_max.x - 1)
+                            {
+                                dir.x = -dir.x;
+                                change ^= TRUE;
+                            }
+                        }
+                        default:     /* A wall */
+                        {
+                            char    chy = CCHAR( mvinch(pos.y - dir.y, pos.x + dir.x)), chx = CCHAR( mvinch(pos.y + dir.y, pos.x - dir.x) );
+
+                            if (chy != WALL && chy != SECRETDOOR &&
+                             chy != '-' && chy != '|')
+                            {
+                                dir.y = -dir.y;
+                                change = TRUE;
+                            }
+                            else if (chx != WALL && chx != SECRETDOOR &&
+                                 chx != '-' && chx != '|')
+                            {
+                                dir.x = -dir.x;
+                                change = TRUE;
+                            }
+                            else
+                            {
+                                dir.y = -dir.y;
+                                dir.x = -dir.x;
+                            }
+                        }
+                    }
+
+                /* Do we change how the bolt looks? */
+
+                if (change)
+                {
+                    change = FALSE;
+
+                    if (dirch == '\\')
+                        dirch = '/';
+                    else if (dirch == '/')
+                        dirch = '\\';
+                }
+
+            break;
+
+            default:
+                if (isalpha(ch))    /* hit a monster */
+                {
+                    item = find_mons(pos.y, pos.x);
+
+                    if (item == NULL)
+                    {
+                        debug("Can't find monster %c @ %d %d.",
+                              ch, pos.y, pos.x);
+
+                        continue;
+                    }
+
+                    tp = THINGPTR(item);
+                    mname = on(player, ISBLIND) ? "monster" : monsters[tp->t_index].m_name;
+
+                    /* Disguised monsters stay hidden if they save */
+
+                    if (on(*tp, ISDISGUISE) && save_throw(VS_MAGIC, tp) &&
+                        (tp->t_type != tp->t_disguise) && off(player, ISBLIND))
+                    {
+                        msg("Wait! That's a %s!", mname);
+                        turn_off(*tp, ISDISGUISE);
+                    }
+
+                    tp->t_wasshot = TRUE;
+
+                    if (on(*tp, CANSELL))
+                    {
+                        luck++;
+                        aggravate();
+                    }
+
+                    /* Hit the monster -- does it do damage? */
+
+                    if (strcmp(name, "ice") == 0)
+                    {
+                        if (on(*tp, NOCOLD) || on(*tp, ISUNDEAD))
+                            no_effect = TRUE;
+                    }
+                    else if (strcmp(name, "flame") == 0)
+                    {
+                        if (on(*tp, NOFIRE))
+                            no_effect = TRUE;
+
+                        if (on(*tp, CANBBURN))
+                        {
+                            seemsg("The %s is burned to death by the flame.",
+                                   mname);
+
+                            take_that[y] += tp->t_stats.s_hpt + 1;
+                            ret_val = TRUE;
+                        }
+                    }
+                    else if (strcmp(name, "lightning bolt") == 0)
+                    {
+                        if (on(*tp, NOBOLT))
+                            no_effect = TRUE;
+
+                        if (on(*tp, BOLTDIVIDE))
+                        {
+                            no_effect = TRUE;
+
+                            if (creat_mons(tp, tp->t_index, NOMESSAGE))
+                                seemsg("The %s divides the %s.", name, mname);
+                        }
+                    }
+
+                    if (no_effect == TRUE)
+                    {
+                        msg("The %s has no effect on the %s.", name,
+                            on(player, ISBLIND) ? "monster" : mname);
+                    }
+                    else
+                    {
+                        take_that[(bounced ? bounced-- : y)] +=
+                            save_throw(VS_MAGIC, tp) ? damage / 2 : damage;
+                    }
+                }
+                else if (pos.y == hero.y && pos.x == hero.x)
+                {
+        at_hero:
+                    player_damage = damage;
+                    running = fighting = FALSE;
+                    bounced = 0;
+
+                    if (cur_armor != NULL &&
+                        cur_armor->o_which == CRYSTAL_ARMOR &&
+                        (strcmp(name, "acid") == 0))
+                    {
+                        player_damage = 0;
+                        msg("The acid splashes harmlessly against your armor!");
+                    }
+                    else if (((cur_armor != NULL &&
+                           cur_armor->o_which == CRYSTAL_ARMOR) ||
+                          (on(player, ISELECTRIC)) ||
+                          is_wearing(R_ELECTRESIST)) &&
+                        (strcmp(name, "lightning bolt") == 0))
+                    {
+                        player_damage = 0;
+
+                        if (rnd(100) < 75
+                            && cur_weapon != NULL
+                            && shooter != &player)
+                        {
+                            cur_weapon->o_flags |= ISZAPPED;
+                            cur_weapon->o_charges += (10 + rnd(15));
+                        }
+
+                        if (cur_weapon != NULL && cur_armor != NULL)
+                            msg("Your armor and %s are covered with dancing blue lights!", weaps[cur_weapon->o_which].w_name);
+                        else if (cur_armor != NULL)
+                            msg("Your armor is covered with dancing blue lights!");
+                        else if (cur_weapon != NULL)
+                            msg("Your %s is covered with dancing blue lights!", weaps[cur_weapon->o_which].w_name);
+                        else
+                            msg("You are momentarily covered with dancing blue lights.");
+                    }
+                    else if ((is_wearing(R_FIRERESIST) || on(player, NOFIRE)) &&
+                         (strcmp(name, "flame") == 0))
+                    {
+                        player_damage = 0;
+                        msg("The flame bathes you harmlessly.");
+                    }
+                    else if ((is_wearing(R_COLDRESIST) || on(player, NOCOLD)) &&
+                         (strcmp(name, "ice") == 0))
+                    {
+                        player_damage = 0;
+                        msg("The ice cracks and quickly melts around you.");
+                    }
+                    else if (save(VS_MAGIC))
+                    {
+                        take_that[BOLT_LENGTH] += player_damage / 2;
+                        debug("Player dodges %s for %d.", name, player_damage / 2);
+                    }
+                    else
+                    {
+                        debug("Player zapped by %s for %d.", name, player_damage);
+                        take_that[BOLT_LENGTH] += player_damage;
+                    }
+
+                    /* Check for gas with special effects */
+
+                    if (off(player, HASOXYGEN) && !is_wearing(R_BREATHE) && !save(VS_BREATH))
+                    {
+                        if (strcmp(name, "nerve gas") == 0)
+                        {
+                            if (no_command == 0)
+                            {
+                                msg("The nerve gas paralyzes you.");
+                                no_command = FREEZETIME;
+                            }
+                        }
+                        else if (strcmp(name, "sleeping gas") == 0)
+                        {
+                            if (no_command == 0)
+                            {
+                                msg("The sleeping gas puts you to sleep.");
+                                no_command = SLEEPTIME;
+                            }
+                        }
+                        else if (strcmp(name, "slow gas") == 0
+                             && !is_wearing(R_FREEDOM))
+                        {
+                            msg("You feel yourself moving %sslower.",
+                                on(player, ISSLOW) ? "even " : "");
+
+                            if (on(player, ISSLOW))
+                                lengthen_fuse(FUSE_NOSLOW, rnd(10) + 4);
+                            else
+                            {
+                                turn_on(player, ISSLOW);
+                                player.t_turn = TRUE;
+                                light_fuse(FUSE_NOSLOW, 0, rnd(10) + 4, AFTER);
+                            }
+                        }
+                        else if (strcmp(name, "fear gas") == 0)
+                        {
+                            if (!(on(player, ISFLEE) &&
+                                  (player.t_chasee==shooter)) &&
+                                (shooter != &player))
+                            {
+                                if (off(player, SUPERHERO)
+                                    && player.t_ctype != C_PALADIN)
+                                {
+                                    turn_on(player, ISFLEE);
+                                    player.t_chasee = shooter;
+                                    player.t_ischasing = FALSE;
+                                    msg("The fear gas terrifies you.");
+                                }
+                                else
+                                    msg("The fear gas has no effect.");
+                            }
+                        }
+                    }
+                }
+                mvwaddch(cw, pos.y, pos.x, dirch);
+                wrefresh(cw);
+            }
+            pos.y += dir.y;
+            pos.x += dir.x;
+        }
+
+        /*
+         * Now that we have determined the damage for the length of the bolt,
+         * apply it to each monster (and then the player) in turn
+         */
+
+        for (x = 0; x < BOLT_LENGTH; x++)
+        {
+            ch = winat(spotpos[x].y, spotpos[x].x);
+
+            if (take_that[x] != 0 && isalpha(ch))
+            {
+                if ((item = find_mons(spotpos[x].y, spotpos[x].x)) == NULL)
+                {
+                    debug("Can't find monster %c @ %d %d.",
+                          ch, spotpos[x].y, spotpos[x].x);
+
+                    continue;
+                }
+                else
+                    tp = THINGPTR(item);
+
+                mname = on(player, ISBLIND) ? "monster" : monsters[tp->t_index].m_name;
+
+                debug("Zapped %s for %d (%d)",
+                      mname, take_that[x], tp->t_stats.s_hpt - take_that[x]);
+
+                if ((tp->t_stats.s_hpt -= take_that[x]) <= 0)
+                {
+                    if (cansee(tp->t_pos.y, tp->t_pos.x))
+                        msg("The %s kills the %s.", name,
+                            on(player, ISBLIND) ? "monster" : mname);
+
+                    killed(shooter, item, NOMESSAGE, get_points);
+                    ret_val = TRUE;
+                }
+                else if (get_points)
+                {
+                    chase_it(&spotpos[x], &player);
+                    summon_help(tp, NOFORCE);
+                }
+            }
+
+            if (spotpos[x].y >= 0 && spotpos[x].x >= 0 &&
+                spotpos[x].y < LINES && spotpos[x].x < COLS)
+                mvwaddch(cw, spotpos[x].y, spotpos[x].x,
+                     show(spotpos[x].y, spotpos[x].x));
+        }
+
+        if (take_that[BOLT_LENGTH] != 0)
+        {
+            if (tp != THINGPTR(fam_ptr))
+            {
+                msg("You are hit by the %s.", name);
+
+                if ((pstats.s_hpt -= take_that[BOLT_LENGTH]) <= 0)
+                {
+                    death(reason);
+                    return;
+                }
+            }
+        }
+
+    return;
+}
+
+/*
+    monster_do_zap()
+        monster gets the effect
+*/
+
+void
+monster_do_zap(struct thing *zapper, int which, int flags)
+{
+    struct stats    *curp = &(zapper->t_stats);
+    int blessed = flags & ISBLESSED;
+    int cursed = flags & ISCURSED;
+    int shoot = FALSE;
+    int damage;
+    int ndice, nsides;
+    int ch;
+    char *bolt_name = NULL;
+    coord pos;
+
+    switch(which)
+    {
+        case WS_MISSILE:
+            bolt_name = "magic missile";
+            pos = do_motion('*', delta.y, delta.x, zapper);
+            ch = winat(pos.y, pos.x);
+            ndice = curp->s_lvl;
+            nsides = 4;
+
+            if (cursed)
+                nsides /= 2;
+            else if (blessed)
+                nsides *= 2;
+
+            damage = roll(ndice, nsides);
+
+            if (ch == PLAYER)
+            {
+                if (save(VS_MAGIC)) /* help the player */
+                    msg("You evade the %s.", bolt_name);
+                else
+                {
+                    msg("You are hit by the %s.", bolt_name);
+
+                    if ((pstats.s_hpt -= damage) <= 0)
+                        death(D_BOLT);
+                }
+            }
+            else if (isalpha(ch))
+            {
+                struct linked_list  *item = find_mons(pos.y, pos.x);
+
+                if (item != NULL)
+                {
+                    struct thing    *tp = THINGPTR(item);
+                    int see_it = cansee(pos.y, pos.x);
+
+                    if ((tp->t_stats.s_hpt -= damage) <= 0)
+                        killed(zapper, item, see_it, (zapper == THINGPTR(fam_ptr)));
+                    else if (see_it)
+                        msg("The %s hits the monster.", bolt_name);
+                }
+            }
+
+            if (pos.y >= 0 && pos.x >= 0 &&
+                pos.y < LINES && pos.x < COLS)
+                mvwaddch(cw, pos.y, pos.x, show(pos.y, pos.x));
+
+            break;
+
+        case WS_CANCEL:
+            cancel_player(off(*zapper, ISUNIQUE));
+            break;
+
+        case WS_COLD:
+            shoot = TRUE;
+            bolt_name = "cold";
+            break;
+
+        case WS_FIRE:
+            shoot = TRUE;
+            bolt_name = "fire";
+            break;
+
+        case WS_ELECT:
+            shoot = TRUE;
+            bolt_name = "lightning";
+            break;
+
+        default:
+            debug("'%s' is a strange stick for a monster to zap!",
+                  ws_magic[which].mi_name);
+            break;
+    }
+
+    if (shoot)
+    {
+        ndice = curp->s_lvl / 2 + 1;
+        nsides = 6;
+
+        if (cursed)
+            nsides /= 2;
+        else if (blessed)
+            nsides *= 2;
+
+        damage = roll(ndice, nsides);
+        shoot_bolt(zapper, zapper->t_pos, delta,
+            (zapper == THINGPTR(fam_ptr)), D_BOLT, bolt_name, damage);
+    }
+}
+
+struct powers
+{
+    unsigned long p_flag;
+    int fuse_id;
+};
+
+/* Order in which powers will attempt to be cancelled */
+
+struct powers player_powers[] =
+{
+    { ISHASTE,    FUSE_NOHASTE     },
+    { ISELECTRIC, FUSE_UNELECTRIFY },
+    { CANINWALL,  FUSE_UNPHASE     },
+    { CANFLY,     FUSE_UNFLY       },
+    { ISINVIS,    FUSE_APPEAR      },
+    { CANREFLECT, FUSE_UNGAZE      },
+    { ISDISGUISE, FUSE_UNDISGUISE  },
+    { HASMSHIELD, FUSE_UNMSHIELD   },
+    { ISREGEN,    FUSE_UNREGEN     },
+    { CANSEE,     FUSE_UNSEE       },
+    { NOCOLD,     FUSE_UNCOLD      },
+    { NOFIRE,     FUSE_UNHOT       },
+    { HASOXYGEN,  FUSE_UNBREATHE   },
+    { HASSHIELD,  FUSE_UNSHIELD    },
+    { ULONG_MAX,         FUSE_NULL        }
+};
+
+void
+cancel_player(int not_unique)
+{
+    struct powers   *pp;
+    int no_effect = TRUE;
+
+    for(pp = player_powers; pp->p_flag != ULONG_MAX; pp++)
+    {
+        if (on(player, pp->p_flag) && !save(VS_MAGIC))
+        {
+            fuses[pp->fuse_id].func(NULL);
+            extinguish_fuse(pp->fuse_id);
+            no_effect = FALSE;
+
+            if (not_unique) /* Gods might cancel everything */
+                break;
+        }
+    }
+
+    if (no_effect)
+        nothing_message(ISNORMAL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/things.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,935 @@
+/*
+    things.c - functions for dealing with things like potions and scrolls
+                    
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <string.h>
+#include <ctype.h>
+#include "rogue.h"
+
+/*
+    inv_name()
+        return the name of something as it would appear in an inventory.
+*/
+
+char *
+inv_name(struct object *obj, int lowercase)
+{
+    char *pb;
+    char buf[1024];
+
+    switch(obj->o_type)
+    {
+        case SCROLL:
+            if (obj->o_count == 1)
+                sprintf(prbuf, "A %s%sscroll ",
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    blesscurse(obj->o_flags));
+            else
+                sprintf(prbuf, "%d %s%sscrolls ",
+                    obj->o_count,
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    blesscurse(obj->o_flags));
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if (know_items[TYP_SCROLL][obj->o_which])
+                sprintf(pb, "of %s", s_magic[obj->o_which].mi_name);
+            else if (guess_items[TYP_SCROLL][obj->o_which])
+                sprintf(pb, "called %s", guess_items[TYP_SCROLL][obj->o_which]);
+            else
+                sprintf(pb, "titled '%s'", s_names[obj->o_which]);
+            break;
+
+        case POTION:
+            if (obj->o_count == 1)
+                sprintf(prbuf, "A %s%spotion ",
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    blesscurse(obj->o_flags));
+            else
+                sprintf(prbuf, "%d %s%spotions ",
+                    obj->o_count,
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    blesscurse(obj->o_flags));
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if (know_items[TYP_POTION][obj->o_which])
+                sprintf(pb, "of %s(%s)", p_magic[obj->o_which].mi_name,
+                    p_colors[obj->o_which]);
+            else if (guess_items[TYP_POTION][obj->o_which])
+                sprintf(pb, "called %s(%s)", guess_items[TYP_POTION][obj->o_which],
+                    p_colors[obj->o_which]);
+            else
+            {
+                if (obj->o_count == 1)
+                    sprintf(prbuf, "A%s %s potion",
+                         obj->o_flags & CANRETURN ? " claimed" :
+                        (char *) vowelstr(p_colors[obj->o_which]),
+                        p_colors[obj->o_which]);
+                else
+                    sprintf(prbuf, "%d %s%s potions",
+                        obj->o_count,
+                     obj->o_flags & CANRETURN ? "claimed " : "",
+                        (char *) p_colors[obj->o_which]);
+            }
+            break;
+
+        case FOOD:
+            if (obj->o_count == 1)
+                sprintf(prbuf, "A%s %s",
+                    obj->o_flags & CANRETURN ? " claimed" :
+                    (char *) vowelstr(fd_data[obj->o_which].mi_name),
+                    fd_data[obj->o_which].mi_name);
+            else
+                sprintf(prbuf, "%d %s%ss", obj->o_count,
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    fd_data[obj->o_which].mi_name);
+            break;
+
+        case WEAPON:
+            if (obj->o_count > 1)
+                sprintf(prbuf, "%d ", obj->o_count);
+            else if ((obj->o_flags & (ISZAPPED | CANRETURN | ISPOISON | ISSILVER | ISTWOH)) ||
+                 ((obj->o_flags & (ISKNOW | ISZAPPED)) == (ISKNOW | ISZAPPED)))
+                strcpy(prbuf, "A ");
+            else
+                sprintf(prbuf, "A%s ", vowelstr(weaps[obj->o_which].w_name));
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if ((obj->o_flags & ISKNOW) && (obj->o_flags & ISZAPPED))
+                sprintf(pb, "charged%s ", charge_str(obj,buf));
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if (obj->o_flags & CANRETURN)
+                sprintf(pb, "claimed ");
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if (obj->o_flags & ISPOISON)
+                sprintf(pb, "poisoned ");
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if (obj->o_flags & ISSILVER)
+                sprintf(pb, "silver ");
+
+            if (obj->o_flags & ISTWOH)
+                sprintf(pb, "two-handed ");
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if (obj->o_flags & ISKNOW)
+                sprintf(pb, "%s %s", num(obj->o_hplus, obj->o_dplus, buf),
+                weaps[obj->o_which].w_name);
+            else
+                sprintf(pb, "%s", weaps[obj->o_which].w_name);
+
+            if (obj->o_count > 1)
+                strcat(prbuf, "s");
+
+            break;
+
+        case ARMOR:
+            if (obj->o_flags & ISKNOW)
+                sprintf(prbuf, "%s%s %s",
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                   num(armors[obj->o_which].a_class - obj->o_ac, 0, buf),
+                    armors[obj->o_which].a_name);
+            else
+                sprintf(prbuf, "%s%s",
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    armors[obj->o_which].a_name);
+
+            break;
+
+        case ARTIFACT:
+            sprintf(prbuf, "the %s", arts[obj->o_which].ar_name);
+
+            if (obj->o_flags & CANRETURN)
+                strcat(prbuf, " (claimed)");
+
+            break;
+
+        case STICK:
+            sprintf(prbuf, "A %s%s%s ",
+                obj->o_flags & CANRETURN ? "claimed " : "",
+                blesscurse(obj->o_flags), ws_type[obj->o_which]);
+
+            pb = &prbuf[strlen(prbuf)];
+
+            if (know_items[TYP_STICK][obj->o_which])
+                sprintf(pb, "of %s%s(%s)", ws_magic[obj->o_which].mi_name,
+                    charge_str(obj,buf), ws_made[obj->o_which]);
+            else if (guess_items[TYP_STICK][obj->o_which])
+                sprintf(pb, "called %s(%s)", guess_items[TYP_STICK][obj->o_which],
+                    ws_made[obj->o_which]);
+            else
+                sprintf(&prbuf[2], "%s%s %s",
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    ws_made[obj->o_which],
+                    ws_type[obj->o_which]);
+
+            break;
+
+        case RING:
+            if (know_items[TYP_RING][obj->o_which])
+                sprintf(prbuf, "A%s%s ring of %s(%s)",
+                    obj->o_flags & CANRETURN ? " claimed" : "", ring_num(obj,buf),
+                    r_magic[obj->o_which].mi_name, r_stones[obj->o_which]);
+            else if (guess_items[TYP_RING][obj->o_which])
+                sprintf(prbuf, "A %sring called %s(%s)",
+                    obj->o_flags & CANRETURN ? "claimed " : "",
+                    guess_items[TYP_RING][obj->o_which], r_stones[obj->o_which]);
+            else
+                sprintf(prbuf, "A%s %s ring",
+                    obj->o_flags & CANRETURN ? "claimed " :
+                    (char *)vowelstr(r_stones[obj->o_which]),
+                    r_stones[obj->o_which]);
+            break;
+
+        case GOLD:
+            sprintf(prbuf, "%d gold pieces", obj->o_count);
+            break;
+
+        default:
+            debug("Picked up something funny.");
+            sprintf(prbuf, "Something bizarre %s", unctrl(obj->o_type));
+            break;
+    }
+
+    /* Is it marked? */
+
+    if (obj->o_mark[0])
+    {
+        pb = &prbuf[strlen(prbuf)];
+        sprintf(pb, " <%s>", obj->o_mark);
+    }
+
+    if (obj == cur_armor)
+        strcat(prbuf, " (being worn)");
+
+    if (obj == cur_weapon)
+        strcat(prbuf, " (weapon in hand)");
+
+    if (obj == cur_ring[LEFT_1])
+        strcat(prbuf, " (on left hand)");
+    else if (obj == cur_ring[LEFT_2])
+        strcat(prbuf, " (on left hand)");
+    else if (obj == cur_ring[LEFT_3])
+        strcat(prbuf, " (on left hand)");
+    else if (obj == cur_ring[LEFT_4])
+        strcat(prbuf, " (on left hand)");
+    else if (obj == cur_ring[LEFT_5])
+        strcat(prbuf, " (on left hand)");
+    else if (obj == cur_ring[RIGHT_1])
+        strcat(prbuf, " (on right hand)");
+    else if (obj == cur_ring[RIGHT_2])
+        strcat(prbuf, " (on right hand)");
+    else if (obj == cur_ring[RIGHT_3])
+        strcat(prbuf, " (on right hand)");
+    else if (obj == cur_ring[RIGHT_4])
+        strcat(prbuf, " (on right hand)");
+    else if (obj == cur_ring[RIGHT_5])
+        strcat(prbuf, " (on right hand)");
+
+    if (obj->o_flags & ISPROT)
+        strcat(prbuf, " [protected]");
+
+    if (lowercase && isupper(prbuf[0]))
+        prbuf[0] = (char) tolower(prbuf[0]);
+    else if (!lowercase && islower(*prbuf))
+        *prbuf = (char) toupper(*prbuf);
+
+    if (!lowercase)
+        strcat(prbuf, ".");
+
+    return(prbuf);
+}
+
+/*
+    rem_obj()
+        Remove an object from the level.
+*/
+
+void
+rem_obj(struct linked_list *item, int dis)
+{
+    struct linked_list  *llptr;
+    struct object *objptr, *op;
+    int x, y;
+
+    if (item == NULL)
+        return;
+
+    detach(lvl_obj, item);
+    objptr = OBJPTR(item);
+
+    if ( (llptr = objptr->next_obj) != NULL )
+    {
+        detach((objptr->next_obj), llptr);
+        attach(lvl_obj, llptr);
+
+        op = OBJPTR(llptr);
+	
+	op->next_obj = objptr->next_obj;
+        
+	if (op->next_obj)
+            objptr->next_obj->l_prev = NULL;
+
+        y = op->o_pos.y;
+        x = op->o_pos.x;
+
+        if (cansee(y, x))
+            mvwaddch(cw, y, x, op->o_type);
+
+        mvaddch(y, x, op->o_type);
+    }
+    else
+    {
+        y = objptr->o_pos.y;
+        x = objptr->o_pos.x;
+
+        /* problems if dropped in rock */
+
+        mvaddch(y,x,(roomin((objptr->o_pos)) == NULL ? PASSAGE : FLOOR));
+    }
+
+    if (dis)
+        discard(item);
+}
+
+/*
+    add_obj()
+        adds an object to the level
+*/
+
+void
+add_obj(struct linked_list *item, int y, int x)
+{
+    struct linked_list  *llptr;
+    struct object*objptr;
+
+    llptr = find_obj(y, x);
+
+    if (llptr)
+    {
+        objptr = OBJPTR(llptr);
+        attach((objptr->next_obj), item);
+    }
+    else
+    {
+        attach(lvl_obj, item);
+        objptr = OBJPTR(item);
+        objptr->next_obj = NULL;
+        objptr->o_pos.y = y;
+        objptr->o_pos.x = x;
+        mvaddch(y, x, objptr->o_type);
+    }
+}
+
+/*
+    drop()
+        put something down
+*/
+
+int
+drop(struct linked_list *item)
+{
+    char    ch = CCHAR( mvwinch(stdscr, hero.y, hero.x) );
+    struct object   *obj;
+
+    switch (ch)
+    {
+        case GOLD:
+        case POTION:
+        case SCROLL:
+        case FOOD:
+        case WEAPON:
+        case ARMOR:
+        case RING:
+        case STICK:
+        case FLOOR:
+        case PASSAGE:
+        case POOL:
+        case ARTIFACT:
+            if (item == NULL && (item = get_item("drop", 0)) == NULL)
+                return(FALSE);
+            break;
+
+        default:
+            msg("You can't drop something here.");
+            return(FALSE);
+    }
+
+    obj = OBJPTR(item);
+
+    if (!dropcheck(obj))
+        return(FALSE);
+
+    /* Curse a dropped scare monster scroll */
+
+    if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
+    {
+        if (obj->o_flags & ISBLESSED)
+            obj->o_flags &= ~ISBLESSED;
+        else
+            obj->o_flags |= ISCURSED;
+    }
+
+    /* Take it out of the pack */
+
+    if (obj->o_count >= 2 && obj->o_group == 0)
+    {
+        struct linked_list  *nitem = new_item(sizeof *obj);
+
+        obj->o_count--;
+        obj = OBJPTR(nitem);
+        *obj = *(OBJPTR(item));
+        obj->o_count = 1;
+        item = nitem;
+    }
+    else
+        rem_pack(obj);
+
+    if (ch == POOL)
+    {
+        msg("The pool bubbles briefly as your %s sinks out of sight.",
+            inv_name(obj, TRUE));
+        discard(item);
+        item = NULL;
+    }
+    else            /* Link it into the level object list */
+    {
+        add_obj(item, hero.y, hero.x);
+        mvaddch(hero.y, hero.x, obj->o_type);
+    }
+
+    if (obj->o_type == ARTIFACT)
+        has_artifact &= ~(1 << obj->o_which);
+
+    updpack();
+    return(TRUE);
+}
+
+/*
+    dropcheck()
+        do special checks for dropping or unweilding|unwearing|unringing
+*/
+
+int
+dropcheck(struct object *op)
+{
+    if (op == NULL)
+        return(TRUE);
+
+    if (op != cur_armor && op != cur_weapon &&
+        op != cur_ring[LEFT_1] && op != cur_ring[LEFT_2] &&
+        op != cur_ring[LEFT_3] && op != cur_ring[LEFT_4] &&
+        op != cur_ring[LEFT_5] &&
+        op != cur_ring[RIGHT_1] && op != cur_ring[RIGHT_2] &&
+        op != cur_ring[RIGHT_3] && op != cur_ring[RIGHT_4] &&
+        op != cur_ring[RIGHT_5])
+        return(TRUE);
+
+    if (op->o_flags & ISCURSED)
+    {
+        msg("You can't.  It appears to be cursed.");
+        return(FALSE);
+    }
+
+    if (op == cur_weapon)
+        cur_weapon = NULL;
+    else if (op == cur_armor)
+    {
+        waste_time();
+        cur_armor = NULL;
+    }
+    else if (op == cur_ring[LEFT_1] || op == cur_ring[LEFT_2] ||
+         op == cur_ring[LEFT_3] || op == cur_ring[LEFT_4] ||
+         op == cur_ring[LEFT_5] ||
+         op == cur_ring[RIGHT_1] || op == cur_ring[RIGHT_2] ||
+         op == cur_ring[RIGHT_3] || op == cur_ring[RIGHT_4] ||
+         op == cur_ring[RIGHT_5])
+    {
+        if (op == cur_ring[LEFT_1])
+            cur_ring[LEFT_1] = NULL;
+        else if (op == cur_ring[LEFT_2])
+            cur_ring[LEFT_2] = NULL;
+        else if (op == cur_ring[LEFT_3])
+            cur_ring[LEFT_3] = NULL;
+        else if (op == cur_ring[LEFT_4])
+            cur_ring[LEFT_4] = NULL;
+        else if (op == cur_ring[LEFT_5])
+            cur_ring[LEFT_5] = NULL;
+        else if (op == cur_ring[RIGHT_1])
+            cur_ring[RIGHT_1] = NULL;
+        else if (op == cur_ring[RIGHT_2])
+            cur_ring[RIGHT_2] = NULL;
+        else if (op == cur_ring[RIGHT_3])
+            cur_ring[RIGHT_3] = NULL;
+        else if (op == cur_ring[RIGHT_4])
+            cur_ring[RIGHT_4] = NULL;
+        else if (op == cur_ring[RIGHT_5])
+            cur_ring[RIGHT_5] = NULL;
+
+        switch (op->o_which)
+        {
+            case R_ADDSTR:
+                chg_str(-op->o_ac, FALSE, FALSE);
+                break;
+            case R_ADDHIT:
+                chg_dext(-op->o_ac, FALSE, FALSE);
+                break;
+            case R_ADDINTEL:
+                pstats.s_intel -= op->o_ac;
+                break;
+            case R_ADDWISDOM:
+                pstats.s_wisdom -= op->o_ac;
+                break;
+
+            case R_SEEINVIS:
+                if (find_slot(FUSE_UNSEE,FUSE) == NULL)
+                {
+                    turn_off(player, CANSEE);
+                    msg("The tingling feeling leaves your eyes.");
+                }
+
+                light(&hero);
+                mvwaddch(cw, hero.y, hero.x, PLAYER);
+                break;
+
+            case R_LIGHT:
+                if (roomin(hero) != NULL)
+                {
+                    light(&hero);
+                    mvwaddch(cw, hero.y, hero.x, PLAYER);
+                }
+                break;
+        }
+    }
+    return(TRUE);
+}
+
+/*
+    new_thing()
+        return a new thing
+*/
+
+struct linked_list *
+new_thing(void)
+{
+    int j, k;
+    struct linked_list  *item;
+    struct object   *cur;
+    short   blesschance = srnd(100);
+    short   cursechance = srnd(100);
+
+    item = new_item(sizeof *cur);
+    cur = OBJPTR(item);
+    cur->o_hplus = cur->o_dplus = 0;
+    cur->o_damage = cur->o_hurldmg = "0d0";
+    cur->o_ac = 11;
+    cur->o_count = 1;
+    cur->o_group = 0;
+    cur->o_flags = 0;
+    cur->o_weight = 0;
+    cur->o_mark[0] = '\0';
+
+    /*
+     * Decide what kind of object it will be If we haven't had food for a
+     * while, let it be food.
+     */
+
+    switch (no_food > 3 ? TYP_FOOD : pick_one(things, numthings))
+    {
+        case TYP_POTION:
+            cur->o_type = POTION;
+            cur->o_which = pick_one(p_magic, maxpotions);
+            cur->o_weight = things[TYP_POTION].mi_wght;
+
+            if (cursechance < p_magic[cur->o_which].mi_curse)
+                cur->o_flags |= ISCURSED;
+            else if (blesschance < p_magic[cur->o_which].mi_bless)
+                cur->o_flags |= ISBLESSED;
+            break;
+
+        case TYP_SCROLL:
+            cur->o_type = SCROLL;
+            cur->o_which = pick_one(s_magic, maxscrolls);
+            cur->o_weight = things[TYP_SCROLL].mi_wght;
+
+            if (cursechance < s_magic[cur->o_which].mi_curse)
+                cur->o_flags |= ISCURSED;
+            else if (blesschance < s_magic[cur->o_which].mi_bless)
+                cur->o_flags |= ISBLESSED;
+            break;
+
+        case TYP_FOOD:
+            no_food = 0;
+            cur->o_type = FOOD;
+            cur->o_which = pick_one(fd_data, maxfoods);
+            cur->o_weight = 2;
+            cur->o_count += extras();
+            break;
+
+        case TYP_WEAPON:
+            cur->o_type = WEAPON;
+            cur->o_which = rnd(maxweapons);
+            init_weapon(cur, cur->o_which);
+
+            if (cursechance < 10)
+            {
+                short   bad = (rnd(10) < 1) ? 2 : 1;
+
+                cur->o_flags |= ISCURSED;
+                cur->o_hplus -= bad;
+                cur->o_dplus -= bad;
+            }
+            else if (blesschance < 15)
+            {
+                short   good = (rnd(10) < 1) ? 2 : 1;
+
+                cur->o_hplus += good;
+                cur->o_dplus += good;
+            }
+            break;
+
+        case TYP_ARMOR:
+            cur->o_type = ARMOR;
+
+            for (j = 0; j < maxarmors; j++)
+                if (blesschance < armors[j].a_prob)
+                    break;
+
+            if (j == maxarmors)
+            {
+                debug("Picked a bad armor %d", blesschance);
+                j = 0;
+            }
+
+            cur->o_which = j;
+            cur->o_ac = armors[j].a_class;
+
+            if (((k = rnd(100)) < 20) && j != MITHRIL)
+            {
+                cur->o_flags |= ISCURSED;
+                cur->o_ac += rnd(3) + 1;
+            }
+            else if (k < 28 || j == MITHRIL)
+                cur->o_ac -= rnd(3) + 1;
+
+            if (j == MITHRIL)
+                cur->o_flags |= ISPROT;
+
+            cur->o_weight = armors[j].a_wght;
+
+            break;
+
+        case TYP_RING:
+            cur->o_type = RING;
+            cur->o_which = pick_one(r_magic, maxrings);
+            cur->o_weight = things[TYP_RING].mi_wght;
+
+            if (cursechance < r_magic[cur->o_which].mi_curse)
+                cur->o_flags |= ISCURSED;
+            else if (blesschance < r_magic[cur->o_which].mi_bless)
+                cur->o_flags |= ISBLESSED;
+
+            switch (cur->o_which)
+            {
+                case R_ADDSTR:
+                case R_ADDWISDOM:
+                case R_ADDINTEL:
+                case R_PROTECT:
+                case R_ADDHIT:
+                case R_ADDDAM:
+                case R_CARRYING:
+                    cur->o_ac = rnd(2) + 1; /* From 1 to 3 */
+
+                    if (cur->o_flags & ISCURSED)
+                        cur->o_ac = -cur->o_ac;
+
+                    if (cur->o_flags & ISBLESSED)
+                        cur->o_ac++;
+
+                    break;
+
+                case R_RESURRECT:
+                case R_TELCONTROL:
+                case R_VREGEN:
+                case R_REGEN:
+                case R_PIETY:
+                case R_WIZARD:
+                    cur->o_ac = 0;
+
+                    if (cur->o_flags & ISCURSED)
+                        cur->o_ac = -1;
+
+                    if (cur->o_flags & ISBLESSED)
+                        cur->o_ac = 1;
+
+                    break;
+
+                case R_DIGEST:
+
+                    if (cur->o_flags & ISCURSED)
+                        cur->o_ac = -1;
+                    else if (cur->o_flags & ISBLESSED)
+                        cur->o_ac = 2;
+                    else
+                        cur->o_ac = 1;
+                    break;
+
+                default:
+                    cur->o_ac = 0;
+                    break;
+            }
+            break;
+
+        case TYP_STICK:
+            cur->o_type = STICK;
+            cur->o_which = pick_one(ws_magic, maxsticks);
+            fix_stick(cur);
+
+            if (cursechance < ws_magic[cur->o_which].mi_curse)
+                cur->o_flags |= ISCURSED;
+            else if (blesschance < ws_magic[cur->o_which].mi_bless)
+                cur->o_flags |= ISBLESSED;
+
+            break;
+
+        default:
+            debug("Picked a bad kind of object");
+            wait_for(' ');
+    }
+
+    return(item);
+}
+
+/*
+    spec_item()
+        provide a new item tailored to specification
+*/
+
+struct linked_list  *
+spec_item(char type, int which, int hitp, int damage)
+{
+    struct linked_list  *item;
+    struct object   *obj;
+
+    item = new_item(sizeof *obj);
+    obj = OBJPTR(item);
+
+    obj->o_count = 1;
+    obj->o_group = 0;
+    obj->o_type = type;
+    obj->o_which = which;
+    obj->o_damage = obj->o_hurldmg = "0d0";
+    obj->o_hplus = 0;
+    obj->o_dplus = 0;
+    obj->o_flags = 0;
+    obj->o_mark[0] = '\0';
+    obj->o_text = NULL;
+    obj->o_launch = 0;
+    obj->o_weight = 0;
+
+    switch(type)       /* Handle special characteristics */
+    {
+        case WEAPON:
+            init_weapon(obj, which);
+            obj->o_hplus = hitp;
+            obj->o_dplus = damage;
+            obj->o_ac = 10;
+            break;
+
+        case ARMOR:
+            obj->o_ac = armors[which].a_class - hitp;
+            break;
+
+        case RING:
+            obj->o_ac = hitp;
+            break;
+
+        case STICK:
+            fix_stick(obj);
+            obj->o_charges = hitp;
+            break;
+
+        case GOLD:
+            obj->o_type = GOLD;
+            obj->o_count = GOLDCALC;
+            obj->o_ac = 11;
+            break;
+    }
+
+    if (hitp > 0 || damage > 0)
+        obj->o_flags |= ISBLESSED;
+    else if (hitp < 0 || damage < 0)
+        obj->o_flags |= ISCURSED;
+
+    return(item);
+}
+
+/*
+    pick_one()
+        pick an item out of a list of nitems possible magic items
+*/
+
+int
+pick_one(struct magic_item *magic, int nitems)
+{
+    int i;
+    struct magic_item   *end;
+    struct magic_item   *start = magic;
+
+    for (end = &magic[nitems], i = rnd(1000); magic < end; magic++)
+        if (i <= magic->mi_prob)
+            break;
+
+    if (magic == end)
+    {
+        if (wizard)
+        {
+            add_line("Bad pick_one: %d from %d items", i, nitems);
+
+            for (magic = start; magic < end; magic++)
+                add_line("%s: %d%%", magic->mi_name, magic->mi_prob);
+
+            end_line();
+        }
+        magic = start;
+    }
+
+    return((int)(magic - start));
+}
+
+
+/*
+    blesscurse()
+        returns whether the object is  blessed or cursed
+*/
+
+char *
+blesscurse(long flags)
+{
+    if (flags & ISKNOW)
+    {
+        if (flags & ISCURSED)
+            return("cursed ");
+
+        if (flags & ISBLESSED)
+            return("blessed ");
+
+        return("normal ");
+    }
+
+    return("");
+}
+
+/*
+    extras()
+        Return the number of extra food items to be created
+*/
+
+int
+extras(void)
+{
+    int i = rnd(100);
+
+    if (i < 10)
+        return(2);
+    else if (i < 20)
+        return(1);
+    else
+        return(0);
+}
+
+/*
+    name_type()
+        Returns a string identifying a pack item's type
+*/
+
+char *
+name_type(int type)
+{
+    switch(type)
+    {
+        case ARMOR:
+            return ("armor");
+
+        case WEAPON:
+            return ("weapons");
+
+        case SCROLL:
+            return ("scrolls");
+
+        case RING:
+            return ("rings");
+
+        case STICK:
+            return ("staffs");
+
+        case POTION:
+            return ("potions");
+
+        case FOOD:
+            return ("food");
+
+        case GOLD:
+            return ("gold");
+
+        default:
+            return ("items");
+    }
+}
+
+/*
+    make_item()
+        adds a linked_list structure to the top of an object for interfacing
+        with other routines
+*/
+
+linked_list *
+make_item(object *obj_p)
+{
+    linked_list *item_p = new_list();
+
+    item_p->l_next = item_p->l_prev = NULL;
+
+    item_p->data.obj = obj_p;
+
+    return(item_p);
+}
+
+/*
+    is_member()
+        Checks to see if a character is a member of an array
+*/
+
+int
+is_member(char *list_p, int member)
+{
+    while (*list_p != 0)
+    {
+        if (*list_p++ == member)
+            return(TRUE);
+    }
+
+    return(FALSE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/trader.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,808 @@
+/*
+    trader.c - Anything to do with trading posts
+     
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "rogue.h"
+
+#define EFFECTIVE_PURSE ((player.t_ctype==C_PALADIN)?(9 * purse / 10) : purse)
+
+/*
+    do_post()
+        Buy and sell things in a trading post
+*/
+
+void
+display_postinfo(void)
+{
+    wclear(hw);
+    wstandout(hw);
+    mvwaddstr(hw, 0, COLS / 2 - 30,
+        "Welcome to Friendly Fiend's Flea Market" );
+    wstandend(hw);
+    wclrtoeol(hw);
+    trans_line();   
+}
+
+void
+do_post(void)
+{
+    int bad_letter = FALSE;
+
+    player.t_trans = 0;
+
+    for (;;)
+    {
+        if (!open_market())
+            return;
+
+        display_postinfo();
+
+        if (bad_letter)
+        {
+            bad_letter = FALSE;
+            wstandout(hw);
+            mvwaddstr(hw, 7, 0, "Type 'i' or 'I' to inventory, "
+                                "'l' to leave, 'b' to buy, or 's' to sell");
+            wstandend(hw);
+        }
+
+        mvwaddstr(hw, 6, 0, "Do you wish to buy, sell, inventory, or leave?");
+        wrefresh(hw);
+
+        switch(readcharw(hw))
+        {
+            case 'b':
+                mvwaddstr(hw, 7, 0,
+                    "Lets go into the buying section of the store...");
+                touchwin(hw);
+                wrefresh(hw);
+                buy_it('\0', ISNORMAL);
+                break;
+
+            case 's':
+                mvwaddstr(hw, 7, 0,
+                    "Lets go into the selling section of the store...");
+                touchwin(hw);
+                wrefresh(hw);
+                sell_it();
+                break;
+
+            case 'i':
+                inventory(pack, '*');
+                break;
+
+            case 'I':
+                wclear(hw);
+                wrefresh(hw);
+                inventory(pack, 0);
+                msg(" ");
+                msg("");
+                break;
+
+            case 'l':
+                wclear(hw);
+                wrefresh(hw);
+                return;
+
+            default:
+                bad_letter = TRUE;
+                break;
+        }
+    }
+}
+
+void
+buy_it(char itemtype, int flags)
+{
+    int i;
+    int blessed = flags & ISBLESSED;
+    int cursed = flags & ISCURSED;
+    int is_spell = flags & SCR_MAGIC;
+    int array_size; /* # of items within type */
+    int which_type = 0; /* Which type to buy */
+    int which_one;  /* Which one within type */
+    int plus_or_minus = 0;  /* for magic items */
+    const struct magic_item   *magic_array = NULL;
+    struct linked_list  *item;
+    struct object *obj;
+    char buf[2 * LINELEN];
+
+buy_more:
+
+    display_postinfo();
+
+    do
+    {
+        array_size = 0;
+
+        if (itemtype == '\0')
+        {
+            mpos = 0;
+	    wmove(hw,10,0);
+	    wclrtoeol(hw);
+            mvwaddstr(hw, 11, 0, "WHAT\tTYPE\n! Potion\n? Scroll\n"
+                                 "= Ring\n/ Stick\n] Armor\n) Weapon\n: Food");
+
+            if (wizard)
+                mvwaddstr(hw, 19, 0, ", Artifact");
+
+            mvwaddstr(hw, 9, 0, "What type of item do you want? ");
+            wclrtoeol(hw);
+            touchwin(hw);
+            wrefresh(hw);
+            itemtype = readcharw(hw);
+        }
+
+        switch(itemtype)
+        {
+            case POTION:
+                which_type = TYP_POTION;
+                array_size = maxpotions;
+                magic_array = p_magic;
+                break;
+
+            case SCROLL:
+                which_type = TYP_SCROLL;
+                array_size = maxscrolls;
+                magic_array = s_magic;
+                break;
+
+            case FOOD:
+                which_type = TYP_FOOD;
+                array_size = maxfoods;
+                magic_array = fd_data;
+                break;
+
+            case WEAPON:
+                which_type = TYP_WEAPON;
+                array_size = maxweapons;
+                break;
+
+            case ARMOR:
+                which_type = TYP_ARMOR;
+                array_size = maxarmors;
+                break;
+
+            case RING:
+                which_type = TYP_RING;
+                array_size = maxrings;
+                magic_array = r_magic;
+                break;
+
+            case STICK:
+                which_type = TYP_STICK;
+                array_size = maxsticks;
+                magic_array = ws_magic;
+                break;
+
+            case ARTIFACT:
+                if (!wizard)
+                {
+                    itemtype = '\0';
+                    continue;
+                }
+
+                which_type = TYP_ARTIFACT;
+                array_size = maxartifact;
+                break;
+
+            case ESCAPE:
+                return;
+
+            default:
+                wstandout(hw);
+                mvwaddstr(hw, 10, 0, "We don't stock any of those.");
+                wstandend(hw);
+                itemtype = '\0';
+                continue;
+        }
+    }
+    while (array_size == 0);
+
+    which_one = array_size;
+
+    do
+    {
+        const struct magic_item   *m_item;
+
+        display_postinfo();
+
+        mpos = 0;
+        sprintf(buf, "Which kind of %s do you wish to have (* for list)? ",
+            things[which_type].mi_name);
+
+        mvwaddstr(hw, 9, 0, buf);
+        
+        touchwin(hw);
+        wrefresh(hw);
+        buf[0] = '\0';
+
+        switch (get_string(buf, hw))
+        {
+            case QUIT:
+            case ESCAPE:
+                itemtype = '\0';
+                goto buy_more;
+        }
+
+        if (buf[0] == '*')      /* print list */
+        {
+            add_line(" ID  BASECOST NAME");
+
+            switch (which_type)
+            {
+                case TYP_RING:
+                case TYP_POTION:
+                case TYP_STICK:
+                case TYP_SCROLL:
+                case TYP_FOOD:
+
+                    for(i=0,m_item=magic_array; i < array_size; i++, m_item++)
+                        if (!is_spell && m_item->mi_worth > 0)
+                        {
+                            sprintf(buf, "%3d) %8d %s", i, m_item->mi_worth,
+                                m_item->mi_name);
+                            add_line(buf);
+                        }
+                    break;
+
+                case TYP_ARMOR:
+                    for (i = 0; i < array_size; i++)
+                        if (!is_spell && armors[i].a_worth > 0)
+                        {
+                            sprintf(buf, "%3d) %8d %s", i, armors[i].a_worth,
+                                armors[i].a_name);
+
+                            add_line(buf);
+                        }
+                    break;
+
+                case TYP_WEAPON:
+                    for (i = 0; i < array_size; i++)
+                        if (!is_spell && weaps[i].w_worth > 0)
+                        {
+                            sprintf(buf, "%3d) %8d %s", i, weaps[i].w_worth,
+                                weaps[i].w_name);
+                            add_line(buf);
+                        }
+                    break;
+
+                case TYP_ARTIFACT:
+                    for (i = 0; i < array_size; i++)
+                    {
+                        sprintf(buf, "%3d) %8d %s", i, arts[i].ar_worth,
+                            arts[i].ar_name);
+                        add_line(buf);
+                    }
+                    break;
+
+                default:
+                    add_line("What a strange type.");
+            }
+
+            end_line();
+            touchwin(hw);
+            wrefresh(hw);
+            continue;
+        }
+
+        if (isdigit(buf[0]))
+            which_one = atoi(buf);
+        else
+            switch (which_type)
+            {
+                case TYP_RING:
+                case TYP_POTION:
+                case TYP_STICK:
+                case TYP_SCROLL:
+                case TYP_FOOD:
+                    for (i=0,m_item=magic_array; i < array_size; i++, m_item++)
+                        if (strcmp(buf, m_item->mi_name) == 0)
+                            which_one = i;
+                    break;
+
+                case TYP_ARMOR:
+                    for (i = 0; i < array_size; i++)
+                        if (strcmp(buf, armors[i].a_name) == 0)
+                            which_one = i;
+                    break;
+
+                case TYP_WEAPON:
+                    for (i = 0; i < array_size; i++)
+                        if (strcmp(buf, weaps[i].w_name) == 0)
+                            which_one = i;
+                    break;
+
+                case TYP_ARTIFACT:
+                    for (i = 0; i < array_size; i++)
+                        if (strcmp(buf, arts[i].ar_name) == 0)
+                            which_one = i;
+                    break;
+
+                default:
+                    msg("What a strange type.");
+            }
+
+        if (which_one < 0 || which_one >= array_size)
+        {
+            wstandout(hw);
+            mvwaddstr(hw, 10, 0, "Type the name or an ID number.");
+            wstandend(hw);
+        }
+    }
+    while (which_one < 0 || which_one >= array_size);
+
+    item = new_item(sizeof *obj);
+    obj = OBJPTR(item);
+
+    if (which_type == TYP_ARTIFACT)
+    {
+        new_artifact(which_one, obj);
+        add_pack(item, NOMESSAGE);
+        itemtype = '\0';
+        goto buy_more;
+    }
+
+    obj->o_type = itemtype;
+    obj->o_which = which_one;
+    obj->o_mark[0] = '\0';
+    obj->o_group = 0;
+    obj->o_count = 1;
+    obj->o_weight = 0;
+    obj->o_dplus = obj->o_hplus = 0;
+    obj->o_worth = 0;
+
+    if (!is_spell)
+    {
+        plus_or_minus = -100;
+
+        do
+        {
+            mvwaddstr(hw, 10, 0, "Do you want the cursed, blessed, or normal"
+                                 " version? (c, b, n) [n]");
+            touchwin(hw);
+            wrefresh(hw);
+
+	    blessed = cursed = FALSE;
+            switch (readcharw(hw))
+            {
+                case ESCAPE:
+                    discard(item);
+                    itemtype = '\0';
+                    goto buy_more;
+
+                case 'c':
+                    cursed = TRUE;
+                    plus_or_minus = 0;
+                    break;
+
+                case 'b':
+                    blessed = TRUE;
+                    plus_or_minus = 0;
+                    break;
+
+                case 'n':
+                case ' ':
+                    plus_or_minus = 0;
+                    break;
+
+                default:
+                    wstandout(hw);
+                    mvwaddstr(hw,11,0,"Type 'c' for cursed, 'b' for blessed, "
+                                      "or 'n' for normal");
+                    wstandend(hw);
+            }
+        }
+        while (plus_or_minus == -100);
+    }
+
+    /* else used blessed, cursed from flags parameter */
+
+    if (which_type == TYP_WEAPON)
+        init_weapon(obj, which_one);
+
+    obj->o_flags |= ISKNOW;
+
+    if (cursed)
+    {
+        plus_or_minus = -(rnd(2) + 1);
+        obj->o_flags |= ISCURSED;
+    }
+    else if (blessed)
+    {
+        plus_or_minus = (rnd(3) + 1);
+        obj->o_flags |= ISBLESSED;
+    }
+    else
+    {
+        plus_or_minus = 0;
+        obj->o_flags |= ISNORMAL;
+    }
+
+    switch (which_type)
+    {
+        case TYP_WEAPON:
+            obj->o_hplus += plus_or_minus;
+            obj->o_dplus += plus_or_minus;
+            break;
+
+        case TYP_ARMOR:
+            obj->o_weight = armors[which_one].a_wght;
+            obj->o_ac = armors[which_one].a_class - plus_or_minus;
+            break;
+
+        case TYP_STICK:
+            fix_stick(obj);
+            break;
+
+        case TYP_RING:
+            obj->o_ac = plus_or_minus;
+            break;
+
+        case TYP_SCROLL:
+        case TYP_POTION:
+            obj->o_weight = things[which_type].mi_wght;
+            break;
+
+        case TYP_FOOD:
+		    break;
+			
+        default:
+            msg("That's a strange thing to try to own.");
+			discard(item);
+            itemtype = '\0';
+            goto buy_more;
+    }
+
+    obj->o_worth = get_worth(obj) * (luck + level / 15 + 1);
+    describe_it(obj);
+
+    if (!wizard && obj->o_worth > EFFECTIVE_PURSE)
+    {
+        wstandout(hw);
+        mvwaddstr(hw, 12, 0, "Unfortunately, you can't afford it.");
+        wstandend(hw);
+        wclrtoeol(hw);
+        touchwin(hw);
+	wrefresh(hw);
+		wait_for(' ');
+		discard(item);
+        itemtype = '\0';
+        goto buy_more;
+    }
+
+    mvwaddstr(hw, 12, 0, "Do you want it? [y] ");
+    wclrtoeol(hw);
+    touchwin(hw);
+    wrefresh(hw);
+
+    switch (readcharw(hw))
+    {
+        case ESCAPE:
+        case 'n':
+            msg("");
+			discard(item);
+            itemtype = '\0';
+            goto buy_more;
+    }
+
+    /* The hero bought the item here */
+
+    mpos = 0;
+
+    if (add_pack(item, NOMESSAGE) && !is_spell)
+    {
+	    if (!wizard)
+		{
+		    purse -= obj->o_worth; /* take his money */
+            ++player.t_trans;
+		}
+		
+        trans_line();   /* show remaining deals */
+
+        switch(which_type)
+        {
+            case TYP_RING:
+            case TYP_STICK:
+            case TYP_SCROLL:
+            case TYP_POTION:
+                know_items[which_type][which_one] = TRUE;
+        }
+    }
+}
+
+/*
+    sell_it()
+        Sell an item to the trading post
+*/
+
+void
+sell_it(void)
+{
+    struct object *obj;
+    struct linked_list  *item;
+    char buf[2 * LINELEN];
+
+    wclear(cw);
+
+    if ((item = get_item("sell", 0)) == NULL)
+        return;
+
+    obj = OBJPTR(item);
+    msg("");
+    display_postinfo();
+    touchwin(hw);
+    wrefresh(hw);
+
+    if ((obj->o_type == ARTIFACT) || (obj->o_worth = get_worth(obj)) == 0)
+    {
+        mpos = 0;
+        msg("We don't buy those.");
+
+        if (is_wearing(R_ADORNMENT) && rnd(10) < 4)
+            msg("How about that %s ring instead?", r_stones[R_ADORNMENT]);
+
+        return;
+    }
+
+    describe_it(obj);
+    mvwaddstr(hw, 12, 0, "Do you want to sell it? [n] ");
+    touchwin(hw);
+    wrefresh(hw);
+
+    switch( readcharw(hw) )
+    {
+        case 'y':
+            break;
+        default:
+            msg("");
+            if (is_wearing(R_ADORNMENT))
+                msg("How about that %s ring instead?",
+                    r_stones[R_ADORNMENT]);
+            return;
+    }
+
+    rem_pack(obj);
+    purse += obj->o_worth; /* give him his money */
+    ++player.t_trans;
+
+    sprintf(buf, "Sold %s.  Hit space to continue.",
+        inv_name(obj, LOWERCASE));
+    discard(item);
+
+    mvwaddstr(hw, 13, 0, buf);
+    touchwin(hw);
+    wrefresh(hw);
+    wait_for(' ');
+}
+
+/*
+    describe_it()
+        Laud or condemn the object
+*/
+
+extern char *inv_name();
+
+void
+describe_it(struct object *obj)
+{
+    static char *cursed_d[] =
+    {
+        "worthless hunk of junk",
+        "shoddy piece of trash",
+        "piece of rusty garbage",
+        "example of terrible workmanship",
+        "cheap hack"
+    };
+
+    static char *normal_d[] =
+    {
+        "journeyman's piece",
+        "fine deal",
+        "great bargain",
+        "good find",
+        "real value",
+        "piece of honest workmanship",
+        "steal",
+        "purchase worth making",
+        "inexpensive product"
+    };
+
+    static char *blessed_d[] =
+    {
+        "magnificant masterpiece",
+        "quality product",
+        "exceptional find",
+        "unbeatable value",
+        "rare beauty",
+        "superior product",
+        "well-crafted item"
+    };
+
+    char    *charp;
+    char    buf[2 * LINELEN];
+
+    if (obj->o_flags & ISBLESSED)
+        charp = blessed_d[rnd(sizeof(blessed_d) / sizeof(char *))];
+    else if (obj->o_flags & ISCURSED)
+        charp = cursed_d[rnd(sizeof(cursed_d) / sizeof(char *))];
+    else
+        charp = normal_d[rnd(sizeof(normal_d) / sizeof(char *))];
+
+    sprintf(buf, "It's a%s %s worth %d pieces of gold.",
+        vowelstr(charp), charp, obj->o_worth);
+
+    mvwaddstr(hw, 10, 0, inv_name(obj, TRUE));
+    mvwaddstr(hw, 11, 0, buf);
+    wclrtoeol(hw);
+}
+
+/*
+    open_market()
+        Retruns TRUE when ok do to transacting
+*/
+
+int
+open_market(void)
+{
+    int maxtrans = is_wearing(R_ADORNMENT) ? MAXPURCH + 4 : MAXPURCH;
+
+    if (wizard || player.t_trans < maxtrans || (level == 0))
+        return(TRUE);
+    else
+    {
+        msg("The market is closed. The stairs are that-a-way.");
+        return(FALSE);
+    }
+}
+
+/*
+    get_worth()
+        Calculate an objects worth in gold
+*/
+
+int
+get_worth(struct object *obj)
+{
+    long    worth = 0;
+    int wh = obj->o_which;
+    int blessed = obj->o_flags & ISBLESSED;
+    int cursed = obj->o_flags & ISCURSED;
+
+    switch (obj->o_type)
+    {
+        case FOOD:
+            if (wh < maxfoods)
+            {
+                worth = obj->o_count * fd_data[wh].mi_worth;
+                if (blessed)
+                    worth *= 2;
+            }
+            break;
+
+        case WEAPON:
+            if (wh < maxweapons)
+            {
+                worth = weaps[wh].w_worth;
+                worth *= obj->o_count * (2 +
+                        (4 * obj->o_hplus +
+                        4 * obj->o_dplus));
+
+                if (obj->o_flags & ISSILVER)
+                    worth *= 2;
+
+                if (obj->o_flags & ISPOISON)
+                    worth *= 2;
+
+                if (obj->o_flags & ISZAPPED)
+                    worth += 20 * obj->o_charges;
+            }
+            break;
+
+        case ARMOR:
+            if (wh < maxarmors)
+            {
+                int plusses = armors[wh].a_class - obj->o_ac;
+
+                worth = armors[wh].a_worth;
+
+                if (plusses > 0)
+                    worth *= (1 + (10 *
+                        (armors[wh].a_class - obj->o_ac)));
+            }
+            break;
+
+        case SCROLL:
+            if (wh < maxscrolls)
+                worth = s_magic[wh].mi_worth;
+            break;
+
+        case POTION:
+            if (wh < maxpotions)
+                worth = p_magic[wh].mi_worth;
+            break;
+
+        case RING:
+            if (wh < maxrings)
+            {
+                worth = r_magic[wh].mi_worth;
+                worth += obj->o_ac * 40;
+            }
+            break;
+
+        case  STICK:
+            if (wh < maxsticks)
+            {
+                worth = ws_magic[wh].mi_worth;
+                worth += 20 * obj->o_charges;
+            }
+            break;
+
+        case ARTIFACT:
+            if (wh < maxartifact)
+                worth = arts[wh].ar_worth;
+            break;
+
+        default:
+            worth = 0;
+    }
+
+    if (obj->o_flags & ISPROT)  /* 300% more for protected */
+        worth *= 3;
+
+    if (blessed)        /* 250% more for blessed */
+        worth = 5 * worth / 2;
+    else if (cursed)    /* half for cursed */
+        worth /= 2;
+
+    if (obj->o_flags & (CANRETURN | ISOWNED))
+        worth *= 4;
+    else if (obj->o_flags & CANRETURN)
+        worth *= 2;
+    else if (obj->o_flags & ISLOST)
+        worth /= 3;
+
+    return(max(0, worth)); /* anything is worth at least one gold piece */
+}
+
+/*
+    trans_line()
+        Show how many transactions the hero has left
+*/
+
+void
+trans_line(void)
+{
+    char buf[2 * LINELEN];
+    int adorned = is_wearing(R_ADORNMENT);
+
+    if (level == 0 && purse > 0)
+        sprintf(buf, "You still have %d pieces of gold left.", purse);
+    else if (purse == 0)
+        sprintf(buf, "You have no money left.");
+    else if (!wizard)
+        sprintf(buf, "You have %d transactions and %d gold pieces remaining.",
+            max(0, (adorned ? MAXPURCH + 4 : MAXPURCH) - player.t_trans),
+            EFFECTIVE_PURSE);
+    else
+        sprintf(buf, "You have infinite transactions remaining.");
+
+    mvwaddstr(hw, LINES - 2, 0, buf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/urogue.6	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,288 @@
+.\"
+.\" Last Modified: 06/16/86
+.\"
+.TH UROGUE 6 "1.03 Draft"
+.SH NAME
+urogue \- UltraRogue \- Exploring the dungeons of doom.
+.SH SYNTAX
+.B urogue
+[
+.I save-file
+]
+[
+.B \-k
+]
+[
+.B \-s
+]
+[
+.B \-n
+]
+[
+.B \-v
+]
+[
+.B \-r
+]
+.SH DESCRIPTION
+.PP
+.I UltraRogue
+is a advanced version of one of the more standard rogue games.
+It is much more difficult and interesting to play than the
+original version on which it is based (Advanced Rogue 2.0).
+Some of it's unique features include 10 player character classes,
+several hundred monsters, charmable monsters, etc.
+.PP
+To win the game
+you must locate 8 artifacts which start appearing from level 25
+down.  You must then bring all artifacts back up out of the dungeon.
+These artifacts also may be 
+.I applied
+to use some of their great powers!  Be warned, though, sometimes these
+powers back-fire on you.
+.SH ENVIRONMENT
+The environment variable 
+.B $UROGUE
+(the person installing 
+.I UltraRogue
+may have changed this for your site)
+is checked to set certain default options for 
+.I UltraRogue.
+The following may be set in the 
+.B $UROGUE:
+.IP "\fBterse\fR (\fIboolean\fR)"
+Short output messages.
+.IP "\fBflush\fR (\fIboolean\fR)"
+Flush typeahead when fighting.
+.IP "\fBjump\fR (\fIboolean\fR)"
+Show position only at the end of running.
+.IP "\fBinven\fR (\fIstring\fR)"
+Inventory style.
+.IP "\fBaskme\fR (\fIboolean\fR)"
+Ask about unidentified things.
+.IP "\fBstopdoor\fR (\fIboolean\fR)"
+Stop running when next to something interesting.
+.IP "\fBname\fR (\fIstring\fR)"
+The rogue's name.
+.IP "\fBfruit\fR (\fIstring\fR)"
+The funny fruit used by the rogue.
+.IP "\fBfile\fR (\fIstring\fR)"
+Default savefile name.
+.IP "\fBscore\fR (\fIstring\fR)"
+Default scorefile name.
+.IP "\fBclass\fR (\fIstring\fR)"
+Default player class.
+.sp
+.PP
+Something like
+.nf
+.sp
+.in +.5in
+setenv UROGUE "name=VAX Killer,fruit=Peach,noterse,jump"
+.in -.5in
+.sp
+.fi
+does the obvious.  The ``score'' option is ignored unless you start
+urogue in wizard mode.  The class option string can have the following
+values: ``fighter'', ``illus'', ``paladin'', ``ranger'', ``cleric'', ``magic'',
+``assasin'', ``druid'', ``ninja'', and ``thief'' and is initialized only at
+startup time.  The ``inven'' option can take the values ``slow'', ``clear'',
+and ``overwrite''.
+.PP
+You may change most of these values while playing with the 
+.B ``o''
+command.
+.SH OPTIONS
+.PP
+If a
+.I save_file
+is specified,
+urogue will be restored from the specified saved game file.
+If the save file is named ``-r'', the default saved game file of
+.I ~/rogue.save
+is restored.
+The other options are:
+.IP \-k
+Place the terminal's kaypad into 
+.I auxilary
+or
+.I applications
+mode.  Once this is done, the keypad may be used for movement instead
+of the normal letter movement keys.  
+The directions are ``1'' move left and down, ``2'' move down, ``3'' move 
+right and down, ``6'' move right, ``9'' move right and up, ``8'' move up,
+``7'' move up, and ``4'' move left.  If the user hits the <RUN> key
+(key ``5'') and then a direction, then the rogue will run in the specified
+direction.
+When the game ends the keypad is restored
+to normal
+.I numeric
+mode if \-k was specified.  The user may also place the keypad into 
+.I auxilary
+or
+.I applications
+mode manually and then may use the keypad without specifing the
+\-k option.
+.IP \-s
+Display the list of scores.
+.IP \-n
+Display the urogue news file.  
+This is a file containing information on currently known bugs,
+changes, fixes, and enhancements to look for from the last version.
+.IP \-v
+Display the urogue version information.
+.SH COMMANDS
+The following is a list of commands for 
+.I UltraRogue.
+You may see a similiar list during a 
+.I UltraRogue
+game by using the 
+.B ``?'' 
+command.
+A 
+.I <direction>
+is one of 
+\fB``h'', ``j'', ``k'', ``l'', ``y'', ``u'', ``b'', \fRor\fB 
+``n''.\fR
+.IP \fB?\fR
+Print out a list of commands.
+.IP \fB/\fR
+Identify objects.
+.IP \fBh\fR
+Move left.
+.IP \fBj\fR
+Move down.
+.IP \fBk\fR
+Move up.
+.IP \fBl\fR
+Move right.
+.IP \fBy\fR
+Move up and left.
+.IP \fBu\fR
+Move up and right.
+.IP \fBb\fR
+Move down and left.
+.IP \fBn\fR
+Move down and right.
+.IP \fB<SHIFT><direction>\fR
+Run in 
+.I <direction>.
+.IP \fBm<direction>\fR
+Move in 
+.I <direction>
+without picking anything up.
+.IP \fBt<direction>\fR
+Throw something in 
+.I <direction>.
+.IP \fBz<direction>\fR
+Zap a wand or staff in 
+.I <direction>.
+.IP \fB>\fR
+Go down a staircase.
+.IP \fB<\fR
+Go up a staircase.
+You must possess at least one Artifact to go up a staircase.
+.IP \fBs\fR
+Search for a trap/secrect door.
+.IP \fB.\fR
+Rest (do nothing) for one turn.
+.IP \fBi\fR
+General inventory.
+.IP \fBI\fR
+Inventory a single item.
+.IP \fBq\fR
+Quaff a potion.
+.IP \fBr\fR
+Read paper.
+.IP \fBe\fR
+Eat one ration of food.
+.IP \fBw\fR
+Wield a weapon.
+.IP \fBW\fR
+Wear armor.
+.IP \fBT\fR
+Take armor off.
+.IP \fBP\fR
+Put on a ring.
+.IP \fBR\fR
+Remove a ring.
+.IP \fBA\fR
+Apply an Artifact.
+.IP \fBd\fR
+Drop an object.
+.IP \fBc\fR
+Call object (generic).
+.IP \fBM\fR
+Mark object (specific).
+.IP \fBo\fR
+Examine/set options.
+.IP \fBC\fR
+Cast a spell/say a prayer.
+.IP \fBp\fR
+Pray to a deity.
+.IP \fBa\fR
+Affect the undead.
+.IP \fB^\fR
+Set a trap.
+.IP \fBD\fR
+Dip something in a pool.
+.IP \fB^T\fR
+Take (steal) from 
+.I <direction>.
+.IP \fB^R\fR
+Redraw screen.
+.IP \fB^P\fR
+Print last message.
+May go up to the last 10 messages.
+.IP \fB<ESCAPE>\fR
+Cancel current command.
+.IP \fBv\fR
+Print 
+.I UltraRogue
+version information.
+.IP \fB!\fR
+Create a shell.  Uses $SHELL if present in your environment.
+.IP \fBS\fR
+Save the current game.
+.IP \fBQ\fR
+Quit the current game.
+.IP \fB=\fR
+Listen for monsters.
+.IP \fBf<direction>\fR
+Fight monster in 
+.I <direction>.
+.IP \fBF<direction>\fR
+Fight monster to death in 
+.I <direction>.
+.IP \fB#\fR
+Buy the object the rogue is standing on.
+Used when in Friendly Fiend's Flea Market.
+.IP \fB$\fR
+Price the object the rogue is standing on.
+Used when in Friendly Fiend's Flea Market.
+.IP \fB%\fR
+Sell an object from the rogue's pack.
+Used when in Friendly Fiend's Flea Market.
+.SH FILES
+.DT
+.ta \w'/usr/games/lib/urogue/scorefile\ \ \ 'u
+/usr/games/lib/urogue/scorefile	\- Score file
+.br
+.ta \w'/usr/games/lib/urogue/motd\ \ \ 'u
+/usr/games/lib/urogue/motd	\- Message of the day
+.br
+.ta \w'/usr/games/lib/urogue/news\ \ \ 'u
+/usr/games/lib/urogue/news	\- News file
+.br
+\fB~\fP/rogue.save	\- Default save file
+.ST
+.SH SEE ALSO
+rogue(6),
+.br
+.I "A Guide to the Dungeons of Doom."
+.SH COPYRIGHT
+UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+.br
+Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+.br
+All rights reserved.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/urogue.sln	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual C++ Express 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "urogue", "urogue.vcproj", "{A428D711-A9BE-4A4E-9013-3AC25A18502D}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{A428D711-A9BE-4A4E-9013-3AC25A18502D}.Debug|Win32.ActiveCfg = Debug|Win32
+		{A428D711-A9BE-4A4E-9013-3AC25A18502D}.Debug|Win32.Build.0 = Debug|Win32
+		{A428D711-A9BE-4A4E-9013-3AC25A18502D}.Release|Win32.ActiveCfg = Release|Win32
+		{A428D711-A9BE-4A4E-9013-3AC25A18502D}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/urogue.vcproj	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,440 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="urogue"
+	ProjectGUID="{A428D711-A9BE-4A4E-9013-3AC25A18502D}"
+	RootNamespace="urogue"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				InlineFunctionExpansion="0"
+				AdditionalIncludeDirectories="../pdcurses"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;SCOREFILE;ALLSCORES"
+				StringPooling="true"
+				MinimalRebuild="true"
+				ExceptionHandling="0"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				BufferSecurityCheck="true"
+				EnableFunctionLevelLinking="true"
+				DisableLanguageExtensions="false"
+				ForceConformanceInForLoopScope="true"
+				UsePrecompiledHeader="0"
+				BrowseInformation="0"
+				WarningLevel="4"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+				CompileAs="1"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="Ws2_32.lib pdcurses.lib advapi32.lib shfolder.lib user32.lib"
+				OutputFile="$(OutDir)/rogue54.exe"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="../pdcurses"
+				IgnoreDefaultLibraryNames="LIBC.LIB"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/rogue54.pdb"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				InlineFunctionExpansion="1"
+				OmitFramePointers="true"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+				StringPooling="true"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="2"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="$(OutDir)/rogue54.exe"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
+			>
+			<File
+				RelativePath="armor.c"
+				>
+			</File>
+			<File
+				RelativePath=".\artifact.c"
+				>
+			</File>
+			<File
+				RelativePath=".\bag.c"
+				>
+			</File>
+			<File
+				RelativePath="chase.c"
+				>
+			</File>
+			<File
+				RelativePath="command.c"
+				>
+			</File>
+			<File
+				RelativePath="daemon.c"
+				>
+			</File>
+			<File
+				RelativePath="daemons.c"
+				>
+			</File>
+			<File
+				RelativePath=".\dict.c"
+				>
+			</File>
+			<File
+				RelativePath=".\dictutil.c"
+				>
+			</File>
+			<File
+				RelativePath=".\encumb.c"
+				>
+			</File>
+			<File
+				RelativePath="fight.c"
+				>
+			</File>
+			<File
+				RelativePath=".\getplay.c"
+				>
+			</File>
+			<File
+				RelativePath=".\ident.c"
+				>
+			</File>
+			<File
+				RelativePath="init.c"
+				>
+			</File>
+			<File
+				RelativePath="io.c"
+				>
+			</File>
+			<File
+				RelativePath="list.c"
+				>
+			</File>
+			<File
+				RelativePath=".\magic.c"
+				>
+			</File>
+			<File
+				RelativePath="main.c"
+				>
+			</File>
+			<File
+				RelativePath=".\maze.c"
+				>
+			</File>
+			<File
+				RelativePath=".\mdport.c"
+				>
+			</File>
+			<File
+				RelativePath=".\memory.c"
+				>
+			</File>
+			<File
+				RelativePath="misc.c"
+				>
+			</File>
+			<File
+				RelativePath=".\monsdata.c"
+				>
+			</File>
+			<File
+				RelativePath="monsters.c"
+				>
+			</File>
+			<File
+				RelativePath="move.c"
+				>
+			</File>
+			<File
+				RelativePath=".\newlvl.c"
+				>
+			</File>
+			<File
+				RelativePath="options.c"
+				>
+			</File>
+			<File
+				RelativePath="pack.c"
+				>
+			</File>
+			<File
+				RelativePath="passages.c"
+				>
+			</File>
+			<File
+				RelativePath=".\player.c"
+				>
+			</File>
+			<File
+				RelativePath="potions.c"
+				>
+			</File>
+			<File
+				RelativePath=".\random.c"
+				>
+			</File>
+			<File
+				RelativePath="rings.c"
+				>
+			</File>
+			<File
+				RelativePath="rip.c"
+				>
+			</File>
+			<File
+				RelativePath="rooms.c"
+				>
+			</File>
+			<File
+				RelativePath="save.c"
+				>
+			</File>
+			<File
+				RelativePath="scrolls.c"
+				>
+			</File>
+			<File
+				RelativePath="state.c"
+				>
+			</File>
+			<File
+				RelativePath=".\status.c"
+				>
+			</File>
+			<File
+				RelativePath="sticks.c"
+				>
+			</File>
+			<File
+				RelativePath="things.c"
+				>
+			</File>
+			<File
+				RelativePath=".\trader.c"
+				>
+			</File>
+			<File
+				RelativePath=".\verify.c"
+				>
+			</File>
+			<File
+				RelativePath="vers.c"
+				>
+			</File>
+			<File
+				RelativePath="weapons.c"
+				>
+			</File>
+			<File
+				RelativePath="wizard.c"
+				>
+			</File>
+			<File
+				RelativePath=".\xcrypt.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc"
+			>
+			<File
+				RelativePath=".\dict.h"
+				>
+			</File>
+			<File
+				RelativePath=".\dictutil.h"
+				>
+			</File>
+			<File
+				RelativePath=".\lint-curses.h"
+				>
+			</File>
+			<File
+				RelativePath="rogue.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+			>
+		</Filter>
+		<File
+			RelativePath=".\history.txt"
+			>
+		</File>
+		<File
+			RelativePath="LICENSE.TXT"
+			>
+		</File>
+		<File
+			RelativePath="Makefile"
+			>
+		</File>
+		<File
+			RelativePath=".\README"
+			>
+		</File>
+		<File
+			RelativePath=".\TODO"
+			>
+		</File>
+		<File
+			RelativePath=".\urogue.6"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/verify.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,19 @@
+/*
+    verify.c - exiting functions
+
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1995 Herb Chong
+    All rights reserved.
+*/
+
+static char sccsid[] = "%W% %G%";
+
+#include "rogue.h"
+
+void verify_function(const char *file, const int line)
+{
+	char s[80];
+
+	sprintf(s, "Verify failure in %s at line %d\n", file, line);
+	fatal(s);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/vers.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,21 @@
+/*
+    vers.c - version number
+         
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+const char *save_format = "UltraRogue Portable Save File Release 001\04";
+const char *version     = "UltraRogue 1.06a October 1995";
+const char *release     = "1.06 Alpha (October 1995)";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/weapons.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,556 @@
+/*
+    weapons.c - Functions for dealing with problems brought about by weapons
+         
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <ctype.h>
+#include <string.h>
+#include "rogue.h"
+
+/*
+    missile()
+        Fire a missile in a given direction
+*/
+
+void
+missile(int ydelta, int xdelta, struct linked_list *item, struct thing *tp)
+{
+    struct object   *obj;
+    struct linked_list  *nitem;
+
+    if (item == NULL)   /* Get which thing we are hurling */
+        return;
+
+    obj = OBJPTR(item);
+
+    if (!dropcheck(obj) || is_current(obj))
+        return;
+
+    /*
+     * Get rid of the thing. If it is a non-multiple item object, or if
+     * it is the last thing, just drop it. Otherwise, create a new item
+     * with a count of one.
+    */
+
+    if (obj->o_count < 2)
+    {
+        if (tp->t_pack == pack)
+            rem_pack(obj);
+        else
+            detach(tp->t_pack, item);
+    }
+    else
+    {
+        obj->o_count--;
+        nitem = (struct linked_list *) new_item(sizeof *obj);
+        obj = OBJPTR(nitem);
+        *obj = *(OBJPTR(item));
+        obj->o_count = 1;
+        item = nitem;
+    }
+
+    switch (obj->o_type)
+    {
+        case ARTIFACT:
+            has_artifact &= ~(1 << obj->o_which);
+            break;
+
+        case SCROLL:
+            if (obj->o_which == S_SCARE && obj->o_flags & ISBLESSED)
+                obj->o_flags &= ~ISBLESSED;
+            else
+                obj->o_flags |= ISCURSED;
+    }
+
+    updpack();
+    obj->o_pos = do_motion(obj->o_type, ydelta, xdelta, tp);
+
+    /*
+     * AHA! Here it has hit something. If it is a wall or a door, or if
+     * it misses (combat) the monster, put it on the floor
+     */
+
+    if (!hit_monster(obj->o_pos.y, obj->o_pos.x, obj, tp))
+    {
+        if (obj->o_type == WEAPON && obj->o_which == GRENADE)
+        {
+            hearmsg("BOOOM!");
+            aggravate();
+
+            if (ntraps + 1 < 2 * MAXTRAPS &&
+                fallpos(obj->o_pos, &traps[ntraps].tr_pos))
+            {
+                mvaddch(traps[ntraps].tr_pos.y, traps[ntraps].tr_pos.x,
+                    TRAPDOOR);
+                traps[ntraps].tr_type = TRAPDOOR;
+                traps[ntraps].tr_flags = ISFOUND;
+                traps[ntraps].tr_show = TRAPDOOR;
+                ntraps++;
+                light(&hero);
+            }
+            discard(item);
+        }
+        else if (obj->o_flags & ISLOST)
+        {
+            if (obj->o_type == WEAPON)
+                addmsg("The %s", weaps[obj->o_which].w_name);
+            else
+                addmsg(inv_name(obj, LOWERCASE));
+
+            msg(" vanishes in a puff of greasy smoke.");
+            discard(item);
+        }
+        else
+        {
+            fall(&player, item, TRUE, TRUE);
+
+            if (obj->o_flags & CANRETURN)
+                msg("You have %s.", inv_name(obj, LOWERCASE));
+        }
+    }
+    else if (obj->o_flags & ISOWNED)
+    {
+        add_pack(item, NOMESSAGE);
+        msg("You have %s.", inv_name(obj, LOWERCASE));
+    }
+
+    mvwaddch(cw, hero.y, hero.x, PLAYER);
+}
+
+/*
+    do_motion()
+        do the actual motion on the screen done by an object
+        traveling across the room
+*/
+
+coord
+do_motion(int ob, int ydelta, int xdelta, struct thing *tp)
+{
+    coord pos;
+    /* Come fly with us ... */
+
+    pos = tp->t_pos;
+
+    for (;;)
+    {
+        int ch;
+
+        /* Erase the old one */
+
+        if (!ce(pos, tp->t_pos) &&
+            cansee(pos.y, pos.x) &&
+            mvwinch(cw, pos.y, pos.x) != ' ')
+        {
+            mvwaddch(cw, pos.y, pos.x, show(pos.y, pos.x));
+        }
+
+        /* Get the new position */
+
+        pos.y += ydelta;
+        pos.x += xdelta;
+
+        if (shoot_ok(ch = winat(pos.y, pos.x)) &&
+            ch != DOOR && !ce(pos, hero))
+        {
+            /* It hasn't hit anything yet, so display it if it alright. */
+
+            if (cansee(pos.y, pos.x) &&
+                mvwinch(cw, pos.y, pos.x) != ' ')
+            {
+                mvwaddch(cw, pos.y, pos.x, ob);
+                wrefresh(cw);
+            }
+			
+            continue;
+
+        }
+        break;
+    }
+
+    return(pos);
+}
+
+/*
+    fall()
+        Drop an item someplace around here.
+*/
+
+void
+fall(struct thing *tp, struct linked_list *item, int pr, int player_owned)
+{
+    struct object *obj;
+    struct room   *rp;
+    coord   fpos;
+
+    obj = OBJPTR(item);
+    rp = roomin(tp->t_pos);
+
+    if (player_owned && obj->o_flags & CANRETURN)
+    {
+        add_pack(item, NOMESSAGE);
+        msg("You have %s.", inv_name(obj, LOWERCASE));
+        return;
+    }
+    else if (fallpos(obj->o_pos, &fpos))
+    {
+        if (obj->o_flags & CANBURN && obj->o_type == WEAPON
+            && obj->o_which == MOLOTOV
+            && ntraps + 1 < 2 * MAXTRAPS)
+        {
+            mvaddch(fpos.y, fpos.x, FIRETRAP);
+            traps[ntraps].tr_type  = FIRETRAP;
+            traps[ntraps].tr_flags = ISFOUND;
+            traps[ntraps].tr_show  = FIRETRAP;
+            traps[ntraps].tr_pos   = fpos;
+            ntraps++;
+
+            if (rp != NULL)
+                rp->r_flags &= ~ISDARK;
+        }
+        else
+        {
+            obj->o_pos = fpos;
+            add_obj(item, fpos.y, fpos.x);
+        }
+
+        if (rp != NULL &&
+            (!(rp->r_flags & ISDARK) ||
+             (rp->r_flags & HASFIRE)))
+        {
+            light(&hero);
+            mvwaddch(cw, hero.y, hero.x, PLAYER);
+        }
+        return;
+    }
+
+    /* get here only if there isn't a place to put it */
+	
+    if (pr)
+    {
+        if (cansee(obj->o_pos.y, obj->o_pos.x))
+        {
+            if (obj->o_type == WEAPON)
+                addmsg("The %s", weaps[obj->o_which].w_name);
+            else
+                addmsg(inv_name(obj, LOWERCASE));
+
+            msg(" vanishes as it hits the ground.");
+        }
+    }
+    discard(item);
+}
+
+/*
+    init_weapon()
+        Set up the initial goodies for a weapon
+*/
+
+void
+init_weapon(struct object *weap, int type)
+{
+    struct init_weps *iwp = &weaps[type];
+
+    weap->o_damage  = iwp->w_dam;
+    weap->o_hurldmg = iwp->w_hrl;
+    weap->o_launch  = iwp->w_launch;
+    weap->o_flags   = iwp->w_flags;
+    weap->o_weight  = iwp->w_wght;
+
+    if (weap->o_flags & ISMANY)
+    {
+        weap->o_count = rnd(8) + 8; 
+        weap->o_group = ++group;
+    }
+    else
+        weap->o_count = 1;
+}
+
+/*
+    hit_monster()
+        does the missile hit the target?
+*/
+
+int
+hit_monster(int y, int x, struct object *weapon, struct thing *thrower)
+{
+    struct linked_list *mon;
+    coord target;
+
+    target.y = y;
+    target.x = x;
+
+    if (thrower == &player)
+        return(fight(&target, weapon, THROWN));
+
+    if (ce(target, hero))
+    {
+        if (good_monster(*thrower))
+        {
+            if (on(*thrower, ISFAMILIAR))
+                msg("Please get out of the way, Master!  I nearly hit you.");
+            else
+                msg("Get out of the way %s!", whoami);
+
+            return(FALSE);
+        }
+
+        return(attack(thrower, weapon, THROWN));
+    }
+
+    if ((mon = find_mons(y, x)) != NULL)
+        return(mon_mon_attack(thrower, mon, weapon, THROWN));
+    else
+        return(FALSE);
+}
+
+
+/*
+    num()
+        Figure out the plus number for armor/weapons
+*/
+
+char *
+num(int n1, int n2, char *buf)
+{
+    if (buf == NULL)
+        return("UltraRogue Error #104");
+
+    if (n1 == 0 && n2 == 0)
+    {
+        strcpy(buf,"+0");
+        return(buf);
+    }
+
+    if (n2 == 0)
+        sprintf(buf, "%s%d", n1 < 0 ? "" : "+", n1);
+    else
+        sprintf(buf, "%s%d, %s%d", n1 < 0 ? "" : "+",
+            n1, n2 < 0 ? "" : "+", n2);
+
+    return(buf);
+}
+
+/*
+    wield()
+        Pull out a certain weapon
+*/
+
+void
+wield(void)
+{
+    struct linked_list *item;
+    struct object *obj, *oweapon;
+
+    oweapon = cur_weapon;
+
+    if (!dropcheck(cur_weapon))
+    {
+        cur_weapon = oweapon;
+        return;
+    }
+
+    cur_weapon = oweapon;
+
+    if ((item = get_item("wield", WEAPON)) == NULL)
+    {
+        after = FALSE;
+        return;
+    }
+
+    obj = OBJPTR(item);
+
+    if (is_current(obj))
+    {
+        after = FALSE;
+        return;
+    }
+
+    wield_ok(&player, obj, TRUE);
+
+    msg("You are now wielding %s.", inv_name(obj, LOWERCASE));
+
+    cur_weapon = obj;
+}
+
+/*
+    fallpos()
+        pick a random position around the given (y, x) coordinates
+*/
+
+int
+fallpos(coord pos, coord *newpos) /*ARGSUSED*/
+{
+    int   y, x, cnt;
+	coord places[9];
+
+    cnt = 0;
+
+    /* look for all the places that qualify */
+
+    for (y = pos.y - 1; y <= pos.y + 1; y++)
+	{
+        for (x = pos.x - 1; x <= pos.x + 1; x++)
+        {
+            switch(CCHAR(mvwinch(stdscr,y,x)))
+            {
+                case GOLD:
+                case POTION:
+                case SCROLL:
+                case FOOD:
+                case WEAPON:
+                case ARMOR:
+                case RING:
+                case STICK:
+                case FLOOR:
+                case PASSAGE:
+                case ARTIFACT:
+                    places[cnt].y = y;
+                    places[cnt].x = x;
+                    cnt++;
+            }
+        }
+    }
+	
+	/* now, pick one of the places, if there are any */
+
+    if (cnt > 0) 
+	{
+        int which = rnd(cnt);
+
+        newpos->y = places[which].y;
+        newpos->x = places[which].x;
+
+        debug("Dropping object at %d, %d", newpos->y, newpos->x);
+    }
+	
+    return(cnt);
+}
+
+/*
+    wield_ok()
+        enforce player class weapons restrictions
+*/
+
+int
+wield_ok(struct thing *wieldee, struct object *obj, int print_message)
+{
+    int ret_val = TRUE;
+    int class_type = wieldee->t_ctype;
+
+    if (obj->o_type != WEAPON)
+    {
+        ret_val = FALSE;
+        return(ret_val);
+    }
+    else
+        switch (class_type)
+        {
+            case C_MAGICIAN: /* need one hand free */
+            case C_ILLUSION:
+                if (obj->o_flags & ISTWOH)
+                    ret_val = FALSE;
+                break;
+
+            case C_THIEF:    /* need portable weapon  */
+            case C_ASSASIN:
+            case C_NINJA:
+                if (obj->o_flags & ISTWOH)
+                    ret_val = FALSE;
+                break;
+
+            case C_CLERIC:   /* No sharp weapons */
+                if (obj->o_flags & ISSHARP)
+                    ret_val = FALSE;
+                break;
+
+            case C_DRUID:    /* No non-silver metal weapons */
+                if (obj->o_flags & ISMETAL && !(obj->o_flags & ISSILVER))
+                    ret_val = FALSE;
+                break;
+
+            case C_PALADIN:  /* must wield sharp stuff */
+                if ((obj->o_flags & ISSHARP) == FALSE)
+                    ret_val = FALSE;
+                break;
+
+            case C_FIGHTER:  /* wield anything */
+            case C_RANGER:
+            case C_MONSTER:
+                break;
+
+            default:  /* Unknown class */
+                debug("Unknown class %d.", class_type);
+                break;
+        }
+
+    if (itemweight(obj) > 18 * pstats.s_str)
+    {
+        if (wieldee == &player && print_message == TRUE)
+            msg("That is too heavy for you to swing effectively!");
+
+        ret_val = FALSE;
+        return(ret_val);
+    }
+
+    if (ret_val == FALSE && print_message == MESSAGE)
+        switch (class_type)
+        {
+            case C_MAGICIAN:
+            case C_ILLUSION:
+                msg("You'll find it hard to cast spells while wielding that!");
+                break;
+
+            case C_THIEF:
+            case C_ASSASIN:
+            case C_NINJA:
+                msg("Don't expect to backstab anyone while wielding that!");
+                break;
+
+            case C_CLERIC:
+            case C_DRUID:
+            case C_PALADIN:
+                msg("Your god strongly disapproves of your wielding that!");
+                break;
+
+            case C_FIGHTER:
+            case C_RANGER:
+            case C_MONSTER:
+                break;
+        }
+
+    return(ret_val);
+}
+
+/*
+    shoot_ok()
+        returns true if it is ok for type to shoot over ch
+*/
+
+int
+shoot_ok(int ch)
+{
+    switch(ch)
+    {
+        case ' ':
+        case '|':
+        case '-':
+        case SECRETDOOR:
+            return(FALSE);
+
+        default:
+            return(!isalpha(ch));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/wizard.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,238 @@
+/*
+    wizard.c - Special wizard commands
+    
+    UltraRogue: The Ultimate Adventure in the Dungeons of Doom
+    Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
+    All rights reserved.
+
+    Based on "Advanced Rogue"
+    Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
+    All rights reserved.
+
+    Based on "Rogue: Exploring the Dungeons of Doom"
+    Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
+    All rights reserved.
+
+    See the file LICENSE.TXT for full copyright and licensing information.
+*/
+
+#include <string.h>
+#include <stdlib.h>
+#include "rogue.h"
+
+/*
+    whatis()
+        What a certain object is
+*/
+
+void
+whatis(struct linked_list *what)
+{
+    struct object *obj;
+    int kludge;
+    int print_message = FALSE;
+
+    if (what == NULL)
+    {
+        print_message = TRUE;
+
+        while ((what = get_item("identify", 0)) == NULL)
+            ;
+    }
+
+    obj = OBJPTR(what);
+    obj->o_flags |= ISKNOW;
+
+    switch (obj->o_type)
+    {
+        case SCROLL: kludge = TYP_SCROLL; break;
+        case POTION: kludge = TYP_POTION; break;
+        case STICK:  kludge = TYP_STICK;  break;
+        case RING:   kludge = TYP_RING;   break;
+        case WEAPON:
+        case ARMOR:
+        default:     kludge = -1;         break;
+    }
+
+    if (kludge != -1)
+    {
+        know_items[kludge][obj->o_which] = TRUE;
+
+        if (guess_items[kludge][obj->o_which])
+        {
+            ur_free(guess_items[kludge][obj->o_which]);
+            guess_items[kludge][obj->o_which] = NULL;
+        }
+    }
+
+    if (print_message)
+        msg(inv_name(obj, UPPERCASE));
+}
+
+/*
+    teleport()
+        Bamf the hero someplace else
+*/
+
+void
+teleport(void)
+{
+    struct room *new_rp = NULL, *old_rp = roomin(hero);
+
+    int rm, which;
+    coord c;
+    int is_lit = FALSE; /* For saving room light state */
+    int rand_position = TRUE;
+
+    c = hero;
+
+    mvwaddch(cw, hero.y, hero.x, mvwinch(stdscr, hero.y, hero.x));
+
+    if (is_wearing(R_TELCONTROL))
+    {
+        msg("Where do you wish to teleport to? (* for help)");
+        wmove(cw, hero.y, hero.x);
+        wrefresh(cw);
+
+        which = (short) (readchar() & 0177);
+
+        while (which != (short) ESCAPE && which != (short) LINEFEED
+            && which != (short) CARRIAGE_RETURN)
+        {
+            switch(which)
+            {
+                case 'h':   c.x--; break;
+                case 'j':   c.y++; break;
+                case 'k':   c.y--; break;
+                case 'l':   c.x++; break;
+                case 'y':   c.x--;
+                            c.y--; break;
+                case 'u':   c.x++;
+                            c.y--; break;
+                case 'b':   c.x--;
+                            c.y++; break;
+                case 'n':   c.x++;
+                            c.y++; break;
+                case '*':
+                    msg("Use h,j,k,l,y,u,b,n to position cursor, then hit"
+                        "return.");
+            }
+
+            c.y = max(c.y, 1);
+            c.y = min(c.y, LINES - 3);
+            c.x = max(c.x, 1);
+            c.x = min(c.x, COLS - 1);
+            wmove(cw, c.y, c.x);
+            wrefresh(cw);
+            which = (short) (readchar() & 0177);
+        }
+
+        which = winat(c.y, c.x);
+
+        if ((which == FLOOR || which == PASSAGE || which == DOOR) &&
+            ((ring_value(R_TELCONTROL) == 0 && rnd(10) < 6)
+             || (ring_value(R_TELCONTROL) > 0 && rnd(10) < 9)))
+        {
+            rand_position = FALSE;
+            msg("You attempt succeeds.");
+            hero = c;
+            new_rp = roomin(hero);
+        }
+        else
+            msg("Your attempt fails.");
+    }
+
+    if (rand_position)
+    {
+        do
+        {
+            rm = rnd_room();
+            rnd_pos(&rooms[rm], &hero);
+        }
+        while (winat(hero.y, hero.x) != FLOOR);
+
+        new_rp = &rooms[rm];
+    }
+
+    /* If hero gets moved, darken old room */
+
+    if (old_rp && old_rp != new_rp)
+    {
+        if (!(old_rp->r_flags & ISDARK))
+            is_lit = TRUE;
+
+        old_rp->r_flags |= ISDARK;  /* Fake darkness */
+        light(&c);
+
+        if (is_lit)
+            old_rp->r_flags &= ~ISDARK; /* Restore light state */
+    }
+
+    light(&hero);
+    mvwaddch(cw, hero.y, hero.x, PLAYER);
+
+    /* turn off ISHELD in case teleportation was done while fighting */
+
+    if (on(player, ISHELD))
+    {
+        struct linked_list  *ip, *nip;
+        struct thing    *mp;
+
+        turn_off(player, ISHELD);
+        hold_count = 0;
+
+        for (ip = mlist; ip; ip = nip)
+        {
+            mp = THINGPTR(ip);
+            nip = next(ip);
+
+            if (on(*mp, DIDHOLD))
+            {
+                turn_off(*mp, DIDHOLD);
+                turn_on(*mp, CANHOLD);
+            }
+
+            turn_off(*mp, DIDSUFFOCATE);
+        }
+    }
+
+    extinguish_fuse(FUSE_SUFFOCATE);
+    player.t_no_move = 0;   /* not trapped anymore */
+    count = 0;
+    running = FALSE;
+
+    return;
+}
+
+/*
+    passwd()
+        see if user knows password
+*/
+
+int
+passwd(void)
+{
+    char *sp, c;
+    char buf[2 * LINELEN];
+
+    msg("Wizard's Password:");
+    mpos = 0;
+    sp = buf;
+
+    while ((c = (readchar() & 0177)) != '\n' && c != '\r' && c != '\033')
+    {
+        if (c == '\0')
+            sp = buf;
+        else if (c == '\b' && sp > buf)
+            sp--;
+        else
+            *sp++ = c;
+    }
+
+    if (sp == buf)
+        return(FALSE);
+
+    *sp = '\0';
+
+    return(TRUE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/xcrypt.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,685 @@
+/*
+ * FreeSec: libcrypt
+ *
+ * Copyright (C) 1994 David Burren
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name(s) of the author(s) nor the names of other contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ * This is an original implementation of the DES and the crypt(3) interfaces
+ * by David Burren <davidb@werj.com.au>.
+ *
+ * An excellent reference on the underlying algorithm (and related
+ * algorithms) is:
+ *
+ *	B. Schneier, Applied Cryptography: protocols, algorithms,
+ *	and source code in C, John Wiley & Sons, 1994.
+ *
+ * Note that in that book's description of DES the lookups for the initial,
+ * pbox, and final permutations are inverted (this has been brought to the
+ * attention of the author).  A list of errata for this book has been
+ * posted to the sci.crypt newsgroup by the author and is available for FTP.
+ *
+ * NOTE:
+ * This file has a static version of des_setkey() so that crypt.o exports
+ * only the crypt() interface. This is required to make binaries linked
+ * against crypt.o exportable or re-exportable from the USA.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+extern unsigned long int md_ntohl(unsigned long int x);
+extern unsigned long int md_htonl(unsigned long int x);
+
+#define _PASSWORD_EFMT1 '_'
+
+static unsigned char	IP[64] = {
+	58, 50, 42, 34, 26, 18, 10,  2, 60, 52, 44, 36, 28, 20, 12,  4,
+	62, 54, 46, 38, 30, 22, 14,  6, 64, 56, 48, 40, 32, 24, 16,  8,
+	57, 49, 41, 33, 25, 17,  9,  1, 59, 51, 43, 35, 27, 19, 11,  3,
+	61, 53, 45, 37, 29, 21, 13,  5, 63, 55, 47, 39, 31, 23, 15,  7
+};
+
+static unsigned char	inv_key_perm[64];
+static unsigned char	key_perm[56] = {
+	57, 49, 41, 33, 25, 17,  9,  1, 58, 50, 42, 34, 26, 18,
+	10,  2, 59, 51, 43, 35, 27, 19, 11,  3, 60, 52, 44, 36,
+	63, 55, 47, 39, 31, 23, 15,  7, 62, 54, 46, 38, 30, 22,
+	14,  6, 61, 53, 45, 37, 29, 21, 13,  5, 28, 20, 12,  4
+};
+
+static unsigned char	key_shifts[16] = {
+	1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+static unsigned char	inv_comp_perm[56];
+static unsigned char	comp_perm[48] = {
+	14, 17, 11, 24,  1,  5,  3, 28, 15,  6, 21, 10,
+	23, 19, 12,  4, 26,  8, 16,  7, 27, 20, 13,  2,
+	41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
+	44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
+};
+
+/*
+ *	No E box is used, as it's replaced by some ANDs, shifts, and ORs.
+ */
+
+static unsigned char	u_sbox[8][64];
+static unsigned char	sbox[8][64] = {
+	{
+		14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
+		 0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
+		 4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
+		15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13
+	},
+	{
+		15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
+		 3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
+		 0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
+		13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9
+	},
+	{
+		10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
+		13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
+		13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
+		 1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12
+	},
+	{
+		 7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
+		13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
+		10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
+		 3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14
+	},
+	{
+		 2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
+		14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
+		 4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
+		11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3
+	},
+	{
+		12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
+		10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
+		 9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
+		 4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13
+	},
+	{
+		 4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
+		13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
+		 1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
+		 6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12
+	},
+	{
+		13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
+		 1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
+		 7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
+		 2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
+	}
+};
+
+static unsigned char	un_pbox[32];
+static unsigned char	pbox[32] = {
+	16,  7, 20, 21, 29, 12, 28, 17,  1, 15, 23, 26,  5, 18, 31, 10,
+	 2,  8, 24, 14, 32, 27,  3,  9, 19, 13, 30,  6, 22, 11,  4, 25
+};
+
+static unsigned int bits32[32] =
+{
+	0x80000000, 0x40000000, 0x20000000, 0x10000000,
+	0x08000000, 0x04000000, 0x02000000, 0x01000000,
+	0x00800000, 0x00400000, 0x00200000, 0x00100000,
+	0x00080000, 0x00040000, 0x00020000, 0x00010000,
+	0x00008000, 0x00004000, 0x00002000, 0x00001000,
+	0x00000800, 0x00000400, 0x00000200, 0x00000100,
+	0x00000080, 0x00000040, 0x00000020, 0x00000010,
+	0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+static unsigned char	bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+
+static unsigned int saltbits;
+static int	old_salt;
+static unsigned int *bits28, *bits24;
+static unsigned char	init_perm[64], final_perm[64];
+static unsigned int en_keysl[16], en_keysr[16];
+static unsigned int de_keysl[16], de_keysr[16];
+static int	des_initialised = 0;
+static unsigned char	m_sbox[4][4096];
+static unsigned int psbox[4][256];
+static unsigned int ip_maskl[8][256], ip_maskr[8][256];
+static unsigned int fp_maskl[8][256], fp_maskr[8][256];
+static unsigned int key_perm_maskl[8][128], key_perm_maskr[8][128];
+static unsigned int comp_maskl[8][128], comp_maskr[8][128];
+static unsigned int old_rawkey0, old_rawkey1;
+
+static unsigned char	ascii64[] =
+	 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+/*	  0000000000111111111122222222223333333333444444444455555555556666 */
+/*	  0123456789012345678901234567890123456789012345678901234567890123 */
+
+static __inline int
+ascii_to_bin(char ch)
+{
+	if (ch > 'z')
+		return(0);
+	if (ch >= 'a')
+		return(ch - 'a' + 38);
+	if (ch > 'Z')
+		return(0);
+	if (ch >= 'A')
+		return(ch - 'A' + 12);
+	if (ch > '9')
+		return(0);
+	if (ch >= '.')
+		return(ch - '.');
+	return(0);
+}
+
+static void
+des_init()
+{
+	int	j, b, k, inbit, obit;
+	unsigned int	*p, *il, *ir, *fl, *fr;
+	unsigned char i;
+
+	old_rawkey0 = old_rawkey1 = 0;
+	saltbits = 0;
+	old_salt = 0;
+	bits24 = (bits28 = bits32 + 4) + 4;
+
+	/*
+	 * Invert the S-boxes, reordering the input bits.
+	 */
+	for (i = 0; i < 8; i++)
+		for (j = 0; j < 64; j++) {
+			b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf);
+			u_sbox[i][j] = sbox[i][b];
+		}
+
+	/*
+	 * Convert the inverted S-boxes into 4 arrays of 8 bits.
+	 * Each will handle 12 bits of the S-box input.
+	 */
+	for (b = 0; b < 4; b++)
+		for (i = 0; i < 64; i++)
+			for (j = 0; j < 64; j++)
+				m_sbox[b][(i << 6) | j] =
+					(u_sbox[(b << 1)][i] << 4) |
+					u_sbox[(b << 1) + 1][j];
+
+	/*
+	 * Set up the initial & final permutations into a useful form, and
+	 * initialise the inverted key permutation.
+	 */
+	for (i = 0; i < 64; i++) {
+		init_perm[final_perm[i] = IP[i] - 1] = i;
+		inv_key_perm[i] = 255;
+	}
+
+	/*
+	 * Invert the key permutation and initialise the inverted key
+	 * compression permutation.
+	 */
+	for (i = 0; i < 56; i++) {
+		inv_key_perm[key_perm[i] - 1] = i;
+		inv_comp_perm[i] = 255;
+	}
+
+	/*
+	 * Invert the key compression permutation.
+	 */
+	for (i = 0; i < 48; i++) {
+		inv_comp_perm[comp_perm[i] - 1] = i;
+	}
+
+	/*
+	 * Set up the OR-mask arrays for the initial and final permutations,
+	 * and for the key initial and compression permutations.
+	 */
+	for (k = 0; k < 8; k++) {
+		for (i = 0; i < 256; i++) {
+			*(il = &ip_maskl[k][i]) = 0;
+			*(ir = &ip_maskr[k][i]) = 0;
+			*(fl = &fp_maskl[k][i]) = 0;
+			*(fr = &fp_maskr[k][i]) = 0;
+			for (j = 0; j < 8; j++) {
+				inbit = 8 * k + j;
+				if (i & bits8[j]) {
+					if ((obit = init_perm[inbit]) < 32)
+						*il |= bits32[obit];
+					else
+						*ir |= bits32[obit-32];
+					if ((obit = final_perm[inbit]) < 32)
+						*fl |= bits32[obit];
+					else
+						*fr |= bits32[obit - 32];
+				}
+			}
+		}
+		for (i = 0; i < 128; i++) {
+			*(il = &key_perm_maskl[k][i]) = 0;
+			*(ir = &key_perm_maskr[k][i]) = 0;
+			for (j = 0; j < 7; j++) {
+				inbit = 8 * k + j;
+				if (i & bits8[j + 1]) {
+					if ((obit = inv_key_perm[inbit]) == 255)
+						continue;
+					if (obit < 28)
+						*il |= bits28[obit];
+					else
+						*ir |= bits28[obit - 28];
+				}
+			}
+			*(il = &comp_maskl[k][i]) = 0;
+			*(ir = &comp_maskr[k][i]) = 0;
+			for (j = 0; j < 7; j++) {
+				inbit = 7 * k + j;
+				if (i & bits8[j + 1]) {
+					if ((obit=inv_comp_perm[inbit]) == 255)
+						continue;
+					if (obit < 24)
+						*il |= bits24[obit];
+					else
+						*ir |= bits24[obit - 24];
+				}
+			}
+		}
+	}
+
+	/*
+	 * Invert the P-box permutation, and convert into OR-masks for
+	 * handling the output of the S-box arrays setup above.
+	 */
+	for (i = 0; i < 32; i++)
+		un_pbox[pbox[i] - 1] = i;
+
+	for (b = 0; b < 4; b++)
+		for (i = 0; i < 256; i++) {
+			*(p = &psbox[b][i]) = 0;
+			for (j = 0; j < 8; j++) {
+				if (i & bits8[j])
+					*p |= bits32[un_pbox[8 * b + j]];
+			}
+		}
+
+	des_initialised = 1;
+}
+
+static void
+setup_salt(int salt)
+{
+	unsigned int	obit, saltbit;
+	int	i;
+
+	if (salt == old_salt)
+		return;
+	old_salt = salt;
+
+	saltbits = 0;
+	saltbit = 1;
+	obit = 0x800000;
+	for (i = 0; i < 24; i++) {
+		if (salt & saltbit)
+			saltbits |= obit;
+		saltbit <<= 1;
+		obit >>= 1;
+	}
+}
+
+static int
+des_setkey(const unsigned char *key)
+{
+	unsigned int k0, k1, rawkey0, rawkey1;
+	int	shifts, round;
+
+	if (!des_initialised)
+		des_init();
+
+	rawkey0 = md_ntohl(*(unsigned int *) key);
+	rawkey1 = md_ntohl(*(unsigned int *) (key + 4));
+
+	if ((rawkey0 | rawkey1)
+	    && rawkey0 == old_rawkey0
+	    && rawkey1 == old_rawkey1) {
+		/*
+		 * Already setup for this key.
+		 * This optimisation fails on a zero key (which is weak and
+		 * has bad parity anyway) in order to simplify the starting
+		 * conditions.
+		 */
+		return(0);
+	}
+	old_rawkey0 = rawkey0;
+	old_rawkey1 = rawkey1;
+
+	/*
+	 *	Do key permutation and split into two 28-bit subkeys.
+	 */
+	k0 = key_perm_maskl[0][rawkey0 >> 25]
+	   | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f]
+	   | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f]
+	   | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f]
+	   | key_perm_maskl[4][rawkey1 >> 25]
+	   | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f]
+	   | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f]
+	   | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f];
+	k1 = key_perm_maskr[0][rawkey0 >> 25]
+	   | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f]
+	   | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f]
+	   | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f]
+	   | key_perm_maskr[4][rawkey1 >> 25]
+	   | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f]
+	   | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f]
+	   | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f];
+	/*
+	 *	Rotate subkeys and do compression permutation.
+	 */
+	shifts = 0;
+	for (round = 0; round < 16; round++) {
+		unsigned int	t0, t1;
+
+		shifts += key_shifts[round];
+
+		t0 = (k0 << shifts) | (k0 >> (28 - shifts));
+		t1 = (k1 << shifts) | (k1 >> (28 - shifts));
+
+		de_keysl[15 - round] =
+		en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f]
+				| comp_maskl[1][(t0 >> 14) & 0x7f]
+				| comp_maskl[2][(t0 >> 7) & 0x7f]
+				| comp_maskl[3][t0 & 0x7f]
+				| comp_maskl[4][(t1 >> 21) & 0x7f]
+				| comp_maskl[5][(t1 >> 14) & 0x7f]
+				| comp_maskl[6][(t1 >> 7) & 0x7f]
+				| comp_maskl[7][t1 & 0x7f];
+
+		de_keysr[15 - round] =
+		en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f]
+				| comp_maskr[1][(t0 >> 14) & 0x7f]
+				| comp_maskr[2][(t0 >> 7) & 0x7f]
+				| comp_maskr[3][t0 & 0x7f]
+				| comp_maskr[4][(t1 >> 21) & 0x7f]
+				| comp_maskr[5][(t1 >> 14) & 0x7f]
+				| comp_maskr[6][(t1 >> 7) & 0x7f]
+				| comp_maskr[7][t1 & 0x7f];
+	}
+	return(0);
+}
+
+static int
+do_des(unsigned int l_in, unsigned int r_in, unsigned int *l_out, 
+       unsigned int *r_out, int count)
+{
+	/*
+	 *	l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format.
+	 */
+	unsigned int	l, r, *kl, *kr, *kl1, *kr1;
+	unsigned int	f = 0, r48l, r48r;
+	int		round;
+
+	if (count == 0) {
+		return(1);
+	} else if (count > 0) {
+		/*
+		 * Encrypting
+		 */
+		kl1 = en_keysl;
+		kr1 = en_keysr;
+	} else {
+		/*
+		 * Decrypting
+		 */
+		count = -count;
+		kl1 = de_keysl;
+		kr1 = de_keysr;
+	}
+
+	/*
+	 *	Do initial permutation (IP).
+	 */
+	l = ip_maskl[0][l_in >> 24]
+	  | ip_maskl[1][(l_in >> 16) & 0xff]
+	  | ip_maskl[2][(l_in >> 8) & 0xff]
+	  | ip_maskl[3][l_in & 0xff]
+	  | ip_maskl[4][r_in >> 24]
+	  | ip_maskl[5][(r_in >> 16) & 0xff]
+	  | ip_maskl[6][(r_in >> 8) & 0xff]
+	  | ip_maskl[7][r_in & 0xff];
+	r = ip_maskr[0][l_in >> 24]
+	  | ip_maskr[1][(l_in >> 16) & 0xff]
+	  | ip_maskr[2][(l_in >> 8) & 0xff]
+	  | ip_maskr[3][l_in & 0xff]
+	  | ip_maskr[4][r_in >> 24]
+	  | ip_maskr[5][(r_in >> 16) & 0xff]
+	  | ip_maskr[6][(r_in >> 8) & 0xff]
+	  | ip_maskr[7][r_in & 0xff];
+
+	while (count--) {
+		/*
+		 * Do each round.
+		 */
+		kl = kl1;
+		kr = kr1;
+		round = 16;
+		while (round--) {
+			/*
+			 * Expand R to 48 bits (simulate the E-box).
+			 */
+			r48l	= ((r & 0x00000001) << 23)
+				| ((r & 0xf8000000) >> 9)
+				| ((r & 0x1f800000) >> 11)
+				| ((r & 0x01f80000) >> 13)
+				| ((r & 0x001f8000) >> 15);
+
+			r48r	= ((r & 0x0001f800) << 7)
+				| ((r & 0x00001f80) << 5)
+				| ((r & 0x000001f8) << 3)
+				| ((r & 0x0000001f) << 1)
+				| ((r & 0x80000000) >> 31);
+			/*
+			 * Do salting for crypt() and friends, and
+			 * XOR with the permuted key.
+			 */
+			f = (r48l ^ r48r) & saltbits;
+			r48l ^= f ^ *kl++;
+			r48r ^= f ^ *kr++;
+			/*
+			 * Do sbox lookups (which shrink it back to 32 bits)
+			 * and do the pbox permutation at the same time.
+			 */
+			f = psbox[0][m_sbox[0][r48l >> 12]]
+			  | psbox[1][m_sbox[1][r48l & 0xfff]]
+			  | psbox[2][m_sbox[2][r48r >> 12]]
+			  | psbox[3][m_sbox[3][r48r & 0xfff]];
+			/*
+			 * Now that we've permuted things, complete f().
+			 */
+			f ^= l;
+			l = r;
+			r = f;
+		}
+		r = l;
+		l = f;
+	}
+	/*
+	 * Do final permutation (inverse of IP).
+	 */
+	*l_out	= fp_maskl[0][l >> 24]
+		| fp_maskl[1][(l >> 16) & 0xff]
+		| fp_maskl[2][(l >> 8) & 0xff]
+		| fp_maskl[3][l & 0xff]
+		| fp_maskl[4][r >> 24]
+		| fp_maskl[5][(r >> 16) & 0xff]
+		| fp_maskl[6][(r >> 8) & 0xff]
+		| fp_maskl[7][r & 0xff];
+	*r_out	= fp_maskr[0][l >> 24]
+		| fp_maskr[1][(l >> 16) & 0xff]
+		| fp_maskr[2][(l >> 8) & 0xff]
+		| fp_maskr[3][l & 0xff]
+		| fp_maskr[4][r >> 24]
+		| fp_maskr[5][(r >> 16) & 0xff]
+		| fp_maskr[6][(r >> 8) & 0xff]
+		| fp_maskr[7][r & 0xff];
+	return(0);
+}
+
+static int
+des_cipher(const unsigned char *in, unsigned char *out, int salt, int count)
+{
+	unsigned int l_out, r_out, rawl, rawr;
+	unsigned int x[2];
+	int	retval;
+
+	if (!des_initialised)
+		des_init();
+
+	setup_salt(salt);
+
+	memcpy(x, in, sizeof x);
+	rawl = md_ntohl(x[0]);
+	rawr = md_ntohl(x[1]);
+	retval = do_des(rawl, rawr, &l_out, &r_out, count);
+
+	x[0] = md_htonl(l_out);
+	x[1] = md_htonl(r_out);
+	memcpy(out, x, sizeof x);
+	return(retval);
+}
+
+char *
+xcrypt(const char *key, const char *setting)
+{
+	int		i;
+	unsigned int	count, salt, l, r0, r1, keybuf[2];
+	unsigned char		*p, *q;
+	static unsigned char	output[21];
+
+	if (!des_initialised)
+		des_init();
+
+	/*
+	 * Copy the key, shifting each character up by one bit
+	 * and padding with zeros.
+	 */
+	q = (unsigned char *) keybuf;
+	while ((q - (unsigned char *) keybuf) < sizeof(keybuf)) {
+		if ((*q++ = *key << 1))
+			key++;
+	}
+	if (des_setkey((unsigned char *) keybuf))
+		return(NULL);
+
+	if (*setting == _PASSWORD_EFMT1) {
+		/*
+		 * "new"-style:
+		 *	setting - underscore, 4 bytes of count, 4 bytes of salt
+		 *	key - unlimited characters
+		 */
+		for (i = 1, count = 0; i < 5; i++)
+			count |= ascii_to_bin(setting[i]) << (i - 1) * 6;
+
+		for (i = 5, salt = 0; i < 9; i++)
+			salt |= ascii_to_bin(setting[i]) << (i - 5) * 6;
+
+		while (*key) {
+			/*
+			 * Encrypt the key with itself.
+			 */
+			if (des_cipher((unsigned char*)keybuf, (unsigned char*)keybuf, 0, 1))
+				return(NULL);
+			/*
+			 * And XOR with the next 8 characters of the key.
+			 */
+			q = (unsigned char *) keybuf;
+			while (((q - (unsigned char *) keybuf) < sizeof(keybuf)) &&
+					*key)
+				*q++ ^= *key++ << 1;
+
+			if (des_setkey((unsigned char *) keybuf))
+				return(NULL);
+		}
+		strncpy((char *)output, setting, 9);
+
+		/*
+		 * Double check that we weren't given a short setting.
+		 * If we were, the above code will probably have created
+		 * wierd values for count and salt, but we don't really care.
+		 * Just make sure the output string doesn't have an extra
+		 * NUL in it.
+		 */
+		output[9] = '\0';
+		p = output + strlen((const char *)output);
+	} else {
+		/*
+		 * "old"-style:
+		 *	setting - 2 bytes of salt
+		 *	key - up to 8 characters
+		 */
+		count = 25;
+
+		salt = (ascii_to_bin(setting[1]) << 6)
+		     |  ascii_to_bin(setting[0]);
+
+		output[0] = setting[0];
+		/*
+		 * If the encrypted password that the salt was extracted from
+		 * is only 1 character long, the salt will be corrupted.  We
+		 * need to ensure that the output string doesn't have an extra
+		 * NUL in it!
+		 */
+		output[1] = setting[1] ? setting[1] : output[0];
+
+		p = output + 2;
+	}
+	setup_salt(salt);
+	/*
+	 * Do it.
+	 */
+	if (do_des(0, 0, &r0, &r1, count))
+		return(NULL);
+	/*
+	 * Now encode the result...
+	 */
+	l = (r0 >> 8);
+	*p++ = ascii64[(l >> 18) & 0x3f];
+	*p++ = ascii64[(l >> 12) & 0x3f];
+	*p++ = ascii64[(l >> 6) & 0x3f];
+	*p++ = ascii64[l & 0x3f];
+
+	l = (r0 << 16) | ((r1 >> 16) & 0xffff);
+	*p++ = ascii64[(l >> 18) & 0x3f];
+	*p++ = ascii64[(l >> 12) & 0x3f];
+	*p++ = ascii64[(l >> 6) & 0x3f];
+	*p++ = ascii64[l & 0x3f];
+
+	l = r1 << 2;
+	*p++ = ascii64[(l >> 12) & 0x3f];
+	*p++ = ascii64[(l >> 6) & 0x3f];
+	*p++ = ascii64[l & 0x3f];
+	*p = 0;
+
+	return((char *)output);
+}