[net.sources.games] Hack 1.0.2 - part 4 of 10

aeb@mcvax.UUCP (Andries Brouwer) (04/07/85)

# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# hack.eat.c hack.end.c hack.engrave.c hack.fight.c hack.invent.c hack.ioctl.c

echo x - hack.eat.c
cat > "hack.eat.c" << '//E*O*F hack.eat.c//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.eat.c - version 1.0.2 */

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

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

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

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

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

static struct {
	struct obj *tin;
	int usedtime, reqtime;
} tin;

opentin(){
	register int r;

	if(!carried(tin.tin))		/* perhaps it was stolen? */
		return(0);		/* %% probably we should use tinoid */
	if(tin.usedtime++ >= 50) {
		pline("You give up your attempt to open the tin.");
		return(0);
	}
	if(tin.usedtime < tin.reqtime)
		return(1);		/* still busy */

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

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

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

	/* Is there some food (probably a heavy corpse) here on the ground? */
	for(otmp = fobj; otmp; otmp = otmp->nobj) {
		if(otmp->ox == u.ux && otmp->oy == u.uy &&
		   otmp->olet == FOOD_SYM) {
			pline("There %s %s here; eat %s? [ny] ",
				(otmp->quan == 1) ? "is" : "are",
				doname(otmp),
				(otmp->quan == 1) ? "it" : "one");
			if(readchar() == 'y') {
				if(otmp->quan != 1)
					(void) splitobj(otmp, 1);
				freeobj(otmp);
				otmp->nobj = invent;
				invent = otmp;
				goto gotit;
			}
		}
	}
	otmp = getobj("%", "eat");
	if(!otmp) return(0);
gotit:
	if(otmp->otyp == TIN){
		if(uwep) {
			switch(uwep->otyp) {
			case CAN_OPENER:
				tmp = 1;
				break;
			case DAGGER:
			case CRYSKNIFE:
				tmp = 3;
				break;
			case PICK_AXE:
			case AXE:
				tmp = 6;
				break;
			default:
				goto no_opener;
			}
			pline("Using your %s you try to open the tin",
				aobjnam(uwep, (char *) 0));
		} else {
		no_opener:
			pline("It is not so easy to open this tin.");
			if(Glib) {
				pline("The tin slips out of your hands.");
				if(otmp->quan > 1) {
					register struct obj *obj;
					extern struct obj *splitobj();

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

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

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

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

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

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

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

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

	if(newhs != u.uhs) {
		if(newhs >= WEAK && u.uhs < WEAK)
			losestr(1);	/* this may kill you -- see below */
		else
		if(newhs < WEAK && u.uhs >= WEAK && u.ustr < u.ustrmax)
			losestr(-1);
		switch(newhs){
		case HUNGRY:
			pline((!incr) ? "You only feel hungry now." :
			      (u.uhunger < 145) ? "You feel hungry." :
				"You are beginning to feel hungry.");
			break;
		case WEAK:
			pline((!incr) ? "You feel weak now." :
			      (u.uhunger < 45) ? "You feel weak." :
				"You are beginning to feel weak.");
			break;
		}
		u.uhs = newhs;
		flags.botl = 1;
		if(u.uhp < 1) {
			pline("You die from hunger and exhaustion.");
			killer = "exhaustion";
			done("starved");
		}
	}
}

#define	CORPSE_I_TO_C(otyp)	(char) ((otyp >= DEAD_ACID_BLOB)\
		     ?  'a' + (otyp - DEAD_ACID_BLOB)\
		     :	'@' + (otyp - DEAD_HUMAN))
poisonous(otmp)
register struct obj *otmp;
{
	return(index(POISONOUS, CORPSE_I_TO_C(otmp->otyp)) != 0);
}

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

echo x - hack.end.c
cat > "hack.end.c" << '//E*O*F hack.end.c//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.end.c - version 1.0.2 */

#include "hack.h"
#include <stdio.h>
#include <signal.h>
#define	Sprintf	(void) sprintf
extern char plname[], pl_character[];
extern char *itoa(), *ordin(), *eos();
extern boolean female;			/* should have been flags.female */

xchar maxdlevel = 1;

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

int done_stopprint;
int done_hup;

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

done_hangup(){
	done_hup++;
	(void) signal(SIGHUP, SIG_IGN);
	done_intr();
}

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

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

#ifdef WIZARD
	if(wizard && *st1 == 'd'){
		u.uswldtim = 0;
		u.uhp = u.uhpmax;
		pline("For some reason you are still alive.");
		flags.move = 0;
		if(multi > 0) multi = 0; else multi = -1;
		flags.botl = 1;
		return;
	}
#endif WIZARD
	(void) signal(SIGINT, done_intr);
	(void) signal(SIGQUIT, done_intr);
	(void) signal(SIGHUP, done_hangup);
	if(*st1 == 'q' && u.uhp < 1){
		st1 = "died";
		killer = "quit while already on Charon's boat";
	}
	if(*st1 == 's') killer = "starvation"; else
	if(*st1 == 'd' && st1[1] == 'r') killer = "drowning"; else
	if(*st1 == 'p') killer = "panic"; else
	if(*st1 == 't') killer = "trickery"; else
	if(!index("bcd", *st1)) killer = st1;
	paybill();
	clearlocks();
	if(flags.toplin == 1) more();
	if(index("bcds", *st1)){
		if(dlevel > 0 && dlevel < 30) /* soon superfluous */
			savebones();
		if(!flags.notombstone)
			outrip();
	}
	if(*st1 == 'c') killer = st1;		/* after outrip() */
	settty((char *) 0);	/* does a clear_screen() */
	if(!done_stopprint)
		printf("Goodbye %s %s...\n\n", pl_character, plname);
	{ long int tmp;
	  tmp = u.ugold - u.ugold0;
	  if(tmp < 0)
		tmp = 0;
	  if(*st1 == 'd' || *st1 == 'b')
		tmp -= tmp/10;
	  u.urexp += tmp;
	  u.urexp += 50 * maxdlevel;
	  if(maxdlevel > 20)
		u.urexp += 1000*((maxdlevel > 30) ? 10 : maxdlevel - 20);
	}
	if(*st1 == 'e') {
		extern struct monst *mydogs;
		register struct monst *mtmp;
		register struct obj *otmp;
		register int i;
		register unsigned worthlessct = 0;
		boolean has_amulet = FALSE;

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

#define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry))
#define	NAMSZ	8
#define	DTHSZ	40
#define	PERSMAX	1
#define	POINTSMIN	1	/* must be > 0 */
#define	ENTRYMAX	100	/* must be >= 10 */
#define	PERS_IS_UID		/* delete for PERSMAX per name; now per uid */
struct toptenentry {
	struct toptenentry *tt_next;
	long int points;
	int level,maxlvl,hp,maxhp;
	int uid;
	char plchar;
	char sex;
	char name[NAMSZ+1];
	char death[DTHSZ+1];
	char date[7];		/* yymmdd */
} *tt_head;

topten(){
	int uid = getuid();
	int rank, rank0 = -1, rank1 = 0;
	int occ_cnt = PERSMAX;
	register struct toptenentry *t0, *t1, *tprev;
	char *recfile = RECORD;
	char *reclock = "record_lock";
	int sleepct = 300;
	FILE *rfile;
	register flg = 0;
	extern char *getdate();
#define	HUP	if(!done_hup)
	while(link(recfile, reclock) == -1) {
		HUP perror(reclock);
		if(!sleepct--) {
			HUP puts("I give up. Sorry.");
			HUP puts("Perhaps there is an old record_lock around?");
			return;
		}
		HUP printf("Waiting for access to record file. (%d)\n",
			sleepct);
		HUP (void) fflush(stdout);
		sleep(1);
	}
	if(!(rfile = fopen(recfile,"r"))){
		HUP puts("Cannot open record file!");
		goto unlock;
	}
	HUP (void) putchar('\n');

	/* create a new 'topten' entry */
	t0 = newttentry();
	t0->level = dlevel;
	t0->maxlvl = maxdlevel;
	t0->hp = u.uhp;
	t0->maxhp = u.uhpmax;
	t0->points = u.urexp;
	t0->plchar = pl_character[0];
	t0->sex = (female ? 'F' : 'M');
	t0->uid = uid;
	(void) strncpy(t0->name, plname, NAMSZ);
	(t0->name)[NAMSZ] = 0;
	(void) strncpy(t0->death, killer, DTHSZ);
	(t0->death)[DTHSZ] = 0;
	(void) strcpy(t0->date, getdate());

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

	t1 = tt_head = newttentry();
	tprev = 0;
	/* rank0: -1 undefined, 0 not_on_list, n n_th on list */
	for(rank = 1; ; ) {
	  if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]",
		t1->date, &t1->uid,
		&t1->level, &t1->maxlvl,
		&t1->hp, &t1->maxhp, &t1->points,
		&t1->plchar, &t1->sex, t1->name, t1->death) != 11
	  || t1->points < POINTSMIN)
			t1->points = 0;
	  if(rank0 < 0 && t1->points < t0->points) {
		rank0 = rank++;
		if(tprev == 0)
			tt_head = t0;
		else
			tprev->tt_next = t0;
		t0->tt_next = t1;
		occ_cnt--;
		flg++;		/* ask for a rewrite */
	  } else
		tprev = t1;
	  if(t1->points == 0) break;
	  if(
#ifdef PERS_IS_UID
	     t1->uid == t0->uid &&
#else
	     strncmp(t1->name, t0->name, NAMSZ) == 0 &&
#endif PERS_IS_UID
	     t1->plchar == t0->plchar && --occ_cnt <= 0){
		if(rank0 < 0){
			rank0 = 0;
			rank1 = rank;
	HUP printf("You didn't beat your previous score of %ld points.\n\n",
				t1->points);
		}
		if(occ_cnt < 0){
			flg++;
			continue;
		}
	  }
	  if(rank <= ENTRYMAX){
	  	t1 = t1->tt_next = newttentry();
	  	rank++;
	  }
	  if(rank > ENTRYMAX){
		t1->points = 0;
		break;
	  }
	}
	if(flg) {	/* rewrite record file */
		(void) fclose(rfile);
		if(!(rfile = fopen(recfile,"w"))){
			HUP puts("Cannot write record file\n");
			goto unlock;
		}

		if(!done_stopprint) if(rank0 > 0){
		    if(rank0 <= 10)
			puts("You made the top ten list!\n");
		    else
		printf("You reached the %d%s place on the top %d list.\n\n",
			rank0, ordin(rank0), ENTRYMAX);
		}
	}
	if(rank0 == 0) rank0 = rank1;
	if(rank0 <= 0) rank0 = rank;
	if(!done_stopprint) outheader();
	t1 = tt_head;
	for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
	  if(flg) fprintf(rfile,"%6s %d %d %d %d %d %ld %c%c %s,%s\n",
	    t1->date, t1->uid,
	    t1->level, t1->maxlvl,
	    t1->hp, t1->maxhp, t1->points,
	    t1->plchar, t1->sex, t1->name, t1->death);
	  if(done_stopprint) continue;
	  if(rank > flags.end_top &&
	    (rank < rank0-flags.end_around || rank > rank0+flags.end_around)
	    && (!flags.end_own ||
#ifdef PERS_IS_UID
				  t1->uid != t0->uid ))
#else
				  strncmp(t1->name, t0->name, NAMSZ)))
