[net.sources] Amiga Hack Source

jcz@ncsu.UUCP (John A. Toebes, VIII) (02/20/86)

#file config.h
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#ifndef CONFIG   /* make sure the compiler doesnt see the typedefs twice */

#define CONFIG
#define VAX      /* to get proper struct initialization */
#define BSD      /* delete this line on System V */
/* #define STUPID */   /* avoid some complicated expressions if
			your C compiler chokes on them */

#define HELP    "help"
#define HACKNAME "hack"
#define HACKDIR "HACK_Game:"
#define HACKCSET "characters"
#define WIZARD  "wizard"/* the person allowed to use the -w option */
#define NEWS   "news"   /* the file containing the latest hack news */
#define FMASK   0660   /* file creation mask */

/* #define register */
#define OPTIONS      /* do not delete the 'o' command */
/* #define SHELL        /* do not delete the '!' command */
#define TRACK      /* do not delete the tracking properties of monsters */

/* size of terminal screen is (ROWNO+2) by COLNO */
#define COLNO   77
#define ROWNO   21

/*
 * small signed integers (8 bits suffice)
 *   typedef   char   schar;
 * will do when you have signed characters; otherwise use
 *   typedef   short int schar;
 */
typedef   char   schar;

/*
 * small unsigned integers (8 bits suffice - but 7 bits do not)
 * - these are usually object types; be careful with inequalities! -
 *   typedef   unsigned char   uchar;
 * will be satisfactory if you have an "unsigned char" type; otherwise use
 *   typedef unsigned short int uchar;
 */
typedef   unsigned char   uchar;

/*
 * small integers in the range 0 - 127, usually coordinates
 * although they are nonnegative they must not be declared unsigned
 * since otherwise comparisons with signed quantities are done incorrectly
 * (thus, in fact, you could make xchar equal to schar)
 */
typedef char   xchar;
typedef   xchar   boolean;      /* 0 or 1 */
#define   TRUE   1
#define   FALSE   0

/*
 * Declaration of bitfields in various structs; if your C compiler
 * doesnt handle bitfields well, e.g., if it is unable to initialize
 * structs containing bitfields, then you might use
 *   #define Bitfield(x,n)   xchar x
 * since the bitfields used never have more than 7 bits. (Most have 1 bit.)
 */
/* #define   Bitfield(x,n)   unsigned x:n */
#define Bitfield(x,n)   xchar x

#endif CONFIG
#file date.h
char datestring[] = "Sunday Jan 5, 1986";
#file def.edog.h
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */



struct edog {

	long hungrytime;	/* at this time dog gets hungry */

	long eattime;		/* dog is eating */

	long droptime;		/* moment dog dropped object */

	unsigned dropdist;		/* dist of drpped obj from @ */

	unsigned apport;		/* amount of training */

	long whistletime;		/* last time he whistled */

};

#define	EDOG(mp)	((struct edog *)(&(mp->mextra[0])))

#file def.eshk.h
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#define   BILLSZ   200
struct bill_x {
   unsigned bo_id;
   Bitfield(useup,1);
   Bitfield(bquan,7);
   unsigned price;      /* price per unit */
};

struct eshk {
   long int robbed;   /* amount stolen by most recent customer */
   schar shoproom;      /* index in rooms; set by inshop() */
   coord shk;      /* usual position shopkeeper */
   coord shd;      /* position shop door */
   int billct;
   struct bill_x bill[BILLSZ];
   int visitct;      /* nr of visits by most recent customer */
   char customer[PL_NSIZ];   /* most recent customer */
   char shknam[PL_NSIZ];
};
#file def.func_tab.h
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */



struct func_tab {

	char f_char;

	int (*f_funct)();

};



extern struct func_tab list[];

#file def.gen.h
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
/* def.gen.h version 1.0.1: added ONCE flag */

struct gen {
   struct gen *ngen;
   xchar gx,gy;
   unsigned gflag;      /* 037: trap type; 040: SEEN flag */
			/* 0100: ONCE only */
#define	TRAPTYPE	037
#define	SEEN	040
#define	ONCE	0100
};
extern struct gen *fgold, *ftrap;
struct gen *g_at();
#define newgen()   (struct gen *) alloc(sizeof(struct gen))
#file def.monst.h
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

struct monst {
   struct monst *nmon;
   struct permonst *data;
   unsigned m_id;
   xchar mx,my;
   xchar mdx,mdy;      /* if mdispl then pos where last displayed */
#define   MTSZ   4
   coord mtrack[MTSZ];   /* monster track */
   schar mhp,orig_hp;
   char mimic;      /* undetected mimic - this is its symbol */
   Bitfield(mdispl,1);   /* mdx,mdy valid */
   Bitfield(minvis,1);   /* invisible */
   Bitfield(cham,1);   /* shape-changer */
   Bitfield(mhide,1);   /* hides beneath objects */
   Bitfield(mundetected,1);   /* not seen in present hiding place */
   Bitfield(mspeed,2);
   Bitfield(msleep,1);
   Bitfield(mfroz,1);
   Bitfield(mconf,1);
   Bitfield(mflee,1);
   Bitfield(mcan,1);   /* has been cancelled */
   Bitfield(mtame,1);      /* implies peaceful */
   Bitfield(mpeaceful,1);   /* does not attack unprovoked */
   Bitfield(isshk,1);   /* is shopkeeper */
   Bitfield(isgd,1);   /* is guard */
   Bitfield(mcansee,1);   /* cansee 1, temp.blinded 0, blind 0 */
   Bitfield(mblinded,7);   /* cansee 0, temp.blinded n, blind 0 */
   Bitfield(mtrapped,1);   /* trapped in a pit or bear trap */
   Bitfield(mnamelth,6);   /* length of name (following mxlth) */
#ifndef NOWORM
   Bitfield(wormno,5);   /* at most 31 worms on any level */
#endif NOWORM
   unsigned mtrapseen;   /* bitmap of traps we've been trapped in */
   long mlstmv;   /* prevent two moves at once */
   struct obj *minvent;
   long mgold;
   unsigned mxlth;      /* length of following data */
   /* in order to prevent alignment problems mextra should
      be (or follow) a long int */
   long mextra[1];      /* monster dependent info */
};

#define newmonst(xl)   (struct monst *) alloc((unsigned)(xl) + sizeof(struct monst))

extern struct monst *fmon;
#ifndef MKLEV
extern struct monst *fallen_down;
#endif MKLEV
struct monst *m_at();

/* these are in mspeed */
#define MSLOW 1 /* slow monster */
#define MFAST 2 /* speeded monster */

#define   NAME(mtmp)   (((char *) mtmp->mextra) + mtmp->mxlth)
#file def.obj.h
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */



struct obj {

	struct obj *nobj;

	unsigned o_id;

	unsigned o_cnt_id;		/* id of container object is in */

	xchar ox,oy;

	xchar odx,ody;

	uchar otyp;

	uchar owt;

	unsigned quan;	/* small in general but large in case of gold */

	schar spe;

	char olet;

	Bitfield(oinvis,1);

	Bitfield(odispl,1);

	Bitfield(known,1);	/* exact nature known */

	Bitfield(dknown,1);	/* color or text known */

	Bitfield(cursed,1);

	Bitfield(unpaid,1);	/* on some bill */

	Bitfield(rustfree,1);

	Bitfield(onamelth,6);

	long age;	/* creation date */

	long owornmask;

#define	W_ARM	01L

#define	W_ARM2	02L

#define	W_ARMH	04L

#define	W_ARMS	010L

#define	W_ARMG	020L

#define	W_ARMOR		(W_ARM | W_ARM2 | W_ARMH | W_ARMS | W_ARMG)

#define	W_RINGL	010000L	/* make W_RINGL = RING_LEFT (see uprop) */

#define	W_RINGR	020000L

#define	W_RING		(W_RINGL | W_RINGR)

#define	W_WEP	01000L

#define	W_BALL	02000L

#define	W_CHAIN	04000L

	long oextra[1];

};



extern struct obj *fobj;



#define newobj(xl)	(struct obj *) alloc((unsigned)(xl) + sizeof(struct obj))

#define	ONAME(otmp)	((char *) otmp->oextra)

#file def.objclass.h
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */



/* definition of a class of objects */



struct objclass {

	char *oc_name;		/* actual name */

	char *oc_descr;		/* description when name unknown */

	char *oc_uname;		/* called by user */

	Bitfield(oc_name_known,1);

	Bitfield(oc_merge,1);	/* merge otherwise equal objects */

	char oc_olet;

	schar oc_prob;		/* probability for mkobj() */

	schar oc_delay;		/* delay when using such an object */

	uchar oc_weight;

	schar oc_oc1, oc_oc2;

	int oc_oi;

#define	nutrition	oc_oi	/* for foods */

#define	a_ac		oc_oc1	/* for armors */

#define	a_can		oc_oc2	/* for armors */

#define bits		oc_oc1	/* for wands and rings */

				/* wands */

#define		NODIR		1

#define		IMMEDIATE	2

#define		RAY		4

				/* rings */

#define		SPEC		1	/* +n is meaningful */

#define	wldam		oc_oc1	/* for weapons */

#define	wsdam		oc_oc2	/* for weapons */

#define	g_val		oc_oi	/* for gems: value on exit */

};



extern struct objclass objects[];



/* definitions of all object-symbols */



#define	ILLOBJ_SYM	'\\'

#define	AMULET_SYM	'"'

#define	FOOD_SYM	'%'

#define	WEAPON_SYM	')'

#define	TOOL_SYM	'('

#define	BALL_SYM	'0'

#define	CHAIN_SYM	'_'

#define	ROCK_SYM	'`'

#define	ARMOR_SYM	'['

#define	POTION_SYM	'!'

#define	SCROLL_SYM	'?'

#define	WAND_SYM	'/'

#define	RING_SYM	'='

#define	GEM_SYM		'*'

/* Other places with explicit knowledge of object symbols:

 * ....shk.c:	char shtypes[] = "=/)%?![";

 * mklev.c:	"=/)%?![<>"

 * hack.mkobj.c:	char mkobjstr[] = "))[[!!!!????%%%%/=**";

 * hack.apply.c:   otmp = getobj("0#%", "put in");

 * hack.eat.c:     otmp = getobj("%", "eat");

 * hack.invent.c:          if(index("!%?[)=*(0/\"", sym)){

 * hack.invent.c:    || index("%?!*",otmp->olet))){

 */

#file def.objects.h
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */



/* objects have letter " % ) ( 0 _ [ ! ? / = * */

#include "def.objclass.h"

#define	NULL	(char *)0



struct objclass objects[] = {



	{ "strange object", NULL, NULL, 1, 0,

		ILLOBJ_SYM, 0, 0, 0, 0, 0, 0 },

	{ "amulet of Yendor", NULL, NULL, 1, 0,

		AMULET_SYM, 100, 0, 2, 0, 0, 0 },



#define	FOOD(name,prob,delay,weight,nutrition)	{ name, NULL, NULL, 1, 1,\

		FOOD_SYM, prob, delay, weight, 0, 0, nutrition }



/* dog eats foods 0-4 but prefers 1 above 0,2,3,4 */

/* food 4 can be read */

/* food 5 improves your vision */

/* food 6 makes you stronger (like Popeye) */

/* foods CORPSE=15 up to CORPSE+52 are cadavers */



	FOOD("food ration", 	50, 5, 4, 800),

	FOOD("tripe ration",	20, 1, 2, 200),

	FOOD("pancake",		3, 1, 1, 200),

	FOOD("dead lizard",	3, 0, 1, 40),

	FOOD("fortune cookie",	7, 0, 1, 40),

	FOOD("carrot",		2, 0, 1, 50),

	FOOD("tin",		7, 0, 1, 0),

	FOOD("orange",		1, 0, 1, 80),

	FOOD("apple",		1, 0, 1, 50),

	FOOD("pear",		1, 0, 1, 50),

	FOOD("melon",		1, 0, 1, 100),

	FOOD("banana",		1, 0, 1, 80),

	FOOD("candy bar",	1, 0, 1, 100),

	FOOD("egg",		1, 0, 1, 80),

	FOOD("clove of garlic",	1, 0, 1, 40),



	FOOD("dead human",	0, 4, 40, 400),

	FOOD("dead giant ant",	0, 1, 3, 30),

	FOOD("dead giant bat",	0, 1, 3, 30),

	FOOD("dead centaur",	0, 5, 50, 500),

	FOOD("dead dragon",	0, 15, 150, 1500),

	FOOD("dead floating eye",	0, 1, 1, 10),

	FOOD("dead freezing sphere",	0, 1, 1, 10),

	FOOD("dead gnome",	0, 1, 10, 100),

	FOOD("dead hobgoblin",	0, 2, 20, 200),

	FOOD("dead stalker",	0, 4, 40, 400),

	FOOD("dead jackal",	0, 1, 10, 100),

	FOOD("dead kobold",	0, 1, 10, 100),

	FOOD("dead leprechaun",	0, 4, 40, 400),

	FOOD("dead mimic",	0, 4, 40, 400),

	FOOD("dead nymph",	0, 4, 40, 400),

	FOOD("dead orc",	0, 2, 20, 200),

	FOOD("dead purple worm",	0, 7, 70, 700),

	FOOD("dead quasit",	0, 2, 20, 200),

	FOOD("dead rust monster",	0, 5, 50, 500),

	FOOD("dead snake",	0, 1, 10, 100),

	FOOD("dead troll",	0, 4, 40, 400),

	FOOD("dead umber hulk",	0, 5, 50, 500),

	FOOD("dead vampire",	0, 4, 40, 400),

	FOOD("dead wraith",	0, 1, 1, 10),

	FOOD("dead xorn",	0, 7, 70, 700),

	FOOD("dead yeti",	0, 7, 70, 700),

	FOOD("dead zombie",	0, 1, 3, 30),

	FOOD("dead acid blob",	0, 1, 3, 30),

	FOOD("dead giant beetle",	0, 1, 1, 10),

	FOOD("dead cockatrice",	0, 1, 3, 30),

	FOOD("dead dog",	0, 2, 20, 200),

	FOOD("dead ettin",	0, 1, 3, 30),

	FOOD("dead fog cloud",	0, 1, 1, 10),

	FOOD("dead gelatinous cube",	0, 1, 10, 100),

	FOOD("dead homunculus",	0, 2, 20, 200),

	FOOD("dead imp",	0, 1, 1, 10),

	FOOD("dead jaguar",	0, 3, 30, 300),

	FOOD("dead killer bee",	0, 1, 1, 10),

	FOOD("dead leocrotta",	0, 5, 50, 500),

	FOOD("dead minotaur",	0, 7, 70, 700),

	FOOD("dead nurse",	0, 4, 40, 400),

	FOOD("dead owlbear",	0, 7, 70, 700),

	FOOD("dead piercer",	0, 2, 20, 200),

	FOOD("dead quivering blob",	0, 1, 10, 100),

	FOOD("dead giant rat",	0, 1, 3, 30),

	FOOD("dead giant scorpion",	0, 1, 10, 100),

	FOOD("dead tengu",	0, 3, 30, 300),

	FOOD("dead unicorn",	0, 3, 30, 300),

	FOOD("dead violet fungi",	0, 1, 10, 100),

	FOOD("dead long worm",	0, 5, 50, 500),

/* %% wt of long worm should be proportional to its length */

	FOOD("dead xan",	0, 3, 30, 300),

	FOOD("dead yellow light",	0, 1, 1, 10),

	FOOD("dead zruty",	0, 6, 60, 600),



/* weapons ... - ROCK come several at a time */

/* weapons ... - (ROCK-1) are shot using idem+(BOW-ARROW) */

/* weapons AXE, SWORD, THSWORD are good for worm-cutting */

/* weapons AXE, DAGGER, CRYSKNIFE are good for tin-opening */

#define WEAPON(name,prob,wt,ldam,sdam)	{ name, NULL, NULL, 1, 0 /*%%*/,\

		WEAPON_SYM, prob, 0, wt, ldam, sdam, 0 }



	WEAPON("arrow",		7, 0, 6, 6),

	WEAPON("sling bullet",	7, 0, 4, 6),

	WEAPON("crossbow bolt",	7, 0, 4, 6),

	WEAPON("dart",		7, 0, 3, 2),

	WEAPON("rock",		6, 1, 3, 3),

	WEAPON("boomerang",	2, 3, 9, 9),

	WEAPON("mace",		9, 3, 6, 7),

	WEAPON("axe",		6, 3, 6, 4),

	WEAPON("flail",		6, 3, 6, 5),

	WEAPON("long sword",	8, 3, 8, 12),

	WEAPON("two handed sword",	6, 4, 10, 6),

	WEAPON("dagger",	6, 3, 4, 3),

	WEAPON("worm tooth",	0, 4, 2, 2),

	WEAPON("crysknife",	0, 3, 12, 12),

	WEAPON("spear",		6, 3, 6, 8),

	WEAPON("bow",		6, 3, 4, 6),

	WEAPON("sling",		5, 3, 6, 6),

	WEAPON("crossbow",	6, 3, 4, 6),



	{ "whistle", "whistle", NULL, 0, 0,

		TOOL_SYM, 90, 0, 2, 0, 0, 0 },

	{ "magic whistle", "whistle", NULL, 0, 0,

		TOOL_SYM, 10, 0, 2, 0, 0, 0 },

	{ "expensive camera", NULL, NULL, 1, 1,

		TOOL_SYM, 0, 0, 3, 0, 0, 0 },

	{ "ice box", "large box", NULL, 0, 0,

		TOOL_SYM, 0, 0, 40, 0, 0, 0 },

	{ "heavy iron ball", NULL, NULL, 1, 0,

		BALL_SYM, 100, 0, 20, 0, 0, 0 },

	{ "iron chain", NULL, NULL, 1, 0,

		CHAIN_SYM, 100, 0, 20, 0, 0, 0 },

	{ "enormous rock", NULL, NULL, 1, 0,

		ROCK_SYM, 100, 0, 200 /* > MAX_CARR_CAP */, 0, 0, 0 },



#define ARMOR(name,prob,delay,ac,can)	{ name, NULL, NULL, 1, 0,\

		ARMOR_SYM, prob, delay, 8, ac, can, 0 }

	ARMOR("helmet",		 3, 1, 9, 0),

	ARMOR("plate mail",		 5, 5, 3, 2),

	ARMOR("splint mail",	 8, 5, 4, 1),

	ARMOR("banded mail",	10, 5, 4, 0),

	ARMOR("chain mail",		10, 5, 5, 1),

	ARMOR("scale mail",		10, 5, 6, 0),

	ARMOR("ring mail",		15, 5, 7, 0),

	/* the armors below do not rust */

	ARMOR("studded leather armor", 13, 3, 7, 1),

	ARMOR("leather armor",	17, 3, 8, 0),

	ARMOR("elven cloak",	 5, 0, 9, 3),

	ARMOR("shield",		 3, 0, 9, 0),

	ARMOR("pair of gloves",	 1, 1, 9, 0),



#define POTION(name,color)	{ name, color, NULL, 0, 1,\

		POTION_SYM, 0, 0, 2, 0, 0, 0 }



	POTION("restore strength",	"orange"),

	POTION("booze",		"bubbly"),

	POTION("invisibility",	"glowing"),

	POTION("fruit juice",	"smoky"),

	POTION("healing",	"pink"),

	POTION("paralysis",	"puce"),

	POTION("monster detection",	"purple"),

	POTION("object detection",	"yellow"),

	POTION("sickness",	"white"),

	POTION("confusion",	"swirly"),

	POTION("gain strength",	"purple-red"),

	POTION("speed",		"ruby"),

	POTION("blindness",	"dark green"),

	POTION("gain level",	"emerald"),

	POTION("extra healing",	"sky blue"),

	POTION("levitation",	"brown"),

	POTION(NULL,	"brilliant blue"),

	POTION(NULL,	"clear"),

	POTION(NULL,	"magenta"),

	POTION(NULL,	"ebony"),



#define SCROLL(name,text,prob) { name, text, NULL, 0, 1,\

		SCROLL_SYM, prob, 0, 3, 0, 0, 0 }

	SCROLL("enchant armor", "ZELGO MER", 6),

	SCROLL("destroy armor", "JUYED AWK YACC", 5),

	SCROLL("confuse monster", "NR 9", 5),

	SCROLL("scare monster", "XIXAXA XOXAXA XUXAXA", 4),

	SCROLL("blank paper", "READ ME", 3),

	SCROLL("remove curse", "PRATYAVAYAH", 6),

	SCROLL("enchant weapon", "DAIYEN FOOELS", 6),

	SCROLL("damage weapon", "HACKEM MUCHE", 5),

	SCROLL("create monster", "LEP GEX VEN ZEA", 5),

	SCROLL("taming", "PRIRUTSENIE", 1),

	SCROLL("genocide", "ELBIB YLOH",2),

	SCROLL("light", "VERR YED HORRE", 10),

	SCROLL("teleportation", "VENZAR BORGAVVE", 5),

	SCROLL("gold detection", "THARR", 4),

	SCROLL("food detection", "YUM YUM", 1),

	SCROLL("identify", "KERNOD WEL", 18),

	SCROLL("magic mapping", "ELAM EBOW", 5),

	SCROLL("amnesia", "DUAM XNAHT", 3),

	SCROLL("fire", "ANDOVA BEGARIN", 5),

	SCROLL("punishment", "VE FORBRYDERNE", 1),

	SCROLL(NULL, "VELOX NEB", 0),

	SCROLL(NULL, "FOOBIE BLETCH", 0),

	SCROLL(NULL, "TEMOV", 0),

	SCROLL(NULL, "GARVEN DEH", 0),



#define	WAND(name,metal,prob,flags)	{ name, metal, NULL, 0, 0,\

		WAND_SYM, prob, 0, 3, flags, 0, 0 }



	WAND("light",	"iridium",		10,	NODIR),

	WAND("secret door detection",	"tin",	5,	NODIR),

	WAND("create monster",	"platinum",	5,	NODIR),

	WAND("wishing",		"glass",	1,	NODIR),

	WAND("striking",	"zinc",		9,	IMMEDIATE),

	WAND("slow monster",	"balsa",	5,	IMMEDIATE),

	WAND("speed monster",	"copper",	5,	IMMEDIATE),

	WAND("undead turning",	"silver",	5,	IMMEDIATE),

	WAND("polymorph",	"brass",	5,	IMMEDIATE),

	WAND("cancellation",	"maple",	5,	IMMEDIATE),

	WAND("teleport monster",	"pine",	5,	IMMEDIATE),

	WAND("make invisible",	"marble",	9,	IMMEDIATE),

	WAND("digging",	"iron",		5,	RAY),

	WAND("magic missile",	"aluminium",	10,	RAY),

	WAND("fire",	"steel",	5,	RAY),

	WAND("sleep",	"curved",	5,	RAY),

	WAND("cold",	"short",	5,	RAY),

	WAND("death",	"long",		1,	RAY),

	WAND(NULL,	"oak",		0,	0),

	WAND(NULL,	"ebony",	0,	0),

	WAND(NULL,	"runed",	0,	0),



#define	RING(name,stone,spec)	{ name, stone, NULL, 0, 0,\

		RING_SYM, 0, 0, 1, spec, 0, 0 }



	RING("adornment",	"engagement",	0),

	RING("teleportation",	"wooden",	0),

	RING("regeneration",	"black onyx",	0),

	RING("searching",	"topaz",	0),

	RING("see invisible",	"pearl",	0),

	RING("stealth",		"sapphire",	0),

	RING("levitation",	"moonstone",	0),

	RING("poison resistance", "agate",	0),

	RING("aggravate monster", "tiger eye",	0),

	RING("hunger",		"shining",	0),

	RING("fire resistance",	"gold",		0),

	RING("cold resistance",	"copper",	0),

	RING("protection from shape changers", "diamond", 0),

	RING("conflict",	"jade",		0),

	RING("gain strength",	"ruby",		SPEC),

	RING("increase damage",	"silver",	SPEC),

	RING("protection",	"granite",	SPEC),

	RING("warning",		"wire",		0),

	RING("teleport control", "iron",	0),

	RING(NULL,		"ivory",	0),

	RING(NULL,		"blackened",	0),



/* gems ************************************************************/

#define	GEM(name,color,prob,gval)	{ name, color, NULL, 0, 1,\

		GEM_SYM, prob, 0, 1, 0, 0, gval }

	GEM("diamond", "blue", 1, 4000),

	GEM("ruby", "red", 1, 3500),

	GEM("sapphire", "blue", 1, 3000),

	GEM("emerald", "green", 1, 2500),

	GEM("turquoise", "green", 1, 2000),

	GEM("aquamarine", "blue", 1, 1500),

	GEM("tourmaline", "green", 1, 1000),

	GEM("topaz", "yellow", 1, 900),

	GEM("opal", "yellow", 1, 800),

	GEM("garnet", "dark", 1, 700),

	GEM("amethyst", "violet", 2, 650),

	GEM("agate", "green", 2, 600),

	GEM("onyx", "white", 2, 550),

	GEM("jasper", "yellowish brown", 2, 500),

	GEM("jade", "green", 2, 450),

	GEM("worthless piece of blue glass", "blue", 20, 0),

	GEM("worthless piece of red glass", "red", 20, 0),

	GEM("worthless piece of yellow glass", "yellow", 20, 0),

	GEM("worthless piece of green glass", "green", 20, 0),

	{ NULL, NULL, NULL, 0, 0, ILLOBJ_SYM, 0, 0, 0, 0, 0, 0 }

};



char obj_symbols[] = {

	ILLOBJ_SYM, AMULET_SYM, FOOD_SYM, WEAPON_SYM, TOOL_SYM,

	BALL_SYM, CHAIN_SYM, ROCK_SYM, ARMOR_SYM, POTION_SYM, SCROLL_SYM,

	WAND_SYM, RING_SYM, GEM_SYM, 0 };

int bases[sizeof(obj_symbols)];

#file def.permonst.h
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */



struct permonst {

	char *mname,mlet;

	schar mlevel,mmove,ac,damn,damd;

	unsigned pxlth;

};

#file def.trap.h
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
/* def.trap.h version 1.0.1 - added ONCE flag */

/* various kinds of traps */
#define BEAR_TRAP	0
#define	ARROW_TRAP	1
#define	DART_TRAP	2
#define TRAPDOOR	3
#define	TELEP_TRAP	4
#define PIT 5
#define SLP_GAS_TRAP	6
#define	PIERC	7
#define	MIMIC	8	/* used only in mklev.c */
/* before adding more trap types, check mfndpos ! */
/* #define SEEN 040 - trap which has been seen */
/* #define ONCE 0100 - once only trap */
#file def.wseg.h
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#ifndef NOWORM
/* worm structure */
struct wseg {
   struct wseg *nseg;
   xchar wx,wy;
   Bitfield(wdispl,1);
};

#define newseg()   (struct wseg *) alloc(sizeof(struct wseg))
#endif NOWORM
#file hack.h
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.h version 1.0.1 - added some flags for HACKOPTIONS */

#include "mklev.h"
#include "hack.onames.h"

/* #define GRAPHICS 1 */

#define MUP    1
#define MDOWN  2

#define ON 1
#define OFF 0

extern struct obj *invent, *uwep, *uarm, *uarm2, *uarmh, *uarms, *uarmg, 
   *uleft, *uright, *fcobj;
extern struct obj *uchain;   /* defined iff PUNISHED */
extern struct obj *uball;   /* defined if PUNISHED */
struct obj *o_at(), *getobj(), *sobj_at();

struct flag {
	unsigned ident;		/* social security number for each monster */
	Bitfield(topl,2);	/* a top line (message) has been printed */
				/* 0: top line empty; 2: no --More-- reqd. */
	Bitfield(cbreak,1);	/* in cbreak mode, rogue format */
	Bitfield(oneline,1);	/* give inventories 1 line at a time */
	Bitfield(time,1);	/* display elapsed 'time' */
	Bitfield(nonews,1);	/* suppress news printing */
	Bitfield(notombstone,1);
 	unsigned end_top, end_around;	/* describe desired score list */
	Bitfield(end_own,1);		/* idem (list all own scores) */
	Bitfield(no_rest_on_space,1);	/* spaces are ignored */
	Bitfield(move,1);
	Bitfield(mv,1);
	Bitfield(run,3);	/* 0: h (etc), 1: H (etc), 2: fh (etc) */
				/* 3: FH, 4: ff+, 5: ff-, 6: FF+, 7: FF- */
	Bitfield(nopick,1);	/* do not pickup objects */
	Bitfield(echo,1);	/* 1 to echo characters */
	Bitfield(botl,1);	/* partially redo status line */
	Bitfield(botlx,1);	/* print an entirely new bottom line */
	Bitfield(nscrinh,1);	/* inhibit nscr() in pline(); */
};
extern struct flag flags;

struct prop {
#define   TIMEOUT      007777   /* mask */
#define   LEFT_RING   W_RINGL   /* 010000L */
#define   RIGHT_RING   W_RINGR   /* 020000L */
#define   INTRINSIC   040000L
#define   LEFT_SIDE   LEFT_RING
#define   RIGHT_SIDE   RIGHT_RING
#define   BOTH_SIDES   (LEFT_SIDE | RIGHT_SIDE)
   long p_flgs;
   int (*p_tofn)();   /* called after timeout */
};

struct you {
   xchar ux, uy;
   schar dx, dy;      /* direction of fast move */
#ifdef QUEST
   schar di;      /* direction of FF */
   xchar ux0, uy0;      /* initial position FF */
#endif QUEST
   xchar udisx, udisy;   /* last display pos */
   char usym;      /* usually '@' */
   schar uluck;
   int last_str_turn:3;   /* 0: none, 1: half turn, 2: full turn */
            /* +: turn right, -: turn left */
   Bitfield(udispl,1);   /* @ on display */
   Bitfield(ulevel,5);
#ifdef QUEST
   Bitfield(uhorizon,7);
#endif QUEST
   Bitfield(utrap,3);   /* trap timeout */
   Bitfield(utraptype,1);   /* defined if utrap nonzero */
#define   TT_BEARTRAP   0
#define   TT_PIT      1
   Bitfield(uinshop,1);


/* perhaps these #define's should also be generated by makedefs */
#define   TELEPAT      LAST_RING      /* not a ring */
#define   Telepat      u.uprops[TELEPAT].p_flgs
#define   FAST      (LAST_RING+1)      /* not a ring */
#define   Fast      u.uprops[FAST].p_flgs
#define   CONFUSION   (LAST_RING+2)      /* not a ring */
#define   Confusion   u.uprops[CONFUSION].p_flgs
#define   INVIS      (LAST_RING+3)      /* not a ring */
#define   Invis      u.uprops[INVIS].p_flgs
#define   GLIB      (LAST_RING+4)      /* not a ring */
#define   Glib      u.uprops[GLIB].p_flgs
#define   PUNISHED   (LAST_RING+5)      /* not a ring */
#define   Punished   u.uprops[PUNISHED].p_flgs
#define   SICK      (LAST_RING+6)      /* not a ring */
#define   Sick      u.uprops[SICK].p_flgs
#define   BLIND      (LAST_RING+7)      /* not a ring */
#define   Blind      u.uprops[BLIND].p_flgs
#define   WOUNDED_LEGS   (LAST_RING+8)      /* not a ring */
#define Wounded_legs   u.uprops[WOUNDED_LEGS].p_flgs
#define PROP(x) (x-RIN_ADORNMENT)       /* convert ring to index in uprops */
   Bitfield(umconf,1);
   char *usick_cause;
   struct prop uprops[LAST_RING+9];

   Bitfield(uswallow,1);      /* set if swallowed by a monster */
   Bitfield(uswldtim,4);      /* time you have been swallowed */
   Bitfield(uhs,3);         /* hunger state - see hack.eat.c */
   schar ustr,ustrmax;
   schar udaminc;
   schar uac;
   int uhp,uhpmax;
   long int ugold,ugold0,uexp,urexp;
   int uhunger;         /* refd only in eat.c and shk.c */
   int uinvault;
   struct monst *ustuck;
   int nr_killed[CMNUM+2];      /* used for experience bookkeeping */
};

extern struct you u;

extern char *traps[];
extern char *plur(), *monnam(), *Monnam(), *amonnam(), *Amonnam(),
   *doname(), *aobjnam();
extern char readchar();
extern char vowels[];

extern xchar curx,cury;   /* cursor location on screen */

extern coord bhitpos;   /* place where thrown weapon falls to the ground */

extern xchar seehx,seelx,seehy,seely; /* where to see*/
extern char *save_cm,*killer;

extern xchar dlevel, maxdlevel; /* dungeon level */

extern long moves;

extern int multi;


extern char lock[];


#define DIST(x1,y1,x2,y2)       (((x1)-(x2))*((x1)-(x2)) + ((y1)-(y2))*((y1)-(y2)))

#define   PL_CSIZ      20   /* sizeof pl_character */
#define   MAX_CARR_CAP   120   /* so that boulders can be heavier */
#define   FAR   (COLNO+2)   /* position outside screen */
#file hack.mfndpos.h
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */



#define	ALLOW_TRAPS	0777

#define	ALLOW_U		01000

#define	ALLOW_M		02000

#define	ALLOW_TM	04000

#define	ALLOW_ALL	(ALLOW_U | ALLOW_M | ALLOW_TM | ALLOW_TRAPS)

#define	ALLOW_SSM	010000

#define	ALLOW_ROCK	020000

#define	NOTONL		040000

#define	NOGARLIC	0100000

#file hack.onames.h
#define	STRANGE_OBJECT	0

#define	AMULET_OF_YENDOR	1

#define	FOOD_RATION	2

#define	TRIPE_RATION	3

#define	PANCAKE	4

#define	DEAD_LIZARD	5

#define	FORTUNE_COOKIE	6

#define	CARROT	7

#define	TIN	8

#define	ORANGE	9

#define	APPLE	10

#define	PEAR	11

#define	MELON	12

#define	BANANA	13

#define	CANDY_BAR	14

#define	EGG	15

#define	CLOVE_OF_GARLIC	16

#define	DEAD_HUMAN	17

#define	DEAD_GIANT_ANT	18

#define	DEAD_GIANT_BAT	19

#define	DEAD_CENTAUR	20

#define	DEAD_DRAGON	21

#define	DEAD_FLOATING_EYE	22

#define	DEAD_FREEZING_SPHERE	23

#define	DEAD_GNOME	24

#define	DEAD_HOBGOBLIN	25

#define	DEAD_STALKER	26

#define	DEAD_JACKAL	27

#define	DEAD_KOBOLD	28

#define	DEAD_LEPRECHAUN	29

#define	DEAD_MIMIC	30

#define	DEAD_NYMPH	31

#define	DEAD_ORC	32

#define	DEAD_PURPLE_WORM	33

#define	DEAD_QUASIT	34

#define	DEAD_RUST_MONSTER	35

#define	DEAD_SNAKE	36

#define	DEAD_TROLL	37

#define	DEAD_UMBER_HULK	38

#define	DEAD_VAMPIRE	39

#define	DEAD_WRAITH	40

#define	DEAD_XORN	41

#define	DEAD_YETI	42

#define	DEAD_ZOMBIE	43

#define	DEAD_ACID_BLOB	44

#define	DEAD_GIANT_BEETLE	45

#define	DEAD_COCKATRICE	46

#define	DEAD_DOG	47

#define	DEAD_ETTIN	48

#define	DEAD_FOG_CLOUD	49

#define	DEAD_GELATINOUS_CUBE	50

#define	DEAD_HOMUNCULUS	51

#define	DEAD_IMP	52

#define	DEAD_JAGUAR	53

#define	DEAD_KILLER_BEE	54

#define	DEAD_LEOCROTTA	55

#define	DEAD_MINOTAUR	56

#define	DEAD_NURSE	57

#define	DEAD_OWLBEAR	58

#define	DEAD_PIERCER	59

#define	DEAD_QUIVERING_BLOB	60

#define	DEAD_GIANT_RAT	61

#define	DEAD_GIANT_SCORPION	62

#define	DEAD_TENGU	63

#define	DEAD_UNICORN	64

#define	DEAD_VIOLET_FUNGI	65

#define	DEAD_LONG_WORM	66

#define	DEAD_XAN	67

#define	DEAD_YELLOW_LIGHT	68

#define	DEAD_ZRUTY	69

#define	ARROW	70

#define	SLING_BULLET	71

#define	CROSSBOW_BOLT	72

#define	DART	73

#define	ROCK	74

#define	BOOMERANG	75

#define	MACE	76

#define	AXE	77

#define	FLAIL	78

#define	LONG_SWORD	79

#define	TWO_HANDED_SWORD	80

#define	DAGGER	81

#define	WORM_TOOTH	82

#define	CRYSKNIFE	83

#define	SPEAR	84

#define	BOW	85

#define	SLING	86

#define	CROSSBOW	87

#define	WHISTLE	88

#define	MAGIC_WHISTLE	89

#define	EXPENSIVE_CAMERA	90

#define	ICE_BOX	91

#define	HEAVY_IRON_BALL	92

#define	IRON_CHAIN	93

#define	ENORMOUS_ROCK	94

#define	HELMET	95

#define	PLATE_MAIL	96

#define	SPLINT_MAIL	97

#define	BANDED_MAIL	98

#define	CHAIN_MAIL	99

#define	SCALE_MAIL	100

#define	RING_MAIL	101

#define	STUDDED_LEATHER_ARMOR	102

#define	LEATHER_ARMOR	103

#define	ELVEN_CLOAK	104

#define	SHIELD	105

#define	PAIR_OF_GLOVES	106

#define	POT_RESTORE_STRENGTH	107

#define	POT_BOOZE	108

#define	POT_INVISIBILITY	109

#define	POT_FRUIT_JUICE	110

#define	POT_HEALING	111

#define	POT_PARALYSIS	112

#define	POT_MONSTER_DETECTION	113

#define	POT_OBJECT_DETECTION	114

#define	POT_SICKNESS	115

#define	POT_CONFUSION	116

#define	POT_GAIN_STRENGTH	117

#define	POT_SPEED	118

#define	POT_BLINDNESS	119

#define	POT_GAIN_LEVEL	120

#define	POT_EXTRA_HEALING	121

#define	POT_LEVITATION	122

#define	SCR_ENCHANT_ARMOR	127

#define	SCR_DESTROY_ARMOR	128

#define	SCR_CONFUSE_MONSTER	129

#define	SCR_SCARE_MONSTER	130

#define	SCR_BLANK_PAPER	131

#define	SCR_REMOVE_CURSE	132

#define	SCR_ENCHANT_WEAPON	133

#define	SCR_DAMAGE_WEAPON	134

#define	SCR_CREATE_MONSTER	135

#define	SCR_TAMING	136

#define	SCR_GENOCIDE	137

#define	SCR_LIGHT	138

#define	SCR_TELEPORTATION	139

#define	SCR_GOLD_DETECTION	140

#define	SCR_FOOD_DETECTION	141

#define	SCR_IDENTIFY	142

#define	SCR_MAGIC_MAPPING	143

#define	SCR_AMNESIA	144

#define	SCR_FIRE	145

#define	SCR_PUNISHMENT	146

#define	WAN_LIGHT	151

#define	WAN_SECRET_DOOR_DETECTION	152

#define	WAN_CREATE_MONSTER	153

#define	WAN_WISHING	154

#define	WAN_STRIKING	155

#define	WAN_SLOW_MONSTER	156

#define	WAN_SPEED_MONSTER	157

#define	WAN_UNDEAD_TURNING	158

#define	WAN_POLYMORPH	159

#define	WAN_CANCELLATION	160

#define	WAN_TELEPORT_MONSTER	161

#define	WAN_MAKE_INVISIBLE	162

#define	WAN_DIGGING	163

#define	WAN_MAGIC_MISSILE	164

#define	WAN_FIRE	165

#define	WAN_SLEEP	166

#define	WAN_COLD	167

#define	WAN_DEATH	168

#define	Adornment	u.uprops[0].p_flgs

#define	RIN_ADORNMENT	172

#define	Teleportation	u.uprops[1].p_flgs

#define	RIN_TELEPORTATION	173

#define	Regeneration	u.uprops[2].p_flgs

#define	RIN_REGENERATION	174

#define	Searching	u.uprops[3].p_flgs

#define	RIN_SEARCHING	175

#define	See_invisible	u.uprops[4].p_flgs

#define	RIN_SEE_INVISIBLE	176

#define	Stealth	u.uprops[5].p_flgs

#define	RIN_STEALTH	177

#define	Levitation	u.uprops[6].p_flgs

#define	RIN_LEVITATION	178

#define	Poison_resistance	u.uprops[7].p_flgs

#define	RIN_POISON_RESISTANCE	179

#define	Aggravate_monster	u.uprops[8].p_flgs

#define	RIN_AGGRAVATE_MONSTER	180

#define	Hunger	u.uprops[9].p_flgs

#define	RIN_HUNGER	181

#define	Fire_resistance	u.uprops[10].p_flgs

#define	RIN_FIRE_RESISTANCE	182

#define	Cold_resistance	u.uprops[11].p_flgs

#define	RIN_COLD_RESISTANCE	183

#define	Protection_from_shape_changers	u.uprops[12].p_flgs

#define	RIN_PROT_SHAPE_CHANGERS	184

#define	Conflict	u.uprops[13].p_flgs

#define	RIN_CONFLICT	185

#define	Gain_strength	u.uprops[14].p_flgs

#define	RIN_GAIN_STRENGTH	186

#define	Increase_damage	u.uprops[15].p_flgs

#define	RIN_INCREASE_DAMAGE	187

#define	Protection	u.uprops[16].p_flgs

#define	RIN_PROTECTION	188

#define	Warning	u.uprops[17].p_flgs

#define	RIN_WARNING	189

#define	Teleport_control	u.uprops[18].p_flgs

#define	RIN_TELEPORT_CONTROL	190

#define	DIAMOND	193

#define	RUBY	194

#define	SAPPHIRE	195

#define	EMERALD	196

#define	TURQUOISE	197

#define	AQUAMARINE	198

#define	TOURMALINE	199

#define	TOPAZ	200

#define	OPAL	201

#define	GARNET	202

#define	AMETHYST	203

#define	AGATE	204

#define	ONYX	205

#define	JASPER	206

#define	JADE	207

/* #define WORTHLESS_PIECE_OF_BLUE_GLASS	208 */

/* #define WORTHLESS_PIECE_OF_RED_GLASS	209 */

/* #define WORTHLESS_PIECE_OF_YELLOW_GLASS	210 */

/* #define WORTHLESS_PIECE_OF_GREEN_GLASS	211 */



#define	CORPSE	DEAD_HUMAN

#define	LAST_GEM	(JADE+1)

#define	LAST_RING	19

#define	NROFOBJECTS	211

#file mklev.h
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "config.h"

/* we are not BSD or system V */
/* #ifdef BSD                   */
/* #include <strings.h>      /* declarations for strcat etc. */
/* #else                        */
/* #include <string.h>      /* idem on System V */
/* #define   index   strchr     */
/* #define   rindex   strrchr   */
/* #endif BSD                   */

#include   "def.objclass.h"

typedef struct {
   xchar x,y;
} coord;

#include   "def.monst.h"   /* uses coord */
#include   "def.gen.h"
#include   "def.obj.h"

extern char ismklev;
extern char *sprintf();

#define   BUFSZ   256   /* for getlin buffers */
#define   PL_NSIZ   32   /* name of player, ghost, shopkeeper */

#define   HWALL 1   /* Level location types */
#define   VWALL 2
#define   SDOOR 3
#define   SCORR 4
#define   LDOOR 5
#define   DOOR 6   /* smallest accessible type */
#define   CORR 7
#define   ROOM 8
#define   STAIRS 9
#ifdef QUEST
#define   CORR_SYM   ':'
#else
#define   CORR_SYM   '#'
#endif QUEST

#define   ERRCHAR   '{'

#define TRAPNUM 9

struct rm {
   char scrsym;
/*   unsigned typ:5; */
/*   unsigned new:1; */
/*   unsigned seen:1;*/
/*   unsigned lit:1; */
   char typ;
   char new;
   char seen;
   char lit;
};
extern struct rm levl[COLNO][ROWNO];

#ifndef QUEST
struct mkroom {
   xchar lx,hx,ly,hy;
   schar rtype,rlit,doorct,fdoor;
};
#define   MAXNROFROOMS   15
extern struct mkroom rooms[MAXNROFROOMS+1];
#define   DOORMAX   100
extern coord doors[DOORMAX];
#endif QUEST


#include   "def.permonst.h"
extern struct permonst mons[];
#define PM_ACIDBLOB	&mons[7]
#define PM_PIERC	&mons[17]
#define PM_MIMIC	&mons[37]
#define PM_CHAM		&mons[47]
#define PM_DEMON	&mons[54]
#define PM_MINOTAUR	&mons[55]	/* last in mons array */
#define PM_SHK		&mons[56]	/* very last */
#define PM_GHOST	&mons[57]	/* for ghosts in saved files */
#define PM_LI_DOG	&mons[58]	/* little dogs to be saved */
#define PM_DOG		&mons[59]	/* medium sized dog */
#define PM_LA_DOG	&mons[60]	/* large sized dog */
#define PMONCOUNT	61		/* number of monsters total */
#define CMNUM		55		/* number of common monsters */

extern long *alloc();

extern xchar xdnstair, ydnstair, xupstair, yupstair; /* stairs up and down */

extern xchar dlevel;
#ifdef WIZARD
extern boolean wizard;
#endif WIZARD
#define   newstring(x)   (char *) alloc((unsigned)(x))

jcz@ncsu.UUCP (John A. Toebes, VIII) (02/20/86)

#file alloc.c
#ifdef LINT

/*
   a ridiculous definition, suppressing
   "possible pointer alignment problem" for (long *) malloc()
   "enlarg defined but never used"
   "ftell defined (in <stdio.h>) but never used"
   from lint
*/
#include <stdio.h>
long *
alloc(n) unsigned n; {
long dummy = ftell(stderr);
   if(n) dummy = 0;   /* make sure arg is used */
   return(&dummy);
}

#else

extern char *malloc();
/* extern char *realloc(); */

long *
alloc(lth)
register unsigned lth;
{
   register char *ptr;

   if(!(ptr = malloc(lth)))
      panic("Cannot get %d bytes", lth);
   return((long *) ptr);
}

long *
enlarge(ptr,lth)
register char *ptr;
register unsigned lth;
{
   register char *nptr;

   nptr = alloc(lth);
   movmem(ptr,nptr,lth);
   free(ptr);
   return((long *) nptr);
}

#endif LINT
#file hack.apply.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.apply.c version 1.0.1 - "The flash awakens %s" (riv05!a3) */

#include	"hack.h"
extern struct monst *bchit();
extern struct obj *addinv();
extern char pl_character[];

doapply() {
register struct obj *obj;
	obj = getobj("(", "use or apply");
	if(!obj) return(0);
	switch(obj->otyp){
	case EXPENSIVE_CAMERA:
		use_camera(obj); break;
	case ICE_BOX:
		use_ice_box(obj); break;
	case MAGIC_WHISTLE:
		if(pl_character[0] == 'W' || u.ulevel > 9) {
			use_magic_whistle(obj);
			break;
		}
		/* fall into next case */
	case WHISTLE:
		use_whistle(obj); break;
	default:
		pline("Sorry, I don't know how to use that.");
		return(0);
	}
	return(1);
}

/* ARGSUSED */
use_camera(obj) /* register */ struct obj *obj; {
register struct monst *mtmp;
	if(!getdir()){
		flags.move = multi = 0;
		return;
	}
	if(mtmp = bchit(u.dx, u.dy, COLNO, '!')) {
		if(mtmp->msleep){
			mtmp->msleep = 0;
			pline("The flash awakens %s.", monnam(mtmp));
		} else
		if(mtmp->data->mlet != 'y')
		if(mtmp->mcansee || mtmp->mblinded){
			register int tmp = dist(mtmp->mx,mtmp->my);
			register int tmp2;
			/* if(cansee(mtmp->mx,mtmp->my)) */
			  pline("%s is blinded by the flash!",Monnam(mtmp));
			setmangry(mtmp);
			if(tmp < 9 && !mtmp->isshk && !rn2(4))
				mtmp->mflee = 1;
			if(tmp < 3) mtmp->mcansee  = mtmp->mblinded = 0;
			else {
				tmp2 = mtmp->mblinded;
				tmp2 += rnd(1 + 50/tmp);
				if(tmp2 > 127) tmp2 = 127;
				mtmp->mblinded = tmp2;
				mtmp->mcansee = 0;
			}
		}
	}
}

struct obj *current_ice_box;	/* a local variable of use_ice_box, to be
				used by its local procedures in/ck_ice_box */
in_ice_box(obj) register struct obj *obj; {
	if(obj == current_ice_box ||
		(Punished && (obj == uball || obj == uchain))){
		pline("You must be kidding.");
		return(0);
	}
	if(obj->owornmask & (W_ARMOR | W_RING)) {
		pline("You cannot refrigerate something you are wearing.");
		return(0);
	}
	if(obj->owt + current_ice_box->owt > 70) {
		pline("It won't fit.");
		return(1);	/* be careful! */
	}
	if(obj == uwep) {
		if(uwep->cursed) {
			pline("Your weapon is welded to your hand!");
			return(0);
		}
		setuwep((struct obj *) 0);
	}
	current_ice_box->owt += obj->owt;
	freeinv(obj);
	obj->o_cnt_id = current_ice_box->o_id;
	obj->nobj = fcobj;
	fcobj = obj;
	obj->age = moves - obj->age;	/* actual age */
	return(1);
}

ck_ice_box(obj) register struct obj *obj; {
	return(obj->o_cnt_id == current_ice_box->o_id);
}

out_ice_box(obj) register struct obj *obj; {
register struct obj *otmp;
	if(obj == fcobj) fcobj = fcobj->nobj;
	else {
		for(otmp = fcobj; otmp->nobj != obj; otmp = otmp->nobj)
			if(!otmp->nobj) panic("out_ice_box");
		otmp->nobj = obj->nobj;
	}
	current_ice_box->owt -= obj->owt;
	obj->age = moves - obj->age;	/* simulated point of time */
	(void) addinv(obj);
}

use_ice_box(obj) register struct obj *obj; {
register int cnt = 0;
register struct obj *otmp;
	current_ice_box = obj;	/* for use by in/out_ice_box */
	for(otmp = fcobj; otmp; otmp = otmp->nobj)
		if(otmp->o_cnt_id == obj->o_id)
			cnt++;
	if(!cnt) pline("Your ice-box is empty.");
	else {
	    pline("Do you want to take something out of the ice-box? [yn] ");
	    if(readchar() == 'y')
		if(askchain(fcobj, (char *) 0, 0, out_ice_box, ck_ice_box, 0))
		    return;
		pline("That was all. Do you wish to put something in? [yn] ");
		if(readchar() != 'y') return;
	}
	/* call getobj: 0: allow cnt; #: allow all types; %: expect food */
	otmp = getobj("0#%", "put in");
	if(!otmp || !in_ice_box(otmp))
		flags.move = multi = 0;
}

struct monst *
bchit(ddx,ddy,range,sym) register int ddx,ddy,range; char sym; {
	register struct monst *mtmp = (struct monst *) 0;
	register int bchx = u.ux, bchy = u.uy;

	if(sym) Tmp_at(-1, sym);	/* open call */
	while(range--) {
		bchx += ddx;
		bchy += ddy;
		if(mtmp = m_at(bchx,bchy))
			break;
		if(levl[bchx][bchy].typ < CORR) {
			bchx -= ddx;
			bchy -= ddy;
			break;
		}
		if(sym) Tmp_at(bchx, bchy);
	}
	if(sym) Tmp_at(-1, -1);
	return(mtmp);
}

#include	"def.edog.h"
/* ARGSUSED */
use_whistle(obj) struct obj *obj; {
register struct monst *mtmp = fmon;
	pline("You produce a high whistling sound.");
	while(mtmp) {
		if(dist(mtmp->mx,mtmp->my) < u.ulevel*10) {
			if(mtmp->msleep)
				mtmp->msleep = 0;
			if(mtmp->mtame)
				EDOG(mtmp)->whistletime = moves;
		}
		mtmp = mtmp->nmon;
	}
}

/* ARGSUSED */
use_magic_whistle(obj) struct obj *obj; {
register struct monst *mtmp = fmon;
	pline("You produce a strange whistling sound.");
	while(mtmp) {
		if(mtmp->mtame) mnexto(mtmp);
		mtmp = mtmp->nmon;
	}
}
#file hack.bones.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "hack.h"
extern char plname[PL_NSIZ];
extern struct monst *makemon();

char bones[] = "bones_xx";

/* save bones and possessions of a deceased adventurer */
savebones(){
register int fd;
register struct obj *otmp;
register struct gen *gtmp;
register struct monst *mtmp;
	if(!rn2(1 + dlevel/2)) return;	/* not so many ghosts on low levels */
	bones[6] = '0' + (dlevel/10);
	bones[7] = '0' + (dlevel%10);
	if((fd = open(bones,0)) >= 0){
		(void) close(fd);
		return;
	}
	/* drop everything; the corpse's possessions are usually cursed */
	otmp = invent;
	while(otmp){
		otmp->ox = u.ux;
		otmp->oy = u.uy;
		otmp->known = 0;
		otmp->age = 0;		/* very long ago */
		otmp->owornmask = 0;
		if(rn2(5)) otmp->cursed = 1;
		if(!otmp->nobj){
			otmp->nobj = fobj;
			fobj = invent;
			invent = 0;	/* superfluous */
			break;
		}
		otmp = otmp->nobj;
	}
	if(!(mtmp = makemon(PM_GHOST, u.ux, u.uy))) return;
	mtmp->mx = u.ux;
	mtmp->my = u.uy;
	mtmp->msleep = 1;
	(void) strcpy((char *) mtmp->mextra, plname);
	mkgold(somegold() + d(dlevel,30), u.ux, u.uy);
	u.ux = FAR;		/* avoid animals standing next to us */
	keepdogs();		/* all tame animals become wild again */
	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
		mtmp->mlstmv = 0;
		if(mtmp->mdispl) unpmon(mtmp);
	}
	for(gtmp = ftrap; gtmp; gtmp = gtmp->ngen)
		gtmp->gflag &= ~SEEN;
	for(otmp = fobj; otmp; otmp = otmp->nobj)
		otmp->onamelth = 0;
	if((fd = creat(bones, FMASK)) < 0) return;
	savelev(fd);
	(void) close(fd);
}

getbones(){
register int fd,x,y,ok;
	if(rn2(3)) return(0);	/* only once in three times do we find bones */
	bones[6] = '0' + dlevel/10;
	bones[7] = '0' + dlevel%10;
	if((fd = open(bones, 0)) < 0) return(0);
	if((ok = uptodate(fd)) != 0){
		(void) getlev(fd);
		(void) close(fd);
		for(x = 0; x < COLNO; x++) for(y = 0; y < ROWNO; y++)
			levl[x][y].seen = levl[x][y].new = 0;
	}
	if(unlink(bones) < 0){
		pline("Cannot unlink %s", bones);
		return(0);
	}
	return(ok);
}
#file hack.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.c version 1.0.1 - many small and unimportant changes */
#include "hack.h"
#include <stdio.h>


extern char news0();
extern char *nomovemsg;
extern char *exclam();
extern struct obj *addinv();
extern boolean hmon();



/* called on movement:
	1. when throwing ball+chain far away
	2. when teleporting
	3. when walking out of a lit room
 */
unsee() {
	register int x,y;
	register struct rm *lev;

/*
	if(u.udispl){
		u.udispl = 0;
		newsym(u.udisx, u.udisy);
	}
*/
#ifndef QUEST
	if(seehx){
		seehx = 0;
	} else
#endif QUEST
	for(x = u.ux-1; x < u.ux+2; x++)
	  for(y = u.uy-1; y < u.uy+2; y++) {
		lev = &levl[x][y];
		if(!lev->lit && lev->scrsym == '.') {
			lev->scrsym =' ';
			lev->new = 1;
			on_scr(x,y);
		}
	}
}

/* called:
	in hack.eat.c: seeoff(0) - blind after eating rotten food
	in hack.mon.c: seeoff(0) - blinded by a yellow light
	in hack.mon.c: seeoff(1) - swallowed
	in hack.do.c:  seeoff(0) - blind after drinking potion
	in hack.do.c:  seeoff(1) - go up or down the stairs
	in hack.trap.c:seeoff(1) - fall through trapdoor
 */
seeoff(mode)	/* 1 to redo @, 0 to leave them */
{	/* 1 means misc movement, 0 means blindness */
	register int x,y;
	register struct rm *lev;

	if(u.udispl && mode){
		u.udispl = 0;
		levl[u.udisx][u.udisy].scrsym = news0(u.udisx,u.udisy);
	}
#ifndef QUEST
	if(seehx) {
		seehx = 0;
	} else
#endif QUEST
	if(!mode) {
		for(x = u.ux-1; x < u.ux+2; x++)
			for(y = u.uy-1; y < u.uy+2; y++) {
				lev = &levl[x][y];
				if(!lev->lit && lev->scrsym == '.')
					lev->seen = 0;
			}
	}
}

/* 'rogue'-like direction commands */
char sdir[] = "hykulnjb";
schar xdir[8] = { -1,-1,0,1,1,1,0,-1 };
schar ydir[8] = { 0,-1,-1,-1,0,1,1,1 };

movecm(cmd)
register char *cmd;
{
register char *dp;
		if(!(dp = index(sdir, *cmd))) return(0);
		u.dx = xdir[dp-sdir];
		u.dy = ydir[dp-sdir];
		return(1);
}
getdir()
{
	char buf[2];
	register int x;

	pline("What direction?");
	buf[0] = readchar();
	buf[1] = 0;
	x = movecm(buf);
	if(x && Confusion) confdir();
	return(x);
}

confdir()
{
	register int x = rn2(8);
	u.dx = xdir[x];
	u.dy = ydir[x];
}

#ifdef QUEST
finddir(){
register int i, ui = u.di;
	for(i = 0; i <= 8; i++){
		if(flags.run & 1) ui++; else ui += 7;
		ui %= 8;
		if(i == 8){
			pline("Not near a wall.");
			flags.move = multi = 0;
			return(0);
		}
		if(!isroom(u.ux+xdir[ui], u.uy+ydir[ui]))
			break;
	}
	for(i = 0; i <= 8; i++){
		if(flags.run & 1) ui += 7; else ui++;
		ui %= 8;
		if(i == 8){
			pline("Not near a room.");
			flags.move = multi = 0;
			return(0);
		}
		if(isroom(u.ux+xdir[ui], u.uy+ydir[ui]))
			break;
	}
	u.di = ui;
	u.dx = xdir[ui];
	u.dy = ydir[ui];
}

isroom(x,y)  register int x,y; {
	return(isok(x,y) && (levl[x][y].typ == ROOM ||
				(levl[x][y].typ >= LDOOR && flags.run >= 6)));
}
#endif QUEST

isok(x,y) register int x,y; {
	return(x >= 0 && x <= COLNO-1 && y >= 0 && y <= ROWNO-1);
}

domove()
{
	xchar oldx,oldy;
	register struct monst *mtmp;
	register struct rm *tmpr,*ust;
	struct gen *trap;
	register struct obj *otmp;

	if(!u.uswallow)
		wipe_engr_at(u.ux, u.uy, rnd(5));
	if(inv_weight() > 0){
		pline("You collapse under your load.");
		nomul(0);
		return;
	}
	if(u.uswallow) {
		u.dx = u.dy = 0;
		u.ux = u.ustuck->mx;
		u.uy = u.ustuck->my;
	} else {
		if(Confusion) {
			do {
				confdir();
			} while(!isok(u.ux+u.dx, u.uy+u.dy) ||
				levl[u.ux+u.dx][u.uy+u.dy].typ < DOOR);
		}
		if(!isok(u.ux+u.dx, u.uy+u.dy)){
			nomul(0);
			return;
		}
	}

	ust = &levl[u.ux][u.uy];
	oldx = u.ux;
	oldy = u.uy;
	if(!u.uswallow)
	    if(trap = g_at(u.ux+u.dx,u.uy+u.dy,ftrap)) {
		if(trap->gflag & SEEN) nomul(0);
	}
	if(u.ustuck && !u.uswallow && (u.ux+u.dx != u.ustuck->mx ||
		u.uy+u.dy != u.ustuck->my)) {
		if(dist(u.ustuck->mx, u.ustuck->my) > 2){
			/* perhaps it fled (or was teleported or ... ) */
			u.ustuck = 0;
		} else {
			if(Blind) pline("You cannot escape from it!");
			else pline("You cannot escape from %s!.",
				monnam(u.ustuck));
			nomul(0);
			return;
		}
	}
	if(u.uswallow || (mtmp = m_at(u.ux+u.dx,u.uy+u.dy))) {
	/* attack monster */
		schar tmp;
		boolean malive = TRUE;
		register struct permonst *mdat;

		nomul(0);
		gethungry();
		if(multi < 0) return;	/* we just fainted */
		if(u.uswallow) mtmp = u.ustuck;
		mdat = mtmp->data;
		if(mdat->mlet == 'L' && !mtmp->mfroz && !mtmp->msleep &&
		   !mtmp->mconf && mtmp->mcansee && !rn2(7) &&
		   (m_move(mtmp, 0) == 2 /* he died */ || /* he moved: */
			mtmp->mx != u.ux+u.dx || mtmp->my != u.uy+u.dy))
			goto nomon;
		if(mtmp->mimic){
			if(!u.ustuck && !mtmp->mflee) u.ustuck = mtmp;
			switch(levl[u.ux+u.dx][u.uy+u.dy].scrsym){
			case '+':
				pline("The door actually was a Mimic.");
				break;
			case '$':
				pline("The chest was a Mimic!");
				break;
			default:
				pline("Wait! That's a Mimic!");
			}
			wakeup(mtmp);	/* clears mtmp->mimic */
			return;
		}
		wakeup(mtmp);	/* clears mtmp->mimic */
		if(mtmp->mhide && mtmp->mundetected){
			register struct obj *obj;
			mtmp->mundetected = 0;
			if((obj = o_at(mtmp->mx,mtmp->my)) && !Blind)
				pline("Wait! There's a %s hiding under %s!",
					mdat->mname, doname(obj));
			return;
		}
		tmp = u.uluck + u.ulevel + mdat->ac + abon();
		if(uwep) {
			if(uwep->olet == WEAPON_SYM)
				tmp += uwep->spe;
			if(uwep->otyp == TWO_HANDED_SWORD) tmp -= 1;
			else if(uwep->otyp == DAGGER) tmp += 2;
			else if(uwep->otyp == CRYSKNIFE) tmp += 3;
			else if(uwep->otyp == SPEAR &&
				index("XDne", mdat->mlet)) tmp += 2;
		}
		if(mtmp->msleep) {
			mtmp->msleep = 0;
			tmp += 2;
		}
		if(mtmp->mfroz) {
			tmp += 4;
			if(!rn2(10)) mtmp->mfroz = 0;
		}
		if(mtmp->mflee) tmp += 2;
		if(u.utrap) tmp -= 3;
		if(tmp <= rnd(20) && !u.uswallow){
			if(Blind) pline("You miss it.");
			else pline("You miss %s.",monnam(mtmp));
		} else {
			/* we hit the monster; be careful: it might die! */

			if((malive = hmon(mtmp,uwep,0)) == TRUE) {
				/* monster still alive */
				if(!rn2(25) && mtmp->mhp < mtmp->orig_hp/2) {
					mtmp->mflee = 1;
					if(u.ustuck == mtmp && !u.uswallow)
						u.ustuck = 0;
				}
#ifndef NOWORM
				if(mtmp->wormno)
					cutworm(mtmp, u.ux+u.dx, u.uy+u.dy,
						uwep ? uwep->otyp : 0);
#endif NOWORM
			}
			if(mdat->mlet == 'a') {
				if(rn2(2)) {
				pline("You are splashed by the blob's acid!");
					losehp_m(rnd(6), mtmp);
				}
				if(!rn2(6)) corrode_weapon();
				else if(!rn2(60)) corrode_armor();
			}
		}
		if(malive && !Blind && mdat->mlet == 'E' && rn2(3)) {
		    if(mtmp->mcansee) {
		      pline("You are frozen by the floating eye's gaze!");
		      nomul((u.ulevel > 6 || rn2(4)) ? rn1(20,-21) : -200);
		    } else {
		      pline("The blinded floating eye cannot defend itself.");
		      if(!rn2(500)) u.uluck--;
		    }
		}
		return;
	}
nomon:
	/* not attacking an animal, so we try to move */
	if(u.utrap) {
		if(u.utraptype == TT_PIT) {
			pline("You are still in a pit.");
			u.utrap--;
		} else {
			pline("You are caught in a beartrap.");
			if((u.dx && u.dy) || !rn2(5)) u.utrap--;
		}
		return;
	}
	tmpr = &levl[u.ux+u.dx][u.uy+u.dy];
	if((tmpr->typ < DOOR) ||
	   (u.dx && u.dy && (tmpr->typ == DOOR || ust->typ == DOOR))){
		flags.move = 0;
		nomul(0);
		return;
	}
	while(otmp = sobj_at(ENORMOUS_ROCK, u.ux+u.dx, u.uy+u.dy)) {
		register xchar rx = u.ux+2*u.dx, ry = u.uy+2*u.dy;
		register struct gen *gtmp;
		nomul(0);
		if(isok(rx,ry) && (levl[rx][ry].typ > DOOR ||
		    (levl[rx][ry].typ == DOOR && (!u.dx || !u.dy))) &&
		    !sobj_at(ENORMOUS_ROCK, rx, ry)) {
			if(m_at(rx,ry)) {
			    pline("You hear a monster behind the rock.");
			    pline("Perhaps that's why you cannot move it.");
			    return;
			}
			if(gtmp = g_at(rx,ry,ftrap))
#include	"def.trap.h"
			    switch(gtmp->gflag & TRAPTYPE) {
			    case PIT:
				pline("You push the rock into a pit!");
				deltrap(gtmp);
				delobj(otmp);
				pline("It completely fills the pit!");
				continue;
			    case TELEP_TRAP:
				pline("You push the rock and suddenly it disappears!");
				delobj(otmp);
				continue;
			    }
			otmp->ox = rx;
			otmp->oy = ry;
			/* pobj(otmp); */
			if(cansee(rx,ry)) atl(rx,ry,otmp->olet);
			if(Invis) newsym(u.ux+u.dx, u.uy+u.dy);

			{ static long lastmovetime;
			/* note: this var contains garbage initially and
			   after a restore */
			if(moves > lastmovetime+2 || moves < lastmovetime)
			pline("With great effort you move the enormous rock.");
			lastmovetime = moves;
			}
		} else {
		    pline("You try to move the enormous rock, but in vain.");
		    return;
		}
	    }
	if(u.dx && u.dy && levl[u.ux][u.uy+u.dy].typ < DOOR &&
		levl[u.ux+u.dx][u.uy].typ < DOOR &&
		invent && inv_weight()+40 > 0) {
		pline("You are carrying too much to get through.");
		nomul(0);
		return;
	}
	if(Punished &&
	   DIST(u.ux+u.dx, u.uy+u.dy, uchain->ox, uchain->oy) > 2){
		if(carried(uball)) {
			movobj(uchain, u.ux, u.uy);
			goto nodrag;
		}

		if(DIST(u.ux+u.dx, u.uy+u.dy, uball->ox, uball->oy) < 3){
			/* leave ball, move chain under/over ball */
			movobj(uchain, uball->ox, uball->oy);
			goto nodrag;
		}

		if(inv_weight() + (int) uball->owt/2 > 0) {
			pline("You cannot %sdrag the heavy iron ball.",
			invent ? "carry all that and also " : "");
			nomul(0);
			return;
		}

		movobj(uball, uchain->ox, uchain->oy);
		unpobj(uball);		/* BAH %% */
		uchain->ox = u.ux;
		uchain->oy = u.uy;
		nomul(-2);
		nomovemsg = "";
	nodrag:	;
	}
	u.ux += u.dx;
	u.uy += u.dy;
	if(flags.run) {
		if(tmpr->typ == DOOR ||
		(xupstair == u.ux && yupstair == u.uy) ||
		(xdnstair == u.ux && ydnstair == u.uy))
			nomul(0);
	}
/*
	if(u.udispl) {
		u.udispl = 0;
		newsym(oldx,oldy);
	}
*/
	if(!Blind) {
#ifdef QUEST
		setsee();
#else
		if(ust->lit) {
			if(tmpr->lit) {
				if(tmpr->typ == DOOR) prl1(u.ux+u.dx,u.uy+u.dy);
				else if(ust->typ == DOOR) nose1(oldx-u.dx,oldy-u.dy);
			} else {
				unsee();
				prl1(u.ux+u.dx,u.uy+u.dy);
			}
		} else {
			if(tmpr->lit) setsee();
			else {
				prl1(u.ux+u.dx,u.uy+u.dy);
				if(tmpr->typ == DOOR) {
					if(u.dy) {
						prl(u.ux-1,u.uy);
						prl(u.ux+1,u.uy);
					} else {
						prl(u.ux,u.uy-1);
						prl(u.ux,u.uy+1);
					}
				}
			}
			nose1(oldx-u.dx,oldy-u.dy);
		}
#endif QUEST
	} else {
		pru();
	}
	if(!flags.nopick) pickup();
	if(trap) dotrap(trap);		/* fall into pit, arrow trap, etc. */
	(void) inshop();
	if(!Blind) read_engr_at(u.ux,u.uy);
}

movobj(obj, ox, oy)
register struct obj *obj;
register int ox, oy;
{
	/* Some dirty programming to get display right */
	freeobj(obj);
	unpobj(obj);
	obj->nobj = fobj;
	fobj = obj;
	obj->ox = ox;
	obj->oy = oy;
}

dopickup(){
	if(!g_at(u.ux,u.uy,fgold) && !o_at(u.ux,u.uy)) {
		pline("There is nothing here to pick up.");
		return(0);
	}
	if(Levitation) {
		pline("You cannot reach the floor.");
		return(1);
	}
	pickup();
	return(1);
}

pickup(){
register struct gen *gold;
register struct obj *obj, *obj2;
register int wt;
	if(Levitation) return;
	while(gold = g_at(u.ux,u.uy,fgold)) {
		pline("%u gold piece%s.", gold->gflag, plur(gold->gflag));
		u.ugold += gold->gflag;
		flags.botl = 1;
		freegold(gold);
		if(flags.run) nomul(0);
		if(Invis) newsym(u.ux,u.uy);
	}
	for(obj = fobj; obj; obj = obj2) {
	    obj2 = obj->nobj;	/* perhaps obj will be picked up */
	    if(obj->ox == u.ux && obj->oy == u.uy) {
		if(flags.run) nomul(0);

#define	DEAD_c	CORPSE+('c'-'a'+'Z'-'@'+1)
		if(obj->otyp == DEAD_COCKATRICE && !uarmg){
		    pline("Touching the dead cockatrice is a fatal mistake.");
		    pline("You turn to stone.");
		    killer = "cockatrice cadaver";
		    done("died");
		}

		if(obj->otyp == SCR_SCARE_MONSTER){
		  if(!obj->spe) obj->spe = 1;
		  else {
		    /* Note: perhaps the 1st pickup failed: you cannot
			carry anymore, and so we never dropped it -
			let's assume that treading on it twice also
			destroys the scroll */
		    pline("The scroll turns to dust as you pick it up.");
		    delobj(obj);
		    continue;
		  }
		}

		/* do not pick up uchain */
		if(Punished && obj == uchain)
			continue;

		wt = inv_weight() + obj->owt;
		if(wt > 0) {
			if(obj->quan > 1) {
				/* see how many we can lift */
				extern struct obj *splitobj();
				int savequan = obj->quan;
				int iw = inv_weight();
				int qq;
				for(qq = 1; qq < savequan; qq++){
					obj->quan = qq;
					if(iw + weight(obj) > 0)
						break;
				}
				obj->quan = savequan;
				qq--;
				/* we can carry qq of them */
				if(!qq) goto too_heavy;
			pline("You can only carry %s of the %s lying here.",
					(qq == 1) ? "one" : "some",
					doname(obj));
				(void) splitobj(obj, qq);
				/* note: obj2 is set already, so we'll never
				 * encounter the other half; if it should be
				 * otherwise then write
				 *	obj2 = splitobj(obj,qq);
				 */
				goto lift_some;
			}
		too_heavy:
			pline("There %s %s here, but %s.",
				(obj->quan == 1) ? "is" : "are",
				doname(obj),
				!invent ? "it is too heavy for you to lift"
					: "you cannot carry anymore");
			break;
		}
	lift_some:
		if(inv_cnt() >= 52) {
		    pline("Your knapsack cannot accomodate anymore items.");
		    break;
		}
		if(wt > -5) pline("You have a little trouble lifting");
		freeobj(obj);
		if(Invis) newsym(u.ux,u.uy);
		addtobill(obj);       /* sets obj->unpaid if necessary */
		{ int pickquan = obj->quan;
		  int mergquan;
		if(!Blind) obj->dknown = 1;	/* this is done by prinv(),
				 but addinv() needs it already for merging */
		obj = addinv(obj);    /* might merge it with other objects */
		  mergquan = obj->quan;
		  obj->quan = pickquan;	/* to fool prinv() */
		prinv(obj);
		  obj->quan = mergquan;
		}
	    }
	}
}

/* stop running if we see something interesting */
/* turn around a corner if that is the only way we can proceed */
/* do not turn left or right twice */
lookaround(){
register int x,y,i,x0,y0,m0,i0 = 9;
register int corrct = 0, noturn = 0;
register struct monst *mtmp;
#ifdef lint
	/* suppress "used before set" message */
	x0 = y0 = 0;
#endif lint
	if(Blind || flags.run == 0) return;
	if(flags.run == 1 && levl[u.ux][u.uy].typ >= ROOM) return;
#ifdef QUEST
	if(u.ux0 == u.ux+u.dx && u.uy0 == u.uy+u.dy) goto stop;
#endif QUEST
	for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++){
		if(x == u.ux && y == u.uy) continue;
		if(!levl[x][y].typ) continue;
		if((mtmp = m_at(x,y)) && !mtmp->mimic &&
		    (!mtmp->minvis || See_invisible)){
			if(!mtmp->mtame || (x == u.ux+u.dx && y == u.uy+u.dy))
				goto stop;
		} else mtmp = 0; /* invisible M cannot influence us */
		if(x == u.ux-u.dx && y == u.uy-u.dy) continue;
		switch(levl[x][y].scrsym){
		case '|':
		case '-':
		case '.':
		case ' ':
			break;
		case '+':
			if(x != u.ux && y != u.uy) break;
			if(flags.run != 1) goto stop;
			/* fall into next case */
		case CORR_SYM:
		corr:
			if(flags.run == 1 || flags.run == 3) {
				i = DIST(x,y,u.ux+u.dx,u.uy+u.dy);
				if(i > 2) break;
				if(corrct == 1 && DIST(x,y,x0,y0) != 1)
					noturn = 1;
				if(i < i0) {
					i0 = i;
					x0 = x;
					y0 = y;
					m0 = mtmp ? 1 : 0;
				}
			}
			corrct++;
			break;
		case '^':
			if(flags.run == 1) goto corr;	/* if you must */
			if(x == u.ux+u.dx && y == u.uy+u.dx) goto stop;
			break;
		default:	/* e.g. objects or trap or stairs */
			if(flags.run == 1) goto corr;
			if(mtmp) break;		/* d */
		stop:
			nomul(0);
			return;
		}
	}
#ifdef QUEST
	if(corrct > 0 && (flags.run == 4 || flags.run == 5)) goto stop;
#endif QUEST
	if(corrct > 1 && flags.run == 2) goto stop;
	if((flags.run == 1 || flags.run == 3) && !noturn && !m0 && i0 &&
		(corrct == 1 || (corrct == 2 && i0 == 1))) {
		/* make sure that we do not turn too far */
		if(i0 == 2) {
		    if(u.dx == y0-u.uy && u.dy == u.ux-x0)
			i = 2;		/* straight turn right */
		    else
			i = -2;		/* straight turn left */
		} else if(u.dx && u.dy) {
		    if((u.dx == u.dy && y0 == u.uy) ||
			(u.dx != u.dy && y0 != u.uy))
			i = -1;		/* half turn left */
		    else
			i = 1;		/* half turn right */
		} else {
		    if((x0-u.ux == y0-u.uy && !u.dy) ||
			(x0-u.ux != y0-u.uy && u.dy))
			i = 1;		/* half turn right */
		    else
			i = -1;		/* half turn left */
		}
		i += u.last_str_turn;
		if(i <= 2 && i >= -2) {
			u.last_str_turn = i;
			u.dx = x0-u.ux, u.dy = y0-u.uy;
		}
	}
}

#ifdef QUEST
cansee(x,y) xchar x,y; {
register int dx,dy,adx,ady,sdx,sdy,dmax,d;
	if(Blind) return(0);
	if(!isok(x,y)) return(0);
	d = dist(x,y);
	if(d < 3) return(1);
	if(d > u.uhorizon*u.uhorizon) return(0);
	if(!levl[x][y].lit)
		return(0);
	dx = x - u.ux;	adx = abs(dx);	sdx = sgn(dx);
	dy = y - u.uy;  ady = abs(dy);	sdy = sgn(dy);
	if(dx == 0 || dy == 0 || adx == ady){
		dmax = (dx == 0) ? ady : adx;
		for(d = 1; d <= dmax; d++)
			if(!rroom(sdx*d,sdy*d))
				return(0);
		return(1);
	} else if(ady > adx){
		for(d = 1; d <= ady; d++){
			if(!rroom(sdx*( (d*adx)/ady ), sdy*d) ||
			   !rroom(sdx*( (d*adx-1)/ady+1 ), sdy*d))
				return(0);
		}
		return(1);
	} else {
		for(d = 1; d <= adx; d++){
			if(!rroom(sdx*d, sdy*( (d*ady)/adx )) ||
			   !rroom(sdx*d, sdy*( (d*ady-1)/adx+1 )))
				return(0);
		}
		return(1);
	}
}

rroom(x,y) register int x,y; {
	return(levl[u.ux+x][u.uy+y].typ >= ROOM);
}

#else

cansee(x,y) xchar x,y; {
	if(Blind || u.uswallow) return(0);
	if(dist(x,y) < 3) return(1);
	if(levl[x][y].lit && seelx <= x && x <= seehx && seely <= y &&
		y <= seehy) return(1);
	return(0);
}
#endif QUEST

sgn(a) register int a; {
	return((a> 0) ? 1 : (a == 0) ? 0 : -1);
}

pow(num) /* returns 2 to the num */
register unsigned num;
{
	return(1 << num);
}

#ifdef QUEST
setsee()
{
	register int x,y;

	if(Blind) {
		pru();
		return;
	}
	for(y = u.uy-u.uhorizon; y <= u.uy+u.uhorizon; y++)
		for(x = u.ux-u.uhorizon; x <= u.ux+u.uhorizon; x++) {
			if(cansee(x,y))
				prl(x,y);
	}
}

#else

setsee()
{
	register int x,y;

	if(Blind) {
		pru();
		return;
	}
	if(!levl[u.ux][u.uy].lit) {
		seelx = u.ux-1;
		seehx = u.ux+1;
		seely = u.uy-1;
		seehy = u.uy+1;
	} else {
		for(seelx = u.ux; levl[seelx-1][u.uy].lit; seelx--);
		for(seehx = u.ux; levl[seehx+1][u.uy].lit; seehx++);
		for(seely = u.uy; levl[u.ux][seely-1].lit; seely--);
		for(seehy = u.uy; levl[u.ux][seehy+1].lit; seehy++);
	}
	for(y = seely; y <= seehy; y++)
		for(x = seelx; x <= seehx; x++) {
			prl(x,y);
	}
	if(!levl[u.ux][u.uy].lit) seehx = 0; /* seems necessary elsewhere */
	else {
	    if(seely == u.uy) for(x = u.ux-1; x <= u.ux+1; x++) prl(x,seely-1);
	    if(seehy == u.uy) for(x = u.ux-1; x <= u.ux+1; x++) prl(x,seehy+1);
	    if(seelx == u.ux) for(y = u.uy-1; y <= u.uy+1; y++) prl(seelx-1,y);
	    if(seehx == u.ux) for(y = u.uy-1; y <= u.uy+1; y++) prl(seehx+1,y);
	}
}
#endif QUEST

nomul(nval)
register int nval;
{
	if(multi < 0) return;
	multi = nval;
	flags.mv = flags.run = 0;
}

abon()
{
	if(u.ustr == 3) return(-3);
	else if(u.ustr < 6) return(-2);
	else if(u.ustr < 8) return(-1);
	else if(u.ustr < 17) return(0);
	else if(u.ustr < 69) return(1);	/* up to 18/50 */
	else if(u.ustr < 118) return(2);
	else return(3);
}

dbon()
{
	if(u.ustr < 6) return(-1);
	else if(u.ustr < 16) return(0);
	else if(u.ustr < 18) return(1);
	else if(u.ustr == 18) return(2);	/* up to 18 */
	else if(u.ustr < 94) return(3);	/* up to 18/75 */
	else if(u.ustr < 109) return(4);	/* up to 18/90 */
	else if(u.ustr < 118) return(5);	/* up to 18/99 */
	else return(6);
}

losestr(num)
register int num;
{
	u.ustr -= num;
	while(u.ustr < 3) {
		u.ustr++;
		u.uhp -= 6;
		u.uhpmax -= 6;
	}
	flags.botl = 1;
}

losehp(n,knam)
register int n;
register char *knam;
{
	u.uhp -= n;
	if(u.uhp > u.uhpmax)
		u.uhpmax = u.uhp;	/* perhaps n was negative */
	flags.botl = 1;
	if(u.uhp < 1)
		killer = knam;	/* the thing that killed you */
}

losehp_m(n,mtmp)
register int n;
register struct monst *mtmp;
{
	u.uhp -= n;
	flags.botl = 1;
	if(u.uhp < 1) done_in_by(mtmp);
}

losexp()	/* hit by V or W */
{
	register int num;

	if(u.ulevel > 1) pline("Goodbye level %d.",u.ulevel--);
	else u.uhp = -1;
	num = rnd(10);
	u.uhp -= num;
	u.uhpmax -= num;
	u.uexp = 10*pow(u.ulevel-1);
	flags.botl = 1;
}

inv_weight(){
register struct obj *otmp = invent;
register int wt = 0;
register int carrcap = 5*(((u.ustr > 18) ? 20 : u.ustr) + u.ulevel);
	if(carrcap > MAX_CARR_CAP) carrcap = MAX_CARR_CAP;
	if(Wounded_legs & LEFT_SIDE) carrcap -= 10;
	if(Wounded_legs & RIGHT_SIDE) carrcap -= 10;
	while(otmp){
		wt += otmp->owt;
		otmp = otmp->nobj;
	}
	return(wt - carrcap);
}

inv_cnt(){
register struct obj *otmp = invent;
register int ct = 0;
	while(otmp){
		ct++;
		otmp = otmp->nobj;
	}
	return(ct);
}

#file hack.cmdlist.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.cmdlist.c version 1.0.1 - added '^T': dotele() and ',': dopickup() */
#include	"config.h"
#include	"def.objclass.h"
#include	"def.func_tab.h"

int doredraw(),doredotopl(),dodrop(),dodrink(),doread(),dosearch(),dopickup(),
doversion(),doweararm(),dowearring(),doremarm(),doremring(),dopay(),doapply(),
dosave(),dowield(),ddoinv(),dozap(),ddocall(),dowhatis(),doengrave(),dotele(),
dohelp(),doeat(),doddrop(),do_mname(),doidtrap(),doprwep(),doprarm(),doprring();
#ifdef SHELL
int dosh();
#endif SHELL
#ifdef OPTIONS
int doset();
#endif OPTIONS
int doup(), dodown(), done1(), donull();
int dothrow();
struct func_tab list[]={
	'\022', doredraw,
	'\024', dotele,
	'\020', doredotopl,
	'a', doapply,
/*	'A' : UNUSED */
/*	'b', 'B' : go sw */
	'c', ddocall,
	'C', do_mname,
	'd', dodrop,
	'D', doddrop,
	'e', doeat,
	'E', doengrave,
/*	'f', 'F' : multiple go (might become 'fight') */
/*	'g', 'G' : UNUSED */
/*	'h', 'H' : go west */
	'i', ddoinv,
#ifdef CHEATINV
	'I', myddoinv,
#else
        'i', ddoinv,
#endif
/*	'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */
#ifdef OPTIONS
	'o', doset,
#endif OPTIONS
/*	'O' : UNUSED */
	'p', dopay,
	'P', dowearring,
	'q', dodrink,
	'Q', done1,
	'r', doread,
	'R', doremring,
	's', dosearch,
	'S', dosave,
	't', dothrow,
	'T', doremarm,
/*	'u', 'U' : go ne */
	'v', doversion,
/*	'V' : UNUSED */
	'w', dowield,
	'W', doweararm,
/*	'x', 'X' : UNUSED */
/*	'y', 'Y' : go nw */
	'z', dozap,
/*	'Z' : UNUSED */
	'<', doup,
	'>', dodown,
	'/', dowhatis,
	'?', dohelp,
#ifdef SHELL
	'!', dosh,
#endif SHELL
	',', dopickup,
	'.', donull,
	' ', donull,
	'^', doidtrap,
	 WEAPON_SYM,  doprwep,
	 ARMOR_SYM,  doprarm,
	 RING_SYM,  doprring,
	0,0,0
};

#file hack.decl.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */



#include	"hack.h"

char nul[40];			/* contains zeros */

char plname[PL_NSIZ] = "player";/* player name */

char lock[32] = "1lock";	/* long enough for login name */



#ifdef WIZARD

boolean wizard;			/* TRUE when called as  hack -w */

#endif WIZARD



struct rm levl[COLNO][ROWNO];	/* level map */

#ifndef QUEST

struct mkroom rooms[MAXNROFROOMS+1];

coord doors[DOORMAX];

#endif QUEST

struct monst *fmon = 0;

struct gen *fgold = 0, *ftrap = 0;

struct obj *fobj = 0, *fcobj = 0, *invent = 0, *uwep = 0, *uarm = 0,

	*uarm2 = 0, *uarmh = 0, *uarms = 0, *uarmg = 0, *uright = 0,

	*uleft = 0, *uchain = 0, *uball = 0;

struct flag flags;

struct you u;



xchar dlevel = 1;

xchar xupstair, yupstair, xdnstair, ydnstair;

char *save_cm = 0, *killer, *nomovemsg;



long moves = 1;

long wailmsg = 0;



int multi = 0;

char genocided[60];

char fut_geno[60];



xchar curx,cury;

xchar seelx, seehx, seely, seehy;	/* corners of lit room */



coord bhitpos;

jcz@ncsu.UUCP (John A. Toebes, VIII) (02/20/86)

#file hack.do.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.do.c version 1.0.1 - check Levitation with POT_PARALYSIS
			   - added flags.no_rest_on_space */

#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include "hack.h"
#include "def.func_tab.h"

extern char *getenv(),*parse(),*getlogin(),*lowc(),*unctrl();
extern int float_down();
extern char *nomovemsg, *catmore;
extern struct obj *splitobj(), *addinv();
extern boolean hmon();
extern char morc;

/*   Routines to do various user commands */

int done1();

dodrink() {
   register struct obj *otmp,*objs;
   register struct monst *mtmp;
   register int unkn = 0, nothing = 0;

   otmp = getobj("!", "drink");
   if(!otmp) return(0);
   switch(otmp->otyp){
   case POT_RESTORE_STRENGTH:
      unkn++;
      pline("Wow!  This makes you feel great!");
      if(u.ustr < u.ustrmax) {
         u.ustr = u.ustrmax;
         flags.botl = 1;
      }
      break;
   case POT_BOOZE:
      unkn++;
      pline("Ooph!  This tastes like liquid fire!");
      Confusion += d(3,8);
      /* the whiskey makes us feel better */
      if(u.uhp < u.uhpmax) losehp(-1, "bottle of whiskey");
      if(!rn2(4)) {
         pline("You pass out.");
         multi = -rnd(15);
         nomovemsg = "You awake with a headache.";
      }
      break;
   case POT_INVISIBILITY:
      if(Invis)
        nothing++;
      else {
        if(!Blind)
          pline("Gee!  All of a sudden, you can't see yourself.");
        else
          pline("You feel rather airy."), unkn++;
        newsym(u.ux,u.uy);
      }
      Invis += rn1(15,31);
      break;
   case POT_FRUIT_JUICE:
      pline("This tastes like fruit juice.");
      lesshungry(20);
      break;
   case POT_HEALING:
      pline("You begin to feel better.");
      flags.botl = 1;
      u.uhp += rnd(10);
      if(u.uhp > u.uhpmax)
         u.uhp = ++u.uhpmax;
      if(Blind) Blind = 1;   /* see on next move */
      if(Sick) Sick = 0;
      break;
   case POT_PARALYSIS:
		if(Levitation)
			pline("Your head is frozen to the ceiling!");
		else
			pline("Your feet are frozen to the floor!");
		nomul(-(rn1(10,25)));
		break;
   case POT_MONSTER_DETECTION:
      if(!fmon) {
         strange_feeling(otmp);
         return(1);
      } else {
         cls();
         for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
            if(mtmp->mx > 0)
            at(mtmp->mx,mtmp->my,mtmp->data->mlet);
         prme();
         pline("You sense the presence of monsters.");
         more();
         docrt();
      }
      break;
   case POT_OBJECT_DETECTION:
      if(!fobj) {
         strange_feeling(otmp);
         return(1);
      } else {
          for(objs = fobj; objs; objs = objs->nobj)
         if(objs->ox != u.ux || objs->oy != u.uy)
            goto outobjmap;
          pline("You sense the presence of objects close nearby.");
          break;
      outobjmap:
         cls();
         for(objs = fobj; objs; objs = objs->nobj)
            at(objs->ox,objs->oy,objs->olet);
         prme();
         pline("You sense the presence of objects.");
         more();
         docrt();
      }
      break;
   case POT_SICKNESS:
      pline("Yech! This stuff tastes like poison.");
      if(Poison_resistance)
    pline("(But in fact it was biologically contaminated orange juice.)");
      losestr(rn1(4,3));
      losehp(rnd(10), "poison potion");
      break;
   case POT_CONFUSION:
      if(!Confusion)
         pline("Huh, What?  Where am I?");
      else
         nothing++;
      Confusion += rn1(7,16);
      break;
   case POT_GAIN_STRENGTH:
      pline("Wow do you feel strong!");
      if(u.ustr == 118) break;
      if(u.ustr > 17) u.ustr += rnd(118-u.ustr);
      else u.ustr++;
      if(u.ustr > u.ustrmax) u.ustrmax = u.ustr;
      flags.botl = 1;
      break;
   case POT_SPEED:
      if(Wounded_legs) {
         if((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
            pline("Your legs feel somewhat better.");
         else
            pline("Your leg feels somewhat better.");
         Wounded_legs = 0;
         unkn++;
         break;
      }
      if(!(Fast & ~INTRINSIC))
         pline("You are suddenly moving much faster.");
      else
         pline("Your legs get new energy."), unkn++;
      Fast += rn1(10,100);
      break;
   case POT_BLINDNESS:
      if(!Blind)
         pline("A cloud of darkness falls upon you.");
      else
         nothing++;
      Blind += rn1(100,250);
      seeoff(0);
      break;
   case POT_GAIN_LEVEL:
      pluslvl();
      break;
   case POT_EXTRA_HEALING:
      pline("You feel much better.");
      flags.botl = 1;
      u.uhp += d(2,20)+1;
      if(u.uhp > u.uhpmax)
         u.uhp = (u.uhpmax += 2);
      if(Blind) Blind = 1;
      if(Sick) Sick = 0;
      break;
   case POT_LEVITATION:
      if(!Levitation)
         float_up();
      else
         nothing++;
      Levitation += rnd(100);
      u.uprops[PROP(RIN_LEVITATION)].p_tofn = float_down;
      break;
   default:
      pline("What a funny potion! (%d)", otmp->otyp);
      impossible();
      return(0);
   }
   if(nothing) {
       unkn++;
       pline("You have a peculiar feeling for a moment, then it passes.");
   }
   if(otmp->dknown && !objects[otmp->otyp].oc_name_known) {
      if(!unkn) {
         objects[otmp->otyp].oc_name_known = 1;
         u.urexp += 10;
      } else if(!objects[otmp->otyp].oc_uname)
         docall(otmp);
   }
   useup(otmp);
   return(1);
}

pluslvl()
{
   register int num;

   pline("You feel more experienced.");
   num = rnd(10);
   u.uhpmax += num;
   u.uhp += num;
   u.uexp = (10*pow(u.ulevel-1))+1;
   pline("Welcome to level %d.", ++u.ulevel);
   flags.botl = 1;
}

strange_feeling(obj)
register struct obj *obj;
{
   pline("You have a strange feeling for a moment, then it passes.");
   if(!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname)
      docall(obj);
   useup(obj);
}

dodrop() {
   register struct obj *obj;

   obj = getobj("0$#", "drop");
   if(!obj) return(0);
   if(obj->olet == '$') {
      if(obj->quan == 0)
         pline("You didn't drop any gold pieces.");
      else {
         mkgold((int) obj->quan, u.ux, u.uy);
         pline("You dropped %u gold piece%s.",
            obj->quan, plur(obj->quan));
         if(Invis) newsym(u.ux, u.uy);
      }
      free((char *) obj);
      return(1);
   }
   return(drop(obj));
}

drop(obj) register struct obj *obj; {
   if(obj->owornmask & (W_ARMOR | W_RING)){
      pline("You cannot drop something you are wearing.");
      return(0);
   }
   if(obj == uwep) {
      if(uwep->cursed) {
         pline("Your weapon is welded to your hand!");
         return(0);
      }
      setuwep((struct obj *) 0);
   }
   pline("You dropped %s.", doname(obj));
   dropx(obj);
   return(1);
}

dropx(obj) register struct obj *obj; {
   if(obj->otyp == CRYSKNIFE)
      obj->otyp = WORM_TOOTH;
   freeinv(obj);
   obj->ox = u.ux;
   obj->oy = u.uy;
   obj->nobj = fobj;
   fobj = obj;
   if(Invis) newsym(u.ux,u.uy);
   subfrombill(obj);
   stackobj(obj);
}

/* drop several things */
doddrop() {
   return(ggetobj("drop", drop, 0));
}

rhack(cmd)
register char *cmd;
{
   register struct func_tab *tlist = list;
   boolean firsttime = FALSE;
   register int res;

   if(!cmd) {
      firsttime = TRUE;
      flags.nopick = 0;
      cmd = parse();
   }
	if(!*cmd || *cmd == 0377 || (flags.no_rest_on_space && *cmd == ' ')){
		flags.move = 0;
		return;      /* probably we just had an interrupt */
	}
   if(movecm(cmd)) {
   walk:
      if(multi) flags.mv = 1;
      domove();
      return;
   }
   if(movecm(lowc(cmd))) {
      flags.run = 1;
   rush:
      if(firsttime){
         if(!multi) multi = COLNO;
         u.last_str_turn = 0;
      }
      flags.mv = 1;
#ifdef QUEST
      if(flags.run >= 4) finddir();
      if(firsttime){
         u.ux0 = u.ux + u.dx;
         u.uy0 = u.uy + u.dy;
      }
#endif QUEST
      domove();
      return;
   }
   if((*cmd == 'f' && movecm(cmd+1)) ||
      movecm(unctrl(cmd))) {
      flags.run = 2;
      goto rush;
   }
   if(*cmd == 'F' && movecm(lowc(cmd+1))) {
      flags.run = 3;
      goto rush;
   }
   if(*cmd == 'm' && movecm(cmd+1)) {
      flags.run = 0;
      flags.nopick = 1;
      goto walk;
   }
   if(*cmd == 'M' && movecm(lowc(cmd+1))) {
      flags.run = 1;
      flags.nopick = 1;
      goto rush;
   }
#ifdef QUEST
   if(*cmd == cmd[1] && (*cmd == 'f' || *cmd == 'F')) {
      flags.run = 4;
      if(*cmd == 'F') flags.run += 2;
      if(cmd[2] == '-') flags.run += 1;
      goto rush;
   }
#endif QUEST
   while(tlist->f_char) {
      if(*cmd == tlist->f_char){
         res = (*(tlist->f_funct))(0);
         if(!res) {
            flags.move = 0;
            multi = 0;
         }
         return;
      }
      tlist++;
   }
   pline("Unknown command '%s'",cmd);
   multi = flags.move = 0;
}

doredraw()
{
   docrt();
   return(0);
}

dohelp()
{
	FILE *fp;
	char bufr[BUFSZ];
	int line, i;
	
	if ( (fp = fopen(HELP,"r")) == NULL)
		pline("cannot access help");
	else
		{
		cls();
		line = 1;
		while(fgets(bufr,BUFSZ,fp))
			{
			myprintf("%s", bufr);
			if (line++ > ROWNO)
				{
				myprintf("---more---");
				xwaitforspace(FALSE);
				morc = 0;
				for (i=0;i<10;i++)
					backsp();
				cl_end();
				line = 1;
				}
			}
		more();
		docrt();
		}
}

#ifdef SHELL
dosh(){
   char *file, *Open();
   if ( (file = Open("CON:1/1/639/199/Hack SubProcess", 1006)) == NULL)
	pline("cannot create process window");
   if (Execute("", file, NULL))
      pline("cannot execute commands");
   Close(file);
   return(0);
}
#endif SHELL

child(wt) {
   pline("Cannot create children");
   docrt();
   return(0);
}

dodown()
{
   if(u.ux != xdnstair || u.uy != ydnstair) {
      pline("You can't go down here.");
      return(0);
   }
   if(u.ustuck) {
      pline("You are being held, and cannot go down.");
      return(1);
   }
   if(Levitation) {
      pline("You're floating high above the stairs.");
      return(0);
   }

   goto_level(dlevel+1, TRUE);
   return(1);
}

doup()
{
   if(u.ux != xupstair || u.uy != yupstair) {
      pline("You can't go up here.");
      return(0);
   }
   if(u.ustuck) {
      pline("You are being held, and cannot go up.");
      return(1);
   }
   if(inv_weight() + 5 > 0) {
      pline("Your load is too heavy to climb the stairs.");
      return(1);
   }

   goto_level(dlevel-1, TRUE);
   return(1);
}

goto_level(newlevel, at_stairs)
register int newlevel;
register boolean at_stairs;
{
   register int fd;
   register boolean up = (newlevel < dlevel);

	if(newlevel <= 0) done("escaped");    /* in fact < 0 is impossible */
	if(newlevel == dlevel) return;	      /* this cannot happen either */

   glo(dlevel);
   fd = creat(lock,FMASK);
   if(fd < 0) {
      /*
       * This is not quite impossible: e.g., we may have
       * exceeded our quota. If that is the case then we
       * cannot leave this level, and cannot save either.
       */
      pline("A mysterious force prevents you from going %s.",
         up ? "up" : "down");
      return;
   }

   if(Punished) unplacebc();
   keepdogs();
   seeoff(1);
   flags.nscrinh = 1;
   u.ux = FAR;            /* hack */
   (void) inshop();         /* probably was a trapdoor */

   savelev(fd);
   (void) close(fd);

   dlevel = newlevel;
   if(maxdlevel < dlevel)
      maxdlevel = dlevel;
   glo(dlevel);
   if((fd = open(lock,0)) < 0)
      mklev();
   else {
      (void) getlev(fd);
      (void) close(fd);
   }

   if(at_stairs) {
       if(up) {
      u.ux = xdnstair;
      u.uy = ydnstair;
      if(!u.ux) {      /* entering a maze from below? */
          u.ux = xupstair;   /* this will confuse the player! */
          u.uy = yupstair;
      }
      if(Punished){
         pline("With great effort you climb the stairs");
         placebc(1);
      }
       } else {
      u.ux = xupstair;
      u.uy = yupstair;
      if(inv_weight() + 5 > 0 || Punished){
         pline("You fall down the stairs.");
         losehp(rnd(3), "fall");
         if(Punished) {
             if(uwep != uball && rn2(3)){
            pline("... and are hit by the iron ball");
            losehp(rnd(20), "iron ball");
             }
             placebc(1);
         }
         selftouch("Falling, you");
      }
       }
   } else {   /* trapdoor or level_tele */
       do {
      u.ux = rnd(COLNO-1);
      u.uy = rn2(ROWNO);
       } while(levl[u.ux][u.uy].typ != ROOM ||
         m_at(u.ux,u.uy));
       if(Punished){
      if(uwep != uball && !up /* %% */ && rn2(5)){
         pline("The iron ball falls on your head.");
         losehp(rnd(25), "iron ball");
      }
      placebc(1);
       }
       selftouch("Falling, you");
   }
   (void) inshop();
#ifdef TRACK
   initrack();
#endif TRACK

   losedogs();
   flags.nscrinh = 0;
   setsee();
	{ register struct monst *mtmp;
	  if(mtmp = m_at(u.ux, u.uy)) mnexto(mtmp);	/* riv05!a3 */
	}
   docrt();
   pickup();
   read_engr_at(u.ux,u.uy);
}

donull() {
   return(1);   /* Do nothing, but let other things happen */
}

struct monst *bhit(), *boomhit();
dothrow()
{
   register struct obj *obj;
   register struct monst *mon;
   register int tmp;

	obj = getobj("#)", "throw");   /* it is also possible to throw food */
				       /* (or jewels, or iron balls ... ) */
   if(!obj || !getdir())
      return(0);
   if(obj->owornmask & (W_ARMOR | W_RING)){
      pline("You can't throw something you are wearing");
      return(0);
   }
   if(obj == uwep){
      if(obj->cursed){
         pline("Your weapon is welded to your hand");
         return(1);
      }
      if(obj->quan > 1)
         setuwep(splitobj(obj, 1));
      else
         setuwep((struct obj *) 0);
   }
   else if(obj->quan > 1)
      (void) splitobj(obj, 1);
   freeinv(obj);
   if(u.uswallow) {
      mon = u.ustuck;
      bhitpos.x = mon->mx;
      bhitpos.y = mon->my;
   } else if(obj->otyp == BOOMERANG) {
      mon = boomhit(u.dx,u.dy);
      /* boomhit delivers -1 if the thing was caught */
      if((int) mon == -1) {
         (void) addinv(obj);
         return(1);
      }
   } else
      mon = bhit(u.dx,u.dy,
         (!Punished || obj != uball) ? 8 :
            !u.ustuck ? 5 : 1,
         obj->olet);
   if(mon) {
      /* awake monster if sleeping */
      wakeup(mon);

      if(obj->olet == WEAPON_SYM) {
         tmp = -1+u.ulevel+mon->data->ac+abon();
         if(obj->otyp < ROCK) {
            if(!uwep ||
                uwep->otyp != obj->otyp+(BOW-ARROW))
               tmp -= 4;
            else {
               tmp += uwep->spe;
            }
         } else
         if(obj->otyp == BOOMERANG) tmp += 4;
         tmp += obj->spe;
         if(u.uswallow || tmp >= rnd(20)) {
            if(hmon(mon,obj,1) == TRUE){
              /* mon still alive */
#ifndef NOWORM
              cutworm(mon,bhitpos.x,bhitpos.y,obj->otyp);
#endif NOWORM
            } else mon = 0;
            /* weapons thrown disappear sometimes */
            if(obj->otyp < BOOMERANG && rn2(3)) {
               /* check bill; free */
               obfree(obj, (struct obj *) 0);
               return(1);
            }
         } else miss(objects[obj->otyp].oc_name, mon);
      } else if(obj->otyp == HEAVY_IRON_BALL) {
         tmp = -1+u.ulevel+mon->data->ac+abon();
         if(!Punished || obj != uball) tmp += 2;
         if(u.utrap) tmp -= 2;
         if(u.uswallow || tmp >= rnd(20)) {
            if(hmon(mon,obj,1) == FALSE)
               mon = 0;   /* he died */
         } else miss("iron ball", mon);
      } else {
         if(cansee(bhitpos.x,bhitpos.y))
            pline("You miss %s.",monnam(mon));
         else pline("You miss it.");
         if(obj->olet == FOOD_SYM && mon->data->mlet == 'd')
            if(tamedog(mon,obj)) return(1);
         if(obj->olet == GEM_SYM && mon->data->mlet == 'u'){
          if(obj->dknown && objects[obj->otyp].oc_name_known){
           if(objects[obj->otyp].g_val > 0){
             u.uluck += 5;
             goto valuable;
           } else {
             pline("%s is not interested in your junk.",
            Monnam(mon));
           }
          } else { /* value unknown to @ */
             u.uluck++;
         valuable:
             pline("%s graciously accepts your gift.",
            Monnam(mon));
             mpickobj(mon, obj);
             rloc(mon);
             return(1);
          }
         }
      }
   }
   obj->ox = bhitpos.x;
   obj->oy = bhitpos.y;
   obj->nobj = fobj;
   fobj = obj;
   /* prevent him from throwing articles to the exit and escaping */
   /* subfrombill(obj); */
   stackobj(obj);
   if(Punished && obj == uball &&
      (bhitpos.x != u.ux || bhitpos.y != u.uy)){
      freeobj(uchain);
      unpobj(uchain);
      if(u.utrap){
         if(u.utraptype == TT_PIT)
            pline("The ball pulls you out of the pit!");
         else {
             register long side =
            rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
             pline("The ball pulls you out of the bear trap.");
             pline("Your %s leg is severely damaged.",
            (side == LEFT_SIDE) ? "left" : "right");
             Wounded_legs |= side + rnd(1000);
             losehp(2, "thrown ball");
         }
         u.utrap = 0;
      }
      unsee();
      uchain->nobj = fobj;
      fobj = uchain;
      u.ux = uchain->ox = bhitpos.x - u.dx;
      u.uy = uchain->oy = bhitpos.y - u.dy;
      setsee();
      (void) inshop();
   }
   if(cansee(bhitpos.x, bhitpos.y)) prl(bhitpos.x,bhitpos.y);
   return(1);
}

/* split obj so that it gets size num */
/* remainder is put in the object structure delivered by this call */
struct obj *
splitobj(obj, num) register struct obj *obj; register int num; {
register struct obj *otmp;
   otmp = newobj(0);
   *otmp = *obj;      /* copies whole structure */
   otmp->o_id = flags.ident++;
   otmp->onamelth = 0;
   obj->quan = num;
   obj->owt = weight(obj);
   otmp->quan -= num;
   otmp->owt = weight(otmp);   /* -= obj->owt ? */
   obj->nobj = otmp;
   if(obj->unpaid) splitbill(obj,otmp);
   return(otmp);
}

char *
lowc(str)
register char *str;
{
   static char buf[2];

   if(*str >= 'A' && *str <= 'Z') *buf = *str+'a'-'A';
   else *buf = *str;
   buf[1] = 0;
   return(buf);
}

char *
unctrl(str)
register char *str;
{
   static char buf[2];
   if(*str >= ('A' & 037) && *str <= ('Z' & 037))
      *buf = *str + 0140;
   else *buf = *str;
   buf[1] = 0;
   return(buf);
}

#file hack.dog.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.dog.c version 1.0.1 - "You feel worried about %s." (Adri Verhoef) */

#include	"hack.h"
#include	"hack.mfndpos.h"
extern char POISONOUS[];
extern struct monst *makemon();
#include "def.edog.h"

makedog(){
register struct monst *mtmp = makemon(PM_LI_DOG,u.ux,u.uy);
	if(!mtmp) return; /* dogs were genocided */
	initedog(mtmp);
}

initedog(mtmp) register struct monst *mtmp; {
	mtmp->mtame = mtmp->mpeaceful = 1;
	EDOG(mtmp)->hungrytime = 1000 + moves;
	EDOG(mtmp)->eattime = 0;
	EDOG(mtmp)->droptime = 0;
	EDOG(mtmp)->dropdist = 10000;
	EDOG(mtmp)->apport = 10;
	EDOG(mtmp)->whistletime = 0;
}

/* attach the monsters that went down (or up) together with @ */
struct monst *mydogs = 0;
struct monst *fallen_down = 0;	/* monsters that fell through a trapdoor */

losedogs(){
register struct monst *mtmp;
	while(mtmp = mydogs){
		mydogs = mtmp->nmon;
		mtmp->nmon = fmon;
		fmon = mtmp;
		mnexto(mtmp);
	}
	while(mtmp = fallen_down){
		fallen_down = mtmp->nmon;
		mtmp->nmon = fmon;
		fmon = mtmp;
		rloc(mtmp);
	}
}

keepdogs(){
register struct monst *mtmp;
	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(mtmp->mtame) {
		if(dist(mtmp->mx,mtmp->my) > 2) {
			mtmp->mtame = 0;	/* dog becomes wild */
			mtmp->mpeaceful = 0;
			continue;
		}
		relmon(mtmp);
		mtmp->nmon = mydogs;
		mydogs = mtmp;
		unpmon(mtmp);
		keepdogs();	/* we destroyed the link, so use recursion */
		return;		/* (admittedly somewhat primitive) */
	}
}

fall_down(mtmp) register struct monst *mtmp; {
	relmon(mtmp);
	mtmp->nmon = fallen_down;
	fallen_down = mtmp;
	unpmon(mtmp);
	mtmp->mtame = 0;
}

/* return quality of food; the lower the better */
#define	DOGFOOD	0
#define	CADAVER	1
#define	ACCFOOD	2
#define	MANFOOD	3
#define	APPORT	4
#define	POISON	5
#define	UNDEF	6
dogfood(obj) register struct obj *obj; {
	switch(obj->olet) {
	case FOOD_SYM:
	    return(
		(obj->otyp == TRIPE_RATION) ? DOGFOOD :
		(obj->otyp < CARROT) ? ACCFOOD :
		(obj->otyp < CORPSE) ? MANFOOD :
		(index(POISONOUS, obj->spe) || obj->age + 50 <= moves ||
		    obj->otyp == DEAD_COCKATRICE)
			? POISON : CADAVER
	    );
	default:
	    if(!obj->cursed) return(APPORT);
	    /* fall into next case */
	case BALL_SYM:
	case CHAIN_SYM:
	case ROCK_SYM:
	    return(UNDEF);
	}
}

/* return 0 (no move), 1 (move) or 2 (dead) */
dog_move(mtmp, after) register struct monst *mtmp; {
register int nx,ny,omx,omy,appr,nearer,j;
int udist,chi,i,whappr;
register struct monst *mtmp2;
register struct permonst *mdat = mtmp->data;
register struct edog *edog = EDOG(mtmp);
struct obj *obj;
struct gen *trap;
xchar cnt,chcnt,nix,niy;
schar dogroom,uroom;
xchar gx,gy,gtyp,otyp;	/* current goal */
coord poss[9];
int info[9];
#define GDIST(x,y) ((x-gx)*(x-gx) + (y-gy)*(y-gy))
#define DDIST(x,y) ((x-omx)*(x-omx) + (y-omy)*(y-omy))

	if(moves <= edog->eattime) return(0);	/* dog is still eating */
	omx = mtmp->mx;
	omy = mtmp->my;
	whappr = (moves - EDOG(mtmp)->whistletime < 5);
	if(moves > edog->hungrytime + 500 && !mtmp->mconf){
		mtmp->mconf = 1;
		mtmp->orig_hp /= 3;
		if(mtmp->mhp > mtmp->orig_hp)
			mtmp->mhp = mtmp->orig_hp;
		if(cansee(omx,omy))
			pline("%s is confused from hunger", Monnam(mtmp));
		else	pline("You feel worried about %s.", monnam(mtmp));
	} else
	if(moves > edog->hungrytime + 750 || mtmp->mhp < 1){
		if(cansee(omx,omy))
			pline("%s dies from hunger", Monnam(mtmp));
		else
		pline("You have a sad feeling for a moment, then it passes");
		mondied(mtmp);
		return(2);
	}
	dogroom = inroom(omx,omy);
	uroom = inroom(u.ux,u.uy);
	udist = dist(omx,omy);

	/* if we are carrying sth then we drop it (perhaps near @) */
	/* Note: if apport == 1 then our behaviour is independent of udist */
	if(mtmp->minvent){
		if(!rn2(udist) || !rn2((int) edog->apport))
		if(rn2(10) < edog->apport){
			relobj(mtmp,0);
			if(edog->apport > 1) edog->apport--;
		}
	} else {
		if(obj = o_at(omx,omy)) if(!index("0_", obj->olet)){
		    if((otyp = dogfood(obj)) <= CADAVER){
			nix = omx;
			niy = omy;
			goto eatobj;
		    }
		    if(obj->owt < 10*mtmp->data->mlevel)
		    if(rn2(20) < edog->apport+3)
		    if(rn2(udist) || !rn2((int) edog->apport)){
			freeobj(obj);
			unpobj(obj);
			/* if(levl[omx][omy].scrsym == obj->olet)
				newsym(omx,omy); */
			mpickobj(mtmp,obj);
		    }
		}
	}

	/* first we look for food */
	gtyp = UNDEF;	/* no goal as yet */
#ifdef LINT
	gx = gy = 0;
#endif LINT
	for(obj = fobj; obj; obj = obj->nobj) {
		otyp = dogfood(obj);
		if(otyp > gtyp || otyp == UNDEF) continue;
		if(inroom(obj->ox,obj->oy) != dogroom) continue;
		if(otyp < MANFOOD &&
		 (dogroom >= 0 || DDIST(obj->ox,obj->oy) < 10)) {
			if(otyp < gtyp || (otyp == gtyp &&
				DDIST(obj->ox,obj->oy) < DDIST(gx,gy))){
				gx = obj->ox;
				gy = obj->oy;
				gtyp = otyp;
			}
		} else
		if(gtyp == UNDEF && dogroom >= 0 &&
		   uroom == dogroom &&
		   !mtmp->minvent && edog->apport > rn2(8)){
			gx = obj->ox;
			gy = obj->oy;
			gtyp = APPORT;
		}
	}
	if(gtyp == UNDEF ||
	  (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)){
		if(dogroom < 0 || dogroom == uroom){
			gx = u.ux;
			gy = u.uy;
#ifndef QUEST
		} else {
			int tmp = rooms[dogroom].fdoor;
			    cnt = rooms[dogroom].doorct;

			gx = gy = FAR;	/* random, far away */
			while(cnt--){
			    if(dist(gx,gy) >
				dist(doors[tmp].x, doors[tmp].y)){
					gx = doors[tmp].x;
					gy = doors[tmp].y;
				}
				tmp++;
			}
			/* here gx == FAR e.g. when dog is in a vault */
			if(gx == FAR || (gx == omx && gy == omy)){
				gx = u.ux;
				gy = u.uy;
			}
#endif QUEST
		}
		appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
		if(after && udist <= 4 && gx == u.ux && gy == u.uy)
			return(0);
		if(udist > 1){
			if(levl[u.ux][u.uy].typ < ROOM || !rn2(4) ||
			   whappr ||
			   (mtmp->minvent && rn2((int) edog->apport)))
				appr = 1;
		}
		/* if you have dog food he'll follow you more closely */
		if(appr == 0){
			obj = invent;
			while(obj){
				if(obj->otyp == TRIPE_RATION){
					appr = 1;
					break;
				}
				obj = obj->nobj;
			}
		}
	} else	appr = 1;	/* gtyp != UNDEF */
	if(mtmp->mconf) appr = 0;
#ifdef TRACK
	if(gx == u.ux && gy == u.uy && (dogroom != uroom || dogroom < 0)){
	extern coord *gettrack();
	register coord *cp;
		cp = gettrack(omx,omy);
		if(cp){
			gx = cp->x;
			gy = cp->y;
		}
	}
#endif TRACK
	nix = omx;
	niy = omy;
	cnt = mfndpos(mtmp,poss,info,ALLOW_M | ALLOW_TRAPS);
	chcnt = 0;
	chi = -1;
	for(i=0; i<cnt; i++){
		nx = poss[i].x;
		ny = poss[i].y;
		if(info[i] & ALLOW_M){
			mtmp2 = m_at(nx,ny);
			if(mtmp2->data->mlevel >= mdat->mlevel+2 ||
			  mtmp2->data->mlet == 'c')
				continue;
			if(after) return(0); /* hit only once each move */

			if(hitmm(mtmp, mtmp2) == 1 && rn2(4) &&
			  mtmp2->mlstmv != moves &&
			  hitmm(mtmp2,mtmp) == 2) return(2);
			return(0);
		}

		/* dog avoids traps */
		/* but perhaps we have to pass a trap in order to follow @ */
		if((info[i] & ALLOW_TRAPS) && (trap = g_at(nx,ny,ftrap))){
			if(!(trap->gflag & SEEN) && rn2(40)) continue;
			if(rn2(10)) continue;
		}

		/* dog eschewes cursed objects */
		/* but likes dog food */
		obj = fobj;
		while(obj){
		    if(obj->ox != nx || obj->oy != ny)
			goto nextobj;
		    if(obj->cursed) goto nxti;
		    if(obj->olet == FOOD_SYM &&
			(otyp = dogfood(obj)) < MANFOOD &&
			(otyp < ACCFOOD || edog->hungrytime <= moves)){
			/* Note: our dog likes the food so much that he
			might eat it even when it conceals a cursed object */
			nix = nx;
			niy = ny;
			chi = i;
		     eatobj:
			edog->eattime =
			    moves + obj->quan * objects[obj->otyp].oc_delay;
			edog->hungrytime =
			    moves + 5*obj->quan * objects[obj->otyp].nutrition;
			mtmp->mconf = 0;
			if(cansee(nix,niy))
			    pline("%s ate %s.", Monnam(mtmp), doname(obj));
			/* perhaps this was a reward */
			if(otyp != CADAVER)
			edog->apport += 200/(edog->dropdist+moves-edog->droptime);
			delobj(obj);
			goto newdogpos;
		    }
		nextobj:
		    obj = obj->nobj;
		}

		for(j=0; j<MTSZ && j<cnt-1; j++)
			if(nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
				if(rn2(4*(cnt-j))) goto nxti;

/* Some stupid C compilers cannot compute the whole expression at once. */
		nearer = GDIST(nx,ny);
		nearer -= GDIST(nix,niy);
		nearer *= appr;
		if((nearer == 0 && !rn2(++chcnt)) || nearer<0 ||
			(nearer > 0 && !whappr &&
				((omx == nix && omy == niy && !rn2(3))
				|| !rn2(12))
			)){
			nix = nx;
			niy = ny;
			if(nearer < 0) chcnt = 0;
			chi = i;
		}
	nxti:	;
	}
newdogpos:
	if(nix != omx || niy != omy){
		if(info[chi] & ALLOW_U){
			(void) hitu(mtmp, d(mdat->damn, mdat->damd)+1);
			return(0);
		}
		mtmp->mx = nix;
		mtmp->my = niy;
		for(j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1];
		mtmp->mtrack[0].x = omx;
		mtmp->mtrack[0].y = omy;
	}
	if(mintrap(mtmp) == 2)	/* he died */
		return(2);
	pmon(mtmp);
	return(1);
}

/* return roomnumber or -1 */
inroom(x,y) xchar x,y; {
#ifndef QUEST
	register struct mkroom *croom = &rooms[0];
	while(croom->hx >= 0){
		if(croom->hx >= x-1 && croom->lx <= x+1 &&
		   croom->hy >= y-1 && croom->ly <= y+1)
			return(croom - rooms);
		croom++;
	}
#endif QUEST
	return(-1);	/* not in room or on door */
}

tamedog(mtmp, obj)
register struct monst *mtmp;
register struct obj *obj;
{
register struct monst *mtmp2;
	if(mtmp->mtame || mtmp->mfroz ||
#ifndef NOWORM
		mtmp->wormno ||
#endif NOWORM
		mtmp->isshk || mtmp->isgd)
		return(0); /* no tame long worms? */
	if(obj) {
		if(dogfood(obj) >= MANFOOD) return(0);
		if(cansee(mtmp->mx,mtmp->my)){
			pline("%s devours the %s.", Monnam(mtmp),
				objects[obj->otyp].oc_name);
		}
		obfree(obj, (struct obj *) 0);
	}
	mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth);
	*mtmp2 = *mtmp;
	mtmp2->mxlth = sizeof(struct edog);
	if(mtmp->mnamelth) (void) strcpy(NAME(mtmp2), NAME(mtmp));
	initedog(mtmp2);
	replmon(mtmp,mtmp2);
	return(1);
}
#file hack.do_name.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.do_name.c version 1.0.1 - correction in call of xname() */

#include "hack.h"
#include <stdio.h>

extern int mousex;
extern int mousey;

coord
getpos(force,goal) int force; char *goal; {
register int cx,cy,i,c;
extern char sdir[];      /* defined in hack.c */
extern schar xdir[], ydir[];   /* idem */
extern char *visctrl();      /* see below */
coord cc;
   pline("(For instructions type a ?)");
   cx = u.ux;
   cy = u.uy;
   curs(cx,cy+2);
   while((c = readchar()) != '.'){
      for(i=0; i<8; i++) if(sdir[i] == c){
         if(1 <= cx + xdir[i] && cx + xdir[i] <= COLNO)
            cx += xdir[i];
         if(0 <= cy + ydir[i] && cy + ydir[i] <= ROWNO-1)
            cy += ydir[i];
         goto nxtc;
      }
      if(c == '?'){
         pline("Use [hjkl] to move the cursor to %s.", goal);
         pline("Type a . when you are at the right place.");
      } else if (c == MDOWN) {
	cx = mousex;
	cy = mousey-2;
	} else if (c == MUP) {
	cx = mousex;
	cy = mousey-2;
	break;
	} else {
         pline("unknown direction: '%s' (%s)",
            visctrl(c),
            force ? "use hjkl or ." : "aborted");
         if(force) goto nxtc;
         cc.x = -1;
         cc.y = 0;
         return(cc);
      }
   nxtc:   ;
      curs(cx,cy+2);
   }
   cc.x = cx;
   cc.y = cy;
   return(cc);
}

do_mname(){
char buf[BUFSZ];
coord cc;
register int cx,cy,lth,i;
register struct monst *mtmp, *mtmp2;
extern char *lmonnam();
   cc = getpos(0, "the monster you want to name");
   cx = cc.x;
   cy = cc.y;
   if(cx < 0) return(0);
   mtmp = m_at(cx,cy);
   if(!mtmp){
       if(cx == u.ux && cy == u.uy){
      extern char plname[];
      pline("This ugly monster is called %s and cannot be renamed.",
          plname);
       } else   pline("There is no monster there.");
       return(1);
   }
   if(mtmp->mimic){
       pline("I see no monster there.");
       return(1);
   }
   if(!cansee(cx,cy)) {
       pline("I cannot see a monster there.");
       return(1);
   }
   pline("What do you want to call %s? ", lmonnam(mtmp));
   getlin(buf);
   clrlin();
   if(!*buf) return(1);
   lth = strlen(buf)+1;
   if(lth > 63){
      buf[62] = 0;
      lth = 63;
   }
   mtmp2 = newmonst(mtmp->mxlth + lth);
   *mtmp2 = *mtmp;
   for(i=0; i<mtmp->mxlth; i++)
      ((char *) mtmp2->mextra)[i] = ((char *) mtmp->mextra)[i];
   mtmp2->mnamelth = lth;
   (void) strcpy(NAME(mtmp2), buf);
   replmon(mtmp,mtmp2);
   if(mtmp2->isshk) setshk();   /* redefine shopkeeper and bill */
   if(mtmp2->isgd) setgd( /* mtmp2 */ );
   return(1);
}

/*
 * This routine changes the address of  obj . Be careful not to call it
 * when there might be pointers around in unknown places. For now: only
 * when  obj  is in the inventory.
 */
do_oname(obj) register struct obj *obj; {
register struct obj *otmp, *otmp2;
register int lth;
char buf[BUFSZ];
   pline("What do you want to name %s? ", doname(obj));
   getlin(buf);
   clrlin();
   if(!*buf) return;
   lth = strlen(buf)+1;
   if(lth > 63){
      buf[62] = 0;
      lth = 63;
   }
   otmp2 = newobj(lth);
   *otmp2 = *obj;
   otmp2->onamelth = lth;
   (void) strcpy(ONAME(otmp2), buf);

   setworn((struct obj *) 0, obj->owornmask);
   setworn(otmp2, otmp2->owornmask);

   /* do freeinv(obj); etc. by hand in order to preserve
      the position of this object in the inventory */
   if(obj == invent) invent = otmp2;
   else for(otmp = invent; ; otmp = otmp->nobj){
      if(!otmp)
         panic("Do_oname: cannot find obj.");
      if(otmp->nobj == obj){
         otmp->nobj = otmp2;
         break;
      }
   }
   /* obfree(obj, otmp2);   /* now unnecessary: no pointers on bill */
   free((char *) obj);   /* let us hope nobody else saved a pointer */
}

ddocall()
{
   register struct obj *obj;

   pline("Do you want to name an individual object? [yn] ");
   if(readchar() == 'y'){
      obj = getobj("#", "name");
      if(obj) do_oname(obj);
   } else {
      obj = getobj("?!=/", "call");
      if(obj) docall(obj);
   }
   return(0);
}

docall(obj)
register struct obj *obj;
{
   char buf[BUFSZ];
   register char **str1;
   extern char *xname();
	struct obj otemp;
   register char *str;

	otemp = *obj;
	otemp.quan = 1;
	str = xname(&otemp);
   pline("Call %s %s: ", index(vowels,*str) ? "an" : "a", str);
   getlin(buf);
   clrlin();
   if(!*buf) return;
   str = newstring(strlen(buf)+1);
   (void) strcpy(str,buf);
   str1 = &(objects[obj->otyp].oc_uname);
   if(*str1) free(*str1);
   *str1 = str;
}

char *
xmonnam(mtmp, vb) register struct monst *mtmp; int vb; {
static char buf[BUFSZ];      /* %% */
extern char *shkname();
	if(mtmp->mnamelth && !vb) {
		(void) strcpy(buf, NAME(mtmp));
		return(buf);
	}
   switch(mtmp->data->mlet) {
   case ' ':
      (void) sprintf(buf, "%s's ghost", (char *) mtmp->mextra);
      break;
   case '@':
      if(mtmp->isshk) {
         (void) strcpy(buf, shkname());
         break;
      }
      /* fall into next case */
   default:
      (void) sprintf(buf, "the %s%s",
         mtmp->minvis ? "invisible " : "",
         mtmp->data->mname);
   }
   if(vb && mtmp->mnamelth) {
      (void) strcat(buf, " called ");
      (void) strcat(buf, NAME(mtmp));
   }
   return(buf);
}

char *
lmonnam(mtmp) register struct monst *mtmp; {
   return(xmonnam(mtmp, 1));
}

char *
monnam(mtmp) register struct monst *mtmp; {
   return(xmonnam(mtmp, 0));
}

char *
Monnam(mtmp) register struct monst *mtmp; {
register char *bp = monnam(mtmp);
   if('a' <= *bp && *bp <= 'z') *bp += ('A' - 'a');
   return(bp);
}

char *
amonnam(mtmp,adj)
register struct monst *mtmp;
register char *adj;
{
   register char *bp = monnam(mtmp);
   static char buf[BUFSZ];      /* %% */

   if(!strncmp(bp, "the ", 4)) bp += 4;
   (void) sprintf(buf, "the %s %s", adj, bp);
   return(buf);
}

char *
Amonnam(mtmp, adj)
register struct monst *mtmp;
register char *adj;
{
   register char *bp = amonnam(mtmp,adj);

   *bp = 'T';
   return(bp);
}

char *
Xmonnam(mtmp) register struct monst *mtmp; {
register char *bp = Monnam(mtmp);
   if(!strncmp(bp, "The ", 4)) {
      bp += 2;
      *bp = 'A';
   }
   return(bp);
}

char *
visctrl(c)
char c;
{
static char ccc[3];
   if(c < 040) {
      ccc[0] = '^';
      ccc[1] = c + 0100;
      ccc[2] = 0;
   } else {
      ccc[0] = c;
      ccc[1] = 0;
   }
   return(ccc);
}
#file hack.do_wear.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.do_wear.c version 1.0.1 - changed an int to long */

#include "hack.h"
#include <stdio.h>
extern char *nomovemsg;

off_msg(otmp) register struct obj *otmp; {
	pline("You were wearing %s.", doname(otmp));
}

doremarm() {
	register struct obj *otmp;
	if(!uarm && !uarmh && !uarms && !uarmg) {
		pline("Not wearing any armor.");
		return(0);
	}
	otmp = (!uarmh && !uarms && !uarmg) ? uarm :
		(!uarms && !uarm && !uarmg) ? uarmh :
		(!uarmh && !uarm && !uarmg) ? uarms :
		(!uarmh && !uarm && !uarms) ? uarmg :
		getobj("[", "take off");
	if(!otmp) return(0);
	if(!(otmp->owornmask & (W_ARMOR - W_ARM2))) {
		pline("You can't take that off.");
		return(0);
	}
	(void) armoroff(otmp);
	return(1);
}

doremring() {
	if(!uleft && !uright){
		pline("Not wearing any ring.");
		return(0);
	}
	if(!uleft)
		return(dorr(uright));
	if(!uright)
		return(dorr(uleft));
	if(uleft && uright) while(1) {
		pline("What ring, Right or Left? ");
		switch(readchar()) {
		case ' ':
		case '\n':
		case '\033':
			return(0);
		case 'l':
		case 'L':
			return(dorr(uleft));
		case 'r':
		case 'R':
			return(dorr(uright));
		}
	}
	/* NOTREACHED */
#ifdef lint
	return(0);
#endif lint
}

dorr(otmp) register struct obj *otmp; {
	if(cursed(otmp)) return(0);
	ringoff(otmp);
	off_msg(otmp);
	return(1);
}

cursed(otmp) register struct obj *otmp; {
	if(otmp->cursed){
		pline("You can't. It appears to be cursed.");
		return(1);
	}
	return(0);
}

armoroff(otmp) register struct obj *otmp; {
register int delay = -objects[otmp->otyp].oc_delay;
	if(cursed(otmp)) return(0);
	setworn((struct obj *) 0, otmp->owornmask & W_ARMOR);
	if(delay) {
		nomul(delay);
		switch(otmp->otyp) {
		case HELMET:
			nomovemsg = "You finished taking off your helmet.";
			break;
		case PAIR_OF_GLOVES:
			nomovemsg = "You finished taking off your gloves";
			break;
		default:
			nomovemsg = "You finished taking off your suit.";
		}
	} else {
		off_msg(otmp);
	}
	return(1);
}

doweararm() {
	register struct obj *otmp;
	register int delay;
	register int err = 0;
	long mask = 0;

	otmp = getobj("[", "wear");
	if(!otmp) return(0);
	if(otmp->owornmask & W_ARMOR) {
		pline("You are already wearing that!");
		return(0);
	}
	if(otmp->otyp == HELMET){
		if(uarmh) {
			pline("You are already wearing a helmet.");
			err++;
		} else
			mask = W_ARMH;
	} else if(otmp->otyp == SHIELD){
		if(uarms) pline("You are already wearing a shield."), err++;
		if(uwep && uwep->otyp == TWO_HANDED_SWORD)
	pline("You cannot wear a shield and wield a two-handed sword."), err++;
		if(!err) mask = W_ARMS;
	} else if(otmp->otyp == PAIR_OF_GLOVES){
		if(uarmg) pline("You are already wearing gloves."); else
		if(uwep && uwep->cursed)
			pline("You cannot wear gloves over your weapon.");
		else mask = W_ARMG;
	} else {
		if(uarm) {
			if(otmp->otyp != ELVEN_CLOAK || uarm2) {
				pline("You are already wearing some armor.");
				err++;
			}
		}
		if(!err) mask = W_ARM;
	}
	if(err) return(0);
	setworn(otmp, mask);
	if(otmp == uwep)
		setuwep((struct obj *) 0);
	delay = -objects[otmp->otyp].oc_delay;
	if(delay){
		nomul(delay);
		nomovemsg = "You finished your dressing manoeuvre.";
	}
	otmp->known = 1;
	return(1);
}

dowearring() {
	register struct obj *otmp;
	long mask = 0;
	long oldprop;

	if(uleft && uright){
		pline("There are no more ring-fingers to fill.");
		return(0);
	}
	otmp = getobj("=", "wear");
	if(!otmp) return(0);
	if(otmp->owornmask & W_RING) {
		pline("You are already wearing that!");
		return(0);
	}
	if(otmp == uleft || otmp == uright) {
		pline("You are already wearing that.");
		return(0);
	}
	if(uleft) mask = RIGHT_RING;
	else if(uright) mask = LEFT_RING;
	else do {
 		pline("What ring-finger, Right or Left? ");
		switch(readchar()){
		case 'l':
		case 'L':
			mask = LEFT_RING;
			break;
		case 'r':
		case 'R':
			mask = RIGHT_RING;
			break;
		case ' ':
		case '\n':
		case '\033':
			return(0);
		}
	} while(!mask);
	setworn(otmp, mask);
	if(otmp == uwep)
		setuwep((struct obj *) 0);
	oldprop = u.uprops[PROP(otmp->otyp)].p_flgs;
	u.uprops[PROP(otmp->otyp)].p_flgs |= mask;
	switch(otmp->otyp){
	case RIN_LEVITATION:
		if(!oldprop) float_up();
		break;
	case RIN_PROT_SHAPE_CHANGERS:
		rescham();
		break;
	case RIN_GAIN_STRENGTH:
		u.ustr += otmp->spe;
		u.ustrmax += otmp->spe;
		flags.botl=1;
		break;
	case RIN_INCREASE_DAMAGE:
		u.udaminc += otmp->spe;
		break;
	}
	prinv(otmp);
	return(1);
}

ringoff(obj)
register struct obj *obj;
{
register long mask;
	mask = obj->owornmask & W_RING;
	setworn((struct obj *) 0, obj->owornmask);
	if(!(u.uprops[PROP(obj->otyp)].p_flgs & mask)){
		pline("Strange... I didnt know you had that ring.");
		impossible();
	}
	u.uprops[PROP(obj->otyp)].p_flgs &= ~mask;
	switch(obj->otyp) {
	case RIN_LEVITATION:
		if(!Levitation) {	/* no longer floating */
			float_down();
		}
		break;
	case RIN_GAIN_STRENGTH:
		u.ustr -= obj->spe;
		u.ustrmax -= obj->spe;
		flags.botl = 1;
		break;
	case RIN_INCREASE_DAMAGE:
		u.udaminc -= obj->spe;
		break;
	}
}

find_ac(){
register int uac = 10;
	if(uarm) uac -= uarm->spe;
	if(uarm2) uac -= uarm2->spe;
	if(uarmh) uac -= uarmh->spe;
	if(uarms) uac -= uarms->spe;
	if(uarmg) uac -= uarmg->spe;
	if(uleft && uleft->otyp == RIN_PROTECTION) uac -= uleft->spe;
	if(uright && uright->otyp == RIN_PROTECTION) uac -= uright->spe;
	if(uac != u.uac){
		u.uac = uac;
		flags.botl = 1;
	}
}

glibr(){
register struct obj *otmp;
int xfl = 0;
	if(!uarmg) if(uleft || uright) {
		/* Note: at present also cursed rings fall off */
		pline("Your %s off your fingers.",
			(uleft && uright) ? "rings slip" : "ring slips");
		xfl++;
		if(otmp = uleft){
			ringoff(uleft);
			dropx(otmp);
		}
		if(otmp = uright){
			ringoff(uright);
			dropx(otmp);
		}
	}
	if(otmp = uwep){
		/* Note: at present also cursed weapons fall */
		setuwep((struct obj *) 0);
		dropx(otmp);
		pline("Your weapon %sslips from your hands.",
			xfl ? "also " : "");
	}
}

struct obj *
some_armor(){
register struct obj *otmph = uarm;
	if(uarmh && (!otmph || !rn2(4))) otmph = uarmh;
	if(uarmg && (!otmph || !rn2(4))) otmph = uarmg;
	if(uarms && (!otmph || !rn2(4))) otmph = uarms;
	return(otmph);
}

corrode_armor(){
register struct obj *otmph = some_armor();
	if(otmph){
		if(otmph->rustfree ||
		   otmph->otyp == ELVEN_CLOAK ||
		   otmph->otyp == LEATHER_ARMOR ||
		   otmph->otyp == STUDDED_LEATHER_ARMOR) {
			pline("Your %s not affected!",
				aobjnam(otmph, "are"));
			return;
		}
		pline("Your %s!", aobjnam(otmph, "corrode"));
		otmph->spe--;
	}
}
#file hack.eat.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.eat.c version 1.0.1 - added morehungry() and FAINTED */

#include   "hack.h"
char POISONOUS[] = "ADKSVabhks";
extern char *nomovemsg;
extern int (*afternmv)();

/* hunger texts used on bottom line (each 8 chars long) */
#define SATIATED	0
#define NOT_HUNGRY	1
#define HUNGRY		2
#define WEAK		3
#define FAINTING	4
#define FAINTED		5
#define STARVED		6

char *hu_stat[] = {
	"Satiated",
	"        ",
	"Hungry  ",
	"Weak    ",
	"Fainting",
	"Fainted ",
	"Starved "
};

init_uhunger(){
   u.uhunger = 900;
   u.uhs = NOT_HUNGRY;
}

struct { char *txt; int nut; } tintxts[] = {
   {"It contains first quality peaches - what a surprise!",   40},
   {"It contains salmon - not bad!",   60},
   {"It contains apple juice - perhaps not what you hoped for.", 20},
   {"It contains some nondescript substance, tasting awfully.", 500},
   {"It contains rotten meat. You vomit.", -50},
   {"It turns out to be empty.",   0}
};

tinopen(){
#define   TTSZ   (sizeof(tintxts)/sizeof(tintxts[0]))
register int r = rn2(2*TTSZ);
   if(r < TTSZ){
       pline(tintxts[r].txt);
       lesshungry(tintxts[r].nut);
       if(r == 1)   /* SALMON */ {
      Glib = rnd(15);
      pline("Eating salmon made your fingers very slippery.");
       }
   } else {
       pline("It contains spinach - this makes you feel like Popeye!");
       lesshungry(600);
       if(u.ustr < 118)
      u.ustr += rnd( ((u.ustr < 17) ? 19 : 118) - u.ustr);
       if(u.ustr > u.ustrmax) u.ustrmax = u.ustr;
       flags.botl = 1;
   }
}

Meatdone(){
   u.usym = '@';
   prme();
}

doeat(){
   register struct obj *otmp;
   register struct objclass *ftmp;
   register int tmp;

   otmp = getobj("%", "eat");
   if(!otmp) return(0);
   if(otmp->otyp == TIN){
      if(uwep && (uwep->otyp == AXE || uwep->otyp == DAGGER ||
             uwep->otyp == CRYSKNIFE)){
         pline("Using your %s you try to open the tin",
            aobjnam(uwep, (char *) 0));
         tmp = 3;
      } else {
         pline("It is not so easy to open this tin.");
				if(Glib) {
					pline("The tin slips out of your hands.");
					dropx(otmp);
					return(1);
				}
				if(otmp->quan > 1) {
					register struct obj *obj;
					extern struct obj *splitobj();

					obj = splitobj(otmp, 1);
					if(otmp == uwep) setuwep(obj);
				}
         tmp = 2 + rn2(1 + 500/((int)(u.ulevel + u.ustr)));
      }
      if(tmp > 50){
         nomul(-50);
         nomovemsg="You give up your attempt to open the tin.";
      } else {
         nomul(-tmp);
         nomovemsg = "You succeed in opening the tin.";
         afternmv = tinopen;
         useup(otmp);
      }
      return(1);
   }
   ftmp = &objects[otmp->otyp];
   if(otmp->otyp >= CORPSE && eatcorpse(otmp)) goto eatx;
   if(!rn2(7) && otmp->otyp != FORTUNE_COOKIE) {
      pline("Blecch!  Rotten food!");
      if(!rn2(4)) {
         pline("You feel rather light headed.");
         Confusion += d(2,4);
      } else if(!rn2(4)&& !Blind) {
         pline("Everything suddenly goes dark.");
         Blind = d(2,10);
         seeoff(0);
      } else if(!rn2(3)) {
         if(Blind)
           pline("The world spins and you slap against the floor.");
         else
           pline("The world spins and goes dark.");
         nomul(-rnd(10));
         nomovemsg = "You are conscious again.";
      }
      lesshungry(ftmp->nutrition / 4);
   } else {
      multi = -ftmp->oc_delay;
      if(u.uhunger >= 1500) {
         pline("You choke over your food.");
         pline("You die...");
         killer = ftmp->oc_name;
         done("choked");
      }
      switch(otmp->otyp){
      case FOOD_RATION:
         if(u.uhunger <= 200)
            pline("That food really hit the spot!");
         else if(u.uhunger <= 700)
            pline("That satiated your stomach!");
         else {
	pline("You're having a hard time getting all that food down.");
            multi -= 2;
         }
         lesshungry(ftmp->nutrition);
         if(multi < 0) nomovemsg = "You finished your meal.";
         break;
      case TRIPE_RATION:
         pline("Yak - dog food!");
         u.uexp++;
         u.urexp += 4;
         flags.botl = 1;
			if(rn2(2)){
				pline("You vomit.");
				morehungry(20);
         } else   lesshungry(ftmp->nutrition);
         break;
      default:
         if(otmp->otyp >= CORPSE)
         pline("That %s tasted terrible!",ftmp->oc_name);
         else
         pline("That %s was delicious!",ftmp->oc_name);
         lesshungry(ftmp->nutrition);
#ifdef QUEST
         if(otmp->otyp == CARROT && !Blind){
            u.uhorizon++;
            setsee();
            pline("Your vision improves.");
         }
#endif QUEST
         if(otmp->otyp == FORTUNE_COOKIE) {
           if(Blind) {
             pline("This cookie has a scrap of paper inside!");
             pline("What a pity, that you cannot read it!");
           } else
             outrumor();
         }
         break;
      }
   }
eatx:
   if(multi<0 && !nomovemsg){
      static char msgbuf[BUFSZ];
      (void) sprintf(msgbuf, "You finished eating the %s.",
            ftmp->oc_name);
      nomovemsg = msgbuf;
   }
   useup(otmp);
   return(1);
}

/* called in hack.main.c */
gethungry(){
   --u.uhunger;
   if((Regeneration || Hunger) && moves%2) u.uhunger--;
	newuhs(TRUE);
}

/* called after vomiting and after performing feats of magic */
morehungry(num) register int num; {
	u.uhunger -= num;
	newuhs(TRUE);
}

/* called after eating something (and after drinking fruit juice) */
lesshungry(num) register int num; {
	u.uhunger += num;
	newuhs(FALSE);
}

unfaint(){
	u.uhs = FAINTING;
	flags.botl = 1;
}

newuhs(incr) boolean incr; {
	register int newhs, h = u.uhunger;

	newhs = (h > 1000) ? SATIATED :
		(h > 150) ? NOT_HUNGRY :
		(h > 50) ? HUNGRY :
		(h > 0) ? WEAK : FAINTING;

	if(newhs == FAINTING) {
		if(u.uhs == FAINTED)
			newhs = FAINTED;
		if(u.uhs <= WEAK || rn2(20-u.uhunger/10) >= 19) {
			if(u.uhs != FAINTED && multi >= 0 /* %% */) {
				pline("You faint from lack of food.");
				nomul(-10+(u.uhunger/10));
				nomovemsg = "You regain consciousness.";
				afternmv = unfaint;
				newhs = FAINTED;
			}
		} else
		if(u.uhunger < -(int)(200 + 25*u.ulevel)) {
			u.uhs = STARVED;
			flags.botl = 1;
			bot();
			pline("You die from starvation.");
			done("starved");
		}
	}

	if(newhs != u.uhs) {
		if(newhs >= WEAK && u.uhs < WEAK)
			losestr(1);
		else
		if(newhs < WEAK && u.uhs >= WEAK && u.ustr < u.ustrmax)
			losestr(-1);
		switch(newhs){
		case HUNGRY:
			pline((!incr) ? "You only feel hungry now." :
			      (u.uhunger < 145) ? "You feel hungry." :
				"You are beginning to feel hungry.");
			break;
		case WEAK:
			pline((!incr) ? "You feel weak now." :
			      (u.uhunger < 45) ? "You feel weak." :
				"You are beginning to feel weak.");
			break;
		}
		u.uhs = newhs;
		flags.botl = 1;
   }
}

/* returns 1 if some text was printed */
eatcorpse(otmp) register struct obj *otmp; {
register schar let = otmp->spe;
register int tp = 0;
   if(moves > otmp->age + 50 + rn2(100)) {
      tp++;
      pline("Ulch -- that meat was tainted!");
      pline("You get very sick.");
      Sick = 10 + rn2(10);
      u.usick_cause = objects[otmp->otyp].oc_name;
   } else if(index(POISONOUS, let) && rn2(5)){
      tp++;
      pline("Ecch -- that must have been poisonous!");
      if(!Poison_resistance){
         losehp(rnd(15), "poisonous corpse");
         losestr(rnd(4));
      } else
         pline("You don't seem affected by the poison.");
   } else if(index("ELNOPQRUuxz", let) && rn2(5)){
      tp++;
      pline("You feel sick.");
      losehp(rnd(8), "cadaver");
   }
   switch(let) {
   case 'L':
   case 'N':
   case 't':
      Teleportation |= INTRINSIC;
      break;
   case 'W':
      pluslvl();
      break;
   case 'n':
      u.uhp = u.uhpmax;
      flags.botl = 1;
      /* fall into next case */
   case '@':
      pline("You cannibal! You will be sorry for this!");
      /* not tp++; */
      /* fall into next case */
   case 'd':
      Aggravate_monster |= INTRINSIC;
      break;
   case 'I':
      See_invisible |= INTRINSIC;
      if(!Invis) newsym(u.ux, u.uy);
      Invis += 50;
      /* fall into next case */
   case 'y':
#ifdef QUEST
      u.uhorizon++;
#endif QUEST
      /* fall into next case */
   case 'B':
      Confusion = 50;
      break;
   case 'D':
      Fire_resistance |= INTRINSIC;
      break;
   case 'E':
      Telepat |= INTRINSIC;
      break;
   case 'F':
   case 'Y':
      Cold_resistance |= INTRINSIC;
      break;
   case 'k':
   case 's':
      Poison_resistance |= INTRINSIC;
      break;
   case 'c':
      pline("You turn to stone.");
      killer = "dead cockatrice";
      done("died");
   case 'M':
     pline("You cannot resist the temptation to mimic a treasure chest.");
     tp++;
     nomul(-30);
     afternmv = Meatdone;
     nomovemsg = "You now again prefer mimicking a human.";
     u.usym = '$';
     prme();
     break;
   }
   return(tp);
}

#file hack.end.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.end.c version 1.0.1 - added "escaped with amulet" */

#include "hack.h"
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#define   Sprintf   (void) sprintf
extern char plname[], pl_character[];
extern char *itoa(), *ordin(), *eos(), *getlogin();

extern char *index(); /* M.E.T. 11/20/85 */

xchar maxdlevel = 1;

done1()
{
   (void) signal(SIGINT,SIG_IGN);
   pline("Really quit?");
   if(readchar() != 'y')
      {
      (void) signal(SIGINT,done1);
      clrlin();
      (void) myfflush(stdout);
      if(multi > 0) nomul(0);
      return(0);
      }
   done("quit");
   /* NOTREACHED */
}

int done_stopprint;

done_intr(){
   done_stopprint++;
   (void) signal(SIGINT,SIG_IGN);
}

done_in_by(mtmp) register struct monst *mtmp; {
static char buf[BUFSZ];
   pline("You die ...");
   if(mtmp->data->mlet == ' ')
      {
      Sprintf(buf, "the ghost of %s", (char *) mtmp->mextra);
      killer = buf;
      }
   else if(mtmp->mnamelth)
      {
      Sprintf(buf, "%s called %s", mtmp->data->mname, NAME(mtmp));
      killer = buf;
      }
   else if(mtmp->minvis)
      {
      Sprintf(buf, "invisible %s", mtmp->data->mname);
      killer = buf;
      }
   else
      killer = mtmp->data->mname;
   done("died");
}

/* called with arg "died", "escaped", "quit", "choked", "panic"
   or "starved" */
/* Be careful not to call panic from here! */
done(st1)
register char *st1;
{

#ifdef WIZARD
   if(wizard && *st1 == 'd'){
      u.ustr = u.ustrmax += 2;
      u.uhp = u.uhpmax += 10;
      if(uarm) uarm->spe++;
      if(uwep) uwep->spe++; /* NB: uwep need not be a weapon! */
      u.uswldtim = 0;
      pline("For some reason you are still alive.");
      flags.move = 0;
      if(multi > 0) multi = 0; else multi = -1;
      flags.botl = 1;
      return;
   }
#endif WIZARD
   (void) signal(SIGINT, done_intr);
   if(*st1 == 'q' && u.uhp < 1)
      {
      st1 = "died";
      killer = "quit while already on Charon's boat";
      }
   if(*st1 == 's')
      killer = "starvation";
   paybill();
   clearlocks();
   if(index("cds", *st1))
		{
		savebones();
		if(!flags.notombstone)
			outrip();
		else
			more();
		}
   myprintf("Contents of your pack when you died:\n");
   myddoinv();
   settty((char *) 0);   /* does a cls() */
   if(!done_stopprint)
      myprintf("Goodbye %s %s...\n\n", pl_character, plname);
   {
      long int tmp;
      tmp = u.ugold - u.ugold0;
      if(tmp < 0) tmp = 0;
      if(*st1 == 'd')
         tmp -= tmp/10;
      else
         killer = st1;
      u.urexp += tmp;
   }
   if(*st1 == 'e')
      {
      extern struct monst *mydogs;
      register struct monst *mtmp = mydogs;
      register struct obj *otmp;
      register int i;
      register unsigned worthlessct = 0;

		killer = st1;
	u.urexp += 50 * maxdlevel;
      if(mtmp)
         {
         if(!done_stopprint) myprintf("You");
         while(mtmp)
            {
            if(!done_stopprint)
               myprintf(" and %s", monnam(mtmp));
            u.urexp += mtmp->mhp;
            mtmp = mtmp->nmon;
            }
         if(!done_stopprint)
          myprintf("\nescaped from the dungeon with %lu points,\n",
         u.urexp);
         }
      else if(!done_stopprint)
        myprintf("You escaped from the dungeon with %lu points,\n",
          u.urexp);
      for(otmp = invent; otmp; otmp = otmp->nobj) {
         if(otmp->olet == GEM_SYM){
            objects[otmp->otyp].oc_name_known = 1;
            i = otmp->quan*objects[otmp->otyp].g_val;
            if(i == 0) {
               worthlessct += otmp->quan;
               continue;
            }
            u.urexp += i;
            if(!done_stopprint)
              myprintf("\t%s (worth %d Zorkmids),\n",
                doname(otmp), i);
         } else if(otmp->olet == AMULET_SYM) {
            otmp->known = 1;
            i = (otmp->spe < 0) ? 2 : 5000;
            u.urexp += i;
            if(!done_stopprint)
              myprintf("\t%s (worth %d Zorkmids),\n",
                doname(otmp), i);
				if(otmp->spe >= 0) {
					u.urexp *= 2;
					killer = "escaped (with amulet)";
				}
         }
      }
      if(worthlessct) if(!done_stopprint)
        myprintf("\t%d worthless piece%s of coloured glass,\n",
        worthlessct, plur(worthlessct));
   } else
      if(!done_stopprint)
        myprintf("You %s on dungeon level %d with %lu points,\n",
          st1,dlevel,u.urexp);
   if(!done_stopprint)
     myprintf("and %lu piece%s of gold, after %lu move%s.\n",
       u.ugold, (u.ugold == 1) ? "" : "s",
       moves, (moves == 1) ? "" : "s");
   if(!done_stopprint)
  myprintf("You were level %d with a maximum of %d hit points when you %s.\n",
       u.ulevel, u.uhpmax, st1);
   if(*st1 == 'e'){
      getret();   /* all those pieces of coloured glass ... */
      cls();
   }
#ifdef WIZARD
   if(!wizard)
#endif WIZARD
      topten();
   if(done_stopprint) myprintf("\n\n");
   hackexit(0);
}

#define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry))
#define   NAMSZ   8
#define   DTHSZ   40
#define   PERSMAX   1
#define   POINTSMIN   1   /* must be > 0 */
#define   ENTRYMAX   100   /* must be >= 10 */
struct toptenentry {
   struct toptenentry *tt_next;
   long int points;
   int level,maxlvl,hp,maxhp;
   char plchar;
   char str[NAMSZ+1];
   char death[DTHSZ+1];
} *tt_head;

topten(){
   int rank, rank0 = -1, rank1 = 0;
   int occ_cnt = PERSMAX;
   register struct toptenentry *t0, *t1, *tprev;
   char *recfile = "record";
   int  rfile;
   register int flg = 0;

   if((rfile = open(recfile,O_RDONLY)) < 0)
      {
      myputs("Cannot open record file!");
      return;
      }
   (void) myputchar('\n');

   /* create a new 'topten' entry */
   t0 = newttentry();
   t0->level = dlevel;
   t0->maxlvl = maxdlevel;
   t0->hp = u.uhp;
   t0->maxhp = u.uhpmax;
   t0->points = u.urexp;
   t0->plchar = pl_character[0];
   (void) strncpy(t0->str, plname, NAMSZ);
   (t0->str)[NAMSZ] = 0;
   (void) strncpy(t0->death, killer, DTHSZ);
   (t0->death)[DTHSZ] = 0;

   /* assure minimum number of points */
   if(t0->points < POINTSMIN)
      t0->points = 0;

   t1 = tt_head = newttentry();
   tprev = 0;
   /* rank0: -1 undefined, 0 not_on_list, n n_th on list */
   for(rank = 1; ; ) {
     if (read(rfile, t1, sizeof(struct toptenentry)) !=
           sizeof(struct toptenentry) || (t1->points < POINTSMIN))
        t1->points = 0;

     if(rank0 < 0 && t1->points < t0->points) {
      rank0 = rank++;
      if(tprev == 0)
         tt_head = t0;
      else
         tprev->tt_next = t0;
      t0->tt_next = t1;
      occ_cnt--;
      flg++;      /* ask for a rewrite */
     } else
      tprev = t1;
     if(t1->points == 0) break;
     if(strncmp(t1->str, t0->str, NAMSZ) == 0 &&
        t1->plchar == t0->plchar && --occ_cnt <= 0){
      if(rank0 < 0){
         rank0 = 0;
         rank1 = rank;
   myprintf("You didn't beat your previous score of %ld points.\n\n",
            t1->points);
      }
      if(occ_cnt < 0){
         flg++;
         continue;
      }
     }
     if(rank <= ENTRYMAX){
        t1 = t1->tt_next = newttentry();
        rank++;
     }
     if(rank > ENTRYMAX){
      t1->points = 0;
      break;
     }
   }
   if(flg) {   /* rewrite record file */
      (void) close(rfile);
      if((rfile=open(recfile,O_WRONLY)) < 0)
         {
         myputs("Cannot write record file\n");
         return;
         }

      if(!done_stopprint) if(rank0 > 0){
          if(rank0 <= 10)
         myputs("You made the top ten list!\n");
          else
      myprintf("You reached the %d%s place on the top %d list.\n\n",
         rank0, ordin(rank0), ENTRYMAX);
      }
   }
   if(rank0 == 0) rank0 = rank1;
   if(rank0 <= 0) rank0 = rank;
   if(!done_stopprint) outheader();
   t1 = tt_head;
   for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
     if(flg) write(rfile, t1, sizeof(struct toptenentry));
     if(done_stopprint) continue;
	  if(rank > flags.end_top &&
	    (rank < rank0-flags.end_around || rank > rank0+flags.end_around)
	    && (!flags.end_own || strncmp(t1->str, t0->str, NAMSZ)))
	  	continue;
	  if(rank == rank0-flags.end_around &&
	     rank0 > flags.end_top+flags.end_around+1 &&
	     !flags.end_own)
		(void) putchar('\n');
     if(rank != rank0)
      (void) outentry(rank, t1, 0);
     else if(!rank1)
      (void) outentry(rank, t1, 1);
     else {
      int t0lth = outentry(0, t0, -1);
      int t1lth = outentry(rank, t1, t0lth);
      if(t1lth > t0lth) t0lth = t1lth;
      (void) outentry(0, t0, t0lth);
     }
   }
   if(rank0 >= rank)
      (void) outentry(0, t0, 1);
   (void) close(rfile);

/* 12nov85 djw */
   getret();
}

outheader() {
char linebuf[BUFSZ];
register char *bp;
   (void) strcpy(linebuf, "Number Points  Name");
   bp = eos(linebuf);
   while(bp < linebuf + COLNO - 9) *bp++ = ' ';
   (void) strcpy(bp, "Hp [max]");
   myputs(linebuf);
}

/* so>0: standout line; so=0: ordinary line; so<0: no output, return lth */
int
outentry(rank,t1,so) register struct toptenentry *t1; {
boolean quit = FALSE, killed = FALSE, starv = FALSE;
char linebuf[BUFSZ];
   linebuf[0] = 0;
   if(rank) Sprintf(eos(linebuf), "%3d", rank);
      else Sprintf(eos(linebuf), "   ");
   Sprintf(eos(linebuf), " %6ld %8s", t1->points, t1->str);
   if(t1->plchar == 'X') Sprintf(eos(linebuf), " ");
   else Sprintf(eos(linebuf), "-%c ", t1->plchar);
	if(!strncmp("escaped", t1->death, 7)) {
	  if(!strcmp(" (with amulet)", t1->death+7))
	    Sprintf(eos(linebuf), "escaped the dungeon with amulet");
	  else
	    Sprintf(eos(linebuf), "escaped the dungeon [max level %d]",
	      t1->maxlvl);
	} else {
     if(!strncmp(t1->death,"quit",4))
       Sprintf(eos(linebuf), "quit"), quit = TRUE;
     else if(!strcmp(t1->death,"choked"))
       Sprintf(eos(linebuf), "choked in his food");
     else if(!strncmp(t1->death,"starv",5))
       Sprintf(eos(linebuf), "starved to death"), starv = TRUE;
     else Sprintf(eos(linebuf), "was killed"), killed = TRUE;
     Sprintf(eos(linebuf), " on%s level %d",
       (killed || starv) ? "" : " dungeon", t1->level);
     if(t1->maxlvl != t1->level)
       Sprintf(eos(linebuf), " [max %d]", t1->maxlvl);
     if(quit && t1->death[4]) Sprintf(eos(linebuf), t1->death + 4);
   }
   if(killed) Sprintf(eos(linebuf), " by %s%s",
     !strncmp(t1->death, "the ", 4) ? "" :
     index(vowels,*t1->death) ? "an " : "a ",
     t1->death);
   Sprintf(eos(linebuf), ".");
   if(t1->maxhp) {
     register char *bp = eos(linebuf);
     char hpbuf[10];
     int hppos;
     Sprintf(hpbuf, (t1->hp > 0) ? itoa(t1->hp) : "-");
     hppos = COLNO - 7 - strlen(hpbuf);
     if(bp <= linebuf + hppos) {
       while(bp < linebuf + hppos) *bp++ = ' ';
       (void) strcpy(bp, hpbuf);
       Sprintf(eos(bp), " [%d]", t1->maxhp);
     }
   }
   if(so == 0) myputs(linebuf);
   else if(so > 0) {
     register char *bp = eos(linebuf);
     if(so >= COLNO) so = COLNO-1;
     while(bp < linebuf + so) *bp++ = ' ';
     *bp = 0;
     standoutbeg();
     myputs(linebuf);
     standoutend();
     (void) myputchar('\n');
   }
   return(strlen(linebuf));
}

char *
itoa(a) int a; {
static char buf[12];
   Sprintf(buf,"%d",a);
   return(buf);
}

char *
ordin(n) int n; {
register int d = n%10;
   return((d==0 || d>3 || n/10==1) ? "th" : (d==1) ? "st" :
      (d==2) ? "nd" : "rd");
}

clearlocks(){
register int x;
   (void) signal(SIGHUP,SIG_IGN);
   for(x = 1; x <= maxdlevel; x++) {
      glo(x);
      (void) unlink(lock);   /* not all levels need be present */
   }
   *index(lock,'.') = 0;
   (void) unlink(lock);
}

#ifdef NOSAVEONHANGUP
hangup(){
   (void) signal(SIGINT,SIG_IGN);
   clearlocks();
   hackexit(1);
}
#endif NOSAVEONHANGUP

char *
eos(s) register char *s; {
   while(*s) s++;
   return(s);
}

/* it is the callers responsibility to check that there is room for c */
charcat(s,c) register char *s, c; {
   while(*s) s++;
   *s++ = c;
   *s = 0;
}

prscore(argc,argv) int argc; char **argv; {
   extern char *hname;
   char *player0;
   char **players;
   int playerct;
   int rank;
   register struct toptenentry *t1;
   char *recfile = "record";
   int  rfile;
   register int flg = 0;
   register int i;

   if((rfile = open(recfile,O_RDONLY)) < 0)
      {
      myputs("Cannot open record file!");
      return;
      }

   if(argc > 1 && !strncmp(argv[1], "-s", 2)){
      if(!argv[1][2]){
         argc--;
         argv++;
      } else if(!argv[1][3] && index("CFKSTWX", argv[1][2])) {
         argv[1]++;
         argv[1][0] = '-';
      } else   argv[1] += 2;
   }
   if(argc <= 1){
      player0 = getlogin();
      if(!player0) player0 = "player";
      playerct = 1;
      players = &player0;
   } else {
      playerct = --argc;
      players = ++argv;
   }
   myputchar('\n');

   t1 = tt_head = newttentry();
   for(rank = 1; ; rank++) {
     if (read(rfile, t1, sizeof(struct toptenentry)) !=
           sizeof(struct toptenentry))
        t1->points = 0;
     if(t1->points == 0) break;
     for(i = 0; i < playerct; i++){
      if(strcmp(players[i], "all") == 0 ||
         strncmp(t1->str, players[i], NAMSZ) == 0 ||
        (players[i][0] == '-' &&
         players[i][1] == t1->plchar &&
         players[i][2] == 0) ||
        (digit(players[i][0]) && rank <= atoi(players[i])))
         flg++;
     }
     t1 = t1->tt_next = newttentry();
   }
   (void) close(rfile);
   if(!flg) {
      myprintf("Cannot find any entries for ");
      if(playerct > 1) myprintf("any of ");
      for(i=0; i<playerct; i++)
         myprintf("%s%s", players[i], (i<playerct-1)?", ":".\n");
      myprintf("Call is: %s -s [playernames]\n", hname);
      return;
   }

   outheader();
   t1 = tt_head;
   for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
      for(i = 0; i < playerct; i++){
         if(strcmp(players[i], "all") == 0 ||
            strncmp(t1->str, players[i], NAMSZ) == 0 ||
           (players[i][0] == '-' &&
            players[i][1] == t1->plchar &&
            players[i][2] == 0) ||
           (digit(players[i][0]) && rank <= atoi(players[i])))
            goto out;
      }
      continue;
   out:
     (void) outentry(rank, t1, 0);
   }
}

jcz@ncsu.UUCP (John A. Toebes, VIII) (02/20/86)

#file hack.engrave.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.engrave.c version 1.0.1 -
	corrected bug in rest_engravings(),
	added make_engr_at() */
#include	"hack.h"
extern char *nomovemsg;
extern char nul[];
struct engr {
	struct engr *nxt_engr;
	char *engr_txt;
	xchar engr_x, engr_y;
	unsigned engr_lth;	/* for save & restore; not length of text */
	long engr_time;	/* moment engraving was (will be) finished */
	xchar engr_type;
#define	DUST	1
#define	ENGRAVE	2
#define	BURN	3
} *head_engr;

struct engr *
engr_at(x,y) register xchar x,y; {
register struct engr *ep = head_engr;
	while(ep) {
		if(x == ep->engr_x && y == ep->engr_y)
			return(ep);
		ep = ep->nxt_engr;
	}
	return((struct engr *) 0);
}

sengr_at(s,x,y) register char *s; register xchar x,y; {
register struct engr *ep = engr_at(x,y);
register char *t;
register int n;
	if(ep && ep->engr_time <= moves) {
		t = ep->engr_txt;
/*
		if(!strcmp(s,t)) return(1);
*/
		n = strlen(s);
		while(*t) {
			if(!strncmp(s,t,n)) return(1);
			t++;
		}
	}
	return(0);
}

wipe_engr_at(x,y,cnt) register xchar x,y,cnt; {
register struct engr *ep = engr_at(x,y);
register int lth,pos;
char ch;
	if(ep){
		if(ep->engr_type != DUST) {
			cnt = rn2(1 + 50/(cnt+1)) ? 0 : 1;
		}
		lth = strlen(ep->engr_txt);
		if(lth && cnt > 0 ) {
			while(cnt--) {
				pos = rn2(lth);
				if((ch = ep->engr_txt[pos]) == ' ')
					continue;
				ep->engr_txt[pos] = (ch != '?') ? '?' : ' ';
			}
		}
		while(lth && ep->engr_txt[lth-1] == ' ')
			ep->engr_txt[--lth] = 0;
		while(ep->engr_txt[0] == ' ')
			ep->engr_txt++;
		if(!ep->engr_txt[0]) del_engr(ep);
	}
}

read_engr_at(x,y) register int x,y; {
register struct engr *ep = engr_at(x,y);
	if(ep && ep->engr_txt[0]) {
	    switch(ep->engr_type) {
	    case DUST:
		pline("Something is written here in the dust.");
		break;
	    case ENGRAVE:
		pline("Something is engraved here on the floor.");
		break;
	    case BURN:
		pline("Some text has been burned here in the floor.");
		break;
	    default:
		pline("Something is written in a very strange way.");
		impossible();
	    }
	    pline("You read: \"%s\".", ep->engr_txt);
	}
}
make_engr_at(x,y,s)
register int x,y;
register char *s;
{
	register struct engr *ep;

	if(ep = engr_at(x,y))
	    del_engr(ep);
	ep = (struct engr *)
	    alloc((unsigned)(sizeof(struct engr) + strlen(s) + 1));
	ep->nxt_engr = head_engr;
	head_engr = ep;
	ep->engr_x = x;
	ep->engr_y = y;
	ep->engr_txt = (char *)(ep + 1);
	(void) strcpy(ep->engr_txt, s);
	ep->engr_time = 0;
	ep->engr_type = DUST;
	ep->engr_lth = strlen(s) + 1;
}

doengrave(){
register int len;
register char *sp;
register struct engr *ep, *oep = engr_at(u.ux,u.uy);
char buf[BUFSZ];
xchar type;
int spct;		/* number of leading spaces */
register struct obj *otmp;
	multi = 0;
	if(u.uswallow) {
		pline("You're joking. Hahaha!");	/* riv05!a3 */
		return(0);
	}

	/* one may write with finger, weapon or wand */
	otmp = getobj("#-)/", "write with");
	if(!otmp) return(0);
	if(otmp == (struct obj *)(1))
		type = DUST;
	else if(otmp->otyp == WAN_FIRE && otmp->spe) {
		type = BURN;
		otmp->spe--;
	} else if(otmp->otyp == DAGGER || otmp->otyp == TWO_HANDED_SWORD ||
		otmp->otyp == CRYSKNIFE ||
		otmp->otyp == LONG_SWORD || otmp->otyp == AXE){
		type = ENGRAVE;
		if((int)otmp->spe <= -3) {
			type = DUST;
			pline("Your %s too dull for engraving.",
				aobjnam(otmp, "are"));
			if(oep && oep->engr_type != DUST) return(1);
		}
	} else	type = DUST;
	if(Levitation && type != BURN){		/* riv05!a3 */
		pline("You can't reach the floor!");
		return(1);
	}
	if(oep && oep->engr_type == DUST){
		  pline("You wipe out the message that was written here.");
		  del_engr(oep);
		  oep = 0;
	}
	if(type == DUST && oep){
	pline("You cannot wipe out the message that is %s in the rock.",
		    (oep->engr_type == BURN) ? "burned" : "engraved");
		  return(1);
	}

	pline("What do you want to %s on the floor here? ",
	  (type == ENGRAVE) ? "engrave" : (type == BURN) ? "burn" : "write");
	getlin(buf);
	clrlin();
	spct = 0;
	sp = buf;
	while(*sp == ' ') spct++, sp++;
	len = strlen(sp);
	if(!len) {
		if(type == BURN) otmp->spe++;
		return(0);
	}
	
	switch(type) {
	case DUST:
	case BURN:
		if(len > 15) {
			multi = -(len/10);
			nomovemsg = "You finished writing.";
		}
		break;
	case ENGRAVE:
		{	int len2 = (otmp->spe + 3) * 2 + 1;
			char *bufp = doname(otmp);
			if(digit(*bufp))
				pline("Your %s get dull.", bufp);
			else {
				if(!strncmp(bufp,"a ",2))
					bufp += 2;
				else if(!strncmp(bufp,"an ",3))
					bufp += 3;
				pline("Your %s gets dull.", bufp);
			}
			if(len2 < len) {
				len = len2;
				sp[len] = 0;
				otmp->spe = -3;
				nomovemsg = "You cannot engrave more.";
			} else {
				otmp->spe -= len/2;
				nomovemsg = "You finished engraving.";
			}
			multi = -len;
		}
		break;
	}
	if(oep) len += strlen(oep->engr_txt) + spct;
	ep = (struct engr *) alloc((unsigned)(sizeof(struct engr) + len + 1));
	ep->nxt_engr = head_engr;
	head_engr = ep;
	ep->engr_x = u.ux;
	ep->engr_y = u.uy;
	sp = (char *)(ep + 1);	/* (char *)ep + sizeof(struct engr) */
	ep->engr_txt = sp;
	if(oep) {
		(void) strcpy(sp, oep->engr_txt);
		(void) strcat(sp, buf);
		del_engr(oep);
	} else
		(void) strcpy(sp, buf);
	ep->engr_lth = len+1;
	ep->engr_type = type;
	ep->engr_time = moves-multi;

	/* kludge to protect pline against excessively long texts */
	if(len > BUFSZ-20) sp[BUFSZ-20] = 0;

	return(1);
}

save_engravings(fd) int fd; {
register struct engr *ep = head_engr;
	while(ep) {
		if(!ep->engr_lth || !ep->engr_txt[0]){
			ep = ep->nxt_engr;
			continue;
		}
		bwrite(fd, (char *) & (ep->engr_lth), sizeof(ep->engr_lth));
		bwrite(fd, (char *) ep, sizeof(struct engr) + ep->engr_lth);
		ep = ep->nxt_engr;
	}
	bwrite(fd, (char *) nul, sizeof(unsigned));
}

rest_engravings(fd) int fd; {
register struct engr *ep;
unsigned lth;
	head_engr = 0;
	while(1) {
		mread(fd, (char *) &lth, sizeof(unsigned));
		if(lth == 0) return;
		ep = (struct engr *) alloc(sizeof(struct engr) + lth);
		mread(fd, (char *) ep, sizeof(struct engr) + lth);
		ep->engr_txt = (char *) (ep + 1);	/* Andreas Bormann */
		ep->nxt_engr = head_engr;
		head_engr = ep;
	}
}

del_engr(ep) register struct engr *ep; {
register struct engr *ept;
	if(ep == head_engr)
		head_engr = ep->nxt_engr;
	else {
		for(ept = head_engr; ept; ept = ept->nxt_engr)
			if(ept->nxt_engr == ep) {
				ept->nxt_engr = ep->nxt_engr;
				goto fnd;
			}
		pline("Error in del_engr?"); impossible();
	fnd:	;
	}
	free((char *) ep);
}
#file hack.fight.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.fight.c version 1.0.1 - corrected symbol of lurker above */

#include	"hack.h"
extern char *exclam(), *xname();

static boolean far_noise;
static long noisetime;

/* hitmm returns 0 (miss), 1 (hit), or 2 (kill) */
hitmm(magr,mdef) register struct monst *magr,*mdef; {
register struct permonst *pa = magr->data, *pd = mdef->data;
int hit;
schar tmp;
boolean vis;
	if(index("Eauy", pa->mlet)) return(0);
	if(magr->mfroz) return(0);		/* riv05!a3 */
	tmp = pd->ac + pa->mlevel;
	if(mdef->mconf || mdef->mfroz || mdef->msleep){
		tmp += 4;
		if(mdef->msleep) mdef->msleep = 0;
	}
	hit = (tmp > rnd(20));
	if(hit) mdef->msleep = 0;
	vis = (cansee(magr->mx,magr->my) && cansee(mdef->mx,mdef->my));
	if(vis){
		char buf[BUFSZ];
		if(mdef->mimic) seemimic(mdef);
		if(magr->mimic) seemimic(magr);
		(void) sprintf(buf,"%s %s", Monnam(magr),
			hit ? "hits" : "misses");
		pline("%s %s.", buf, monnam(mdef));
	} else {
		boolean far = (dist(magr->mx, magr->my) > 15);
		if(far != far_noise || moves-noisetime > 10) {
			far_noise = far;
			noisetime = moves;
			pline("You hear some noises%s.",
				far ? " in the distance" : "");
		}
	}
	if(hit){
		if(magr->data->mlet == 'c' && !magr->cham) {
			magr->orig_hp += 3;
			if(vis) pline("%s is turned to stone!", Monnam(mdef));
			else if(mdef->mtame)
     pline("You have a peculiarly sad feeling for a moment, then it passes.");
			monstone(mdef);
			hit = 2;
		} else
		if((mdef->mhp -= d(pa->damn,pa->damd)) < 1) {
			magr->orig_hp += 1 + rn2(pd->mlevel+1);
			if(magr->mtame && magr->orig_hp > 8*pa->mlevel){
				if(pa == PM_LI_DOG)
					magr->data = pa = PM_DOG;
				else if(pa == PM_DOG)
					magr->data = pa = PM_LA_DOG;
			}
			if(vis) pline("%s is killed!", Monnam(mdef));
			else if(mdef->mtame)
		pline("You have a sad feeling for a moment, then it passes.");
			mondied(mdef);
			hit = 2;
		}
	}
	return(hit);
}

/* drop (perhaps) a cadaver and remove monster */
mondied(mdef) register struct monst *mdef; {
register struct permonst *pd = mdef->data;
		if(letter(pd->mlet) && rn2(3)){
			mksobj_at(pd->mlet,CORPSE,mdef->mx,mdef->my);
			if(cansee(mdef->mx,mdef->my)){
				unpmon(mdef);
				atl(mdef->mx,mdef->my,fobj->olet);
			}
			stackobj(fobj);
		}
		mondead(mdef);
}

/* drop a rock and remove monster */
monstone(mdef) register struct monst *mdef; {
	extern char mlarge[];
	if(index(mlarge, mdef->data->mlet))
		mksobj_at(ROCK_SYM, ENORMOUS_ROCK, mdef->mx, mdef->my);
	else
		mksobj_at(WEAPON_SYM, ROCK, mdef->mx, mdef->my);
	if(cansee(mdef->mx, mdef->my)){
		unpmon(mdef);
		atl(mdef->mx,mdef->my,fobj->olet);
	}
	mondead(mdef);
}
		

fightm(mtmp) register struct monst *mtmp; {
register struct monst *mon;
	for(mon = fmon; mon; mon = mon->nmon) if(mon != mtmp) {
		if(DIST(mon->mx,mon->my,mtmp->mx,mtmp->my) < 3)
		    if(rn2(4))
			return(hitmm(mtmp,mon));
	}
	return(-1);
}

hitu(mtmp,dam)
register struct monst *mtmp;
register int dam;
{
	register int tmp;

	if(u.uswallow) return(0);

	if(mtmp->mhide && mtmp->mundetected) {
		mtmp->mundetected = 0;
		if(!Blind) {
			register struct obj *obj;
			extern char * Xmonnam();
			if(obj = o_at(mtmp->mx,mtmp->my))
				pline("%s was hidden under %s!",
					Xmonnam(mtmp), doname(obj));
		}
	}

	tmp = u.uac;
	/* give people with Ac = -10 at least some vulnerability */
	if(tmp < 0) {
		dam += tmp;		/* decrease damage */
		if(dam <= 0) dam = 1;
		tmp = -rn2(-tmp);
	}
	tmp += mtmp->data->mlevel;
	if(multi < 0) tmp += 4;
	if(Invis || !mtmp->mcansee) tmp -= 2;
	if(mtmp->mtrapped) tmp -= 2;
	if(tmp <= rnd(20)) {
		if(Blind) pline("It misses.");
		else pline("%s misses.",Monnam(mtmp));
		return(0);
	}
	if(Blind) pline("It hits!");
	else pline("%s hits!",Monnam(mtmp));
	losehp_m(dam, mtmp);
	return(1);
}

/* u is hit by sth, but not a monster */
thitu(tlev,dam,name)
register int tlev,dam;
register char *name;
{
char buf[BUFSZ];
	setan(name,buf);
	if(u.uac + tlev <= rnd(20)) {
		if(Blind) pline("It misses.");
		else pline("You are almost hit by %s!", buf);
		return(0);
	} else {
		if(Blind) pline("You are hit!");
		else pline("You are hit by %s!", buf);
		losehp(dam,name);
		return(1);
	}
}

char mlarge[] = "bCDdegIlmnoPSsTUwY\',&";

boolean
hmon(mon,obj,thrown)	/* return TRUE if mon still alive */
register struct monst *mon;
register struct obj *obj;
register int thrown;
{
	register int tmp;

	if(!obj){
		tmp = rnd(2);	/* attack with bare hands */
		if(mon->data->mlet == 'c' && !uarmg){
			pline("You hit the cockatrice with your bare hands");
			pline("You turn to stone ...");
			done_in_by(mon);
		}
	} else if(obj->olet == WEAPON_SYM) {
	    if(obj == uwep && (obj->otyp > SPEAR || obj->otyp < BOOMERANG))
		tmp = rnd(2);
	    else {
		if(index(mlarge, mon->data->mlet)) {
			tmp = rnd(objects[obj->otyp].wldam);
			if(obj->otyp == TWO_HANDED_SWORD) tmp += d(2,6);
			else if(obj->otyp == FLAIL) tmp += rnd(4);
		} else {
			tmp = rnd(objects[obj->otyp].wsdam);
		}
		tmp += obj->spe;
		if(!thrown && obj == uwep && obj->otyp == BOOMERANG
		 && !rn2(3)){
		  pline("As you hit %s, the boomerang breaks into splinters.",
				monnam(mon));
			freeinv(obj);
			setworn((struct obj *) 0, obj->owornmask);
			obfree(obj, (struct obj *) 0);
			tmp++;
		}
	    }
	    if(mon->data->mlet == 'O' && !strcmp(ONAME(obj), "Orcrist"))
		tmp += rnd(10);
	} else	switch(obj->otyp) {
		case HEAVY_IRON_BALL:
			tmp = rnd(25); break;
		case EXPENSIVE_CAMERA:
	pline("You succeed in destroying your camera. Congratulations!");
			freeinv(obj);
			if(obj->owornmask)
				setworn((struct obj *) 0, obj->owornmask);
			obfree(obj, (struct obj *) 0);
			return(TRUE);
		case DEAD_COCKATRICE:
			pline("You hit %s with the cockatrice corpse",
				monnam(mon));
			pline("%s is turned to stone!", Monnam(mon));
			killed(mon);
			return(FALSE);
		case CLOVE_OF_GARLIC:
			if(index(" VWZ", mon->data->mlet))
				mon->mflee = 1;
			tmp = 1;
			break;
		default:
			/* non-weapons can damage because of their weight */
			/* (but not too much) */
			tmp = obj->owt/10;
			if(tmp < 1) tmp = 1;
			else tmp = rnd(tmp);
			if(tmp > 6) tmp = 6;
		}

	/****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG) */

	tmp += u.udaminc + dbon();
	if(u.uswallow)
		if(mon->data->mlet == 'P') {
			if((tmp -= u.uswldtim) <= 0) {
				pline("Your arms are no longer able to hit.");
				return(TRUE);
			}
		}
	if(tmp < 1) tmp = 1;
	mon->mhp -= tmp;
	if(mon->mhp < 1) {
		killed(mon);
		return(FALSE);
	}

	if(thrown) {	/* this assumes that we cannot throw plural things */
		hit( xname(obj)		/* or: objects[obj->otyp].oc_name */,
			mon, exclam(tmp) );
		return(TRUE);
	}
	if(Blind) pline("You hit it.");
	else pline("You hit %s%s", monnam(mon), exclam(tmp));

	if(u.umconf) {
		if(!Blind) {
			pline("Your hands stop glowing blue.");
			if(!mon->mfroz && !mon->msleep)
				pline("%s appears confused.",Monnam(mon));
		}
		mon->mconf = 1;
		u.umconf = 0;
	}
	return(TRUE);	/* mon still alive */
}
#file hack.invent.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include   "hack.h"
#include   <stdio.h>
#undef max

extern struct obj *splitobj();
extern char morc;
#ifndef NOWORM
#include   "def.wseg.h"

extern struct wseg *wsegs[32];
#endif NOWORM

struct obj *
addinv(obj) register struct obj *obj; {
   register struct obj *otmp;
   for(otmp = invent; otmp; otmp = otmp->nobj) {
      if(merged(otmp, obj, 0)) return(otmp);
      if(!otmp->nobj) {
         otmp->nobj = obj;
         obj->nobj = 0;
         return(obj);
      }
   }
   invent = obj;
   obj->nobj = 0;
   return(obj);
}

useup(obj)
register struct obj *obj;
{
   if(obj->quan > 1){
      obj->quan--;
      obj->owt = weight(obj);
   } else {
      setnotworn(obj);
      freeinv(obj);
      obfree(obj, (struct obj *) 0);
   }
}

freeinv(obj) register struct obj *obj; {
   register struct obj *otmp;
   if(obj == invent) invent = invent->nobj;
   else {
      for(otmp = invent; otmp->nobj != obj; otmp = otmp->nobj)
         if(!otmp->nobj) panic("freeinv");
      otmp->nobj = obj->nobj;
   }
}

/* destroy object in fobj chain (if unpaid, it remains on the bill) */
delobj(obj) register struct obj *obj; {
   freeobj(obj);
   unpobj(obj);
   obfree(obj, (struct obj *) 0);
}

/* unlink obj from chain starting with fobj */
freeobj(obj) register struct obj *obj; {
   register struct obj *otmp;

   if(obj == fobj) fobj = fobj->nobj;
   else {
      for(otmp = fobj; otmp->nobj != obj; otmp = otmp->nobj)
         if(!otmp) panic("error in freeobj");
      otmp->nobj = obj->nobj;
   }
}

/* Note: freegold throws away its argument! */
freegold(gold) register struct gen *gold; {
   register struct gen *gtmp;

   if(gold == fgold) fgold = gold->ngen;
   else {
      for(gtmp = fgold; gtmp->ngen != gold; gtmp = gtmp->ngen)
         if(!gtmp) panic("error in freegold");
      gtmp->ngen = gold->ngen;
   }
   free((char *) gold);
}

deltrap(trap)
register struct gen *trap;
{
   register struct gen *gtmp;

   if(trap==ftrap) ftrap=ftrap->ngen;
   else {
      for(gtmp=ftrap;gtmp->ngen!=trap;gtmp=gtmp->ngen) ;
      gtmp->ngen=trap->ngen;
   }
   free((char *) trap);
}

struct wseg *m_atseg;

struct monst *
m_at(x,y)
register int x,y;
{
   register struct monst *mtmp;
#ifndef NOWORM
   register struct wseg *wtmp;
#endif NOWORM

   m_atseg = 0;
   for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
      if(mtmp->mx == x && mtmp->my == y)
         return(mtmp);
#ifndef NOWORM
      if(mtmp->wormno){
          for(wtmp = wsegs[mtmp->wormno]; wtmp; wtmp = wtmp->nseg)
          if(wtmp->wx == x && wtmp->wy == y){
         m_atseg = wtmp;
         return(mtmp);
          }
      }
#endif NOWORM
   }
   return(0);
}

struct obj *
o_at(x,y)
register int x,y;
{
   register struct obj *otmp;

   for(otmp = fobj; otmp; otmp = otmp->nobj)
      if(otmp->ox == x && otmp->oy == y) return(otmp);
   return(0);
}

struct obj *
sobj_at(n,x,y)
register int n,x,y;
{
   register struct obj *otmp;

   for(otmp = fobj; otmp; otmp = otmp->nobj)
      if(otmp->ox == x && otmp->oy == y && otmp->otyp == n)
         return(otmp);
   return(0);
}

carried(obj) register struct obj *obj; {
register struct obj *otmp;
   for(otmp = invent; otmp; otmp = otmp->nobj)
      if(otmp == obj) return(1);
   return(0);
}

struct obj *
o_on(id, objchn) unsigned int id; register struct obj *objchn; {
   while(objchn) {
      if(objchn->o_id == id) return(objchn);
      objchn = objchn->nobj;
   }
   return((struct obj *) 0);
}

struct gen *
g_at(x,y,ptr)
register int x,y;
register struct gen *ptr;
{
   while(ptr) {
      if(ptr->gx == x && ptr->gy == y) return(ptr);
      ptr = ptr->ngen;
   }
   return(0);
}

/* getobj returns:
   struct obj *xxx:   object to do something with.
   0            error return: no object.
   1            explicitly no object (as in w-).
*/
struct obj *
getobj(let,word)
register char *let,*word;
{
   register struct obj *otmp;
   register char ilet,ilet1,ilet2;
   char buf[BUFSZ];
   char lets[BUFSZ];
   register int foo = 0, foo2, cnt;
   register char *bp = buf;
   xchar allowcnt = 0;   /* 0, 1 or 2 */
   boolean allowgold = FALSE;
   boolean allowall = FALSE;
   boolean allownone = FALSE;
   xchar foox = 0;

   if(*let == '0') let++, allowcnt = 1;
   if(*let == '$') let++, allowgold = TRUE;
   if(*let == '#') let++, allowall = TRUE;
   if(*let == '-') let++, allownone = TRUE;
   if(allownone) *bp++ = '-';
   if(allowgold) *bp++ = '$';
   if(bp[-1] == '-') *bp++ = ' ';

   ilet = 'a';
   for(otmp = invent; otmp; otmp = otmp->nobj){
      if(!*let || index(let, otmp->olet)) {
         bp[foo++] = ilet;
         /* ugly check: remove inappropriate things */
         if((!strcmp(word, "take off") &&
             !(otmp->owornmask & (W_ARMOR - W_ARM2)))
         || (!strcmp(word, "wear") &&
             (otmp->owornmask & (W_ARMOR | W_RING)))
         || (!strcmp(word, "wield") &&
             (otmp->owornmask & W_WEP))) {
            foo--;
            foox++;
         }
      }
      if(ilet == 'z') ilet = 'A'; else ilet++;
   }
   bp[foo] = 0;
   if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
   (void) strcpy(lets, bp);   /* necessary since we destroy buf */
   if(foo > 5) {         /* compactify string */
      foo = foo2 = 1;
      ilet2 = bp[0];
      ilet1 = bp[1];
      while(ilet = bp[++foo2] = bp[++foo]){
         if(ilet == ilet1+1){
            if(ilet1 == ilet2+1)
               bp[foo2 - 1] = ilet1 = '-';
            else if(ilet2 == '-') {
               bp[--foo2] = ++ilet1;
               continue;
            }
         }
         ilet2 = ilet1;
         ilet1 = ilet;
      }
   }
   if(!foo && !allowall && !allowgold && !allownone) {
      pline("You don't have anything %sto %s.",
         foox ? "else " : "", word);
      return(0);
   }
   for(;;) {
      if(!buf[0])
         pline("What do you want to %s [*]? ", word);
      else
         pline("What do you want to %s [%s or ?*]? ",
            word, buf);

      cnt = 0;
      ilet = readchar();
      while(digit(ilet) && allowcnt) {
         cnt = 10*cnt + (ilet - '0');
         allowcnt = 2;   /* signal presence of cnt */
         ilet = readchar();
      }
      if(digit(ilet)) {
         pline("No count allowed with this command.");
         continue;
      }
      if(ilet == '\033' || ilet == ' ' || ilet == '\n')
         return((struct obj *)0);
      if(ilet == '-') {
         return((struct obj *)(allownone ? 1 : 0));
      }
      if(ilet == '$') {
         if(!allowgold){
            pline("You cannot %s gold.", word);
            continue;
         }
         otmp = newobj(0);
         /* should set o_id etc. but otmp will be freed soon */
         otmp->olet = '$';
         if(allowcnt == 2 && cnt < u.ugold)
            u.ugold -= cnt;
         else {
            cnt = u.ugold;
            u.ugold = 0;
         }
         flags.botl = 1;
         otmp->quan = cnt;
         return(otmp);
      }
      if(ilet == '?') {
         doinv(lets);
         if(!(ilet = morc)) continue;
         /* he typed a letter (not a space) to more() */
      } else if(ilet == '*') {
         doinv("");
         if(!(ilet = morc)) continue;
         /* ... */
      }
      if(ilet >= 'A' && ilet <= 'Z') ilet += 'z'-'A'+1;
      ilet -= 'a';
      for(otmp = invent; otmp && ilet; ilet--, otmp = otmp->nobj) ;
      if(!otmp) {
         pline("You don't have that object.");
         continue;
      }
      if(cnt < 0 || otmp->quan < cnt) {
         pline("You don't have that many! [You have %d]"
         , otmp->quan);
         continue;
      }
      break;
   }
   if(!allowall && let && !index(let,otmp->olet)) {
      pline("That is a silly thing to %s.",word);
      return(0);
   }
   if(allowcnt == 2) {   /* cnt given */
      if(cnt == 0) return(0);
      if(cnt != otmp->quan) {
         register struct obj *obj;
         obj = splitobj(otmp, cnt);
         if(otmp == uwep) setuwep(obj);
      }
   }
   return(otmp);
}

ckunpaid(otmp) register struct obj *otmp; {
   return( otmp->unpaid );
}

/* interactive version of getobj */
/* used for Drop and Identify */
ggetobj(word, fn, max)
char *word;
int (*fn)(),  max;
{
char buf[BUFSZ];
register char *ip;
register char sym;
register int oletct = 0, iletct = 0;
register boolean allflag = FALSE;
char olets[20], ilets[20];
int (*ckfn)() = (int (*)()) 0;
   if(!invent){
      pline("You have nothing to %s.", word);
      return(0);
   } else {
      register struct obj *otmp = invent;
      register int uflg = 0;

      ilets[0] = 0;
      while(otmp) {
         if(!index(ilets, otmp->olet)){
            ilets[iletct++] = otmp->olet;
            ilets[iletct] = 0;
         }
         if(otmp->unpaid) uflg = 1;
         otmp = otmp->nobj;
      }
      ilets[iletct++] = ' ';
      if(uflg) ilets[iletct++] = 'u';
      ilets[iletct++] = 'a';
      ilets[iletct] = 0;
   }
   pline("What kinds of thing do you want to %s? [%s] ",
      word, ilets);
   getlin(buf);
   ip = buf;
   olets[0] = 0;
   while(sym = *ip++){
      if(sym == ' ') continue;
      if(sym == 'a') allflag = TRUE; else
      if(sym == 'u') ckfn = ckunpaid; else
      if(index("!%?[()=*/\"0", sym)){
         if(!index(olets, sym)){
            olets[oletct++] = sym;
            olets[oletct] = 0;
         }
      }
      else pline("You don't have any %c's.", sym);
   }
   return askchain(invent, olets, allflag, fn, ckfn, max);
}

/* Walk through the chain starting at objchn and ask for all objects
   with olet in olets (if nonNULL) and satisfying ckfn (if nonNULL)
   whether the action in question (i.e., fn) has to be performed.
   If allflag then no questions are asked. Max gives the max nr of
   objects treated.
 */
askchain(objchn, olets, allflag, fn, ckfn, max)
struct obj *objchn;
register char *olets;
int allflag;
int (*fn)(), (*ckfn)();
int max;
{
register struct obj *otmp, *otmp2;
register char sym, ilet;
register int cnt = 0;
   ilet = 'a'-1;
   for(otmp = objchn; otmp; otmp = otmp2){
      if(ilet == 'z') ilet = 'A'; else ilet++;
      otmp2 = otmp->nobj;
      if(olets && *olets && !index(olets, otmp->olet)) continue;
      if(ckfn && !(*ckfn)(otmp)) continue;
      if(!allflag) {
         prname(otmp, ilet, 1);
         addtopl(" (ynaq)? ");
         sym = readchar();
      }
      else   sym = 'y';

      switch(sym){
      case 'a':
         allflag = 1;
      case 'y':
         cnt += (*fn)(otmp);
         if(--max == 0) goto ret;
      case 'n':
      default:
         break;
      case 'q':
         goto ret;
      }
   }
   pline(cnt ? "That was all." : "No applicable objects.");
ret:
   if(!flags.echo) echo(OFF);
   return(cnt);
}

obj_to_let(obj)
register struct obj *obj;
{
   register struct obj *otmp;
   register char ilet = 'a';

   for(otmp = invent; otmp && otmp != obj; otmp = otmp->nobj)
      if(++ilet > 'z') ilet = 'A';
   return(otmp ? ilet : 0);
}

prinv(obj)
register struct obj *obj;
{
   prname(obj, obj_to_let(obj), 1);
}

prname(obj,let,onelin)
register struct obj *obj;
register char let;
{
   char li[BUFSZ];

   (void) sprintf(li, " %c - %s.", let, doname(obj));
   switch(onelin) {
   case 1:
      pline(li+1);
      break;
   case 0:
      myputs(li+1);
      break;
   case -1:
      cl_end();
      myputs(li);
      curx += strlen(li);
   }
}

ddoinv()
{
   doinv((char *) 0);
   return(0);
}

myddoinv()
{
   mydoinv((char *) 0);
   return(0);
}

myprname(obj,let,onelin)
register struct obj *obj;
register char let;
{
   char li[BUFSZ];

   (void) sprintf(li, " %c - %s.", let, mydoname(obj));
   switch(onelin) {
   case 1:
      pline(li+1);
      break;
   case 0:
      myputs(li+1);
      break;
   case -1:
      cl_end();
      myputs(li);
      curx += strlen(li);
   }
}

mydoinv(lets) register char *lets; {
   register struct obj *otmp;
   register char ilet = 'a';
   int ct = 0;
   int maxlth = 0;
   int lth;

   if(!invent){
      pline("Not carrying anything");
      if(lets) return;
   }
   if(!flags.oneline) {
       if(!lets || !*lets)
      for(otmp = invent; otmp; otmp = otmp->nobj) ct++;
       else
      ct = strlen(lets);
       if(ct > 1 && ct < ROWNO && (lets || !inshop())){
      for(otmp = invent; otmp; otmp = otmp->nobj) {
          if(!lets || !*lets || index(lets, ilet)) {
         lth = strlen(doname(otmp));
         if(lth > maxlth) maxlth = lth;
          }
          if(++ilet > 'z') ilet = 'A';
      }
      ilet = 'a';
      lth = COLNO - maxlth - 7;
      if(lth < 10) goto clrscr;
      home();
      cl_end();
      flags.topl = 0;
      ct = 0;
      for(otmp = invent; otmp; otmp = otmp->nobj) {
          if(!lets || !*lets || index(lets, ilet)) {
         curs(lth, ++ct);
         myprname(otmp, ilet, -1);
          }
          if(++ilet > 'z') ilet = 'A';
      }
      curs(lth, ct+1);
      cl_end();
      cmore();   /* sets morc */
      /* test whether morc is a reasonable answer */
      if(lets && *lets && !index(lets, morc)) morc = 0;

      home();
      cl_end();
      docorner(lth, ct);
      return;
       }
   }
    clrscr:
   if(ct > 1) cls();
   for(otmp = invent; otmp; otmp = otmp->nobj){
      if(!lets || !*lets || index(lets, ilet))
         myprname(otmp, ilet, (ct > 1) ? 0 : 1);
      if(++ilet > 'z') ilet = 'A';
   }
   /* tell doinvbill whether we cleared the screen */
   if(!lets) doinvbill((ct > 1));
   if(ct > 1){
      cgetret();
      docrt();
   } else
      morc = 0;   /* %% */
}

doinv(lets) register char *lets; {
   register struct obj *otmp;
   register char ilet = 'a';
   int ct = 0;
   int maxlth = 0;
   int lth;

   if(!invent){
      pline("Not carrying anything");
      if(lets) return;
   }
   if(!flags.oneline) {
       if(!lets || !*lets)
      for(otmp = invent; otmp; otmp = otmp->nobj) ct++;
       else
      ct = strlen(lets);
       if(ct > 1 && ct < ROWNO && (lets || !inshop())){
      for(otmp = invent; otmp; otmp = otmp->nobj) {
          if(!lets || !*lets || index(lets, ilet)) {
         lth = strlen(doname(otmp));
         if(lth > maxlth) maxlth = lth;
          }
          if(++ilet > 'z') ilet = 'A';
      }
      ilet = 'a';
      lth = COLNO - maxlth - 7;
      if(lth < 10) goto clrscr;
      home();
      cl_end();
      flags.topl = 0;
      ct = 0;
      for(otmp = invent; otmp; otmp = otmp->nobj) {
          if(!lets || !*lets || index(lets, ilet)) {
         curs(lth, ++ct);
         prname(otmp, ilet, -1);
          }
          if(++ilet > 'z') ilet = 'A';
      }
      curs(lth, ct+1);
      cl_end();
      cmore();   /* sets morc */
      /* test whether morc is a reasonable answer */
      if(lets && *lets && !index(lets, morc)) morc = 0;

      home();
      cl_end();
      docorner(lth, ct);
      return;
       }
   }
    clrscr:
   if(ct > 1) cls();
   for(otmp = invent; otmp; otmp = otmp->nobj){
      if(!lets || !*lets || index(lets, ilet))
         prname(otmp, ilet, (ct > 1) ? 0 : 1);
      if(++ilet > 'z') ilet = 'A';
   }
   /* tell doinvbill whether we cleared the screen */
   if(!lets) doinvbill((ct > 1));
   if(ct > 1){
      cgetret();
      docrt();
   } else
      morc = 0;   /* %% */
}

stackobj(obj) register struct obj *obj; {
register struct obj *otmp = fobj;
   for(otmp = fobj; otmp; otmp = otmp->nobj) if(otmp != obj)
   if(otmp->ox == obj->ox && otmp->oy == obj->oy &&
      merged(obj,otmp,1))
         return;
}

/* merge obj with otmp and delete obj if types agree */
merged(otmp,obj,lose) register struct obj *otmp, *obj; {
   if(otmp->otyp == obj->otyp &&
     obj->unpaid == otmp->unpaid && obj->spe == otmp->spe &&
     obj->known == otmp->known && obj->dknown == otmp->dknown &&
     obj->cursed == otmp->cursed &&
     ((obj->olet == WEAPON_SYM && obj->otyp < BOOMERANG)
     || index("%?!*",otmp->olet))){
      otmp->quan += obj->quan;
      otmp->owt += obj->owt;
      if(lose) freeobj(obj);
      obfree(obj,otmp);   /* free(obj), bill->otmp */
      return(1);
   } else   return(0);
}

doprwep(){
   if(!uwep) pline("You are empty handed.");
   else prinv(uwep);
   return(0);
}

doprarm(){
   if(!uarm && !uarmg && !uarms && !uarmh)
      pline("You are not wearing any armor.");
   else {
      char lets[6];
      register int ct = 0;

      if(uarm) lets[ct++] = obj_to_let(uarm);
      if(uarm2) lets[ct++] = obj_to_let(uarm2);
      if(uarmh) lets[ct++] = obj_to_let(uarmh);
      if(uarms) lets[ct++] = obj_to_let(uarms);
      if(uarmg) lets[ct++] = obj_to_let(uarmg);
      lets[ct] = 0;
      doinv(lets);
   }
   return(0);
}

doprring(){
   if(!uleft && !uright)
      pline("You are not wearing any rings.");
   else {
      char lets[3];
      register int ct = 0;

      if(uleft) lets[ct++] = obj_to_let(uleft);
      if(uright) lets[ct++] = obj_to_let(uright);
      lets[ct] = 0;
      doinv(lets);
   }
   return(0);
}

digit(c) char c; {
   return(c >= '0' && c <= '9');
}

#file hack.lev.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.lev.c version 1.0.1 - somewhat more careful monster regeneration */

#include "hack.h"
#include <signal.h>
#include <stdio.h>
extern struct monst *restmonchn();
extern struct obj *restobjchn();
extern struct obj *billobjs;
extern char *itoa();

extern char nul[];
#ifndef NOWORM
#include   "def.wseg.h"

extern struct wseg *wsegs[32], *wheads[32];
extern long wgrowtime[32];
#endif NOWORM

getlev(fd)
{
   register struct gen *gtmp;
#ifndef NOWORM
   register struct wseg *wtmp;
#endif NOWORM
   register int tmp;
   long omoves;

   if(fd<0 || read(fd, (char *) levl, sizeof(levl)) != sizeof(levl))
      return(1);
   fgold = 0;
   ftrap = 0;
   mread(fd, (char *)&omoves, sizeof(omoves));   /* 0 from MKLEV */
   mread(fd, (char *)&xupstair, sizeof(xupstair));
   mread(fd, (char *)&yupstair, sizeof(yupstair));
   mread(fd, (char *)&xdnstair, sizeof(xdnstair));
   mread(fd, (char *)&ydnstair, sizeof(ydnstair));

   fmon = restmonchn(fd);
   if(omoves) {
	/* regenerate animals while on another level */
	long tmoves = (moves > omoves) ? moves-omoves : 0;
	register struct monst *mtmp, *mtmp2;
	extern char genocided[];
	long newhp;

       for(mtmp = fmon; mtmp; mtmp = mtmp2) {
      mtmp2 = mtmp->nmon;
      if(index(genocided, mtmp->data->mlet)) {
         mondead(mtmp);
         continue;
		}
		newhp = mtmp->mhp +
			(index("ViT", mtmp->data->mlet) ? tmoves : tmoves/20);
		if(newhp > mtmp->orig_hp)
			mtmp->mhp = mtmp->orig_hp;
		else
			mtmp->mhp = newhp;
       }
   }

   setshk();
   setgd();
   gtmp = newgen();
   mread(fd, (char *)gtmp, sizeof(struct gen));
   while(gtmp->gx) {
      gtmp->ngen = fgold;
      fgold = gtmp;
      gtmp = newgen();
      mread(fd, (char *)gtmp, sizeof(struct gen));
   }
   mread(fd, (char *)gtmp, sizeof(struct gen));
   while(gtmp->gx) {
      gtmp->ngen = ftrap;
      ftrap = gtmp;
      gtmp = newgen();
      mread(fd, (char *)gtmp, sizeof(struct gen));
   }
   free((char *) gtmp);
   fobj = restobjchn(fd);
   billobjs = restobjchn(fd);
   rest_engravings(fd);
#ifndef QUEST
   mread(fd, (char *)rooms, sizeof(rooms));
   mread(fd, (char *)doors, sizeof(doors));
#endif QUEST
   if(!omoves) return(0);   /* from MKLEV */
#ifndef NOWORM
   mread(fd, (char *)wsegs, sizeof(wsegs));
   for(tmp = 1; tmp < 32; tmp++) if(wsegs[tmp]){
      wheads[tmp] = wsegs[tmp] = wtmp = newseg();
      while(1) {
         mread(fd, (char *)wtmp, sizeof(struct wseg));
         if(!wtmp->nseg) break;
         wheads[tmp]->nseg = wtmp = newseg();
         wheads[tmp] = wtmp;
      }
   }
   mread(fd, (char *)wgrowtime, sizeof(wgrowtime));
#endif NOWORM
   return(0);
}

mread(fd, buf, len)
register int fd;
register char *buf;
register unsigned len;
{
register int rlen;
   rlen = read(fd, buf, (int) len);
   if(rlen != len){
      pline("Read %d instead of %d bytes\n", rlen, len);
      panic("Cannot read %d bytes from file #%d\n", len, fd);
   }
}
#file hack.main.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.main.c version 1.0.1 - some cosmetic changes */

#include <stdio.h>
#include <signal.h>
/* #include <errno.h> */
#include "hack.h"

extern char plname[PL_NSIZ], pl_character[PL_CSIZ];
#ifndef AMIGA
extern char *getlogin();
extern char *getenv();
#endif

int (*afternmv)();

int done1();
int hangup();

char safelock[] = "safelock";
xchar locknum;            /* max num of players */
char SAVEF[PL_NSIZ + 22] = "Saved Games/";
char perm[] = "perm";
char *hname;      /* name of the game (argv[0] of call) */
char obuf[BUFSIZ];   /* BUFSIZ is defined in stdio.h */

extern char *nomovemsg;
extern long wailmsg;

main(argc,argv)
int argc;
char *argv[];
{
   int fd;
#ifdef NEWS
	int nonews = 0;
#endif NEWS
   char *dir;

   initterm();
#ifdef AMIGA
   if (argc == 0)
	{
	geticon();
	hname = HACKNAME;
	argc = 1;
	}
   else
#endif
   hname = argv[0];

   /*
    * See if we must change directory to the playground.
    * (Perhaps hack runs suid and playground is inaccessible
    *  for the player.)
    * The environment variable HACKDIR is overridden by a
    *  -d command line option.
    */
#ifndef AMIGA
   if ( (dir = getenv("HACKDIR")) == NULL)
#endif
	dir = HACKDIR;

   if(argc > 1 && !strncmp(argv[1], "-d", 2)) {
      argc--;
      argv++;
      dir = argv[0]+2;
      if(*dir == '=' || *dir == ':') dir++;
      if(!*dir && argc > 1) {
         argc--;
         argv++;
         dir = argv[0];
      }
      if(!*dir)
		    error("Flag -d must be followed by a directory name.");
   }
#ifndef AMIGA
	/*
	 * Now we know the directory containing 'record' and
	 * may do a prscore().
	 */
	if(argc > 1 && !strncmp(argv[1], "-s", 2)) {
		if(dir) chdirx(dir);
		prscore(argc, argv);
		hackexit(0);
	}
#endif
   /*
    * It seems he really wants to play. Find the creation date of
    * this game so as to avoid restoring outdated savefiles.
    */
   gethdate(hname);

   /*
    * We cannot do chdir earlier, otherwise gethdate will fail.
    */
   if(dir) chdirx(dir);
#ifdef GRAPHICS
   InitGraphics();
#endif
   /*
    * Who am i? Perhaps we should use $USER instead?
    */
#ifdef AMIGA
   if (!*plname)
#endif
	(void) strncpy(plname, getlogin(), sizeof(plname)-1);

	/*
	 * Process options.
	 */
	initoptions();
	while(argc > 1 && argv[1][0] == '-'){
		argv++;
		argc--;
		switch(argv[0][1]){
#ifdef WIZARD
		case 'w':
			if(!strcmp(getlogin(), WIZARD))
				wizard = TRUE;
			else myprintf("Sorry.\n");
			break;
#endif WIZARD
#ifdef NEWS
		case 'n':
			flags.nonews = TRUE;
			break;
#endif NEWS
		case 'u':
			if(argv[0][2])
			(void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
			else if(argc > 1) {
				argc--;
				argv++;
			(void) strncpy(plname, argv[0], sizeof(plname)-1);
			} else
				myprintf("Player name expected after -u\n");
			break;
		default:
			myprintf("Unknown option: %s\n", *argv);
		}
	}

	if(argc > 1)
		locknum = atoi(argv[1]);
#ifdef WIZARD
	if(wizard) (void) strcpy(plname, "wizard"); else
#endif WIZARD
	if(!*plname || !strncmp(plname, "player", 4)) askname();
#ifdef AMIGA
	if (!pl_character[0])
#endif
	plnamesuffix();      /* strip suffix from name */

	setbuf(stdout,obuf);
	(void) srand(getpid());
	startup();
	cls();
	(void) signal(SIGHUP, hangup);
#ifdef WIZARD
	if(!wizard) {
#endif WIZARD
		(void) signal(SIGQUIT,SIG_IGN);
		(void) signal(SIGINT,SIG_IGN);
		if(locknum)
			lockcheck();
		else
			(void) strcpy(lock,plname);
#ifdef WIZARD
	} else {
		register char *sfoo;
		(void) strcpy(lock,plname);
#ifndef AMIGA
      if(sfoo = getenv("MAGIC"))
         while(*sfoo) {
            switch(*sfoo++) {
            case 'n': (void) srand(*sfoo++);
               break;
            }
         }
      if(sfoo = getenv("GENOCIDED")){
         if(*sfoo == '!'){
            extern struct permonst mons[PMONCOUNT];
            extern char genocided[], fut_geno[];
            register struct permonst *pm = mons;
            register char *gp = genocided;

            while(pm < mons+CMNUM+2){
               if(!index(sfoo, pm->mlet))
                  *gp++ = pm->mlet;
               pm++;
            }
            *gp = 0;
         } else
            (void) strcpy(genocided, sfoo);
         (void) strcpy(fut_geno, genocided);
      }
#endif
   }
#endif WIZARD
   u.uhp = 1;   /* prevent RIP on early quits */
   u.ux = FAR;   /* prevent nscr() */
   (void) strcat(SAVEF,plname);
   if((fd = open(SAVEF,0)) >= 0 &&
      (uptodate(fd) || unlink(SAVEF) == 666)) {
      (void) signal(SIGINT,done1);
      myputs("Restoring old save file...");
      (void) myfflush(stdout);
      dorecover(fd);
      flags.move = 0;
   } else {
#ifdef NEWS
	if(!flags.nonews)
		if((fd = open(NEWS,0)) >= 0)
			outnews(fd);
#endif NEWS
      flags.ident = 1;
      init_objects(0);
      u_init();
      (void) signal(SIGINT,done1);
      glo(1);
      mklev();
      u.ux = xupstair;
      u.uy = yupstair;
      (void) inshop();
      setsee();
      flags.botlx = 1;
      makedog();
      seemons();
      docrt();
      pickup();
      read_engr_at(u.ux,u.uy);   /* superfluous ? */
      flags.move = 1;
      flags.cbreak = ON;
      flags.echo = OFF;
   }
   setftty();
#ifdef TRACK
   initrack();
#endif TRACK
   for(;;) {
      if(flags.move) {
#ifdef TRACK
         settrack();
#endif TRACK
         if(moves%2 == 0 ||
           (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
            extern struct monst *makemon();
            movemon();
            if(!rn2(70))
                (void) makemon((struct permonst *)0, 0, 0);
         }
         if(Glib) glibr();
         timeout();
			++moves;
			if(flags.time) flags.botl = 1;
			if(u.uhp < 1) {
				pline("You die...");
				done("died");
				}
         if(u.uhp*10 < u.uhpmax && moves-wailmsg > 50){
             wailmsg = moves;
             if(u.uhp == 1)
             pline("You hear the wailing of the Banshee...");
             else
             pline("You hear the howling of the CwnAnnwn...");
         }
         if(u.uhp < u.uhpmax) {
            if(u.ulevel > 9) {
               if(Regeneration || !(moves%3)) {
                   flags.botl = 1;
                   u.uhp += rnd((int) u.ulevel-9);
                   if(u.uhp > u.uhpmax)
                  u.uhp = u.uhpmax;
               }
            } else if(Regeneration ||
               (!(moves%(22-u.ulevel*2)))) {
               flags.botl = 1;
               u.uhp++;
            }
         }
         if(Teleportation && !rn2(85)) tele();
         if(Searching && multi >= 0) (void) dosearch();
         gethungry();
         invault();
      }
      if(multi < 0) {
         if(!++multi){
            pline(nomovemsg ? nomovemsg :
               "You can move again.");
            nomovemsg = 0;
            if(afternmv) (*afternmv)();
            afternmv = 0;
         }
      }
      flags.move = 1;
      find_ac();
#ifndef QUEST
      if(!flags.mv || Blind)
#endif QUEST
      {
         seeobjs();
         seemons();
         nscr();
      }
      if(flags.botl || flags.botlx) bot();
      if(multi > 0) {
#ifdef QUEST
         if(flags.run >= 4) finddir();
#endif QUEST
         lookaround();
         if(!multi) {   /* lookaround may clear multi */
            flags.move = 0;
            continue;
         }
         if(flags.mv) {
            if(multi<COLNO && !--multi)
               flags.mv = flags.run = 0;
            domove();
         } else {
            --multi;
            rhack(save_cm);
         }
		} else if(multi == 0)
			rhack((char *) 0);
		if(multi && multi%7 == 0)
			(void) fflush(stdout);
   }
}

lockcheck()
{
/*   extern int errno;                         */
/*   register int i, fd;                       */
/*                                             */
/* we ignore QUIT and INT at this point        */
/*    if (link(perm,safelock) == -1)           */
/*        error("Cannot link safelock. (Try again or rm safelock.)");*/
/*                                             */
/*                                             */
/*    for(i = 0; i < locknum; i++) {           */
/*       lock[0]= 'a' + i;                     */
/*       if((fd = open(lock,0)) == -1) {       */
/*          if(errno == ENOENT) goto gotlock;  */  /* no such file */
/*          (void) unlink(safelock);           */
/*          error("Cannot open %s", lock);	*/
/*       }					*/
/*       (void) close(fd);			*/
/*    }						*/
/*     (void) unlink(safelock);			*/
/*   error("Too many hacks running now.");	*/
/*	}					*/
/* gotlock:					*/
/*    fd = creat(lock,FMASK);                  */
/*	if(unlink(safelock) == -1) {		*/
/*		error("Cannot unlink safelock.");*/
/*    if(fd == -1) {                           */
/*       error("cannot creat lock file.");     */
/*    } else {                                 */
/*       int pid;                              */
/*                                             */
/*       pid = getpid();                       */ 
/*		if(write(fd, (char *) &pid, sizeof(pid)) != sizeof(pid)){ */
/*          error("cannot write lock");        */
/*       }                                     */
/*	if(close(fd) == -1) {			*/
/*          error("cannot close lock");        */
/*       }                                     */
/*    }                                        */
}

/*VARARGS1*/
error(s,a1,a2,a3,a4) char *s,*a1,*a2,*a3,*a4;
   {
   myprintf("Error: ");
   myprintf(s,a1,a2,a3,a4);
   (void) myputchar('\n');
   hackexit(1);
   }

glo(foo)
register int foo;
{
   /* construct the string  xlock.n  */
   register char *tf;

   tf = lock;
   while(*tf && *tf!='.') tf++;
   (void) sprintf(tf, ".%d", foo);
}

/*
 * plname is filled either by an option (-u Player  or  -uPlayer) or
 * explicitly (-w implies wizard) or by askname.
 * It may still contain a suffix denoting pl_character.
 */
askname(){
register int c,ct;
	myprintf("\nWho are you? ");
	ct = 0;
	(void) myfflush();
	while((c = inchar()) != '\n')
		{
		if (c != '-')
			if (c == 8) { /* backspace */
				if (ct) {
					ct--;
					backsp();
					myputchar(' ');
					backsp();
					myfflush();
					}
			continue;
			}
		else
            if (c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
               if (ct < sizeof(plname)-1)
                  {
                  plname[ct++] = c;
                  myprintf("%c", c);
                  }
	(void) myfflush();
      }
   plname[ct] = 0;
   if(ct == 0) askname();
#ifdef QUEST
   else myprintf("Hello %s, welcome to quest!\n", plname);
#else
   else myprintf("Hello %s, welcome to hack!\n", plname);
#endif QUEST
}

impossible(){
   pline("Program in disorder - perhaps you'd better Quit");
}

#ifdef NEWS
int stopnews;

stopnws(){
   (void) signal(SIGINT, SIG_IGN);
   stopnews++;
}

outnews(fd) int fd; {
int (*prevsig)();
char ch;
   prevsig = signal(SIGINT, stopnws);
   while(!stopnews && read(fd,&ch,1) == 1)
      (void) myputchar(ch);
   (void) myputchar('\n');
   (void) myfflush(stdout);
   (void) close(fd);
   (void) signal(SIGINT, prevsig);
   /* See whether we will ask TSKCFW: he might have told us already */
   if(!stopnews && pl_character[0])
      getret();
}
#endif NEWS

chdirx(dir) char *dir; {
   if(chdir(dir) < 0) {
      perror(dir);
      error("Cannot chdir to %s.", dir);
   }
}
#file hack.makemon.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.makemon.c version 1.0.1 - newly created demons do not sleep */

#include	"hack.h"
extern char fut_geno[];

extern char *index();

struct monst zeromonst;

/*
 * called with [x,y] = coordinates;
 *	[0,0] means anyplace
 *	[u.ux,u.uy] means: call mnexto (not in MKLEV)
 *
 *	In case we make an Orc or killer bee, we make an entire horde (swarm);
 *	note that in this case we return only one of them (the one at [x,y]).
 */
struct monst *
makemon(ptr,x,y)
register struct permonst *ptr;
{
	register struct monst *mtmp;
	register int tmp, ct;
	boolean anything = (!ptr);

	if(x != 0 || y != 0) if(m_at(x,y)) return((struct monst *) 0);
	if(ptr){
		if(index(fut_geno, ptr->mlet)) return((struct monst *) 0);
	} else {
		ct = CMNUM - strlen(fut_geno);
		if(index(fut_geno, 'm')) ct++;  /* make only 1 minotaur */
		if(index(fut_geno, '@')) ct++;
		if(ct <= 0) return(0); 		  /* no more monsters! */
		tmp = rn2(ct*dlevel/24 + 7);
		if(tmp < dlevel - 4) tmp = rn2(ct*dlevel/24 + 12);
		if(tmp >= ct) tmp = rn1(ct - ct/2, ct/2);
		for(ct = 0; ct < CMNUM; ct++){
			ptr = &mons[ct];
			if(index(fut_geno, ptr->mlet))
				continue;
			if(!tmp--) goto gotmon;
		}
		panic("makemon?");
	}
gotmon:
	mtmp = newmonst(ptr->pxlth);
	*mtmp = zeromonst;	/* clear all entries in structure */
	for(ct = 0; ct < ptr->pxlth; ct++)
		((char *) &(mtmp->mextra[0]))[ct] = 0;
	mtmp->nmon = fmon;
	fmon = mtmp;
	mtmp->m_id = flags.ident++;
	mtmp->data = ptr;
	mtmp->mxlth = ptr->pxlth;
	if(ptr->mlet == 'D') mtmp->orig_hp = mtmp->mhp = 80;
	else if(!ptr->mlevel) mtmp->orig_hp = mtmp->mhp = rnd(4);
	else mtmp->orig_hp = mtmp->mhp = d(ptr->mlevel, 8);
	mtmp->mx = x;
	mtmp->my = y;
	mtmp->mcansee = 1;
	if(ptr->mlet == 'M')
		mtmp->mimic = ']';
/*        if (!ismklev)
           { */
	   if(x == u.ux && y == u.uy)
		mnexto(mtmp);
	   if(x == 0 && y == 0)
		rloc(mtmp);
/*           }*/
	if(ptr->mlet == 's' || ptr->mlet == 'S') {
		mtmp->mhide = mtmp->mundetected = 1;
		if(ismklev && mtmp->mx && mtmp->my)
			mkobj_at(0, mtmp->mx, mtmp->my);
	}
	if(ptr->mlet == ':') {
		mtmp->cham = 1;
                if (ismklev)
		   (void) newcham(mtmp, &mons[dlevel+14+rn2(CMNUM-14-dlevel)]);
	}
	if(ptr->mlet == 'I') mtmp->minvis = 1;
	if(ptr->mlet == 'L' || ptr->mlet == 'N'
		||(ismklev && ptr->mlet != '&' && ptr->mlet != 'w' && rn2(5))
	) mtmp->msleep = 1;

#ifndef NOWORM
/*        if (!ismklev) */
	   if(ptr->mlet == 'w' && getwn(mtmp))
		initworm(mtmp);
#endif NOWORM

	if(anything) if(ptr->mlet == 'O' || ptr->mlet == 'k') {
		coord enexto();
		coord mm;
		register int cnt = rnd(10);
		mm.x = x;
		mm.y = y;
		while(cnt--) {
			mm = enexto(mm.x, mm.y);
			(void) makemon(ptr, mm.x, mm.y);
		}
	}

	return(mtmp);
}

coord
enexto(xx,yy)
register xchar xx,yy;
{
	register xchar x,y;
	coord foo[15], *tfoo;
	int range;

	tfoo = foo;
	range = 1;
	do {	/* full kludge action. */
		for(x = xx-range; x <= xx+range; x++)
			if(goodpos(x, yy-range)) {
				tfoo->x = x;
				(tfoo++)->y = yy-range;
				if(tfoo == &foo[15]) goto foofull;
			}
		for(x = xx-range; x <= xx+range; x++)
			if(goodpos(x,yy+range)) {
				tfoo->x = x;
				(tfoo++)->y = yy+range;
				if(tfoo == &foo[15]) goto foofull;
			}
		for(y = yy+1-range; y < yy+range; y++)
			if(goodpos(xx-range,y)) {
				tfoo->x = xx-range;
				(tfoo++)->y = y;
				if(tfoo == &foo[15]) goto foofull;
			}
		for(y = yy+1-range; y < yy+range; y++)
			if(goodpos(xx+range,y)) {
				tfoo->x = xx+range;
				(tfoo++)->y = y;
				if(tfoo == &foo[15]) goto foofull;
			}
		range++;
	} while(tfoo == foo);
foofull:
	return( foo[rn2(tfoo-foo)] );
}

goodpos(x,y)	/* used only in mnexto and rloc */
{
	return(
	! (x < 1 || x > COLNO-2 || y < 1 || y > ROWNO-2 ||
	   m_at(x,y) || levl[x][y].typ < DOOR
	   || (ismklev && x == u.ux && y == u.uy)
	   || (ismklev && sobj_at(ENORMOUS_ROCK, x, y))
	));
}
#file hack.mhitu.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.mhitu.c version 1.0.1 - corrected bug for 'R' (Mike Newton)
			      - also some separate code for swallowed (a3) */
#include	"hack.h"
extern struct monst *makemon();

/*
 * mhitu: monster hits you
 *	  returns 1 if monster dies (e.g. 'y', 'F'), 0 otherwise
 */
mhitu(mtmp)
register struct monst *mtmp;
{
	register struct permonst *mdat = mtmp->data;
	register int tmp, ctmp;

	nomul(0);

	/* If swallowed, can only be affected by hissers and by u.ustuck */
	if(u.uswallow) {
		if(mtmp != u.ustuck && mdat->mlet != 'c')
			return(0);
		switch(mdat->mlet) {
		case 'c':
			if(!rn2(13)) {
				pline("Outside, you hear %s's hissing!",
					monnam(mtmp));
				pline("%s gets turned to stone!",
					Monnam(u.ustuck));
				pline("And the same fate befalls you.");
				done_in_by(mtmp);
			}
			break;
		case ',':
			youswld(mtmp,4+u.uac,5,"The trapper");
			break;
		case '\'':
			youswld(mtmp,rnd(6),7,"The lurker above");
			break;
		case 'P':
			youswld(mtmp,d(2,4),12,"The purple worm");
			break;
		default:
			pline("The mysterious monster digests you.");
			u.uhp = 0;
		}
		if(u.uhp < 1) done_in_by(mtmp);
		return(0);
	}
	if(!index("&DuxynNF",mdat->mlet))
		tmp = hitu(mtmp,d(mdat->damn,mdat->damd));
	else
		tmp = 0;

	ctmp = tmp && !mtmp->mcan &&
	  (!uarm || objects[uarm->otyp].a_can < rnd(3) || !rn2(50));
	switch(mdat->mlet) {
	case '&':
		if(!mtmp->cham && !mtmp->mcan && !rn2(13)) {
			(void) makemon(PM_DEMON,u.ux,u.uy);
		} else {
			(void) hitu(mtmp,d(2,6));
			(void) hitu(mtmp,d(2,6));
			(void) hitu(mtmp,rnd(3));
			(void) hitu(mtmp,rnd(3));
			(void) hitu(mtmp,rn1(4,2));
		}
		break;
	case ',':
		if(tmp) justswld(mtmp,"The trapper");
		break;
	case '\'':
		if(tmp) justswld(mtmp,"The lurker above");
		break;
	case 'A':
		if(ctmp && rn2(2)) {
			pline("You feel weaker!");
			losestr(1);
		}
		break;
	case 'C':
		(void) hitu(mtmp,rnd(6));
		break;
	case 'c':
		if(!rn2(5)) {
			pline("You hear %s's hissing!", monnam(mtmp));
			if(ctmp || !rn2(5)) {
				pline("You get turned to stone!");
				done_in_by(mtmp);
			}
		}
		break;
	case 'D':
		if(rn2(6) || mtmp->mcan) {
			(void) hitu(mtmp,d(3,10));
			(void) hitu(mtmp,rnd(8));
			(void) hitu(mtmp,rnd(8));
			break;
		}
		kludge("%s breathes fire!","The dragon");
		buzz(-1,mtmp->mx,mtmp->my,u.ux-mtmp->mx,u.uy-mtmp->my);
		break;
	case 'd':
		(void) hitu(mtmp,d(2,4));
		break;
	case 'e':
		(void) hitu(mtmp,d(3,6));
		break;
	case 'F':
		if(mtmp->mcan) break;
		kludge("%s explodes!","The freezing sphere");
		if(Cold_resistance) pline("You don't seem affected by it.");
		else {
			xchar dn;
			if(17-(u.ulevel/2) > rnd(20)) {
				pline("You get blasted!");
				dn = 6;
			} else {
				pline("You duck the blast...");
				dn = 3;
			}
			losehp_m(d(dn,6), mtmp);
		}
		mondead(mtmp);
		return(1);
	case 'g':
		if(ctmp && multi >= 0 && !rn2(6)) {
			kludge("You are frozen by %ss juices","the cube'");
			nomul(-rnd(10));
		}
		break;
	case 'h':
		if(ctmp && multi >= 0 && !rn2(5)) {
			nomul(-rnd(10));
			kludge("You are put to sleep by %ss bite!",
				"the homunculus'");
		}
		break;
	case 'j':
		tmp = hitu(mtmp,rnd(3));
		tmp &= hitu(mtmp,rnd(3));
		if(tmp){
			(void) hitu(mtmp,rnd(4));
			(void) hitu(mtmp,rnd(4));
		}
		break;
	case 'k':
		if((hitu(mtmp,rnd(4)) || !rn2(3)) && ctmp){
			poisoned("bee's sting",mdat->mname);
		}
		break;
	case 'L':
		if(tmp) stealgold(mtmp);
		break;
	case 'N':
		if(mtmp->mcan && !Blind) {
	pline("%s tries to seduce you, but you seem not interested.",
			Amonnam(mtmp, "plain"));
			if(rn2(3)) rloc(mtmp);
		} else if(steal(mtmp)) {
			rloc(mtmp);
			mtmp->mflee = 1;
		}
		break;
	case 'n':
		if(!uwep && !uarm && !uarmh && !uarms && !uarmg) {
		    pline("%s hits! (I hope you don't mind)",
			Monnam(mtmp));
			u.uhp += rnd(7);
			if(!rn2(7)) u.uhpmax++;
			if(u.uhp > u.uhpmax) u.uhp = u.uhpmax;
			flags.botl = 1;
			if(!rn2(50)) rloc(mtmp);
		} else {
			(void) hitu(mtmp,d(2,6));
			(void) hitu(mtmp,d(2,6));
		}
		break;
	case 'o':
		tmp = hitu(mtmp,rnd(6));
		if(hitu(mtmp,rnd(6)) && ctmp &&
		    !u.ustuck && rn2(2)) {
			u.ustuck = mtmp;
			kludge("%s has grabbed you!","The owlbear");
			u.uhp -= d(2,8);
		} else if(u.ustuck == mtmp) {
			u.uhp -= d(2,8);
			pline("You are being crushed.");
		}
		break;
	case 'P':
		if(ctmp && !rn2(4))
			justswld(mtmp,"The purple worm");
		else
			(void) hitu(mtmp,d(2,4));
		break;
	case 'Q':
		(void) hitu(mtmp,rnd(2));
		(void) hitu(mtmp,rnd(2));
		break;
	case 'R':
		if(ctmp && uarmh && !uarmh->rustfree &&
		    (int) uarmh->spe >= -1) {
			pline("Your helmet rusts!");
			uarmh->spe--;
		} else
			if(ctmp && uarm && !uarm->rustfree &&
			 uarm->otyp < STUDDED_LEATHER_ARMOR &&
			 (int)uarm->spe >= -1) {
				pline("Your armor rusts!");
				uarm->spe--;
			}
		break;
	case 'S':
		if(ctmp && !rn2(8)) {
			poisoned("snake's bite",mdat->mname);
		}
		break;
	case 's':
		if(tmp && !rn2(8)) {
			poisoned("scorpion's sting",mdat->mname);
		}
		(void) hitu(mtmp,rnd(8));
		(void) hitu(mtmp,rnd(8));
		break;
	case 'T':
		(void) hitu(mtmp,rnd(6));
		(void) hitu(mtmp,rnd(6));
		break;
	case 't':
		if(!rn2(5)) rloc(mtmp);
		break;
	case 'u':
		mtmp->mflee = 1;
		break;
	case 'U':
		(void) hitu(mtmp,d(3,4));
		(void) hitu(mtmp,d(3,4));
		break;
	case 'v':
		if(ctmp && !u.ustuck) u.ustuck = mtmp;
		break;
	case 'V':
		if(tmp) u.uhp -= 4;
		if(ctmp && !rn2(3)) losexp();
		break;
	case 'W':
		if(ctmp && !rn2(5)) losexp();
		break;
#ifndef NOWORM
	case 'w':
		if(tmp) wormhit(mtmp);
#endif NOWORM
		break;
	case 'X':
		(void) hitu(mtmp,rnd(5));
		(void) hitu(mtmp,rnd(5));
		(void) hitu(mtmp,rnd(5));
		break;
	case 'x':
		{ register long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE;
		  pline("%s pricks in your %s leg!",
			Monnam(mtmp), (side == RIGHT_SIDE) ? "right" : "left");
		  Wounded_legs |= side + rnd(5);
		  losehp_m(2, mtmp);
		  break;
		}
	case 'y':
		if(mtmp->mcan) break;
		mondead(mtmp);
		if(!Blind) {
			pline("You are blinded by a blast of light!");
			Blind = d(4,12);
			seeoff(0);
		}
		return(1);
	case 'Y':
		(void) hitu(mtmp,rnd(6));
		break;
	}
	if(u.uhp < 1) done_in_by(mtmp);
	return(0);
}

jcz@ncsu.UUCP (John A. Toebes, VIII) (02/21/86)

#file hack.pri.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.pri.c version 1.0.1 - tiny change in mnewsym() - added time */

#include "hack.h"
#include <stdio.h>
xchar scrlx, scrhx, scrly, scrhy;   /* corners of new area on screen */

extern char *hu_stat[];   /* in eat.c */

swallowed()
{
   char *ulook = "|@|";
   ulook[1] = u.usym;

   cls();
   curs(u.ux-1, u.uy+1);
   myprintf("/-\\");
   curx = u.ux+2;
   curs(u.ux-1, u.uy+2);
   myprintf(ulook);
   curx = u.ux+2;
   curs(u.ux-1, u.uy+3);
   myprintf("\\-/");
   curx = u.ux+2;
   u.udispl = 1;
   u.udisx = u.ux;
   u.udisy = u.uy;
}


/*VARARGS1*/
boolean panicking;

panic(str,a1,a2,a3,a4,a5,a6)
char *str;
{
   if(panicking++) hackexit(1);   /* avoid loops */
   home();
   myprintf(" Suddenly, the dungeon collapses.\n");
   myprintf(" ERROR:  ");
   myprintf(str,a1,a2,a3,a4,a5,a6);
/* if(fork()) */
      done("panic");
/* else          */
/*    abort();   */   /* generate core dump */
}

atl(x,y,ch)
register int x,y;
{
   register struct rm *crm = &levl[x][y];

   if(x<0 || x>COLNO-1 || y<0 || y>ROWNO-1)
      panic("at(%d,%d,%c_%o_)",x,y,ch,ch);
   if(crm->seen && crm->scrsym == ch) return;
   crm->scrsym = ch;
   crm->new = 1;
   on_scr(x,y);
}

on_scr(x,y)
register int x,y;
{
   if(x<scrlx) scrlx = x;
   if(x>scrhx) scrhx = x;
   if(y<scrly) scrly = y;
   if(y>scrhy) scrhy = y;
}

/* call: (x,y) - display
   (-1,0) - close (leave last symbol)
   (-1,-1)- close (undo last symbol)
   (-1,let)-open: initialize symbol
   (-2,let)-change let
*/

tmp_at(x,y) schar x,y; {
static schar prevx, prevy;
static char let;
   if((int)x == -2){   /* change let call */
      let = y;
      return;
   }
   if((int)x == -1 && (int)y >= 0){   /* open or close call */
      let = y;
      prevx = -1;
      return;
   }
   if(prevx >= 0 && cansee(prevx,prevy)) {
      delay_output();
      prl(prevx, prevy);   /* in case there was a monster */
      at(prevx, prevy, levl[prevx][prevy].scrsym);
   }
   if(x >= 0){   /* normal call */
      if(cansee(x,y)) at(x,y,let);
      prevx = x;
      prevy = y;
   } else {   /* close call */
      let = 0;
      prevx = -1;
   }
}

/* like the previous, but the symbols are first erased on completion */
Tmp_at(x,y) schar x,y; {
static char let;
static xchar cnt;
static coord tc[COLNO];      /* but watch reflecting beams! */
register int xx,yy;
   if((int)x == -1) {
      if(y > 0) {   /* open call */
         let = y;
         cnt = 0;
         return;
      }
      /* close call (do not distinguish y==0 and y==-1) */
      while(cnt--) {
         xx = tc[cnt].x;
         yy = tc[cnt].y;
         prl(xx, yy);
         at(xx, yy, levl[xx][yy].scrsym);
      }
      cnt = let = 0;   /* superfluous */
      return;
   }
   if((int)x == -2) {   /* change let call */
      let = y;
      return;
   }
   /* normal call */
   if(cansee(x,y)) {
      if(cnt) delay_output();
      at(x,y,let);
      tc[cnt].x = x;
      tc[cnt].y = y;
      if(++cnt >= COLNO) panic("Tmp_at overflow?");
      levl[x][y].new = 0;   /* prevent pline-nscr erasing --- */
   }
}

#ifndef GRAPHICS
at(x,y,ch)
register xchar x,y;
char ch;
{
#ifndef lint
   /* if xchar is unsigned, lint will complain about  if(x < 0)  */
   if(x < 0 || x > COLNO-1 || y < 0 || y > ROWNO-1)
      panic("At gets 0%o at %d %d(%d %d)",ch,x,y,u.ux,u.uy);
#endif lint
   if(!ch) {
      home();
      myprintf("At gets null at %2d %2d.",x,y);
      curx = ROWNO+1;
      return;
   }
   y += 2;
   curs(x,y);
   myputchar(ch);
   curx++;
}
#endif

prme(){
   if(!Invis) at(u.ux,u.uy,u.usym);
}

docrt()
{
   register int x,y;
   register struct rm *room;
   register struct monst *mtmp;

   if(u.uswallow) {
      swallowed();
      return;
   }
   cls();
   if(!Invis){
      levl[(u.udisx = u.ux)][(u.udisy = u.uy)].scrsym = u.usym;
      levl[u.udisx][u.udisy].seen = 1;
      u.udispl = 1;
   } else   u.udispl = 0;

   /* %% - is this really necessary? */
   for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
      if(mtmp->mdispl && !(room = &levl[mtmp->mx][mtmp->my])->new &&
         !room->seen)
         mtmp->mdispl = 0;

   for(y = 0; y < ROWNO; y++)
      for(x = 0; x < COLNO; x++)
         if((room = &levl[x][y])->new) {
            room->new = 0;
            at(x,y,room->scrsym);
         } else if(room->seen) at(x,y,room->scrsym);
   scrlx = COLNO;
   scrly = ROWNO;
   scrhx = scrhy = 0;
   flags.botlx = 1;
   bot();
}

docorner(xmin,ymax) register int xmin,ymax; {
   register int x,y;
   register struct rm *room;
   if(u.uswallow) {   /* Can be done more efficiently */
      swallowed();
      return;
   }
   for(y = 0; y < ymax; y++) {
      curs(xmin,y+2);
      cl_end();
      for(x = xmin; x < COLNO; x++) {
         if((room = &levl[x][y])->new) {
            room->new = 0;
            at(x,y,room->scrsym);
         } else if(room->seen) at(x,y,room->scrsym);
      }
   }
}

pru()
{
   if(u.udispl && (Invis || u.udisx != u.ux || u.udisy != u.uy))
      /* if(! levl[u.udisx][u.udisy].new) */
         if(!vism_at(u.udisx, u.udisy))
            newsym(u.udisx, u.udisy);
   if(Invis) {
      u.udispl = 0;
      prl(u.ux,u.uy);
   } else
   if(!u.udispl || u.udisx != u.ux || u.udisy != u.uy) {
      atl(u.ux, u.uy, u.usym);
      u.udispl = 1;
      u.udisx = u.ux;
      u.udisy = u.uy;
   }
   levl[u.ux][u.uy].seen = 1;
}

#ifndef NOWORM
#include   "def.wseg.h"
extern struct wseg *m_atseg;
#endif NOWORM

/* print a position that is visible for @ */
prl(x,y)
{
   register struct rm *room;
   register struct monst *mtmp;
   register struct obj *otmp;

   if(x == u.ux && y == u.uy && !Invis) {
      pru();
      return;
   }
   room = &levl[x][y];
   if((!room->typ) || (room->typ<DOOR && levl[u.ux][u.uy].typ == CORR))
      return;
   if((mtmp = m_at(x,y)) && !mtmp->mhide &&
      (!mtmp->minvis || See_invisible)) {
#ifndef NOWORM
      if(m_atseg)
         pwseg(m_atseg);
      else
#endif NOWORM
      pmon(mtmp);
   }
   else if(otmp = o_at(x,y))
      atl(x,y,otmp->olet);
   else if(mtmp && (!mtmp->minvis || See_invisible)) {
      /* must be a hiding monster, but not hiding right now */
      /* assume for the moment that long worms do not hide */
      pmon(mtmp);
   }
   else if(g_at(x,y,fgold)) atl(x,y,'$');
   else if(!room->seen || room->scrsym == ' ') {
      room->new = room->seen = 1;
      newsym(x,y);
      on_scr(x,y);
   }
   room->seen = 1;
}

char
news0(x,y)
register xchar x,y;
{
   register struct obj *otmp;
   register struct gen *gtmp;
   struct rm *room;
   register char tmp;

   room = &levl[x][y];
   if(!room->seen) tmp = ' ';
   else if(!Blind && (otmp = o_at(x,y))) tmp = otmp->olet;
   else if(!Blind && g_at(x,y,fgold)) tmp = '$';
   else if(x == xupstair && y == yupstair) tmp = '<';
   else if(x == xdnstair && y == ydnstair) tmp = '>';
   else if((gtmp = g_at(x,y,ftrap)) && (gtmp->gflag & SEEN)) tmp = '^';
   else switch(room->typ) {
   case SCORR:
   case SDOOR:
      tmp = room->scrsym;   /* %% wrong after killing mimic ! */
      break;
   case HWALL:
      tmp = '-';
      break;
   case VWALL:
      tmp = '|';
      break;
   case LDOOR:
   case DOOR:
      tmp = '+';
      break;
   case CORR:
      tmp = CORR_SYM;
      break;
   case ROOM:
      if(room->lit || cansee(x,y) || Blind) tmp = '.';
      else tmp = ' ';
      break;
   default: tmp = ERRCHAR;
   }
   return(tmp);
}

newsym(x,y)
register int x,y;
{
   atl(x,y,news0(x,y));
}

/* used with wand of digging: fill scrsym and force display */
mnewsym(x,y)
register int x,y;
{
	register struct monst *mtmp = m_at(x,y);
	register struct rm *room;
	char newscrsym;

   if(!mtmp || (mtmp->minvis && !See_invisible) ||
          (mtmp->mhide && o_at(x,y))){
		room = &levl[x][y];
		newscrsym = news0(x,y);
		if(room->scrsym != newscrsym) {
			room->scrsym = newscrsym;
			room->seen = 0;
		}
   }
}

nosee(x,y)
register int x,y;
{
   register struct rm *room;

   room = &levl[x][y];
   if(room->scrsym == '.' && !room->lit && !Blind) {
      room->scrsym = ' ';
      room->new = 1;
      on_scr(x,y);
   }
}

#ifndef QUEST
prl1(x,y)
register int x,y;
{
   if(u.dx) {
      if(u.dy) {
         prl(x-(2*u.dx),y);
         prl(x-u.dx,y);
         prl(x,y);
         prl(x,y-u.dy);
         prl(x,y-(2*u.dy));
      } else {
         prl(x,y-1);
         prl(x,y);
         prl(x,y+1);
      }
   } else {
      prl(x-1,y);
      prl(x,y);
      prl(x+1,y);
   }
}

nose1(x,y)
register int x,y;
{
   if(u.dx) {
      if(u.dy) {
         nosee(x,u.uy);
         nosee(x,u.uy-u.dy);
         nosee(x,y);
         nosee(u.ux-u.dx,y);
         nosee(u.ux,y);
      } else {
         nosee(x,y-1);
         nosee(x,y);
         nosee(x,y+1);
      }
   } else {
      nosee(x-1,y);
      nosee(x,y);
      nosee(x+1,y);
   }
}
#endif QUEST

vism_at(x,y) register int x,y; {
register struct monst *mtmp;
register int csi = (See_invisible != 0);
   return((x == u.ux && y == u.uy && (!Invis || csi)) ? 1 :
      ((mtmp = m_at(x,y)) && (!mtmp->minvis || csi) &&
         (!mtmp->mhide || !o_at(mtmp->mx,mtmp->my)))
      ? cansee(x,y) : 0);
}

#ifdef NEWSCR
pobj(obj) register struct obj *obj; {
register int show = (!obj->oinvis || See_invisible) &&
      cansee(obj->ox,obj->oy);
   if(obj->odispl){
      if(obj->odx != obj->ox || obj->ody != obj->oy || !show)
      if(!vism_at(obj->odx,obj->ody)){
         newsym(obj->odx, obj->ody);
         obj->odispl = 0;
      }
   }
   if(show && !vism_at(obj->ox,obj->oy)){
      atl(obj->ox,obj->oy,obj->olet);
      obj->odispl = 1;
      obj->odx = obj->ox;
      obj->ody = obj->oy;
   }
}
#endif NEWSCR

unpobj(obj) register struct obj *obj; {
/*    if(obj->odispl){
      if(!vism_at(obj->odx, obj->ody))
         newsym(obj->odx, obj->ody);
      obj->odispl = 0;
   }
*/
   if(!vism_at(obj->ox,obj->oy))
      newsym(obj->ox,obj->oy);
}

seeobjs(){
register struct obj *obj, *obj2;
   for(obj = fobj; obj; obj = obj2) {
      obj2 = obj->nobj;
      if(obj->olet == FOOD_SYM && obj->otyp >= CORPSE
         && obj->age + 250 < moves)
            delobj(obj);
   }
   for(obj = invent; obj; obj = obj2) {
      obj2 = obj->nobj;
      if(obj->olet == FOOD_SYM && obj->otyp >= CORPSE
         && obj->age + 250 < moves)
            useup(obj);
   }
}

seemons(){
register struct monst *mtmp;
   for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
      pmon(mtmp);
#ifndef NOWORM
      if(mtmp->wormno) wormsee(mtmp->wormno);
#endif NOWORM
   }
}

pmon(mon) register struct monst *mon; {
register int show =
   ((!mon->minvis || See_invisible) &&
      (!mon->mhide || !o_at(mon->mx,mon->my)) &&
      cansee(mon->mx,mon->my))
    || (Blind && Telepat);
   if(mon->mdispl){
      if(mon->mdx != mon->mx || mon->mdy != mon->my || !show)
         unpmon(mon);
   }
   if(show && !mon->mdispl){
      atl(mon->mx,mon->my,
        mon->mimic ? mon->mimic : mon->data->mlet);
      mon->mdispl = 1;
      mon->mdx = mon->mx;
      mon->mdy = mon->my;
   }
}

unpmon(mon) register struct monst *mon; {
   if(mon->mdispl){
      newsym(mon->mdx, mon->mdy);
      mon->mdispl = 0;
   }
}

nscr()
{
   register int x,y;
   register struct rm *room;

   if(u.uswallow || u.ux == FAR || flags.nscrinh) return;
   pru();
   for(y = scrly; y <= scrhy; y++)
      for(x = scrlx; x <= scrhx; x++)
         if((room = &levl[x][y])->new) {
            room->new = 0;
            at(x,y,room->scrsym);
         }
   scrhx = scrhy = 0;
   scrlx = COLNO;
   scrly = ROWNO;
}

char oldbot[100], newbot[100];      /* 100 >= COLNO */
extern char *eos();
bot()
{
register char *ob = oldbot, *nb = newbot;
register int i;
	if(flags.botlx) *ob = 0;
	flags.botl = flags.botlx = 0;
	(void) sprintf(newbot,
		"Level %-2d  Gold %-5lu  Hp %3d(%d)  Ac %-2d  Str ",
		dlevel, u.ugold, u.uhp, u.uhpmax, u.uac);
	if(u.ustr>18) {
	    if(u.ustr>117)
		(void) strcat(newbot,"18/**");
	    else
		(void) sprintf(eos(newbot), "18/%02d",u.ustr-18);
	} else
	    (void) sprintf(eos(newbot), "%-2d   ",u.ustr);
	(void) sprintf(eos(newbot), "  Exp %2d/%-5lu ", u.ulevel,u.uexp);
	(void) strcat(newbot, hu_stat[u.uhs]);
	if(flags.time)
	    (void) sprintf(eos(newbot), "  %ld", moves);
	if(strlen(newbot) >= COLNO) {
		register char *bp0, *bp1;
		bp0 = bp1 = newbot;
		do {
			if(*bp0 != ' ' || bp0[1] != ' ' || bp0[2] != ' ')
				*bp1++ = *bp0;
		} while(*bp0++);
	}
	for(i = 1; i<COLNO; i++) {
      if(*ob != *nb){
         curs(i,ROWNO+2);
         (void) myputchar(*nb ? *nb : ' ');
         curx++;
      }
      if(*ob) ob++;
      if(*nb) nb++;
   }
   (void) strcpy(oldbot, newbot);
}

#ifdef WAN_PROBING
mstatusline(mtmp) register struct monst *mtmp; {
   pline("Status of %s: ", monnam(mtmp));
   pline("Level %-2d  Gold %-5lu  Hp %3d(%d)  Ac %-2d  Dam %d",
       mtmp->data->mlevel, mtmp->mgold, mtmp->mhp, mtmp->orig_hp,
       mtmp->data->ac, (mtmp->data->damn + 1) * (mtmp->data->damd + 1));
}
#endif WAN_PROBING

cls(){
   if(flags.topl == 1)
      more();
   flags.topl = 0;

   clear_screen();

   flags.botlx = 1;
}

#file hack.read.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.read.c version 1.0.1 - tiny correction in SCR_MAGIC_MAPPING */

#include "hack.h"

extern struct monst *makemon();
int identify();

doread() {
	register struct obj *scroll;
	register boolean confused = (Confusion != 0);
	register boolean known = FALSE;

	scroll = getobj("?", "read");
	if(!scroll) return(0);
	if(!scroll->dknown && Blind) {
	    pline("Being blind, you cannot read the formula on the scroll.");
	    return(0);
	}
	if(Blind)
	  pline("As you pronounce the formula on it, the scroll disappears.");
	else
	  pline("As you read the scroll, it disappears.");
	if(confused)
	  pline("Being confused, you mispronounce the magic words ... ");

	switch(scroll->otyp) {

	case SCR_ENCHANT_ARMOR:
	    {	extern struct obj *some_armor();
		register struct obj *otmp = some_armor();
		if(!otmp) {
			strange_feeling(scroll);
			return(1);
		}
		if(confused) {
			pline("Your %s glows silver for a moment.",
				objects[otmp->otyp].oc_name);
			otmp->rustfree = 1;
			break;
		}
		if(otmp->spe*2 + objects[otmp->otyp].a_ac > 23 &&
			!rn2(3)) {
	pline("Your %s glows violently green for a while, then evaporates.",
			objects[otmp->otyp].oc_name);
			useup(otmp);
			break;
		}
		pline("Your %s glows green for a moment.",
			objects[otmp->otyp].oc_name);
		otmp->cursed = 0;
		otmp->spe++;
		break;
	    }
	case SCR_DESTROY_ARMOR:
		if(confused) {
			register struct obj *otmp = some_armor();
			if(!otmp) {
				strange_feeling(scroll);
				return(1);
			}
			pline("Your %s glows purple for a moment.",
				objects[otmp->otyp].oc_name);
			otmp->rustfree = 0;
			break;
		}
		if(uarm) {
		    pline("Your armor turns to dust and falls to the floor!");
		    useup(uarm);
		} else if(uarmh) {
		    pline("Your helmet turns to dust and is blown away!");
		    useup(uarmh);
		} else if(uarmg) {
			pline("Your gloves vanish!");
			useup(uarmg);
			selftouch("You");
		} else {
			strange_feeling(scroll);
			return(1);
		}
		break;
	case SCR_CONFUSE_MONSTER:
		if(confused) {
			pline("Your hands begin to glow purple.");
			Confusion += rnd(100);
		} else {
			pline("Your hands begin to glow blue.");
			u.umconf = 1;
		}
		break;
	case SCR_SCARE_MONSTER:
	    {	register int ct = 0;
		register struct monst *mtmp;

		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
			if(cansee(mtmp->mx,mtmp->my)) {
				if(confused)
					mtmp->mflee = mtmp->mfroz =
					mtmp->msleep = 0;
				else
					mtmp->mflee = 1;
				ct++;
			}
		if(!ct) {
		    if(confused)
			pline("You hear sad wailing in the distance.");
		    else
			pline("You hear maniacal laughter in the distance.");
		}
		break;
	    }
	case SCR_BLANK_PAPER:
		if(confused)
		    pline("You see strange patterns on this scroll.");
		else
		    pline("This scroll seems to be blank.");
		break;
	case SCR_REMOVE_CURSE:
	    {	register struct obj *obj;
		if(confused)
		  pline("You feel like you need some help.");
		else
		  pline("You feel like someone is helping you.");
		for(obj = invent; obj ; obj = obj->nobj)
			if(obj->owornmask)
				obj->cursed = confused;
		if(Punished && !confused) {
			Punished = 0;
			freeobj(uchain);
			unpobj(uchain);
			free((char *) uchain);
			uball->spe = 0;
			uball->owornmask &= ~W_BALL;
			uchain = uball = (struct obj *) 0;
		}
		break;
	    }
	case SCR_CREATE_MONSTER:
	    {	register int cnt = 1;

		if(!rn2(73)) cnt += rn2(4) + 1;
		if(confused) cnt += 12;
		while(cnt--)
		    (void) makemon(confused ? PM_ACIDBLOB :
			(struct permonst *) 0, u.ux, u.uy);
		break;
	    }
	case SCR_ENCHANT_WEAPON:
		if(!uwep) {
			strange_feeling(scroll);
			return(1);
		}
		if(confused) {
			pline("Your %s glows silver for a moment.",
				objects[uwep->otyp].oc_name);
			uwep->rustfree = 1;
		} else
			if(!chwepon(scroll, 1)) return(1);
		break;
	case SCR_DAMAGE_WEAPON:
		if(confused) {
			pline("Your %s glows purple for a moment.",
				objects[uwep->otyp].oc_name);
			uwep->rustfree = 0;
		} else
			if(!chwepon(scroll, -1)) return(1);
		break;
	case SCR_TAMING:
	    {	register int i,j;
		register int bd = confused ? 5 : 1;
		register struct monst *mtmp;

		for(i = -bd; i <= bd; i++) for(j = -bd; j <= bd; j++)
		if(mtmp = m_at(u.ux+i, u.uy+j))
			(void) tamedog(mtmp, (struct obj *) 0);
		break;
	    }
	case SCR_GENOCIDE:
	    {	extern char genocided[], fut_geno[];
		char buf[BUFSZ];
		register struct monst *mtmp, *mtmp2;

		pline("You have found a scroll of genocide!");
		known = TRUE;
		if(confused)
			*buf = u.usym;
		else do {
	    pline("What monster do you want to genocide (Type the letter)? ");
			getlin(buf);
		} while(strlen(buf) != 1 || !letter(*buf));
		if(!index(fut_geno, *buf))
			charcat(fut_geno, *buf);
		if(!index(genocided, *buf))
			charcat(genocided, *buf);
		else {
			pline("Such monsters do not exist in this world.");
			break;
		}
		for(mtmp = fmon; mtmp; mtmp = mtmp2){
			mtmp2 = mtmp->nmon;
			if(mtmp->data->mlet == *buf)
				mondead(mtmp);
		}
		pline("Wiped out all %c's.", *buf);
		if(*buf == u.usym) {
			killer = "scroll of genocide";
			u.uhp = -1;
		}
		break;
		}
	case SCR_LIGHT:
		if(!Blind) known = TRUE;
		litroom(!confused);
		break;
	case SCR_TELEPORTATION:
		if(confused)
			level_tele();
		else {
#ifdef QUEST
			register int oux = u.ux, ouy = u.uy;
			tele();
			if(dist(oux, ouy) > 100) known = TRUE;
#else QUEST
			register int uroom = inroom(u.ux, u.uy);
			tele();
			if(uroom != inroom(u.ux, u.uy)) known = TRUE;
#endif QUEST
		}
		break;
	case SCR_GOLD_DETECTION:
	    {	register struct gen *head = confused ? ftrap : fgold;
		register struct gen *gtmp;

		if(!head) {
			strange_feeling(scroll);
			return(1);
		} else {
			known = TRUE;
			for(gtmp = head; gtmp; gtmp = gtmp->ngen)
				if(gtmp->gx != u.ux || gtmp->gy != u.uy)
					goto outgoldmap;
			/* only under me - no separate display required */
			if(confused)
			    pline("You feel very giddy!");
			else
			    pline("You notice some gold between your feet.");
			break;
		outgoldmap:
			cls();
			for(gtmp = head; gtmp; gtmp = gtmp->ngen)
				at(gtmp->gx, gtmp->gy, '$');
			prme();
			if(confused)
			    pline("You feel very greedy!");
			else
			    pline("You feel very greedy, and sense gold!");
			more();
			docrt();
		}
		break;
	    }
	case SCR_FOOD_DETECTION:
	    {	register int ct = 0, ctu = 0;
		register struct obj *obj;
		register char foodsym = confused ? POTION_SYM : FOOD_SYM;

		for(obj = fobj; obj; obj = obj->nobj)
			if(obj->olet == FOOD_SYM) {
				if(obj->ox == u.ux && obj->oy == u.uy) ctu++;
				else ct++;
			}
		if(!ct && !ctu) {
			strange_feeling(scroll);
			return(1);
		} else if(!ct) {
			known = TRUE;
			pline("You smell %s close nearby.",
				confused ? "something" : "food");
			
		} else {
			known = TRUE;
			cls();
			for(obj = fobj; obj; obj = obj->nobj)
			    if(obj->olet == foodsym)
				at(obj->ox, obj->oy, FOOD_SYM);
			prme();
			pline("Your nose tingles and you smell %s!",
				confused ? "something" : "food");
			more();
			docrt();
		}
		break;
	    }
	case SCR_IDENTIFY:
		/* known = TRUE; */
		if(confused)
			pline("You identify this as an identify scroll.");
		else
			pline("This is an identify scroll.");
		useup(scroll);
		objects[SCR_IDENTIFY].oc_name_known = 1;
		if(!confused)
		    while(
			!ggetobj("identify", identify, rn2(5) ? 1 : rn2(5))
			&& invent
		    );
		return(1);
	case SCR_MAGIC_MAPPING:
	    {	register struct rm *lev;
		register int num, zx, zy;

		known = TRUE;
		pline("On this scroll %s a map!",
			confused ? "was" : "is");
		for(zy = 0; zy < ROWNO; zy++)
			for(zx = 0; zx < COLNO; zx++) {
				if(confused && rn2(7)) continue;
				lev = &(levl[zx][zy]);
				if((num = lev->typ) == 0)
					continue;
				if(num == SCORR) {
					lev->typ = CORR;
					lev->scrsym = CORR_SYM;
				} else
				if(num == SDOOR) {
					lev->typ = DOOR;
					lev->scrsym = '+';
					/* do sth in doors ? */
				} else if(lev->seen) continue;
#ifndef QUEST
				if(num != ROOM)
#endif QUEST
				{
				  lev->seen = lev->new = 1;
				  if(lev->scrsym == ' ')
				    newsym(zx,zy);
				  else
				    on_scr(zx,zy);
				}
			}
		break;
	    }
	case SCR_AMNESIA:
	    {	register int zx, zy;

		known = TRUE;
		for(zx = 0; zx < COLNO; zx++) for(zy = 0; zy < ROWNO; zy++)
		    if(!confused || rn2(7))
			if(!cansee(zx,zy))
			    levl[zx][zy].seen = 0;
		docrt();
		pline("Thinking of Maud you forget everything else.");
		break;
	    }
	case SCR_FIRE:
	    {	register int num;

		known = TRUE;
		if(confused) {
		    pline("The scroll catches fire and you burn your hands.");
		    losehp(1, "scroll of fire");
		} else {
		    pline("The scroll erupts in a tower of flame!");
		    if(Fire_resistance)
			pline("You are uninjured.");
		    else {
			num = rnd(6);
			u.uhpmax -= num;
			losehp(num, "scroll of fire");
		    }
		}
		break;
	    }
	case SCR_PUNISHMENT:
		known = TRUE;
		if(confused) {
			pline("You feel guilty.");
			break;
		}
		pline("You are being punished for your misbehaviour!");
		if(Punished){
			pline("Your iron ball gets heavier.");
			uball->owt += 15;
			break;
		}
		Punished = INTRINSIC;
		mkobj_at(CHAIN_SYM, u.ux, u.uy);
		setworn(fobj, W_CHAIN);
		mkobj_at(BALL_SYM, u.ux, u.uy);
		setworn(fobj, W_BALL);
		uball->spe = 1;		/* special ball (see save) */
		break;
	default:
		pline("What weird language is this written in? (%d)",
			scroll->otyp);
		impossible();
	}
	if(!objects[scroll->otyp].oc_name_known) {
		if(known && !confused) {
			objects[scroll->otyp].oc_name_known = 1;
			u.urexp += 10;
		} else if(!objects[scroll->otyp].oc_uname)
			docall(scroll);
	}
	useup(scroll);
	return(1);
}

identify(otmp)
register struct obj *otmp;
{
	objects[otmp->otyp].oc_name_known = 1;
	otmp->known = otmp->dknown = 1;
	prinv(otmp);
	return(1);
}

litroom(on)
register boolean on;
{
	register int num,zx,zy;

	/* first produce the text (provided he is not blind) */
	if(Blind) goto do_it;
	if(!on) {
		if(u.uswallow || !xdnstair || levl[u.ux][u.uy].typ == CORR ||
		    !levl[u.ux][u.uy].lit) {
			pline("It seems even darker in here than before.");
			return;
		} else
			pline("It suddenly becomes dark in here.");
	} else {
		if(u.uswallow){
			pline("%s's stomach is lit.", Monnam(u.ustuck));
			return;
		}
		if(!xdnstair){
			pline("Nothing Happens");
			return;
		}
#ifdef QUEST
		pline("The cave lights up around you, then fades.");
		return;
#else QUEST
		if(levl[u.ux][u.uy].typ == CORR) {
		    pline("The corridor lights up around you, then fades.");
		    return;
		} else if(levl[u.ux][u.uy].lit) {
		    pline("The light here seems better now.");
		    return;
		} else
		    pline("The room is lit.");
#endif QUEST
	}

do_it:
#ifdef QUEST
	return;
#else QUEST
	if(levl[u.ux][u.uy].lit == on)
		return;
	if(levl[u.ux][u.uy].typ == DOOR) {
		if(levl[u.ux][u.uy+1].typ >= ROOM) zy = u.uy+1;
		else if(levl[u.ux][u.uy-1].typ >= ROOM) zy = u.uy-1;
		else zy = u.uy;
		if(levl[u.ux+1][u.uy].typ >= ROOM) zx = u.ux+1;
		else if(levl[u.ux-1][u.uy].typ >= ROOM) zx = u.ux-1;
		else zx = u.ux;
	} else {
		zx = u.ux;
		zy = u.uy;
	}
	for(seelx = u.ux; (num = levl[seelx-1][zy].typ) != CORR && num != 0;
		seelx--);
	for(seehx = u.ux; (num = levl[seehx+1][zy].typ) != CORR && num != 0;
		seehx++);
	for(seely = u.uy; (num = levl[zx][seely-1].typ) != CORR && num != 0;
		seely--);
	for(seehy = u.uy; (num = levl[zx][seehy+1].typ) != CORR && num != 0;
		seehy++);
	for(zy = seely; zy <= seehy; zy++)
		for(zx = seelx; zx <= seehx; zx++) {
			levl[zx][zy].lit = on;
			if(!Blind && dist(zx,zy) > 2)
				if(on) prl(zx,zy); else nosee(zx,zy);
		}
	if(!on) seehx = 0;
#endif	QUEST
}
#file hack.rip.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include <stdio.h>
#include "hack.h"
/* #include   <libraries/dos.h> */

extern char plname[];

static char *rip[] = {
"                       ----------",
"                      /          \\",
"                     /    REST    \\",
"                    /      IN      \\",
"                   /     PEACE      \\",
"                  /                  \\",
"                  |                  |",
"                  |                  |",
"                  |                  |",
"                  |                  |",
"                  |                  |",
"                  |       1001       |",
"                 *|     *  *  *      | *",
"        _________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______\n",
0
};

outrip(){
   register char **dp = rip;
   register char *dpx;
/*   struct DateStamp now, *DateStamp(); */
   char buf[BUFSZ];
   register int x,y;
   int thisyear;

   cls();

/*   now = DateStamp(&now);  */
   thisyear = 85;
   (void) strcpy(buf, plname);
   buf[16] = 0;
   center(6, buf);
   (void) sprintf(buf, "%ld AU", u.ugold);
   center(7, buf);
   (void) sprintf(buf, "killed by%s",
      !strncmp(killer, "the ", 4) ? "" :
      !strcmp(killer, "starvation") ? "" :
      index(vowels, *killer) ? " an" : " a");
   center(8, buf);
   (void) strcpy(buf, killer);
   if(strlen(buf) > 16) {
       register int i,i0,i1;
      i0 = i1 = 0;
      for(i = 0; i <= 16; i++)
         if(buf[i] == ' ') i0 = i, i1 = i+1;
      if(!i0) i0 = i1 = 16;
      buf[i1 + 16] = 0;
      center(10, buf+i1);
      buf[i0] = 0;
   }
   center(9, buf);
   (void) sprintf(buf, "19%2d", thisyear);
   center(11, buf);
   for(y=8; *dp; y++,dp++){
      x = 0;
      dpx = *dp;
      while(dpx[x]) {
         while(dpx[x] == ' ') x++;
         curs(x,y);
         while(dpx[x] && dpx[x] != ' '){
            extern int done_stopprint;
            if(done_stopprint)
               return;
            curx++;
            (void) myputchar(dpx[x++]);
         }
      }
   }
   getret();
}

center(line, text) int line; char *text; {
register char *ip,*op;
   ip = text;
   op = &rip[line][28 - ((strlen(text)+1)/2)];
   while(*ip) *op++ = *ip++;
}
#file hack.rumors.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */



#include	<stdio.h>

#include	"config.h"

#define	CHARSZ	8	/* number of bits in a char */

#define	RUMORFILE	"rumors"

extern long *alloc();

extern char *index();

int n_rumors = 0;

int n_used_rumors = -1;

char *usedbits;



init_rumors(rumf) register FILE *rumf; {

register int i;

	n_used_rumors = 0;

	while(skipline(rumf)) n_rumors++;

	rewind(rumf);

	i = n_rumors/CHARSZ;

	usedbits = (char *) alloc((unsigned)(i+1));

	for( ; i>=0; i--) usedbits[i] = 0;

}



skipline(rumf) register FILE *rumf; {

char line[COLNO];

	while(1) {

		if(!fgets(line, sizeof(line), rumf)) return(0);

		if(index(line, '\n')) return(1);

	}

}



outline(rumf) register FILE *rumf; {

char line[COLNO];

register char *ep;

	if(!fgets(line, sizeof(line), rumf)) return;

	if((ep = index(line, '\n')) != 0) *ep = 0;

	pline("This cookie has a scrap of paper inside! It reads: ");

	pline(line);

}



outrumor(){

register int rn,i;

register FILE *rumf;

	if(n_rumors <= n_used_rumors ||

	  (rumf = fopen(RUMORFILE, "r")) == NULL) return;

	if(n_used_rumors < 0) init_rumors(rumf);

	if(!n_rumors) goto none;

	rn = rn2(n_rumors - n_used_rumors);

	i = 0;

	while(rn || used(i)) {

		(void) skipline(rumf);

		if(!used(i)) rn--;

		i++;

	}

	usedbits[i/CHARSZ] |= (1 << (i % CHARSZ));

	n_used_rumors++;

	outline(rumf);

none:

	(void) fclose(rumf);

}



used(i) register int i; {

	return(usedbits[i/CHARSZ] & (1 << (i % CHARSZ)));

}

#file hack.save.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "hack.h"
extern char genocided[60];	/* defined in Decl.c */
extern char fut_geno[60];	/* idem */
#include <signal.h>

extern char SAVEF[], nul[];
extern char pl_character[PL_CSIZ];
extern long lseek();
extern struct obj *restobjchn();
extern struct monst *restmonchn();

extern char *index();		/* M.E.T.  11/20/85 */

dosave(){
	if(dosave0(0)) {
		settty("Be seeing you ...\n");
		hackexit(0);
	}
#ifdef lint
	return(0);
#endif lint
}

#ifndef NOSAVEONHANGUP
hangup(){
	(void) dosave0(1);
	hackexit(1);
}
#endif NOSAVEONHANGUP

/* returns 1 if save successful */
dosave0(hu) int hu; {
	register int fd, ofd;
	int tmp;      /* not register ! */
	(void) signal(SIGHUP, SIG_IGN);
	(void) signal(SIGINT, SIG_IGN);
	if((fd = creat(SAVEF, FMASK)) < 0)
		{
		if(!hu) pline("Cannot open save file. (Continue or Quit)");
			return(0);
		}
	makeicon(SAVEF, pl_character[0]);
	savelev(fd);
	saveobjchn(fd, invent);
	saveobjchn(fd, fcobj);
	savemonchn(fd, fallen_down);
	bwrite(fd, (char *) &flags, sizeof(struct flag));
	bwrite(fd, (char *) &dlevel, sizeof dlevel);
	bwrite(fd, (char *) &maxdlevel, sizeof maxdlevel);
	bwrite(fd, (char *) &moves, sizeof moves);
	bwrite(fd, (char *) &u, sizeof(struct you));
	bwrite(fd, (char *) pl_character, sizeof pl_character);
	bwrite(fd, (char *) genocided, sizeof genocided);
	bwrite(fd, (char *) fut_geno, sizeof fut_geno);
	savenames(fd);
	for(tmp = 1; tmp <= maxdlevel; tmp++)
		{
		glo(tmp);
		if((ofd = open(lock, 0)) < 0)
			continue;
		(void) getlev(ofd);
		(void) close(ofd);
		bwrite(fd, (char *) &tmp, sizeof tmp);   /* level number */
		savelev(fd);            /* actual level */
		(void) unlink(lock);
		}
	(void) close(fd);
	*index(lock, '.') = 0;
	(void) unlink(lock);
	return(1);
}

dorecover(fd)
register int fd;
{
	register int nfd;
	int tmp;      /* not a register ! */
	struct obj *otmp;
	 (void) getlev(fd);
	invent = restobjchn(fd);
	for(otmp = invent; otmp; otmp = otmp->nobj)
		if(otmp->owornmask)
			setworn(otmp, otmp->owornmask);
	fcobj = restobjchn(fd);
	fallen_down = restmonchn(fd);
	mread(fd, (char *) &flags, sizeof(struct flag));
	mread(fd, (char *) &dlevel, sizeof dlevel);
	mread(fd, (char *) &maxdlevel, sizeof maxdlevel);
	mread(fd, (char *) &moves, sizeof moves);
	mread(fd, (char *) &u, sizeof(struct you));
	mread(fd, (char *) pl_character, sizeof pl_character);
	mread(fd, (char *) genocided, sizeof genocided);
	mread(fd, (char *) fut_geno, sizeof fut_geno);
	restnames(fd);
	while(1)
		{
		if(read(fd, (char *) &tmp, sizeof tmp) != sizeof tmp)
			break;
		if(getlev(fd))
			break;      /* this is actually an error */
		glo(tmp);
		if((nfd = creat(lock, FMASK)) < 0)
			panic("Cannot open temp file %s!\n", lock);
		savelev(nfd);
		(void) close(nfd);
		}
	(void) lseek(fd, 0L, 0);
	(void) getlev(fd);
	(void) close(fd);
	(void) unlink(SAVEF);
	(void) delicon(SAVEF);
	if(Punished) {
		for(otmp = fobj; otmp; otmp = otmp->nobj)
			if(otmp->olet == CHAIN_SYM) goto chainfnd;
		panic("Cannot find the iron chain?");
	chainfnd:
		uchain = otmp;
		if(!uball)
			{
			for(otmp = fobj; otmp; otmp = otmp->nobj)
				if(otmp->olet == BALL_SYM && otmp->spe)
					goto ballfnd;
			panic("Cannot find the iron ball?");
			ballfnd:
			uball = otmp;
			}
	}
#ifndef QUEST
	setsee();  /* only to recompute seelx etc. - these weren't saved */
#endif QUEST
	docrt();
}

struct obj *
restobjchn(fd)
register int fd;
{
	register struct obj *otmp, *otmp2;
	register struct obj *first = 0;
	int xl;
#ifdef lint
	/* suppress "used before set" warning from lint */
	otmp2 = 0;
#endif lint
	while(1)
		{
		mread(fd, (char *) &xl, sizeof(xl));
		if(xl == -1) break;
		otmp = newobj(xl);
		if(!first) first = otmp;
		else otmp2->nobj = otmp;
		mread(fd, (char *) otmp, (unsigned) xl + sizeof(struct obj));
		if(!otmp->o_id)   /* from MKLEV */
			otmp->o_id = flags.ident++;
		otmp2 = otmp;
		}
	if(first && otmp2->nobj)
		{
		pline("Restobjchn: error reading objchn.");
		impossible();
		otmp2->nobj = 0;
		}
	return(first);
}

struct monst *
restmonchn(fd)
register int fd;
{
	register struct monst *mtmp, *mtmp2;
	register struct monst *first = 0;
	int xl;
    
#ifdef FUNNYRELOC
	struct permonst *monbegin;

	mread(fd, (char *)&monbegin, sizeof(monbegin));
#endif

#ifdef lint
	/* suppress "used before set" warning from lint */
	mtmp2 = 0;
#endif lint
	while(1)
		{
		mread(fd, (char *) &xl, sizeof(xl));
		if(xl == -1) break;
		mtmp = newmonst(xl);
		if(!first) first = mtmp;
		else mtmp2->nmon = mtmp;
		mread(fd, (char *) mtmp, (unsigned) xl + sizeof(struct monst));
#ifdef DEBUGMON
		myprintf("Read Monster #%d", mtmp->data);
#endif
		mtmp->data = &mons[ (int) mtmp->data ];
		if(!mtmp->m_id) {         /* from MKLEV */
			mtmp->m_id = flags.ident++;
#ifndef NOWORM
			if(mtmp->data->mlet == 'w' && getwn(mtmp)){
			initworm(mtmp);
			mtmp->msleep = 0;
			}
#endif NOWORM
		}
		if(mtmp->minvent)
			mtmp->minvent = restobjchn(fd);
		mtmp2 = mtmp;
		}
	if(first && mtmp2->nmon){
		pline("Restmonchn: error reading monchn.");
		impossible();
		mtmp2->nmon = 0;
	}
	return(first);
}
#file hack.search.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.search.c version 1.0.1 - small correction in findit() */

#include "hack.h"
#include "def.trap.h"

extern struct monst *makemon();

findit()   /* returns number of things found */
{
   int num;
   register xchar zx,zy;
   register struct gen *gtmp;
   register struct monst *mtmp;
   xchar lx,hx,ly,hy;

   if(u.uswallow) return(0);
   for(lx = u.ux;(num = levl[lx-1][u.uy].typ) && num != CORR;lx--) ;
   for(hx = u.ux;(num = levl[hx+1][u.uy].typ) && num != CORR;hx++) ;
   for(ly = u.uy;(num = levl[u.ux][ly-1].typ) && num != CORR;ly--) ;
   for(hy = u.uy;(num = levl[u.ux][hy+1].typ) && num != CORR;hy++) ;
   num = 0;
   for(zy = ly;zy <= hy;zy++)
      for(zx = lx;zx <= hx;zx++) {
         if(levl[zx][zy].typ == SDOOR) {
            levl[zx][zy].typ = DOOR;
            atl(zx,zy,'+');
            num++;
         } else if(levl[zx][zy].typ == SCORR) {
            levl[zx][zy].typ = CORR;
            atl(zx,zy,CORR_SYM);
            num++;
         } else if(gtmp = g_at(zx,zy,ftrap)) {
            if(gtmp->gflag == PIERC){
               (void) makemon(PM_PIERC,zx,zy);
               num++;
               deltrap(gtmp);
				} else if(!(gtmp->gflag & SEEN)) {
					gtmp->gflag |= SEEN;
					if(!vism_at(zx,zy)) atl(zx,zy,'^');
					num++;
				}
         } else if(mtmp = m_at(zx,zy)) if(mtmp->mimic){
            seemimic(mtmp);
            num++;
         }
      }
   return(num);
}

dosearch()
{
   register xchar x,y;
   register struct gen *tgen;
   register struct monst *mtmp;

   for(x = u.ux-1; x < u.ux+2; x++)
   for(y = u.uy-1; y < u.uy+2; y++) if(x != u.ux || y != u.uy) {
      if(levl[x][y].typ == SDOOR && !rn2(7)) {
         levl[x][y].typ = DOOR;
         levl[x][y].seen = 0;   /* force prl */
         prl(x,y);
         nomul(0);
      } else if(levl[x][y].typ == SCORR && !rn2(7)) {
         levl[x][y].typ = CORR;
         levl[x][y].seen = 0;   /* force prl */
         prl(x,y);
         nomul(0);
      } else {
         if(mtmp = m_at(x,y)) if(mtmp->mimic){
            seemimic(mtmp);
            pline("You find a mimic.");
            return(1);
         }
         for(tgen = ftrap;tgen;tgen = tgen->ngen)
         if(tgen->gx == x && tgen->gy == y &&
            !(tgen->gflag & SEEN) && !rn2(8)) {
            nomul(0);
            pline("You find a%s.",
					traps[tgen->gflag & TRAPTYPE]);
            if(tgen->gflag == PIERC) {
               deltrap(tgen);
               (void) makemon(PM_PIERC,x,y);
               return(1);
            }
            tgen->gflag |= SEEN;
            if(!vism_at(x,y)) atl(x,y,'^');
         }
      }
   }
   return(1);
}

/* ARGSUSED */
doidtrap(str) /* register */ char *str; {
register struct gen *tgen;
register int x,y;
   if(!getdir()) return(0);
   x = u.ux + u.dx;
   y = u.uy + u.dy;
   for(tgen = ftrap; tgen; tgen = tgen->ngen)
      if(tgen->gx == x && tgen->gy == y &&
         (tgen->gflag & SEEN)) {
			pline("That is a%s.", traps[tgen->gflag & TRAPTYPE]);
         return(0);
      }
   pline("I can't see a trap there.");
   return(0);
}

wakeup(mtmp)
register struct monst *mtmp;
{
   mtmp->msleep = 0;
   setmangry(mtmp);
   if(mtmp->mimic) seemimic(mtmp);
}

/* NOTE: we must check if(mtmp->mimic) before calling this routine */
seemimic(mtmp)
register struct monst *mtmp;
{
      mtmp->mimic = 0;
      unpmon(mtmp);
      pmon(mtmp);
}

jcz@ncsu.UUCP (John A. Toebes, VIII) (02/21/86)

#file hack.shk.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "hack.h"
#ifdef QUEST
int shlevel = 0;
struct monst *shopkeeper = 0;
struct obj *billobjs = 0;
obfree(obj,merge) register struct obj *obj, *merge; {
	free((char *) obj);
}
inshop(){ return(0); }
addtobill(){}
subfrombill(){}
splitbill(){}
dopay(){}
paybill(){}
doinvbill(){}
shkdead(){}
shk_move(){ return(0); }
setshk(){}
char *shkname(){ return(""); }

#else
#include	"hack.mfndpos.h"
#include	"def.eshk.h"

#define	ESHK	((struct eshk *)(&(shopkeeper->mextra[0])))
#define	NOTANGRY	shopkeeper->mpeaceful
#define	ANGRY	!NOTANGRY

extern char plname[];
extern struct obj *o_on();
struct monst *shopkeeper = 0;
struct bill_x *bill;
int shlevel = 0;	/* level of this shopkeeper */
struct obj *billobjs;	/* objects on bill with bp->useup */
/* #define	billobjs	shopkeeper->minvent
   doesnt work so well, since we do not want these objects to be dropped
   when the shopkeeper is killed.
   (See also the save and restore routines.)
 */

/* invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
		obj->quan <= bp->bquan
 */

long int total;

char shtypes[] = "=/)%?!["; /* 8 shoptypes: 7 specialized, 1 mixed */
char *shopnam[] = {
	"engagement ring", "walking cane", "antique weapon",
	"delicatessen", "second hand book", "liquor",
	"used armor", "assorted antiques"
};

char *
shkname() {
	return(ESHK->shknam);
}

shkdead(){
	rooms[ESHK->shoproom].rtype = 0;
	setpaid();
	shopkeeper = 0;
	bill = (struct bill_x *) -1000;	/* dump core when referenced */
}

setpaid(){	/* caller has checked that shopkeeper exists */
register struct obj *obj;
	for(obj = invent; obj; obj = obj->nobj)
		obj->unpaid = 0;
	for(obj = fobj; obj; obj = obj->nobj)
		obj->unpaid = 0;
	while(obj = billobjs){
		billobjs = obj->nobj;
		free((char *) obj);
	}
	ESHK->billct = 0;
}

addupbill(){	/* delivers result in total */
		/* caller has checked that shopkeeper exists */
register int ct = ESHK->billct;
register struct bill_x *bp = bill;
	total = 0;
	while(ct--){
		total += bp->price * bp->bquan;
		bp++;
	}
}

inshop(){
register int tmp = inroom(u.ux,u.uy);
	if(tmp < 0 || rooms[tmp].rtype < 8) {
		u.uinshop = 0;
		if(shopkeeper && ESHK->billct){
			pline("Somehow you escaped the shop without paying!");
			addupbill();
			pline("You stole for a total worth of %lu zorkmids.",
				total);
			ESHK->robbed += total;
			setpaid();
		}
		if(tmp >= 0 && rooms[tmp].rtype == 7){
			register struct monst *mtmp;
			pline("Welcome to David's treasure zoo!");
			rooms[tmp].rtype = 0;
			for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
				if(!rn2(4)) mtmp->msleep = 0;
		}
	} else {
		if(shlevel != dlevel) setshk();
		if(!shopkeeper) u.uinshop = 0;
		else if(!u.uinshop){
			if(!ESHK->visitct ||
				strncmp(ESHK->customer, plname, PL_NSIZ)){
				/* He seems to be new here */
				ESHK->visitct = 0;
				(void) strncpy(ESHK->customer,plname,PL_NSIZ);
				NOTANGRY = 1;
			}
			pline("Hello %s! Welcome%s to %s's %s shop!",
				plname,
				ESHK->visitct++ ? " again" : "",
				shkname(),
				shopnam[rooms[ESHK->shoproom].rtype - 8] );
			u.uinshop = 1;
		}
	}
	return(u.uinshop);
}

setshk(){
register struct monst *mtmp;
	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(mtmp->isshk){
		shopkeeper = mtmp;
		bill = &(ESHK->bill[0]);
		shlevel = dlevel;
		if(ANGRY && strncpy(ESHK->customer,plname,PL_NSIZ))
			NOTANGRY = 1;
		billobjs = 0;
		return;
	}
	shopkeeper = 0;
	bill = (struct bill_x *) -1000;	/* dump core when referenced */
}

struct bill_x *
onbill(obj) register struct obj *obj; {
register struct bill_x *bp;
	if(!shopkeeper) return(0);
	for(bp = bill; bp < &bill[ESHK->billct]; bp++)
		if(bp->bo_id == obj->o_id) {
			if(!obj->unpaid) pline("onbill: paid obj on bill?");
			return(bp);
		}
	if(obj->unpaid) pline("onbill: unpaid obj not on bill?");
	return(0);
}

/* called with two args on merge */
obfree(obj,merge) register struct obj *obj, *merge; {
register struct bill_x *bp = onbill(obj);
register struct bill_x *bpm;
	if(bp) {
		if(!merge){
			bp->useup = 1;
			obj->unpaid = 0;	/* only for doinvbill */
			obj->nobj = billobjs;
			billobjs = obj;
			return;
		}
		bpm = onbill(merge);
		if(!bpm){
			/* this used to be a rename */
			impossible();
			return;
		} else {
			/* this was a merger */
			bpm->bquan += bp->bquan;
			ESHK->billct--;
			*bp = bill[ESHK->billct];
		}
	}
	free((char *) obj);
}

pay(tmp) long tmp; {
	u.ugold -= tmp;
	shopkeeper->mgold += tmp;
	flags.botl = 1;
}

dopay(){
long ltmp;
register struct bill_x *bp;
int shknear = (shlevel == dlevel && shopkeeper &&
	dist(shopkeeper->mx,shopkeeper->my) < 3);
int pass, tmp;

	multi = 0;
	if(!inshop() && !shknear) {
		pline("You are not in a shop.");
		return(0);
	}
	if(!shknear &&
	    inroom(shopkeeper->mx,shopkeeper->my) != ESHK->shoproom){
		pline("There is nobody here to receive your payment.");
		return(0);
	}
	if(!ESHK->billct){
		pline("You do not owe %s anything.", monnam(shopkeeper));
		if(!u.ugold){
			pline("Moreover, you have no money.");
			return(1);
		}
		if(ESHK->robbed){
			pline("But since the shop has been robbed recently,");
			pline("you %srepay %s's expenses.",
				(u.ugold < ESHK->robbed) ? "partially " : "",
				monnam(shopkeeper));
			pay((u.ugold<ESHK->robbed) ? u.ugold : ESHK->robbed);
			ESHK->robbed = 0;
			return(1);
		}
		if(ANGRY){
			pline("But in order to appease %s,",
				amonnam(shopkeeper, "angry"));
			if(u.ugold >= 1000){
				ltmp = 1000;
				pline(" you give him 1000 gold pieces.");
			} else {
				ltmp = u.ugold;
				pline(" you give him all your money.");
			}
			pay(ltmp);
			if(rn2(3)){
				pline("%s calms down.", Monnam(shopkeeper));
				NOTANGRY = 1;
			} else	pline("%s is as angry as ever.",
					Monnam(shopkeeper));
		}
		return(1);
	}
	for(pass = 0; pass <= 1; pass++) {
		tmp = 0;
		while(tmp < ESHK->billct) {
			bp = &bill[tmp];
			if(!pass && !bp->useup) {
				tmp++;
				continue;
			}
			if(!dopayobj(bp)) return(1);
			bill[tmp] = bill[--ESHK->billct];
		}
	}
	pline("Thank you for shopping in %s's %s store!",
		shkname(),
		shopnam[rooms[ESHK->shoproom].rtype - 8]);
	NOTANGRY = 1;
	return(1);
}

/* return 1 if paid successfully */
/*        0 if not enough money */
/*       -1 if object could not be found (but was paid) */
dopayobj(bp) register struct bill_x *bp; {
register struct obj *obj;
long ltmp;

	/* find the object on one of the lists */
	if(bp->useup)
		obj = o_on(bp->bo_id, billobjs);
	else if(!(obj = o_on(bp->bo_id, invent)) &&
		!(obj = o_on(bp->bo_id, fobj)) &&
		!(obj = o_on(bp->bo_id, fcobj))) {
		    register struct monst *mtmp;
		    for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
			if(obj = o_on(bp->bo_id, mtmp->minvent))
			    break;
		    for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon)
			if(obj = o_on(bp->bo_id, mtmp->minvent))
			    break;
		}
	if(!obj) {
		pline("Shopkeeper administration out of order.");
		impossible();
		setpaid();	/* be nice to the player */
		return(0);
	}

	if(!obj->unpaid && !bp->useup){
		pline("Paid object on bill??");
		impossible();
		return(1);
	}
	obj->unpaid = 0;
	ltmp = bp->price * bp->bquan;
	if(ANGRY) ltmp += ltmp/3;
	if(u.ugold < ltmp){
		pline("You don't have gold enough to pay %s.",
			doname(obj));
		obj->unpaid = 1;
		return(0);
	}
	pay(ltmp);
	pline("You bought %s for %ld gold piece%s.",
		doname(obj), ltmp, (ltmp == 1) ? "" : "s");
	if(bp->useup) {
		register struct obj *otmp = billobjs;
		if(obj == billobjs)
			billobjs = obj->nobj;
		else {
			while(otmp && otmp->nobj != obj) otmp = otmp->nobj;
			if(otmp) otmp->nobj = obj->nobj;
			else pline("Error in shopkeeper administration");
		}
		free((char *) obj);
	}
	return(1);
}

/* routine called after dying (or quitting) with nonempty bill */
paybill(){
	if(shopkeeper && ESHK->billct){
		addupbill();
		if(total > u.ugold){
			shopkeeper->mgold += u.ugold;
			u.ugold = 0;
		pline("%s comes and takes all your possessions.",
			Monnam(shopkeeper));
		} else {
			u.ugold -= total;
			shopkeeper->mgold += total;
	pline("%s comes and takes the %ld zorkmids you owed him.",
		Monnam(shopkeeper), total);
		}
		setpaid();	/* in case we create bones */
	}
}

/* called in hack.c when we pickup an object */
addtobill(obj) register struct obj *obj; {
register struct bill_x *bp;
	if(!inshop() || (u.ux == ESHK->shk.x && u.uy == ESHK->shk.y) ||
		(u.ux == ESHK->shd.x && u.uy == ESHK->shd.y) ||
		onbill(obj) /* perhaps we threw it away earlier */
	) return;
	if(ESHK->billct == BILLSZ){
		pline("You got that for free!");
		return;
	}
	bp = &bill[ESHK->billct];
	bp->bo_id = obj->o_id;
	bp->bquan = obj->quan;
	bp->useup = 0;
	bp->price = getprice(obj);
	ESHK->billct++;
	obj->unpaid = 1;
}

splitbill(obj,otmp) register struct obj *obj, *otmp; {
	/* otmp has been split off from obj */
register struct bill_x *bp;
register int tmp;
	bp = onbill(obj);
	if(!bp) { impossible(); return; }
	if(bp->bquan < otmp->quan) {
		pline("Negative quantity on bill??");
		impossible();
	}
	if(bp->bquan == otmp->quan) {
		pline("Zero quantity on bill??");
		impossible();
	}
	bp->bquan -= otmp->quan;

	/* addtobill(otmp); */
	if(ESHK->billct == BILLSZ) otmp->unpaid = 0;
	else {
		tmp = bp->price;
		bp = &bill[ESHK->billct];
		bp->bo_id = otmp->o_id;
		bp->bquan = otmp->quan;
		bp->useup = 0;
		bp->price = tmp;
		ESHK->billct++;
	}
}

subfrombill(obj) register struct obj *obj; {
long ltmp;
register int tmp;
register struct obj *otmp;
register struct bill_x *bp;
	if(!inshop() || (u.ux == ESHK->shk.x && u.uy == ESHK->shk.y) ||
		(u.ux == ESHK->shd.x && u.uy == ESHK->shd.y))
		return;
	if((bp = onbill(obj)) != 0){
		obj->unpaid = 0;
		if(bp->bquan > obj->quan){
			otmp = newobj(0);
			*otmp = *obj;
			bp->bo_id = otmp->o_id = flags.ident++;
			otmp->quan = (bp->bquan -= obj->quan);
			otmp->owt = 0;	/* superfluous */
			otmp->onamelth = 0;
			bp->useup = 1;
			otmp->nobj = billobjs;
			billobjs = otmp;
			return;
		}
		ESHK->billct--;
		*bp = bill[ESHK->billct];
		return;
	}
	if(obj->unpaid){
		pline("%s didn't notice.", Monnam(shopkeeper));
		obj->unpaid = 0;
		return;		/* %% */
	}
	/* he dropped something of his own - probably wants to sell it */
	if(shopkeeper->msleep || shopkeeper->mfroz ||
		inroom(shopkeeper->mx,shopkeeper->my) != ESHK->shoproom)
		return;
	if(ESHK->billct == BILLSZ ||
	  ((tmp = shtypes[rooms[ESHK->shoproom].rtype-8]) && tmp != obj->olet)
	  || index("_0", obj->olet)) {
		pline("%s seems not interested.", Monnam(shopkeeper));
		return;
	}
	ltmp = getprice(obj) * obj->quan;
	if(ANGRY) {
		ltmp /= 3;
		NOTANGRY = 1;
	} else	ltmp /= 2;
	if(ESHK->robbed){
		if((ESHK->robbed -= ltmp) < 0) ESHK->robbed = 0;
pline("Thank you for your contribution to restock this recently plundered shop.");
		return;
	}
	if(ltmp > shopkeeper->mgold) ltmp = shopkeeper->mgold;
	pay(-ltmp);
	if(!ltmp)
	pline("%s gladly accepts %s but cannot pay you at present.",
		Monnam(shopkeeper), doname(obj));
	else
	pline("You sold %s and got %ld gold piece%s.", doname(obj), ltmp,
		(ltmp == 1) ? "" : "s");
}

doinvbill(cl) int cl; {
register unsigned tmp,cnt = 0;
register struct obj *obj;
char buf[BUFSZ];
	if(!shopkeeper) return;
	for(tmp = 0; tmp < ESHK->billct; tmp++) if(bill[tmp].useup) cnt++;
	if(!cnt) return;
	if(!cl && !flags.oneline) cls();
	if(!flags.oneline) myputs("\n\nUnpaid articles already used up:\n");
	for(tmp = 0; tmp < ESHK->billct; tmp++) if(bill[tmp].useup){
		for(obj = billobjs; obj; obj = obj->nobj)
			if(obj->o_id == bill[tmp].bo_id) break;
		if(!obj) {
			pline("Bad shopkeeper administration.");
			impossible();
			return;
		}
		(void) sprintf(buf, "* -  %s", doname(obj));
		for(cnt=0; buf[cnt]; cnt++);
		while(cnt < 50) buf[cnt++] = ' ';
		(void) sprintf(&buf[cnt], " %5d zorkmids",
				bill[tmp].price * bill[tmp].bquan);
		if(flags.oneline)
			pline(buf);
		else
			myputs(buf);
	}
	if(!cl && !flags.oneline) {
		getret();
		docrt();
	}
}

getprice(obj) register struct obj *obj; {
register int tmp,ac;
	switch(obj->olet){
		case AMULET_SYM:
			tmp = 10*rnd(500);
			break;
		case TOOL_SYM:
			tmp = 10*rnd(150);
			break;
		case RING_SYM:
			tmp = 10*rnd(100);
			break;
		case WAND_SYM:
			tmp = 10*rnd(100);
			break;
		case SCROLL_SYM:
			tmp = 10*rnd(50);
			break;
		case POTION_SYM:
			tmp = 10*rnd(50);
			break;
		case FOOD_SYM:
			tmp = 10*rnd(5 + (2000/realhunger()));
			break;
		case GEM_SYM:
			tmp = 10*rnd(20);
			break;
		case ARMOR_SYM:
			ac = 10 - obj->spe;
			tmp = 100 + (10-ac)*(10-ac)*rnd(20-ac);
			break;
		case WEAPON_SYM:
			if(obj->otyp < BOOMERANG)
				tmp = 5*rnd(10);
			else if(obj->otyp == LONG_SWORD ||
				obj->otyp == TWO_HANDED_SWORD)
				tmp = 10*rnd(150);
			else	tmp = 10*rnd(75);
			break;
		case CHAIN_SYM:
			pline("Strange ..., carrying a chain?");
		case BALL_SYM:
			tmp = 10;
			break;
		default:
			tmp = 10000;
	}
	return(tmp);
}

realhunger(){	/* not completely foolproof */
register int tmp = u.uhunger;
register struct obj *otmp = invent;
	while(otmp){
		if(otmp->olet == FOOD_SYM && !otmp->unpaid)
			tmp += objects[otmp->otyp].nutrition;
		otmp = otmp->nobj;
	}
	return((tmp <= 0) ? 1 : tmp);
}

shk_move(){
register struct monst *mtmp;
register struct permonst *mdat = shopkeeper->data;
register xchar gx,gy,omx,omy,nx,ny,nix,niy;
register schar appr,i;
schar shkr,tmp,chi,chcnt,cnt;
boolean uondoor, avoid;
coord poss[9];
int info[9];
	omx = shopkeeper->mx;
	omy = shopkeeper->my;
	shkr = inroom(omx,omy);
	if(ANGRY && dist(omx,omy) < 3){
		(void) hitu(shopkeeper, d(mdat->damn, mdat->damd)+1);
		return(0);
	}
	appr = 1;
	gx = ESHK->shk.x;
	gy = ESHK->shk.y;
	if(ANGRY){
		long saveBlind = Blind;
		Blind = 0;
		if(shopkeeper->mcansee && !Invis && cansee(omx,omy)) {
			gx = u.ux;
			gy = u.uy;
		}
		Blind = saveBlind;
		avoid = FALSE;
	} else {
#define	GDIST(x,y)	((x-gx)*(x-gx)+(y-gy)*(y-gy))
		if(Invis)
		  avoid = FALSE;
		else {
		  uondoor = (u.ux == ESHK->shd.x && u.uy == ESHK->shd.y);
		  avoid = ((u.uinshop && dist(gx,gy) > 8) || uondoor);
		  if(((!ESHK->robbed && !ESHK->billct) || avoid)
		  	&& GDIST(omx,omy) < 3){
		  	if(!online(omx,omy)) return(0);
		  	if(omx == gx && omy == gy)
		  		appr = gx = gy = 0;
		  }
		}
	}
	if(omx == gx && omy == gy) return(0);
	if(shopkeeper->mconf) appr = 0;
	nix = omx;
	niy = omy;
	cnt = mfndpos(shopkeeper,poss,info,
		(avoid ? NOTONL : 0) | ALLOW_SSM);
	if(cnt == 0 && avoid && uondoor)
		cnt = mfndpos(shopkeeper,poss,info,ALLOW_SSM);
	chi = -1;
	chcnt = 0;
	for(i=0; i<cnt; i++){
		nx = poss[i].x;
		ny = poss[i].y;
	   	if((tmp = levl[nx][ny].typ) = ROOM ||
		(shkr != ESHK->shoproom && (tmp==CORR || tmp==DOOR)))
#ifdef STUPID
		/* cater for stupid compilers */
		{ int zz;
		if((!appr && !rn2(++chcnt)) ||
		   (appr && (zz = GDIST(nix,niy)) && zz > GDIST(nx,ny))){
#else
		if((!appr && !rn2(++chcnt)) ||
		   (appr && GDIST(nx,ny) < GDIST(nix,niy))){
#endif STUPID
			nix = nx;
			niy = ny;
			chi = i;
#ifdef STUPID
		   }
#endif STUPID
		}
	}
	if(nix != omx || niy != omy){
		if(info[chi] & ALLOW_M){
			mtmp = m_at(nix,niy);
			if(hitmm(shopkeeper,mtmp) == 1 && rn2(3) &&
			   hitmm(mtmp,shopkeeper) == 2) return(2);
			return(0);
		} else if(info[chi] & ALLOW_U){
			(void) hitu(shopkeeper, d(mdat->damn, mdat->damd)+1);
			return(0);
		}
		shopkeeper->mx = nix;
		shopkeeper->my = niy;
		pmon(shopkeeper);
		return(1);
	}
	return(0);
}
#endif QUEST

char *
plur(n) unsigned n; {
	return((n==1) ? "" : "s");
}

online(x,y) {
	return(x==u.ux || y==u.uy ||
		(x-u.ux)*(x-u.ux) == (y-u.uy)*(y-u.uy));
}
#file hack.stat.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

gethdate(name) char *name; {
/* register char *np;                                  */
/*    if(stat(name, &hbuf))                            */
/*       error("Cannot get status of %s.",             */
/*          (np = index(name, '/')) ? np+1 : name);    */
}

uptodate(fd) {
/*    if(fstat(fd, &buf)) {                            */
/*       pline("Cannot get status?");                  */
/*       return(0);                                    */
/*    }                                                */
/*    if(buf.st_ctime < hbuf.st_ctime) {               */
/*       pline("Saved level is out of date.");         */
/*       return(0);                                    */
/*    }                                                */
   return(1);
}
#file hack.steal.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "hack.h"

stealgold(mtmp)  register struct monst *mtmp; {
register struct gen *gold = g_at(u.ux, u.uy, fgold);
register int tmp;
	if(gold && ( !u.ugold || gold->gflag > u.ugold || !rn2(5))) {
		mtmp->mgold += gold->gflag;
		freegold(gold);
		if(Invis) newsym(u.ux, u.uy);
		pline("%s quickly snatches some gold from between your feet!",
			Monnam(mtmp));
		if(!u.ugold || !rn2(5)) {
			rloc(mtmp);
			mtmp->mflee = 1;
		}
	} else if(u.ugold) {
		u.ugold -= (tmp = somegold());
		pline("Your purse feels lighter.");
		mtmp->mgold += tmp;
		rloc(mtmp);
		mtmp->mflee = 1;
		flags.botl = 1;
	}
}

somegold(){
	return( (u.ugold < 100) ? u.ugold :
		(u.ugold > 10000) ? rnd(10000) : rnd((int) u.ugold) );
}

/* steal armor after he finishes taking it off */
unsigned stealoid;		/* object to be stolen */
unsigned stealmid;		/* monster doing the stealing */
stealarm(){
	register struct monst *mtmp;
	register struct obj *otmp;

	for(otmp = invent; otmp; otmp = otmp->nobj)
	  if(otmp->o_id == stealoid) {
	    for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
	      if(mtmp->m_id == stealmid) {
		if(dist(mtmp->mx,mtmp->my) < 3) {
		  freeinv(otmp);
		  pline("%s steals %s!", Monnam(mtmp), doname(otmp));
		  mpickobj(mtmp,otmp);
		  mtmp->mflee = 1;
		  rloc(mtmp);
		}
		break;
	      }
	    break;
	  }
	stealoid = 0;
}

/* returns 1 when something was stolen */
/* (or at least, when N should flee now) */
/* avoid stealing the object stealoid */
steal(mtmp)
struct monst *mtmp;
{
	register struct obj *otmp;
	register int tmp;
	register int named = 0;

	if(!invent){
	    if(Blind)
	      pline("Somebody tries to rob you, but finds nothing to steal.");
	    else
	      pline("%s tries to rob you, but she finds nothing to steal!",
		Monnam(mtmp));
	    return(1);	/* let her flee */
	}
	tmp = 0;
	for(otmp = invent; otmp; otmp = otmp->nobj)
		tmp += ((otmp->owornmask & (W_ARMOR | W_RING)) ? 5 : 1);
	tmp = rn2(tmp);
	for(otmp = invent; otmp; otmp = otmp->nobj)
		if((tmp -= ((otmp->owornmask & (W_ARMOR | W_RING)) ? 5 : 1))
			< 0) break;
	if(!otmp) panic("Steal fails!");
	if(otmp->o_id == stealoid) return(0);
	if((otmp->owornmask & (W_ARMOR | W_RING))){
		switch(otmp->olet) {
		case RING_SYM:
			ringoff(otmp);
			break;
		case ARMOR_SYM:
			if(multi < 0 || otmp == uarms){
			  setworn((struct obj *) 0, otmp->owornmask & W_ARMOR);
			  break;
			}
		{ int curssv = otmp->cursed;
			otmp->cursed = 0;
			pline("%s seduces you and %s off your %s.",
				Amonnam(mtmp, Blind ? "gentle" : "beautiful"),
				otmp->cursed ? "helps you to take"
					    : "you start taking",
				(otmp == uarmg) ? "gloves" :
				(otmp == uarmh) ? "helmet" : "armor");
			named++;
			(void) armoroff(otmp);
			otmp->cursed = curssv;
			if(multi < 0){
				extern char *nomovemsg;
				extern int (*afternmv)();
				/*
				multi = 0;
				nomovemsg = 0;
				afternmv = 0;
				*/
				stealoid = otmp->o_id;
				stealmid = mtmp->m_id;
				afternmv = stealarm;
				return(0);
			}
			break;
		}
		default:
			impossible();
		}
	}
	else if(otmp == uwep)
		setuwep((struct obj *) 0);
	if(otmp->olet == CHAIN_SYM) {
		pline("How come you are carrying that chain?");
		impossible();
	}
	if(Punished && otmp == uball){
		Punished = 0;
		freeobj(uchain);
		free((char *) uchain);
		uchain = (struct obj *) 0;
		uball->spe = 0;
		uball = (struct obj *) 0;	/* superfluous */
	}
	freeinv(otmp);
	pline("%s stole %s.", named ? "She" : Monnam(mtmp), doname(otmp));
	mpickobj(mtmp,otmp);
	return((multi < 0) ? 0 : 1);
}

mpickobj(mtmp,otmp)
register struct monst *mtmp;
register struct obj *otmp;
{
	otmp->nobj = mtmp->minvent;
	mtmp->minvent = otmp;
}

/* release the objects the killed animal has stolen */
relobj(mtmp,show)
register struct monst *mtmp;
register int show;
{
	register struct obj *otmp, *otmp2;

	for(otmp = mtmp->minvent; otmp; otmp = otmp2){
		otmp->ox = mtmp->mx;
		otmp->oy = mtmp->my;
		otmp2 = otmp->nobj;
		otmp->nobj = fobj;
		fobj = otmp;
		stackobj(fobj);
		if(show & cansee(mtmp->mx,mtmp->my))
			atl(otmp->ox,otmp->oy,otmp->olet);
	}
	mtmp->minvent = (struct obj *) 0;
	if(mtmp->mgold || mtmp->data->mlet == 'L') {
		register int tmp;

		tmp = (mtmp->mgold > 10000) ? 10000 : mtmp->mgold;
		mkgold( tmp + d(dlevel,30), mtmp->mx, mtmp->my);
		if(show & cansee(mtmp->mx,mtmp->my))
			atl(mtmp->mx,mtmp->my,'$');
	}
}
#file hack.timeout.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */



#include	"hack.h"

#define	SIZE(x)	(sizeof(x) / sizeof(x[0]))



timeout(){

register struct prop *upp;

	for(upp = u.uprops; upp < u.uprops+SIZE(u.uprops); upp++)

	    if((upp->p_flgs & TIMEOUT) && !--upp->p_flgs) {

		if(upp->p_tofn) (*upp->p_tofn)();

		else switch(upp - u.uprops){

		case SICK:

			pline("You die because of food poisoning");

			killer = u.usick_cause;

			done("died");

			/* NOTREACHED */

		case FAST:

			pline("You feel yourself slowing down");

			break;

		case CONFUSION:

			pline("You feel less confused now");

			break;

		case BLIND:

			pline("You can see again");

			setsee();

			break;

		case INVIS:

			on_scr(u.ux,u.uy);

			pline("You are no longer invisible.");

		}

	}

}

#file hack.topl.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "hack.h"
#include <stdio.h>
extern char *eos();
#define   TOPLSZ   (COLNO-8)   /* leave room for --More-- */
char toplines[BUFSZ];
xchar tlx, tly;         /* set by pline; used by addtopl */

struct topl {
   struct topl *next_topl;
   char *topl_text;
} *old_toplines, *last_redone_topl;
#define   OTLMAX   20      /* max nr of old toplines remembered */

doredotopl(){
   if(last_redone_topl)
      last_redone_topl = last_redone_topl->next_topl;
   if(!last_redone_topl)
      last_redone_topl = old_toplines;
   if(last_redone_topl){
      (void) strcpy(toplines, last_redone_topl->topl_text);
   }
   redotoplin();
   return(0);
}

redotoplin() {
   home();
   if(index(toplines, '\n')) cl_end();
   putstr(toplines);
   cl_end();
   tlx = curx;
   tly = cury;
   flags.topl = 1;
   if(tly > 1)
      more();
}

remember_topl() {
register struct topl *tl;
register int cnt = OTLMAX;
   if(last_redone_topl &&
      !strcmp(toplines, last_redone_topl->topl_text)) return;
   if(old_toplines &&
      !strcmp(toplines, old_toplines->topl_text)) return;
   last_redone_topl = 0;
   tl = (struct topl *)
      alloc((unsigned)(strlen(toplines) + sizeof(struct topl) + 1));
   tl->next_topl = old_toplines;
   tl->topl_text = (char *)(tl + 1);
   (void) strcpy(tl->topl_text, toplines);
   old_toplines = tl;
   while(cnt && tl){
      cnt--;
      tl = tl->next_topl;
   }
   if(tl && tl->next_topl){
      free((char *) tl->next_topl);
      tl->next_topl = 0;
   }
}

addtopl(s) char *s; {
   curs(tlx,tly);
   if(tlx + strlen(s) > COLNO) putsym('\n');
   putstr(s);
   tlx = curx;
   tly = cury;
   flags.topl = 1;
}

xmore(spaceflag)
boolean spaceflag;   /* TRUE if space required */
{
   if(flags.topl) {
      curs(tlx, tly);
      if(tlx + 8 > COLNO) putsym('\n'), tly++;
   }
   putstr("--More--");
   xwaitforspace(spaceflag);
   if(flags.topl && tly > 1) {
      home();
      cl_end();
      docorner(1, tly-1);
   }
   flags.topl = 0;
}

more(){
   xmore(TRUE);
}

cmore(){
   xmore(FALSE);
}

clrlin(){
   if(flags.topl) {
      home();
      cl_end();
      if(tly > 1) docorner(1, tly-1);
      remember_topl();
   }
   flags.topl = 0;
}

/*VARARGS1*/
pline(line,arg1,arg2,arg3,arg4,arg5,arg6)
/* register */  char *line,*arg1,*arg2,*arg3,*arg4,*arg5,*arg6;
{
   char pbuf[BUFSZ];
   register char *bp = pbuf, *tl;
   register int n,n0;

   if(!line || !*line) return;
   if(!index(line, '%')) (void) strcpy(pbuf,line); else
   (void) sprintf(pbuf,line,arg1,arg2,arg3,arg4,arg5,arg6);
   if(flags.topl == 1 && !strcmp(pbuf, toplines)) return;
   nscr();      /* %% */

   /* If there is room on the line, print message on same line */
   /* But messages like "You die..." deserve their own line */
   n0 = strlen(bp);
   if(flags.topl == 1 && tly == 1 &&
       n0 + strlen(toplines) + 3 < TOPLSZ &&
       strncmp(bp, "You ", 4)) {
      (void) strcat(toplines, "  ");
      (void) strcat(toplines, bp);
      tlx += 2;
      addtopl(bp);
      return;
   }
   if(flags.topl == 1) more();
   remember_topl();
   toplines[0] = 0;
   while(n0){
      if(n0 >= COLNO){
         /* look for appropriate cut point */
         n0 = 0;
         for(n = 0; n < COLNO; n++) if(bp[n] == ' ')
            n0 = n;
         if(!n0) for(n = 0; n < COLNO-1; n++)
            if(!letter(bp[n])) n0 = n;
         if(!n0) n0 = COLNO-2;
      }
      (void) strncpy((tl = eos(toplines)), bp, n0);
      tl[n0] = 0;
      bp += n0;

      /* remove trailing spaces, but leave one */
      while(n0 > 1 && tl[n0-1] == ' ' && tl[n0-2] == ' ')
         tl[--n0] = 0;

      n0 = strlen(bp);
      if(n0 && tl[0]) (void) strcat(tl, "\n");
   }
   redotoplin();
}

putsym(c) char c; {
   switch(c) {
   case '\b':
      backsp();
      return;
   case '\n':
      curx = 1;
      cury++;
      if(cury > tly) tly = cury;
      break;
   default:
      curx++;
      if(curx == COLNO) putsym('\n');
   }
   (void) myputchar(c);
}

putstr(s) register char *s; {
   while(*s) putsym(*s++);
}

#file hack.track.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "hack.h"
#ifdef TRACK
#define	UTSZ	50

coord utrack[UTSZ];
int utcnt = 0;
int utpnt = 0;

initrack(){
	utcnt = utpnt = 0;
}

/* add to track */
settrack(){
	if(utcnt < UTSZ) utcnt++;
	if(utpnt == UTSZ) utpnt = 0;
	utrack[utpnt].x = u.ux;
	utrack[utpnt].y = u.uy;
	utpnt++;
}

coord *
gettrack(x,y) register int x,y; {
register int i,cnt;
coord tc;
	cnt = utcnt;
	for(i = utpnt-1; cnt--; i--){
		if(i == -1) i = UTSZ-1;
		tc = utrack[i];
		if((x-tc.x)*(x-tc.x) + (y-tc.y)*(y-tc.y) < 3)
			return(&(utrack[i]));
	}
	return(0);
}
#endif TRACK
#file hack.trap.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.trap.c version 1.0.1 - added dotele(); */

#include   "hack.h"
#include   "def.trap.h"

extern struct monst *makemon();

char vowels[] = "aeiou";

char *traps[] = {
   " bear trap",
   "n arrow trap",
   " dart trap",
   " trapdoor",
   " teleportation trap",
   " pit",
   " sleeping gas trap",
   " piercer",
   " mimic"
};

dotrap(trap) register struct gen *trap; {
   nomul(0);
   if(trap->gflag&SEEN && !rn2(5))
		pline("You escape a%s.",traps[trap->gflag & TRAPTYPE]);
   else {
      trap->gflag |= SEEN;
		switch(trap->gflag & TRAPTYPE) {
      case SLP_GAS_TRAP:
         pline("A cloud of gas puts you to sleep!");
         nomul(-rnd(25));
         break;
      case BEAR_TRAP:
         if(Levitation) {
            pline("You float over a bear trap.");
            break;
         }
         u.utrap = 4 + rn2(4);
         u.utraptype = TT_BEARTRAP;
         pline("A bear trap closes on your foot!");
         break;
      case PIERC:
         deltrap(trap);
         if(makemon(PM_PIERC,u.ux,u.uy)) {
           pline("A piercer suddenly drops from the ceiling!");
           if(uarmh)
            pline("Its blow glances off your helmet.");
           else
            (void) thitu(3,d(4,6),"falling piercer");
         }
         break;
      case ARROW_TRAP:
         pline("An arrow shoots out at you!");
         if(!thitu(8,rnd(6),"arrow")){
            mksobj_at(WEAPON_SYM, ARROW, u.ux, u.uy);
            fobj->quan = 1;
         }
         break;
      case TRAPDOOR:
         if(!xdnstair) {
pline("A trap door in the ceiling opens and a rock falls on your head!");
if(uarmh) pline("Fortunately, you are wearing a helmet!");
         losehp(uarmh ? 2 : d(2,10),"falling rock");
         } else {
             register int newlevel = dlevel + 1;
            while(!rn2(4) && newlevel < 29)
               newlevel++;
            pline("A trap door opens up under you!");
            if(Levitation || u.ustuck) {
             pline("For some reason you don't fall in.");
               break;
            }

            goto_level(newlevel, FALSE);
         }
         break;
      case DART_TRAP:
         pline("A little dart shoots out at you!");
         if(thitu(7,rnd(3),"little dart")) {
             if(!rn2(6))
            poisoned("dart","poison dart");
         } else {
            mksobj_at(WEAPON_SYM, DART, u.ux, u.uy);
            fobj->quan = 1;
         }
         break;
		case TELEP_TRAP:
			if(trap->gflag & ONCE) {
				deltrap(trap);
				newsym(u.ux,u.uy);
				vtele();
			} else {
				newsym(u.ux,u.uy);
				tele();
			}
			break;
      case PIT:
         if(Levitation) {
            pline("A pit opens up under you!");
            pline("You don't fall in!");
            break;
         }
         pline("You fall into a pit!");
         u.utrap = rn1(6,2);
         u.utraptype = TT_PIT;
         losehp(rnd(6),"fall into a pit");
         selftouch("Falling, you");
         break;
      default:
         pline("You hit a trap of type %d",trap->gflag);
         impossible();
      }
   }
}

mintrap(mtmp) register struct monst *mtmp; {
   register struct gen *gen = g_at(mtmp->mx, mtmp->my, ftrap);
   register int wasintrap = mtmp->mtrapped;

   if(!gen) {
      mtmp->mtrapped = 0;   /* perhaps teleported? */
   } else if(wasintrap) {
      if(!rn2(40)) mtmp->mtrapped = 0;
   } else {
	    register int tt = (gen->gflag & TRAPTYPE);
       int in_sight = cansee(mtmp->mx,mtmp->my);
       extern char mlarge[];
       if(mtmp->mtrapseen & (1 << tt)) {
      /* he has been in such a trap - perhaps he escapes */
      if(rn2(4)) return(0);
       }
       mtmp->mtrapseen |= (1 << tt);
       switch (tt) {
      case BEAR_TRAP:
         if(strchr(mlarge, mtmp->data->mlet)) {
            if(in_sight)
              pline("%s is caught in a bear trap!",
               Monnam(mtmp));
            else
              if(mtmp->data->mlet == 'o')
             pline("You hear the roaring of an angry bear!");
            mtmp->mtrapped = 1;
         }
         break;
      case PIT:
         if(!strchr("Eyw", mtmp->data->mlet)) {
            mtmp->mtrapped = 1;
            if(in_sight)
              pline("%s falls in a pit!", Monnam(mtmp));
         }
         break;
      case SLP_GAS_TRAP:
         if(!mtmp->msleep && !mtmp->mfroz) {
            mtmp->msleep = 1;
            if(in_sight)
              pline("%s suddenly falls asleep!",
               Monnam(mtmp));
         }
         break;
      case TELEP_TRAP:
         rloc(mtmp);
         if(in_sight && !cansee(mtmp->mx,mtmp->my))
            pline("%s suddenly disappears!",
               Monnam(mtmp));
         break;
      case ARROW_TRAP:
         if(in_sight) {
            pline("%s is hit by an arrow!",
               Monnam(mtmp));
         }
         mtmp->mhp -= 3;
         break;
      case DART_TRAP:
         if(in_sight) {
            pline("%s is hit by a dart!",
               Monnam(mtmp));
         }
         mtmp->mhp -= 2;
         /* not mondied here !! */
         break;
      case TRAPDOOR:
         if(!xdnstair) {
            mtmp->mhp -= 10;
            if(in_sight)
pline("A trap door in the ceiling opens and a rock hits %s!", monnam(mtmp));
            break;
         }
         if(mtmp->data->mlet != 'w'){
            fall_down(mtmp);
            if(in_sight)
      pline("Suddenly, %s disappears out of sight.", monnam(mtmp));
            return(2);   /* no longer on this level */
         }
         break;
      case PIERC:
         break;
      default:
         pline("Some monster encountered an impossible trap.");
         impossible();
       }
   }
   return(mtmp->mtrapped);
}

selftouch(arg) char *arg; {
   if(uwep && uwep->otyp == DEAD_COCKATRICE){
      pline("%s touch the dead cockatrice.", arg);
      pline("You turn to stone.");
      killer = objects[uwep->otyp].oc_name;
      done("died");
   }
}

float_up(){
   if(u.utrap) {
      if(u.utraptype == TT_PIT) {
         u.utrap = 0;
         pline("You float up, out of the pit!");
      } else {
         pline("You float up, only your leg is still stuck.");
      }
   } else
      pline("You start to float in the air!");
}

float_down(){
   register struct gen *trap;
   pline("You float gently to the ground.");
   if(trap = g_at(u.ux,u.uy,ftrap))
		switch(trap->gflag & TRAPTYPE) {
		case PIERC:
			break;
		case TRAPDOOR:
			if(!xdnstair || u.ustuck) break;
			/* fall into next case */
		default:
			dotrap(trap);
		}
   pickup();
}

vtele() {
#define	VAULT	6
	register struct mkroom *croom;
	for(croom = &rooms[0]; croom->hx >= 0; croom++)
	    if(croom->rtype == VAULT) {
		register int x,y;

		x = rn2(2) ? croom->lx : croom->hx;
		y = rn2(2) ? croom->ly : croom->hy;
		if(teleok(x,y)) {
		    teleds(x,y);
		    return;
		}
 	    }
	tele();
}

tele() {
	extern coord getpos();
	coord cc;
	register int nux,nuy;

   if(Teleport_control) {
      pline("To what position do you want to be teleported?");
      cc = getpos(1, "the desired position"); /* 1: force valid */
      /* possible extensions: introduce a small error if
         magic power is low; allow transfer to solid rock */
      if(teleok(cc.x, cc.y)){
			teleds(cc.x, cc.y);
			return;
      }
      pline("Sorry ...");
   }
   do {
      nux = rnd(COLNO-1);
      nuy = rn2(ROWNO);
   } while(!teleok(nux, nuy));

	teleds(nux, nuy);
}

teleds(nux, nuy)
register int nux,nuy;
{
   if(Punished) unplacebc();
   unsee();
   u.utrap = 0;
   u.ustuck = 0;
   u.ux = nux;
   u.uy = nuy;
   setsee();
   if(Punished) placebc(1);
   if(u.uswallow){
      u.uswldtim = u.uswallow = 0;
      docrt();
   }
   nomul(0);
   (void) inshop();
   pickup();
   if(!Blind) read_engr_at(u.ux,u.uy);
}

teleok(x,y) register int x,y; {
   return( isok(x,y) && levl[x][y].typ > DOOR && !m_at(x,y) &&
      !sobj_at(ENORMOUS_ROCK,x,y) && !g_at(x,y,ftrap)
   );
   /* Note: gold is permitted (because of vaults) */
}

dotele() {
	extern char pl_character[];

	if(
#ifdef WIZARD
	   !wizard &&
#endif WIZARD
		      (!Teleportation || u.ulevel < 6 ||
			(pl_character[0] != 'W' && u.ulevel < 10))) {
		pline("You are not able to teleport at will.");
		return(0);
	}
	if(u.uhunger <= 100 || u.ustr < 6) {
		pline("You miss the strength for a teleport spell.");
		return(1);
	}
	tele();
	morehungry(100);
	return(1);
}

placebc(attach) int attach; {
   if(!uchain || !uball){
      pline("Where are your chain and ball??");
      impossible();
      return;
   }
   uball->ox = uchain->ox = u.ux;
   uball->oy = uchain->oy = u.uy;
   if(attach){
      uchain->nobj = fobj;
      fobj = uchain;
      if(!carried(uball)){
         uball->nobj = fobj;
         fobj = uball;
      }
   }
}

unplacebc(){
   if(!carried(uball)){
      freeobj(uball);
      unpobj(uball);
   }
   freeobj(uchain);
   unpobj(uchain);
}

level_tele() {
register int newlevel = 5 + rn2(20);   /* 5 - 24 */
   if(dlevel == newlevel)
      if(!xdnstair) newlevel--; else newlevel++;
   goto_level(newlevel, FALSE);
}

#file hack.tty.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include   "hack.h"
#include   <stdio.h>

char inchar();

gettty(){
}

/* reset terminal to original state */
settty(s) char *s; {
   clear_screen();
   if(s) myprintf(s);
   (void) myfflush(stdout);
   flags.echo = OFF;
   flags.cbreak = OFF;
}

setctty(){
}

setftty(){
}

echo(n)
register int n;
{
}

/* always want to expand tabs, or to send a clear line char before
   printing something on topline */
xtabs()
{
}

#ifdef LONG_CMD
cbreak(n)
register int n;
{
}
#endif LONG_CMD

getlin(bufp)
register char *bufp;
{
   register char *obufp = bufp;
   register int c;

   flags.topl = 2;      /* nonempty, no --More-- required */
   for(;;) {
      (void) myfflush(stdout);
      c = inchar();
      if(c == '\b') {
         if(bufp != obufp) {
            bufp--;
            putstr("\b \b"); /* putsym converts \b */
         } else   bell();
      } else if(c == '\n') {
         *bufp = 0;
         return;
      } else {
         *bufp = c;
         bufp[1] = 0;
         putstr(bufp);
         if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO)
            bufp++;
      }
   }
}

getret() {
   xgetret(TRUE);
}

cgetret() {
   xgetret(FALSE);
}

xgetret(spaceflag)
boolean spaceflag;   /* TRUE if space (return) required */
{
   myprintf("\nHit %s to continue: ",
      flags.cbreak ? "space" : "return");
   xwaitforspace(spaceflag);
}

char morc;   /* tell the outside world what char he used */

xwaitforspace(spaceflag)
boolean spaceflag;
{
register int c;

   (void) myfflush(stdout);
   morc = 0;

   while((c = inchar()) != '\n')
      {
      if (flags.cbreak)
         {
         if (c == ' ')
            break;
         if (!spaceflag && letter(c))
            {
            morc = c;
            break;
            }
         }
      }
   }

char *
parse()
{
   static char inline[COLNO];
   register int foo;

   flags.move = 1;
   if(!Invis) curs(u.ux,u.uy+2); else home();
   (void) myfflush(stdout);
   while((foo = inchar()) >= '0' && foo <= '9')
      multi += 10*multi+foo-'0';
   if(multi) {
      multi--;
      save_cm = inline;
   }
   inline[0] = foo;
   inline[1] = 0;
   if(foo == 'f' || foo == 'F'){
      inline[1] = inchar();
#ifdef QUEST
      if(inline[1] == foo) inline[2] = inchar(); else
#endif QUEST
      inline[2] = 0;
   }
   if(foo == 'm' || foo == 'M'){
      inline[1] = inchar();
      inline[2] = 0;
   }
   clrlin();
   return(inline);
}

char
readchar() {
   register int sym;
   (void) myfflush(stdout);
   sym = inchar();
   if(flags.topl == 1) flags.topl = 2;
   return((char) sym);
}

jcz@ncsu.UUCP (John A. Toebes, VIII) (02/22/86)

#file hack.u_init.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "hack.h"
#include <stdio.h>
#include <signal.h>
#define   Strcat   (void) strcat
#define   UNDEF_TYP   0
#define   UNDEF_SPE   (-1)
extern struct obj *addinv();
extern char plname[];

char pl_character[PL_CSIZ];

struct trobj {
   uchar trotyp;
   schar trspe;
   char trolet;
   Bitfield(trquan,6);
   Bitfield(trknown,1);
};

#ifdef WIZARD
struct trobj Extra_objs[] = {
   { 0, 0, 0, 0, 0 },
   { 0, 0, 0, 0, 0 }
};
#endif WIZARD

struct trobj Cave_man[] = {
   { MACE, 1, WEAPON_SYM, 1, 1 },
   { BOW, 1, WEAPON_SYM, 1, 1 },
   { ARROW, 0, WEAPON_SYM, 25, 1 },   /* quan is variable */
   { LEATHER_ARMOR, 2, ARMOR_SYM, 1, 1 },
   { 0, 0, 0, 0, 0}
};

struct trobj Fighter[] = {
   { TWO_HANDED_SWORD, 0, WEAPON_SYM, 1, 1 },
   { RING_MAIL, 3, ARMOR_SYM, 1, 1 },
   { 0, 0, 0, 0, 0 }
};

struct trobj Knight[] = {
   { LONG_SWORD, 0, WEAPON_SYM, 1, 1 },
   { SPEAR, 2, WEAPON_SYM, 1, 1 },
   { RING_MAIL, 4, ARMOR_SYM, 1, 1 },
   { HELMET, 1, ARMOR_SYM, 1, 1 },
   { SHIELD, 1, ARMOR_SYM, 1, 1 },
   { PAIR_OF_GLOVES, 1, ARMOR_SYM, 1, 1 },
   { 0, 0, 0, 0, 0 }
};

struct trobj Speleologist[] = {
   { STUDDED_LEATHER_ARMOR, 3, ARMOR_SYM, 1, 1 },
   { UNDEF_TYP, 0, POTION_SYM, 2, 0 },
   { FOOD_RATION, 0, FOOD_SYM, 3, 1 },
   { ICE_BOX, 0, TOOL_SYM, 1, 0 },
   { 0, 0, 0, 0, 0}
};

struct trobj Tourist[] = {
   { UNDEF_TYP, 0, FOOD_SYM, 10, 1 },
   { POT_EXTRA_HEALING, 0, POTION_SYM, 2, 0 },
   { EXPENSIVE_CAMERA, 0, TOOL_SYM, 1, 1 },
   { DART, 2, WEAPON_SYM, 25, 1 },   /* quan is variable */
   { 0, 0, 0, 0, 0 }
};

struct trobj Wizard[] = {
   { ELVEN_CLOAK, 1, ARMOR_SYM, 1, 1 },
   { UNDEF_TYP, UNDEF_SPE, WAND_SYM, 2, 0 },
   { UNDEF_TYP, UNDEF_SPE, RING_SYM, 2, 0 },
   { UNDEF_TYP, UNDEF_SPE, POTION_SYM, 2, 0 },
   { UNDEF_TYP, UNDEF_SPE, SCROLL_SYM, 3, 0 },
   { 0, 0, 0, 0, 0 }
};

#ifdef NEWS
int u_in_infl;

u_in_intrup()
{
   u_in_infl++;
   (void) signal(SIGINT, u_in_intrup);
}
#endif NEWS

u_init(){
register int c,pc,i;
#ifdef NEWS
   /* It is not unlikely that we get an interrupt here
      intended to kill the news; unfortunately this would
      also kill (part of) the following question */
int (*prevsig)() = signal(SIGINT, u_in_intrup);
#endif NEWS
register char *cp;
char buf[256];
   if(pc = pl_character[0]) goto got_suffix;
   buf[0] = 0;
   Strcat(buf, "\nTell me what kind of character you are:\n");
   Strcat(buf, "Are you a Tourist, a Speleologist, a Fighter,\n");
   Strcat(buf, "        a Knight, a Cave-man or a Wizard? [TSFKCW] ");
intrup:
   for(cp = buf; *cp; cp++){
#ifdef NEWS
      if(u_in_infl){
         u_in_infl = 0;
         goto intrup;
      }
#endif NEWS
      (void) myputchar(*cp);
   }
loop:
   (void) myfflush(stdout);
   pc = 0;
   while((c = inchar()) != '\n') {
#ifndef AMIGA
      if(c == EOF) {
#ifdef NEWS
         if(u_in_infl) goto intrup;   /* %% */
#endif NEWS
         settty("\nEnd of input?\n");
         hackexit(0);
         }
      else
#endif !AMIGA
         if(pc && c==8)  /* backspace over it? */
         {
         myputchar(c);
         pc = 0;
         }
      else if (!pc)
         {
         pc = c;
         myputchar(c);
         }
   }
   if(!pc || !strchr("TSFKCWtsfkcw", pc)){
      myprintf("\nAnswer with T,S,F,K,C or W. What are you? ");
      goto loop;
   }
got_suffix:
   myputchar('\n');
   myfflush();
   if('a' <= pc && pc <= 'z') pc += 'A'-'a';

#ifdef NEWS
   (void) signal(SIGINT,prevsig);
#endif NEWS

   u.usym = '@';
   u.ulevel = 1;
   init_uhunger();
   u.uhpmax = u.uhp = 12;
   u.ustrmax = u.ustr = !rn2(20) ? 14 + rn2(7) : 16;
#ifdef QUEST
   u.uhorizon = 6;
#endif QUEST
   switch(pc) {
   case 'C':
      setpl_char("Cave-man");
      Cave_man[2].trquan = 12 + rnd(9)*rnd(9);
      u.uhp = u.uhpmax = 16;
      u.ustr = u.ustrmax = 18;
      ini_inv(Cave_man);
      break;
   case 'T':
      setpl_char("Tourist");
      Tourist[3].trquan = 20 + rnd(20);
      u.ugold = u.ugold0 = rnd(1000);
      u.uhp = u.uhpmax = 10;
      u.ustr = u.ustrmax = 8;
      ini_inv(Tourist);
      break;
   case 'W':
      setpl_char("Wizard");
      for(i=1; i<=4; i++) if(!rn2(5))
         Wizard[i].trquan += rn2(3) - 1;
      u.uhp = u.uhpmax = 15;
      u.ustr = u.ustrmax = 16;
      ini_inv(Wizard);
      break;
   case 'S':
      setpl_char("Speleologist");
      Fast = INTRINSIC;
      Stealth = INTRINSIC;
      u.uhp = u.uhpmax = 12;
      u.ustr = u.ustrmax = 10;
      ini_inv(Speleologist);
      break;
   case 'K':
      setpl_char("Knight");
      u.uhp = u.uhpmax = 12;
      u.ustr = u.ustrmax = 10;
      ini_inv(Knight);
      break;
   case 'F':
      setpl_char("Fighter");
      u.uhp = u.uhpmax = 14;
      u.ustr = u.ustrmax = 17;
      ini_inv(Fighter);
   }
   find_ac();
   /* make sure he can carry all he has - especially for T's */
   while(inv_weight() > 0 && u.ustr < 118)
      u.ustr++, u.ustrmax++;
#ifdef WIZARD
   if(wizard) wiz_inv();
#endif WIZARD
}

ini_inv(trop) register struct trobj *trop; {
register struct obj *obj;
extern struct obj *mkobj();
   while(trop->trolet) {
      obj = mkobj(trop->trolet);
      obj->known = trop->trknown;
      obj->cursed = 0;
      if(obj->olet == WEAPON_SYM){
         obj->quan = trop->trquan;
         trop->trquan = 1;
      }
      if(trop->trspe != UNDEF_SPE)
         obj->spe = trop->trspe;
      if(trop->trotyp != UNDEF_TYP)
         obj->otyp = trop->trotyp;
      obj->owt = weight(obj);   /* defined after setting otyp+quan */
      obj = addinv(obj);
      if(obj->olet == ARMOR_SYM){
         switch(obj->otyp){
         case SHIELD:
            if(!uarms) setworn(obj, W_ARMS);
            break;
         case HELMET:
            if(!uarmh) setworn(obj, W_ARMH);
            break;
         case PAIR_OF_GLOVES:
            if(!uarmg) setworn(obj, W_ARMG);
            break;
         case ELVEN_CLOAK:
            if(!uarm2)
               setworn(obj, W_ARM);
            break;
         default:
            if(!uarm) setworn(obj, W_ARM);
         }
      }
      if(obj->olet == WEAPON_SYM)
         if(!uwep) setuwep(obj);
      if(--trop->trquan) continue;   /* make a similar object */
      trop++;
   }
}

#ifdef WIZARD
wiz_inv(){
register struct trobj *trop = &Extra_objs[0];
extern char *getenv();
register char *ep = getenv("INVENT");
register int type;
   while(ep && *ep) {
      type = atoi(ep);
      ep = strchr(ep, ',');
      if(ep) while(*ep == ',' || *ep == ' ') ep++;
      if(type <= 0 || type > NROFOBJECTS) continue;
      trop->trotyp = type;
      trop->trolet = objects[type].oc_olet;
      trop->trspe = 4;
      trop->trknown = 1;
      trop->trquan = 1;
      ini_inv(trop);
   }
   /* give him a wand of wishing by default */
   trop->trotyp = WAN_WISHING;
   trop->trolet = WAND_SYM;
   trop->trspe = 20;
   trop->trknown = 1;
   trop->trquan = 1;
   ini_inv(trop);
}
#endif WIZARD

setpl_char(plc) char *plc; {
   (void) strncpy(pl_character, plc, PL_CSIZ-1);
   pl_character[PL_CSIZ-1] = 0;
}

plnamesuffix() {
register char *p;
   if(p = strrchr(plname, '-')) {
      *p = 0;
      if(!plname[0]) {
         askname();
         plnamesuffix();
      }
      if(strchr("TSFKCWtsfkcw", p[1])) {
         pl_character[0] = p[1];
         pl_character[1] = 0;
      }
   }
}

#file hack.vault.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include	"hack.h"
#ifdef QUEST
setgd(/* mtmp */) /* struct monst *mtmp; */ {}
gd_move() { return(2); }
gddead(mtmp) struct monst *mtmp; {}
invault(){}

#else


extern struct monst *makemon();
#define	VAULT	6
#define	FCSIZ	(ROWNO+COLNO)
struct fakecorr {
	xchar fx,fy,ftyp;
};

struct egd {
	int fcbeg, fcend;	/* fcend: first unused pos */
	xchar gdx, gdy;		/* goal of guard's walk */
	unsigned gddone:1;
	struct fakecorr fakecorr[FCSIZ];
};

struct permonst pm_guard =
	{ "guard", '@', 12, 12, -1, 4, 10, sizeof(struct egd) };

struct monst *guard;
int gdlevel;
#define	EGD	((struct egd *)(&(guard->mextra[0])))

restfakecorr(){
register int fcx,fcy,fcbeg;
register struct rm *crm;

	while((fcbeg = EGD->fcbeg) < EGD->fcend) {
		fcx = EGD->fakecorr[fcbeg].fx;
		fcy = EGD->fakecorr[fcbeg].fy;
		if((u.ux == fcx && u.uy == fcy) || cansee(fcx,fcy) ||
		   m_at(fcx,fcy))
			return;
		crm = &levl[fcx][fcy];
		crm->typ = EGD->fakecorr[fcbeg].ftyp;
		if(!crm->typ) crm->seen = 0;
		newsym(fcx,fcy);
		EGD->fcbeg++;
	}
	/* it seems he left the corridor - let the guard disappear */
	mondead(guard);
	guard = 0;
}

setgd(){
register struct monst *mtmp;
	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(mtmp->isgd){
		guard = mtmp;
		gdlevel = dlevel;
		return;
	}
	guard = 0;
}

invault(){
register int tmp = inroom(u.ux, u.uy);
	if(tmp < 0 || rooms[tmp].rtype != VAULT) {
		u.uinvault = 0;
		return;
	}
	if(++u.uinvault % 50 == 0 && (!guard || gdlevel != dlevel)) {
	char buf[BUFSZ];
	register int x,y,dx,dy,gx,gy;

		/* first find the goal for the guard */
		for(dy = 0; dy < ROWNO; dy++)
		  for(y = u.uy-dy; y <= u.uy+dy; y++) {
		    if(y > u.uy-dy) y = u.uy+dy;
		    if(y < 0 || y > ROWNO-1) continue;
		    for(x = u.ux; x < COLNO; x++)
			if(levl[x][y].typ == CORR) goto fnd;
		    for(x = u.ux-1; x > 0; x--)
			if(levl[x][y].typ == CORR) goto fnd;
		}
		impossible();
		tele();
		return;
	fnd:
		gx = x; gy = y;

		/* next find a good place for a door in the wall */
		x = u.ux; y = u.uy;
		while(levl[x][y].typ > DOOR) {
			dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
			dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
			if(abs(gx-x) >= abs(gy-y)) x += dx;
			else y += dy;
		}

		/* make something interesting happen */
		if(!(guard = makemon(&pm_guard,x,y))) return;
		guard->isgd = guard->mpeaceful = 1;
		EGD->gddone = 0;
		gdlevel = dlevel;
		if(!cansee(guard->mx, guard->my)) {
			mondead(guard);
			guard = 0;
			return;
		}
		EGD->gdx = gx;
		EGD->gdy = gy;
		EGD->fcbeg = 0;
		EGD->fakecorr[0].fx = x;
		EGD->fakecorr[0].fy = y;
		EGD->fakecorr[0].ftyp = levl[x][y].typ;
		levl[x][y].typ = DOOR;
		EGD->fcend = 1;

		pline("Suddenly one of the Vault's guards enters!");
		pmon(guard);
		pline("\"Hello stranger, who are you?\" - ");
		getlin(buf);
		clrlin();
		pline("\"I don't know you.\"");
		if(!u.ugold) pline("\"Please follow me.\"");
		else {
		    pline("\"Most likely all that gold was stolen from this vault.\"");
		    pline("\"Please drop your gold (say d$ ) and follow me.\"");
		}
	}
}

gd_move(){
register int x,y,dx,dy,gx,gy,nx,ny,tmp;
register struct fakecorr *fcp;
register struct rm *crm;
	if(!guard || gdlevel != dlevel){
		pline("Where is the guard?");
		impossible();
		return(2);	/* died */
	}
	if(u.ugold || dist(guard->mx,guard->my) > 2 || EGD->gddone){
		restfakecorr();
		return(0);	/* didnt move */
	}
	x = guard->mx;
	y = guard->my;
	/* look around (hor & vert only) for accessible places */
	for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++)
	    if(nx == x || ny == y) if(nx != x || ny != y)
	    if(isok(nx,ny))
	    if((tmp = (crm = &levl[nx][ny])->typ) >= SDOOR) {
		register int i;
		for(i = EGD->fcbeg; i < EGD->fcend; i++)
			if(EGD->fakecorr[i].fx == nx &&
			   EGD->fakecorr[i].fy == ny)
				goto nextnxy;
		if((i = inroom(nx,ny)) >= 0 && rooms[i].rtype == VAULT)
			goto nextnxy;
		/* seems we found a good place to leave him alone */
		EGD->gddone = 1;
		if(tmp >= DOOR) goto newpos;
		crm->typ = (tmp == SCORR) ? CORR : DOOR;
		goto proceed;
	nextnxy:	;
	}
	nx = x;
	ny = y;
	gx = EGD->gdx;
	gy = EGD->gdy;
	dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
	dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
	if(abs(gx-x) >= abs(gy-y)) nx += dx; else ny += dy;

	while((tmp = (crm = &levl[nx][ny])->typ) != 0) {
	/* in view of the above we must have  tmp < SDOOR */
	/* must be a wall here */
		if(isok(nx+nx-x,ny+ny-y) && levl[nx+nx-x][ny+ny-y].typ > DOOR){
			crm->typ = DOOR;
			goto proceed;
		}
		if(dy && nx != x) {
			nx = x; ny = y+dy; dx = 0;
			continue;
		}
		if(dx && ny != y) {
			ny = y; nx = x+dx; dy = 0;
			continue;
		}
		/* I don't like this, but ... */
		crm->typ = DOOR;
		goto proceed;
	}
	crm->typ = CORR;
proceed:
	fcp = &(EGD->fakecorr[EGD->fcend]);
	if(EGD->fcend++ == FCSIZ) panic("fakecorr overflow");
	fcp->fx = nx;
	fcp->fy = ny;
	fcp->ftyp = tmp;
newpos:
	if(EGD->gddone) nx = ny = 0;
	guard->mx = nx;
	guard->my = ny;
	pmon(guard);
	restfakecorr();
	return(1);
}

gddead(){
	guard = 0;
}


#endif QUEST
#file hack.version.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */

#include	"date.h"

doversion(){
	pline("AMIGA %s 1.0.1 - last edit %s.",
#ifdef QUEST
		"Quest"
#else
		"Hack"
#endif QUEST
	, datestring);
	return(0);
}
#file hack.whatis.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.whatis.c version 1.0.1 - whatis asks for one char only. */

#include	<stdio.h>
#include "hack.h"

dowhatis()
{
	FILE *fp;
	char bufr[BUFSZ];
	register char *ep, q;
	extern char readchar();

	if(!(fp = fopen("data","r")))
		pline("Cannot open data file!");
	else {
		pline("Specify what? ");
		q = readchar();
		while(fgets(bufr,BUFSZ,fp))
			if(*bufr == q) {
				ep = index(bufr, '\n');
				if(ep) *ep = 0;
				else impossible();
				pline(bufr);
				if(ep[-1] == ';') morewhat(fp);
				goto fnd;
			}
		pline("I've never heard of such things.");
	fnd:
		(void) fclose(fp);
	}
}

morewhat(fp) FILE *fp; {
char bufr[BUFSZ];
register char *ep;
	pline("More info? ");
	if(readchar() != 'y') return;
	cls();
	while(fgets(bufr,BUFSZ,fp) && *bufr == '\t'){
		ep = index(bufr, '\n');
		if(!ep) break;
		*ep = 0;
		myputs(bufr+1);
	}
	more();
	docrt();
}
#file hack.wield.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.wield.c version 1.0.1 - evaporate%s */

#include	"hack.h"

setuwep(obj) register struct obj *obj; {
	setworn(obj, W_WEP);
}

dowield()
{
	register struct obj *wep;
	register int res = 0;

	multi = 0;
	if(!(wep = getobj("#-)", "wield"))) /* nothing */;
	else if(uwep == wep)
		pline("You are already wielding that!");
	else if(uwep && uwep->cursed)
		pline("The %s welded to your hand!",
			aobjnam(uwep, "are"));
	else if((int) wep == 1) {
		if(uwep == 0){
			pline("You are already empty handed.");
		} else {
			setuwep((struct obj *) 0);
			res++;
			pline("You are empty handed.");
		}
	} else if(uarms && wep->otyp == TWO_HANDED_SWORD)
	pline("You cannot wield a two-handed sword and wear a shield.");
	else if(wep->owornmask & (W_ARMOR | W_RING))
		pline("You cannot wield that!");
	else {
		setuwep(wep);
		res++;
		if(uwep->cursed) pline("The %s itself to your hand!",
			aobjnam(uwep, "weld"));
		else prinv(uwep);
	}
	return(res);
}

corrode_weapon(){
	if(!uwep || uwep->olet != WEAPON_SYM) return;	/* %% */
	if(uwep->rustfree)
		pline("Your %s not affected.", aobjnam(uwep, "are"));
	else {
		pline("Your %s!", aobjnam(uwep, "corrode"));
		uwep->spe--;
	}
}

chwepon(otmp,amount)
register struct obj *otmp;
register int amount;
{
register char *color = (amount < 0) ? "black" : "green";
register char *time;
	if(!uwep || uwep->olet != WEAPON_SYM) {
		strange_feeling(otmp);
		return(0);
	}

	if(uwep->otyp == WORM_TOOTH && amount > 0) {
		uwep->otyp = CRYSKNIFE;
		pline("Your weapon seems sharper now.");
		uwep->cursed = 0;
		return(1);
	}

	if(uwep->otyp == CRYSKNIFE && amount < 0) {
		uwep->otyp = WORM_TOOTH;
		pline("Your weapon looks duller now.");
		return(1);
	}

	/* there is a (soft) upper limit to uwep->spe */
	if(amount > 0 && uwep->spe > 5 && rn2(3)) {
	    pline("Your %s violently green for a while and then evaporate%s.",
		aobjnam(uwep, "glow"), (uwep->quan == 1) ? "s" : "");
	    useup(uwep);
	    return(1);
	}
	if(!rn2(6)) amount *= 2;
	time = (amount*amount == 1) ? "moment" : "while";
	pline("Your %s %s for a %s.",
		aobjnam(uwep, "glow"), color, time);
	uwep->spe += amount;
	if(amount > 0) uwep->cursed = 0;
	return(1);
}
#file hack.worm.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "hack.h"
#ifndef NOWORM
#include "def.wseg.h"

struct wseg *wsegs[32];	/* linked list, tail first */
struct wseg *wheads[32];
long wgrowtime[32];

getwn(mtmp) struct monst *mtmp; {
register int tmp;
	for(tmp=1; tmp<32; tmp++) if(!wsegs[tmp]) {
		mtmp->wormno = tmp;
		return(1);
	}
	return(0);	/* level infested with worms */
}

/* called to initialize a worm unless cut in half */
initworm(mtmp) struct monst *mtmp; {
register struct wseg *wtmp;
register int tmp = mtmp->wormno;
	if(!tmp) return;
	wheads[tmp] = wsegs[tmp] = wtmp = newseg();
	wgrowtime[tmp] = 0;
	wtmp->wx = mtmp->mx;
	wtmp->wy = mtmp->my;
/*	wtmp->wdispl = 0;*/
	wtmp->nseg = 0;
}

worm_move(mtmp) struct monst *mtmp; {
register struct wseg *wtmp, *whd;
register int tmp = mtmp->wormno;
	wtmp = newseg();
	wtmp->wx = mtmp->mx;
	wtmp->wy = mtmp->my;
	wtmp->nseg = 0;
/*	wtmp->wdispl = 0;*/
	(whd = wheads[tmp])->nseg = wtmp;
	wheads[tmp] = wtmp;
	if(cansee(whd->wx,whd->wy)){
		unpmon(mtmp);
		atl(whd->wx, whd->wy, '~');
		whd->wdispl = 1;
	} else	whd->wdispl = 0;
	if(wgrowtime[tmp] <= moves) {
		if(!wgrowtime[tmp]) wgrowtime[tmp] = moves + rnd(5);
		else wgrowtime[tmp] += 2+rnd(15);
		mtmp->orig_hp++;
		mtmp->mhp++;
		return;
	}
	whd = wsegs[tmp];
	wsegs[tmp] = whd->nseg;
	remseg(whd);
}

worm_nomove(mtmp) register struct monst *mtmp; {
register int tmp;
register struct wseg *wtmp;
	tmp = mtmp->wormno;
	wtmp = wsegs[tmp];
	if(wtmp == wheads[tmp]) return;
	if(wtmp == 0 || wtmp->nseg == 0) panic("worm_nomove?");
	wsegs[tmp] = wtmp->nseg;
	remseg(wtmp);
	mtmp->mhp--;	/* orig_hp not changed ! */
}

wormdead(mtmp) register struct monst *mtmp; {
register int tmp = mtmp->wormno;
register struct wseg *wtmp, *wtmp2;
	if(!tmp) return;
	mtmp->wormno = 0;
	for(wtmp = wsegs[tmp]; wtmp; wtmp = wtmp2){
		wtmp2 = wtmp->nseg;
		remseg(wtmp);
	}
	wsegs[tmp] = 0;
}

wormhit(mtmp) register struct monst *mtmp; {
register int tmp = mtmp->wormno;
register struct wseg *wtmp;
	if(!tmp) return;	/* worm without tail */
	for(wtmp = wsegs[tmp]; wtmp; wtmp = wtmp->nseg)
		(void) hitu(mtmp,1);
}

wormsee(tmp) register unsigned tmp; {
register struct wseg *wtmp = wsegs[tmp];
	if(!wtmp) panic("wormsee: wtmp==0");
	for(; wtmp->nseg; wtmp = wtmp->nseg)
		if(!cansee(wtmp->wx,wtmp->wy) && wtmp->wdispl){
			newsym(wtmp->wx, wtmp->wy);
			wtmp->wdispl = 0;
		}
}

pwseg(wtmp) register struct wseg *wtmp; {
	if(!wtmp->wdispl){
		atl(wtmp->wx, wtmp->wy, '~');
		wtmp->wdispl = 1;
	}
}

cutworm(mtmp,x,y,weptyp)
register struct monst *mtmp;
register xchar x,y;
register uchar weptyp;		/* uwep->otyp or 0 */
{
	register struct wseg *wtmp, *wtmp2;
	register struct monst *mtmp2;
	register int tmp,tmp2;
	if(mtmp->mx == x && mtmp->my == y) return;	/* hit headon */

	/* cutting goes best with axe or sword */
	tmp = rnd(20);
	if(weptyp == LONG_SWORD || weptyp == TWO_HANDED_SWORD ||
		weptyp == AXE) tmp += 5;
	if(tmp < 12) return;

	/* if tail then worm just loses a tail segment */
	tmp = mtmp->wormno;
	wtmp = wsegs[tmp];
	if(wtmp->wx == x && wtmp->wy == y){
		wsegs[tmp] = wtmp->nseg;
		remseg(wtmp);
		return;
	}

	/* cut the worm in two halves */
	mtmp2 = newmonst(0);
	*mtmp2 = *mtmp;
	mtmp2->mxlth = mtmp2->mnamelth = 0;

	/* sometimes the tail end dies */
	if(rn2(3) || !getwn(mtmp2)){
		monfree(mtmp2);
		tmp2 = 0;
	} else {
		tmp2 = mtmp2->wormno;
		wsegs[tmp2] = wsegs[tmp];
		wgrowtime[tmp2] = 0;
	}
	do {
		if(wtmp->nseg->wx == x && wtmp->nseg->wy == y){
			if(tmp2) wheads[tmp2] = wtmp;
			wsegs[tmp] = wtmp->nseg->nseg;
			remseg(wtmp->nseg);
			wtmp->nseg = 0;
			if(tmp2){
				pline("You cut the worm in half.");
				mtmp2->orig_hp = mtmp2->mhp =
					d(mtmp2->data->mlevel, 8);
				mtmp2->mx = wtmp->wx;
				mtmp2->my = wtmp->wy;
				mtmp2->nmon = fmon;
				fmon = mtmp2;
				pmon(mtmp2);
			} else {
				pline("You cut off part of the worm's tail.");
				remseg(wtmp);
			}
			mtmp->mhp /= 2;
			return;
		}
		wtmp2 = wtmp->nseg;
		if(!tmp2) remseg(wtmp);
		wtmp = wtmp2;
	} while(wtmp->nseg);
	panic("Cannot find worm segment");
}

remseg(wtmp) register struct wseg *wtmp; {
	if(wtmp->wdispl)
		newsym(wtmp->wx, wtmp->wy);
	free((char *) wtmp);
}
#endif NOWORM
#file hack.worn.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */



#include "hack.h"



struct worn {

	long w_mask;

	struct obj **w_obj;

} worn[] = {

	{ W_ARM, &uarm },

	{ W_ARM2, &uarm2 },

	{ W_ARMH, &uarmh },

	{ W_ARMS, &uarms },

	{ W_ARMG, &uarmg },

	{ W_RINGL, &uleft },

	{ W_RINGR, &uright },

	{ W_WEP, &uwep },

	{ W_BALL, &uball },

	{ W_CHAIN, &uchain },

	{ 0, 0 }

};



setworn(obj, mask)

register struct obj *obj;

long mask;

{

	register struct worn *wp;

	register struct obj *oobj;



	for(wp = worn; wp->w_mask; wp++) if(wp->w_mask & mask) {

		oobj = *(wp->w_obj);

		if(oobj && !(oobj->owornmask & wp->w_mask)){

			pline("Setworn: mask = %d.", wp->w_mask);

			impossible();

		}

		if(oobj) oobj->owornmask &= ~wp->w_mask;

		if(obj && oobj && wp->w_mask == W_ARM){

			if(uarm2) {

				pline("Setworn: uarm2 set?");

				impossible();

			} else

				setworn(uarm, W_ARM2);

		}

		*(wp->w_obj) = obj;

		if(obj) obj->owornmask |= wp->w_mask;

	}

	if(uarm2 && !uarm) {

		uarm = uarm2;

		uarm2 = 0;

		uarm->owornmask ^= (W_ARM | W_ARM2);

	}

}



/* called e.g. when obj is destroyed */

setnotworn(obj) register struct obj *obj; {

	register struct worn *wp;



	for(wp = worn; wp->w_mask; wp++)

		if(obj == *(wp->w_obj)) {

			*(wp->w_obj) = 0;

			obj->owornmask &= ~wp->w_mask;

		}

	if(uarm2 && !uarm) {

		uarm = uarm2;

		uarm2 = 0;

		uarm->owornmask ^= (W_ARM | W_ARM2);

	}

}

jcz@ncsu.UUCP (John A. Toebes, VIII) (02/22/86)

#file hack.zap.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "hack.h"

extern struct monst *makemon();
struct monst *bhit();
char *exclam();

char *fl[]= {
	"magic missile",
	"bolt of fire",
	"sleep ray",
	"bolt of cold",
	"death ray"
};

dozap()
{
	register struct obj *obj;
	register struct monst *mtmp;
	xchar zx,zy;
	register int num;

	obj = getobj("/", "zap");
	if(!obj) return(0);
	if(obj->spe < 0 || (obj->spe == 0 && rn2(121))) {
		pline("Nothing Happens");
		return(1);
	}
	if(obj->spe == 0)
		pline("You wrest one more spell from the worn-out wand.");
	if(!(objects[obj->otyp].bits & NODIR) && !getdir())
		return(1); /* make him pay for knowing !NODIR */
	obj->spe--;
	if(objects[obj->otyp].bits & IMMEDIATE) {
		if((u.uswallow && (mtmp = u.ustuck)) ||
		   (mtmp = bhit(u.dx,u.dy,rn1(8,6),0))) {
			wakeup(mtmp);
			switch(obj->otyp) {
			case WAN_STRIKING:
				if(rnd(20) < 10+mtmp->data->ac) {
					register int tmp = d(2,12);
					hit("wand", mtmp, exclam(tmp));
					mtmp->mhp -= tmp;
					if(mtmp->mhp < 1) killed(mtmp);
				} else miss("wand", mtmp);
				break;
			case WAN_SLOW_MONSTER:
				mtmp->mspeed = MSLOW;
				break;
			case WAN_SPEED_MONSTER:
				mtmp->mspeed = MFAST;
				break;
			case WAN_UNDEAD_TURNING:
				if(index("WVZ&",mtmp->data->mlet)) {
					mtmp->mhp -= rnd(8);
					if(mtmp->mhp<1) killed(mtmp);
					else mtmp->mflee = 1;
				}
				break;
			case WAN_POLYMORPH:
				if( newcham(mtmp,&mons[rn2(CMNUM)]) )
					objects[obj->otyp].oc_name_known = 1;
				break;
			case WAN_CANCELLATION:
				mtmp->mcan = 1;
				break;
			case WAN_TELEPORT_MONSTER:
				rloc(mtmp);
				break;
			case WAN_MAKE_INVISIBLE:
				mtmp->minvis = 1;
				break;
#ifdef WAN_PROBING
			case WAN_PROBING:
				mstatusline(mtmp);
				break;
#endif WAN_PROBING
			default:
				pline("What an interesting wand (%d)",
					obj->otyp);
				impossible();
			}
		}
	} else {
	switch(obj->otyp){
		case WAN_LIGHT:
			litroom(TRUE);
			break;
		case WAN_SECRET_DOOR_DETECTION:
			if(!findit()) return(1);
			break;
		case WAN_CREATE_MONSTER:
			{ register int cnt = 1;
			if(!rn2(23)) cnt += rn2(7) + 1;
			while(cnt--)
			    (void) makemon((struct permonst *) 0, u.ux, u.uy);
			}
			break;
		case WAN_WISHING:
			{ char buf[BUFSZ];
			  register struct obj *otmp;
			  extern struct obj *readobjnam(), *addinv();
		      if(u.uluck + rn2(5) < 0) {
			pline("Unfortunately, nothing happens.");
			break;
		      }
		      pline("You may wish for an object. What do you want? ");
		      getlin(buf);
		      otmp = readobjnam(buf);
		      otmp = addinv(otmp);
		      prinv(otmp);
		      break;
			}
		case WAN_DIGGING:
			{ register struct rm *room;
			  register int digdepth;
			if(u.uswallow) {
				pline("You pierce %s's stomach wall!",
					monnam(u.ustuck));
				u.uswallow = 0;
				mnexto(u.ustuck);
				u.ustuck->mhp = 1;	/* almost dead */
				u.ustuck = 0;
				setsee();
				docrt();
				break;
			}
			zx = u.ux+u.dx;
			zy = u.uy+u.dy;
			if(!isok(zx,zy)) break;
			digdepth = 4 + rn2(10);
			if(levl[zx][zy].typ == CORR) num = CORR;
			else num = ROOM;
			Tmp_at(-1, '*');	/* open call */
			while(digdepth--) {
				if(zx == 0 || zx == COLNO-1 ||
					 zy == 0 || zy == ROWNO-1)
					break;
				room = &levl[zx][zy];
				Tmp_at(zx,zy);
				if(!xdnstair){
					if(zx < 3 || zx > COLNO-3 ||
					    zy < 3 || zy > ROWNO-3)
						break;
					if(room->typ == HWALL ||
					    room->typ == VWALL){
						room->typ = ROOM;
						break;
					}
				} else if(num == ROOM || num == 10){
					if(room->typ != ROOM && room->typ) {
						if(room->typ != CORR)
							room->typ = DOOR;
						if(num == 10) break;
						num = 10;
					} else if(!room->typ)
						room->typ = CORR;
				} else {
					if(room->typ != CORR && room->typ) {
						room->typ = DOOR;
						break;
					} else room->typ = CORR;
				}
				mnewsym(zx,zy);
				zx += u.dx;
				zy += u.dy;
			}
			mnewsym(zx,zy);	/* not always necessary */
			Tmp_at(-1,-1);	/* closing call */
			break;
			}
		default:
			buzz((int) obj->otyp - WAN_MAGIC_MISSILE,
				u.ux, u.uy, u.dx, u.dy);
			break;
		}
		if(!objects[obj->otyp].oc_name_known) {
			u.urexp += 10;
			objects[obj->otyp].oc_name_known = 1;
		}
	}
	return(1);
}

char *
exclam(force)
register int force;
{
	/* force == 0 occurs e.g. with sleep ray */
	/* note that large force is usual with wands so that !! would
		require information about hand/weapon/wand */
	return( (force < 0) ? "?" : (force <= 4) ? "." : "!" );
}

hit(str,mtmp,force)
register char *str;
register struct monst *mtmp;
register char *force;		/* usually either "." or "!" */
{
	if(!cansee(mtmp->mx,mtmp->my)) pline("The %s hits it.", str);
	else pline("The %s hits %s%s", str, monnam(mtmp), force);
}

miss(str,mtmp)
register char *str;
register struct monst *mtmp;
{
	if(!cansee(mtmp->mx,mtmp->my)) pline("The %s misses it.",str);
	else pline("The %s misses %s.",str,monnam(mtmp));
}

/* sets bhitpos to the final position of the weapon thrown */
/* coord bhitpos; */

/* check !u.uswallow before calling bhit() */
struct monst *
bhit(ddx,ddy,range,sym)
register int ddx,ddy,range;
char sym;
{
	register struct monst *mtmp;

	bhitpos.x = u.ux;
	bhitpos.y = u.uy;

	if(sym) tmp_at(-1, sym);	/* open call */
	while(range--) {
		bhitpos.x += ddx;
		bhitpos.y += ddy;
		if(mtmp = m_at(bhitpos.x,bhitpos.y)){
			if(sym) tmp_at(-1, -1);	/* close call */
			return(mtmp);
		}
		if(levl[bhitpos.x][bhitpos.y].typ<CORR) {
			bhitpos.x -= ddx;
			bhitpos.y -= ddy;
			break;
		}
		if(sym) tmp_at(bhitpos.x, bhitpos.y);
	}
	if(sym) tmp_at(-1, 0);	/* leave last symbol */
	return(0);
}

struct monst *
boomhit(dx,dy) {
	register int i, ct;
	register struct monst *mtmp;
	char sym = ')';
	extern schar xdir[], ydir[];

	bhitpos.x = u.ux;
	bhitpos.y = u.uy;

	for(i=0; i<8; i++) if(xdir[i] == dx && ydir[i] == dy) break;
	tmp_at(-1, sym);	/* open call */
	for(ct=0; ct<10; ct++) {
		if(i == 8) i = 0;
		sym = ')' + '(' - sym;
		tmp_at(-2, sym);	/* change let call */
		dx = xdir[i];
		dy = ydir[i];
		bhitpos.x += dx;
		bhitpos.y += dy;
		if(mtmp = m_at(bhitpos.x, bhitpos.y)){
			tmp_at(-1,-1);
			return(mtmp);
		}
		if(levl[bhitpos.x][bhitpos.y].typ<CORR) {
			bhitpos.x -= dx;
			bhitpos.y -= dy;
			break;
		}
		if(bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */
			if(rn2(20) >= 10+u.ulevel){	/* we hit ourselves */
				(void) thitu(10, rnd(10), "boomerang");
				break;
			} else {	/* we catch it */
				tmp_at(-1,-1);
				pline("Skillfully, you catch the boomerang.");
				return((struct monst *) -1);
			}
		}
		tmp_at(bhitpos.x, bhitpos.y);
		if(ct % 5 != 0) i++;
	}
	tmp_at(-1, -1);	/* do not leave last symbol */
	return(0);
}

char
dirlet(dx,dy) register int dx,dy; {
	return
		(dx == dy) ? '\\' : (dx && dy) ? '/' : dx ? '-' : '|';
}

/* type < 0: monster spitting fire at you */
buzz(type,sx,sy,dx,dy)
register int type;
register xchar sx,sy;
register int dx,dy;
{
	register char *fltxt = (type < 0) ? "blaze of fire" : fl[type];
	struct rm *lev;
	xchar range;
	struct monst *mon;

	if(u.uswallow) {
		register int tmp;

		if(type < 0) return;
		tmp = zhit(u.ustuck, type);
		pline("The %s rips into %s%s",
			fltxt, monnam(u.ustuck), exclam(tmp));
		return;
	}
	if(type < 0) pru();
	range = rn1(7,7);
	Tmp_at(-1, dirlet(dx,dy));	/* open call */
	while(range-- > 0) {
		sx += dx;
		sy += dy;
		if((lev = &levl[sx][sy])->typ) Tmp_at(sx,sy);
		else {
			int bounce = 0;
			if(cansee(sx-dx,sy-dy)) pline("The %s bounces!",fltxt);
			if(levl[sx][sy-dy].typ > DOOR) bounce = 1;
			if(levl[sx-dx][sy].typ > DOOR) {
				if(!bounce || rn2(2)) bounce = 2;
			}
			switch(bounce){
			case 0:
				dx = -dx;
				dy = -dy;
				continue;
			case 1:
				dy = -dy;
				sx -= dx;
				break;
			case 2:
				dx = -dx;
				sy -= dy;
				break;
			}
			Tmp_at(-2,dirlet(dx,dy));
			continue;
		}
		if((mon = m_at(sx,sy)) &&
		   (type >= 0 || mon->data->mlet != 'D')) {
			wakeup(mon);
			if(rnd(20) < 18 + mon->data->ac) {
				register int tmp = zhit(mon,type);
				if(mon->mhp < 1) {
					if(type < 0) {
					    if(cansee(mon->mx,mon->my))
					      pline("%s is killed by the %s!",
						Monnam(mon), fltxt);
					    mondied(mon);
					} else
					    killed(mon);
				} else
					hit(fltxt, mon, exclam(tmp));
				range -= 2;
			} else
				miss(fltxt,mon);
		} else if(sx == u.ux && sy == u.uy) {
			if(rnd(20) < 18+u.uac) {
				register int dam = 0;
				range -= 2;
				pline("The %s hits you!",fltxt);
				switch(type) {
				case 0:
					dam = d(2,6);
					break;
				case -1:	/* dragon fire */
				case 1:
					if(Fire_resistance)
						pline("You don't feel hot!");
					else dam = d(6,6);
					break;
				case 2:
					nomul(-rnd(25)); /* sleep ray */
					break;
				case 3:
					if(Cold_resistance)
						pline("You don't feel cold!");
					else dam = d(6,6);
					break;
				case 4:
					u.uhp = -1;
				}
				losehp(dam,fltxt);
			} else pline("The %s whizzes by you!",fltxt);
		}
		if(lev->typ <= DOOR) {
			int bounce = 0, rmn;
			if(cansee(sx,sy)) pline("The %s bounces!",fltxt);
			range--;
			if(!dx || !dy || !rn2(20)){
				dx = -dx;
				dy = -dy;
			} else {
			  if((rmn = levl[sx][sy-dy].typ) > DOOR &&
			    (
			     rmn >= ROOM ||
				levl[sx+dx][sy-dy].typ > DOOR)){
				bounce = 1;
			  }
			  if((rmn = levl[sx-dx][sy].typ) > DOOR &&
			    (
			     rmn >= ROOM ||
				levl[sx-dx][sy+dy].typ > DOOR)){
				if(!bounce || rn2(2)){
					bounce = 2;
				}
			  }
			  switch(bounce){
			  case 0:
				dy = -dy;
				dx = -dx;
				break;
			  case 1:
				dy = -dy;
				break;
			  case 2:
				dx = -dx;
				break;
			  }
			  Tmp_at(-2, dirlet(dx,dy));
			}
		}
	}
	Tmp_at(-1,-1);
}

zhit(mon,type)			/* returns damage to mon */
register struct monst *mon;
register int type;
{
	register int tmp = 0;

	switch(type) {
	case 0:			/* magic missile */
		tmp = d(2,6);
		break;
	case -1:		/* Dragon blazing fire */
	case 1:			/* fire */
		if(index("Dg", mon->data->mlet)) break;
		tmp = d(6,6);
		if(mon->data->mlet == 'Y') tmp += 7;
		break;
	case 2:			/* sleep*/
		mon->mfroz = 1;
		break;
	case 3:			/* cold */
		if(index("YFgf", mon->data->mlet)) break;
		tmp = d(6,6);
		if(mon->data->mlet == 'D') tmp += 7;
		break;
	case 4:			/* death*/
		if(index("WVZ",mon->data->mlet)) break;
		tmp = mon->mhp+1;
		break;
	}
	mon->mhp -= tmp;
	return(tmp);
}
#file makedefs.c
/* construct definitions of object constants */
#define	DEF_FILE	"def.objects.h"
#define	LINSZ	1000
#define	STRSZ	40

int fd;
char string[STRSZ];

main(){
register int index = 0;
register int propct = 0;
register char *sp;
	fd = open(DEF_FILE, 0);
	if(fd < 0) {
		perror(DEF_FILE);
		exit(1);
	}
	skipuntil("objects[] = {");
	while(getentry()) {
		if(!*string){
			index++;
			continue;
		}
		for(sp = string; *sp; sp++)
			if(*sp == ' ' || *sp == '\t')
				*sp = '_';
		if(!strncmp(string, "RIN_", 4)){
			capitalize(string+4);
			printf("#define	%s	u.uprops[%d].p_flgs\n",
				string+4, propct++);
		}
		for(sp = string; *sp; sp++) capitalize(sp);
		/* avoid trouble with stupid C preprocessors */
		if(!strncmp(string, "WORTHLESS_PIECE_OF_", 19))
			printf("/* #define %s	%d */\n", string, index);
		else
			printf("#define	%s	%d\n", string, index);
		index++;
	}
	printf("\n#define	CORPSE	DEAD_HUMAN\n");
	printf("#define	LAST_GEM	(JADE+1)\n");
	printf("#define	LAST_RING	%d\n", propct);
	printf("#define	NROFOBJECTS	%d\n", index-1);
}

char line[LINSZ], *lp = line, *lp0 = line, *lpe = line;
int eof;

readline(){
register int n = read(fd, lp0, (line+LINSZ)-lp0);
	if(n < 0){
		printf("Input error.\n");
		exit(1);
	}
	if(n == 0) eof++;
	lpe = lp0+n;
}

char
nextchar(){
	if(lp == lpe){
		readline();
		lp = lp0;
	}
	return((lp == lpe) ? 0 : *lp++);
}

skipuntil(s) char *s; {
register char *sp0, *sp1;
loop:
	while(*s != nextchar())
		if(eof) {
			printf("Cannot skipuntil %s\n", s);
			exit(1);
		}
	if(strlen(s) > lpe-lp+1){
		register char *lp1, *lp2;
		lp2 = lp;
		lp1 = lp = lp0;
		while(lp2 != lpe) *lp1++ = *lp2++;
		lp2 = lp0;	/* save value */
		lp0 = lp1;
		readline();
		lp0 = lp2;
		if(strlen(s) > lpe-lp+1) {
			printf("error in skipuntil");
			exit(1);
		}
	}
	sp0 = s+1;
	sp1 = lp;
	while(*sp0 && *sp0 == *sp1) sp0++, sp1++;
	if(!*sp0){
		lp = sp1;
		return(1);
	}
	goto loop;
}

getentry(){
int inbraces = 0, inparens = 0, stringseen = 0, commaseen = 0;
int prefix = 0;
char ch;
#define	NSZ	10
char identif[NSZ], *ip;
	string[0] = string[4] = 0;
	/* read until {...} or XXX(...) followed by ,
	   skip comment and #define lines
	   deliver 0 on failure
	 */
	while(1) {
		ch = nextchar();
	swi:
		if(letter(ch)){
			ip = identif;
			do {
				if(ip < identif+NSZ-1) *ip++ = ch;
				ch = nextchar();
			} while(letter(ch) || digit(ch));
			*ip = 0;
			while(ch == ' ' || ch == '\t') ch = nextchar();
			if(ch == '(' && !inparens && !stringseen)
				if(!strcmp(identif, "WAND") ||
				   !strcmp(identif, "RING") ||
				   !strcmp(identif, "POTION") ||
				   !strcmp(identif, "SCROLL"))
				(void) strncpy(string, identif, 3),
				string[3] = '_',
				prefix = 4;
		}
		switch(ch) {
		case '/':
			/* watch for comment */
			if((ch = nextchar()) == '*')
				skipuntil("*/");
			goto swi;
		case '{':
			inbraces++;
			continue;
		case '(':
			inparens++;
			continue;
		case '}':
			inbraces--;
			if(inbraces < 0) return(0);
			continue;
		case ')':
			inparens--;
			if(inparens < 0) {
				printf("too many ) ?");
				exit(1);
			}
			continue;
		case '\n':
			/* watch for #define at begin of line */
			if((ch = nextchar()) == '#'){
				register char pch;
				/* skip until '\n' not preceded by '\\' */
				do {
					pch = ch;
					ch = nextchar();
				} while(ch != '\n' || pch == '\\');
				continue;
			}
			goto swi;
		case ',':
			if(!inparens && !inbraces){
				if(prefix && !string[prefix])
					string[0] = 0;
				if(stringseen) return(1);
				printf("unexpected ,\n");
				exit(1);
			}
			commaseen++;
			continue;
		case '\'':
			if((ch = nextchar()) == '\\') ch = nextchar();
			if(nextchar() != '\''){
				printf("strange character denotation?\n");
				exit(1);
			}
			continue;
		case '"':
			{
				register char *sp = string + prefix;
				register char pch;
				register int store = (inbraces || inparens)
					&& !stringseen++ && !commaseen;
				do {
					pch = ch;
					ch = nextchar();
					if(store && sp < string+STRSZ)
						*sp++ = ch;
				} while(ch != '"' || pch == '\\');
				if(store) *--sp = 0;
				continue;
			}
		}
	}
}

capitalize(sp) register char *sp; {
	if('a' <= *sp && *sp <= 'z') *sp += 'A'-'a';
}

letter(ch) register char ch; {
	return( ('a' <= ch && ch <= 'z') ||
		('A' <= ch && ch <= 'Z') );
}

digit(ch) register char ch; {
	return( '0' <= ch && ch <= '9' );
}

#file mklev.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* mklev.c version 1.0.1 - new makecorridor() */
#ifndef MKLEV
#define	MKLEV
#endif
#include <stdio.h>
#include "hack.h"
#include "def.trap.h"

extern struct monst *makemon();

static char tspe[2],**args;
static int doorindex;
static schar nxcor;

char ismklev;
struct mkroom *croom, *troom;
boolean goldseen;
int nroom;
int smeq[MAXNROFROOMS+1];
char *tfile;

#ifdef WIZARD
extern boolean wizard;
#endif

#define somex() ((rand()%(croom->hx-croom->lx+1))+croom->lx)
#define somey() ((rand()%(croom->hy-croom->ly+1))+croom->ly)

extern char nul[40];
extern struct rm levl[COLNO][ROWNO];
extern struct monst *fmon;
extern struct obj *fobj;
extern struct gen *fgold, *ftrap;
extern char *fut_geno;      /* monsters that should not be created anymore */
extern struct mkroom rooms[MAXNROFROOMS+1];
extern coord doors[DOORMAX];
extern int comp();
extern xchar dlevel;
extern xchar xdnstair,xupstair,ydnstair,yupstair;
   
zeroout(addr, len)
char *addr;
int len;
{
	while(--len>0) *addr++=0;
}

mklev()
{
	register unsigned tryct;

	tfile = lock;
	troom = NULL;
	doorindex = 0;
	nroom = 0;

	if(getbones()) return;
	ismklev = 1;
	if(dlevel < rn1(3, 26)) tspe[0] = 'a';   /* normal level */
	else tspe[0] = 'b';         /* maze */
	tspe[1] = 0;

	/* zap the object bases */
	{int i;extern int bases[];
	for(i=0;i<15;bases[i++]=0);}

	/* zap the room pictures */
	zeroout(levl,COLNO*ROWNO*sizeof(struct rm));

	fmon = NULL;
	fobj = NULL;
	fgold = ftrap = NULL;
   
	zeroout( doors, sizeof(coord)*DOORMAX);

	xdnstair = xupstair = ydnstair = yupstair = 0;
	zeroout(rooms, (MAXNROFROOMS+1)*sizeof(struct mkroom));

	init_objects();
	rooms[0].hx = -1;   /* in case we are in a maze */

	/* a: normal; b: maze */
	if(*tspe == 'b') {
		makemaz();
#ifdef DOSAVE
		{
		int fd;
		if((fd = creat(tfile,FMASK)) < 0) 
			panic("Cannot create %s\n", tfile);
		savelev(fd);
		close(fd);
		}
#endif
		ismklev = 0;
		return(0);
	}

	/* construct the rooms */
	while(nroom < (MAXNROFROOMS/3)) {
		croom = rooms;
		nroom = 0;
		(void) makerooms(0);      /* not secret */
	}

	/* for each room: put things inside */
	for(croom = rooms; croom->hx > 0; croom++) {

		/* put a sleeping monster inside */
		if(!rn2(3)) (void)
			makemon((struct permonst *) 0, somex(), somey());

		/* put traps and mimics inside */
		goldseen = FALSE;
		while(!rn2(8-(dlevel/6))) mktrap(0,0);
		if(!goldseen && !rn2(3)) mkgold(0,somex(),somey());
		if(!rn2(3)) {
			mkobj_at(0, somex(), somey());
			tryct = 0;
			while(!rn2(5)) {
				if(++tryct > 100){
					myprintf("tryct overflow4\n");
					break;
				}
				mkobj_at(0, somex(), somey());
			}
		}
	}
	tryct = 0;
	do {
		if(++tryct > 1000) panic("Cannot make dnstairs\n");
		croom = &rooms[rn2(nroom)];
		xdnstair = somex();
		ydnstair = somey();
	} while((*tspe =='n' && (!(xdnstair%2) || !(ydnstair%2))) ||
		g_at(xdnstair,ydnstair,ftrap));
	levl[xdnstair][ydnstair].scrsym ='>';
	levl[xdnstair][ydnstair].typ = STAIRS;
	troom = croom;
	do {
		if(++tryct > 2000) panic("Cannot make upstairs\n");
		croom = &rooms[rn2(nroom)];
		xupstair = somex();
		yupstair = somey();
	} while(croom == troom || m_at(xupstair,yupstair) ||
		g_at(xupstair,yupstair,ftrap));
	levl[xupstair][yupstair].scrsym ='<';
	levl[xupstair][yupstair].typ = STAIRS;

#ifdef DEBUG
	dumpit();
#endif
	qsort((char *) rooms, nroom, sizeof(struct mkroom), comp);
	makecorridors();
	make_niches();

	/* make a secret treasure vault, not connected to the rest */
	if(nroom < (2*MAXNROFROOMS/3)) if(!rn2(3)) {
		register int x,y;
		troom = croom = &rooms[nroom];
		if(makerooms(1)) {      /* make secret room */
			troom->rtype = 6;      /* treasure vault */
			for(x = troom->lx; x <= troom->hx; x++)
			for(y = troom->ly; y <= troom->hy; y++)
				mkgold(rnd(dlevel*100) + 50, x, y);
			if(!rn2(3))
				makevtele();
		}
	}

#ifdef WIZARD
	if(wizard){
		if(rn2(3)) mkshop(); else mkzoo();
	} else
#endif WIZARD
	if(dlevel > 1 && dlevel < 20 && rn2(dlevel) < 2)
		mkshop();
	else
		if(dlevel > 6 && !rn2(7) )
			mkzoo();
#ifdef DOSAVE
	{
	int fd;
	if((fd = creat(tfile,FMASK)) < 0) 
		panic("Cannot create %s\n", tfile);
	savelev(fd);
	close(fd);
	}
#endif
	ismklev = 0;
	return(0);
}

makerooms(secret)
int secret;
{
	register int lowx, lowy;
	register int tryct = 0;

   while(nroom < (MAXNROFROOMS/2) || secret)
      for(lowy = rn1(3,3); lowy < ROWNO-7; lowy += rn1(2,4))
         {
         for(lowx = rn1(3,4); lowx < COLNO-10; lowx += rn1(2,7))
            {
            if (tryct++ > 10000) return(0);

            if ((lowy += (rn2(5)-2)) < 3)
               lowy = 3;
            else
               if(lowy > ROWNO-6)
                  lowy = ROWNO-6;

            if(levl[lowx][lowy].typ) continue;

            if ((secret && maker(lowx, 1, lowy, 1)) ||
                (!secret && maker(lowx,rn1(9,2),lowy,rn1(4,2))
                && nroom+2 > MAXNROFROOMS)) return(1);
            }
         }
	return(1);
}

comp(x,y)
register struct mkroom *x,*y;
{
   if(x->lx < y->lx) return(-1);
   return(x->lx > y->lx);
}

coord
finddpos(xl,yl,xh,yh) {
coord ff;
register int x,y;
	ff.x = (xl == xh) ? xl : (xl + rn2(xh-xl+1));
	ff.y = (yl == yh) ? yl : (yl + rn2(yh-yl+1));
	if(okdoor(ff.x, ff.y)) return(ff);
	if(xl < xh) for(x = xl; x <= xh; x++)
		if(okdoor(x, ff.y)){
			ff.x = x;
			return(ff);
		}
	if(yl < yh) for(y = yl; y <= yh; y++)
		if(okdoor(ff.x, y)){
			ff.y = y;
			return(ff);
		}
	return(ff);
}

/* if allowable, create a door at [x,y] */
okdoor(x,y)
register int x,y;
{
	if(levl[x-1][y].typ == DOOR || levl[x+1][y].typ == DOOR ||
	   levl[x][y+1].typ == DOOR || levl[x][y-1].typ == DOOR ||
	   levl[x-1][y].typ == SDOOR || levl[x+1][y].typ == SDOOR ||
	   levl[x][y-1].typ == SDOOR || levl[x][y+1].typ == SDOOR ||
	   (levl[x][y].typ != HWALL && levl[x][y].typ != VWALL) ||
	   doorindex >= DOORMAX)
		return(0);
	return(1);
}

dodoor(x,y,aroom)
register int x,y;
register struct mkroom *aroom;
{
	if(doorindex >= DOORMAX) panic("DOORMAX exceeded?");
	if(!okdoor(x,y) && nxcor) return;
	dosdoor(x,y,aroom,rn2(8) ? DOOR : SDOOR);
}

dosdoor(x,y,aroom,type)
register int x,y;
register struct mkroom *aroom;
register int type;
{
	register struct mkroom *broom;
	register int tmp;

	levl[x][y].typ = type;
	if(type == DOOR)
		levl[x][y].scrsym ='+';
	aroom->doorct++;
	broom = aroom+1;
	if(broom->hx < 0) tmp = doorindex; else
	for(tmp = doorindex; tmp > broom->fdoor; tmp--)
		doors[tmp] = doors[tmp-1];
	doorindex++;
	doors[tmp].x = x;
	doors[tmp].y = y;
	for( ; broom->hx >= 0; broom++) broom->fdoor++;
}

/* Only called from makerooms() */
maker(lowx,ddx,lowy,ddy)
schar lowx,ddx,lowy,ddy;
{
	register int x, y, hix = lowx+ddx, hiy = lowy+ddy;

	if(nroom >= MAXNROFROOMS) return(0);
	if(hix > COLNO-5) hix = COLNO-5;
	if(hiy > ROWNO-4) hiy = ROWNO-4;
chk:
	if(hix <= lowx || hiy <= lowy) return(0);

	/* check area around room (and make room smaller if necessary) */
	for(x = lowx-4; x <= hix+4; x++)
		for(y = lowy-3; y <= hiy+3; y++)
			if(levl[x][y].typ) {
				if(rn2(3)) return(0);
				lowx = x+5;
				lowy = y+4;
				goto chk;
			}

	/* on low levels the room is lit (usually) */
	/* secret vaults are always lit */
	if((rnd(dlevel) < 10 && rn2(77)) || (ddx == 1 && ddy == 1))
		for(x = lowx-1; x <= hix+1; x++)
			for(y = lowy-1; y <= hiy+1; y++)
				levl[x][y].lit = 1;
	croom->lx = lowx;
	croom->hx = hix;
	croom->ly = lowy;
	croom->hy = hiy;
	croom->rtype = croom->doorct = croom->fdoor = 0;
	for(x = lowx-1; x <= hix+1; x++)
	    for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
		levl[x][y].scrsym = '-';
		levl[x][y].typ = HWALL;
	}
	for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
	    for(y = lowy; y <= hiy; y++) {
		levl[x][y].scrsym = '|';
		levl[x][y].typ = VWALL;
	}
	for(x = lowx; x <= hix; x++)
	    for(y = lowy; y <= hiy; y++) {
		levl[x][y].scrsym = '.';
		levl[x][y].typ = ROOM;
	}
	croom++;
	croom->hx = -1;
	smeq[nroom] = nroom;
	nroom++;
	return(1);
}

makecorridors() {
	register int a,b;

	nxcor = 0;
	for(a = 0; a < nroom-1; a++)
		join(a, a+1);
	for(a = 0; a < nroom-2; a++)
	    if(smeq[a] != smeq[a+2])
		join(a, a+2);
	for(a = 0; a < nroom; a++)
	    for(b = 0; b < nroom; b++)
		if(smeq[a] != smeq[b])
		    join(a, b);
	if(nroom > 2)
	    for(nxcor = rn2(nroom) + 4; nxcor; nxcor--) {
		a = rn2(nroom);
		b = rn2(nroom-2);
		if(b >= a) b += 2;
		join(a, b);
	    }
}

join(a,b)
register int a,b;
{
	coord cc,tt;
	register int tx, ty, xx, yy;
	register struct rm *crm;
	register int dx, dy, dix, diy, cct;

	croom = &rooms[a];
	troom = &rooms[b];

	/* find positions cc and tt for doors in croom and troom
	   and direction for a corridor between them */

   if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return;
   if(troom->lx > croom->hx) {
      dx = 1;
      dy = 0;
      xx = croom->hx+1;
      tx = troom->lx-1;
      cc = finddpos(xx,croom->ly,xx,croom->hy);
      tt = finddpos(tx,troom->ly,tx,troom->hy);
   } else if(troom->hy < croom->ly) {
      dy = -1;
      dx = 0;
      yy = croom->ly-1;
      cc = finddpos(croom->lx,yy,croom->hx,yy);
      ty = troom->hy+1;
      tt = finddpos(troom->lx,ty,troom->hx,ty);
   } else if(troom->hx < croom->lx) {
      dx = -1;
      dy = 0;
      xx = croom->lx-1;
      tx = troom->hx+1;
      cc = finddpos(xx,croom->ly,xx,croom->hy);
      tt = finddpos(tx,troom->ly,tx,troom->hy);
   } else {
      dy = 1;
      dx = 0;
      yy = croom->hy+1;
      ty = troom->ly-1;
      cc = finddpos(croom->lx,yy,croom->hx,yy);
      tt = finddpos(troom->lx,ty,troom->hx,ty);
   }
	xx = cc.x;
	yy = cc.y;
	tx = tt.x - dx;
	ty = tt.y - dy;
	if(nxcor && levl[xx+dx][yy+dy].typ)
		return;
	dodoor(xx,yy,croom);

	cct = 0;
	while(xx != tx || yy != ty) {
	    xx += dx;
	    yy += dy;

	    /* loop: dig corridor at [xx,yy] and find new [xx,yy] */
	    if(cct++ > 500 || (nxcor && !rn2(35)))
		return;

	    if(xx == COLNO-1 || xx == 0 || yy == 0 || yy == ROWNO-1)
		return;		/* impossible */

	    crm = &levl[xx][yy];
	    if(!(crm->typ)) {
		if(rn2(100)) {
			crm->typ = CORR;
			crm->scrsym = CORR_SYM;
		} else {
			crm->typ = SCORR;
			crm->scrsym = ' ';
		}
		if(nxcor && !rn2(50)) {
			mkobj_at(ROCK_SYM, xx, yy);
		}
	    } else
	    if(crm->typ != CORR && crm->typ != SCORR) {
		/* strange ... */
      return;
	    }

	    /* find next corridor position */
	    dix = abs(xx-tx);
	    diy = abs(yy-ty);

	    /* do we have to change direction ? */
	    if(dy && dix > diy) {
		register int ddx = (xx > tx) ? -1 : 1;

		crm = &levl[xx+ddx][yy];
		if(!crm->typ || crm->typ == CORR || crm->typ == SCORR) {
		    dx = ddx;
		    dy = 0;
		    continue;
		}
	    } else if(dx && diy > dix) {
		register int ddy = (yy > ty) ? -1 : 1;

		crm = &levl[xx][yy+ddy];
		if(!crm->typ || crm->typ == CORR || crm->typ == SCORR) {
		    dy = ddy;
		    dx = 0;
		    continue;
		}
	    }

	    /* continue straight on? */
	    crm = &levl[xx+dx][yy+dy];
	    if(!crm->typ || crm->typ == CORR || crm->typ == SCORR)
		continue;

	    /* no, what must we do now?? */
	    if(dx) {
		dx = 0;
		dy = (ty < yy) ? -1 : 1;
		crm = &levl[xx+dx][yy+dy];
		if(!crm->typ || crm->typ == CORR || crm->typ == SCORR)
		    continue;
		dy = -dy;
		continue;
	    } else {
		dy = 0;
		dx = (tx < xx) ? -1 : 1;
		crm = &levl[xx+dx][yy+dy];
		if(!crm->typ || crm->typ == CORR || crm->typ == SCORR)
		    continue;
		dx = -dx;
		continue;
	    }
   }
	/* we succeeded in digging the corridor */
	dodoor(tt.x, tt.y, troom);

	if(smeq[a] < smeq[b])
		smeq[b] = smeq[a];
	else
		smeq[a] = smeq[b];
}

make_niches()
{
	register int ct = rn2(nroom/2 + 1)+1;
	while(ct--) makeniche(FALSE);
}

makevtele()
{
	makeniche(TRUE);
}

makeniche(with_trap)
boolean with_trap;
{
	register struct mkroom *aroom;
	register struct rm *rm;
	register int vct = 8;
	coord dd;
	register int dy,xx,yy;
	register struct gen *gtmp;

	if(doorindex < DOORMAX)
	  while(vct--) {
	    aroom = &rooms[rn2(nroom-1)];
	    if(aroom->rtype != 0) continue;	/* not an ordinary room */
	    if(rn2(2)) {
		dy = 1;
		dd = finddpos(aroom->lx,aroom->hy+1,aroom->hx,aroom->hy+1);
	    } else {
		dy = -1;
		dd = finddpos(aroom->lx,aroom->ly-1,aroom->hx,aroom->ly-1);
	    }
	    xx = dd.x;
	    yy = dd.y;
	    if((rm = &levl[xx][yy+dy])->typ) continue;
	    if(with_trap || !rn2(4)) {
		rm->typ = SCORR;
		rm->scrsym = ' ';
		if(with_trap) {
		    gtmp = newgen();
		    gtmp->gx = xx;
		    gtmp->gy = yy+dy;
		    gtmp->gflag = TELEP_TRAP | ONCE;
		    gtmp->ngen = ftrap;
		    ftrap = gtmp;
		    make_engr_at(xx,yy-dy,"ad ae?ar um");
		}
		dosdoor(xx,yy,aroom,SDOOR);
	    } else {
		rm->typ = CORR;
		rm->scrsym = CORR_SYM;
		if(rn2(7))
		    dosdoor(xx,yy,aroom,rn2(5) ? SDOOR : DOOR);
		else {
		    mksobj_at(SCROLL_SYM,SCR_TELEPORTATION,xx,yy+dy);
		    if(!rn2(3)) mkobj_at(0,xx,yy+dy);
		}
	    }
	    return;
      }
}

/* make a trap somewhere (in croom if mazeflag = 0) */
mktrap(num,mazeflag)
register int num,mazeflag;
{
	register struct gen *gtmp;
	register int kind,nopierc,nomimic,fakedoor,fakegold,tryct = 0;
	register xchar mx,my;


   if(!num || num >= TRAPNUM) {
      nopierc = (dlevel < 4) ? 1 : 0;
      nomimic = (dlevel < 9 || goldseen ) ? 1 : 0;
      if(index(fut_geno, 'M')) nomimic = 1;
      kind = rn2(TRAPNUM - nopierc - nomimic);
      /* note: PIERC = 7, MIMIC = 8, TRAPNUM = 9 */
   } else kind = num;

   if(kind == MIMIC) {
		register struct monst *mtmp;

      fakedoor = (!rn2(3) && !mazeflag);
      fakegold = (!fakedoor && !rn2(2));
      if(fakegold) goldseen = TRUE;
      do {
         if(++tryct > 200) return;
         if(fakedoor) {
            /* note: fakedoor maybe on actual door */
            if(rn2(2)){
               if(rn2(2))
                  mx = croom->hx+1;
               else mx = croom->lx-1;
               my = somey();
            } else {
               if(rn2(2))
                  my = croom->hy+1;
               else my = croom->ly-1;
               mx = somex();
            }
         } else if(mazeflag) {
            extern coord mazexy();
            coord mm;
            mm = mazexy();
            mx = mm.x;
            my = mm.y;
         } else {
            mx = somex();
            my = somey();
         }
      } while(m_at(mx,my));
      if(mtmp = makemon(PM_MIMIC,mx,my))
          mtmp->mimic =
         fakegold ? '$' : fakedoor ? '+' :
         (mazeflag && rn2(2)) ? AMULET_SYM :
         "=/)%?![<>" [ rn2(9) ];
      return;
   }
   gtmp = newgen();
   gtmp->gflag = kind;
   do {
      if(++tryct > 200){
         free((char *) gtmp);
         return;
      }
      if(mazeflag){
         extern coord mazexy();
         coord mm;
         mm = mazexy();
         gtmp->gx = mm.x;
         gtmp->gy = mm.y;
      } else {
         gtmp->gx = somex();
         gtmp->gy = somey();
      }
   } while(g_at(gtmp->gx, gtmp->gy, ftrap));
   gtmp->ngen = ftrap;
   ftrap = gtmp;
   if(mazeflag && !rn2(10) && gtmp->gflag < PIERC) gtmp->gflag |= SEEN;
}

#ifdef DEBUG
dumpit()
   {
   int x, y;
   struct rm *room;

   cgetret(); 

   /* kludge in making everything visible */
   for(y=0; y < ROWNO; y++)
      for(x=0; x < COLNO-3; x++)
         if ( (room = &levl[x][y])->typ)
            at(x,y, (room->scrsym) ? room->scrsym : '?');
   }
#endif
#file mklv.makemaz.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include "mklev.h"
extern struct monst *makemon();
extern coord mazexy();

makemaz()
{
	int x,y;
	register int zx,zy;
	coord mm;

	for(x = 2; x < COLNO-1; x++)
		for(y = 2; y < ROWNO-1; y++)
			levl[x][y].typ = (x%2 && y%2) ? 0 : HWALL;
	mm = mazexy();
	zx = mm.x;
	zy = mm.y;
	walkfrom(zx,zy);
	mkobj_at(AMULET_SYM, zx, zy);
	mkobj_at(ROCK_SYM, zx, zy);	/* put a rock on top of the amulet */
	/* (probably this means that one needs a wand of digging to reach 
	    the amulet - we must make sure that the player has a chance of
	    getting one; let us say when he kills the minotaur; of course
	    the minotaur itself may be blocked behind rocks, but well...) */
	for(x = 2; x < COLNO-1; x++)
		for(y = 2; y < ROWNO-1; y++) {
			switch(levl[x][y].typ) {
			case HWALL:
				levl[x][y].scrsym = '-';
				break;
			case ROOM:
				levl[x][y].scrsym = '.';
				break;
			}
		}
	for(x = rn1(8,11); x; x--) {
		mm = mazexy();
		mkobj_at(0, mm.x, mm.y);
	}
	for(x = rn1(10,2); x; x--) {
		mm = mazexy();
		mkobj_at(ROCK_SYM, mm.x, mm.y);
	}
	mm = mazexy();
	(void) makemon(PM_MINOTAUR, mm.x, mm.y);
	for(x = rn1(5,7); x; x--) {
		mm = mazexy();
		(void) makemon((struct permonst *) 0, mm.x, mm.y);
	}
	for(x = rn1(6,7); x; x--) {
		mm = mazexy();
		mkgold(0,mm.x,mm.y);
	}
	for(x = rn1(6,7); x; x--)
		mktrap(0,1);
	mm = mazexy();
	levl[(xupstair = mm.x)][(yupstair = mm.y)].scrsym = '<';
	levl[xupstair][yupstair].typ = STAIRS;
	xdnstair = ydnstair = 0;
}

walkfrom(x,y) int x,y; {
register int q,a,dir;
int dirs[4];
	levl[x][y].typ = ROOM;
	while(1) {
		q = 0;
		for(a = 0; a < 4; a++)
			if(okay(x,y,a)) dirs[q++]= a;
		if(!q) return;
		dir = dirs[rn2(q)];
		move(&x,&y,dir);
		levl[x][y].typ = ROOM;
		move(&x,&y,dir);
		walkfrom(x,y);
	}
}

move(x,y,dir)
register int *x, *y;
register int dir;
{
	switch(dir){
		case 0: --(*y); break;
		case 1: (*x)++; break;
		case 2: (*y)++; break;
		case 3: --(*x); break;
	}
}

okay(x,y,dir)
int x,y;
register int dir;
{
	move(&x,&y,dir);
	move(&x,&y,dir);
	if(x<3 || y<3 || x>COLNO-3 || y>ROWNO-3 || levl[x][y].typ != 0)
		return(0);
	else
		return(1);
}

coord
mazexy(){
	coord mm;
	mm.x = 3 + 2*rn2(COLNO/2 - 2);
	mm.y = 3 + 2*rn2(ROWNO/2 - 2);
	return mm;
}
#file mklv.shk.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#ifndef QUEST
#include "mklev.h"
#include "def.eshk.h"
#define   ESHK   ((struct eshk *)(&(shk->mextra[0])))
extern struct monst *makemon();

extern char shtypes[]; /* = "=/)%?!["; ** 8 shoptypes: 7 specialised, 1 mixed */
schar shprobs[] = { 3,3,5,5,10,10,14,50 };   /* their probabilities */

mkshop(){
register struct mkroom *sroom;
register int sh,sx,sy,i;
register char let;
int roomno;
register struct monst *shk;
   for(sroom = &rooms[0], roomno = 0; ; sroom++, roomno++){
      if(sroom->hx < 0) return;
      if(sroom->lx <= xdnstair && xdnstair <= sroom->hx &&
         sroom->ly <= ydnstair && ydnstair <= sroom->hy) continue;
      if(sroom->lx <= xupstair && xupstair <= sroom->hx &&
         sroom->ly <= yupstair && yupstair <= sroom->hy) continue;
      if(
#ifdef WIZARD
         wizard ||
#endif WIZARD
         sroom->doorct == 1) break;
   }
#ifdef WIZARD
   if(wizard){
      extern char *getenv();
      register char *ep = getenv("SHOPTYPE");
      if(ep){
         if(*ep == 'z' || *ep == 'Z'){
            mkzoo();
            return;
         }
         for(i=0; shtypes[i]; i++)
            if(*ep == shtypes[i]) break;
         let = i;
         goto gotlet;
      }
   }
#endif WIZARD
   for(i = rn2(100),let = 0; (i -= shprobs[let])>= 0; let++)
      if(!shtypes[let]) break;   /* superfluous */
#ifdef WIZARD
gotlet:
#endif WIZARD
   sroom->rtype = 8+let;
   let = shtypes[let];
   sh = sroom->fdoor;
   sx = doors[sh].x;
   sy = doors[sh].y;
   if(sx == sroom->lx-1) sx++; else
   if(sx == sroom->hx+1) sx--; else
   if(sy == sroom->ly-1) sy++; else
   if(sy == sroom->hy+1) sy--; else {
      myprintf("Where is shopdoor?");
      return;
   }
   if(!(shk = makemon(PM_SHK,sx,sy))) return;
   shk->isshk = shk->mpeaceful = 1;
   shk->msleep = 0;
   shk->mtrapseen = ~0;   /* we know all the traps already */
   ESHK->shoproom = roomno;
   ESHK->shd = doors[sh];
   ESHK->shk.x = sx;
   ESHK->shk.y = sy;
   ESHK->robbed = 0;
   ESHK->visitct = 0;
   shk->mgold = 1000 + 30*rnd(100);   /* initial capital */
   ESHK->billct = 0;
   findname(ESHK->shknam, let);
   for(sx = sroom->lx; sx <= sroom->hx; sx++)
   for(sy = sroom->ly; sy <= sroom->hy; sy++){
      register struct monst *mtmp;
      if((sx == sroom->lx && doors[sh].x == sx-1) ||
         (sx == sroom->hx && doors[sh].x == sx+1) ||
         (sy == sroom->ly && doors[sh].y == sy-1) ||
         (sy == sroom->hy && doors[sh].y == sy+1)) continue;
      if(rn2(100) < dlevel && !m_at(sx,sy) &&
         (mtmp = makemon(PM_MIMIC, sx, sy))){
         mtmp->mimic =
             (let && rn2(10) < dlevel) ? let : ']';
         continue;
      }
      mkobj_at(let, sx, sy);
   }
#ifdef WIZARD
   if(wizard) myprintf("I made a %c-shop.", let ? let : 'g');
#endif WIZARD
}

mkzoo(){
register struct mkroom *sroom;
register int sh,sx,sy,i;
int goldlim = 500 * dlevel;
   for(sroom = &rooms[0]; ; sroom++){
      if(sroom->hx < 0) return;
      if(sroom->lx <= xdnstair && xdnstair <= sroom->hx &&
         sroom->ly <= ydnstair && ydnstair <= sroom->hy) continue;
      if(sroom->lx <= xupstair && xupstair <= sroom->hx &&
         sroom->ly <= yupstair && yupstair <= sroom->hy) continue;
      if(sroom->doorct == 1) break;
   }
   sroom->rtype = 7;
   sh = sroom->fdoor;
   for(sx = sroom->lx; sx <= sroom->hx; sx++)
   for(sy = sroom->ly; sy <= sroom->hy; sy++){
      if((sx == sroom->lx && doors[sh].x == sx-1) ||
         (sx == sroom->hx && doors[sh].x == sx+1) ||
         (sy == sroom->ly && doors[sh].y == sy-1) ||
         (sy == sroom->hy && doors[sh].y == sy+1)) continue;
      (void) makemon((struct permonst *) 0,sx,sy);
      i = sq(dist2(sx,sy,doors[sh].x,doors[sh].y));
      if(i >= goldlim) i = 5*dlevel;
      goldlim -= i;
      mkgold(10 + rn2(i), sx, sy);
   }
#ifdef WIZARD
   if(wizard) myprintf("I made a zoo.");
#endif WIZARD
}

dist2(x0,y0,x1,y1){
   return((x0-x1)*(x0-x1) + (y0-y1)*(y0-y1));
}

sq(a) int a; {
   return(a*a);
}
#endif QUEST
#file mklv.shknam.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */



#include "mklev.h"



char *shkliquors[] = {

	/* Ukraine */

	"Njezjin", "Tsjernigof", "Gomel", "Ossipewsk", "Gorlowka",

	/* N. Russia */

	"Konosja", "Weliki Oestjoeg", "Syktywkar", "Sablja",

	"Narodnaja", "Kyzyl",

	/* Silezie */

	"Walbrzych", "Swidnica", "Klodzko", "Raciborz", "Gliwice",

	"Brzeg", "Krnov", "Hradec Kralove",

	/* Schweiz */

	"Leuk", "Brig", "Brienz", "Thun", "Sarnen", "Burglen", "Elm",

	"Flims", "Vals", "Schuls", "Zum Loch",

	0

};



char *shkbooks[] = {

	/* Eire */

	"Skibbereen", "Kanturk", "Rath Luirc", "Ennistymon", "Lahinch",

	"Loughrea", "Croagh", "Maumakeogh", "Ballyjamesduff",

	"Kinnegad", "Lugnaquillia", "Enniscorthy", "Gweebarra",

	"Kittamagh", "Nenagh", "Sneem", "Ballingeary", "Kilgarvan",

	"Cahersiveen", "Glenbeigh", "Kilmihil", "Kiltamagh",

	"Droichead Atha", "Inniscrone", "Clonegal", "Lisnaskea",

	"Culdaff", "Dunfanaghy", "Inishbofin", "Kesh",

	0

};



char *shkarmors[] = {

	/* Turquie */

	"Demirci", "Kalecik", "Boyabai", "Yildizeli", "Gaziantep",

	"Siirt", "Akhalataki", "Tirebolu", "Aksaray", "Ermenak",

	"Iskenderun", "Kadirli", "Siverek", "Pervari", "Malasgirt",

	"Bayburt", "Ayancik", "Zonguldak", "Balya", "Tefenni",

	"Artvin", "Kars", "Makharadze", "Malazgirt", "Midyat",

	"Birecik", "Kirikkale", "Alaca", "Polatli", "Nallihan",

	0

};



char *shkwands[] = {

	/* Wales */

	"Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach",

	"Rhaeader", "Llandrindod", "Llanfair-ym-muallt",

	"Y-Fenni", "Measteg", "Rhydaman", "Beddgelert",

	"Curig", "Llanrwst", "Llanerchymedd", "Caergybi",

	/* Scotland */

	"Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar",

	"Kerloch", "Beinn a Ghlo", "Drumnadrochit", "Morven",

	"Uist", "Storr", "Sgurr na Ciche", "Cannich", "Gairloch",

	"Kyleakin", "Dunvegan",

	0

};



char *shkrings[] = {

	/* Hollandse familienamen */

	"Feyfer", "Flugi", "Gheel", "Havic", "Haynin", "Hoboken",

	"Imbyze", "Juyn", "Kinsky", "Massis", "Matray", "Moy",

	"Olycan", "Sadelin", "Svaving", "Tapper", "Terwen", "Wirix",

	"Ypey",

	/* Skandinaviske navne */

	"Rastegaisa", "Varjag Njarga", "Kautekeino", "Abisko",

	"Enontekis", "Rovaniemi", "Avasaksa", "Haparanda",

	"Lulea", "Gellivare", "Oeloe", "Kajaani", "Fauske",

	0

};



char *shkfoods[] = {

	/* Indonesia */

	"Djasinga", "Tjibarusa", "Tjiwidej", "Pengalengan",

	"Bandjar", "Parbalingga", "Bojolali", "Sarangan",

	"Ngebel", "Djombang", "Ardjawinangun", "Berbek",

	"Papar", "Baliga", "Tjisolok", "Siboga", "Banjoewangi",

	"Trenggalek", "Karangkobar", "Njalindoeng", "Pasawahan",

	"Pameunpeuk", "Patjitan", "Kediri", "Pemboeang", "Tringanoe",

	"Makin", "Tipor", "Semai", "Berhala", "Tegal", "Samoe",

	0

};



char *shkweapons[] = {

	/* Perigord */

	"Voulgezac", "Rouffiac", "Lerignac", "Touverac", "Guizengeard",

	"Melac", "Neuvicq", "Vanzac", "Picq", "Urignac", "Corignac",

	"Fleac", "Lonzac", "Vergt", "Queyssac", "Liorac", "Echourgnac",

	"Cazelon", "Eypau", "Carignan", "Monbazillac", "Jonzac",

	"Pons", "Jumilhac", "Fenouilledes", "Laguiolet", "Saujon",

	"Eymoutiers", "Eygurande", "Eauze", "Labouheyre",

	0

};



char *shkgeneral[] = {

	/* Suriname */

	"Hebiwerie", "Possogroenoe", "Asidonhopo", "Manlobbi",

	"Adjama", "Pakka Pakka", "Kabalebo", "Wonotobo",

	"Akalapi", "Sipaliwini",

	/* Greenland */

	"Annootok", "Upernavik", "Angmagssalik",

	/* N. Canada */

	"Aklavik", "Inuvik", "Tuktoyaktuk",

	"Chicoutimi", "Ouiatchouane", "Chibougamau",

	"Matagami", "Kipawa", "Kinojevis",

	"Abitibi", "Maganasipi",

	/* Iceland */

	"Akureyri", "Kopasker", "Budereyri", "Akranes", "Bordeyri",

	"Holmavik",

	0

};



struct shk_nx {

	char x;

	char **xn;

} shk_nx[] = {

	{ POTION_SYM,	shkliquors },

	{ SCROLL_SYM,	shkbooks },

	{ ARMOR_SYM,	shkarmors },

	{ WAND_SYM,	shkwands },

	{ RING_SYM,	shkrings },

	{ FOOD_SYM,	shkfoods },

	{ WEAPON_SYM,	shkweapons },

	{ 0,		shkgeneral }

};



findname(nampt, let) char *nampt; char let; {

register struct shk_nx *p = shk_nx;

register char **q;

register int i;

	while(p->x && p->x != let) p++;

	q = p->xn;

	for(i=0; i<dlevel; i++) if(!q[i]){

		/* Not enough names, try general name */

		if(let) findname(nampt, 0);

		else (void) strcpy(nampt, "Dirk");

		return;

	}

	(void) strncpy(nampt, q[i], PL_NSIZ);

	nampt[PL_NSIZ-1] = 0;

}

#file rnd.c
#define RND(x)	((rand()>>3) % x)

rn1(x,y)
register int x,y;
{
	return(RND(x)+y);
}

rn2(x)
register int x;
{
	return(RND(x));
}

rnd(x)
register int x;
{
	return(RND(x)+1);
}

d(n,x)
register int n,x;
{
	register int tmp = n;

	while(n--) tmp += RND(x);
	return(tmp);
}
#file savelev.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* savelev.h version 1.0.1 - also save engravings from MKLEV */

#include "hack.h"
#include <stdio.h>
extern struct monst *restmonchn();
extern struct obj *restobjchn();
extern struct obj *billobjs;
extern char *itoa();

extern char nul[];
#ifndef NOWORM
#include	"def.wseg.h"

extern struct wseg *wsegs[32], *wheads[32];
extern long wgrowtime[32];
#endif NOWORM

savelev(fd){
#ifndef NOWORM
	register struct wseg *wtmp, *wtmp2;
	register int tmp;
#endif NOWORM

	if(fd < 0)
           panic("Save on bad file!");

	bwrite(fd,(char *) levl,sizeof(levl));
	bwrite(fd,(char *) &moves,sizeof(long));
	bwrite(fd,(char *) &xupstair,sizeof(xupstair));
	bwrite(fd,(char *) &yupstair,sizeof(yupstair));
	bwrite(fd,(char *) &xdnstair,sizeof(xdnstair));
	bwrite(fd,(char *) &ydnstair,sizeof(ydnstair));
	savemonchn(fd, fmon);
	savegenchn(fd, fgold);
	savegenchn(fd, ftrap);
	saveobjchn(fd, fobj);
	saveobjchn(fd, billobjs);
/*	if (!ismklev) */
	   billobjs = 0;
	save_engravings(fd);
#ifndef QUEST
	bwrite(fd,(char *) rooms,sizeof(rooms));
	bwrite(fd,(char *) doors,sizeof(doors));
#endif QUEST
/* 	if (!ismklev) */
	   {
	   fgold = ftrap = 0;
	   fmon = 0;
	   fobj = 0;
	   }
/*--------------------------------------------------------------------*/
#ifndef NOWORM
	bwrite(fd,(char *) wsegs,sizeof(wsegs));
	for(tmp=1; tmp<32; tmp++){
		for(wtmp = wsegs[tmp]; wtmp; wtmp = wtmp2){
			wtmp2 = wtmp->nseg;
			bwrite(fd,(char *) wtmp,sizeof(struct wseg));
		}
/*		if (!ismklev) */
		   wsegs[tmp] = 0;
	}
	bwrite(fd,(char *) wgrowtime,sizeof(wgrowtime));
#endif NOWORM
/*--------------------------------------------------------------------*/
}

bwrite(fd,loc,num)
register int fd;
register char *loc;
register unsigned num;
{
/* lint wants the 3rd arg of write to be an int; lint -p an unsigned */
	if(write(fd, loc, (int) num) != num)
		panic("cannot write %d bytes to file #%d",num,fd);
}

saveobjchn(fd,otmp)
register int fd;
register struct obj *otmp;
{
	register struct obj *otmp2;
	unsigned xl;
	int minusone = -1;

	while(otmp) {
		otmp2 = otmp->nobj;
		xl = otmp->onamelth;
		bwrite(fd, (char *) &xl, sizeof(int));
		bwrite(fd, (char *) otmp, xl + sizeof(struct obj));
/*		if (!ismklev) */
			free((char *) otmp);
		otmp = otmp2;
	}
	bwrite(fd, (char *) &minusone, sizeof(int));
}

savemonchn(fd,mtmp)
register int fd;
register struct monst *mtmp;
{
	register struct monst *mtmp2;
	unsigned xl;
	int minusone = -1;
	int monnum;
#ifdef FUNNYRELOC
	struct permonst *monbegin = &mons[0];

	bwrite(fd, (char *) &monbegin, sizeof(monbegin));
#endif

	while(mtmp) {
		mtmp2 = mtmp->nmon;
		xl = mtmp->mxlth + mtmp->mnamelth;
		bwrite(fd, (char *) &xl, sizeof(int));

		/* JAT - just save the offset into the monster table, */
		/* it will be relocated when read in */
		monnum = mtmp->data - &mons[0];
		mtmp->data = (struct permonst *)monnum;
#ifdef DEBUGMON
		myprintf("Wrote monster #%d", monnum);
#endif
		bwrite(fd, (char *) mtmp, xl + sizeof(struct monst));
		if(mtmp->minvent) saveobjchn(fd,mtmp->minvent);
/*		if (!ismklev) */
		   free((char *) mtmp);
		mtmp = mtmp2;
	}
	bwrite(fd, (char *) &minusone, sizeof(int));
}

savegenchn(fd,gtmp)
register int fd;
register struct gen *gtmp;
{
	register struct gen *gtmp2;
	while(gtmp) {
		gtmp2 = gtmp->ngen;
		bwrite(fd, (char *) gtmp, sizeof(struct gen));
/*		if (!ismklev) */
		   free((char *) gtmp);
		gtmp = gtmp2;
	}
	bwrite(fd, nul, sizeof(struct gen));
}

jcz@ncsu.UUCP (John A. Toebes, VIII) (02/22/86)

#file def.arrows.h
unsigned long UPdata[] = {
0x00000000,
0x00780000,
0x01FE0000,
0x07FF8000,
0x00780000,
0x00780000,
0x00780000,
0x00780000,
0x00780000,
0x00000000,

0xFFFFFC00,
0xFFE7FC00,
0xFFF9FC00,
0xFFFE7C00,
0xFFF7FC00,
0xFFF7FC00,
0xFFF7FC00,
0xFFF7FC00,
0xFFF7FC00,
0xFFFFFC00 };

unsigned long DOWNdata[] = {
0x00000000,
0x00780000,
0x00780000,
0x00780000,
0x00780000,
0x00780000,
0x07FF8000,
0x01FE0000,
0x00780000,
0x00000000,

0xFFFFFC00,
0xFF87FC00,
0xFFF7FC00,
0xFFF7FC00,
0xFFF7FC00,
0xFFF7FC00,
0xFFF07C00,
0xFFFFFC00,
0xFFFFFC00,
0xFFFFFC00 };

unsigned long RIGHTdata[] = {
0x00000000,
0x00000000,
0x00070000,
0x0007C000,
0x3FFFF000,
0x3FFFF000,
0x0007C000,
0x00070000,
0x00000000,
0x00000000,

0xFFFFFC00,
0xFFFFFC00,
0xFFF8FC00,
0xFFFF3C00,
0xC00FCC00,
0xFFFFEC00,
0xFFFFFC00,
0xFFFFFC00,
0xFFFFFC00,
0xFFFFFC00 };

unsigned long LEFTdata[] = {
0x00000000,
0x00000000,
0x03800000,
0x0F800000,
0x3FFFF000,
0x3FFFF000,
0x0F800000,
0x03800000,
0x00000000,
0x00000000,

0xFFFFFC00,
0xFFFFFC00,
0xFE7FFC00,
0xFF7FFC00,
0xFF000C00,
0xFFFFEC00,
0xFFFFFC00,
0xFFFFFC00,
0xFFFFFC00,
0xFFFFFC00 };

unsigned long UPLEFTdata[] = {
0x00000000,
0x1FF80000,
0x1FE00000,
0x1FE00000,
0x1FF80000,
0x187E0000,
0x001F8000,
0x0007E000,
0x00018000,
0x00000000,

0xFFFFFC00,
0xE007FC00,
0xFFDFFC00,
0xFFDFFC00,
0xFFE7FC00,
0xFFF9FC00,
0xFFFE7C00,
0xFFFF9C00,
0xFFFFFC00,
0xFFFFFC00 };

unsigned long UPRIGHTdata[] = {
0x00000000,
0x007FE000,
0x001FE000,
0x001FE000,
0x007FE000,
0x01F86000,
0x07E00000,
0x1F800000,
0x06000000,
0x00000000,

0xFFFFFC00,
0xFF801C00,
0xFFFF9C00,
0xFFFF9C00,
0xFFFF9C00,
0xFFFF9C00,
0xFFFFFC00,
0xFFFFFC00,
0xFFFFFC00,
0xFFFFFC00 };

unsigned long DOWNLEFTdata[] = {
0x00000000,
0x00018000,
0x0007E000,
0x001F8000,
0x187E0000,
0x1FF80000,
0x1FE00000,
0x1FE00000,
0x1FF80000,
0x00000000,

0xFFFFFC00,
0xFFFE7C00,
0xFFFF9C00,
0xFFFFFC00,
0xE7FFFC00,
0xF9FFFC00,
0xFFFFFC00,
0xFF9FFC00,
0xFFE7FC00,
0xFFFFFC00 };

unsigned long DOWNRIGHTdata[] = {
0x00000000,
0x06000000,
0x1F800000,
0x07E00000,
0x01F86000,
0x007FE000,
0x001FE000,
0x0007E000,
0x001FE000,
0x00000000,

0xFFFFFC00,
0xF9FFFC00,
0xFE7FFC00,
0xFF9FFC00,
0xFFE79C00,
0xFFF8DC00,
0xFFFFDC00,
0xFFFFDC00,
0xFFFFDC00,
0xFFFFFC00 };
#file def.menus.h
#define TEXT(nam,str) struct IntuiText nam = {0,1,JAM2,0,0,NULL,str,NULL}
	/* Commands */
	TEXT(T_HELP,  "?   display help");
	TEXT(T_o,     "o   set options");
	TEXT(T_SHELL, "!   AMIGADOS commands");
	TEXT(T_v,     "v   version number");
	TEXT(T_CR,    "^R   redraw screen");
	TEXT(T_CP,    "^P   repeat last message");
	TEXT(T_Q,     "Q   quit game");
	TEXT(T_S,     "S   save the game");

	/* Inventory */
	TEXT(T_i,     "i   inventory");
	TEXT(T_p,     "p   pay your bill");
	TEXT(T_d,     "d   drop an object");
	TEXT(T_D,     "D   Drop several things");
	TEXT(T_COMMA, ",   Pickup an object");
	TEXT(T_SLASH, "/   identify something");
	TEXT(T_c,     "c   call class of objects");
	TEXT(T_C,     "C   Christen a monster");

	/* Actions */
	TEXT(T_a,    "a   apply/use something");
	TEXT(T_e,    "e   eat something");
	TEXT(T_q,    "q   quaff a potion");
	TEXT(T_r,    "r   read a scroll");
	TEXT(T_t,    "t   throw/shoot weapon");
	TEXT(T_z,    "z   zap a wand");

	/* Preparations */
	TEXT(T_w,    "w   wield a weapon");
	TEXT(T_P,    "P   Put on ring");
	TEXT(T_R,    "R   Remove ring");
	TEXT(T_T,    "T   Take off armor");
	TEXT(T_W,    "W   Wear armor");
	TEXT(T_WPN,   ")   current weapon");
	TEXT(T_ARMOR, "[   current armor");
	TEXT(T_RING,  "=   current rings");

	/* Movement */
	TEXT(T_E,     "E   Engrave msg on floor");
	TEXT(T_s,     "s   search");
	TEXT(T_UP,    "<   Go up stairs");
	TEXT(T_DOWN,  ">   Go down stairs");
	TEXT(T_WAIT,  ".   wait a moment");
	TEXT(T_CT,    "^T   Teleport");

#define IFLAGS ITEMENABLED|ITEMTEXT|HIGHCOMP
#define IDATA(str,off) 0,off,200,9,IFLAGS,0,(APTR)&str,NULL,NULL,NULL,NULL

struct MenuItem cmdsub[] = {
	{ &cmdsub[1], IDATA(T_HELP,   0) },
	{ &cmdsub[2], IDATA(T_o,     10) },
	{ &cmdsub[3], IDATA(T_SHELL, 20) },
	{ &cmdsub[4], IDATA(T_v,     30) },
	{ &cmdsub[5], IDATA(T_CR,    40) },
	{ &cmdsub[6], IDATA(T_CP,    50) },
	{ &cmdsub[7], IDATA(T_Q,     60) },
	{ NULL,       IDATA(T_S,     70) } };

struct MenuItem invsub[] = {
	{ &invsub[1], IDATA(T_i,      0) },
	{ &invsub[2], IDATA(T_p,     10) },
	{ &invsub[3], IDATA(T_d,     20) },
	{ &invsub[4], IDATA(T_D,     30) },
	{ &invsub[5], IDATA(T_COMMA, 40) },
	{ &invsub[6], IDATA(T_SLASH, 50) },
	{ &invsub[7], IDATA(T_c,     60) },
	{ NULL,       IDATA(T_C,     70) } };

struct MenuItem actsub[] = {
	{ &actsub[1], IDATA(T_a,    0) },
	{ &actsub[2], IDATA(T_e,    10) },
	{ &actsub[3], IDATA(T_q,    20) },
	{ &actsub[4], IDATA(T_r,    30) },
	{ &actsub[5], IDATA(T_t,    40) },
	{ NULL,       IDATA(T_z,    50) } };

struct MenuItem armsub[] = {
	{ &armsub[1], IDATA(T_w,      0) },
	{ &armsub[2], IDATA(T_P,     10) },
	{ &armsub[3], IDATA(T_R,     20) },
	{ &armsub[4], IDATA(T_T,     30) },
	{ &armsub[5], IDATA(T_W,     40) },
	{ &armsub[6], IDATA(T_WPN,   50) },
	{ &armsub[7], IDATA(T_ARMOR, 60) },
	{ NULL,       IDATA(T_RING,  70) } };

struct MenuItem movsub[] = {
	{ &movsub[1], IDATA(T_E,    0) },
	{ &movsub[2], IDATA(T_s,    10) },
	{ &movsub[3], IDATA(T_UP,   20) },
	{ &movsub[4], IDATA(T_DOWN, 30) },
	{ &movsub[5], IDATA(T_WAIT, 40) },
	{ NULL,       IDATA(T_CT,   50) } };

struct Menu HackMenu[] = {
   { &HackMenu[1], 10,0, 80,0,MENUENABLED,"Commands",     &cmdsub[0] },
   { &HackMenu[2], 90,0, 80,0,MENUENABLED,"Inventory",    &invsub[0] },
   { &HackMenu[3],180,0, 80,0,MENUENABLED,"Actions",      &actsub[0] },
   { &HackMenu[4],270,0,100,0,MENUENABLED,"Preparations", &armsub[0] },
   { NULL,        390,0, 80,0,MENUENABLED,"Movement",     &movsub[0] } };

char menukey[5][10] = {
	{
	'?',   /*   display help */
	'o',   /*   set options */
	'!',   /*   AMIGADOS commands */
	'v',   /*   version number */
	022,   /*R   redraw screen */
	024,   /*P   repeat last message */
	'Q',   /*   quit game */
	'S',   /*   save the game */
	},{
	/* Inventory */
	'i',   /*   inventory */
	'p',   /*   pay your bill */
	'd',   /*   drop an object */
	'D',   /*   Drop several things */
	',',   /*   Pickup an object */
	'/',   /*   identify something */
	'c',   /*   call a class of objects */
	'C',   /*   Christen a monster */
	},{
	/* Actions */
	'a',   /*   apply/use something */
	'e',   /*   eat something */
	'q',   /*   quaff a potion */
	'r',   /*   read a scroll */
	't',   /*   throw/shoot weapon */
	'z',   /*   zap a wand */
	},{
	/* Preparations */
	'w',   /*   wield a weapon */
	'P',   /*   Put on ring */
	'R',   /*   Remove ring */
	'T',   /*   Take off armor */
	'W',   /*   Wear armor */
	')',   /*   current weapon */
	'[',   /*   current armor */
	'=',   /*   current rings */
	},{
	/* Movement */
	'E',   /*   Engrave msg on floor */
	's',   /*   search */
	'<',   /*   Go up stairs */
	'>',   /*   Go down stairs */
	'.',   /*   wait a moment */
	024,   /*   Teleport */
	} };
#file hack.window.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include <exec/types.h>
#include <exec/io.h>
#include <intuition/intuition.h>
#include <stdio.h>
#include "hack.h"   /* for ROWNO and COLNO */
#include "def.menus.h"

#define XSIZE 8
#define YSIZE 8
#define BASEX 4
#define BASEY 4   /* should be -4 */

#define ICON_REV       0
#define GRAPHICS_REV   29
#define INTUITION_REV  29

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
char *IconBase;
int mousex, mousey;

#define BUFFERED 512
char out_buffer[BUFFERED];
int bufcnt;
char *out_bufp;

#ifdef STUPIDARROWS
#include "def.arrows.h"
struct Image URImage = { 0,0,22,10,2,(short *)&UPRIGHTdata,   0x3, 0, NULL };
struct Image DRImage = { 0,0,22,10,2,(short *)&DOWNRIGHTdata, 0x3, 0, NULL };
struct Image RImage  = { 0,0,22,10,2,(short *)&RIGHTdata,     0x3, 0, NULL };
struct Image DImage  = { 0,0,22,10,2,(short *)&DOWNdata,      0x3, 0, NULL };
struct Image UImage  = { 0,0,22,10,2,(short *)&UPdata,        0x3, 0, NULL };
struct Image LImage  = { 0,0,22,10,2,(short *)&LEFTdata,      0x3, 0, NULL };
struct Image DLImage = { 0,0,22,10,2,(short *)&DOWNLEFTdata,  0x3, 0, NULL };
struct Image ULImage = { 0,0,22,10,2,(short *)&UPLEFTdata,    0x3, 0, NULL };

struct Gadget URGadget = { NULL,      436, 0, 22,10,
			GADGHCOMP | GADGIMAGE, GADGIMMEDIATE, BOOLGADGET,
			(APTR)&URImage, NULL, NULL, 0, NULL, 'u', NULL };
struct Gadget DRGadget = { &URGadget, 568, 0, 22,10,
			GADGHCOMP | GADGIMAGE, GADGIMMEDIATE, BOOLGADGET,
			(APTR)&DRImage, NULL, NULL, 0, NULL, 'n', NULL };
struct Gadget RGadget  = { &DRGadget, 490, 0, 22,10,
			GADGHCOMP | GADGIMAGE, GADGIMMEDIATE, BOOLGADGET,
			(APTR)&RImage, NULL, NULL, 0, NULL, 'l', NULL };
struct Gadget DGadget  = { &RGadget,  544, 0, 22,10,
			GADGHCOMP | GADGIMAGE, GADGIMMEDIATE, BOOLGADGET,
			(APTR)&DImage, NULL, NULL, 0, NULL, 'j', NULL };
struct Gadget UGadget  = { &DGadget,  412, 0, 22,10,
			GADGHCOMP | GADGIMAGE, GADGIMMEDIATE, BOOLGADGET,
			(APTR)&UImage, NULL, NULL, 0, NULL, 'k', NULL };
struct Gadget LGadget  = { &UGadget,  466, 0, 22,10,
			GADGHCOMP | GADGIMAGE, GADGIMMEDIATE, BOOLGADGET,
			(APTR)&LImage, NULL, NULL, 0, NULL, 'h', NULL };
struct Gadget DLGadget = { &LGadget,  520, 0, 22,10,
			GADGHCOMP | GADGIMAGE, GADGIMMEDIATE, BOOLGADGET,
			(APTR)&DLImage, NULL, NULL, 0, NULL, 'b', NULL };
struct Gadget ULGadget = { &DLGadget, 388, 0, 22,10,
			GADGHCOMP | GADGIMAGE, GADGIMMEDIATE, BOOLGADGET,
			(APTR)&ULImage, NULL, NULL, 0, NULL, 'y', NULL };
#endif

struct TextAttr HackFont =
	{ "topaz.font", TOPAZ_EIGHTY,FS_NORMAL, FPF_ROMFONT};

struct NewScreen NewHackScreen = {
0, 0, 640, 200, 3, 0, 1, HIRES, CUSTOMSCREEN, &HackFont,
"HACK V1.0.1a - Ported by  John A. Toebes, VIII", NULL, NULL };

struct Window *HackWindow;
struct Screen *HackScreen;

struct NewWindow NewHackWindow = {
  0,1,640,199, -1,-1,   /* left, top, width, height, detailpen, blockpen */
  MOUSEBUTTONS | CLOSEWINDOW | RAWKEY | MENUPICK
#ifdef STUPIDARROWS
 | GADGETDOWN
#endif
  ,WINDOWDEPTH | WINDOWCLOSE | ACTIVATE | SIMPLE_REFRESH,
#ifdef STUPIDARROWS
  &ULGadget,
#else
  NULL,
#endif
NULL, "HACK V1.0.1a - Ported by John A. Toebes, VIII",
  NULL, NULL, 640,200,640,200, CUSTOMSCREEN };

struct IOStdReq consoleIO;

#define HO "\x9BH"
#define CL "\x0C"
#define CE "\x9BK"
#define UP "\x0B"
#define CM "\x9B%d;%dH"
#define ND "\x09"
#define XD "\x9BB"
#define BC "\x08"
#define SO "\x9B4m"
#define SE "\x9B0m"
#define BELL 7
int myx, myy;

startup()
{
}

/* Cursor movements */
extern xchar curx, cury;

curs(x,y)
register int x,y;   /* not xchar: perhaps xchar is unsigned and
            curx-x would be unsigned as well */
{
   if (y != cury || x != curx)
	myprintf(CM, y, x);
   curx = x;
   cury = y;
}

cl_end() {
	myprintf(CE);
}

clear_screen() {
	myprintf(CL);
	curx = cury = 1;
}

home()
{
	myprintf(HO);
	curx = cury = 1;
}

standoutbeg()
{
	myprintf(SO);
}

standoutend()
{
	myprintf(SE);
}

backsp()
{
	myprintf(BC);
	curx--;
}

bell()
{
	myputchar(BELL);
}

delay_output()
{
   /* delay 40 ms, 50 ticks/sec    */
/*   Delay (2); */
}

initterm()
   {
#ifdef DEBUGIT
	printf("intuition.library?\n");
	fflush(stdout);
#endif
   if ( (IntuitionBase = (struct IntuitionBase *)
	OpenLibrary("intuition.library", INTUITION_REV)) == NULL)
	_exit(2);

#ifdef DEBUGIT
	printf("graphics.library?\n");
	fflush(stdout);
#endif
   if ( (GfxBase = (struct GfxBase *)
	OpenLibrary("graphics.library",GRAPHICS_REV)) == NULL)
	_exit(3);

#ifdef DEBUGIT
	printf("icon.library?\n");
	fflush(stdout);
#endif
   if ( (IconBase = (char *)
	OpenLibrary("icon.library",ICON_REV)) == NULL)
	_exit(4);

   if ( (HackScreen = (struct Screen *)
	OpenScreen(&NewHackScreen)) == NULL)
	_exit(5);

   NewHackWindow.Screen = HackScreen;

#ifdef DEBUGIT
	printf("OpenWindow?\n");
	fflush(stdout);
#endif
   if ( (HackWindow = (struct Window *)
	OpenWindow(&NewHackWindow)) == NULL)
	{
	CloseScreen(HackScreen);
	_exit(6);
	}

#ifdef DEBUGIT
	printf("menu strip?\n");
	fflush(stdout);
#endif
   SetMenuStrip(HackWindow,&HackMenu);

#ifdef DEBUGIT
	printf("console.device?\n");
	fflush(stdout);
#endif
   consoleIO.io_Data = (APTR) HackWindow;
   consoleIO.io_Length = sizeof(*HackWindow);
   if (OpenDevice("console.device",0, &consoleIO, 0) != 0)
	hackexit(7);

#ifdef DEBUGIT
	printf("doneinit\n");
	fflush(stdout);
#endif
   bufcnt = 0;
   out_bufp = out_buffer;
   }

hackexit(code)
int code;
   {
   CloseDevice(&consoleIO);
   ClearMenuStrip(HackWindow);
   CloseWindow(HackWindow);
   CloseScreen(HackScreen);
   CloseLibrary(IconBase);
   CloseLibrary(GfxBase);
   CloseLibrary(IntuitionBase);
   _exit(code);
   }

myfflush()
   {
	register int dummy1, dummy2;
   if (bufcnt)
	{
	consoleIO.io_Command = CMD_WRITE;
	consoleIO.io_Data = (APTR)out_buffer;
	consoleIO.io_Length = bufcnt;
	DoIO(&consoleIO);
	}
   bufcnt = 0;
   }

myputchar(c)
char c;
   {
	if (bufcnt == BUFFERED)
		myfflush();

	out_buffer[bufcnt++] = c;
   }

myputs(str)
char *str;
   {
	register int dummy1, dummy2;
	int len, tocopy;

	len = strlen(str);

	if (len >= BUFFERED)
		{
		myfflush();
		consoleIO.io_Command = CMD_WRITE;
		consoleIO.io_Data = (APTR)str;
		consoleIO.io_Length = len;
		DoIO(&consoleIO);
		}
	else
		{
		if (bufcnt+len >= BUFFERED) /* is there room */
			{
			tocopy = BUFFERED - bufcnt;
			movmem(str, &out_buffer[bufcnt], tocopy);
			bufcnt += tocopy;
			len -= tocopy;
			str += tocopy;
			myfflush();
			}
		if (len)
			{
			/* just move it in */
			movmem(str, &out_buffer[bufcnt], len);
			bufcnt += len;
			}
		}
	myputchar('\n');
   }

/*VARARGS1*/
myprintf(str,a1,a2,a3,a4,a5,a6,a7,a8,a9)
char *str,*a1,*a2,*a3,*a4,*a5,*a6,*a7,*a8,*a9;
   {
	char buf[BUFFERED], *bptr;
	int len, tocopy;

	bptr = &buf;
	len = (int)sprintf(bptr,str,a1,a2,a3,a4,a5,a6,a7,a8,a9);
	if (bufcnt+len >= BUFFERED) /* is there room */
		{
		tocopy = BUFFERED - bufcnt;
		movmem(bptr, &out_buffer[bufcnt], tocopy);
		bufcnt += tocopy;
		len -= tocopy;
		bptr += tocopy;
		myfflush();
		}
	if (len)
		{
		/* just move it in */
		movmem(bptr, &out_buffer[bufcnt], len);
		bufcnt += len;
		}
   }

inchar()
   {
	register int dummy1, dummy2;
	struct IntuiMessage *Message, *GetMsg();
	int c;
	USHORT thismenu, menusel;
#ifdef STUPIDARROWS
   struct Gadget *gadget;
#endif
   struct MenuItem *item, *ItemAddress();
   c = 0;
   while(!c)
      {
      while( (Message = GetMsg(HackWindow->UserPort)) == NULL)
         Wait( 1 << HackWindow->UserPort->mp_SigBit );

      switch(Message->Class)
	{
	case MENUPICK:
		menusel = thismenu = Message->Code;
		while(thismenu != MENUNULL)
		   {
		   menusel = thismenu;
		   item = ItemAddress(&HackMenu, thismenu);
		   thismenu = item->NextSelect;
		   }
		if (menusel != MENUNULL)
		   c = menukey[MENUNUM(menusel)][ITEMNUM(menusel)];
		break;
	case MOUSEBUTTONS:
		mousex = ( (Message->MouseX) + BASEX ) / XSIZE;
 		mousey = ( (Message->MouseY) - BASEY ) / YSIZE;
		if (mousex > 0 && mousey > 0 &&
		    mousex <= COLNO && mousey <= ROWNO )
			{
			if (Message->Code == SELECTDOWN)
				c = MDOWN;
			else if (Message->Code == SELECTUP)
				c = MUP;
			}
		break;
	case CLOSEWINDOW:
		c = 'Q';
		break;
#ifdef STUPIDARROWS
	case GADGETDOWN:
		gadget = (struct Gadget *)Message->IAddress;
		c = gadget->GadgetID;
		break;
#endif
	case RAWKEY:
		c = cnvrtkey(Message->Code,Message->Qualifier);
		break;
	default:
		c = 'Q';
		break;
	}
      ReplyMsg(Message);
      }
   return(c);
   }

#define NORMAL 0
#define SHIFTED 1
#define CONTROL 2
#define ALTED 3
short lookup[4][96] =
{
/* unshifted table */
	'`',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
	'8',	'9',	'0',	'-',	'=',	'\\',	0,	'0',
	'q',	'w',	'e',	'r',	't',	'y',	'u',	'i',
	'o',	'p',	'[',	']',	0,	'b',	'j',	'n',
	'a',	's',	'd',	'f',	'g',	'h',	'j',	'k',
	'l',	';',	'\'',	0,	0,	'h',	'.',	'l',
	0,	'z',	'x',	'c',	'v',	'b',	'n',	'm',
	',',	'.',	'/',	0,	'.',	'y',	'k',	'u',
	' ',	8,	'i',	'\n',	'\n',	022,	8,	0,
	0,	0,	'-',	0,	'k',	'j',	'l',	'h',
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	'?',

/* shifted table */
	'~',	'!',	'@',	'#',	'$',	'%',	'^',	'&',
	'*',	'(',	')',	'_',	'+',	'|',	0,	'0',
	'Q',	'W',	'E',	'R',	'T',	'Y',	'U',	'I',
	'O',	'P',	'{',	'}',	0,	'B',	'J',	'N',
	'A',	'S',	'D',	'F',	'G',	'H',	'J',	'K',
	'L',	':',	'"',	0,	0,	'H',	'.',	'L',
	0,	'Z',	'X',	'C',	'V',	'B',	'N',	'M',
	'<',	'>',	'?',	0,	'.',	'Y',	'K',	'U',
	' ',	'H',	'I',	'\N',	'\N',	022,	'H',	0,
	0,	0,	'-',	0,	'K',	'J',	'L',	'H',
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	'?',

/* controlled table */
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	'Q',	0,	0,
	0,	0,	0,	022,	024,	0,	0,	0,
	0,	020,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	'?',

/* alted table */
	'`',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
	'8',	'9',	'0',	'-',	'=',	'\\',	0,	'0',
	'q',	'w',	'e',	'r',	't',	'y',	'u',	'i',
	'o',	'p',	'[',	']',	0,	'b',	'j',	'n',
	'a',	's',	'd',	'f',	'g',	'h',	'j',	'k',
	'l',	';',	'\'',	0,	0,	'h',	'.',	'l',
	0,	'z',	'x',	'c',	'v',	'b',	'n',	'm',
	',',	'.',	'?',	0,	'.',	'y',	'k',	'u',
	' ',	'h',	'i',	'\n',	'\n',	022,	'h',	0,
	0,	0,	'-',	0,	'k',	'j',	'l',	'h',
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	'?'
};

int cnvrtkey(code, qual )
USHORT code, qual;
   {
   int table;

   if (code > 0x5f)
      return(0);

   if (qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
      table = SHIFTED;
   else if (qual & (IEQUALIFIER_LALT | IEQUALIFIER_RALT))
       table = ALTED;
   else if (qual & (IEQUALIFIER_CONTROL))
      table = CONTROL;
   else
      table = NORMAL;
   return((int)lookup[table][code]);
   }
#file hack.termcap.c
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */

#include <stdio.h>
#include "config.h"   /* for ROWNO and COLNO */

#define HEIGHT 8
#define WIDTH  8
#define TOP    16
#define LEFT   3

startup()
{
}

/* Cursor movements */
extern xchar curx, cury;

curs(x,y)
register int x,y;   /* not xchar: perhaps xchar is unsigned and
            curx-x would be unsigned as well */
{
   if (y == cury && x == curx) return;
   cmov(x,y);
}

nocmov(x,y)
{
  cmov(x,y);   /* always go to the requested position */
}

cmov(x,y)
register int x,y;
{
   setxy(LEFT+x*WIDTH,TOP+y*HEIGHT);
   cury = y;
   curx = x;
}


cl_end() {
   weraeol();
}

clear_screen() {
   /* printf(CL); */
   home();
}

home()
{
   setxy(TOP,LEFT);
   curx = cury = 1;
}

standoutbeg()
{
   /* printf(SO); */
}

standoutend()
{
   /* printf(SE); */
}

backsp()
{
   cmov(curx-1,cury);
}

bell()
{
    /* putchar('\007'); */
}

delay_output()
{
   /* delay 40 ms, 50 ticks/sec    */
   Delay (2);
}

#file hack.graphics.c
/* Copyright (c) John A. Toebes, VIII 1986 */
#include <exec/types.h>
#include <exec/io.h>
#include <intuition/intuition.h>
#include <graphics/view.h>
#include <stdio.h>
#include <fcntl.h>
#include "config.h"
#include "hack.h"   /* for ROWNO and COLNO */

#define XSIZE 8
#define YSIZE 8
#define BASEX (-4)
#define BASEY 19
#define PICSIZE (8*4)
#define USEDPLANES 3
extern struct Window *HackWindow;
extern struct Screen *HackScreen;
UWORD colormap[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
USHORT mondata[] = 
  { 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00,
    0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00,
    0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00,
    0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00 };
struct Image monImage = 
   { 0, 0, 8, 8, 3, &mondata[0], 0x0f, 0x0, NULL };
char *monpics;
char basemon;

InitGraphics()
   {
   char maxchar;
   int file;
   int size;
   int i;
   register int dummy1, dummy2;
   if ( (file = open(HACKCSET, O_RDONLY)) == -1 )
	panic("Cannot Open Graphics Characters");
/*   cm = GetColorMap(16);
   HackScreen->ViewPort.ColorMap = cm; */
   mread(file,colormap, 32);
   for (i=0; i<8; i++)
	SetRGB4(&HackScreen->ViewPort, i,
		(colormap[i] >> 8) & 0x0f,
		(colormap[i] >> 4) & 0x0f,
		(colormap[i]) &0x0f);
   mread(file,&basemon,1);
   mread(file,&maxchar,1);
   size = (maxchar-basemon)*PICSIZE;
   if ((monpics = (char *)malloc(size)) == NULL)
	panic("Cannot get char area");
   mread(file,monpics,size);
   }

at(x,y,ch)
register xchar x,y;
char ch;
   {
   char *thisone;
   int i;

   /* first construct the picture */
   thisone = monpics+PICSIZE*(ch-basemon);
   for (i=0; i<PICSIZE; i++)
	mondata[i] = thisone[i] << 8;
   if ((curx == x) & (cury == (y+2)) )
	home();
   myfflush();
   DrawImage(HackWindow->RPort, &monImage, BASEX+(x*XSIZE), BASEY+(y*YSIZE));
   }
#file hack.icon.c
#include <workbench/startup.h>
#include <workbench/icon.h>
#include <workbench/workbench.h>

extern struct WBStartup *WBenchMsg;
extern char pl_character[];
extern char plname[];

geticon()
   {
   struct WBArg *argp;
   char *argname;

   argp = WBenchMsg->sm_ArgList;
   if (WBenchMsg->sm_NumArgs > 1)
	{
	argname = (argp+1)->wa_Name;
	pl_character[0] = pl_character[1] = 0;
	/* argp now points to the name */
	if      (!strcmp(argname, "Wizard"      )) pl_character[0] = 'W';
	else if (!strcmp(argname, "Speliologist")) pl_character[0] = 'S';
	else if (!strcmp(argname, "Tourist"     )) pl_character[0] = 'T';
	else if (!strcmp(argname, "Fighter"     )) pl_character[0] = 'F';
	else if (!strcmp(argname, "Knight"      )) pl_character[0] = 'K';
	else if (!strcmp(argname, "Caveman"     )) pl_character[0] = 'C';
	else strcpy(plname, argname);
	}
   }

makeicon(name,type)
char *name;
char type;
   {
   char *source;
   struct DiskObject *object;

   switch(type) {
	case 'w':
	case 'W':	source = "Wizard";
			break;
	case 's':
	case 'S':	source = "Speliologist";
			break;
	case 't':
	case 'T':	source = "Tourist";
			break;
	case 'f':
	case 'F':	source = "Fighter";
			break;
	case 'k':
	case 'K':	source = "Knight";
			break;
	case 'c':
	case 'C':	source = "Caveman";
			break;

	default:	source = "HACK";
			break;
	}
	if ( (object = GetDiskObject(source)) == NULL)
		myprintf("Cannot get source icon - err #%d\n", IoErr() );
	object->do_CurrentX = NO_ICON_POSITION;
	object->do_CurrentY = NO_ICON_POSITION;
	if ( (object = PutDiskObject( name, object )) == NULL)
		myprintf("Cannot create save icon - err #%d\n", IoErr() );
	FreeDiskObject(object);
   }

delicon(name)
   {
   struct WBObject *object;
   char tempname[100];  /* should hold any file name */

   strcpy(tempname,name);
   strcat(tempname,".info");
   if ( unlink(tempname) == -1)
	myprintf("Cannot delete .info file\n");
   }
#file qsort.c
qsort( v, n, size, comp)
char *v;
int n;
int size;
int (*comp)();
   {
   int gap, i, j, x, cnt;
   char temp, *p1, *p2;

   cnt = 0;
   for (gap=n/2; gap > 0 ; gap /= 2)
      for (i=gap; i<n; i++)
         for (j = i-gap; j >= 0; j -= gap)
            if ( (*comp) ( (p1=v+j*size), (p2=v+(j+gap)*size) ) < 0)
               {
               cnt++;
               /* exchange them */
               for (x=0; x<size; x++)
                  {
                  temp = *p1;
                  *p1++ = *p2;
                  *p2++ = temp;
                  }
               }
   return(cnt);
   }
#file unixxface.c
#include <stdio.h>
#include <libraries/dosextens.h>

int getpid()
   {
   long now[3];

   DateStamp(&now);

   return(now[0] ^ now[1] ^ now[2]);
   }

int *signal(num,func)
int num;
int *func;
   {
   return(NULL);
   }


getenv(var)
char *var;
   {
   return(NULL);
   }


execl()
   {
   /* this should flag an error */
   }


chdir(dir)
char *dir;
   {
   struct FileLock *lock;

   if ( (lock = Lock(dir, ACCESS_READ)) == NULL)
	return(1);  /* cannot find the directory */

   lock = CurrentDir( lock );

   if (lock)
	UnLock(lock);

   /* change to the desired directory */
   return(0);  /* phoney success */
   }


char *getlogin()
   {
   /* return the login name - perhaps we can use getenv */
   return (NULL);
   }

perror(string)
char *string;
   {
   myprintf("Call to perror for '%s'\n", string);
   }

char *index(p,c)
char *p;
char c;
   {
   char *strchr();

   return(strchr(p,c));
   }

char *rindex(p,c)
char *p;
char c;
   {
   char *strrchr();

   return(strrchr(p,c));
   }
#file _main.c
#include <stdio.h>
#include <ctype.h>
#include <ios1.h>

#include "workbench/startup.h"
#include "libraries/dos.h"

#define MAXARG 32              /* maximum command line arguments */

#ifndef TINY
extern int _stack,_fmode,_iomode;
#endif
extern int LoadAddress;

extern struct UFB _ufbs[];
int argc;			/* arg count */
char *argv[MAXARG];		/* arg pointers */

#define MAXWINDOW 40
extern struct WBStartup *WBenchMsg;
static char window[MAXWINDOW] = "con:10/10/320/80/";

/**
*
* name         _main - process command line, open files, and call "main"
*
* synopsis     _main(line);
*              char *line;     ptr to command line that caused execution
*
* description	This function performs the standard pre-processing for
*		the main module of a C program.  It accepts a command
*		line of the form
*
*			pgmname arg1 arg2 ...
*
*		and builds a list of pointers to each argument.  The first
*		pointer is to the program name.  For some environments, the
*		standard I/O files are also opened, using file names that
*		were set up by the OS interface module XCMAIN.
*
**/
_main(line)
char *line;
{
char c;
int x;

/*
*
* Build argument pointer list
*
*/
for(argc = 0; argc < MAXARG; )
	{
	while(isspace(*line)) line++;
	if(*line == '\0') break;
	argv[argc++] = line;
	while((*line != '\0') && (isspace(*line) == 0)) line++;
	c = *line;
	*line++ = '\0';
	if(c == '\0') break;
	}

_ufbs[0].ufbflg |= UFB_OP | UFB_RA | UFB_NC;
_ufbs[1].ufbflg |= UFB_OP | UFB_WA | UFB_NC;
_ufbs[2].ufbflg |= UFB_OP | UFB_WA ;

/*
*
* Call user's main program
*
*/
#ifdef DEBUG
printf("load address = %lx\n",LoadAddress);
Debug(0);
#endif

main(argc,argv);              /* call main function */
_exit(0);
}

#file link_hack
FROM HACK_game:lib/c.o+     *
HACK_source:_main.o+        *
HACK_source:savelev.o+      *
HACK_source:hack.trap.o+    *
HACK_source:hack.save.o+    *
HACK_source:hack.o+         *
HACK_source:hack.rumors.o+  *
HACK_source:hack.end.o+     *
HACK_source:hack.apply.o+   *
HACK_source:hack.mhitu.o+   *
HACK_source:hack.o_init.o+  *
HACK_source:hack.worm.o+    *
HACK_source:hack.do.o+      *
HACK_source:hack.wield.o+   *
HACK_source:hack.pri.o+     *
HACK_source:hack.invent.o+  *
HACK_source:hack.version.o+ *
HACK_source:hack.u_init.o+  *
HACK_source:hack.vault.o+   *
HACK_source:hack.eat.o+     *
HACK_source:hack.dog.o+     *
HACK_source:hack.timeout.o+ *
HACK_source:rnd.o+          *
HACK_source:hack.cmdlist.o+ *
HACK_source:hack.options.o+ *
HACK_source:hack.topl.o+    *
HACK_source:hack.mkobj.o+   *
HACK_source:hack.monst.o+   *
HACK_source:hack.stat.o+    *
HACK_source:hack.steal.o+   *
HACK_source:hack.makemon.o+ *
HACK_source:mklv.shknam.o+  *
HACK_source:hack.track.o+   *
HACK_source:hack.zap.o+     *
HACK_source:hack.do_wear.o+ *
HACK_source:mklv.shk.o+     *
HACK_source:hack.objnam.o+  *
HACK_source:hack.worn.o+    *
HACK_source:hack.lev.o+     *
HACK_source:hack.shk.o+     *
HACK_source:hack.whatis.o+  *
HACK_source:hack.bones.o+   *
HACK_source:hack.read.o+    *
HACK_source:hack.Decl.o+    *
HACK_source:hack.search.o+  *
HACK_source:hack.do_name.o+ *
HACK_source:mklv.makemaz.o+ *
HACK_source:hack.main.o+    *
HACK_source:alloc.o+        *
HACK_source:hack.fight.o+   *
HACK_source:hack.tty.o+     *
HACK_source:UnixXface.o+    *
HACK_source:hack.engrave.o+ *
HACK_source:mklev.o+        *
HACK_source:hack.mon.o+     *
HACK_source:qsort.o+        *
HACK_source:hack.window.o+  *
HACK_source:hack.graphics.o+*
HACK_source:hack.icon.o+    *
HACK_source:hack.rip.o

TO      HACK_game:Hack
LIBRARY HACK_game:lib/lc.lib+HACK_game:lib/amiga.lib
MAP     nil:
#file ccall
stack 10000
lc1 -ii: -cw -oram: hack.window
lc2 -v -ohack_source: ram:hack.window
lc1 -ii: -cw -oram: hack.icon
lc2 -v -ohack_source: ram:hack.icon
lc1 -ii: -cw -oram: unixxface
lc2 -v -ohack_source: ram:unixxface
lc1 -ii: -cw -oram: -dTINY _main
lc2 -v -ohack_source: ram:-dTINY _main
lc1 -ii: -cw -oram: hack.save
lc2 -v -ohack_source: ram:hack.save
lc1 -ii: -cw -oram: hack.trap
lc2 -v -ohack_source: ram:hack.trap
lc1 -ii: -cw -oram: hack
lc2 -v -ohack_source: ram:hack
lc1 -ii: -cw -oram: hack.rumors
lc2 -v -ohack_source: ram:hack.rumors
lc1 -ii: -cw -oram: hack.end
lc2 -v -ohack_source: ram:hack.end
lc1 -ii: -cw -oram: hack.apply
lc2 -v -ohack_source: ram:hack.apply
lc1 -ii: -cw -oram: hack.o_init
lc2 -v -ohack_source: ram:hack.o_init
lc1 -ii: -cw -oram: hack.mhitu
lc2 -v -ohack_source: ram:hack.mhitu
lc1 -ii: -cw -oram: hack.worm
lc2 -v -ohack_source: ram:hack.worm
lc1 -ii: -cw -oram: hack.do
lc2 -v -ohack_source: ram:hack.do
lc1 -ii: -cw -oram: hack.pri
lc2 -v -ohack_source: ram:hack.pri
lc1 -ii: -cw -oram: hack.invent
lc2 -v -ohack_source: ram:hack.invent
lc1 -ii: -cw -oram: hack.wield
lc2 -v -ohack_source: ram:hack.wield
lc1 -ii: -cw -oram: hack.version
lc2 -v -ohack_source: ram:hack.version
lc1 -ii: -cw -oram: hack.u_init
lc2 -v -ohack_source: ram:hack.u_init
lc1 -ii: -cw -oram: hack.vault
lc2 -v -ohack_source: ram:hack.vault
lc1 -ii: -cw -oram: hack.dog
lc2 -v -ohack_source: ram:hack.dog
lc1 -ii: -cw -oram: hack.eat
lc2 -v -ohack_source: ram:hack.eat
lc1 -ii: -cw -oram: hack.timeout
lc2 -v -ohack_source: ram:hack.timeout
lc1 -ii: -cw -oram: rnd
lc2 -v -ohack_source: ram:rnd
lc1 -ii: -cw -oram: hack.options
lc2 -v -ohack_source: ram:hack.options
lc1 -ii: -cw -oram: hack.cmdlist
lc2 -v -ohack_source: ram:hack.cmdlist
lc1 -ii: -cw -oram: qsort
lc2 -v -ohack_source: ram:qsort
lc1 -ii: -cw -oram: hack.zap
lc2 -v -ohack_source: ram:hack.zap
lc1 -ii: -cw -oram: hack.do_wear
lc2 -v -ohack_source: ram:hack.do_wear
lc1 -ii: -cw -oram: mklv.shk
lc2 -v -ohack_source: ram:mklv.shk
lc1 -ii: -cw -oram: hack.objnam
lc2 -v -ohack_source: ram:hack.objnam
lc1 -ii: -cw -oram: hack.worn
lc2 -v -ohack_source: ram:hack.worn
lc1 -ii: -cw -oram: hack.lev
lc2 -v -ohack_source: ram:hack.lev
lc1 -ii: -cw -oram: hack.shk
lc2 -v -ohack_source: ram:hack.shk
lc1 -ii: -cw -oram: hack.whatis
lc2 -v -ohack_source: ram:hack.whatis
lc1 -ii: -cw -oram: hack.bones
lc2 -v -ohack_source: ram:hack.bones
lc1 -ii: -cw -oram: hack.read
lc2 -v -ohack_source: ram:hack.read
lc1 -ii: -cw -oram: hack.Decl
lc2 -v -ohack_source: ram:hack.Decl
lc1 -ii: -cw -oram: hack.search
lc2 -v -ohack_source: ram:hack.search
lc1 -ii: -cw -oram: hack.do_name
lc2 -v -ohack_source: ram:hack.do_name
lc1 -ii: -cw -oram: mklev
lc2 -v -ohack_source: ram:mklev
lc1 -ii: -cw -oram: mklv.makemaz
lc2 -v -ohack_source: ram:mklv.makemaz
lc1 -ii: -cw -oram: hack.main
lc2 -v -ohack_source: ram:hack.main
lc1 -ii: -cw -oram: alloc
lc2 -v -ohack_source: ram:alloc
lc1 -ii: -cw -oram: hack.fight
lc2 -v -ohack_source: ram:hack.fight
lc1 -ii: -cw -oram: hack.tty
lc2 -v -ohack_source: ram:hack.tty
lc1 -ii: -cw -oram: hack.engrave
lc2 -v -ohack_source: ram:hack.engrave
lc1 -ii: -cw -oram: hack.mon
lc2 -v -ohack_source: ram:hack.mon
lc1 -ii: -cw -oram: hack.rip
lc2 -v -ohack_source: ram:hack.rip
lc1 -ii: -cw -oram: hack.topl
lc2 -v -ohack_source: ram:hack.topl
lc1 -ii: -cw -oram: hack.mkobj
lc2 -v -ohack_source: ram:hack.mkobj
lc1 -ii: -cw -oram: hack.monst
lc2 -v -ohack_source: ram:hack.monst
lc1 -ii: -cw -oram: savelev
lc2 -v -ohack_source: ram:savelev
lc1 -ii: -cw -oram: hack.stat
lc2 -v -ohack_source: ram:hack.stat
lc1 -ii: -cw -oram: hack.steal
lc2 -v -ohack_source: ram:hack.steal
lc1 -ii: -cw -oram: mklv.shknam
lc2 -v -ohack_source: ram:mklv.shknam
lc1 -ii: -cw -oram: hack.makemon
lc2 -v -ohack_source: ram:hack.makemon
lc1 -ii: -cw -oram: hack.track
lc2 -v -ohack_source: ram:hack.track

jcz@ncsu.UUCP (John A. Toebes, VIII) (02/22/86)

#file data
@   human (or you)
-   a wall
|   a wall
+   a door
.   the floor of a room
#   a corridor
}   water filled area
<   the staircase to the previous level
>   the staircase to the next level
^   a trap
$   a pile, pot or chest of gold
%%  a piece of food
!   a potion
*   a gem
?   a scroll
=   a ring
/   a wand
[   a suit of armor
)   a weapon
(   a useful item (camera, key, rope etc.)
0   an iron ball
_   an iron chain
"   an amulet
,   a trapper
:   a chameleon
'   a lurker above
&   a demon
A   a giant ant
B   a giant bat
C   a centaur;
	Of all the monsters put together by  the  Greek  imagination
	the  Centaurs (Kentauroi) constituted a class in themselves.
	Despite a strong streak  of  sensuality  in  their  make-up,
	their  normal  behaviour  was  moral, and they took a kindly
	thought of man's welfare. The attempted outrage of Nessos on
	Deianeira,  and  that  of the whole tribe of Centaurs on the
	Lapith women, are more than offset  by  the  hospitality  of
	Pholos  and  by  the  wisdom of Cheiron, physician, prophet,
	lyrist, and the instructor of Achilles.  Further,  the  Cen-
	taurs  were  peculiar in that their nature, which united the
	body of a horse with the trunk and head of a  man,  involved
	an  unthinkable  duplication  of  vital organs and important
	members. So grotesque a combination seems  almost  un-Greek.
	These  strange  creatures were said to live in the caves and
	clefts of the mountains, myths associating  them  especially
	with the hills of Thessaly and the range of Erymanthos.
		[Mythology of all races, Vol. 1, pp. 270-271]
D   a dragon;
	In the West the dragon was the natural  enemy  of  man.  Although
	preferring to live in bleak and desolate regions, whenever it was
	seen among men it left in its wake a  trail  of  destruction  and
	disease. Yet any attempt to slay this beast was a perilous under-
	taking. For the dragon's assailant had to contend not  only  with
	clouds  of  sulphurous fumes pouring from its fire-breathing nos-
	trils, but also with the thrashings of its tail, the most  deadly
	part of its serpent-like body.
	[From: Mythical Beasts by Deirdre Headon (The Leprechaun Library)]
E   a floating eye
F   a freezing sphere
G   a gnome
H   a hobgoblin;
	Hobgoblin. Used by the  Puritans  and  in  later  times  for
	wicked  goblin  spirits,  as in Bunyan's 'Hobgoblin nor foul
	friend', but its more correct use is for the friendly  spir-
	its  of  the brownie type.  In 'A midsummer night's dream' a
	fairy says to Shakespeare's Puck:
		Those that Hobgoblin call you, and sweet Puck,
		You do their work, and they shall have good luck:
		Are you not he?
	and obviously Puck would not wish to be called  a  hobgoblin
	if that was an ill-omened word.
	Hobgoblins are on the whole, good-humoured and ready  to  be
	helpful,  but fond of practical joking, and like most of the
	fairies rather nasty people to annoy. Boggarts hover on  the
	verge of hobgoblindom.  Bogles are just over the edge.
	One Hob mentioned by Henderson, was Hob Headless who haunted
	the  road  between Hurworth and Neasham, but could not cross
	the little river Kent, which flowed into the  Tess.  He  was
	exorcised  and  laid under a large stone by the roadside for
	ninety-nine years and a day. If anyone was so unwary  as  to
	sit  on  that stone, he would be unable to quit it for ever.
	The ninety-nine years is nearly up, so trouble may  soon  be
	heard of on the road between Hurworth and Neasham.
		[Katharine Briggs, A  dictionary  of Fairies]
I   an invisible stalker
J   a jackal
K   a kobold
L   a leprechaun;
	The Irish Leprechaun is the Faeries' shoemaker and is  known
	under  various  names  in different parts of Ireland: Cluri-
	caune in Cork, Lurican in Kerry, Lurikeen in Kildare and Lu-
	rigadaun  in  Tipperary.  Although he works for the Faeries,
	the Leprechaun is not of the same species. He is small,  has
	dark  skin  and wears strange clothes.  His nature has some-
	thing of the manic-depressive about it: first  he  is  quite
	happy,  whistling merrily as he nails a sole on to a shoe; a
	few minutes later, he is sullen and  morose,  drunk  on  his
	home-made  heather ale. The Leprechaun's two great loves are
	tobacco and whiskey, and he is a first-rate con-man,  impos-
	sible  to  out-fox.  No  one, no matter how clever, has ever
	managed to cheat him out of his hidden pot of  gold  or  his
	magic  shilling. At the last minute he always thinks of some
	way to divert his captor's attention  and  vanishes  in  the
	twinkling  of  an eye.
		[From: A Field Guide to the Little People
			by  Nancy Arrowsmith & George Moorse. ]
M   a mimic
N   a nymph
O   an orc
P   a purple worm
Q   a quasit
R   a rust monster
S   a snake
T   a troll
U   an umber hulk
V   a vampire
W   a wraith
X   a xorn
Y   a yeti
Z   a zombie
a   an acid blob
b   a giant beetle
c   a cockatrice;
	Once in a great while, when the positions of the  stars  are
	just  right, a seven-year-old rooster will lay an egg. Then,
	along will come a snake, to coil around the egg, or a  toad,
	to  squat  upon  the  egg, keeping it warm and helping it to
	hatch. When it hatches, out comes a creature  called  basil-
	isk, or cockatrice, the most deadly of all creatures. A sin-
	gle glance from its yellow, piercing toad's eyes  will  kill
	both  man  and beast. Its power of destruction is said to be
	so great that sometimes simply to hear its  hiss  can  prove
	fatal.  Its breath is so venomenous that it causes all vege-
	tation to wither.
	There is, however, one  creature  which  can  withstand  the
	basilisk's deadly gaze, and this is the weasel. No one knows
	why this is so, but although the fierce weasel can slay  the
	basilisk,  it will itself be killed in the struggle. Perhaps
	the weasel knows the basilisk's fatal weakness: if  it  ever
	sees  its own reflection in a mirror it will perish instant-
	ly. But even a dead basilisk is dangerous, for  it  is  said
	that merely touching its lifeless body can cause a person to
	sicken and die.
		[From: Mythical Beasts by Deirdre Headon (The Leprechaun
		Library) and other sources. ]
d   a dog
e   an ettin
f   a fog cloud
g   a gelatinous cube
h   a homunculus
i   an imp;
	An 'imp' is an off-shoot or cutting. Thus an 'ymp tree'  was
	a grafted tree, or one grown from a cutting, not from seed.
	'Imp' properly means a small devil, an off-shoot  of  Satan,
	but  the distinction between goblins or bogles and imps from
	hell is hard to make, and many in the  Celtic  countries  as
	well as the English Puritans regarded all fairies as devils.
	The fairies of tradition often hover  uneasily  between  the
	ghostly and the diabolic state.
		[Katharine Briggs, A dictionary of Fairies]
j   a jaguar
k   a killer bee
l   a leocrotta
m   a minotaur
n   a nurse
o   an owlbear
p   a piercer
q   a quivering blob
r   a giant rat
s   a scorpion
t   a tengu;
	The tengu was the  most  troublesome  creature  of  Japanese
	legend.	Part  bird  and part man, with red beak for a nose
	and flashing eyes, the tengu was notorious for  stirring  up
	feuds  and  prolonging  enmity between families. Indeed, the
	belligerent tengus were supposed to have  been  man's  first
	instructors in the use of arms.
		[From: Mythical Beasts by Deirdre Headon
			(The Leprechaun Library). ]
u   a unicorn;
	Men have always sought the elusive unicorn, for  the  single
	twisted  horn  which projected from its forehead was thought
	to be a powerful talisman. It was said that the unicorn  had
	simply  to  dip  the tip of its horn in a muddy pool for the
	water to become pure. Men also believed that to  drink  from
	this horn was a protection against all sickness, and that if
	the horn was ground to a powder it would act as an  antidote
	to  all poisons. Less than 200 years ago in France, the horn
	of a unicorn was used in a ceremony to test the  royal  food
	for poison.
	Although only the size of a small horse, the  unicorn  is  a
	very  fierce  beast,  capable  of killing an elephant with a
	single thrust from its horn.  Its  fleetness  of  foot  also
	makes  this solitary creature difficult to capture. However,
	it can be tamed and captured by a maiden. Made gentle by the
	sight  of a virgin, the unicorn can be lured to lay its head
	in her lap, and in this docile mood, the maiden  may  secure
	it with a golden rope.
		[From: Mythical Beasts by Deirdre Headon
			(The Leprechaun Library). ]
v   a violet fungi
w   a long worm;
	From its teeth the crysknife can be manufactured.
x   a xan;
	The xan were animals sent to prick the legs of the Lords of Xibalba.
y   a yellow light
z   a zruty;
	The zruty are wild and gigantic beings, living in the wildernesses
	of the Tatra mountains.
~   the tail of a long worm
	Welcome to HACK!		   ( description of version 1.0.1 )

	Hack is a Dungeons and Dragons like game where you (the adventurer)
descend into the depths of the dungeon in search of the Amulet of Yendor
(reputed to be hidden below the twentieth level).  You are accompanied by a
little dog that can help you in many ways and can be trained to do all
sorts of things. On the way you will find useful (or useless) items, (quite
possibly with magic properties) and assorted monsters.  You attack a monster
by trying to move into the space a monster is in (but often it is much
wiser to leave it alone).

	Unlike most adventure games, which give you a verbal description of
your location, hack gives you a visual image of the dungeon level you are on.

	Hack uses the following symbols:
		A to Z and a to z:  monsters.  You can find out what a letter
represents by saying "/ (letter)", as in "/A", which will tell you that 'A'
is a giant ant.
		- and |  These form the walls of a room (or maze).
		.  this is the floor of a room.
		#  this is a corridor.
		>  this is the staircase to the next level.
		<  the staircase to the previous level.
		`  A large boulder.
		@  You (usually).
		^  A trap.
		)  A weapon of some sort.
		(  Some other useful object (key, rope, dynamite, camera, ...)
		[  A suit of armor.
		%  A piece of food (not necessarily healthy ...).
		/  A wand.
		=  A ring.
		?  A scroll.
		!  A magic potion.
		$  A pile or pot of gold.

Commands:
	Hack knows the following commands:
	?	help: print this list.
	Q	Quit the game.
	S	Save the game.
	<	up: go up the staircase (if you are standing on it).
	>	down: go down (just like up).
	kjhlyubn - go one step in the direction indicated.
		k: north (i.e., to the top of the screen),
		j: south, h: west, l: east, y: ne, u: nw, b: se, n: sw.
	KJHLYUBN - Go in that direction until you hit a wall or run
		into something.
	m	(followed by one of kjhlyubn): move without picking up
		any objects.
	M	(followed by one of KJHLYUBN): Move far, no pickup.
	f	(followed by one of kjhlyubn): move until something
		interesting is found.
	F	(followed by one of KJHLYUBN): as previous, but forking
		of corridors is not considered interesting.
	i	print your inventory.
	s	search for secret doors and traps around you.
	^	ask for the type of a trap you found earlier.
	)	ask for current wielded weapon.
	[	ask for current armor.
	=	ask for current rings.
	.	rest, do nothing.
	^R	redraw the screen.
	^P	repeat last message
		(subsequent ^P's repeat earlier messages).
	^T	teleport.
	/	(followed by any symbol): tell what this symbol represents.
	e	eat food.
	w	wield weapon. w- means: wield nothing, use bare hands.
	q	drink (quaff) a potion.
	r	read a scroll.
	T	Takeoff armor.
	R	Remove Ring.
	W	Wear armor.
	P	Put on a ring.
	t	throw or shoot a weapon.
	z	zap a wand.
	p	pay your shopping bill.
	d	drop something. d7a: drop seven items of object a.
	D	Drop several things.
		In answer to the question "What kinds of things do you
		want to drop? [!%= au]" you should give zero or more
		object symbols possibly followed by 'a' and/or 'u'.
		'a' means: drop all such objects, without asking for
			confirmation.
		'u' means: drop only unpaid objects (when in a shop).
	a	use, apply - Generic command for using a key to lock
		or unlock a door, using a camera, using a rope, etc.
	c	call: name a certain object or class of objects.
	C	Call: Name an individual monster.
	E	Engrave: Write a message in the dust on the floor.
		E- means: use fingers for writing.
	o	set options. You will be asked to enter an option line.
		If this is empty, the current options are reported.
		Otherwise it should be a list of options separated by commas.
		Possible boolean options are: oneline, time, news, tombstone;
		they can be negated by prefixing them with '!' or "no".
		A compound option is endgame; it is followed by a description
		of what parts of the list of topscorers should be printed
		when the game is finished.
	v	print version number.

	You can put a number before a command to repeat it that many times,
	as in "20s" or "40.".

	Some special feature that have been added just for the AMIGA:

	The numeric keypad (and cursor keys) may be used to indicate
direction.  ie. 8 on the keypad, UP arrow and 'k' are all ways to move up
one space.  Pressing SHIFT with the keypad or arrow keys causes you move
in the desired direction until something interesting happens.  The 8 arrows
that appear on the title bar may also be use to move a single space in the
indicated direction at a time.

	Menus appear on the top of the screen so that you can just select a
command.  The command character appears on the menu so that you can use
these menus as a quick form of help.

	When you Christen a monster, or are prompted for a Teleport location
(only when you have a ring of Teleport Control), you can use the mouse to
indicate the place you want to go.


	Have Fun, and Good Hacking!
"Quit" is a four letter word.
A fading corridor enlightens your insight.
A glowing potion is too hot to drink.
A long worm hits with all of its length.
A monstrous mind is a toy for ever.
A ring of adornment protects against Nymphs.
A rumour has it that rumours are just rumours.
A smoky potion surely affects your vision.
A spear might hit a nurse.
A spear will hit an ettin.
A tin of smoked eel is a wonderful find.
A truly wise man never plays leapfrog with a unicorn.
A two-handed sword usually misses.
A unicorn can be tamed only by a fair maiden.
A visit to the Zoo is very educational; you meet interesting animals.
A wand of vibration might bring the whole cave crashing about your ears.
Afraid of falling piercers? Wear a helmet!
All monsters are created evil, but some are more evil than others.
An elven cloak is always the height of fashion.
An elven cloak protects against magic.
Any small object that is accidentally dropped will hide under a larger object.
Attack long worms from the rear - that is so much safer!
Be careful when eating salmon - your fingers might become greasy.
Be careful when throwing a boomerang - you might hit the back of your head.
Better go home and hit your kids. They are just little monsters!
Better go home and play with your kids. They are just little monsters!
Better leave the dungeon, otherwise you might get hurt badly.
Beware of dark rooms - they may be the Morgue.
Beware of falling rocks, wear a helmet!
Beware of wands of instant disaster.
Beyond the 23-rd level lies a happy retirement in a room of your own.
Blank scrolls make more interesting reading.
Booksellers never read scrolls; it might carry them to far away.
Booksellers never read scrolls; it might leave their shop unguarded.
Dead lizards protect against a cockatrice.
Death is just around the next door.
Death is life's way of telling you you've been fired.
Descend in order to meet more decent monsters.
Direct a direct hit on your direct opponent, directing in the right direction.
Don't bother about money: only Leprechauns and shopkeepers are interested.
Don't forget! Large dogs are MUCH harder to kill than little dogs.
Don't tell a soul you found a secret door, otherwise it isn't secret anymore.
Don't throw gems. They are so precious! Besides, you might hit a roommate.
Drinking might affect your health.
Drop your vanity and get rid of your jewels! Pickpockets about!
Dungeon expects every monster to do his duty.
Dust is an armor of poor quality.
Eventually all wands of striking do strike.
Eventually you will come to admire the swift elegance of a retreating nymph.
Ever tried to catch a flying boomerang?
Every dog should be a domesticated one.
Every hand has only one finger to put a ring on. You've got only two hands. So?
Everybody should have tasted a scorpion at least once in his life.
Fiery letters might deter monsters.
First Law of Hacking: leaving is much more difficult than entering.
For any remedy there is a misery.
Fourth Law of Hacking: you will find the exit at the entrance.
Gems are the droppings of other inmates.
Gems do get a burden.
Genocide on shopkeepers is punishable.
Giving head to a long worm is like a long lasting reception.
Good day for overcoming obstacles.  Try a steeplechase.
Gossip is the opiate of the depressed.
Hackers do it with bugs.
Half Moon tonight.  (At least it's better than no Moon at all.)
Hitting is the lingua franca in these regions.
Hungry dogs are unreliable.
Hungry? There is an abundance of food on the next level.
I doubt whether nurses are virgins.
I once knew a hacker who ate too fast and choked to death.....
I smell a maze of twisty little passages.
If a shopkeeper kicks you out of his shop, he'll kick you out of the dungeon.
If you are too cute some monsters might be tempted to embrace you.
If you can't learn to do it well, learn to enjoy doing it badly.
If you need a wand of digging, kindly ask the minotaur.
If you see nurses you better start looking somewhere for a doctor.
If you turn blind: don't expect your dog to be turned into a seeing-eye dog.
If you want to hit, use a dagger.
If you want to rob a shop, train your dog.
If you're afraid of trapdoors, just cover the floor with all you've got.
Improve your environment, using a wand of rearrangement.
In a hurry? Try a ride on a fast moving quasit!
In need of a rest? Quaff a potion of sickness!
Inside a shop you better take a look at the price tags before buying anything.
It is bad manners to use a wand in a shop.
It is not always a good idea to whistle for your dog.
It might be a good idea to offer the unicorn a ruby.
It seems you keep overlooking a sign reading "No trespassing"!
It's all a matter of life and death, so beware of the undead.
It's not safe to Save.
Just below any trapdoor there may be another one. Just keep falling!
Keep a clear mind: quaff clear potions.
Keep your armours away from rust.
Keep your weaponry away from acids.
Kill a unicorn and you kill your luck.
Latest news? Put newsgroup 'netUNX.indoor.hackers-scroll' in your .newsrc!
Leprechauns hide their gold in a secret room.
Liquor sellers do not drink; they hate to see you twice.
Looking pale? Quaff a red potion!
M.M.Vault cashiers teleport any amount of gold to the next local branch.
Many monsters make a murdering mob.
Money is the root of all evil.
Money to invest? Take it to the local branch of the Magic Memory Vault!
Monsters come from nowhere to hit you everywhere.
Monsters sleep because you are boring, not because they ever get tired.
Most monsters prefer minced meat. That's why they are hitting you!
Most rumors are just as misleading as this one.
Much ado Nothing Happens.
Murder complaint? Mail to 'netnix!devil!gamble!freak!trap!lastwill!rip'.
Never ask a shopkeeper for a price list.
Never attack a guard.
Never fight a monster: you might get killed.
Never kick a sleeping dog.
Never map the labyrinth.
Never mind the monsters hitting you: they just replace the charwomen.
Never ride a long worm.
Never trust a random generator in magic fields.
Never use your best weapon to engrave a curse.
Never vomit on a door mat.
No weapon is better than a crysknife.
Not all rumors are as misleading as this one.
Not even a spear will hit a Xorn.
One has to leave shops before closing time.
One level further down somebody is getting killed, right now.
One wand of concentration equals eight scrolls of create monster.
Only a wizard can use a magic whistle.
Only david can find the zoo!
Only real trappers escape traps.
Only wizards are able to zap a wand.
Opening a tin is difficult, especially when you are not so strong!
Opening a tin is difficult, especially when you attempt this bare handed!
Operation coded OVERKILL has started now.
PLEASE ignore previous rumour.
Plain nymphs are harmless.
Playing billiards pays when you are in a shop.
Pursue the monsters and you will be had indeed.
Put on a ring of teleportation: it will take you away from onslaught.
Reading Tolkien might help you.
Reading Herbert will disgust you, but in one case it might be enlightening.
Reading might change your vision.
Reading might improve your scope.
Relying on a dog might turn you in a dog addict.
Savings do include amnesia.
Scorpions often hide under tripe rations.
Screw up your courage!  You've screwed up everything else.
Second Law of Hacking: first in, first out.
Shopkeepers accept creditcards, as long as you pay cash.
Snakes are often found under worthless objects.
Some monsters can be tamed. I once saw a hacker with a tame Dragon!
Speed Kills (The Doors)
Spinach, carrot, and a melon - a meal fit for a nurse!
Stay clear of the level of no return.
Suddenly the dungeon will collapse ...
Take a long worm from the rear, according to its mate it's a lot more fun.
Teleportation lessens your orientation.
The Jackal only eats bad food.
The Leprechaun Gold Tru$t is no division of the Magic Memory Vault.
The Leprechauns hide their treasure in a small hidden room.
The air is positively magic in here. Better wear a negative armor.
The best equipment for your work is, of course, the most expensive.
The emptiness of a ghost is too heavy to bear.
The longer the wand the better.
The secret of wands of Nothing Happens: try again!
The use of dynamite is dangerous.
There are monsters of softening penetration.
There are monsters of striking charity.
There have been people like you in here; their ghosts seek revenge on you.
There is a VIP-lounge on this level. Only first-class travellers admitted.
There is a big treasure hidden in the zoo!
There is a message concealed in each fortune cookie.
There is a trap on this level!
There is more magic in this cave than meets the eye.
There is no business like throw business.
There is no harm in praising a large dog.
There seem to be monsters of touching benevolence.
They say that a dagger hits.
They say that a dog avoids traps.
They say that a dog can be trained to fetch objects.
They say that a dog never steps on a cursed object.
They say that a spear will hit a Dragon.
They say that a spear will hit a Xorn.
They say that a spear will hit a neo-otyugh. (Do YOU know what that is?)
They say that a spear will hit an ettin.
They say that a two-handed sword misses.
They say that a unicorn might bring you luck.
They say that an elven cloak may be worn over your armor.
They say that an elven cloak protects against magic.
They say that dead lizards protect against a cockatrice.
They say that killing a shopkeeper brings bad luck.
They say that monsters never step on a scare monster scroll.
They say that only david can find the zoo!
They say that the use of dynamite is dangerous.
They say that there is a big treasure hidden in the zoo!
They say that there is a message concealed in each fortune cookie.
They say that there is a trap on this level!
They say that throwing food at a wild dog might tame him.
They say that you cannot trust scrolls of rumour.
They say that you need a key in order to open locked doors.
Third Law of Hacking: the last blow counts most.
This is the Leprechaun Law: every purse has a price.
Throwing food at a wild dog might tame him.
Tin openers are rare indeed.
To hit or not to hit, that is the question.
Travel fast, use some magic speed!
Tripe on its own is revolting,  but with onions it's delicious!
Try hacking in the wee hours: you will have more room.
Vampires hate garlic.
Visitors are requested not to apply genocide to shopkeepers.
WARNING from H.M. Govt:  Quaffing may be dangerous to your health.
Watch your steps on staircases.
Wear armor, going naked seems to offend public decency in here.
What do you think would be the use of a sword called "Orcrist" ?
When a piercer drops in on you, you will be tempted to hit the ceiling!
When in a shop, do as shopkeepers do.
When punished, watch your steps on the stairs!
Why would anybody in his sane mind engrave "Elbereth" ?
You are heading for head-stone for sure.
You are just the kind of bad food some monsters like to digest.
You can always wear an elven cloak.
You can't leave a shop through the back door: there ain't one!
You cannot trust scrolls of rumour.
You feel greedy and want more gold? Why don't you try digging?
You feel like someone is pulling your leg.
You may have a kick from kicking a little dog.
You might cut yourself on a long sword.
You need a key in order to open locked doors.
You want to regain strength? Two levels ahead is a guesthouse!
You offend Shai-Hulud by sheathing your crysknife without having drawn blood.
You'll need a spear if you want to attack a Dragon.
You've got to know how to put out a yellow light.
Zapping a wand of Nothing Happens doesn't harm you a bit.