Hack sources (part 7 of 15)

funhouse play at mcvax.UUCP
Tue Dec 18 10:33:59 AEST 1984


# This is part 7 (of 15) of the Hack sources. Send complaints to
# mcvax!play .
# 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.invent.c hack.ioctl.c hack.lev.c hack.main.c

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

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

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

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

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

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

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

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

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

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

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

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

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

struct wseg *m_atseg;

struct monst *
m_at(x,y)
register 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);
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* called with "": all objects in inventory; with 0: also usedup ones */
/* otherwise: all objects with (serial) letter in lets */
doinv(lets) register char *lets; {
	register struct obj *otmp;
	register char ilet = 'a';
	int ct = 0;
	int maxlth = 0;
	int lth;

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

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

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

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

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

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

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

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

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

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

echo x - hack.ioctl.c
cat > "hack.ioctl.c" << '//E*O*F hack.ioctl.c//'
/* 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
}


//E*O*F hack.ioctl.c//

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

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

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

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

#include "savelev.h"

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

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

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

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

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

mread(fd, buf, len)
register fd;
register char *buf;
register unsigned len;
{
register int rlen;
	rlen = read(fd, buf, (int) len);
	if(rlen != len){
		pline("Read %d instead of %d bytes\n", rlen, len);
		panic("Cannot read %d bytes from file #%d\n", len, fd);
	}
}

#ifdef BSD
#include	<sys/wait.h>
#else
#include	<wait.h>
#endif BSD

mklev()
{
	register int fd;
	char type[2];
	union wait status;
	extern char fut_geno[];

	if(getbones()) return;
	if(dlevel < rn1(3, 26)) type[0] = 'a';	/* normal level */
	else type[0] = 'b';			/* maze */
	type[1] = 0;
	switch(fork()){
	case 0:
		(void) signal(SIGINT, SIG_IGN);
		(void) signal(SIGQUIT, SIG_IGN);
		execl("./mklev", "mklev", lock, type, itoa(dlevel), fut_geno, 
#ifdef WIZARD
			wizard ? "w" :
#endif WIZARD
					"", (char *) 0);
		exit(2);
	case -1:
		settty("Cannot fork!\n");
		exit(1);
	default:
		(void) fflush(stdout);	/* You fell into a trap ... */
		(void) wait(&status);
	}
	if(status.w_status) {
		if(status.w_coredump) {
			settty("Mklev dumped core. Exiting...\n");
			exit(1);
		}
		if(status.w_termsig) {
			settty("Mklev killed by a signal. Exiting...\n");
			exit(1);
		}
		if(status.w_retcode) {
			if(status.w_retcode == 2) {
				settty("Cannot execl mklev.\n");
				exit(1);
			}
			pline("Mklev failed. Let's try again.");
			mklev();
			return;
		}
	}
	if((fd = open(lock, 0)) < 0) {
		pline("Can't open %s!", lock);
		mklev();
		return;
	}
	(void) getlev(fd);
	(void) close(fd);
}
//E*O*F hack.lev.c//

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

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

extern char *getlogin();
extern char plname[PL_NSIZ], pl_character[PL_CSIZ];
extern char *getenv();

int (*afternmv)();

int done1();
int hangup();

char safelock[] = "safelock";
xchar locknum;				/* max num of players */
char *catmore = "/bin/cat";		/* or e.g. /usr/ucb/more */
char SAVEF[PL_NSIZ + 5] = "save/";
char perm[] = "perm";
char *hname;		/* name of the game (argv[0] of call) */
char obuf[BUFSIZ];	/* BUFSIZ is defined in stdio.h */

extern char *nomovemsg;
extern long wailmsg;

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

	hname = argv[0];

	/*
	 * See if we must change directory to the playground.
	 * (Perhaps hack runs suid and playground is inaccessible
	 *  for the player.)
	 * The environment variable HACKDIR is overridden by a
	 *  -d command line option.
	 */
	dir = getenv("HACKDIR");
	if(argc > 1 && !strncmp(argv[1], "-d", 2)) {
		argc--;
		argv++;
		dir = argv[0]+2;
		if(*dir == '=' || *dir == ':') dir++;
		if(!*dir && argc > 1) {
			argc--;
			argv++;
			dir = argv[0];
		}
		if(!*dir)
			error("Flag -d must be followed by a directory name.");
	}

	/*
	 * Now we know the directory containing 'record' and
	 * may do a prscore().
	 */
	if(argc > 1 && !strncmp(argv[1], "-s", 2)) {
		if(dir) chdirx(dir);
		prscore(argc, argv);
		exit(0);
	}

	/*
	 * It seems he really wants to play. Find the creation date of
	 * this game so as to avoid restoring outdated savefiles.
	 */
	gethdate(hname);

	/*
	 * We cannot do chdir earlier, otherwise gethdate will fail.
	 */
	if(dir) chdirx(dir);

	/*
	 * Who am i? Perhaps we should use $USER instead?
	 */
	(void) strncpy(plname, getlogin(), sizeof(plname)-1);

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

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

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

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

lockcheck()
{
	extern int errno;
	register int i, fd;

	/* we ignore QUIT and INT at this point */
	if (link(perm,safelock) == -1)
		error("Cannot link safelock. (Try again or rm safelock.)");

	for(i = 0; i < locknum; i++) {
		lock[0]= 'a' + i;
		if((fd = open(lock,0)) == -1) {
			if(errno == ENOENT) goto gotlock;    /* no such file */
			(void) unlink(safelock);
			error("Cannot open %s", lock);
		}
		(void) close(fd);
	}
	(void) unlink(safelock);
	error("Too many hacks running now.");
gotlock:
	fd = creat(lock,FMASK);
	if(fd == -1) {
		error("cannot creat lock file.");
	} else {
		int pid;

		pid = getpid();
		if(write(fd, (char *) &pid, 2) != 2){
			error("cannot write lock");
		}
		if(close(fd) == -1){
			error("cannot close lock");
		}
	}
	if(unlink(safelock) == -1){
		error("Cannot unlink safelock");
	}
}

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

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

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

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

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

#ifdef NEWS
int stopnews;

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

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

chdirx(dir) char *dir; {
	if(chdir(dir) < 0) {
		perror(dir);
		error("Cannot chdir to %s.", dir);
	}
}
//E*O*F hack.main.c//

exit 0



More information about the Comp.sources.unix mailing list