#endif PERS_IS_UID
	  	continue;
	  if(rank == rank0-flags.end_around &&
	     rank0 > flags.end_top+flags.end_around+1 &&
	     !flags.end_own)
		(void) putchar('\n');
	  if(rank != rank0)
		(void) outentry(rank, t1, 0);
	  else if(!rank1)
		(void) outentry(rank, t1, 1);
	  else {
		int t0lth = outentry(0, t0, -1);
		int t1lth = outentry(rank, t1, t0lth);
		if(t1lth > t0lth) t0lth = t1lth;
		(void) outentry(0, t0, t0lth);
	  }
	}
	if(rank0 >= rank) if(!done_stopprint)
		(void) outentry(0, t0, 1);
	(void) fclose(rfile);
unlock:
	(void) unlink(reclock);
}

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

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

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

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

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

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

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

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

/*
 * Called with args from main if argc >= 0. In this case, list scores as
 * requested. Otherwise, find scores for the current player (and list them
 * if argc == -1).
 */
prscore(argc,argv) int argc; char **argv; {
	extern char *hname;
	char *player0;
	char **players;
	int playerct;
	int rank;
	register struct toptenentry *t1, *t2;
	char *recfile = RECORD;
	FILE *rfile;
	register flg = 0;
	register int i;
#ifdef nonsense
	long total_score = 0L;
	char totchars[10];
	int totcharct = 0;
#endif nonsense
	int outflg = (argc >= -1);

	if(!(rfile = fopen(recfile,"r"))){
		puts("Cannot open record file!");
		return;
	}

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

	t1 = tt_head = newttentry();
	for(rank = 1; ; rank++) {
	  if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]",
		t1->date, &t1->uid,
		&t1->level, &t1->maxlvl,
		&t1->hp, &t1->maxhp, &t1->points,
		&t1->plchar, &t1->sex, t1->name, t1->death) != 11)
			t1->points = 0;
	  if(t1->points == 0) break;
	  for(i = 0; i < playerct; i++){
		if(strcmp(players[i], "all") == 0 ||
		   strncmp(t1->name, players[i], NAMSZ) == 0 ||
		  (players[i][0] == '-' &&
		   players[i][1] == t1->plchar &&
		   players[i][2] == 0) ||
		  (digit(players[i][0]) && rank <= atoi(players[i])))
			flg++;
	  }
	  t1 = t1->tt_next = newttentry();
	}
	(void) fclose(rfile);
	if(!flg) {
	    if(outflg) {
		printf("Cannot find any entries for ");
		if(playerct > 1) printf("any of ");
		for(i=0; i<playerct; i++)
			printf("%s%s", players[i], (i<playerct-1)?", ":".\n");
		printf("Call is: %s -s [playernames]\n", hname);
	    }
	    return;
	}

	if(outflg) outheader();
	t1 = tt_head;
	for(rank = 1; t1->points != 0; rank++, t1 = t2) {
		t2 = t1->tt_next;
		for(i = 0; i < playerct; i++){
			if(strcmp(players[i], "all") == 0 ||
			   strncmp(t1->name, players[i], NAMSZ) == 0 ||
			  (players[i][0] == '-' &&
			   players[i][1] == t1->plchar &&
			   players[i][2] == 0) ||
			  (digit(players[i][0]) && rank <= atoi(players[i]))){
				if(outflg)
				    (void) outentry(rank, t1, 0);
#ifdef nonsense
				total_score += t1->points;
				if(totcharct < sizeof(totchars)-1)
				    totchars[totcharct++] = t1->plchar;
#endif nonsense
				break;
			}
		}
		free((char *) t1);
	}
