[net.sources] hack mods

robert@gitpyr.UUCP (Robert Viduya) (01/21/85)

I've made a few mods to hack.  For a list, see the parent of this article.
I've made one more mod since I posted the original article and that was
a new command that let's you do selective inventories ("What scrolls do
I have?").  Here are the modified files in shar format (no, I'm not
posting the whole thing over again).  I spent about a day tracking down
all the changes I made to make the list of modified files.  However,
being human, I might have missed something.  If so, send me mail.

				robert

--------------------Decapitate Here------------------------
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	hack.cmdlist.c
#	hack.do.c
#	hack.invent.c
#	hack.main.c
#	hack.o_init.c
#	hack.read.c
#	hack.shk.c
#	hack.termcap.c
#	hack.topl.c
#	hack.tty.c
#	hack.wield.c
#	hack.zap.c
#	help
#	help.nr
#	hh
#	mklev.c
sed 's/^X//' << '--burp--' > hack.cmdlist.c
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
X
X#include	"config.h"
X#include	"def.objclass.h"
X#include	"def.func_tab.h"
X
Xint     doredraw (), doredotopl (), dodrop (), dodrink (), doread (),
X        dosearch (), doversion (), doweararm (), dowearring (),
X        doremarm (), doremring (), dopay (), doapply (), dosave (),
X        dowield (), ddoinv (), dozap (), ddocall (), dowhatis (), doengrave (),
X        dohelp (), doeat (), doddrop (), do_mname (), doidtrap (),
X        doprwep (), doprarm (), doprring (), dodiscovered (), dotypeinv ();
X#ifdef SHELL
Xint     dosh ();
X#endif SHELL
X#ifdef OPTIONS
Xint     doset ();
X#endif OPTIONS
Xint     doup (), dodown (), done1 (), donull ();
Xint     dothrow ();
Xstruct func_tab list[] = {
X    '\022', doredraw,
X    '\020', doredotopl,
X    'a', doapply,
X/*  'A' : UNUSED */
X/*  'b', 'B' : go sw */
X    'c', ddocall,
X    'C', do_mname,
X    'd', dodrop,
X    'D', doddrop,
X    'e', doeat,
X    'E', doengrave,
X/*  'f', 'F' : multiple go (might become 'fight') */
X/*  'g', 'G' : UNUSED */
X/*  'h', 'H' : go west */
X    'i', ddoinv,
X    'I', dotypeinv,
X/*  'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */
X#ifdef OPTIONS
X    'o', doset,
X#endif OPTIONS
X/*  'O' : UNUSED */
X    'p', dopay,
X    'P', dowearring,
X    'q', dodrink,
X    'Q', done1,
X    'r', doread,
X    'R', doremring,
X    's', dosearch,
X    'S', dosave,
X    't', dothrow,
X    'T', doremarm,
X/*  'u', 'U' : go ne */
X    'v', doversion,
X/*  'V' : UNUSED */
X    'w', dowield,
X    'W', doweararm,
X/*  'x', 'X' : UNUSED */
X/*  'y', 'Y' : go nw */
X    'z', dozap,
X/*  'Z' : UNUSED */
X    '<', doup,
X    '>', dodown,
X    '/', dowhatis,
X    '?', dohelp,
X#ifdef SHELL
X    '!', dosh,
X#endif SHELL
X    '.', donull,
X    ' ', donull,
X    '^', doidtrap,
X    '\\', dodiscovered,
X    WEAPON_SYM, doprwep,
X    ARMOR_SYM, doprarm,
X    RING_SYM, doprring,
X    0, 0, 0
X};
--burp--
sed 's/^X//' << '--burp--' > hack.do.c
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
X
X#include <stdio.h>
X#include <signal.h>
X#include <ctype.h>
X#include "config.h"
X#include "hack.h"
X#include "def.func_tab.h"
X
Xextern char *getenv (), *parse (), *getlogin (), *lowc (), *unctrl ();
Xextern int  float_down ();
Xextern char *nomovemsg;
Xextern struct obj  *splitobj (), *addinv ();
Xextern  boolean hmon ();
X
X/*	Routines to do various user commands */
X
Xint     done1 ();
X
Xdodrink ()
X{
X    register struct obj *otmp, *objs;
X    register struct monst  *mtmp;
X    register int    unkn = 0, nothing = 0;
X
X    otmp = getobj ("!", "drink");
X    if (!otmp)
X	return (0);
X    switch (otmp -> otyp) {
X	case POT_RESTORE_STRENGTH: 
X	    unkn++;
X	    pline ("Wow!  This makes you feel great!");
X	    if (u.ustr < u.ustrmax) {
X		u.ustr = u.ustrmax;
X		flags.botl = 1;
X	    }
X	    break;
X	case POT_BOOZE: 
X	    unkn++;
X	    pline ("Ooph!  This tastes like liquid fire!");
X	    Confusion += d (3, 8);
X	    /* the whiskey makes us feel better */
X	    if (u.uhp < u.uhpmax)
X		losehp (-1, "bottle of whiskey");
X	    if (!rn2 (4)) {
X		pline ("You pass out.");
X		multi = -rnd (15);
X		nomovemsg = "You awake with a headache.";
X	    }
X	    break;
X	case POT_INVISIBILITY: 
X	    if (Invis)
X		nothing++;
X	    else {
X		if (!Blind)
X		    pline ("Gee!  All of a sudden, you can't see yourself.");
X		else
X		    pline ("You feel rather airy."), unkn++;
X		newsym (u.ux, u.uy);
X	    }
X	    Invis += rn1 (15, 31);
X	    break;
X	case POT_FRUIT_JUICE: 
X	    pline ("This tastes like fruit juice.");
X	    lesshungry (20);
X	    break;
X	case POT_HEALING: 
X	    pline ("You begin to feel better.");
X	    flags.botl = 1;
X	    u.uhp += rnd (10);
X	    if (u.uhp > u.uhpmax)
X		u.uhp = ++u.uhpmax;
X	    if (Blind)
X		Blind = 1;		/* see on next move */
X	    if (Sick)
X		Sick = 0;
X	    break;
X	case POT_PARALYSIS: 
X	    pline ("Your feet are frozen to the floor!");
X	    nomul (-(rn1 (10, 25)));
X	    break;
X	case POT_MONSTER_DETECTION: 
X	    if (!fmon) {
X		pline ("You feel threatened.");
X		strange_feeling (otmp);
X		return (1);
X	    }
X	    else {
X		cls ();
X		for (mtmp = fmon; mtmp; mtmp = mtmp -> nmon)
X		    if (mtmp -> mx > 0)
X			at (mtmp -> mx, mtmp -> my, mtmp -> data -> mlet);
X		prme ();
X		pline ("You sense the presence of monsters.");
X		more ();
X		docrt ();
X	    }
X	    break;
X	case POT_OBJECT_DETECTION: 
X	    if (!fobj) {
X		pline ("You feel a pull downward.");
X		strange_feeling (otmp);
X		return (1);
X	    }
X	    else {
X		for (objs = fobj; objs; objs = objs -> nobj)
X		    if (objs -> ox != u.ux || objs -> oy != u.uy)
X			goto outobjmap;
X		pline ("You sense the presence of objects close nearby.");
X		break;
X	outobjmap: 
X		cls ();
X		for (objs = fobj; objs; objs = objs -> nobj)
X		    at (objs -> ox, objs -> oy, objs -> olet);
X		prme ();
X		pline ("You sense the presence of objects.");
X		more ();
X		docrt ();
X	    }
X	    break;
X	case POT_SICKNESS: 
X	    pline ("Yech! This stuff tastes like poison.");
X	    if (Poison_resistance)
X		pline ("(But in fact it was biologically contaminated orange juice.)");
X	    losestr (rn1 (4, 3));
X	    losehp (rnd (10), "poison potion");
X	    break;
X	case POT_CONFUSION: 
X	    if (!Confusion)
X		pline ("Huh, What?  Where am I?");
X	    else
X		nothing++;
X	    Confusion += rn1 (7, 16);
X	    break;
X	case POT_GAIN_STRENGTH: 
X	    pline ("Wow do you feel strong!");
X	    if (u.ustr == 118)
X		break;
X	    if (u.ustr > 17)
X		u.ustr += rnd (118 - u.ustr);
X	    else
X		u.ustr++;
X	    if (u.ustr > u.ustrmax)
X		u.ustrmax = u.ustr;
X	    flags.botl = 1;
X	    break;
X	case POT_SPEED: 
X	    if (Wounded_legs) {
X		if ((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
X		    pline ("Your legs feel somewhat better.");
X		else
X		    pline ("Your leg feels somewhat better.");
X		Wounded_legs = 0;
X		unkn++;
X		break;
X	    }
X	    if (!(Fast & ~INTRINSIC))
X		pline ("You are suddenly moving much faster.");
X	    else
X		pline ("Your legs get new energy."), unkn++;
X	    Fast += rn1 (10, 100);
X	    break;
X	case POT_BLINDNESS: 
X	    if (!Blind)
X		pline ("A cloud of darkness falls upon you.");
X	    else
X		nothing++;
X	    Blind += rn1 (100, 250);
X	    seeoff (0);
X	    break;
X	case POT_GAIN_LEVEL: 
X	    pluslvl ();
X	    break;
X	case POT_EXTRA_HEALING: 
X	    pline ("You feel much better.");
X	    flags.botl = 1;
X	    u.uhp += d (2, 20) + 1;
X	    if (u.uhp > u.uhpmax)
X		u.uhp = (u.uhpmax += 2);
X	    if (Blind)
X		Blind = 1;
X	    if (Sick)
X		Sick = 0;
X	    break;
X	case POT_LEVITATION: 
X	    if (!Levitation)
X		float_up ();
X	    else
X		nothing++;
X	    Levitation += rnd (100);
X	    u.uprops[PROP (RIN_LEVITATION)].p_tofn = float_down;
X	    break;
X	default: 
X	    pline ("What a funny potion! (%d)", otmp -> otyp);
X	    impossible ();
X	    return (0);
X    }
X    if (nothing) {
X	unkn++;
X	pline ("You have a peculiar feeling for a moment, then it passes.");
X    }
X    if (otmp -> dknown && !objects[otmp -> otyp].oc_name_known) {
X	if (!unkn) {
X	    objects[otmp -> otyp].oc_name_known = 1;
X	    u.urexp += 10;
X	}
X	else
X	    if (!objects[otmp -> otyp].oc_uname)
X		docall (otmp);
X    }
X    useup (otmp);
X    return (1);
X}
X
Xpluslvl ()
X{
X    register    num;
X
X    pline ("You feel more experienced.");
X    num = rnd (10);
X    u.uhpmax += num;
X    u.uhp += num;
X    u.uexp = (10 * pow (u.ulevel - 1)) + 1;
X    pline ("Welcome to level %d.", ++u.ulevel);
X    flags.botl = 1;
X}
X
Xstrange_feeling (obj)
Xregister struct obj *obj;
X{
X    if (!objects[obj -> otyp].oc_name_known && !objects[obj -> otyp].oc_uname)
X	docall (obj);
X    useup (obj);
X}
X
Xdodrop ()
X{
X    register struct obj *obj;
X
X    obj = getobj ("0$#", "drop");
X    if (!obj)
X	return (0);
X    if (obj -> olet == '$') {
X	if (obj -> quan == 0)
X	    pline ("You didn't drop any gold pieces.");
X	else {
X	    mkgold ((int) obj -> quan, u.ux, u.uy);
X	    pline ("You dropped %u gold piece%s.", obj -> quan, plur (obj -> quan));
X	    if (Invis)
X		newsym (u.ux, u.uy);
X	}
X	free ((char *) obj);
X	return (1);
X    }
X    return (drop (obj));
X}
X
Xdrop (obj)
Xregister struct obj *obj;
X{
X    if (obj -> owornmask & (W_ARMOR | W_RING)) {
X	pline ("You cannot drop something you are wearing.");
X	return (0);
X    }
X    if (obj == uwep) {
X	if (uwep -> cursed) {
X	    pline ("Your weapon is welded to your hand!");
X	    return (0);
X	}
X	setuwep ((struct obj   *) 0);
X    }
X    pline ("You dropped %s.", doname (obj));
X    dropx (obj);
X    return (1);
X}
X
Xdropx (obj)
Xregister struct obj *obj;
X{
X    if (obj -> otyp == CRYSKNIFE)
X	obj -> otyp = WORM_TOOTH;
X    freeinv (obj);
X    obj -> ox = u.ux;
X    obj -> oy = u.uy;
X    obj -> nobj = fobj;
X    fobj = obj;
X    if (Invis)
X	newsym (u.ux, u.uy);
X    subfrombill (obj);
X    stackobj (obj);
X}
X
X/* drop several things */
Xdoddrop ()
X{
X    return (ggetobj ("drop", drop, 0));
X}
X
Xrhack (cmd)
Xregister char  *cmd;
X{
X    register struct func_tab   *tlist = list;
X    boolean firsttime = FALSE;
X    register    res;
X
X    if (!cmd) {
X	firsttime = TRUE;
X	flags.nopick = 0;
X	cmd = parse ();
X    }
X    if (!*cmd || *cmd == 0377)
X	return;				/* probably we just had an interrupt */
X    if (movecm (cmd)) {
Xwalk: 
X	if (multi)
X	    flags.mv = 1;
X	domove ();
X	return;
X    }
X    if (movecm (lowc (cmd))) {
X	flags.run = 1;
Xrush: 
X	if (firsttime) {
X	    if (!multi)
X		multi = COLNO;
X	    u.last_str_turn = 0;
X	}
X	flags.mv = 1;
X#ifdef QUEST
X	if (flags.run >= 4)
X	    finddir ();
X	if (firsttime) {
X	    u.ux0 = u.ux + u.dx;
X	    u.uy0 = u.uy + u.dy;
X	}
X#endif QUEST
X	domove ();
X	return;
X    }
X    if ((*cmd == 'f' && movecm (cmd + 1)) || movecm (unctrl (cmd))) {
X	flags.run = 2;
X	goto rush;
X    }
X    if (*cmd == 'F' && movecm (lowc (cmd + 1))) {
X	flags.run = 3;
X	goto rush;
X    }
X    if (*cmd == 'm' && movecm (cmd + 1)) {
X	flags.run = 0;
X	flags.nopick = 1;
X	goto walk;
X    }
X    if (*cmd == 'M' && movecm (lowc (cmd + 1))) {
X	flags.run = 1;
X	flags.nopick = 1;
X	goto rush;
X    }
X#ifdef QUEST
X    if (*cmd == cmd[1] && (*cmd == 'f' || *cmd == 'F')) {
X	flags.run = 4;
X	if (*cmd == 'F')
X	    flags.run += 2;
X	if (cmd[2] == '-')
X	    flags.run += 1;
X	goto rush;
X    }
X#endif QUEST
X    while (tlist -> f_char) {
X	if (*cmd == tlist -> f_char) {
X	    res = (*(tlist -> f_funct)) (0);
X	    if (!res) {
X		flags.move = 0;
X		multi = 0;
X	    }
X	    return;
X	}
X	tlist++;
X    }
X    pline ("Unknown command '%s'", cmd);
X    multi = flags.move = 0;
X}
X
Xdoredraw ()
X{
X    docrt ();
X    return (0);
X}
X
Xdohelp ()
X{
X    FILE * f;
X    char    line[100], c;
X    int     count;
X    char    done;
X
X    pline ("Long or short help? ");
X    while (((c = readchar ()) != 'l') && (c != 's') && (c != '\033'))
X	bell ();
X    if (c == '\033')
X	return (0);
X    if ((f = fopen ((c == 'l' ? "help" : "hh"), "r")) == NULL) {
X	pline ("Can't get help");
X	return (0);
X    }
X    count = 1;
X    done = 0;
X    while (((fgets (line, 100, f)) != NULL) && (!done)) {
X	curs (1, count);
X	cl_end ();
X	puts (line);
X	count++;
X	if (count >= ROWNO + 1) {
X	    curs (1, count);
X	    cl_end ();
X	    curs (1, ROWNO + 2);
X	    cl_end ();
X	    standoutbeg ();
X	    fputs ("--More--", stdout);
X	    standoutend ();
X	    while (((c = readchar ()) != ' ') && (c != 'q'))
X		bell ();
X	    done = (c == 'q');
X	    count = 1;
X	}
X    }
X    (void) fclose (f);
X    curs (1, count);
X    cl_eos ();
X    curs (1, ROWNO + 2);
X    standoutbeg ();
X    fputs ("Hit space to continue...", stdout);
X    standoutend ();
X    while (readchar () != ' ')
X	bell ();
X    docrt ();
X    return (0);
X}
X
X#ifdef SHELL
Xdosh ()
X{
X    register char  *str;
X    char    hackpath[128];
X
X    (void) getwd (hackpath);
X    if (child (0)) {
X	(void) chdir (getenv ("HOME"));
X	if (str = getenv ("SHELL"))
X	    execl (str, str, (char *) 0);
X	if (strcmp ("player", getlogin ()))
X	    execl ("/bin/sh", "sh", (char *) 0);
X	pline ("sh: cannot execute.");
X	exit (1);
X    }
X    (void) chdir (hackpath);
X    return (0);
X}
X#endif SHELL
X
X#ifdef BSD
X#include	<sys/wait.h>
X#else
X#include	<wait.h>
X#endif BSD
X
Xchild (wt)
X{
X    register int    f = fork ();
X    if (f == 0) {			/* child */
X	settty ((char *) 0);
X	(void) setuid (getuid ());
X	(void) setgid (getgid ());
X	return (1);
X    }
X    if (f == -1) {			/* cannot fork */
X	pline ("Fork failed. Try again.");
X	return (0);
X    }
X    /* fork succeeded; wait for child to exit */
X    (void) signal (SIGINT, SIG_IGN);
X    (void) signal (SIGQUIT, SIG_IGN);
X    (void) wait ((union wait *) 0);
X    setctty ();
X    (void) signal (SIGINT, done1);
X#ifdef WIZARD
X    if (wizard)
X	(void) signal (SIGQUIT, SIG_DFL);
X#endif WIZARD
X    if (wt)
X	getret ();
X    start_screen ();
X    docrt ();
X    return (0);
X}
X
Xdodown ()
X{
X    if (u.ux != xdnstair || u.uy != ydnstair) {
X	pline ("You can't go down here.");
X	return (0);
X    }
X    if (u.ustuck) {
X	pline ("You are being held, and cannot go down.");
X	return (1);
X    }
X    if (Levitation) {
X	pline ("You're floating high above the stairs.");
X	return (0);
X    }
X
X    goto_level (dlevel + 1, TRUE);
X    return (1);
X}
X
Xdoup ()
X{
X    if (u.ux != xupstair || u.uy != yupstair) {
X	pline ("You can't go up here.");
X	return (0);
X    }
X    if (u.ustuck) {
X	pline ("You are being held, and cannot go up.");
X	return (1);
X    }
X    if (inv_weight () + 5 > 0) {
X	pline ("Your load is too heavy to climb the stairs.");
X	return (1);
X    }
X
X    goto_level (dlevel - 1, TRUE);
X    return (1);
X}
X
Xgoto_level (newlevel, at_stairs)
Xregister int    newlevel;
Xregister    boolean at_stairs;
X{
X    register    fd;
X    register    boolean up = (newlevel < dlevel);
X
X    if (newlevel <= 0)
X	done ("escaped");		/* in fact < 0 is impossible */
X    if (newlevel == dlevel)
X	return;				/* this cannot happen either */
X
X    glo (dlevel);
X    fd = creat (lock, FMASK);
X    if (fd < 0) {
X	/* 
X	 * This is not quite impossible: e.g., we may have
X	 * exceeded our quota. If that is the case then we
X	 * cannot leave this level, and cannot save either.
X	 */
X	pline ("A mysterious force prevents you from going %d.",
X		up ? "up" : "down");
X	return;
X    }
X
X    if (Punished)
X	unplacebc ();
X    keepdogs ();
X    seeoff (1);
X    flags.nscrinh = 1;
X    u.ux = FAR;				/* hack */
X    (void) inshop ();			/* probably was a trapdoor */
X
X    savelev (fd);
X    (void) close (fd);
X
X    dlevel = newlevel;
X    if (maxdlevel < dlevel)
X	maxdlevel = dlevel;
X    glo (dlevel);
X    if ((fd = open (lock, 0)) < 0)
X	mklev ();
X    else {
X	(void) getlev (fd);
X	(void) close (fd);
X    }
X
X    if (at_stairs) {
X	if (up) {
X	    u.ux = xdnstair;
X	    u.uy = ydnstair;
X	    if (!u.ux) {		/* entering a maze from below? */
X		u.ux = xupstair;	/* this will confuse the player! */
X		u.uy = yupstair;
X	    }
X	    if (Punished) {
X		pline ("With great effort you climb the stairs");
X		placebc (1);
X	    }
X	}
X	else {
X	    u.ux = xupstair;
X	    u.uy = yupstair;
X	    if (inv_weight () + 5 > 0 || Punished) {
X		pline ("You fall down the stairs.");
X		losehp (rnd (3), "fall");
X		if (Punished) {
X		    if (uwep != uball && rn2 (3)) {
X			pline ("... and are hit by the iron ball");
X			losehp (rnd (20), "iron ball");
X		    }
X		    placebc (1);
X		}
X		selftouch ("Falling, you");
X	    }
X	}
X    }
X    else {				/* trapdoor or level_tele */
X	do {
X	    u.ux = rnd (COLNO - 1);
X	    u.uy = rn2 (ROWNO);
X	} while (levl[u.ux][u.uy].typ != ROOM ||
X		m_at (u.ux, u.uy));
X	if (Punished) {
X	    if (uwep != uball && !up /* %% */ && rn2 (5)) {
X		pline ("The iron ball falls on your head.");
X		losehp (rnd (25), "iron ball");
X	    }
X	    placebc (1);
X	}
X	selftouch ("Falling, you");
X    }
X    (void) inshop ();
X#ifdef TRACK
X    initrack ();
X#endif TRACK
X
X    losedogs ();
X    flags.nscrinh = 0;
X    setsee ();
X    docrt ();
X    pickup ();
X    read_engr_at (u.ux, u.uy);
X}
X
Xdonull ()
X{
X    return (1);			/* Do nothing, but let other things happen */
X}
X
Xstruct monst   *bhit (), *boomhit ();
X
Xdothrow ()
X{
X    register struct obj *obj;
X    register struct monst  *mon;
X    register    tmp;
X
X    obj = getobj ("#)", "throw");	/* it is also possible to throw food */
X    /* (or jewels, or iron balls ... ) */
X    if (!obj || !getdir ())
X	return (0);
X    if (obj -> owornmask & (W_ARMOR | W_RING)) {
X	pline ("You can't throw something you are wearing");
X	return (0);
X    }
X    if (obj == uwep) {
X	if (obj -> cursed) {
X	    pline ("Your weapon is welded to your hand");
X	    return (1);
X	}
X	if (obj -> quan > 1)
X	    setuwep (splitobj (obj, 1));
X	else
X	    setuwep ((struct obj   *) 0);
X    }
X    else
X	if (obj -> quan > 1)
X	    (void) splitobj (obj, 1);
X    freeinv (obj);
X    if (u.uswallow) {
X	mon = u.ustuck;
X	bhitpos.x = mon -> mx;
X	bhitpos.y = mon -> my;
X    }
X    else
X	if (obj -> otyp == BOOMERANG) {
X	    mon = boomhit (u.dx, u.dy);
X	    /* boomhit delivers -1 if the thing was caught */
X	    if ((int) mon == -1) {
X		(void) addinv (obj);
X		return (1);
X	    }
X	}
X	else
X	    mon = bhit (u.dx, u.dy,
X		    (!Punished || obj != uball) ? 8 :
X		    !u.ustuck ? 5 : 1,
X		    obj -> olet);
X    if (mon) {
X	/* awake monster if sleeping */
X	wakeup (mon);
X
X	if (obj -> olet == WEAPON_SYM) {
X	    tmp = -1 + u.ulevel + mon -> data -> ac + abon ();
X	    if (obj -> otyp < ROCK) {
X		if (!uwep ||
X			uwep -> otyp != obj -> otyp + (BOW - ARROW))
X		    tmp -= 4;
X		else {
X		    tmp += uwep -> spe;
X		}
X	    }
X	    else
X		if (obj -> otyp == BOOMERANG)
X		    tmp += 4;
X	    tmp += obj -> spe;
X	    if (u.uswallow || tmp >= rnd (20)) {
X		if (hmon (mon, obj, 1) == TRUE) {
X		    /* mon still alive */
X#ifndef NOWORM
X		    cutworm (mon, bhitpos.x, bhitpos.y, obj -> otyp);
X#endif NOWORM
X		}
X		else
X		    mon = 0;
X		/* weapons thrown disappear sometimes */
X		if (obj -> otyp < BOOMERANG && rn2 (3)) {
X		    /* check bill; free */
X		    obfree (obj, (struct obj   *) 0);
X		    return (1);
X		}
X	    }
X	    else
X		miss (objects[obj -> otyp].oc_name, mon);
X	}
X	else
X	    if (obj -> otyp == HEAVY_IRON_BALL) {
X		tmp = -1 + u.ulevel + mon -> data -> ac + abon ();
X		if (!Punished || obj != uball)
X		    tmp += 2;
X		if (u.utrap)
X		    tmp -= 2;
X		if (u.uswallow || tmp >= rnd (20)) {
X		    if (hmon (mon, obj, 1) == FALSE)
X			mon = 0;	/* he died */
X		}
X		else
X		    miss ("iron ball", mon);
X	    }
X	    else {
X		if (cansee (bhitpos.x, bhitpos.y))
X		    pline ("You miss %s.", monnam (mon));
X		else
X		    pline ("You miss it.");
X		if (obj -> olet == FOOD_SYM && mon -> data -> mlet == 'd')
X		    if (tamedog (mon, obj))
X			return (1);
X		if (obj -> olet == GEM_SYM && mon -> data -> mlet == 'u') {
X		    if (obj -> dknown && objects[obj -> otyp].oc_name_known) {
X			if (objects[obj -> otyp].g_val > 0) {
X			    u.uluck += 5;
X			    goto valuable;
X			}
X			else {
X			    pline ("%s is not interested in your junk.",
X				    Monnam (mon));
X			}
X		    }
X		    else {		/* value unknown to @ */
X			u.uluck++;
X		valuable: 
X			pline ("%s graciously accepts your gift.",
X				Monnam (mon));
X			mpickobj (mon, obj);
X			rloc (mon);
X			return (1);
X		    }
X		}
X	    }
X    }
X    obj -> ox = bhitpos.x;
X    obj -> oy = bhitpos.y;
X    obj -> nobj = fobj;
X    fobj = obj;
X    /* prevent him from throwing articles to the exit and escaping */
X    /* subfrombill(obj); */
X    stackobj (obj);
X    if (Punished && obj == uball &&
X	    (bhitpos.x != u.ux || bhitpos.y != u.uy)) {
X	freeobj (uchain);
X	unpobj (uchain);
X	if (u.utrap) {
X	    if (u.utraptype == TT_PIT)
X		pline ("The ball pulls you out of the pit!");
X	    else {
X		register int    side =
X		                rn2 (3) ? LEFT_SIDE : RIGHT_SIDE;
X		pline ("The ball pulls you out of the bear trap.");
X		pline ("Your %s leg is severely damaged.",
X			(side == LEFT_SIDE) ? "left" : "right");
X		Wounded_legs |= side + rnd (1000);
X		losehp (2, "thrown ball");
X	    }
X	    u.utrap = 0;
X	}
X	unsee ();
X	uchain -> nobj = fobj;
X	fobj = uchain;
X	u.ux = uchain -> ox = bhitpos.x - u.dx;
X	u.uy = uchain -> oy = bhitpos.y - u.dy;
X	setsee ();
X	(void) inshop ();
X    }
X    if (cansee (bhitpos.x, bhitpos.y))
X	prl (bhitpos.x, bhitpos.y);
X    return (1);
X}
X
Xgetdir ()
X{
X    char    buf[2];
X    pline ("What direction?");
X    buf[0] = readchar ();
X    buf[1] = 0;
X    return (movecm (buf));
X}
X
X/* split obj so that it gets size num */
X/* remainder is put in the object structure delivered by this call */
Xstruct obj *
Xsplitobj (obj, num)
Xregister struct obj *obj;
Xregister int    num;
X{
X    register struct obj *otmp;
X    otmp = newobj (0);
X    *otmp = *obj;			/* copies whole structure */
X    otmp -> o_id = flags.ident++;
X    otmp -> onamelth = 0;
X    obj -> quan = num;
X    obj -> owt = weight (obj);
X    otmp -> quan -= num;
X    otmp -> owt = weight (otmp);	/* -= obj->owt ? */
X    obj -> nobj = otmp;
X    if (obj -> unpaid)
X	splitbill (obj, otmp);
X    return (otmp);
X}
X
Xchar   *
Xlowc (str)
Xregister char  *str;
X{
X    static char buf[2];
X
X    if (*str >= 'A' && *str <= 'Z')
X	*buf = *str + 'a' - 'A';
X    else
X	*buf = *str;
X    buf[1] = 0;
X    return (buf);
X}
X
Xchar   *
Xunctrl (str)
Xregister char  *str;
X{
X    static char buf[2];
X    if (*str >= ('A' & 037) && *str <= ('Z' & 037))
X	*buf = *str + 0140;
X    else
X	*buf = *str;
X    buf[1] = 0;
X    return (buf);
X}
--burp--
sed 's/^X//' << '--burp--' > hack.invent.c
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
X
X#include	"hack.h"
X#include	<stdio.h>
Xextern struct obj  *splitobj ();
Xextern char morc;
X#ifndef NOWORM
X#include	"def.wseg.h"
X
Xextern struct wseg *wsegs[32];
X#endif NOWORM
X
Xstruct obj *
Xaddinv (object)
Xregister struct obj *object;
X{
X    register struct obj *otmp, *potmp;
X
X    if (!invent) {	/* empty list */
X	invent = object;
X	object -> nobj = 0;
X    }
X    else {
X	potmp = 0;
X	otmp = invent;
X	/* search for matching type or greater */
X	while ((otmp) && (otmp -> olet < object -> olet)) { 
X	    potmp = otmp;
X	    otmp = otmp -> nobj;
X	}
X	if (!otmp) {	/* ran off end */
X	    potmp -> nobj = object;
X	    object -> nobj = 0;
X	}
X	else if (otmp -> olet > object -> olet) {	/* new obj type */
X	    if (!potmp) {	/* top of list */
X		object -> nobj = invent;
X		invent = object;
X	    }
X	    else {
X		object -> nobj = otmp;
X		potmp -> nobj = object;
X	    }
X	}
X	else {		/* must be == */
X	    while ((otmp) && (otmp -> olet == object -> olet)) {
X		if (merged (otmp, object, 0))
X		    return (otmp);
X		else {
X		    potmp = otmp;
X		    otmp = otmp -> nobj;
X		}
X	    }
X	    /* not merged - insert after */
X	    object -> nobj = otmp;
X	    potmp -> nobj = object;
X	}
X    }
X    return (object);
X}
X
Xuseup (obj)
Xregister struct obj *obj;
X{
X    if (obj -> quan > 1) {
X	obj -> quan--;
X	obj -> owt = weight (obj);
X    }
X    else {
X	setnotworn (obj);
X	freeinv (obj);
X	obfree (obj, (struct obj   *) 0);
X    }
X}
X
Xfreeinv (obj)
Xregister struct obj  *obj;
X{
X    register struct obj *otmp;
X    if (obj == invent)
X	invent = invent -> nobj;
X    else {
X	for (otmp = invent; otmp -> nobj != obj; otmp = otmp -> nobj)
X	    if (!otmp -> nobj)
X		panic ("freeinv");
X	otmp -> nobj = obj -> nobj;
X    }
X}
X
X/* destroy object in fobj chain (if unpaid, it remains on the bill) */
Xdelobj (obj)
Xregister struct obj   *obj;
X{
X    freeobj (obj);
X    unpobj (obj);
X    obfree (obj, (struct obj   *) 0);
X}
X
X/* unlink obj from chain starting with fobj */
Xfreeobj (obj)
Xregister struct obj  *obj;
X{
X    register struct obj *otmp;
X
X    if (obj == fobj)
X	fobj = fobj -> nobj;
X    else {
X	for (otmp = fobj; otmp -> nobj != obj; otmp = otmp -> nobj)
X	    if (!otmp)
X		panic ("error in freeobj");
X	otmp -> nobj = obj -> nobj;
X    }
X}
X
X/* Note: freegold throws away its argument! */
Xfreegold (gold)
Xregister struct gen *gold;
X{
X    register struct gen *gtmp;
X
X    if (gold == fgold)
X	fgold = gold -> ngen;
X    else {
X	for (gtmp = fgold; gtmp -> ngen != gold; gtmp = gtmp -> ngen)
X	    if (!gtmp)
X		panic ("error in freegold");
X	gtmp -> ngen = gold -> ngen;
X    }
X    free ((char *) gold);
X}
X
Xdeltrap (trap)
Xregister struct gen *trap;
X{
X    register struct gen *gtmp;
X
X    if (trap == ftrap)
X	ftrap = ftrap -> ngen;
X    else {
X	for (gtmp = ftrap; gtmp -> ngen != trap; gtmp = gtmp -> ngen);
X	gtmp -> ngen = trap -> ngen;
X    }
X    free ((char *) trap);
X}
X
Xstruct wseg *m_atseg;
X
Xstruct monst   *
Xm_at (x, y)
Xregister    x, y;
X{
X    register struct monst  *mtmp;
X#ifndef NOWORM
X    register struct wseg   *wtmp;
X#endif NOWORM
X
X    m_atseg = 0;
X    for (mtmp = fmon; mtmp; mtmp = mtmp -> nmon) {
X	if (mtmp -> mx == x && mtmp -> my == y)
X	    return (mtmp);
X#ifndef NOWORM
X	if (mtmp -> wormno) {
X	    for (wtmp = wsegs[mtmp -> wormno]; wtmp; wtmp = wtmp -> nseg)
X		if (wtmp -> wx == x && wtmp -> wy == y) {
X		    m_atseg = wtmp;
X		    return (mtmp);
X		}
X	}
X#endif NOWORM
X    }
X    return (0);
X}
X
Xstruct obj *
Xo_at (x, y)
Xregister    x, y;
X{
X    register struct obj *otmp;
X
X    for (otmp = fobj; otmp; otmp = otmp -> nobj)
X	if (otmp -> ox == x && otmp -> oy == y)
X	    return (otmp);
X    return (0);
X}
X
Xstruct obj *
Xsobj_at (n, x, y)
Xregister    n, x, y;
X{
X    register struct obj *otmp;
X
X    for (otmp = fobj; otmp; otmp = otmp -> nobj)
X	if (otmp -> ox == x && otmp -> oy == y && otmp -> otyp == n)
X	    return (otmp);
X    return (0);
X}
X
Xcarried (obj)
Xregister struct obj  *obj;
X{
X    register struct obj *otmp;
X    for (otmp = invent; otmp; otmp = otmp -> nobj)
X	if (otmp == obj)
X	    return (1);
X    return (0);
X}
X
Xstruct obj *
Xo_on (id, objchn)
Xunsigned int  id;
Xregister struct obj *objchn;
X{
X    while (objchn) {
X	if (objchn -> o_id == id)
X	    return (objchn);
X	objchn = objchn -> nobj;
X    }
X    return ((struct obj *) 0);
X}
X
Xstruct gen *
Xg_at (x, y, ptr)
Xregister    x, y;
Xregister struct gen *ptr;
X{
X    while (ptr) {
X	if (ptr -> gx == x && ptr -> gy == y)
X	    return (ptr);
X	ptr = ptr -> ngen;
X    }
X    return (0);
X}
X
X/* getobj returns:
X	struct obj *xxx:	object to do something with.
X	0				error return: no object.
X	-1			explicitly no object (as in w-).
X*/
Xstruct obj *
Xgetobj (let, word)
Xregister char  *let, *word;
X{
X    register struct obj *otmp;
X    register char   ilet, ilet1, ilet2;
X    char    buf[BUFSZ];
X    char    lets[BUFSZ];
X    register int    foo = 0, foo2, cnt;
X    register char  *bp = buf;
X    xchar allowcnt = 0;			/* 0, 1 or 2 */
X    boolean allowgold = FALSE;
X    boolean allowall = FALSE;
X    boolean allownone = FALSE;
X    xchar foox = 0;
X
X    if (*let == '0')
X	let++, allowcnt = 1;
X    if (*let == '$')
X	let++, allowgold = TRUE;
X    if (*let == '#')
X	let++, allowall = TRUE;
X    if (*let == '-')
X	let++, allownone = TRUE;
X    if (allownone)
X	*bp++ = '-';
X    if (allowgold)
X	*bp++ = '$';
X    if (bp[-1] == '-')
X	*bp++ = ' ';
X
X    ilet = 'a';
X    for (otmp = invent; otmp; otmp = otmp -> nobj) {
X	if (!*let || index (let, otmp -> olet)) {
X	    bp[foo++] = ilet;
X	    /* ugly check: remove inappropriate things */
X	    if ((!strcmp (word, "take off") &&
X			!(otmp -> owornmask & (W_ARMOR - W_ARM2)))
X		    || (!strcmp (word, "wear") &&
X			(otmp -> owornmask & (W_ARMOR | W_RING)))
X		    || (!strcmp (word, "wield") &&
X			(otmp -> owornmask & W_WEP))) {
X		foo--;
X		foox++;
X	    }
X	}
X	if (ilet == 'z')
X	    ilet = 'A';
X	else
X	    ilet++;
X    }
X    bp[foo] = 0;
X    if (foo == 0 && bp > buf && bp[-1] == ' ')
X	*--bp = 0;
X    (void) strcpy (lets, bp);		/* necessary since we destroy buf */
X    if (foo > 5) {			/* compactify string */
X	foo = foo2 = 1;
X	ilet2 = bp[0];
X	ilet1 = bp[1];
X	while (ilet = bp[++foo2] = bp[++foo]) {
X	    if (ilet == ilet1 + 1) {
X		if (ilet1 == ilet2 + 1)
X		    bp[foo2 - 1] = ilet1 = '-';
X		else
X		    if (ilet2 == '-') {
X			bp[--foo2] = ++ilet1;
X			continue;
X		    }
X	    }
X	    ilet2 = ilet1;
X	    ilet1 = ilet;
X	}
X    }
X    if (!foo && !allowall && !allowgold && !allownone) {
X	pline ("You don't have anything %sto %s.",
X		foox ? "else " : "", word);
X	return (0);
X    }
X    for (;;) {
X	if (!buf[0])
X	    pline ("What do you want to %s [*]? ", word);
X	else
X	    pline ("What do you want to %s [%s or ?*]? ",
X		    word, buf);
X
X	cnt = 0;
X	ilet = readchar ();
X	while (digit (ilet) && allowcnt) {
X	    cnt = 10 * cnt + (ilet - '0');
X	    allowcnt = 2;		/* signal presence of cnt */
X	    ilet = readchar ();
X	}
X	if (digit (ilet)) {
X	    pline ("No count allowed with this command.");
X	    continue;
X	}
X	if (ilet == '\033' || ilet == ' ' || ilet == '\n')
X	    return ((struct obj *) 0);
X	if (ilet == '-') {
X	    return ((struct obj *) (allownone ? -1 : 0));
X	}
X	if (ilet == '$') {
X	    if (!allowgold) {
X		pline ("You cannot %s gold.", word);
X		continue;
X	    }
X	    otmp = newobj (0);
X	    /* should set o_id etc. but otmp will be freed soon */
X	    otmp -> olet = '$';
X	    if (allowcnt == 2 && cnt < u.ugold)
X		u.ugold -= cnt;
X	    else {
X		cnt = u.ugold;
X		u.ugold = 0;
X	    }
X	    flags.botl = 1;
X	    otmp -> quan = cnt;
X	    return (otmp);
X	}
X	if (ilet == '?') {
X	    doinv (lets);
X	    if (!(ilet = morc))
X		continue;
X	    /* he typed a letter (not a space) to more() */
X	}
X	else
X	    if (ilet == '*') {
X		doinv ("");
X		if (!(ilet = morc))
X		    continue;
X		/* ... */
X	    }
X	if (ilet >= 'A' && ilet <= 'Z')
X	    ilet += 'z' - 'A' + 1;
X	ilet -= 'a';
X	for (otmp = invent; otmp && ilet; ilet--, otmp = otmp -> nobj);
X	if (!otmp) {
X	    pline ("You don't have that object.");
X	    continue;
X	}
X	if (cnt < 0 || otmp -> quan < cnt) {
X	    pline ("You don't have that many! [You have %d]"
X		    ,otmp -> quan);
X	    continue;
X	}
X	break;
X    }
X    if (!allowall && let && !index (let, otmp -> olet)) {
X	pline ("That is a silly thing to %s.", word);
X	return (0);
X    }
X    if (allowcnt == 2) {		/* cnt given */
X	if (cnt == 0)
X	    return (0);
X	if (cnt != otmp -> quan) {
X	    register struct obj *obj;
X	    obj = splitobj (otmp, cnt);
X	    if (otmp == uwep)
X		setuwep (obj);
X	}
X    }
X    return (otmp);
X}
X
Xckunpaid (otmp)
Xregister struct obj *otmp;
X{
X    return (otmp -> unpaid);
X}
X
X/* interactive version of getobj */
X/* used for Drop and Identify */
Xggetobj (word, fn, max)
Xchar   *word;
Xint     (*fn) (), max;
X{
X    char    buf[BUFSZ];
X    register char  *ip;
X    register char   sym;
X    register int    oletct = 0, iletct = 0;
X    register    boolean allflag = FALSE;
X    char    olets[20], ilets[20];
X    int     (*ckfn) () = (int (*) ()) 0;
X    if (!invent) {
X	pline ("You have nothing to %s.", word);
X	return (0);
X    }
X    else {
X	register struct obj *otmp = invent;
X	register int    uflg = 0;
X
X	ilets[0] = 0;
X	while (otmp) {
X	    if (!index (ilets, otmp -> olet)) {
X		ilets[iletct++] = otmp -> olet;
X		ilets[iletct] = 0;
X	    }
X	    if (otmp -> unpaid)
X		uflg = 1;
X	    otmp = otmp -> nobj;
X	}
X	ilets[iletct++] = ' ';
X	if (uflg)
X	    ilets[iletct++] = 'u';
X	ilets[iletct++] = 'a';
X	ilets[iletct] = 0;
X    }
X    pline ("What kinds of thing do you want to %s? [%s] ",
X	    word, ilets);
X    getlin (buf);
X    ip = buf;
X    olets[0] = 0;
X    while (sym = *ip++) {
X	if (sym == ' ')
X	    continue;
X	if (sym == 'a')
X	    allflag = TRUE;
X	else
X	    if (sym == 'u')
X		ckfn = ckunpaid;
X	    else
X		if (index ("!%?[()=*/\"0", sym)) {
X		    if (!index (olets, sym)) {
X			olets[oletct++] = sym;
X			olets[oletct] = 0;
X		    }
X		}
X		else
X		    pline ("You don't have any %c's.", sym);
X    }
X    return askchain (invent, olets, allflag, fn, ckfn, max);
X}
X
X/* Walk through the chain starting at objchn and ask for all objects
X   with olet in olets (if nonNULL) and satisfying ckfn (if nonNULL)
X   whether the action in question (i.e., fn) has to be performed.
X   If allflag then no questions are asked. Max gives the max nr of
X   objects treated.
X */
Xaskchain (objchn, olets, allflag, fn, ckfn, max)
Xstruct obj *objchn;
Xregister char  *olets;
Xint     allflag;
Xint     (*fn) (), (*ckfn) ();
Xint     max;
X{
X    register struct obj *otmp, *otmp2;
X    register char   sym, ilet;
X    register int    cnt = 0;
X    ilet = 'a' - 1;
X    for (otmp = objchn; otmp; otmp = otmp2) {
X	if (ilet == 'z')
X	    ilet = 'A';
X	else
X	    ilet++;
X	otmp2 = otmp -> nobj;
X	if (olets && *olets && !index (olets, otmp -> olet))
X	    continue;
X	if (ckfn && !(*ckfn) (otmp))
X	    continue;
X	if (!allflag) {
X	    prname (otmp, ilet, 1);
X	    addtopl (" (ynaq)? ");
X	    sym = readchar ();
X	}
X	else
X	    sym = 'y';
X
X	switch (sym) {
X	    case 'a': 
X		allflag = 1;
X	    case 'y': 
X		cnt += (*fn) (otmp);
X		if (--max == 0)
X		    goto ret;
X	    case 'n': 
X	    default: 
X		break;
X	    case 'q': 
X		goto ret;
X	}
X    }
X    pline (cnt ? "That was all." : "No applicable objects.");
Xret: 
X    if (!flags.echo)
X	echo (OFF);
X    return (cnt);
X}
X
Xobj_to_let (obj)
Xregister struct obj *obj;
X{
X    register struct obj *otmp;
X    register char   ilet = 'a';
X
X    for (otmp = invent; otmp && otmp != obj; otmp = otmp -> nobj)
X	if (++ilet > 'z')
X	    ilet = 'A';
X    return (otmp ? ilet : 0);
X}
X
Xprinv (obj)
Xregister struct obj *obj;
X{
X    prname (obj, obj_to_let (obj), 1);
X}
X
Xprname (obj, let, onelin)
Xregister struct obj *obj;
Xregister char   let;
X{
X    char    li[BUFSZ];
X
X    (void) sprintf (li, " %c - %s.", let, doname (obj));
X    switch (onelin) {
X	case 1: 
X	    pline (li + 1);
X	    break;
X	case 0: 
X	    puts (li + 1);
X	    break;
X	case -1: 
X	    cl_end ();
X	    fputs (li, stdout);
X	    curx += strlen (li);
X    }
X}
X
Xdotypeinv ()
X{
X    char		c[BUFSZ];
X    char		stuff[BUFSZ];
X    register int	stct;
X    register struct obj	*otmp = invent;
X    register char	ilet;
X
X    if (!invent) {
X	pline ("You aren't carrying anything.");
X	return;
X    }
X    else {
X	stuff[0] = 0;
X	stct = 0;
X	while (otmp) {
X	    if (!index (stuff, otmp -> olet)) {
X		stuff[stct++] = otmp -> olet;
X		stuff[stct] = 0;
X	    }
X	    otmp = otmp -> nobj;
X	}
X	stuff[stct] = 0;
X	pline ("What objects do you want an inventory of [%s]? ",stuff);
X	getlin (c);
X	if ((c[0] == '\033') || (c[0] == '\0'))
X	    return;
X	stct = 0;
X	ilet = 'a';
X	for (otmp = invent; otmp; otmp = otmp -> nobj) {
X	    if (index (c, otmp -> olet))
X		stuff[stct++] = ilet;
X	    if (ilet == 'z')
X		ilet = 'A';
X	    else
X		ilet++;
X	}
X	stuff[stct] = '\0';
X	doinv (stuff);
X    }
X}
X
Xddoinv ()
X{
X    doinv ((char *) 0);
X    return (0);
X}
X
X/* called with "": all objects in inventory; with 0: also usedup ones */
X/* otherwise: all objects with (serial) letter in lets */
Xdoinv (lets)
Xregister char *lets;
X{
X    register struct obj *otmp;
X    register char   ilet = 'a';
X    int     ct = 0;
X    int     maxlth = 0;
X    int     lth;
X    int     curline;
X
X    if (!invent) {
X	pline ("Not carrying anything");
X	if (lets)
X	    return;
X    }
X    if (!flags.oneline) {
X	if (!lets || !*lets)
X	    for (otmp = invent; otmp; otmp = otmp -> nobj)
X		ct++;
X	else
X	    ct = strlen (lets);
X	if (ct > 1 && ct < ROWNO && (lets || !inshop ())) {
X	    for (otmp = invent; otmp; otmp = otmp -> nobj) {
X		if (!lets || !*lets || index (lets, ilet)) {
X		    lth = strlen (doname (otmp));
X		    if (lth > maxlth)
X			maxlth = lth;
X		}
X		if (++ilet > 'z')
X		    ilet = 'A';
X	    }
X	    ilet = 'a';
X	    lth = COLNO - maxlth - 7;
X	    if (lth < 10)
X		goto clrscr;
X	    home ();
X	    cl_end ();
X	    flags.topl = 0;
X	    ct = 0;
X	    for (otmp = invent; otmp; otmp = otmp -> nobj) {
X		if (!lets || !*lets || index (lets, ilet)) {
X		    curs (lth, ++ct);
X		    prname (otmp, ilet, -1);
X		}
X		if (++ilet > 'z')
X		    ilet = 'A';
X	    }
X	    curs (lth, ct + 1);
X	    cl_end ();
X	    cmore ();			/* sets morc */
X	    /* test whether morc is a reasonable answer */
X	    if (lets && *lets && !index (lets, morc))
X		morc = 0;
X
X	    home ();
X	    cl_end ();
X	    docorner (lth, ct);
X	    return;
X	}
X    }
Xclrscr: 
X    if (ct == 1) {
X	for (otmp = invent; otmp; otmp = otmp -> nobj) {
X	    if (!lets || !*lets || index (lets, ilet))
X		prname (otmp, ilet, 1);
X	    if (++ilet > 'z')
X		ilet = 'A';
X	}
X	standoutbeg ();
X	printf ("--More--");
X	standoutend ();
X	if ((morc = readchar ()) == ' ')
X	    morc = 0;
X	return;
X    }
X    else {
X	cls ();
X	curline = 1;
X	for (otmp = invent; otmp; otmp = otmp -> nobj) {
X	    if (!lets || !*lets || index (lets, ilet)) {
X		curs (1, curline);
X		cl_end ();
X		prname (otmp, ilet, 0);
X		curline++;
X		if (curline >= ROWNO + 1) {
X		    curs (1, curline);
X		    cl_end ();
X		    curs (1, ROWNO + 2);
X		    cl_end ();
X		    standoutbeg ();
X		    printf ("---More---");
X		    standoutend ();
X		    if ((morc = readchar ()) != ' ') {
X			docrt ();
X			return;
X		    }
X		    curline = 1;
X		}
X	    }
X	    if (++ilet > 'z')
X		ilet = 'A';
X	}
X	curs (1, curline);
X	cl_eos ();
X	/* tell doinvbill whether we cleared the screen */
X	if (!lets) {
X	    curs (1, ROWNO + 2);
X	    standoutbeg ();
X	    printf ("---More---");
X	    standoutend ();
X	    if ((morc = readchar ()) != ' ') {
X		docrt ();
X		return;
X	    }
X	    else
X		morc = 0;
X	    if (!doinvbill (1)) {
X		docrt ();
X		return;
X	    }
X	    else
X		printf("\r\n");
X	}
X	curs (1, ROWNO + 2);
X	standoutbeg ();
X	printf ("Hit space to continue...");
X	standoutend ();
X	if ((morc = readchar ()) == ' ')
X	    morc = 0;
X	docrt ();
X    }
X}
X
Xstackobj (obj)
Xregister struct obj *obj;
X{
X    register struct obj *otmp = fobj;
X    for (otmp = fobj; otmp; otmp = otmp -> nobj)
X	if (otmp != obj)
X	    if (otmp -> ox == obj -> ox && otmp -> oy == obj -> oy &&
X		    merged (obj, otmp, 1))
X		return;
X}
X
X/* merge obj with otmp and delete obj if types agree */
Xmerged (otmp, object, lose)
Xregister struct obj *otmp, *object;
X{
X    if (otmp -> otyp == object -> otyp
X	    && object -> unpaid == otmp -> unpaid
X	    && object -> spe == otmp -> spe
X	    && object -> known == otmp -> known
X	    && object -> dknown == otmp -> dknown
X	    && object -> cursed == otmp -> cursed
X	    && ((object -> olet == WEAPON_SYM
X		    && object -> otyp < BOOMERANG)
X		|| index ("%?!*", otmp -> olet))) {
X	otmp -> quan += object -> quan;
X	otmp -> owt += object -> owt;
X	if (lose)
X	    freeobj (object);
X	obfree (object, otmp);		/* free(object), bill->otmp */
X	return (1);
X    }
X    else
X	return (0);
X}
X
Xdoprwep ()
X{
X    if (!uwep)
X	pline ("You are empty handed.");
X    else
X	prinv (uwep);
X    return (0);
X}
X
Xdoprarm ()
X{
X    if (!uarm && !uarmg && !uarms && !uarmh)
X	pline ("You are not wearing any armor.");
X    else {
X	char    lets[6];
X	register int    ct = 0;
X
X	if (uarm)
X	    lets[ct++] = obj_to_let (uarm);
X	if (uarm2)
X	    lets[ct++] = obj_to_let (uarm2);
X	if (uarmh)
X	    lets[ct++] = obj_to_let (uarmh);
X	if (uarms)
X	    lets[ct++] = obj_to_let (uarms);
X	if (uarmg)
X	    lets[ct++] = obj_to_let (uarmg);
X	lets[ct] = 0;
X	doinv (lets);
X    }
X    return (0);
X}
X
Xdoprring ()
X{
X    if (!uleft && !uright)
X	pline ("You are not wearing any rings.");
X    else {
X	char    lets[3];
X	register int    ct = 0;
X
X	if (uleft)
X	    lets[ct++] = obj_to_let (uleft);
X	if (uright)
X	    lets[ct++] = obj_to_let (uright);
X	lets[ct] = 0;
X	doinv (lets);
X    }
X    return (0);
X}
X
Xdigit (c)
Xchar  c;
X{
X    return (c >= '0' && c <= '9');
X}
--burp--
sed 's/^X//' << '--burp--' > hack.main.c
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
X
X#include <stdio.h>
X#include <signal.h>
X#include <errno.h>
X#include "hack.h"
X
X#define gpid	((int) getpid())
Xlong	time ();
X
Xextern char *getlogin ();
Xextern char plname[PL_NSIZ], pl_character[PL_CSIZ];
Xextern char *getenv ();
X
Xint     (*afternmv) ();
Xint     done1 ();
Xint     hangup ();
X
Xchar    safelock[] = "safelock";
Xxchar locknum;				/* max num of players */
Xchar    SAVEF[PL_NSIZ + 5] = "save/";
Xchar    perm[] = "perm";
Xchar   *hname;				/* name of the game (argv[0] of call) */
Xchar    obuf[BUFSIZ];			/* BUFSIZ is defined in stdio.h */
X
Xextern char *nomovemsg;
Xextern long wailmsg;
X
Xmain (argc, argv)
Xint     argc;
Xchar   *argv[];
X{
X#ifdef NEWS
X    int     nonews = 0;
X#endif NEWS
X    int     fd;
X    char   *dir;
X
X    hname = argv[0];
X
X    /* 
X     * See if we must change directory to the playground.
X     * (Perhaps hack runs suid and playground is inaccessible
X     *  for the player.)
X     * The environment variable HACKDIR is overridden by a
X     *  -d command line option.
X     */
X    dir = getenv ("HACKDIR");
X    if (argc > 1 && !strncmp (argv[1], "-d", 2)) {
X	argc--;
X	argv++;
X	dir = argv[0] + 2;
X	if (*dir == '=' || *dir == ':')
X	    dir++;
X	if (!*dir && argc > 1) {
X	    argc--;
X	    argv++;
X	    dir = argv[0];
X	}
X	if (!*dir)
X	    error ("Flag -d must be followed by a directory name.");
X    }
X
X    /* 
X     * Now we know the directory containing 'record' and
X     * may do a prscore().
X     */
X    if (argc > 1 && !strncmp (argv[1], "-s", 2)) {
X	if (dir)
X	    chdirx (dir);
X	prscore (argc, argv);
X	exit (0);
X    }
X
X    /* 
X     * It seems he really wants to play. Find the creation date of
X     * this game so as to avoid restoring outdated savefiles.
X     */
X    gethdate (hname);
X
X    /* 
X     * We cannot do chdir earlier, otherwise gethdate will fail.
X     */
X    if (dir)
X	chdirx (dir);
X
X    /* 
X     * Who am i? Perhaps we should use $USER instead?
X     */
X    (void) strncpy (plname, getlogin (), sizeof (plname) - 1);
X
X    /* 
X     * Process options.
X     */
X    while (argc > 1 && argv[1][0] == '-') {
X	argv++;
X	argc--;
X	switch (argv[0][1]) {
X#ifdef WIZARD
X	    case 'w': 
X		if (!strcmp (getlogin (), WIZARD))
X		    wizard = TRUE;
X		else
X		    printf ("Sorry.\n");
X		break;
X#endif WIZARD
X#ifdef NEWS
X	    case 'n': 
X		nonews++;
X		break;
X#endif NEWS
X	    case 'u': 
X		if (argv[0][2])
X		    (void) strncpy (plname, argv[0] + 2, sizeof (plname) - 1);
X		else
X		    if (argc > 1) {
X			argc--;
X			argv++;
X			(void) strncpy (plname, argv[0], sizeof (plname) - 1);
X		    }
X		    else
X			printf ("Player name expected after -u\n");
X		break;
X	    default: 
X		printf ("Unknown option: %s\n", *argv);
X	}
X    }
X
X    if (argc > 1)
X	locknum = atoi (argv[1]);
X#ifdef WIZARD
X    if (wizard)
X	(void) strcpy (plname, "wizard");
X    else
X#endif WIZARD
X	if (!*plname || !strncmp (plname, "player", 4))
X	    askname ();
X    plnamesuffix ();			/* strip suffix from name */
X
X    setbuf (stdout, obuf);
X    (void) srand ((int) time ((long *) 0));
X    startup ();
X    cls ();
X    (void) signal (SIGHUP, hangup);
X#ifdef WIZARD
X    if (!wizard) {
X#endif WIZARD
X	(void) signal (SIGQUIT, SIG_IGN);
X	(void) signal (SIGINT, SIG_IGN);
X	if (locknum)
X	    lockcheck ();
X	else
X	    (void) strcpy (lock, plname);
X#ifdef WIZARD
X    }
X    else {
X	register char  *sfoo;
X	(void) strcpy (lock, plname);
X	if (sfoo = getenv ("MAGIC"))
X	    while (*sfoo) {
X		switch (*sfoo++) {
X		    case 'n': 
X			(void) srand (*sfoo++);
X			break;
X		}
X	    }
X	if (sfoo = getenv ("GENOCIDED")) {
X	    if (*sfoo == '!') {
X		extern struct permonst  mons[CMNUM + 2];
X		extern char genocided[], fut_geno[];
X		register struct permonst   *pm = mons;
X		register char  *gp = genocided;
X
X		while (pm < mons + CMNUM + 2) {
X		    if (!index (sfoo, pm -> mlet))
X			*gp++ = pm -> mlet;
X		    pm++;
X		}
X		*gp = 0;
X	    }
X	    else
X		(void) strcpy (genocided, sfoo);
X	    (void) strcpy (fut_geno, genocided);
X	}
X    }
X#endif WIZARD
X    u.uhp = 1;				/* prevent RIP on early quits */
X    u.ux = FAR;				/* prevent nscr() */
X    (void) strcat (SAVEF, plname);
X    if ((fd = open (SAVEF, 0)) >= 0 && (uptodate (fd) || unlink (SAVEF) == 666)) {
X	(void) signal (SIGINT, done1);
X	puts ("Restoring old save file...");
X	(void) fflush (stdout);
X	dorecover (fd);
X	flags.move = 0;
X    }
X    else {
X#ifdef NEWS
X	if (!nonews)
X	    if ((fd = open (NEWS, 0)) >= 0)
X		outnews (fd);
X#endif NEWS
X	flags.ident = 1;
X	init_objects ();
X	u_init ();
X	(void) signal (SIGINT, done1);
X	glo (1);
X	mklev ();
X	u.ux = xupstair;
X	u.uy = yupstair;
X	(void) inshop ();
X	setsee ();
X	flags.botlx = 1;
X	makedog ();
X	seemons ();
X	docrt ();
X	pickup ();
X	read_engr_at (u.ux, u.uy);	/* superfluous ? */
X	flags.move = 1;
X	flags.cbreak = ON;
X	flags.echo = OFF;
X    }
X    setftty ();
X#ifdef TRACK
X    initrack ();
X#endif TRACK
X    for (;;) {
X	if (flags.move) {
X#ifdef TRACK
X	    settrack ();
X#endif TRACK
X	    if (moves % 2 == 0 || (!(Fast & ~INTRINSIC) && (!Fast || rn2 (3)))) {
X		extern struct monst *makemon ();
X		movemon ();
X		if (!rn2 (70))
X		    (void) makemon ((struct permonst   *) 0, 0, 0);
X	    }
X	    if (Glib)
X		glibr ();
X	    timeout ();
X	    ++moves;
X	    if (u.uhp < 1) {
X		pline ("You die...");
X		done ("died");
X	    }
X	    if (u.uhp * 10 < u.uhpmax && moves - wailmsg > 50) {
X		wailmsg = moves;
X		if (u.uhp == 1)
X		    pline ("You hear the wailing of the Banshee...");
X		else
X		    pline ("You hear the howling of the CwnAnnwn...");
X	    }
X	    if (u.uhp < u.uhpmax) {
X		if (u.ulevel > 9) {
X		    if (Regeneration || !(moves % 3)) {
X			flags.botl = 1;
X			u.uhp += rnd ((int) u.ulevel - 9);
X			if (u.uhp > u.uhpmax)
X			    u.uhp = u.uhpmax;
X		    }
X		}
X		else
X		    if (Regeneration || (!(moves % (22 - u.ulevel * 2)))) {
X			flags.botl = 1;
X			u.uhp++;
X		    }
X	    }
X	    if (Teleportation && !rn2 (85))
X		tele ();
X	    if (Searching && multi >= 0)
X		(void) dosearch ();
X	    gethungry ();
X	    invault ();
X	}
X	if (multi < 0) {
X	    if (!++multi) {
X		pline (nomovemsg ? nomovemsg : "You can move again.");
X		nomovemsg = 0;
X		if (afternmv)
X		    (*afternmv) ();
X		afternmv = 0;
X	    }
X	}
X	flags.move = 1;
X	find_ac ();
X#ifndef QUEST
X	if (!flags.mv || Blind)
X#endif QUEST
X	{
X	    seeobjs ();
X	    seemons ();
X	    nscr ();
X	}
X	if (flags.botl || flags.botlx)
X	    bot ();
X	if (multi > 0) {
X#ifdef QUEST
X	    if (flags.run >= 4)
X		finddir ();
X#endif QUEST
X	    lookaround ();
X	    if (!multi) {		/* lookaround may clear multi */
X		flags.move = 0;
X		continue;
X	    }
X	    if (flags.mv) {
X		if (multi < COLNO && !--multi)
X		    flags.mv = flags.run = 0;
X		domove ();
X	    }
X	    else {
X		--multi;
X		rhack (save_cm);
X	    }
X	}
X	else
X	    if (multi == 0)
X		rhack ((char *) 0);
X    }
X}
X
Xlockcheck ()
X{
X    extern int  errno;
X    register int    i, fd;
X
X    /* we ignore QUIT and INT at this point */
X    if (link (perm, safelock) == -1) {
X	perror ("safelock");
X	error ("Cannot link safelock. (Try again or rm safelock.)");
X    }
X
X    for (i = 0; i < locknum; i++) {
X	lock[0] = 'a' + i;
X	if ((fd = open (lock, 0)) == -1) {
X	    if (errno == ENOENT)
X		goto gotlock;		/* no such file */
X	    (void) unlink (safelock);
X	    perror (lock);
X	    error ("Cannot open %s", lock);
X	}
X	(void) close (fd);
X    }
X    (void) unlink (safelock);
X    error ("Too many hacks running now.");
Xgotlock: 
X    fd = creat (lock, FMASK);
X    if (fd == -1) {
X	error ("cannot creat lock file.");
X    }
X    else {
X	int     pid;
X
X	pid = gpid;
X	if (write (fd, (char *) & pid, sizeof(int)) != sizeof(int)) {
X	    error ("cannot write lock");
X	}
X	if (close (fd) == -1) {
X	    error ("cannot close lock");
X	}
X    }
X    if (unlink (safelock) == -1) {
X	error ("Cannot unlink safelock");
X    }
X}
X
X/*VARARGS1*/
Xerror (s, a1, a2, a3, a4)
Xchar   *s, *a1, *a2, *a3, *a4;
X{
X    printf ("Error: ");
X    printf (s, a1, a2, a3, a4);
X    (void) putchar ('\n');
X    exit (1);
X}
X
Xglo (foo)
Xregister    foo;
X{
X    /* construct the string  xlock.n  */
X    register char  *tf;
X
X    tf = lock;
X    while (*tf && *tf != '.')
X	tf++;
X    (void) sprintf (tf, ".%d", foo);
X}
X
X/*
X * plname is filled either by an option (-u Player  or  -uPlayer) or
X * explicitly (-w implies wizard) or by askname.
X * It may still contain a suffix denoting pl_character.
X */
Xaskname ()
X{
X    register int    c, ct;
X    printf ("\nWho are you? ");
X    ct = 0;
X    while ((c = getchar ()) != '\n') {
X	if (c == EOF)
X	    error ("End of input\n");
X	if (c != '-')
X	    if (c < 'A' || (c > 'Z' && c < 'a') || c > 'z')
X		c = '_';
X	if (ct < sizeof (plname) - 1)
X	    plname[ct++] = c;
X    }
X    plname[ct] = 0;
X    if (ct == 0)
X	askname ();
X#ifdef QUEST
X    else
X	printf ("Hello %s, welcome to quest!\n", plname);
X#else
X    else
X	printf ("Hello %s, welcome to hack!\n", plname);
X#endif QUEST
X}
X
Ximpossible ()
X{
X    pline ("Program in disorder - perhaps you'd better Quit");
X}
X
X#ifdef NEWS
Xint     stopnews;
X
Xstopnws ()
X{
X    (void) signal (SIGINT, SIG_IGN);
X    stopnews++;
X}
X
Xoutnews (fd)
Xint     fd;
X{
X    int     (*prevsig) ();
X    char    ch;
X    prevsig = signal (SIGINT, stopnws);
X    while (!stopnews && read (fd, &ch, 1) == 1)
X	(void) putchar (ch);
X    (void) putchar ('\n');
X    (void) fflush (stdout);
X    (void) close (fd);
X    (void) signal (SIGINT, prevsig);
X    /* See whether we will ask TSKCFW: he might have told us already */
X    if (!stopnews && pl_character[0])
X	getret ();
X}
X#endif NEWS
X
Xchdirx (dir)
Xchar   *dir;
X{
X    if (chdir (dir) < 0) {
X	perror (dir);
X	error ("Cannot chdir to %s.", dir);
X    }
X}
--burp--
sed 's/^X//' << '--burp--' > hack.o_init.c
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
X
X#include	"config.h"		/* for typedefs */
X#include	"def.objects.h"
X
Xint
Xletindex (let)
Xregister char	let;
X{
X    register int    i = 0;
X    register char   ch;
X    while ((ch = obj_symbols[i++]) != 0)
X	if (ch == let)
X	    return (i);
X    return (0);
X}
X
Xinit_objects ()
X{
X    register int    i, j, first, last, sum, end;
X    register char   let, *tmp;
X    /* init base; if probs given check that they add up to 100, otherwise compute probs; shuffle descriptions */
X    end = sizeof (objects) / sizeof (objects[0]);
X    first = 0;
X    while (first < end) {
X	let = objects[first].oc_olet;
X	last = first + 1;
X	while (last < end && objects[last].oc_olet == let
X		&& objects[last].oc_name != NULL)
X	    last++;
X	i = letindex (let);
X	if ((!i && let != ILLOBJ_SYM) || bases[i] != 0)
X	    panic ("initialization error");
X	bases[i] = first;
Xcheck: 
X#ifdef MKLEV
X#include	"hack.onames.h"
X	if (let == GEM_SYM) {
X	    extern  xchar dlevel;
X	    for (j = 0; j < 9 - dlevel / 3; j++)
X		objects[first + j].oc_prob = 0;
X	    first += j;
X	    if (first >= last || first >= LAST_GEM)
X		printf ("Not enough gems? - first=%d last=%d j=%d LAST_GEM=%d\n", first, last, j, LAST_GEM);
X	    for (j = first; j < LAST_GEM; j++)
X		objects[j].oc_prob = (20 + j - first) / (LAST_GEM - first);
X	}
X#endif MKLEV
X	sum = 0;
X	for (j = first; j < last; j++)
X	    sum += objects[j].oc_prob;
X	if (sum == 0) {
X	    for (j = first; j < last; j++)
X		objects[j].oc_prob = (100 + j - first) / (last - first);
X	    goto check;
X	}
X	if (sum != 100)
X#ifdef MKLEV
X		panic
X#else
X		error
X#endif MKLEV
X		("init-prob error for %c", let);
X	/* shuffling is rather meaningless in mklev, but we must update  last  anyway */
X	if (objects[first].oc_descr != NULL && let != TOOL_SYM) {
X	    /* shuffle, also some additional descriptions */
X	    while (last < end && objects[last].oc_olet == let)
X		last++;
X	    j = last;
X	    while (--j > first) {
X		i = first + rn2 (j + 1 - first);
X		tmp = objects[j].oc_descr;
X		objects[j].oc_descr = objects[i].oc_descr;
X		objects[i].oc_descr = tmp;
X	    }
X	}
X	first = last;
X    }
X}
X
Xprobtype (let)
Xregister char    let;
X{
X    register int    i = bases[letindex (let)];
X    register int    prob = rn2 (100);
X    while ((prob -= objects[i].oc_prob) >= 0)
X	i++;
X    if (objects[i].oc_olet != let || !objects[i].oc_name)
X	panic ("probtype(%c) error, i=%d", let, i);
X    return (i);
X}
X
X#ifndef MKLEV
X#define SIZE(x) (sizeof x)/(sizeof x[0])
Xextern long *alloc ();
X
Xsavenames (fd)
Xregister fd;
X{
X    register int    i;
X    unsigned    len;
X    bwrite (fd, (char *) bases, sizeof bases);
X    bwrite (fd, (char *) objects, sizeof objects);
X    /* as long as we use only one version of Hack/Quest we need not save oc_name and oc_descr, but we must save oc_uname for all
X       objects */
X    for (i = 0; i < SIZE (objects); i++) {
X	if (objects[i].oc_uname) {
X	    len = strlen (objects[i].oc_uname) + 1;
X	    bwrite (fd, (char *) & len, sizeof len);
X	    bwrite (fd, objects[i].oc_uname, len);
X	}
X    }
X}
X
Xrestnames (fd)
Xregister fd;
X{
X    register int    i;
X    unsigned    len;
X    mread (fd, (char *) bases, sizeof bases);
X    mread (fd, (char *) objects, sizeof objects);
X    for (i = 0; i < SIZE (objects); i++)
X	if (objects[i].oc_uname) {
X	    mread (fd, (char *) & len, sizeof len);
X	    objects[i].oc_uname = (char *) alloc (len);
X	    mread (fd, objects[i].oc_uname, len);
X	}
X}
X
Xdodiscovered()
X{
X    register int	i, end, curline, c;
X    int			maxlth = 0, lth = 0;
X    int			ct = 0;
X    char		buf[256];
X
X    end = sizeof(objects) / sizeof(objects[0]);
X    for (i = 0; i < end; i++) {
X	if (((objects[i].oc_name_known) || (objects[i].oc_uname != NULL))
X	&& ((objects[i].oc_olet == POTION_SYM)	/* could use index but	     */
X	|| (objects[i].oc_olet == SCROLL_SYM)	/* i'd like to stay with the */
X	|| (objects[i].oc_olet == WAND_SYM)	/* defined symbols	     */
X	|| (objects[i].oc_olet == RING_SYM))) {
X	    ct++;
X	    lth = 8;
X	    if (objects[i].oc_name_known)
X		lth += (4 + strlen (objects[i].oc_name));
X	    if (objects[i].oc_uname != NULL)
X		lth += (8 + strlen (objects[i].oc_uname));
X	    lth += (2 + strlen(objects[i].oc_descr));
X	    if (lth > maxlth)
X		maxlth = lth;
X	}
X    }
X    lth = COLNO - maxlth - 1;
X    if (ct == 0)
X	pline ("You haven't discovered anything yet...");
X    else if ((ct >= 1 && ct < ROWNO) && (lth >= 10)) {
X	home ();
X	cl_end ();
X	curline = 1;
X	for (i = 0; i < end; i++) {
X	    if (((objects[i].oc_name_known) || (objects[i].oc_uname != NULL))
X	    && ((objects[i].oc_olet == POTION_SYM)
X	    || (objects[i].oc_olet == SCROLL_SYM)
X	    || (objects[i].oc_olet == WAND_SYM)
X	    || (objects[i].oc_olet == RING_SYM))) {
X		curs (lth, curline);
X		cl_end ();
X		prdiscobj (i);
X		curline++;
X	    }
X	}
X	curs (lth, curline);
X	cl_end ();
X	standoutbeg ();
X	printf ("--More--");
X	standoutend ();
X	c = readchar ();	/* any key */
X	home ();
X	cl_end ();
X	docorner (lth, curline);
X    }
X    else {
X	curline = 1;
X	for (i = 0; i < end; i++) {
X	    if (((objects[i].oc_name_known) || (objects[i].oc_uname != NULL))
X	    && ((objects[i].oc_olet == POTION_SYM)
X	    || (objects[i].oc_olet == SCROLL_SYM)
X	    || (objects[i].oc_olet == WAND_SYM)
X	    || (objects[i].oc_olet == RING_SYM))) {
X		curs (1, curline);
X		cl_end ();
X		prdiscobj (i);
X		curline++;
X		ct--;
X		if (curline >= ROWNO + 1) {
X		    curs (1, curline);
X		    cl_end ();
X		    curs (1, ROWNO + 2);
X		    cl_end ();
X		    standoutbeg ();
X		    printf ("---More---");
X		    standoutend ();
X		    while (((c = readchar ()) != ' ') && (c != 'q'))
X			bell ();
X		    if (c == 'q')
X			break;
X		    curline = 1;
X		}
X	    }
X	}
X	curs (1, curline);
X	cl_eos ();
X	curs (1, ROWNO + 2);
X	standoutbeg();
X	printf("Hit space to continue...");
X	standoutend();
X	while (readchar() != ' ')
X	    bell();
X	docrt ();
X    }
X}
X
Xprdiscobj (i)
Xint	i;
X{
X    switch (objects[i].oc_olet) {
X	case POTION_SYM:
X	    printf (" potion ");
X	    break;
X	case SCROLL_SYM:
X	    printf (" scroll ");
X	    break;
X	case WAND_SYM:
X	    printf (" wand   ");
X	    break;
X	case RING_SYM:
X	    printf (" ring   ");
X	    break;
X	default:
X	    printf (" toilet ");
X	    break;
X    }
X    if (objects[i].oc_name_known)
X	printf ("of %s ",objects[i].oc_name);
X    if (objects[i].oc_uname != NULL)
X	printf ("called %s ",objects[i].oc_uname);
X    printf ("(%s)",objects[i].oc_descr);
X}
X#endif MKLEV
--burp--
sed 's/^X//' << '--burp--' > hack.read.c
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
X
X#include "hack.h"
X
Xextern struct monst *makemon ();
Xint     identify ();
X
Xdoread ()
X{
X    register struct obj *scroll;
X    register    boolean confused = (Confusion != 0);
X    register    boolean known = FALSE;
X
X    scroll = getobj ("?", "read");
X    if (!scroll)
X	return (0);
X    if (!scroll -> dknown && Blind) {
X	pline ("Being blind, you cannot read the formula on the scroll.");
X	return (0);
X    }
X    if (Blind)
X	pline ("As you pronounce the formula on it, the scroll disappears.");
X    else
X	pline ("As you read the scroll, it disappears.");
X    if (confused)
X	pline ("Being confused, you mispronounce the magic words ... ");
X
X    switch (scroll -> otyp) {
X
X	case SCR_ENCHANT_ARMOR: 
X	    {
X		extern struct obj  *some_armor ();
X		register struct obj *otmp = some_armor ();
X		if (!otmp) {
X		    pline ("You skin glows then fades.");
X		    strange_feeling (scroll);
X		    return (1);
X		}
X		if (confused) {
X		    pline ("Your %s glows silver for a moment.",
X			    objects[otmp -> otyp].oc_name);
X		    otmp -> rustfree = 1;
X		    break;
X		}
X		if (otmp -> spe * 2 + objects[otmp -> otyp].a_ac > 23 &&
X			!rn2 (3)) {
X		    pline ("Your %s glows violently green for a while, then evaporates.",
X			    objects[otmp -> otyp].oc_name);
X		    useup (otmp);
X		    break;
X		}
X		pline ("Your %s glows green for a moment.",
X			objects[otmp -> otyp].oc_name);
X		otmp -> cursed = 0;
X		otmp -> spe++;
X		break;
X	    }
X	case SCR_DESTROY_ARMOR: 
X	    if (confused) {
X		register struct obj *otmp = some_armor ();
X		if (!otmp) {
X		    pline ("Your bones itch.");
X		    strange_feeling (scroll);
X		    return (1);
X		}
X		pline ("Your %s glows purple for a moment.",
X			objects[otmp -> otyp].oc_name);
X		otmp -> rustfree = 0;
X		break;
X	    }
X	    if (uarm) {
X		pline ("Your armor turns to dust and falls to the floor!");
X		useup (uarm);
X	    }
X	    else
X		if (uarmh) {
X		    pline ("Your helmet turns to dust and is blown away!");
X		    useup (uarmh);
X		}
X		else
X		    if (uarmg) {
X			pline ("Your gloves vanish!");
X			useup (uarmg);
X			selftouch ("You");
X		    }
X		    else {
X			pline ("Your skin itches.");
X			strange_feeling (scroll);
X			return (1);
X		    }
X	    break;
X	case SCR_CONFUSE_MONSTER: 
X	    if (confused) {
X		pline ("Your hands begin to glow purple.");
X		Confusion += rnd (100);
X	    }
X	    else {
X		pline ("Your hands begin to glow blue.");
X		u.umconf = 1;
X	    }
X	    break;
X	case SCR_SCARE_MONSTER: 
X	    {
X		register int    ct = 0;
X		register struct monst  *mtmp;
X
X		for (mtmp = fmon; mtmp; mtmp = mtmp -> nmon)
X		    if (cansee (mtmp -> mx, mtmp -> my)) {
X			if (confused)
X			    mtmp -> mflee = mtmp -> mfroz =
X				mtmp -> msleep = 0;
X			else
X			    mtmp -> mflee = 1;
X			ct++;
X		    }
X		if (!ct) {
X		    if (confused)
X			pline ("You hear sad wailing in the distance.");
X		    else
X			pline ("You hear maniacal laughter in the distance.");
X		}
X		break;
X	    }
X	case SCR_BLANK_PAPER: 
X	    if (confused)
X		pline ("You see strange patterns on this scroll.");
X	    else
X		pline ("This scroll seems to be blank.");
X	    break;
X	case SCR_REMOVE_CURSE: 
X	    {
X		register struct obj *obj;
X		if (confused)
X		    pline ("You feel like you need some help.");
X		else
X		    pline ("You feel like someone is helping you.");
X		for (obj = invent; obj; obj = obj -> nobj)
X		    if (obj -> owornmask)
X			obj -> cursed = confused;
X		if (Punished && !confused) {
X		    Punished = 0;
X		    freeobj (uchain);
X		    unpobj (uchain);
X		    free ((char *) uchain);
X		    uball -> spe = 0;
X		    uball -> owornmask &= ~W_BALL;
X		    uchain = uball = (struct obj   *) 0;
X		}
X		break;
X	    }
X	case SCR_CREATE_MONSTER: 
X	    {
X		register int    cnt = 1;
X
X		if (!rn2 (73))
X		    cnt += rn2 (4) + 1;
X		if (confused)
X		    cnt += 12;
X		while (cnt--)
X		    (void) makemon (confused ? PM_ACIDBLOB :
X			    (struct permonst   *) 0, u.ux, u.uy);
X		break;
X	    }
X	case SCR_ENCHANT_WEAPON: 
X	    if (!uwep) {
X		pline ("Your hands twitch.");
X		strange_feeling (scroll);
X		return (1);
X	    }
X	    if (confused) {
X		pline ("Your %s glows silver for a moment.",
X			objects[uwep -> otyp].oc_name);
X		uwep -> rustfree = 1;
X	    }
X	    else
X		if (!chwepon (scroll, 1))
X		    return (1);
X	    break;
X	case SCR_DAMAGE_WEAPON: 
X	    if (confused) {
X		pline ("Your %s glows purple for a moment.",
X			objects[uwep -> otyp].oc_name);
X		uwep -> rustfree = 0;
X	    }
X	    else
X		if (!chwepon (scroll, -1))
X		    return (1);
X	    break;
X	case SCR_TAMING: 
X	    {
X		register int    i, j;
X		register int    bd = confused ? 5 : 1;
X		register struct monst  *mtmp;
X
X		for (i = -bd; i <= bd; i++)
X		    for (j = -bd; j <= bd; j++)
X			if (mtmp = m_at (u.ux + i, u.uy + j))
X			    (void) tamedog (mtmp, (struct obj  *) 0);
X		break;
X	    }
X	case SCR_GENOCIDE: 
X	    {
X		extern char genocided[], fut_geno[];
X		char    buf[BUFSZ];
X		register struct monst  *mtmp, *mtmp2;
X
X		pline ("You have found a scroll of genocide!");
X		known = TRUE;
X		if (confused)
X		    *buf = u.usym;
X		else
X		    do {
X			pline ("What monster do you want to genocide (Type the letter)? ");
X			getlin (buf);
X		    } while (strlen (buf) != 1 || !letter (*buf));
X		if (!index (fut_geno, *buf))
X		    charcat (fut_geno, *buf);
X		if (!index (genocided, *buf))
X		    charcat (genocided, *buf);
X		else {
X		    pline ("Such monsters do not exist in this world.");
X		    break;
X		}
X		for (mtmp = fmon; mtmp; mtmp = mtmp2) {
X		    mtmp2 = mtmp -> nmon;
X		    if (mtmp -> data -> mlet == *buf)
X			mondead (mtmp);
X		}
X		pline ("Wiped out all %c's.", *buf);
X		if (*buf == u.usym) {
X		    killer = "scroll of genocide";
X		    u.uhp = -1;
X		}
X		break;
X	    }
X	case SCR_LIGHT: 
X	    if (!Blind)
X		known = TRUE;
X	    litroom (!confused);
X	    break;
X	case SCR_TELEPORTATION: 
X	    if (confused)
X		level_tele ();
X	    else {
X#ifdef QUEST
X		register int    oux = u.ux, ouy = u.uy;
X		tele ();
X		if (dist (oux, ouy) > 100)
X		    known = TRUE;
X#else QUEST
X		register int    uroom = inroom (u.ux, u.uy);
X		tele ();
X		if (uroom != inroom (u.ux, u.uy))
X		    known = TRUE;
X#endif QUEST
X	    }
X	    break;
X	case SCR_GOLD_DETECTION: 
X	    {
X		register struct gen *head = confused ? ftrap : fgold;
X		register struct gen *gtmp;
X
X		if (!head) {
X		    pline ("You feel materially poor.");
X		    strange_feeling (scroll);
X		    return (1);
X		}
X		else {
X		    known = TRUE;
X		    for (gtmp = head; gtmp; gtmp = gtmp -> ngen)
X			if (gtmp -> gx != u.ux || gtmp -> gy != u.uy)
X			    goto outgoldmap;
X		    /* only under me - no separate display required */
X		    if (confused)
X			pline ("You feel very giddy!");
X		    else
X			pline ("You notice some gold between your feet.");
X		    break;
X	    outgoldmap: 
X		    cls ();
X		    for (gtmp = head; gtmp; gtmp = gtmp -> ngen)
X			at (gtmp -> gx, gtmp -> gy, '$');
X		    prme ();
X		    if (confused)
X			pline ("You feel very greedy!");
X		    else
X			pline ("You feel very greedy, and sense gold!");
X		    more ();
X		    docrt ();
X		}
X		break;
X	    }
X	case SCR_FOOD_DETECTION: 
X	    {
X		register    ct = 0, ctu = 0;
X		register struct obj *obj;
X		register char   foodsym = confused ? POTION_SYM : FOOD_SYM;
X
X		for (obj = fobj; obj; obj = obj -> nobj)
X		    if (obj -> olet == FOOD_SYM) {
X			if (obj -> ox == u.ux && obj -> oy == u.uy)
X			    ctu++;
X			else
X			    ct++;
X		    }
X		if (!ct && !ctu) {
X		    pline ("Your nose twitches.");
X		    strange_feeling (scroll);
X		    return (1);
X		}
X		else
X		    if (!ct) {
X			known = TRUE;
X			pline ("You smell %s close nearby.",
X				confused ? "something" : "food");
X
X		    }
X		    else {
X			known = TRUE;
X			cls ();
X			for (obj = fobj; obj; obj = obj -> nobj)
X			    if (obj -> olet == foodsym)
X				at (obj -> ox, obj -> oy, FOOD_SYM);
X			prme ();
X			pline ("Your nose tingles and you smell %s!",
X				confused ? "something" : "food");
X			more ();
X			docrt ();
X		    }
X		break;
X	    }
X	case SCR_IDENTIFY: 
X	    known = TRUE;
X	    if (confused)
X		pline ("You identify this as an identify scroll.");
X	    else
X		pline ("This is an identify scroll.");
X	    useup (scroll);
X	    objects[SCR_IDENTIFY].oc_name_known = 1;
X	    if (!confused)
X		while (
X			!ggetobj ("identify", identify, rn2 (5) ? 1 : rn2 (5))
X			&& invent
X		    );
X	    return (1);
X	case SCR_MAGIC_MAPPING: 
X	    {
X		register struct rm *lev;
X		register int    num, zx, zy;
X
X		known = TRUE;
X		pline ("On this scroll %s a map!",
X			confused ? "was" : "is");
X		for (zy = 0; zy < ROWNO; zy++)
X		    for (zx = 0; zx < COLNO; zx++) {
X			if (confused && rn2 (7))
X			    continue;
X			lev = &(levl[zx][zy]);
X			if ((num = lev -> typ) == 0)
X			    continue;
X			if (num == SCORR) {
X			    lev -> typ = CORR;
X			    lev -> scrsym = CORR_SYM;
X			}
X			else
X			    if (num == SDOOR) {
X				lev -> typ = DOOR;
X				lev -> scrsym = '+';
X				/* do sth in doors ? */
X			    }
X			    else
X				if (lev -> seen)
X				    continue;
X#ifndef QUEST
X			if (num != ROOM)
X#endif QUEST
X			{
X			    lev -> seen = lev -> new = 1;
X			    on_scr (zx, zy);
X			}
X		    }
X		break;
X	    }
X	case SCR_AMNESIA: 
X	    {
X		register int    zx, zy;
X
X		known = TRUE;
X		for (zx = 0; zx < COLNO; zx++)
X		    for (zy = 0; zy < ROWNO; zy++)
X			if (!confused || rn2 (7))
X			    if (!cansee (zx, zy))
X				levl[zx][zy].seen = 0;
X		docrt ();
X		pline ("Thinking of Maud you forget everything else.");
X		break;
X	    }
X	case SCR_FIRE: 
X	    {
X		register int    num;
X
X		known = TRUE;
X		if (confused) {
X		    pline ("The scroll catches fire and you burn your hands.");
X		    losehp (1, "scroll of fire");
X		}
X		else {
X		    pline ("The scroll erupts in a tower of flame!");
X		    if (Fire_resistance)
X			pline ("You are uninjured.");
X		    else {
X			num = rnd (6);
X			u.uhpmax -= num;
X			losehp (num, "scroll of fire");
X		    }
X		}
X		break;
X	    }
X	case SCR_PUNISHMENT: 
X	    known = TRUE;
X	    if (confused) {
X		pline ("You feel guilty.");
X		break;
X	    }
X	    pline ("You are being punished for your misbehaviour!");
X	    if (Punished) {
X		pline ("Your iron ball gets heavier.");
X		uball -> owt += 15;
X		break;
X	    }
X	    Punished = INTRINSIC;
X	    mkobj_at (CHAIN_SYM, u.ux, u.uy);
X	    setworn (fobj, W_CHAIN);
X	    mkobj_at (BALL_SYM, u.ux, u.uy);
X	    setworn (fobj, W_BALL);
X	    uball -> spe = 1;		/* special ball (see save) */
X	    break;
X	default: 
X	    pline ("What weird language is this written in? (%d)",
X		    scroll -> otyp);
X	    impossible ();
X    }
X    if (!objects[scroll -> otyp].oc_name_known) {
X	if (known && !confused) {
X	    objects[scroll -> otyp].oc_name_known = 1;
X	    u.urexp += 10;
X	}
X	else
X	    if (!objects[scroll -> otyp].oc_uname)
X		docall (scroll);
X    }
X    useup (scroll);
X    return (1);
X}
X
Xidentify (otmp)
Xregister struct obj *otmp;
X{
X    objects[otmp -> otyp].oc_name_known = 1;
X    otmp -> known = otmp -> dknown = 1;
X    prinv (otmp);
X    return (1);
X}
X
Xlitroom (on)
Xregister    boolean on;
X{
X    register    num, zx, zy;
X
X    /* first produce the text (provided he is not blind) */
X    if (Blind)
X	goto do_it;
X    if (!on) {
X	if (u.uswallow || !xdnstair || levl[u.ux][u.uy].typ == CORR ||
X		!levl[u.ux][u.uy].lit) {
X	    pline ("It seems even darker in here than before.");
X	    return;
X	}
X	else
X	    pline ("It suddenly becomes dark in here.");
X    }
X    else {
X	if (u.uswallow) {
X	    pline ("%s's stomach is lit.", Monnam (u.ustuck));
X	    return;
X	}
X	if (!xdnstair) {
X	    pline ("Nothing Happens");
X	    return;
X	}
X#ifdef QUEST
X	pline ("The cave lights up around you, then fades.");
X	return;
X#else QUEST
X	if (levl[u.ux][u.uy].typ == CORR) {
X	    pline ("The corridor lights up around you, then fades.");
X	    return;
X	}
X	else
X	    if (levl[u.ux][u.uy].lit) {
X		pline ("The light here seems better now.");
X		return;
X	    }
X	    else
X		pline ("The room is lit.");
X#endif QUEST
X    }
X
Xdo_it: 
X#ifdef QUEST
X    return;
X#else QUEST
X    if (levl[u.ux][u.uy].lit == on)
X	return;
X    if (levl[u.ux][u.uy].typ == DOOR) {
X	if (levl[u.ux][u.uy + 1].typ >= ROOM)
X	    zy = u.uy + 1;
X	else
X	    if (levl[u.ux][u.uy - 1].typ >= ROOM)
X		zy = u.uy - 1;
X	    else
X		zy = u.uy;
X	if (levl[u.ux + 1][u.uy].typ >= ROOM)
X	    zx = u.ux + 1;
X	else
X	    if (levl[u.ux - 1][u.uy].typ >= ROOM)
X		zx = u.ux - 1;
X	    else
X		zx = u.ux;
X    }
X    else {
X	zx = u.ux;
X	zy = u.uy;
X    }
X    for (seelx = u.ux; (num = levl[seelx - 1][zy].typ) != CORR && num != 0;
X	    seelx--);
X    for (seehx = u.ux; (num = levl[seehx + 1][zy].typ) != CORR && num != 0;
X	    seehx++);
X    for (seely = u.uy; (num = levl[zx][seely - 1].typ) != CORR && num != 0;
X	    seely--);
X    for (seehy = u.uy; (num = levl[zx][seehy + 1].typ) != CORR && num != 0;
X	    seehy++);
X    for (zy = seely; zy <= seehy; zy++)
X	for (zx = seelx; zx <= seehx; zx++) {
X	    levl[zx][zy].lit = on;
X	    if (!Blind && dist (zx, zy) > 2)
X		if (on)
X		    prl (zx, zy);
X		else
X		    nosee (zx, zy);
X	}
X    if (!on)
X	seehx = 0;
X#endif	QUEST
X}
--burp--
sed 's/^X//' << '--burp--' > hack.shk.c
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
X
X#include "hack.h"
X#ifdef QUEST
Xint     shlevel = 0;
Xstruct monst   *shopkeeper = 0;
Xstruct obj *billobjs = 0;
Xobfree (obj, merge) register struct obj *obj, *merge; {
X    free ((char *) obj);
X}
Xinshop () {
X    return (0);
X}
Xaddtobill () {
X}
Xsubfrombill () {
X}
Xsplitbill () {
X}
Xdopay () {
X}
Xpaybill () {
X}
Xdoinvbill () {
X}
Xshkdead () {
X}
Xshk_move () {
X    return (0);
X}
Xsetshk () {
X}
Xchar   *shkname () {
X            return ("");
X}
X
X#else
X#include	"hack.mfndpos.h"
X#include	"def.eshk.h"
X
X#define	ESHK	((struct eshk *)(&(shopkeeper->mextra[0])))
X#define	NOTANGRY	shopkeeper->mpeaceful
X#define	ANGRY	!NOTANGRY
X
Xextern char plname[];
Xextern struct obj  *o_on ();
Xstruct monst   *shopkeeper = 0;
Xstruct bill_x  *bill;
Xint     shlevel = 0;			/* level of this shopkeeper */
Xstruct obj *billobjs;			/* objects on bill with bp->useup */
X/* #define	billobjs	shopkeeper->minvent
X * doesnt work so well, since we do not want these objects to be dropped
X * when the shopkeeper is killed.
X * (See also the save and restore routines.)
X */
X
X/* invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
X * obj->quan <= bp->bquan
X */
X
Xlong int    total;
X
Xchar    shtypes[] = "=/)%?![";		/* 8 shoptypes: 7 specialized, 1 mixed */
Xchar   *shopnam[] = {
X    "engagement ring", "walking cane", "antique weapon",
X    "delicatessen", "second hand book", "liquor",
X    "used armor", "assorted antiques"
X};
X
Xchar   *
Xshkname ()
X{
X            return (ESHK -> shknam);
X}
X
Xshkdead ()
X{
X    rooms[ESHK -> shoproom].rtype = 0;
X    setpaid ();
X    shopkeeper = 0;
X    bill = (struct bill_x  *) - 1000;	/* dump core when referenced */
X}
X
Xsetpaid ()	/* caller has checked that shopkeeper exists */
X{
X    register struct obj *obj;
X    for (obj = invent; obj; obj = obj -> nobj)
X	obj -> unpaid = 0;
X    for (obj = fobj; obj; obj = obj -> nobj)
X	obj -> unpaid = 0;
X    while (obj = billobjs) {
X	billobjs = obj -> nobj;
X	free ((char *) obj);
X    }
X    ESHK -> billct = 0;
X}
X
Xaddupbill ()	/* delivers result in total */
X{
X    /* caller has checked that shopkeeper exists */
X    register    ct = ESHK -> billct;
X    register struct bill_x *bp = bill;
X    total = 0;
X    while (ct--) {
X	total += bp -> price * bp -> bquan;
X	bp++;
X    }
X}
X
Xinshop ()
X{
X    register    tmp = inroom (u.ux, u.uy);
X    if (tmp < 0 || rooms[tmp].rtype < 8) {
X	u.uinshop = 0;
X	if (shopkeeper && ESHK -> billct) {
X	    pline ("Somehow you escaped the shop without paying!");
X	    addupbill ();
X	    pline ("You stole for a total worth of %lu zorkmids.",
X		    total);
X	    ESHK -> robbed += total;
X	    setpaid ();
X	}
X	if (tmp >= 0 && rooms[tmp].rtype == 7) {
X	    register struct monst  *mtmp;
X	    pline ("Welcome to David's treasure zoo!");
X	    rooms[tmp].rtype = 0;
X	    for (mtmp = fmon; mtmp; mtmp = mtmp -> nmon)
X		if (!rn2 (4))
X		    mtmp -> msleep = 0;
X	}
X    }
X    else {
X	if (shlevel != dlevel)
X	    setshk ();
X	if (!shopkeeper)
X	    u.uinshop = 0;
X	else
X	    if (!u.uinshop) {
X		if (!ESHK -> visitct ||
X			strncmp (ESHK -> customer, plname, PL_NSIZ)) {
X		    /* He seems to be new here */
X		    ESHK -> visitct = 0;
X		    (void) strncpy (ESHK -> customer, plname, PL_NSIZ);
X		    NOTANGRY = 1;
X		}
X		pline ("Hello %s! Welcome%s to %s's %s shop!",
X			plname,
X			ESHK -> visitct++ ? " again" : "",
X			shkname (),
X			shopnam[rooms[ESHK -> shoproom].rtype - 8]);
X		u.uinshop = 1;
X	    }
X    }
X    return (u.uinshop);
X}
X
Xsetshk ()
X{
X    register struct monst  *mtmp;
X    for (mtmp = fmon; mtmp; mtmp = mtmp -> nmon)
X	if (mtmp -> isshk) {
X	    shopkeeper = mtmp;
X	    bill = &(ESHK -> bill[0]);
X	    shlevel = dlevel;
X	    if (ANGRY && strncpy (ESHK -> customer, plname, PL_NSIZ))
X		NOTANGRY = 1;
X	    billobjs = 0;
X	    return;
X	}
X    shopkeeper = 0;
X    bill = (struct bill_x  *) - 1000;	/* dump core when referenced */
X}
X
Xstruct bill_x  *
Xonbill (obj)
Xregister struct obj   *obj;
X{
X    register struct bill_x *bp;
X    if (!shopkeeper)
X	return (0);
X    for (bp = bill; bp < &bill[ESHK -> billct]; bp++)
X	if (bp -> bo_id == obj -> o_id) {
X	    if (!obj -> unpaid)
X		pline ("onbill: paid obj on bill?");
X	    return (bp);
X	}
X    if (obj -> unpaid)
X	pline ("onbill: unpaid obj not on bill?");
X    return (0);
X}
X
X/* called with two args on merge */
Xobfree (obj, merge)
Xregister struct obj *obj, *merge;
X{
X    register struct bill_x *bp = onbill (obj);
X    register struct bill_x *bpm;
X    if (bp) {
X	if (!merge) {
X	    bp -> useup = 1;
X	    obj -> unpaid = 0;		/* only for doinvbill */
X	    obj -> nobj = billobjs;
X	    billobjs = obj;
X	    return;
X	}
X	bpm = onbill (merge);
X	if (!bpm) {
X	    /* this used to be a rename */
X	    impossible ();
X	    return;
X	}
X	else {
X	    /* this was a merger */
X	    bpm -> bquan += bp -> bquan;
X	    ESHK -> billct--;
X	    *bp = bill[ESHK -> billct];
X	}
X    }
X    free ((char *) obj);
X}
X
Xpay (tmp) long  tmp;
X{
X    u.ugold -= tmp;
X    shopkeeper -> mgold += tmp;
X    flags.botl = 1;
X}
X
Xdopay ()
X{
X    long    ltmp;
X    register struct bill_x *bp;
X    int     shknear = (shlevel == dlevel && shopkeeper &&
X	        dist (shopkeeper -> mx, shopkeeper -> my) < 3);
X    int     pass, tmp;
X
X    multi = 0;
X    if (!inshop () && !shknear) {
X	pline ("You are not in a shop.");
X	return (0);
X    }
X    if (!shknear &&
X	    inroom (shopkeeper -> mx, shopkeeper -> my) != ESHK -> shoproom) {
X	pline ("There is nobody here to receive your payment.");
X	return (0);
X    }
X    if (!ESHK -> billct) {
X	pline ("You do not owe %s anything.", monnam (shopkeeper));
X	if (!u.ugold) {
X	    pline ("Moreover, you have no money.");
X	    return (1);
X	}
X	if (ESHK -> robbed) {
X	    pline ("But since the shop has been robbed recently,");
X	    pline ("you %srepay %s's expenses.",
X		    (u.ugold < ESHK -> robbed) ? "partially " : "",
X		    monnam (shopkeeper));
X	    pay ((u.ugold < ESHK -> robbed) ? u.ugold : ESHK -> robbed);
X	    ESHK -> robbed = 0;
X	    return (1);
X	}
X	if (ANGRY) {
X	    pline ("But in order to appease %s,",
X		    amonnam (shopkeeper, "angry"));
X	    if (u.ugold >= 1000) {
X		ltmp = 1000;
X		pline (" you give him 1000 gold pieces.");
X	    }
X	    else {
X		ltmp = u.ugold;
X		pline (" you give him all your money.");
X	    }
X	    pay (ltmp);
X	    if (rn2 (3)) {
X		pline ("%s calms down.", Monnam (shopkeeper));
X		NOTANGRY = 1;
X	    }
X	    else
X		pline ("%s is as angry as ever.",
X			Monnam (shopkeeper));
X	}
X	return (1);
X    }
X    for (pass = 0; pass <= 1; pass++) {
X	tmp = 0;
X	while (tmp < ESHK -> billct) {
X	    bp = &bill[tmp];
X	    if (!pass && !bp -> useup) {
X		tmp++;
X		continue;
X	    }
X	    if (!dopayobj (bp))
X		return (1);
X	    bill[tmp] = bill[--ESHK -> billct];
X	}
X    }
X    pline ("Thank you for shopping in %s's %s store!",
X	    shkname (),
X	    shopnam[rooms[ESHK -> shoproom].rtype - 8]);
X    NOTANGRY = 1;
X    return (1);
X}
X
X/* return 1 if paid successfully */
X/*        0 if not enough money */
X/*       -1 if object could not be found (but was paid) */
Xdopayobj (bp)
Xregister struct bill_x   *bp;
X{
X    register struct obj *obj;
X    long    ltmp;
X
X    /* find the object on one of the lists */
X    if (bp -> useup)
X	obj = o_on (bp -> bo_id, billobjs);
X    else
X	if (!(obj = o_on (bp -> bo_id, invent)) &&
X		!(obj = o_on (bp -> bo_id, fobj)) &&
X		!(obj = o_on (bp -> bo_id, fcobj))) {
X	    register struct monst  *mtmp;
X	    for (mtmp = fmon; mtmp; mtmp = mtmp -> nmon)
X		if (obj = o_on (bp -> bo_id, mtmp -> minvent))
X		    break;
X	    for (mtmp = fallen_down; mtmp; mtmp = mtmp -> nmon)
X		if (obj = o_on (bp -> bo_id, mtmp -> minvent))
X		    break;
X	}
X    if (!obj) {
X	pline ("Shopkeeper administration out of order.");
X	impossible ();
X	setpaid ();			/* be nice to the player */
X	return (0);
X    }
X
X    if (!obj -> unpaid && !bp -> useup) {
X	pline ("Paid object on bill??");
X	impossible ();
X	return (1);
X    }
X    obj -> unpaid = 0;
X    ltmp = bp -> price * bp -> bquan;
X    if (ANGRY)
X	ltmp += ltmp / 3;
X    if (u.ugold < ltmp) {
X	pline ("You don't have gold enough to pay %s.",
X		doname (obj));
X	obj -> unpaid = 1;
X	return (0);
X    }
X    pay (ltmp);
X    pline ("You bought %s for %ld gold piece%s.",
X	    doname (obj), ltmp, (ltmp == 1) ? "" : "s");
X    if (bp -> useup) {
X	register struct obj *otmp = billobjs;
X	if (obj == billobjs)
X	    billobjs = obj -> nobj;
X	else {
X	    while (otmp && otmp -> nobj != obj)
X		otmp = otmp -> nobj;
X	    if (otmp)
X		otmp -> nobj = obj -> nobj;
X	    else
X		pline ("Error in shopkeeper administration");
X	}
X	free ((char *) obj);
X    }
X    return (1);
X}
X
X/* routine called after dying (or quitting) with nonempty bill */
Xpaybill ()
X{
X    if (shopkeeper && ESHK -> billct) {
X	addupbill ();
X	if (total > u.ugold) {
X	    shopkeeper -> mgold += u.ugold;
X	    u.ugold = 0;
X	    pline ("%s comes and takes all your possessions.",
X		    Monnam (shopkeeper));
X	}
X	else {
X	    u.ugold -= total;
X	    shopkeeper -> mgold += total;
X	    pline ("%s comes and takes the %ld zorkmids you owed him.",
X		    Monnam (shopkeeper), total);
X	}
X	setpaid ();			/* in case we create bones */
X    }
X}
X
X/* called in hack.c when we pickup an object */
Xaddtobill (obj)
Xregister struct obj *obj;
X{
X    register struct bill_x *bp;
X    if (!inshop () || (u.ux == ESHK -> shk.x && u.uy == ESHK -> shk.y) ||
X	    (u.ux == ESHK -> shd.x && u.uy == ESHK -> shd.y) ||
X	    onbill (obj)		/* perhaps we threw it away earlier */
X	)
X	return;
X    if (ESHK -> billct == BILLSZ) {
X	pline ("You got that for free!");
X	return;
X    }
X    bp = &bill[ESHK -> billct];
X    bp -> bo_id = obj -> o_id;
X    bp -> bquan = obj -> quan;
X    bp -> useup = 0;
X    bp -> price = getprice (obj);
X    ESHK -> billct++;
X    obj -> unpaid = 1;
X}
X
Xsplitbill (obj, otmp)
Xregister struct obj  *obj, *otmp;
X{
X    /* otmp has been split off from obj */
X    register struct bill_x *bp;
X    register int    tmp;
X    bp = onbill (obj);
X    if (!bp) {
X	impossible ();
X	return;
X    }
X    if (bp -> bquan < otmp -> quan) {
X	pline ("Negative quantity on bill??");
X	impossible ();
X    }
X    if (bp -> bquan == otmp -> quan) {
X	pline ("Zero quantity on bill??");
X	impossible ();
X    }
X    bp -> bquan -= otmp -> quan;
X
X    /* addtobill(otmp); */
X    if (ESHK -> billct == BILLSZ)
X	otmp -> unpaid = 0;
X    else {
X	tmp = bp -> price;
X	bp = &bill[ESHK -> billct];
X	bp -> bo_id = otmp -> o_id;
X	bp -> bquan = otmp -> quan;
X	bp -> useup = 0;
X	bp -> price = tmp;
X	ESHK -> billct++;
X    }
X}
X
Xsubfrombill (obj)
Xregister struct obj  *obj;
X{
X    long    ltmp;
X    register int    tmp;
X    register struct obj *otmp;
X    register struct bill_x *bp;
X    if (!inshop () || (u.ux == ESHK -> shk.x && u.uy == ESHK -> shk.y) ||
X	    (u.ux == ESHK -> shd.x && u.uy == ESHK -> shd.y))
X	return;
X    if ((bp = onbill (obj)) != 0) {
X	obj -> unpaid = 0;
X	if (bp -> bquan > obj -> quan) {
X	    otmp = newobj (0);
X	    *otmp = *obj;
X	    bp -> bo_id = otmp -> o_id = flags.ident++;
X	    otmp -> quan = (bp -> bquan -= obj -> quan);
X	    otmp -> owt = 0;		/* superfluous */
X	    otmp -> onamelth = 0;
X	    bp -> useup = 1;
X	    otmp -> nobj = billobjs;
X	    billobjs = otmp;
X	    return;
X	}
X	ESHK -> billct--;
X	*bp = bill[ESHK -> billct];
X	return;
X    }
X    if (obj -> unpaid) {
X	pline ("%s didn't notice.", Monnam (shopkeeper));
X	obj -> unpaid = 0;
X	return;				/* %% */
X    }
X    /* he dropped something of his own - probably wants to sell it */
X    if (shopkeeper -> msleep || shopkeeper -> mfroz ||
X	    inroom (shopkeeper -> mx, shopkeeper -> my) != ESHK -> shoproom)
X	return;
X    if (ESHK -> billct == BILLSZ ||
X	    ((tmp = shtypes[rooms[ESHK -> shoproom].rtype - 8]) && tmp != obj -> olet)
X	    || index ("_0", obj -> olet)) {
X	pline ("%s seems not interested.", Monnam (shopkeeper));
X	return;
X    }
X    ltmp = getprice (obj) * obj -> quan;
X    if (ANGRY) {
X	ltmp /= 3;
X	NOTANGRY = 1;
X    }
X    else
X	ltmp /= 2;
X    if (ESHK -> robbed) {
X	if ((ESHK -> robbed -= ltmp) < 0)
X	    ESHK -> robbed = 0;
X	pline ("Thank you for your contribution to restock this recently plundered shop.");
X	return;
X    }
X    if (ltmp > shopkeeper -> mgold)
X	ltmp = shopkeeper -> mgold;
X    pay (-ltmp);
X    if (!ltmp)
X	pline ("%s gladly accepts %s but cannot pay you at present.",
X		Monnam (shopkeeper), doname (obj));
X    else
X	pline ("You sold %s and got %ld gold piece%s.", doname (obj), ltmp,
X		(ltmp == 1) ? "" : "s");
X}
X
Xdoinvbill (cl)
Xint  cl;
X{
X    register unsigned   tmp, cnt = 0;
X    register struct obj *obj;
X    char    buf[BUFSZ];
X    int	    retval;
X
X    retval = 0;
X    if (!shopkeeper)
X	return (retval);
X    for (tmp = 0; tmp < ESHK -> billct; tmp++)
X	if (bill[tmp].useup)
X	    cnt++;
X    if (!cnt)
X	return (retval);
X    if (!cl && !flags.oneline)
X	cls ();
X    if (!flags.oneline) {
X	retval = 1;
X	puts ("\n\nUnpaid articles already used up:\n");
X    }
X    for (tmp = 0; tmp < ESHK -> billct; tmp++)
X	if (bill[tmp].useup) {
X	    for (obj = billobjs; obj; obj = obj -> nobj)
X		if (obj -> o_id == bill[tmp].bo_id)
X		    break;
X	    if (!obj) {
X		pline ("Bad shopkeeper administration.");
X		impossible ();
X		return (retval);
X	    }
X	    retval = 1;
X	    (void) sprintf (buf, "* -  %s", doname (obj));
X	    for (cnt = 0; buf[cnt]; cnt++);
X	    while (cnt < 50)
X		buf[cnt++] = ' ';
X	    (void) sprintf (&buf[cnt], " %5d zorkmids",
X		    bill[tmp].price * bill[tmp].bquan);
X	    if (flags.oneline)
X		pline (buf);
X	    else
X		puts (buf);
X	}
X    if (!cl && !flags.oneline) {
X	getret ();
X	docrt ();
X    }
X    return (retval);
X}
X
Xgetprice (obj)
Xregister struct obj *obj;
X{
X    register int    tmp, ac;
X    switch (obj -> olet) {
X	case AMULET_SYM: 
X	    tmp = 10 * rnd (500);
X	    break;
X	case TOOL_SYM: 
X	    tmp = 10 * rnd (150);
X	    break;
X	case RING_SYM: 
X	    tmp = 10 * rnd (100);
X	    break;
X	case WAND_SYM: 
X	    tmp = 10 * rnd (100);
X	    break;
X	case SCROLL_SYM: 
X	    tmp = 10 * rnd (50);
X	    break;
X	case POTION_SYM: 
X	    tmp = 10 * rnd (50);
X	    break;
X	case FOOD_SYM: 
X	    tmp = 10 * rnd (5 + (2000 / realhunger ()));
X	    break;
X	case GEM_SYM: 
X	    tmp = 10 * rnd (20);
X	    break;
X	case ARMOR_SYM: 
X	    ac = 10 - obj -> spe;
X	    tmp = 100 + (10 - ac) * (10 - ac) * rnd (20 - ac);
X	    break;
X	case WEAPON_SYM: 
X	    if (obj -> otyp < BOOMERANG)
X		tmp = 5 * rnd (10);
X	    else
X		if (obj -> otyp == LONG_SWORD ||
X			obj -> otyp == TWO_HANDED_SWORD)
X		    tmp = 10 * rnd (150);
X		else
X		    tmp = 10 * rnd (75);
X	    break;
X	case CHAIN_SYM: 
X	    pline ("Strange ..., carrying a chain?");
X	case BALL_SYM: 
X	    tmp = 10;
X	    break;
X	default: 
X	    tmp = 10000;
X    }
X    return (tmp);
X}
X
Xrealhunger ()	/* not completely foolproof */
X{
X    register    tmp = u.uhunger;
X    register struct obj *otmp = invent;
X    while (otmp) {
X	if (otmp -> olet == FOOD_SYM && !otmp -> unpaid)
X	    tmp += objects[otmp -> otyp].nutrition;
X	otmp = otmp -> nobj;
X    }
X    return ((tmp <= 0) ? 1 : tmp);
X}
X
Xshk_move ()
X{
X    register struct monst  *mtmp;
X    register struct permonst   *mdat = shopkeeper -> data;
X    register    xchar gx, gy, omx, omy, nx, ny, nix, niy;
X    register    schar appr, i;
X    schar shkr, tmp, chi, chcnt, cnt;
X    boolean uondoor, avoid;
X    coord poss[9];
X    int     info[9];
X    omx = shopkeeper -> mx;
X    omy = shopkeeper -> my;
X    shkr = inroom (omx, omy);
X    if (ANGRY && dist (omx, omy) < 3) {
X	(void) hitu (shopkeeper, d (mdat -> damn, mdat -> damd) + 1);
X	return (0);
X    }
X    appr = 1;
X    gx = ESHK -> shk.x;
X    gy = ESHK -> shk.y;
X    if (ANGRY) {
X	int     saveBlind = Blind;
X	Blind = 0;
X	if (shopkeeper -> mcansee && !Invis && cansee (omx, omy)) {
X	    gx = u.ux;
X	    gy = u.uy;
X	}
X	Blind = saveBlind;
X	avoid = FALSE;
X    }
X    else {
X#define	GDIST(x,y)	((x-gx)*(x-gx)+(y-gy)*(y-gy))
X	if (Invis)
X	    avoid = FALSE;
X	else {
X	    uondoor = (u.ux == ESHK -> shd.x && u.uy == ESHK -> shd.y);
X	    avoid = ((u.uinshop && dist (gx, gy) > 8) || uondoor);
X	    if (((!ESHK -> robbed && !ESHK -> billct) || avoid)
X		    && GDIST (omx, omy) < 3) {
X		if (!online (omx, omy))
X		    return (0);
X		if (omx == gx && omy == gy)
X		    appr = gx = gy = 0;
X	    }
X	}
X    }
X    if (omx == gx && omy == gy)
X	return (0);
X    if (shopkeeper -> mconf)
X	appr = 0;
X    nix = omx;
X    niy = omy;
X    cnt = mfndpos (shopkeeper, poss, info,
X	    (avoid ? NOTONL : 0) | ALLOW_SSM);
X    if (cnt == 0 && avoid && uondoor)
X	cnt = mfndpos (shopkeeper, poss, info, ALLOW_SSM);
X    chi = -1;
X    chcnt = 0;
X    for (i = 0; i < cnt; i++) {
X	nx = poss[i].x;
X	ny = poss[i].y;
X	if ((tmp = levl[nx][ny].typ) == ROOM ||
X		(shkr != ESHK -> shoproom && (tmp == CORR || tmp == DOOR)))
X	    if ((!appr && !rn2 (++chcnt)) ||
X		    (appr && GDIST (nx, ny) < GDIST (nix, niy))) {
X		nix = nx;
X		niy = ny;
X		chi = i;
X	    }
X    }
X    if (nix != omx || niy != omy) {
X	if (info[chi] & ALLOW_M) {
X	    mtmp = m_at (nix, niy);
X	    if (hitmm (shopkeeper, mtmp) == 1 && rn2 (3) &&
X		    hitmm (mtmp, shopkeeper) == 2)
X		return (2);
X	    return (0);
X	}
X	else
X	    if (info[chi] & ALLOW_U) {
X		(void) hitu (shopkeeper, d (mdat -> damn, mdat -> damd) + 1);
X		return (0);
X	    }
X	shopkeeper -> mx = nix;
X	shopkeeper -> my = niy;
X	pmon (shopkeeper);
X	return (1);
X    }
X    return (0);
X}
X#endif QUEST
X
Xchar   *
Xplur (n) unsigned   n;
X{
X    return ((n == 1) ? "" : "s");
X}
X
Xonline (x, y)
X{
X    return (x == u.ux || y == u.uy ||
X	    (x - u.ux) * (x - u.ux) == (y - u.uy) * (y - u.uy));
X}
--burp--
sed 's/^X//' << '--burp--' > hack.termcap.c
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
X
X#include <stdio.h>
X#include "config.h"			/* for ROWNO and COLNO */
Xextern char *tgetstr (), *tgoto (), *getenv ();
Xextern long *alloc ();
X
Xshort   ospeed;				/* terminal baudrate; used by tputs */
Xchar    tbuf[512];
Xchar   *HO, *CL, *CE, *UP, *CM, *ND, *XD, *BC, *SO, *SE, *TI, *TE;
Xchar   *VS, *VE, *CD;
Xint	SG;
Xchar    PC = '\0';
X
Xstartup ()
X{
X    register char  *tmp;
X    register char  *tptr;
X    char   *tbufptr, *pc;
X
X    gettty ();				/* sets ospeed */
X
X    tptr = (char *) alloc (1024);
X
X    tbufptr = tbuf;
X    if (!(tmp = getenv ("TERM")))
X	error ("Can't get TERM.");
X    if (tgetent (tptr, tmp) < 1)
X	error ("Unknown terminal type: %s.", tmp);
X    if (pc = tgetstr ("pc", &tbufptr))
X	PC = *pc;
X    if (!(BC = tgetstr ("bc", &tbufptr))) {
X	if (!tgetflag ("bs"))
X	    error ("Terminal must backspace.");
X	BC = tbufptr;
X	tbufptr += 2;
X	*BC = '\b';
X    }
X    HO = tgetstr ("ho", &tbufptr);
X    if (tgetnum ("co") < COLNO || tgetnum ("li") < ROWNO + 2)
X	error ("Screen must be at least %d by %d!",
X		ROWNO + 2, COLNO);
X    if (!(CL = tgetstr ("cl",&tbufptr))
X    || !(ND = tgetstr ("nd", &tbufptr))
X    || !(UP = tgetstr ("up",&tbufptr))
X    || tgetflag ("os"))
X		error("Hack needs CL, UP, ND, and no OS.");
X    if (!(CM = tgetstr ("cm", &tbufptr)))
X	printf ("Use of hack on terminals without CM is suspect...\n");
X    CE = tgetstr ("ce",&tbufptr);
X    CD = tgetstr ("cd",&tbufptr);
X    XD = tgetstr ("xd", &tbufptr);
X    SO = tgetstr ("so", &tbufptr);
X    SE = tgetstr ("se", &tbufptr);
X    SG = tgetnum ("sg");
X    TI = tgetstr ("ti", &tbufptr);
X    TE = tgetstr ("te", &tbufptr);
X    VS = tgetstr ("vs", &tbufptr);
X    VE = tgetstr ("ve", &tbufptr);
X    if (!SO || !SE || !SG)
X	SO = SE = 0;
X    if (tbufptr - tbuf > sizeof (tbuf))
X	error ("TERMCAP entry too big...\n");
X    free (tptr);
X    start_screen ();
X}
X
Xstart_screen ()
X{
X    xputs (TI);
X    xputs (VS);
X}
X
Xend_screen ()
X{
X    xputs (TE);
X    xputs (VE);
X}
X
X/* Cursor movements */
Xextern  xchar curx, cury;
X
Xcurs (x, y)
Xregister int    x, y;			/* not xchar: perhaps xchar is unsigned and curx-x would be unsigned as well */
X{
X
X    if (y == cury && x == curx)
X	return;
X    if (abs (cury - y) <= 3 && abs (curx - x) <= 3)
X	nocmov (x, y);
X    else
X	if ((x <= 3 && abs (cury - y) <= 3) || (!CM && x < abs (curx - x))) {
X	    (void) putchar ('\r');
X	    curx = 1;
X	    nocmov (x, y);
X	}
X	else
X	    if (!CM)
X		nocmov (x, y);
X	    else
X		cmov (x, y);
X}
X
Xnocmov (x, y)
X{
X    if (curx < x) {			/* Go to the right. */
X	while (curx < x) {
X	    xputs (ND);
X	    curx++;
X	}
X    }
X    else
X	if (curx > x) {
X	    while (curx > x) {		/* Go to the left. */
X		xputs (BC);
X		curx--;
X	    }
X	}
X    if (cury > y) {
X	if (UP) {
X	    while (cury > y) {		/* Go up. */
X		xputs (UP);
X		cury--;
X	    }
X	}
X	else
X	    cmov (x, y);
X    }
X    else
X	if (cury < y) {
X	    if (XD) {
X		while (cury < y) {
X		    xputs (XD);
X		    cury++;
X		}
X	    }
X	    else
X		cmov (x, y);
X	}
X}
X
Xcmov (x, y)
Xregister    x, y;
X{
X    if (!CM)
X	error ("Tries to cmov from %d %d to %d %d\n", curx, cury, x, y);
X    xputs (tgoto (CM, x - 1, y - 1));
X    cury = y;
X    curx = x;
X}
X
Xxputc (c)
Xchar  c;
X{
X    (void) fputc (c, stdout);
X}
X
Xxputs (s)
Xchar *s;
X{
X    tputs (s, 1, xputc);
X}
X
Xcl_end ()
X{
X    register int	i;
X
X    if (CE)
X	xputs (CE);
X    else {
X	for (i = COLNO - curx; i > 0; --i)
X	    xputc (' ');
X	cmov (curx, cury);
X    }
X}
X
Xcl_eos ()
X{
X    register int	i;
X
X    if (CD)
X	xputs (CD);
X    else {
X	for (i = (ROWNO + 1) - curx; i > 0; --i) {
X	    cl_end ();
X	    putchar ('\r');
X	    putchar ('\n');
X	}
X	cl_end ();
X	cmov (curx, cury);
X    }
X}
X
Xclear_screen ()
X{
X    xputs (CL);
X    curx = cury = 1;
X}
X
Xhome ()
X{
X    if (HO)
X	xputs (HO);
X    else
X	xputs (tgoto (CM, 0, 0));
X    curx = cury = 1;
X}
X
Xstandoutbeg ()
X{
X    if (SO)
X	xputs (SO);
X}
X
Xstandoutend ()
X{
X    if (SE)
X	xputs (SE);
X}
X
Xbacksp ()
X{
X    xputs (BC);
X    curx--;
X}
X
Xbell ()
X{
X    putsym ('\007');
X}
X
Xdelay_output ()
X{
X    /* delay 40 ms - could also use a 'nap'-system call */
X    tputs ("40", 1, xputc);
X}
--burp--
sed 's/^X//' << '--burp--' > hack.topl.c
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
X
X#include "hack.h"
X#include <stdio.h>
Xextern char *eos ();
X#define	TOPLSZ	(COLNO-8)		/* leave room for --More-- */
Xchar    toplines[BUFSZ];
Xxchar tlx, tly;				/* set by pline; used by addtopl */
X
Xstruct topl {
X    struct topl *next_topl;
X    char   *topl_text;
X}          *old_toplines, *last_redone_topl;
X#define	OTLMAX	20			/* max nr of old toplines remembered */
X
Xdoredotopl ()
X{
X    if (last_redone_topl)
X	last_redone_topl = last_redone_topl -> next_topl;
X    if (!last_redone_topl)
X	last_redone_topl = old_toplines;
X    if (last_redone_topl) {
X	(void) strcpy (toplines, last_redone_topl -> topl_text);
X    }
X    redotoplin ();
X    return (0);
X}
X
Xredotoplin ()
X{
X    home ();
X    if (index (toplines, '\n'))
X	cl_end ();
X    putstr (toplines);
X    cl_end ();
X    tlx = curx;
X    tly = cury;
X    flags.topl = 1;
X    if (tly > 1)
X	more ();
X}
X
Xremember_topl ()
X{
X    register struct topl   *tl;
X    register int    cnt = OTLMAX;
X    if (last_redone_topl &&
X	    !strcmp (toplines, last_redone_topl -> topl_text))
X	return;
X    if (old_toplines &&
X	    !strcmp (toplines, old_toplines -> topl_text))
X	return;
X    last_redone_topl = 0;
X    tl = (struct topl  *)
X                        alloc ((unsigned) (strlen (toplines) + sizeof (struct topl) + 1));
X    tl -> next_topl = old_toplines;
X    tl -> topl_text = (char *) (tl + 1);
X    (void) strcpy (tl -> topl_text, toplines);
X    old_toplines = tl;
X    while (cnt && tl) {
X	cnt--;
X	tl = tl -> next_topl;
X    }
X    if (tl && tl -> next_topl) {
X	free ((char *) tl -> next_topl);
X	tl -> next_topl = 0;
X    }
X}
X
Xaddtopl (s) char   *s;
X{
X    curs (tlx, tly);
X    if (tlx + strlen (s) > COLNO)
X	putsym ('\n');
X    putstr (s);
X    tlx = curx;
X    tly = cury;
X    flags.topl = 1;
X}
X
Xxmore (spaceflag)
Xboolean spaceflag;			/* TRUE if space required */
X{
X    if (flags.topl) {
X	curs (tlx, tly);
X	if (tlx + 8 > COLNO)
X	    putsym ('\n'), tly++;
X    }
X    standoutbeg ();
X    putstr ("--More--");
X    standoutend ();
X    xwaitforspace (spaceflag);
X    if (flags.topl && tly > 1) {
X	home ();
X	cl_end ();
X	docorner (1, tly - 1);
X    }
X    flags.topl = 0;
X}
X
Xmore ()
X{
X    xmore (TRUE);
X}
X
Xcmore ()
X{
X    xmore (FALSE);
X}
X
Xclrlin ()
X{
X    if (flags.topl) {
X	home ();
X	cl_end ();
X	if (tly > 1)
X	    docorner (1, tly - 1);
X	remember_topl ();
X    }
X    flags.topl = 0;
X}
X
X/*VARARGS1*/
Xpline (line, arg1, arg2, arg3, arg4, arg5, arg6)
Xregister char  *line, *arg1, *arg2, *arg3, *arg4, *arg5, *arg6;
X{
X    char    pbuf[BUFSZ];
X    register char  *bp = pbuf, *tl;
X    register int    n, n0;
X
X    if (!line || !*line)
X	return;
X    if (!index (line, '%'))
X	(void) strcpy (pbuf, line);
X    else
X	(void) sprintf (pbuf, line, arg1, arg2, arg3, arg4, arg5, arg6);
X    if (flags.topl == 1 && !strcmp (pbuf, toplines))
X	return;
X    nscr ();				/* %% */
X
X    /* If there is room on the line, print message on same line */
X    /* But messages like "You die..." deserve their own line */
X    n0 = strlen (bp);
X    if (flags.topl == 1 && tly == 1 &&
X	    n0 + strlen (toplines) + 3 < TOPLSZ &&
X	    strncmp (bp, "You ", 4)) {
X	(void) strcat (toplines, "  ");
X	(void) strcat (toplines, bp);
X	tlx += 2;
X	addtopl (bp);
X	return;
X    }
X    if (flags.topl == 1)
X	more ();
X    remember_topl ();
X    toplines[0] = 0;
X    while (n0) {
X	if (n0 >= COLNO) {
X	    /* look for appropriate cut point */
X	    n0 = 0;
X	    for (n = 0; n < COLNO; n++)
X		if (bp[n] == ' ')
X		    n0 = n;
X	    if (!n0)
X		for (n = 0; n < COLNO - 1; n++)
X		    if (!letter (bp[n]))
X			n0 = n;
X	    if (!n0)
X		n0 = COLNO - 2;
X	}
X	(void) strncpy ((tl = eos (toplines)), bp, n0);
X	tl[n0] = 0;
X	bp += n0;
X
X	/* remove trailing spaces, but leave one */
X	while (n0 > 1 && tl[n0 - 1] == ' ' && tl[n0 - 2] == ' ')
X	    tl[--n0] = 0;
X
X	n0 = strlen (bp);
X	if (n0 && tl[0])
X	    (void) strcat (tl, "\n");
X    }
X    redotoplin ();
X}
X
Xputsym (c)
Xchar c;
X{
X    switch (c) {
X	case '\b': 
X	    backsp ();
X	    return;
X	case '\n': 
X	    curx = 1;
X	    cury++;
X	    if (cury > tly)
X		tly = cury;
X	    break;
X	default: 
X	    curx++;
X	    if (curx == COLNO)
X		putsym ('\n');
X    }
X    (void) putchar (c);
X}
X
Xputstr (s)
Xregister char   *s;
X{
X    while (*s)
X	putsym (*s++);
X}
--burp--
sed 's/^X//' << '--burp--' > hack.tty.c
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
X
X#include	"hack.h"
X#include	<stdio.h>
X#include	<sgtty.h>
X#include	<ctype.h>
X
Xstruct sgttyb   inittyb, curttyb;
Xextern short    ospeed;
X
X
Xgettty ()
X{
X    (void) gtty (0, &inittyb);
X    (void) gtty (0, &curttyb);
X    ospeed = inittyb.sg_ospeed;
X/*
X	if(ospeed <= B300) flags.oneline = 1;
X*/
X    getioctls ();
X    xtabs ();
X}
X
X/* reset terminal to original state */
Xsettty (s)
Xchar *s;
X{
X    clear_screen ();
X    end_screen ();
X    if (s)
X	printf (s);
X    (void) fflush (stdout);
X    if (stty (0, &inittyb) == -1)
X	puts ("Cannot change tty");
X    flags.echo = (inittyb.sg_flags & ECHO) ? ON : OFF;
X    flags.cbreak = (inittyb.sg_flags & CBREAK) ? ON : OFF;
X    setioctls ();
X}
X
Xsetctty ()
X{
X    if (stty (0, &curttyb) == -1)
X	puts ("Cannot change tty");
X}
X
Xsetftty ()
X{
X    register int    ef = (flags.echo == ON) ? ECHO : 0;
X    register int    cf = (flags.cbreak == ON) ? CBREAK : 0;
X    register int    change = 0;
X    if ((curttyb.sg_flags & ECHO) != ef) {
X	curttyb.sg_flags &= ~ECHO;
X	curttyb.sg_flags |= ef;
X	change++;
X    }
X    if ((curttyb.sg_flags & CBREAK) != cf) {
X	curttyb.sg_flags &= ~CBREAK;
X	curttyb.sg_flags |= cf;
X	change++;
X    }
X    if (change) {
X	setctty ();
X    }
X}
X
Xecho (n)
Xregister    n;
X{
X
X    /* (void) gtty(0,&curttyb); */
X    if (n == ON)
X	curttyb.sg_flags |= ECHO;
X    else
X	curttyb.sg_flags &= ~ECHO;
X    setctty ();
X}
X
X/* always want to expand tabs, or to send a clear line char before
X   printing something on topline */
Xxtabs ()
X{
X
X    /* (void) gtty(0, &curttyb); */
X    curttyb.sg_flags |= XTABS;
X    setctty ();
X}
X
X#ifdef LONG_CMD
Xcbreak (n)
Xregister    n;
X{
X
X    /* (void) gtty(0,&curttyb); */
X    if (n == ON)
X	curttyb.sg_flags |= CBREAK;
X    else
X	curttyb.sg_flags &= ~CBREAK;
X    setctty ();
X}
X#endif LONG_CMD
X
Xgetlin (bufp)
Xregister char  *bufp;
X{
X    register char  *obufp = bufp;
X    register int    c;
X
X    flags.topl = 2;			/* nonempty, no --More-- required */
X    for (;;) {
X	(void) fflush (stdout);
X	if ((c = getchar ()) == EOF) {
X	    *bufp = 0;
X	    return;
X	}
X	if (c == '\b') {
X	    if (bufp != obufp) {
X		bufp--;
X		putstr ("\b \b");	/* putsym converts \b */
X	    }
X	    else
X		bell ();
X	}
X	else if (c == '\n') {
X	    *bufp = 0;
X	    return;
X	}
X	else if (c == '\177') {
X	    while (bufp != obufp) {
X		putstr ("\b \b");
X		bufp--;
X	    }
X	}
X	else if (isprint(c)) {
X	    *bufp = c;
X	    bufp[1] = 0;
X	    putstr (bufp);
X	    if (bufp - obufp < BUFSZ - 1 && bufp - obufp < COLNO)
X		bufp++;
X	}
X	else
X	    bell();
X    }
X}
X
Xgetret ()
X{
X    xgetret (TRUE);
X}
X
Xcgetret ()
X{
X    xgetret (FALSE);
X}
X
Xxgetret (spaceflag)
Xboolean spaceflag;		/* TRUE if space (return) required */
X{
X    printf ("\nHit %s to continue: ",
X	    flags.cbreak ? "space" : "return");
X    xwaitforspace (spaceflag);
X}
X
Xchar    morc;			/* tell the outside world what char he used */
Xxwaitforspace (spaceflag)
Xboolean spaceflag;
X{
X    register int    c;
X
X    (void) fflush (stdout);
X    morc = 0;
X
X    while ((c = getchar ()) != '\n') {
X	if (c == EOF) {
X	    settty ("End of input?\n");
X	    exit (0);
X	}
X	if (flags.cbreak) {
X	    if (c == ' ')
X		break;
X	    if (!spaceflag && letter (c)) {
X		morc = c;
X		break;
X	    }
X	}
X    }
X}
X
Xchar   *
Xparse ()
X{
X    static char inline[COLNO];
X    register    foo;
X
X    flags.move = 1;
X    if (!Invis)
X	curs (u.ux, u.uy + 2);
X    else
X	home ();
X    (void) fflush (stdout);
X    while ((foo = getchar ()) >= '0' && foo <= '9')
X	multi += 10 * multi + foo - '0';
X    if (multi) {
X	multi--;
X	save_cm = inline;
X    }
X    inline[0] = foo;
X    inline[1] = 0;
X    if (foo == EOF) {
X	settty ("End of input?\n");
X	exit (0);
X    }
X    if (foo == 'f' || foo == 'F') {
X	inline[1] = getchar ();
X#ifdef QUEST
X	if (inline[1] == foo)
X	    inline[2] = getchar ();
X	else
X#endif QUEST
X		inline[2] = 0;
X    }
X    if (foo == 'm' || foo == 'M') {
X	inline[1] = getchar ();
X	inline[2] = 0;
X    }
X    clrlin ();
X    return (inline);
X}
X
Xchar
Xreadchar ()
X{
X    register int    sym;
X    (void) fflush (stdout);
X    if ((sym = getchar ()) == EOF) {
X	settty ("End of input?\n");
X	exit (0);
X    }
X    if (flags.topl == 1)
X	flags.topl = 2;
X    return ((char) sym);
X}
--burp--
sed 's/^X//' << '--burp--' > hack.wield.c
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
X
X#include	"hack.h"
X
Xsetuwep (obj)
Xregister struct obj  *obj;
X{
X    setworn (obj, W_WEP);
X}
X
Xdowield ()
X{
X    register struct obj *wep;
X    register int    res = 0;
X
X    multi = 0;
X    if (!(wep = getobj ("#-)", "wield")))
X	/* nothing */ ;
X    else if (uwep == wep)
X	pline ("You are already wielding that!");
X    else if (uwep && uwep -> cursed)
X	pline ("The %s welded to your hand!", aobjnam (uwep, "are"));
X    else if ((int) wep == -1) {
X	if (uwep == 0) {
X	    pline ("You are already empty handed.");
X	}
X	else {
X	    setuwep ((struct obj   *) 0);
X	    res++;
X	    pline ("You are empty handed.");
X	}
X    }
X    else if (uarms && wep -> otyp == TWO_HANDED_SWORD)
X	pline ("You cannot wield a two-handed sword and wear a shield.");
X    else if (wep -> owornmask & (W_ARMOR | W_RING))
X	pline ("You cannot wield that!");
X    else {
X	setuwep (wep);
X	res++;
X	if (uwep -> cursed)
X	    pline ("The %s itself to your hand!", aobjnam (uwep, "weld"));
X	else
X	    prinv (uwep);
X    }
X    return (res);
X}
X
Xcorrode_weapon ()
X{
X    if (!uwep || uwep -> olet != WEAPON_SYM)
X	return;				/* %% */
X    if (uwep -> rustfree)
X	pline ("Your %s not affected.", aobjnam (uwep, "are"));
X    else {
X	pline ("Your %s!", aobjnam (uwep, "corrode"));
X	uwep -> spe--;
X    }
X}
X
Xchwepon (otmp, amount)
Xregister struct obj *otmp;
Xregister    amount;
X{
X    register char  *color = (amount < 0) ? "black" : "green";
X    register char  *time;
X    if (!uwep || uwep -> olet != WEAPON_SYM) {
X	pline ((amount > 0) ? "Your hands glow then fade." : "Your hands itch.");
X	strange_feeling (otmp);
X	return (0);
X    }
X
X    if (uwep -> otyp == WORM_TOOTH && amount > 0) {
X	uwep -> otyp = CRYSKNIFE;
X	pline ("Your weapon seems sharper now.");
X	uwep -> cursed = 0;
X	return (1);
X    }
X
X    if (uwep -> otyp == CRYSKNIFE && amount < 0) {
X	uwep -> otyp = WORM_TOOTH;
X	pline ("Your weapon looks duller now.");
X	return (1);
X    }
X
X    /* there is a (soft) upper limit to uwep->spe */
X    if (amount > 0 && uwep -> spe > 5 && rn2 (3)) {
X	pline ("Your %s violently green for a while and then evaporates.",
X		aobjnam (uwep, "glow"));
X	useup (uwep);
X	return (1);
X    }
X    if (!rn2 (6))
X	amount *= 2;
X    time = (amount * amount == 1) ? "moment" : "while";
X    pline ("Your %s %s for a %s.",
X	    aobjnam (uwep, "glow"), color, time);
X    uwep -> spe += amount;
X    if (amount > 0)
X	uwep -> cursed = 0;
X    return (1);
X}
--burp--
sed 's/^X//' << '--burp--' > hack.zap.c
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
X
X#include "hack.h"
X
Xextern struct monst *makemon ();
Xstruct monst   *bhit ();
Xchar   *exclam ();
X
Xchar   *fl[] = {
X    "magic missile",
X    "bolt of fire",
X    "sleep ray",
X    "bolt of cold",
X    "death ray"
X};
X
Xdozap ()
X{
X    register struct obj *obj;
X    register struct monst  *mtmp;
X    xchar zx, zy;
X    register    num;
X
X    obj = getobj ("/", "zap");
X    if (!obj)
X	return (0);
X    if (obj -> spe < 0 || (obj -> spe == 0 && rn2 (121))) {
X	pline ("Nothing Happens");
X	return (1);
X    }
X    if (obj -> spe == 0)
X	pline ("You wrest one more spell from the worn-out wand.");
X    if (!(objects[obj -> otyp].bits & NODIR) && !getdir ())
X	return (1);		/* make him pay for knowing !NODIR */
X    obj -> spe--;
X    if (objects[obj -> otyp].bits & IMMEDIATE) {
X	if ((u.uswallow && (mtmp = u.ustuck)) ||
X		(mtmp = bhit (u.dx, u.dy, rn1 (8, 6), 0))) {
X	    wakeup (mtmp);
X	    switch (obj -> otyp) {
X		case WAN_STRIKING: 
X		    if (rnd (20) < 10 + mtmp -> data -> ac) {
X			register int    tmp = d (2, 12);
X			hit ("wand", mtmp, exclam (tmp));
X			mtmp -> mhp -= tmp;
X			if (mtmp -> mhp < 1)
X			    killed (mtmp);
X		    }
X		    else
X			miss ("wand", mtmp);
X		    break;
X		case WAN_SLOW_MONSTER: 
X		    mtmp -> mspeed = MSLOW;
X		    break;
X		case WAN_SPEED_MONSTER: 
X		    mtmp -> mspeed = MFAST;
X		    break;
X		case WAN_UNDEAD_TURNING: 
X		    if (index ("WVZ&", mtmp -> data -> mlet)) {
X			mtmp -> mhp -= rnd (8);
X			if (mtmp -> mhp < 1)
X			    killed (mtmp);
X			else
X			    mtmp -> mflee = 1;
X		    }
X		    break;
X		case WAN_POLYMORPH: 
X		    if (newcham (mtmp, &mons[rn2 (CMNUM)]))
X			objects[obj -> otyp].oc_name_known = 1;
X		    break;
X		case WAN_CANCELLATION: 
X		    mtmp -> mcan = 1;
X		    break;
X		case WAN_TELEPORT_MONSTER: 
X		    rloc (mtmp);
X		    break;
X		case WAN_MAKE_INVISIBLE: 
X		    mtmp -> minvis = 1;
X		    break;
X#ifdef WAN_PROBING
X		case WAN_PROBING: 
X		    mstatusline (mtmp);
X		    break;
X#endif WAN_PROBING
X		default: 
X		    pline ("What an interesting wand (%d)",
X			    obj -> otyp);
X		    impossible ();
X	    }
X	}
X    }
X    else {
X	switch (obj -> otyp) {
X	    case WAN_LIGHT: 
X		litroom (TRUE);
X		break;
X	    case WAN_SECRET_DOOR_DETECTION: 
X		if (!findit ())
X		    return (1);
X		break;
X	    case WAN_CREATE_MONSTER: 
X		{
X		    register int    cnt = 1;
X		    if (!rn2 (23))
X			cnt += rn2 (7) + 1;
X		    while (cnt--)
X			(void) makemon ((struct permonst   *) 0, u.ux, u.uy);
X		}
X		break;
X	    case WAN_WISHING: 
X		{
X		    char    buf[BUFSZ];
X		    register struct obj *otmp;
X		    extern struct obj  *readobjnam (), *addinv ();
X		    if ((u.uluck + rn2 (5) < 0) && (!wizard)) {
X			pline ("Unfortunately, nothing happens.");
X			break;
X		    }
X		    pline ("You may wish for an object. What do you want? ");
X		    getlin (buf);
X		    otmp = readobjnam (buf);
X		    otmp = addinv (otmp);
X		    prinv (otmp);
X		    break;
X		}
X	    case WAN_DIGGING: 
X		{
X		    register struct rm *room;
X		    register int    digdepth;
X		    if (u.uswallow) {
X			pline ("You pierce %s's stomach wall!",
X				monnam (u.ustuck));
X			u.uswallow = 0;
X			mnexto (u.ustuck);
X			u.ustuck -> mhp = 1;/* almost dead */
X			u.ustuck = 0;
X			setsee ();
X			docrt ();
X			break;
X		    }
X		    zx = u.ux + u.dx;
X		    zy = u.uy + u.dy;
X		    if (!isok (zx, zy))
X			break;
X		    digdepth = 4 + rn2 (10);
X		    if (levl[zx][zy].typ == CORR)
X			num = CORR;
X		    else
X			num = ROOM;
X		    Tmp_at (-1, '*');	/* open call */
X		    while (digdepth--) {
X			if (zx == 0 || zx == COLNO - 1 ||
X				zy == 0 || zy == ROWNO - 1)
X			    break;
X			room = &levl[zx][zy];
X			Tmp_at (zx, zy);
X			if (!xdnstair) {
X			    if (zx < 3 || zx > COLNO - 3 ||
X				    zy < 3 || zy > ROWNO - 3)
X				break;
X			    if (room -> typ == HWALL ||
X				    room -> typ == VWALL) {
X				room -> typ = ROOM;
X				break;
X			    }
X			}
X			else
X			    if (num == ROOM || num == 10) {
X				if (room -> typ != ROOM && room -> typ) {
X				    if (room -> typ != CORR)
X					room -> typ = DOOR;
X				    if (num == 10)
X					break;
X				    num = 10;
X				}
X				else
X				    if (!room -> typ)
X					room -> typ = CORR;
X			    }
X			    else {
X				if (room -> typ != CORR && room -> typ) {
X				    room -> typ = DOOR;
X				    break;
X				}
X				else
X				    room -> typ = CORR;
X			    }
X			mnewsym (zx, zy);
X			zx += u.dx;
X			zy += u.dy;
X		    }
X		    mnewsym (zx, zy);	/* not always necessary */
X		    Tmp_at (-1, -1);	/* closing call */
X		    break;
X		}
X	    default: 
X		buzz ((int) obj -> otyp - WAN_MAGIC_MISSILE,
X			u.ux, u.uy, u.dx, u.dy);
X		break;
X	}
X	if (!objects[obj -> otyp].oc_name_known) {
X	    u.urexp += 10;
X	    objects[obj -> otyp].oc_name_known = 1;
X	}
X    }
X    return (1);
X}
X
Xchar   *
Xexclam (force)
Xregister int    force;
X{
X    /* force == 0 occurs e.g. with sleep ray */
X    /* note that large force is usual with wands so that !! would require information about hand/weapon/wand */
X    return ((force < 0) ? "?" : (force <= 4) ? "." : "!");
X}
X
Xhit (str, mtmp, force)
Xregister char  *str;
Xregister struct monst  *mtmp;
Xregister char  *force;			/* usually either "." or "!" */
X{
X    if (!cansee (mtmp -> mx, mtmp -> my))
X	pline ("The %s hits it.", str);
X    else
X	pline ("The %s hits %s%s", str, monnam (mtmp), force);
X}
X
Xmiss (str, mtmp)
Xregister char  *str;
Xregister struct monst  *mtmp;
X{
X    if (!cansee (mtmp -> mx, mtmp -> my))
X	pline ("The %s misses it.", str);
X    else
X	pline ("The %s misses %s.", str, monnam (mtmp));
X}
X
X/* sets bhitpos to the final position of the weapon thrown */
X/* coord bhitpos; */
X
X/* check !u.uswallow before calling bhit() */
Xstruct monst   *
Xbhit (ddx, ddy, range, sym)
Xregister    ddx, ddy, range;
Xchar    sym;
X{
X    register struct monst  *mtmp;
X
X    bhitpos.x = u.ux;
X    bhitpos.y = u.uy;
X
X    if (sym)
X	tmp_at (-1, sym);		/* open call */
X    while (range--) {
X	bhitpos.x += ddx;
X	bhitpos.y += ddy;
X	if (mtmp = m_at (bhitpos.x, bhitpos.y)) {
X	    if (sym)
X		tmp_at (-1, -1);	/* close call */
X	    return (mtmp);
X	}
X	if (levl[bhitpos.x][bhitpos.y].typ < CORR) {
X	    bhitpos.x -= ddx;
X	    bhitpos.y -= ddy;
X	    break;
X	}
X	if (sym)
X	    tmp_at (bhitpos.x, bhitpos.y);
X    }
X    if (sym)
X	tmp_at (-1, 0);			/* leave last symbol */
X    return (0);
X}
X
Xstruct monst   *
Xboomhit (dx, dy)
X{
X    register int    i, ct;
X    register struct monst  *mtmp;
X    char    sym = ')';
X    extern  schar xdir[], ydir[];
X
X    bhitpos.x = u.ux;
X    bhitpos.y = u.uy;
X
X    for (i = 0; i < 8; i++)
X	if (xdir[i] == dx && ydir[i] == dy)
X	    break;
X    tmp_at (-1, sym);			/* open call */
X    for (ct = 0; ct < 10; ct++) {
X	if (i == 8)
X	    i = 0;
X	sym = ')' + '(' - sym;
X	tmp_at (-2, sym);		/* change let call */
X	dx = xdir[i];
X	dy = ydir[i];
X	bhitpos.x += dx;
X	bhitpos.y += dy;
X	if (mtmp = m_at (bhitpos.x, bhitpos.y)) {
X	    tmp_at (-1, -1);
X	    return (mtmp);
X	}
X	if (levl[bhitpos.x][bhitpos.y].typ < CORR) {
X	    bhitpos.x -= dx;
X	    bhitpos.y -= dy;
X	    break;
X	}
X	if (bhitpos.x == u.ux && bhitpos.y == u.uy) {/* ct == 9 */
X	    if (rn2 (20) >= 10 + u.ulevel) {/* we hit ourselves */
X		(void) thitu (10, rnd (10), "boomerang");
X		break;
X	    }
X	    else {			/* we catch it */
X		tmp_at (-1, -1);
X		pline ("Skillfully, you catch the boomerang.");
X		return ((struct monst  *) - 1);
X	    }
X	}
X	tmp_at (bhitpos.x, bhitpos.y);
X	if (ct % 5 != 0)
X	    i++;
X    }
X    tmp_at (-1, -1);			/* do not leave last symbol */
X    return (0);
X}
X
Xchar
Xdirlet (dx, dy)
Xregister    dx, dy;
X{
X    return (dx == dy) ? '\\' : (dx && dy) ? '/' : dx ? '-' : '|';
X}
X
X/* type < 0: monster spitting fire at you */
Xbuzz (type, sx, sy, dx, dy)
Xregister int    type;
Xregister    xchar sx, sy;
Xregister int    dx, dy;
X{
X    register char  *fltxt = (type < 0) ? "blaze of fire" : fl[type];
X    struct rm  *lev;
X    xchar range;
X    struct monst   *mon;
X
X    if (u.uswallow) {
X	register int    tmp;
X
X	if (type < 0)
X	    return;
X	tmp = zhit (u.ustuck, type);
X	pline ("The %s rips into %s%s",
X		fltxt, monnam (u.ustuck), exclam (tmp));
X	return;
X    }
X    if (type < 0)
X	pru ();
X    range = rn1 (7, 7);
X    Tmp_at (-1, dirlet (dx, dy));	/* open call */
X    while (range-- > 0) {
X	sx += dx;
X	sy += dy;
X	if ((lev = &levl[sx][sy]) -> typ)
X	    Tmp_at (sx, sy);
X	else {
X	    int     bounce = 0;
X	    if (cansee (sx - dx, sy - dy))
X		pline ("The %s bounces!", fltxt);
X	    if (levl[sx][sy - dy].typ > DOOR)
X		bounce = 1;
X	    if (levl[sx - dx][sy].typ > DOOR) {
X		if (!bounce || rn2 (2))
X		    bounce = 2;
X	    }
X	    switch (bounce) {
X		case 0: 
X		    dx = -dx;
X		    dy = -dy;
X		    continue;
X		case 1: 
X		    dy = -dy;
X		    sx -= dx;
X		    break;
X		case 2: 
X		    dx = -dx;
X		    sy -= dy;
X		    break;
X	    }
X	    Tmp_at (-2, dirlet (dx, dy));
X	    continue;
X	}
X	if ((mon = m_at (sx, sy)) &&
X		(type >= 0 || mon -> data -> mlet != 'D')) {
X	    wakeup (mon);
X	    if (rnd (20) < 18 + mon -> data -> ac) {
X		register int    tmp = zhit (mon, type);
X		if (mon -> mhp < 1) {
X		    if (type < 0) {
X			if (cansee (mon -> mx, mon -> my))
X			    pline ("%s is killed by the %s!",
X				    Monnam (mon), fltxt);
X			mondied (mon);
X		    }
X		    else
X			killed (mon);
X		}
X		else
X		    hit (fltxt, mon, exclam (tmp));
X		range -= 2;
X	    }
X	    else
X		miss (fltxt, mon);
X	}
X	else
X	    if (sx == u.ux && sy == u.uy) {
X		if (rnd (20) < 18 + u.uac) {
X		    register int    dam = 0;
X		    range -= 2;
X		    pline ("The %s hits you!", fltxt);
X		    switch (type) {
X			case 0: 
X			    dam = d (2, 6);
X			    break;
X			case -1: 	/* dragon fire */
X			case 1: 
X			    if (Fire_resistance)
X				pline ("You don't feel hot!");
X			    else
X				dam = d (6, 6);
X			    break;
X			case 2: 
X			    nomul (-rnd (25));/* sleep ray */
X			    break;
X			case 3: 
X			    if (Cold_resistance)
X				pline ("You don't feel cold!");
X			    else
X				dam = d (6, 6);
X			    break;
X			case 4: 
X			    u.uhp = -1;
X		    }
X		    losehp (dam, fltxt);
X		}
X		else
X		    pline ("The %s whizzes by you!", fltxt);
X	    }
X	if (lev -> typ <= DOOR) {
X	    int     bounce = 0, rmn;
X	    if (cansee (sx, sy))
X		pline ("The %s bounces!", fltxt);
X	    range--;
X	    if (!dx || !dy || !rn2 (20)) {
X		dx = -dx;
X		dy = -dy;
X	    }
X	    else {
X		if ((rmn = levl[sx][sy - dy].typ) > DOOR &&
X			(
X			    rmn >= ROOM ||
X			    levl[sx + dx][sy - dy].typ > DOOR)) {
X		    bounce = 1;
X		}
X		if ((rmn = levl[sx - dx][sy].typ) > DOOR &&
X			(
X			    rmn >= ROOM ||
X			    levl[sx - dx][sy + dy].typ > DOOR)) {
X		    if (!bounce || rn2 (2)) {
X			bounce = 2;
X		    }
X		}
X		switch (bounce) {
X		    case 0: 
X			dy = -dy;
X			dx = -dx;
X			break;
X		    case 1: 
X			dy = -dy;
X			break;
X		    case 2: 
X			dx = -dx;
X			break;
X		}
X		Tmp_at (-2, dirlet (dx, dy));
X	    }
X	}
X    }
X    Tmp_at (-1, -1);
X}
X
Xzhit (mon, type)			/* returns damage to mon */
Xregister struct monst  *mon;
Xregister    type;
X{
X    register int    tmp = 0;
X
X    switch (type) {
X	case 0: 			/* magic missile */
X	    tmp = d (2, 6);
X	    break;
X	case -1: 			/* Dragon blazing fire */
X	case 1: 			/* fire */
X	    if (index ("Dg", mon -> data -> mlet))
X		break;
X	    tmp = d (6, 6);
X	    if (mon -> data -> mlet == 'Y')
X		tmp += 7;
X	    break;
X	case 2: 			/* sleep */
X	    mon -> mfroz = 1;
X	    break;
X	case 3: 			/* cold */
X	    if (index ("YFgf", mon -> data -> mlet))
X		break;
X	    tmp = d (6, 6);
X	    if (mon -> data -> mlet == 'D')
X		tmp += 7;
X	    break;
X	case 4: 			/* death */
X	    if (index ("WVZ", mon -> data -> mlet))
X		break;
X	    tmp = mon -> mhp + 1;
X	    break;
X    }
X    mon -> mhp -= tmp;
X    return (tmp);
X}
--burp--
sed 's/^X//' << '--burp--' > help
X                                 Welcome to HACK!
X
XHack is a Dungeons and Dragons like game where you (the adventurer) descend
Xinto  the  depths of the dungeon in search of the Amulet of Yendor (reputed
Xto be hidden on the twentieth level).  You are accompanied by a little  dog
Xthat  can  help  you  in  many  ways  and can be trained to do all sorts of
Xthings.  On the way you will find useful (or useless) items, (quite  possi-
Xbly  with magic properties) and assorted monsters.  You attack a monster by
Xtrying to move into the space a monster is in (but often it is  much  wiser
Xto leave it alone).
X
XUnlike most adventure games, which give you a verbal  description  of  your
Xlocation, hack gives you a visual image of the dungeon level you are on.
X
XHack uses the following symbols:
X
X     A-Z and  a-z         Monsters.   You  can  find  out  what  a   letter
X                         represents  by  saying  "/  (letter)", as in "/A",
X                         which will tell you that 'A' is a giant ant.
X
X     - and |             These form the walls of a room (or maze).
X
X     .                   this is the floor of a room.
X
X     #                   this is a corridor.
X
X     >                   this is the staircase to the next level.
X
X     <                   the staircase to the previous level.
X
X     `                   A large boulder.
X
X     @                   You (usually).
X
X     ^                   A trap.
X
X     )                   A weapon of some sort.
X
X     (                   Some other useful  object  (key,  rope,  dynamite,
X                         camera, ...)
X
X     [                   A suit of armor.
X
X     %                   A piece of food (not necessarily healthy ...).
X
X     /                   A wand.
X
X     =                   A ring.
X
X     ?                   A scroll.
X
X     !                   A magic potion.
X
X     $                   A pile or pot of gold.
X
X
X                                 Commands:
X
X     Hack knows the following commands:
X
X     ?                   help: print this list.
X
X     Q                   Quit the game.
X
X     <                   up: go up the staircase (if you  are  standing  on
X                         it).
X
X     >                   down: go down (just like up).
X
X     kjhlyubn            go one step in the direction indicated.  k:  north
X                         (i.e.,  to  the  top  of the screen), j: south, h:
X                         west, l: east, y: ne, u: nw, b: se, n: sw.
X
X     KJHLYUBN            Go in that direction until you hit a wall  or  run
X                         into something.
X
X     m                   (followed by one of kjhlyubn): move without  pick-
X                         ing up any objects.
X
X     M                   (followed by one of KJHLYUBN): Move far, no  pick-
X                         up.
X
X     f                   (followed by one of kjhlyubn):  move  until  some-
X                         thing interesting is found.
X
X     F                   (followed by one of KJHLYUBN):  as  previous,  but
X                         forking  of  corridors is not considered interest-
X                         ing.
X
X     i                   print your inventory.
X
X     I                   print selected parts of your inventory.
X
X     s                   search for secret doors and traps around you.
X
X     ^                   ask for the type of a trap you found earlier.
X
X     )                   ask for current wielded weapon.
X
X     [                   ask for current armor.
X
X     =                   ask for current rings.
X
X     .                   rest, do nothing.
X
X     ^R                  redraw the screen.
X
X     ^P                  repeat last message (subsequent ^P's  repeat  ear-
X                         lier messages).
X
X     /                   (followed by any symbol): tell  what  this  symbol
X                         represents.
X
X     e                   eat food.
X
X     w                   wield weapon. w- means: wield  nothing,  use  bare
X                         hands.
X
X     q                   drink (quaff) a potion.
X
X     r                   read a scroll.
X
X     T                   Takeoff armor.
X
X     R                   Remove Ring.
X
X     W                   Wear armor.
X
X     P                   Put on a ring.
X
X     t                   throw or shoot a weapon.
X
X     p                   pay your shopping bill.
X
X     d                   drop something. d7a: drop seven items of object a.
X
X     D                   Drop several things.  In answer  to  the  question
X                         "What  kinds  of  things do you want to drop? [!%=
X                         au]" you should give zero or more  object  symbols
X                         possibly followed by 'a' and/or 'u'.
X
X     a                   use, apply - Generic command for using  a  key  to
X                         lock  or  unlock  a  door, using a camera, using a
X                         rope, etc.
X
X     c                   call: name a certain object or class of objects.
X
X     C                   Call: Name an individual monster.
X
X     E                   Engrave: Write a message in the dust on the floor.
X                                                  E- means: use fingers for
X                         writing.
X
X     o                   set options. (see below)
X
X     v                   print version number.
X
X     \                   print a list of things discovered.
X
X
XYou can put a number before a command to repeat it that many times,  as  in
X"20s" or "40.".
X
X                                    Options:
X
XTo turn an option on, say 'ox', where x is the optionletter.   To  turn  it
Xoff, say 'o!x'.
X The following options currently exist.
X
X
X     e                   echo - Echo typed characters.
X
X     o                   oneline - Give inventories one line at a time  (at
X                         the top of your screen).
X
X
X                          Have Fun, and Good Hacking!
X
--burp--
sed 's/^X//' << '--burp--' > help.nr
X.pl 1
X.ll 75
X.ce 1
X	Welcome to HACK!
X.sp 1
XHack is a Dungeons and Dragons like game where you (the adventurer)
Xdescend into the depths of the dungeon in search of the Amulet of Yendor
X(reputed to be hidden on the twentieth level).
XYou are accompanied by a little dog that can help you in many ways and
Xcan be trained to do all sorts of things.
XOn the way you will find useful (or useless) items, (quite possibly with
Xmagic properties) and assorted monsters.
XYou attack a monster by trying to move into the space a monster is
Xin (but often it is much wiser to leave it alone).
X
XUnlike most adventure games, which give you a verbal description of
Xyour location, hack gives you a visual image of the dungeon level you are on.
X
XHack uses the following symbols:
X.de TE
X.sp
X.ti 0
X..
X.ta 5m 25m
X.in 25m
X.TE
X	A-Z\ and a-z	\
XMonsters.
XYou can find out what a letter represents by saying "/ (letter)",
Xas in "/A", which will tell you that 'A' is a giant ant.
X.TE
X	- and |	\
XThese form the walls of a room (or maze).
X.TE
X	\.	\
Xthis is the floor of a room.
X.TE
X	#	\
Xthis is a corridor.
X.TE
X	>	\
Xthis is the staircase to the next level.
X.TE
X	<	\
Xthe staircase to the previous level.
X.TE
X	`	\
XA large boulder.
X.TE
X	@	\
XYou (usually).
X.TE
X	^	\
XA trap.
X.TE
X	)	\
XA weapon of some sort.
X.TE
X	(	\
XSome other useful object (key, rope, dynamite, camera, ...)
X.TE
X	[	\
XA suit of armor.
X.TE
X	%	\
XA piece of food (not necessarily healthy ...).
X.TE
X	/	\
XA wand.
X.TE
X	=	\
XA ring.
X.TE
X	?	\
XA scroll.
X.TE
X	!	\
XA magic potion.
X.TE
X	$	\
XA pile or pot of gold.
X.TE
X.in 0
X.sp
X.ce 1
XCommands:
X.sp
X	Hack knows the following commands:
X.ta 5m 25m
X.in 25m
X.TE
X	?	\
Xhelp: print this list.
X.TE
X	Q	\
XQuit the game.
X.TE
X	<	\
Xup: go up the staircase (if you are standing on it).
X.TE
X	>	\
Xdown: go down (just like up).
X.TE
X	kjhlyubn	\
Xgo one step in the direction indicated.
Xk: north (i.e., to the top of the screen), j: south, h: west, l: east, y: ne, u: nw, b: se, n: sw.
X.TE
X	KJHLYUBN	\
XGo in that direction until you hit a wall or run into something.
X.TE
X	m	\
X(followed by one of kjhlyubn): move without picking up any objects.
X.TE
X	M	\
X(followed by one of KJHLYUBN): Move far, no pickup.
X.TE
X	f	\
X(followed by one of kjhlyubn): move until something interesting is found.
X.TE
X	F	\
X(followed by one of KJHLYUBN): as previous, but forking of corridors is not considered interesting.
X.TE
X	i	\
Xprint your inventory.
X.TE
X	I	\
Xprint selected parts of your inventory.
X.TE
X	s	\
Xsearch for secret doors and traps around you.
X.TE
X	^	\
Xask for the type of a trap you found earlier.
X.TE
X	)	\
Xask for current wielded weapon.
X.TE
X	[	\
Xask for current armor.
X.TE
X	=	\
Xask for current rings.
X.TE
X	\.	\
Xrest, do nothing.
X.TE
X	^R	\
Xredraw the screen.
X.TE
X	^P	\
Xrepeat last message (subsequent ^P's repeat earlier messages).
X.TE
X	/	\
X(followed by any symbol): tell what this symbol represents.
X.TE
X	e	\
Xeat food.
X.TE
X	w	\
Xwield weapon. w- means: wield nothing, use bare hands.
X.TE
X	q	\
Xdrink (quaff) a potion.
X.TE
X	r	\
Xread a scroll.
X.TE
X	T	\
XTakeoff armor.
X.TE
X	R	\
XRemove Ring.
X.TE
X	W	\
XWear armor.
X.TE
X	P	\
XPut on a ring.
X.TE
X	t	\
Xthrow or shoot a weapon.
X.TE
X	p	\
Xpay your shopping bill.
X.TE
X	d	\
Xdrop something. d7a: drop seven items of object a.
X.TE
X	D	\
XDrop several things.
XIn answer to the question "What kinds of things do you want to drop? [!%= au]"
Xyou should give zero or more object symbols possibly followed by 'a' and/or 'u'.
X'a' means: drop all such objects, without asking for confirmation.
X'u' means: drop only unpaid objects (when in a shop).
X.TE
X	a	\
Xuse, apply - Generic command for using a key to lock or unlock a door, using a camera, using a rope, etc.
X.TE
X	c	\
Xcall: name a certain object or class of objects.
X.TE
X	C	\
XCall: Name an individual monster.
X.TE
X	E	\
XEngrave: Write a message in the dust on the floor.
X		E- means: use fingers for writing.
X.TE
X	o	\
Xset options. (see below)
X.TE
X	v	\
Xprint version number.
X.TE
X	\\	\
Xprint a list of things discovered.
X.TE
X.in 0
X.sp 2
XYou can put a number before a command to repeat it that many times, as in "20s" or "40.".
X.sp
X.ce 1
X	Options:
X.sp
XTo turn an option on, say 'ox', where x is the optionletter.
XTo turn it off, say 'o!x'.
X The following options currently exist.
X
X.ta 5m 25m
X.in 25m
X.TE
X	e	\
Xecho - Echo typed characters.
X.TE
X	o	\
Xoneline - Give inventories one line at a time (at the top of your screen).
X.TE
X.in 0
X.sp 3
X.ce 1
X	Have Fun, and Good Hacking!
--burp--
sed 's/^X//' << '--burp--' > hh
Xy k u	Move commands:
X \|/		hykulnjb: single move in specified direction
Xh-+-l		HYKULNJB: repeated move in specified direction
X /|\			(until stopped by e.g. a wall)
Xb j n		f<dir>: fast movement in direction <dir>
X			(until something interesting is seen)
X		m<dir>: move without picking up objects
X
XMeta commands:
XQ	quit	leave the game
XS	save	save the game (to be continued later)
Xo	set	set options
X?	help	print information
X/	whatis	give name (and sometimes more info) of specified monster
X\	known	print list of what's been discovered
X!	sh	escape to some SHELL
Xv	version	print version number
X^R	redraw	redraw the screen (^R denotes the symbol CTRL/R)
X^P	print	repeat last message  (subsequent ^P's repeat earlier messages)
X
XGame commands:
Xa	apply, use  use something (a key, camera, etc.)
Xc	call	give a name to a class of objects
Xd	drop	drop an object. d7a: drop seven items of object a.
Xe	eat	eat something
Xi	invent	list the inventory (and shopping bill)
XI	invent	list selected parts of the inventory
Xp	pay	pay your bill
Xq	drink	quaff a potion
Xr	read	read a scroll
Xs	search	search for secret doors, hidden traps and monsters
Xt	throw	throw or shoot a weapon
Xw	wield	wield a weapon	(w-  wield nothing)
Xz	zap	zap a wand
XC	name	name an individual monster (e.g., baptize your dog)
XD	Drop	drop several things
XE	Engrave write a message in the dust on the floor  (E-  use fingers)
XP	wear	put on a ring
XR	remove	remove a ring
XT	remove	take off some armor
XW	wear	put on some armor
X<	up	go up the stairs
X>	down	go down the stairs
X^	trap_id	identify a previously found trap
X),[,=	ask for current weapon, armor, rings, respectively
X. or <space>  wait a moment
--burp--
sed 's/^X//' << '--burp--' > mklev.c
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
X
X#include <stdio.h>
X#include "mklev.h"
X#include "def.trap.h"
X
Xextern char *getlogin ();
Xextern struct monst *makemon ();
X
Xchar   *tfile, *tspe, **args;
Xchar    nul[40];
Xlong	time ();
X
X#include "savelev.h"
X
X#ifdef WIZARD
Xboolean wizard;
X#endif WIZARD
X
X#define somex() ((rand()%(croom->hx-croom->lx+1))+croom->lx)
X#define somey() ((rand()%(croom->hy-croom->ly+1))+croom->ly)
X
Xstruct rm   levl[COLNO][ROWNO];
Xstruct monst   *fmon;
Xstruct obj *fobj;
Xstruct gen *fgold, *ftrap;
X
Xchar   *fut_geno;	/* monsters that should not be created anymore */
X
Xstruct mkroom   rooms[MAXNROFROOMS + 1], *croom, *troom;
Xcoord doors[DOORMAX];
Xint     doorindex = 0;
Xint     comp ();
X
Xxchar dlevel;
Xschar nxcor, xx, yy, dx, dy, tx, ty;	/* for corridors and other things... */
Xboolean goldseen;
Xint     nroom;
X
Xxchar xdnstair, xupstair, ydnstair, yupstair;
X
X
Xmain (argc, argv)
Xchar   *argv[];
X{
X    register unsigned   tryct;
X
X    if (argc < 6)
X	panic ("Too few arguments!!");
X    args = argv;
X    tfile = argv[1];
X    tspe = argv[2];
X    dlevel = atoi (argv[3]);
X    if (dlevel < 1)
X	panic ("Bad level");
X    fut_geno = argv[4];
X#ifdef WIZARD
X    wizard = (argv[5][0] == 'w');
X#endif WIZARD
X    (void) srand ((int) time ((long *) 0));
X    init_objects ();
X    rooms[0].hx = -1;			/* in case we are in a maze */
X
X    /* a: normal; b: maze */
X    if (*tspe == 'b') {
X	makemaz ();
X	savelev ();
X	exit (0);
X    }
X
X    /* construct the rooms */
X    while (nroom < (MAXNROFROOMS / 3)) {
X	croom = rooms;
X	nroom = 0;
X	(void) makerooms (0);		/* not secret */
X    }
X
X    /* for each room: put things inside */
X    for (croom = rooms; croom -> hx > 0; croom++) {
X
X	/* put a sleeping monster inside */
X	if (!rn2 (3))
X	    (void)
X		makemon ((struct permonst  *) 0, somex (), somey ());
X
X	/* put traps and mimics inside */
X	goldseen = FALSE;
X	while (!rn2 (8 - (dlevel / 6)))
X	    mktrap (0, 0);
X	if (!goldseen && !rn2 (3))
X	    mkgold (0, somex (), somey ());
X	if (!rn2 (3)) {
X	    mkobj_at (0, somex (), somey ());
X	    tryct = 0;
X	    while (!rn2 (5)) {
X		if (++tryct > 100) {
X		    printf ("tryct overflow4\n");
X		    break;
X		}
X		mkobj_at (0, somex (), somey ());
X	    }
X	}
X    }
X    tryct = 0;
X    do {
X	if (++tryct > 1000)
X	    panic ("Cannot make dnstairs\n");
X	croom = &rooms[rn2 (nroom)];
X	xdnstair = somex ();
X	ydnstair = somey ();
X    } while ((*tspe == 'n' && (!(xdnstair % 2) || !(ydnstair % 2))) ||
X	    g_at (xdnstair, ydnstair, ftrap));
X    levl[xdnstair][ydnstair].scrsym = '>';
X    levl[xdnstair][ydnstair].typ = STAIRS;
X    troom = croom;
X    do {
X	if (++tryct > 2000)
X	    panic ("Cannot make upstairs\n");
X	croom = &rooms[rn2 (nroom)];
X	xupstair = somex ();
X	yupstair = somey ();
X    } while (croom == troom || m_at (xupstair, yupstair) ||
X	    g_at (xupstair, yupstair, ftrap));
X    levl[xupstair][yupstair].scrsym = '<';
X    levl[xupstair][yupstair].typ = STAIRS;
X
X    qsort ((char *) rooms, nroom, sizeof (struct mkroom), comp);
X    croom = rooms;
X    troom = croom + 1;
X    nxcor = 0;
X    mkpos ();
X    do
X	makecor ();
X    while (croom -> hx > 0 && troom -> hx > 0);
X
X    /* make a secret treasure vault, not connected to the rest */
X    if (nroom < (2 * MAXNROFROOMS / 3))
X	if (!rn2 (3)) {
X	    register int    x, y;
X	    troom = croom = &rooms[nroom];
X	    if (makerooms (1)) {	/* make secret room */
X		troom -> rtype = 6;	/* treasure vault */
X		for (x = troom -> lx; x <= troom -> hx; x++)
X		    for (y = troom -> ly; y <= troom -> hy; y++)
X			mkgold (rnd (dlevel * 100) + 50, x, y);
X	    }
X	}
X
X#ifdef WIZARD
X    if (wizard) {
X	if (rn2 (3))
X	    mkshop ();
X	else
X	    mkzoo ();
X    }
X    else
X#endif WIZARD
X	if (dlevel > 1 && dlevel < 20 && rn2 (dlevel) < 2)
X	    mkshop ();
X	else
X	    if (dlevel > 6 && !rn2 (7))
X		mkzoo ();
X    savelev ();
X    exit (0);
X}
X
Xmakerooms (secret) int  secret; {
X    register int    lowx, lowy;
X    register int    tryct = 0;
X    while (nroom < (MAXNROFROOMS / 2) || secret)
X	for (lowy = rn1 (3, 3); lowy < ROWNO - 7; lowy += rn1 (2, 4)) {
X	    for (lowx = rn1 (3, 4); lowx < COLNO - 10; lowx += rn1 (2, 7)) {
X		if (tryct++ > 10000)
X		    return (0);
X		if ((lowy += (rn2 (5) - 2)) < 3)
X		    lowy = 3;
X		else
X		    if (lowy > ROWNO - 6)
X			lowy = ROWNO - 6;
X		if (levl[lowx][lowy].typ)
X		    continue;
X		if ((secret && maker (lowx, 1, lowy, 1)) ||
X			(!secret && maker (lowx, rn1 (9, 2), lowy, rn1 (4, 2))
X			    && nroom + 2 > MAXNROFROOMS))
X		    return (1);
X	    }
X	}
X    return (1);
X}
X
Xcomp (x, y)
Xregister struct mkroom *x, *y;
X{
X    if (x -> lx < y -> lx)
X	return (-1);
X    return (x -> lx > y -> lx);
X}
X
Xcoord
Xfinddpos (xl, yl, xh, yh) {
X    coord ff;
X    register    x, y;
X    ff.x = (xl == xh) ? xl : (xl + rn2 (xh - xl + 1));
X    ff.y = (yl == yh) ? yl : (yl + rn2 (yh - yl + 1));
X    if (okdoor (ff.x, ff.y))
X	return (ff);
X    if (xl < xh)
X	for (x = xl; x <= xh; x++)
X	    if (okdoor (x, ff.y)) {
X		ff.x = x;
X		return (ff);
X	    }
X    if (yl < yh)
X	for (y = yl; y <= yh; y++)
X	    if (okdoor (ff.x, y)) {
X		ff.y = y;
X		return (ff);
X	    }
X    return (ff);
X}
X
X/* when croom and troom exist, find position for a door in croom
X   and direction for a corridor towards position [tx,ty] in the wall
X   of troom */
Xmkpos () {
X    coord cc, tt;
X    if (troom -> hx < 0 || croom -> hx < 0 || doorindex >= DOORMAX)
X	return;
X    if (troom -> lx > croom -> hx) {
X	dx = 1;
X	dy = 0;
X	xx = croom -> hx + 1;
X	tx = troom -> lx - 1;
X	cc = finddpos (xx, croom -> ly, xx, croom -> hy);
X	tt = finddpos (tx, troom -> ly, tx, troom -> hy);
X    }
X    else
X	if (troom -> hy < croom -> ly) {
X	    dy = -1;
X	    dx = 0;
X	    yy = croom -> ly - 1;
X	    cc = finddpos (croom -> lx, yy, croom -> hx, yy);
X	    ty = troom -> hy + 1;
X	    tt = finddpos (troom -> lx, ty, troom -> hx, ty);
X	}
X	else
X	    if (troom -> hx < croom -> lx) {
X		dx = -1;
X		dy = 0;
X		xx = croom -> lx - 1;
X		tx = troom -> hx + 1;
X		cc = finddpos (xx, croom -> ly, xx, croom -> hy);
X		tt = finddpos (tx, troom -> ly, tx, troom -> hy);
X	    }
X	    else {
X		dy = 1;
X		dx = 0;
X		yy = croom -> hy + 1;
X		ty = troom -> ly - 1;
X		cc = finddpos (croom -> lx, yy, croom -> hx, yy);
X		tt = finddpos (troom -> lx, ty, troom -> hx, ty);
X	    }
X    xx = cc.x;
X    yy = cc.y;
X    tx = tt.x;
X    ty = tt.y;
X    if (levl[xx + dx][yy + dy].typ) {
X	if (nxcor)
X	    newloc ();
X	else {
X	    dodoor (xx, yy, croom);
X	    xx += dx;
X	    yy += dy;
X	}
X	return;
X    }
X    dodoor (xx, yy, croom);
X}
X
X/* if allowable, create a door at [x,y] */
Xokdoor (x, y)
Xregister    x, y;
X{
X    if (levl[x - 1][y].typ == DOOR || levl[x + 1][y].typ == DOOR ||
X	    levl[x][y + 1].typ == DOOR || levl[x][y - 1].typ == DOOR ||
X	    levl[x - 1][y].typ == SDOOR || levl[x + 1][y].typ == SDOOR ||
X	    levl[x][y - 1].typ == SDOOR || levl[x][y + 1].typ == SDOOR ||
X	    (levl[x][y].typ != HWALL && levl[x][y].typ != VWALL) ||
X	    doorindex >= DOORMAX)
X	return (0);
X    return (1);
X}
X
Xdodoor (x, y, aroom)
Xregister    x, y;
Xregister struct mkroom *aroom;
X{
X    register struct mkroom *broom;
X    register    tmp;
X    if (doorindex >= DOORMAX)
X	panic ("DOORMAX exceeded?");
X    if (!okdoor (x, y) && nxcor)
X	return;
X    if (!rn2 (8))
X	levl[x][y].typ = SDOOR;
X    else {
X	levl[x][y].scrsym = '+';
X	levl[x][y].typ = DOOR;
X    }
X    aroom -> doorct++;
X    broom = aroom + 1;
X    if (broom -> hx < 0)
X	tmp = doorindex;
X    else
X	for (tmp = doorindex; tmp > broom -> fdoor; tmp--)
X	    doors[tmp] = doors[tmp - 1];
X    doorindex++;
X    doors[tmp].x = x;
X    doors[tmp].y = y;
X    for (; broom -> hx >= 0; broom++)
X	broom -> fdoor++;
X}
X
Xnewloc () {
X    register    a, b;
X    register int    tryct = 0;
X
X    ++croom;
X    ++troom;
X    if (nxcor || croom -> hx < 0 || troom -> hx < 0) {
X	if (nxcor++ > rn1 (nroom, 4)) {
X	    croom = &rooms[nroom];
X	    return;
X	}
X	do {
X	    if (++tryct > 100) {
X		printf ("tryct overflow5\n");
X		croom = &rooms[nroom];
X		return;
X	    }
X	    a = rn2 (nroom);
X	    b = rn2 (nroom);
X	    croom = &rooms[a];
X	    troom = &rooms[b];
X	} while (croom == troom || (troom == croom + 1 && !rn2 (3)));
X    }
X    mkpos ();
X}
X
X/* make a trap somewhere (in croom if mazeflag = 0) */
Xmktrap (num, mazeflag)
Xregister    num, mazeflag;
X{
X    register struct gen *gtmp;
X    register int    kind, nopierc, nomimic, fakedoor, fakegold, tryct = 0;
X    register    xchar mx, my;
X
X    if (!num || num >= TRAPNUM) {
X	nopierc = (dlevel < 4) ? 1 : 0;
X	nomimic = (dlevel < 9 || goldseen) ? 1 : 0;
X	if (index (fut_geno, 'M'))
X	    nomimic = 1;
X	kind = rn2 (TRAPNUM - nopierc - nomimic);
X	/* note: PIERC = 7, MIMIC = 8, TRAPNUM = 9 */
X    }
X    else
X	kind = num;
X
X    if (kind == MIMIC) {
X	register struct monst  *mtmp;
X
X	fakedoor = (!rn2 (3) && !mazeflag);
X	fakegold = (!fakedoor && !rn2 (2));
X	if (fakegold)
X	    goldseen = TRUE;
X	do {
X	    if (++tryct > 200)
X		return;
X	    if (fakedoor) {
X		/* note: fakedoor maybe on actual door */
X		if (rn2 (2)) {
X		    if (rn2 (2))
X			mx = croom -> hx + 1;
X		    else
X			mx = croom -> lx - 1;
X		    my = somey ();
X		}
X		else {
X		    if (rn2 (2))
X			my = croom -> hy + 1;
X		    else
X			my = croom -> ly - 1;
X		    mx = somex ();
X		}
X	    }
X	    else
X		if (mazeflag) {
X		    extern  coord mazexy ();
X		    coord mm;
X		    mm = mazexy ();
X		    mx = mm.x;
X		    my = mm.y;
X		}
X		else {
X		    mx = somex ();
X		    my = somey ();
X		}
X	} while (m_at (mx, my));
X	if (mtmp = makemon (PM_MIMIC, mx, my))
X	    mtmp -> mimic =
X		fakegold ? '$' : fakedoor ? '+' :
X		(mazeflag && rn2 (2)) ? AMULET_SYM :
X		"=/)%?![<>"[rn2 (9)];
X	return;
X    }
X    gtmp = newgen ();
X    gtmp -> gflag = kind;
X    do {
X	if (++tryct > 200) {
X	    printf ("tryct overflow7\n");
X	    free ((char *) gtmp);
X	    return;
X	}
X	if (mazeflag) {
X	    extern  coord mazexy ();
X	    coord mm;
X	    mm = mazexy ();
X	    gtmp -> gx = mm.x;
X	    gtmp -> gy = mm.y;
X	}
X	else {
X	    gtmp -> gx = somex ();
X	    gtmp -> gy = somey ();
X	}
X    } while (g_at (gtmp -> gx, gtmp -> gy, ftrap));
X    gtmp -> ngen = ftrap;
X    ftrap = gtmp;
X    if (mazeflag && !rn2 (10) && gtmp -> gflag < PIERC)
X	gtmp -> gflag |= SEEN;
X}
X
X/*VARARGS1*/
Xpanic (str, arg1, arg2, arg3)
Xchar   *str, *arg1, *arg2, *arg3;
X{
X    char    bufr[BUFSZ];
X    extern char *sprintf ();
X    (void) sprintf (bufr, str, arg1, arg2, arg3);
X    (void) write (1, "\nMKLEV ERROR:  ", 15);
X    puts (bufr);
X    (void) fflush (stdout);
X    exit (1);
X}
X
Xmaker (lowx, ddx, lowy, ddy)
Xschar lowx, ddx, lowy, ddy;
X{
X    register    x, y, hix = lowx + ddx, hiy = lowy + ddy;
X
X    if (nroom >= MAXNROFROOMS)
X	return (0);
X    if (hix > COLNO - 5)
X	hix = COLNO - 5;
X    if (hiy > ROWNO - 4)
X	hiy = ROWNO - 4;
Xchk: 
X    if (hix <= lowx || hiy <= lowy)
X	return (0);
X
X    /* check area around room (and make room smaller if necessary) */
X    for (x = lowx - 4; x <= hix + 4; x++)
X	for (y = lowy - 3; y <= hiy + 3; y++)
X	    if (levl[x][y].typ) {
X		if (rn2 (3))
X		    return (0);
X		lowx = x + 5;
X		lowy = y + 4;
X		goto chk;
X	    }
X
X    /* on low levels the room is lit (usually) */
X    /* secret vaults are always lit */
X    if ((rnd (dlevel) < 10 && rn2 (77)) || (ddx == 1 && ddy == 1))
X	for (x = lowx - 1; x <= hix + 1; x++)
X	    for (y = lowy - 1; y <= hiy + 1; y++)
X		levl[x][y].lit = 1;
X    croom -> lx = lowx;
X    croom -> hx = hix;
X    croom -> ly = lowy;
X    croom -> hy = hiy;
X    croom -> rtype = croom -> doorct = croom -> fdoor = 0;
X    for (x = lowx - 1; x <= hix + 1; x++)
X	for (y = lowy - 1; y <= hiy + 1; y += (hiy - lowy + 2)) {
X	    levl[x][y].scrsym = '-';
X	    levl[x][y].typ = HWALL;
X	}
X    for (x = lowx - 1; x <= hix + 1; x += (hix - lowx + 2))
X	for (y = lowy; y <= hiy; y++) {
X	    levl[x][y].scrsym = '|';
X	    levl[x][y].typ = VWALL;
X	}
X    for (x = lowx; x <= hix; x++)
X	for (y = lowy; y <= hiy; y++) {
X	    levl[x][y].scrsym = '.';
X	    levl[x][y].typ = ROOM;
X	}
X    croom++;
X    croom -> hx = -1;
X    nroom++;
X    return (1);
X}
X
Xmakecor () {
X    register    nx, ny;
X    register struct rm *crm;
X    register    dix, diy, secondtry = 0;
X
Xtryagain: 
X    nx = xx + dx;
X    ny = yy + dy;
X
X    if (nxcor && !rn2 (35)) {
X	newloc ();
X	return;
X    }
X    if (nx == COLNO - 1 || nx == 0 || ny == 0 || ny == ROWNO - 1) {
X	if (nxcor) {
X	    newloc ();
X	    return;
X	}
X	else {
X	    printf ("something went wrong. we try again...\n");
X	    execl ("./mklev", args[0], tfile, tspe, args[3], args[4], args[5], 0);
X	    panic ("cannot execute ./mklev\n");
X	}
X    }
X
X    dix = abs (nx - tx);
X    diy = abs (ny - ty);
X    if (dy && dix > diy) {
X	dy = 0;
X	dx = (nx > tx) ? -1 : 1;
X    }
X    else
X	if (dx && diy > dix) {
X	    dx = 0;
X	    dy = (ny > ty) ? -1 : 1;
X	}
X
X    crm = &levl[nx][ny];
X    if (!(crm -> typ)) {
X	if (rn2 (100)) {
X	    crm -> typ = CORR;
X	    crm -> scrsym = CORR_SYM;
X	}
X	else {
X	    crm -> typ = SCORR;
X	    crm -> scrsym = ' ';
X	}
X	xx = nx;
X	yy = ny;
X	if (nxcor && !rn2 (50)) {
X	    mkobj_at (ROCK_SYM, nx, ny);
X	}
X	return;
X    }
X    if (crm -> typ == CORR || crm -> typ == SCORR) {
X	xx = nx;
X	yy = ny;
X	return;
X    }
X    if (nx == tx && ny == ty) {
X	dodoor (nx, ny, troom);
X	newloc ();
X	return;
X    }
X    if (!secondtry++ && (nx != xx + dx || ny != yy + dy))
X	goto tryagain;
X    if (dx) {
X	if (ty < ny)
X	    dy = -1;
X	else
X	    dy = levl[nx + dx][ny - 1].typ == ROOM ? 1 : -1;
X	dx = 0;
X    }
X    else {
X	if (tx < nx)
X	    dx = -1;
X	else
X	    dx = levl[nx - 1][ny + dy].typ == ROOM ? 1 : -1;
X	dy = 0;
X    }
X}
X
Xstruct monst   *
X                m_at (x, y)
Xregister    x, y;
X{
X    register struct monst  *mtmp;
X
X    for (mtmp = fmon; mtmp; mtmp = mtmp -> nmon)
X	if (mtmp -> mx == x && mtmp -> my == y)
X	    return (mtmp);
X    return (0);
X}
X
Xstruct gen *
X            g_at (x, y, ptr)
Xregister    x, y;
Xregister struct gen *ptr;
X{
X    while (ptr) {
X	if (ptr -> gx == x && ptr -> gy == y)
X	    return (ptr);
X	ptr = ptr -> ngen;
X    }
X    return (0);
X}
--burp--
exit
-- 
Robert Viduya
    Office of Computing Services
    Georgia Institute of Technology, Atlanta GA 30332
    Phone:  (404) 894-4669

...!{akgua,allegra,amd,hplabs,ihnp4,masscomp,ut-ngp}!gatech!gitpyr!robert
...!{rlgvax,sb1,uf-cgrl,unmvax,ut-sally}!gatech!gitpyr!robert