#ifdef nonsense
	totchars[totcharct] = 0;

	/* We would like to determine whether he is experienced. However,
	   the information collected here only tells about the scores/roles
	   that got into the topten (top 100?). We should maintain a
	   .hacklog or something in his home directory. */
	flags.beginner = (total_score < 6000);
	for(i=0; i<6; i++)
	    if(!index(totchars, "CFKSTWX"[i])) {
		flags.beginner = 1;
		if(!pl_character[0]) pl_character[0] = "CFKSTWX"[i];
		break;
	}
#endif nonsense
}
//E*O*F hack.end.c//

echo x - hack.engrave.c
cat > "hack.engrave.c" << '//E*O*F hack.engrave.c//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.engrave.c - version 1.0.2 */

#include	"hack.h"

extern char *nomovemsg;
extern char nul[];
extern struct obj zeroobj;
struct engr {
	struct engr *nxt_engr;
	char *engr_txt;
	xchar engr_x, engr_y;
	unsigned engr_lth;	/* for save & restore; not length of text */
	long engr_time;	/* moment engraving was (will be) finished */
	xchar engr_type;
#define	DUST	1
#define	ENGRAVE	2
#define	BURN	3
} *head_engr;

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

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

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

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

make_engr_at(x,y,s)
register int x,y;
register char *s;
{
	register struct engr *ep;

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

doengrave(){
register int len;
register char *sp;
register struct engr *ep, *oep = engr_at(u.ux,u.uy);
char buf[BUFSZ];
xchar type;
int spct;		/* number of leading spaces */
register struct obj *otmp;
	multi = 0;

	if(u.uswallow) {
		pline("You're joking. Hahaha!");	/* riv05!a3 */
		return(0);
	}

	/* one may write with finger, weapon or wand */
	otmp = getobj("#-)/", "write with");
	if(!otmp) return(0);
	if(otmp == &zeroobj) {
		if(uwep) {
			pline("You are now empty-handed.");
			setuwep((struct obj *) 0);
		}
		type = DUST;
	} else if(otmp->otyp == WAN_FIRE && otmp->spe) {
		type = BURN;
		otmp->spe--;
	} else {
		if(otmp != uwep) {
			pline("You now wield %s.", doname(otmp));
			setuwep(otmp);
		}

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

	pline("What do you want to %s on the floor here? ",
	  (type == ENGRAVE) ? "engrave" : (type == BURN) ? "burn" : "write");
	getlin(buf);
	clrlin();
	spct = 0;
	sp = buf;
	while(*sp == ' ') spct++, sp++;
	len = strlen(sp);
	if(!len) {
		if(type == BURN) otmp->spe++;
		return(0);
	}
	
	switch(type) {
	case DUST:
	case BURN:
		if(len > 15) {
			multi = -(len/10);
			nomovemsg = "You finished writing.";
		}
		break;
	case ENGRAVE:
		{	int len2 = (otmp->spe + 3) * 2 + 1;

			pline("Your %s dull.", aobjnam(otmp, "get"));
			if(len2 < len) {
				len = len2;
				sp[len] = 0;
				otmp->spe = -3;
				nomovemsg = "You cannot engrave more.";
			} else {
				otmp->spe -= len/2;
				nomovemsg = "You finished engraving.";
			}
			multi = -len;
		}
		break;
	}
	if(oep) len += strlen(oep->engr_txt) + spct;
	ep = (struct engr *) alloc((unsigned)(sizeof(struct engr) + len + 1));
	ep->nxt_engr = head_engr;
	head_engr = ep;
	ep->engr_x = u.ux;
	ep->engr_y = u.uy;
	sp = (char *)(ep + 1);	/* (char *)ep + sizeof(struct engr) */
	ep->engr_txt = sp;
	if(oep) {
		(void) strcpy(sp, oep->engr_txt);
		(void) strcat(sp, buf);
		del_engr(oep);
	} else
		(void) strcpy(sp, buf);
	ep->engr_lth = len+1;
	ep->engr_type = type;
	ep->engr_time = moves-multi;

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

	return(1);
}

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

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

del_engr(ep) register struct engr *ep; {
register struct engr *ept;
	if(ep == head_engr)
		head_engr = ep->nxt_engr;
	else {
		for(ept = head_engr; ept; ept = ept->nxt_engr) {
			if(ept->nxt_engr == ep) {
				ept->nxt_engr = ep->nxt_engr;
				goto fnd;
			}
		}
		impossible("Error in del_engr?");
		return;
	fnd:	;
	}
	free((char *) ep);
}
//E*O*F hack.engrave.c//

echo x - hack.fight.c
cat > "hack.fight.c" << '//E*O*F hack.fight.c//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.fight.c - version 1.0.2 */

#include	"hack.h"
extern struct permonst li_dog, dog, la_dog;
extern char *exclam(), *xname();
extern struct obj *mkobj_at();

static boolean far_noise;
static long noisetime;

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

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

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

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

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

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

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

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

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

	tmp += u.udaminc + dbon();
	if(u.uswallow) {
		if((tmp -= u.uswldtim) <= 0) {
			pline("Your arms are no longer able to hit.");
			return(TRUE);
		}
	}
	if(tmp < 1) tmp = 1;
	mon->mhp -= tmp;
	if(mon->mhp < 1) {
		killed(mon);
		return(FALSE);
	}
	if(mon->mtame && (!mon->mflee || mon->mfleetim)) {
		mon->mflee = 1;			/* Rick Richardson */
		mon->mfleetim += 10*rnd(tmp);
	}

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

	if(u.umconf) {
		if(!Blind) {
			pline("Your hands stop glowing blue.");
			if(!mon->mfroz && !mon->msleep)
				pline("%s appears confused.",Monnam(mon));
		}
		mon->mconf = 1;
		u.umconf = 0;
	}
	return(TRUE);	/* mon still alive */
}

/* try to attack; return FALSE if monster evaded */
/* u.dx and u.dy must be set */
attack(mtmp)
register struct monst *mtmp;
{
	schar tmp;
	boolean malive = TRUE;
	register struct permonst *mdat;
	mdat = mtmp->data;

	if(mdat->mlet == 'L' && !mtmp->mfroz && !mtmp->msleep &&
	   !mtmp->mconf && mtmp->mcansee && !rn2(7) &&
	   (m_move(mtmp, 0) == 2 /* he died */ || /* he moved: */
		mtmp->mx != u.ux+u.dx || mtmp->my != u.uy+u.dy))
		return(FALSE);

	if(mtmp->mimic){
		if(!u.ustuck && !mtmp->mflee) u.ustuck = mtmp;
		switch(levl[u.ux+u.dx][u.uy+u.dy].scrsym){
		case '+':
			pline("The door actually was a Mimic.");
			break;
		case '$':
			pline("The chest was a Mimic!");
			break;
		default:
			pline("Wait! That's a Mimic!");
		}
		wakeup(mtmp);	/* clears mtmp->mimic */
		return(TRUE);
	}

	wakeup(mtmp);

	if(mtmp->mhide && mtmp->mundetected){
		register struct obj *obj;

		mtmp->mundetected = 0;
		if((obj = o_at(mtmp->mx,mtmp->my)) && !Blind)
			pline("Wait! There's a %s hiding under %s!",
				mdat->mname, doname(obj));
		return(TRUE);
	}

	tmp = u.uluck + u.ulevel + mdat->ac + abon();
	if(uwep) {
		if(uwep->olet == WEAPON_SYM || uwep->otyp == PICK_AXE)
			tmp += uwep->spe;
		if(uwep->otyp == TWO_HANDED_SWORD) tmp -= 1;
		else if(uwep->otyp == DAGGER) tmp += 2;
		else if(uwep->otyp == CRYSKNIFE) tmp += 3;
		else if(uwep->otyp == SPEAR &&
			index("XDne", mdat->mlet)) tmp += 2;
	}
	if(mtmp->msleep) {
		mtmp->msleep = 0;
		tmp += 2;
	}
	if(mtmp->mfroz) {
		tmp += 4;
		if(!rn2(10)) mtmp->mfroz = 0;
	}
	if(mtmp->mflee) tmp += 2;
	if(u.utrap) tmp -= 3;

	/* with a lot of luggage, your agility diminishes */
	tmp -= (inv_weight() + 40)/20;

	if(tmp <= rnd(20) && !u.uswallow){
		if(Blind) pline("You miss it.");
		else pline("You miss %s.",monnam(mtmp));
	} else {
		/* we hit the monster; be careful: it might die! */

		if((malive = hmon(mtmp,uwep,0)) == TRUE) {
		/* monster still alive */
			if(!rn2(25) && mtmp->mhp < mtmp->mhpmax/2) {
				mtmp->mflee = 1;
				if(!rn2(3)) mtmp->mfleetim = rnd(100);
				if(u.ustuck == mtmp && !u.uswallow)
					u.ustuck = 0;
			}
#ifndef NOWORM
			if(mtmp->wormno)
				cutworm(mtmp, u.ux+u.dx, u.uy+u.dy,
					uwep ? uwep->otyp : 0);
#endif NOWORM
		}
		if(mdat->mlet == 'a') {
			if(rn2(2)) {
				pline("You are splashed by the blob's acid!");
				losehp_m(rnd(6), mtmp);
				if(!rn2(30)) corrode_armor();
			}
			if(!rn2(6)) corrode_weapon();
		}
	}
	if(malive && !Blind && !mtmp->minvis && mdat->mlet == 'E'
	   && !mtmp->mcan && rn2(3)) {
	    if(mtmp->mcansee) {
	      pline("You are frozen by the floating eye's gaze!");
	      nomul((u.ulevel > 6 || rn2(4)) ? rn1(20,-21) : -200);
	    } else {
	      pline("The blinded floating eye cannot defend itself.");
	      if(!rn2(500)) u.uluck--;
	    }
	}
	return(TRUE);
}
//E*O*F hack.fight.c//

echo x - hack.invent.c
cat > "hack.invent.c" << '//E*O*F hack.invent.c//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.invent.c - version 1.0.2 */

#include	"hack.h"
#include	<stdio.h>
extern struct obj *splitobj();
extern struct obj zeroobj;
extern char morc;
extern char quitchars[];
char *xprname();
#ifndef NOWORM
#include	"def.wseg.h"

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

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

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

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

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

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

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

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

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

deltrap(trap)
register struct trap *trap;
{
	register struct trap *ttmp;

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

struct wseg *m_atseg;

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

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

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

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

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

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

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

carrying(type)
register int type;
{
	register struct obj *otmp;

	for(otmp = invent; otmp; otmp = otmp->nobj)
		if(otmp->otyp == type)
			return(TRUE);
	return(FALSE);
}

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

struct trap *
t_at(x,y)
register x,y;
{
	register struct trap *trap = ftrap;
	while(trap) {
		if(trap->tx == x && trap->ty == y) return(trap);
		trap = trap->ntrap;
	}
	return(0);
}

struct gold *
g_at(x,y)
register x,y;
{
	register struct gold *gold = fgold;
	while(gold) {
		if(gold->gx == x && gold->gy == y) return(gold);
		gold = gold->ngold;
	}
	return(0);
}

/* make dummy object structure containing gold - for temporary use only */
struct obj *
mkgoldobj(q)
register long q;
{
	register struct obj *otmp;

	otmp = newobj(0);
	/* should set o_id etc. but otmp will be freed soon */
	otmp->olet = '$';
	u.ugold -= q;
	OGOLD(otmp) = q;
	flags.botl = 1;
	return(otmp);
}

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

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

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

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

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

/* interactive version of getobj - used for Drop and Identify */
/* return the number of times fn was called successfully */
ggetobj(word, fn, max)
char *word;
int (*fn)(),  max;
{
char buf[BUFSZ];
register char *ip;
register char sym;
register int oletct = 0, iletct = 0;
register boolean allflag = FALSE;
char olets[20], ilets[20];
int (*ckfn)() = (int (*)()) 0;
xchar allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0;	/* BAH */
	if(!invent && !allowgold){
		pline("You have nothing to %s.", word);
		return(0);
	} else {
		register struct obj *otmp = invent;
		register int uflg = 0;

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

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

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

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

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

prinv(obj)
register struct obj *obj;
{
	pline(xprname(obj, obj_to_let(obj)));
}

static char *
xprname(obj,let)
register struct obj *obj;
register char let;
{
	static char li[BUFSZ];

	(void) sprintf(li, "%c - %s.", let, doname(obj));
	return(li);
}

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

/* called with 0 or "": all objects in inventory */
/* otherwise: all objects with (serial) letter in lets */
doinv(lets)
register char *lets;
{
	register struct obj *otmp;
	register char ilet;
	int ct = 0;
	char any[BUFSZ];

	morc = 0;		/* just to be sure */

	if(!invent){
		pline("Not carrying anything.");
		return;
	}

	cornline(0, (char *) 0);
	ilet = 'a';
	for(otmp = invent; otmp; otmp = otmp->nobj) {
	    if(!lets || !*lets || index(lets, ilet)) {
		cornline(1, xprname(otmp, ilet));
		any[ct++] = ilet;
	    }
	    if(++ilet > 'z') ilet = 'A';
	}
	any[ct] = 0;
	cornline(2, any);
}

dotypeinv ()				/* free after Robert Viduya */
/* Changed to one type only, so he doesnt have to type cr */
{
    char c, ilet;
    char stuff[BUFSZ];
    register int stct;
    register struct obj *otmp;
    boolean billx = inshop() && doinvbill(0);
    boolean unpd = FALSE;

	if (!invent && !u.ugold && !billx) {
	    pline ("You aren't carrying anything.");
	    return(0);
	}

	stct = 0;
	if(u.ugold) stuff[stct++] = '$';
	stuff[stct] = 0;
	for(otmp = invent; otmp; otmp = otmp->nobj) {
	    if (!index (stuff, otmp->olet)) {
		stuff[stct++] = otmp->olet;
		stuff[stct] = 0;
	    }
	    if(otmp->unpaid)
		unpd = TRUE;
	}
	if(unpd) stuff[stct++] = 'u';
	if(billx) stuff[stct++] = 'x';
	stuff[stct] = 0;

	if(stct > 1) {
	    pline ("What type of object [%s] do you want an inventory of? ",
		stuff);
	    c = readchar();
	    if(index(quitchars,c)) return(0);
	} else
	    c = stuff[0];

	if(c == '$')
	    return(doprgold());

	if(c == 'x') {
	    if(billx)
		(void) doinvbill(1);
	    else
		pline("No used-up objects on the shopping bill.");
	    return(0);
	}

	if(c == 'u' && !unpd) {
		pline("You are not carrying any unpaid objects.");
		return(0);
	}

	stct = 0;
	ilet = 'a';
	for (otmp = invent; otmp; otmp = otmp -> nobj) {
	    if (c == otmp -> olet || (c == 'u' && otmp -> unpaid))
		stuff[stct++] = ilet;
	    if (ilet == 'z')
		ilet = 'A';
	    else
		ilet++;
	}
	stuff[stct] = '\0';
	if(stct == 0)
		pline("You have no such objects.");
	else
		doinv (stuff);

	return(0);
}

/* look at what is here */
dolook() {
    register struct obj *otmp, *otmp0;
    register struct gold *gold;
    char *verb = Blind ? "feel" : "see";
    int	ct = 0;

    if(!u.uswallow) {
	otmp0 = o_at(u.ux, u.uy);
	gold = g_at(u.ux, u.uy);
    }
    if(u.uswallow || (!otmp0 && !gold)) {
	pline("You %s no objects here.", verb);
	return(!!Blind);
    }

    if(Blind) pline("You try to feel what is lying here on the floor.");
    cornline(0, "Things that are here:");
    for(otmp = otmp0; otmp; otmp = otmp->nobj) {
	if(otmp->ox == u.ux && otmp->oy == u.uy) {
	    ct++;
	    cornline(1, doname(otmp));
	    if(Blind && otmp->otyp == DEAD_COCKATRICE && !uarmg) {
		pline("Touching the dead cockatrice is a fatal mistake ...");
		pline("You die ...");
		killer = "dead cockatrice";
		done("died");
	    }
	}
    }

    if(gold) {
	char gbuf[30];

	(void) sprintf(gbuf, "%ld gold piece%s",
		gold->amount, plur(gold->amount));
	if(!ct++)
	    pline("You %s here %s.", verb, gbuf);
	else
	    cornline(1, gbuf);
    }

    if(ct == 1 && !gold) {
	pline("You %s here %s.", verb, doname(otmp0));
	cornline(3, (char *) 0);
    }
    if(ct > 1)
	cornline(2, (char *) 0);
    return(!!Blind);
}

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

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

/*
 * Gold is no longer displayed; in fact, when you have a lot of money,
 * it may take a while before you have counted it all.
 * [Bug: d$ and pickup still tell you how much it was.]
 */
extern int (*occupation)();
extern char *occtxt;
static long goldcounted;

countgold(){
	if((goldcounted += 100*(u.ulevel + 1)) >= u.ugold) {
		long eps = 0;
		if(!rn2(2)) eps = rnd((int) (u.ugold/100 + 1));
		pline("You probably have about %ld gold pieces.",
			u.ugold + eps);
		return(0);	/* done */
	}
	return(1);		/* continue */
}

doprgold(){
	if(!u.ugold)
		pline("You do not carry any gold.");
	else if(u.ugold <= 500)
		pline("You are carrying %ld gold pieces.", u.ugold);
	else {
		pline("You sit down in order to count your gold pieces.");
		goldcounted = 500;
		occupation = countgold;
		occtxt = "counting your gold";
	}
	return(1);
}

/* --- end of gold counting section --- */

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

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

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

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

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

digit(c) char c; {
	return(c >= '0' && c <= '9');
}
//E*O*F hack.invent.c//

echo x - hack.ioctl.c
cat > "hack.ioctl.c" << '//E*O*F hack.ioctl.c//'
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.ioctl.c - version 1.0.2 */

/* This cannot be part of hack.tty.c (as it was earlier) since on some
   systems (e.g. MUNIX) the include files <termio.h> and <sgtty.h>
   define the same constants, and the C preprocessor complains. */
#include <stdio.h>
#include "config.h"
#ifdef BSD
#include	<sgtty.h>
struct ltchars ltchars, ltchars0;
#else
#include	<termio.h>	/* also includes part of <sgtty.h> */
struct termio termio;
#endif BSD

getioctls() {
#ifdef BSD
	(void) ioctl(fileno(stdin), (int) TIOCGLTC, (char *) &ltchars);
	(void) ioctl(fileno(stdin), (int) TIOCSLTC, (char *) &ltchars0);
#else
	(void) ioctl(fileno(stdin), (int) TCGETA, &termio);
#endif BSD
}

setioctls() {
#ifdef BSD
	(void) ioctl(fileno(stdin), (int) TIOCSLTC, (char *) &ltchars);
#else
	(void) ioctl(fileno(stdin), (int) TCSETA, &termio);
#endif BSD
}

#ifdef SUSPEND		/* implies BSD */
dosuspend() {
#include	<signal.h>
#ifdef SIGTSTP
	if(signal(SIGTSTP, SIG_IGN) == SIG_DFL) {
		settty((char *) 0);
		(void) signal(SIGTSTP, SIG_DFL);
		(void) kill(0, SIGTSTP);
		gettty();
		setftty();
		docrt();
	} else {
		pline("I don't think your shell has job control.");
	}
#else SIGTSTP
	pline("Sorry, it seems we have no SIGTSTP here. Try ! or S.");
#endif SIGTSTP
	return(0);
}
#endif SUSPEND
//E*O*F hack.ioctl.c//

exit 0