DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T m

⟦fda5603bc⟧ TextFile

    Length: 46657 (0xb641)
    Types: TextFile
    Names: »monster.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/General/Ularn/monster.c« 

TextFile

/*
 *	monster.c
 *
 *	This file contains the following functions:
 *	------------------------------------------------------------------------
 *
 *	createmonster(monstno)	Function to create a monster next to the player
 *		int monstno;
 *
 *	int cgood(x,y,itm,monst)	Function to check location for emptiness
 *		int x,y,itm,monst;
 *
 *	createitem(it,arg) 	Routine to place an item next to the player
 *		int it,arg;
 *
 *	cast() 		Subroutine called by parse to cast a spell for the user
 *
 *	speldamage(x) 	Function to perform spell functions cast by the player
 *		int x;
 *
 *	loseint()	Routine to decrement your int (intelligence) if > 3
 *
 *	isconfuse() 	Routine to check to see if player is confused
 *
 *	nospell(x,monst) Routine to return 1 if a spell doesn't affect a monster
 *		int x,monst;
 *
 *	fullhit(xx)	Function to return full damage against a monst (aka web)
 *		int xx;
 *
 *			Routine to direct spell damage 1 square in 1 dir
 *	direct(spnum,dam,str,arg)	
 *		int spnum,dam,arg;
 *		char *str;
 *
 *			Function to perform missile attacks
 *	godirect(spnum,dam,str,delay,cshow)		
 *		int spnum,dam,delay;
 *		char *str,cshow;
 *
 *		  Routine to put "monster" or the monster name into lastmosnt
 *	ifblind(x,y)	
 *		int x,y;
 *
 *	tdirect(spnum)		Routine to teleport away a monster
 *		int spnum;
 *
 *		  	Routine to damage all monsters 1 square from player
 *	omnidirect(sp,dam,str)  
 *		int sp,dam;
 *		char *str;
 *
 *	dirsub(x,y)	Routine to ask for direction, then modify x,y for it
 *	int *x,*y;
 *
 *	vxy(x,y)  	Routine to verify/fix (*x,*y) for being within bounds
 *		int *x,*y;
 *
 *	dirpoly(spnum)	Routine to ask for a direction and polymorph a monst
 *		int spnum;
 *
 *	hitmonster(x,y) Function to hit a monster at the designated coordinates
 *		int x,y;
 *
 *	hitm(x,y,amt)	Function to just hit a monster at a given coordinates
 *		int x,y,amt;
 *
 *	hitplayer(x,y) 	Function for the monster to hit the player from (x,y)
 *		int x,y;
 *
 *	dropsomething(monst) 	Function to create an object when a monster dies
 *		int monst;
 *
 *	dropgold(amount)	Function to drop some gold around player
 *		int amount;
 *
 *	something(level) 	Function to create a random item around player
 *		int level;
 *
 *	newobject(lev,i) 	Routine to return a randomly selected new object
 *		int lev,*i;
 *
 *  spattack(atckno,xx,yy)    Function to process special attacks from monsters
 *  	int atckno,xx,yy;
 *
 *		   Routine to subtract hp from user and flag bottomline display
 *	checkloss(x) 	
 *		int x;
 *
 *		   Routine to annihilate monsters around player, playerx,playery
 *	annihilate()   
 *
 *		  Function to create a new sphere of annihilation
 *	newsphere(x,y,dir,lifetime)  
 *		int x,y,dir,lifetime;
 *
 *	rmsphere(x,y)	Function to delete a sphere of annihilation from list
 *		int x,y;
 *
 *	sphboom(x,y)	Function to perform the effects of a sphere detonation
 *		int x,y;
 *
 *	genmonst()	Function to ask for monster and genocide from game
 *
 */
#include "header.h"

struct isave	/* used for altar reality */
{
	char type;	/* 0=item,  1=monster */
	char id;	/* item number or monster number */
	short arg;	/* the type of item or hitpoints of monster */
};

/*
 *		Function to create a monster next to the player
 *	createmonster(monstno) 		
 *		int monstno;
 *
 *	Enter with the monster number (1 to MAXMONST+8)
 *	Returns no value.
 */
createmonster(mon)
int mon;
{
	register int x,y,k,i;
	if (mon<1 || mon>MAXMONST+8)	{
		beep(); 
		lprintf("\ncan't createmonst(%d)\n",(long)mon); 
		nap(3000); 
		return;
	}
	while (monster[mon].genocided && mon<MAXMONST) 
		mon++; /* genocided? */
	for (k=rnd(8), i= -8; i<0; i++,k++)/* choose direction, then try all */
	{
		if (k>8) k=1;		/* wraparound the diroff arrays */
		x = playerx + diroffx[k];		
		y = playery + diroffy[k];
		if (cgood(x,y,0,1))	/* if we can create here */
		{
			mitem[x][y] = mon;
			hitp[x][y] = monster[mon].hitpoints;
			stealth[x][y]=know[x][y]=0;
			switch(mon) {
			case ROTHE: 
			case POLTERGEIST: 
			case VAMPIRE:    
				stealth[x][y]=1;
			};
			return;
		}
	}
}

/*
 *	int cgood(x,y,itm,monst)	Function to check location for emptiness
 *		int x,y,itm,monst;
 *
 *	Routine to return TRUE if a location does not have itm or monst there
 *	returns FALSE (0) otherwise
 *	Enter with itm or monst TRUE or FALSE if checking it
 *	Example:  if itm==TRUE check for no item at this location
 *			  if monst==TRUE check for no monster at this location
 *	This routine will return FALSE if at a wall or the dungeon exit on level 1
 */
cgood(x,y,itm,monst)
register int x,y;
int itm,monst;
{
	if ((y>=0) && (y<=MAXY-1) 
	    && (x>=0) && (x<=MAXX-1)) 		/* within bounds? */
	  if (item[x][y]!=OWALL)		/* can't make on walls */
	    if (itm==0 || (item[x][y]==0))	/* is it free of items? */
		if (monst==0 || (mitem[x][y]==0)) /*is it free of monsters? */
			if ((level!=1) || (x!=33) || (y!=MAXY-1)) 
				/* not exit to level 1 */
				return(1);
	return(0);
}

/*
 *	createitem(it,arg) 	Routine to place an item next to the player
 *		int it,arg;
 *
 *	Enter with the item number and its argument (iven[], ivenarg[])
 *	Returns no value, thus we don't know about createitem() failures.
 */
createitem(it,arg)
int it;
long arg;
{
	register int x,y,k,i;

	if (it >= MAXOBJ) 
		return;	/* no such object */

	for (k=rnd(8), i= -8; i<0; i++,k++) { /* choose direction, try all */
		if (k>8) k=1;		/* wraparound the diroff arrays */
		x = playerx + diroffx[k];
		y = playery + diroffy[k];
		if ( (it != OMAXGOLD && it != OGOLDPILE) ) {
		    if (cgood(x,y,1,0)) {	/* if we can create here */
			item[x][y] = it;  
			know[x][y]=0;  
			iarg[x][y]=arg;  
			return;
		    }
		}
		else {
			int i;
			switch (item[x][y]) {
			case OGOLDPILE :
				if ( (iarg[x][y] + arg) < 32767) {
					iarg[x][y] += arg;
					return;
				}
			case ODGOLD :
				if ( (10 * iarg[x][y] + arg) < 327670L) {
					i = iarg[x][y] ;
					iarg[x][y] = (10 * i + arg) / 10;
					item[x][y] = ODGOLD;
					return;
				}
			case OMAXGOLD :
				if ( (100 * iarg[x][y] + arg) < 3276700L) {
					i = (100 * iarg[x][y]) + arg;
					iarg[x][y] = i / 100;
					item[x][y] = OMAXGOLD;
					return;
				}
			case OKGOLD :
				if ( (1000 * iarg[x][y] + arg) < 32767000L) { 
					i = iarg[x][y];
					iarg[x][y] = (1000 * i + arg) / 1000;
					item[x][y] = OKGOLD;
					return;
				}
				else iarg[x][y] = 32767000L; 
				return;
			default :
		    		if (cgood(x,y,1,0)) {
					item[x][y] = it;  
					know[x][y]=0;  
					if (it == OMAXGOLD)
						iarg[x][y]= arg / 100;  
					else iarg[x][y]=arg;  
					return;
				}
			} /* end switch */
		} /* end else */
	} /* end for */
}

/*
 *	cast() 		Subroutine called by parse to cast a spell for the user
 *
 *	No arguments and no return value.
 */
static char eys[] = "\nEnter your spell: ";

cast()
{
	register int i,j,a,b,d;

	cursors();
	if (c[SPELLS]<=0) {	
		lprcat("\nYou don't have any spells!");	
		return;	
	}
	lprcat(eys);		
	--c[SPELLS];
	while ((a=getcharacter())=='D') { 	
		seemagic(-1); 
		cursors();  
		lprcat(eys); 
	}
	if (a=='\33') goto over; 	/* to escape casting a spell	*/
	if ((b=getcharacter())=='\33') goto over; /*to escape casting a spell */
	if ((d=getcharacter())=='\33') { 
over: 
		lprcat(aborted); 
		c[SPELLS]++; 
		return; 
	} 			/* to escape casting a spell */
	/*seq search for his spell, hash?*/
	for (lprc('\n'),j= -1,i=0; i<SPNUM+1; i++) 
		if ((spelcode[i][0]==a) && (spelcode[i][1]==b) && (spelcode[i][2]==d))
			if (spelknow[i]) {  	
				speldamage(i);  
				j = 1;  
				i=SPNUM+1;
			}

	if (j == -1) lprcat("  Nothing Happened ");
	bottomline();
}

/*
 *	speldamage(x)	Function to perform spell functions cast by the player
 *	int x;
 *
 *	Enter with the spell number, returns no value.
 *	Please insure that there are 2 spaces before all messages here
 */
speldamage(x)
int x;
{
	register int i,j,clev;
	int xl,xh,yl,yh;
	register char *p,*kn,*pm;

	if (x>=SPNUM+1) return;	/* no such spell */

	if (c[TIMESTOP])  { 	
		lprcat("  It didn't seem to work"); 
		return; 
	}  /* not if time stopped */

	if ((rnd(23)==7) || (rnd(18) > c[INTELLIGENCE]))
	{ 	
		lprcat("  It didn't work!");  
		return; 
	}

	clev = c[LEVEL];
	if (clev*3+2 < x) 
	{ 	
		lprcat("  Nothing happens.  You seem inexperienced at this"); 
		return; 
	}

	switch(x)
	{
		/* ----- LEVEL 1 SPELLS ----- */

	case 0:	
		if (c[PROTECTIONTIME]==0)
			c[MOREDEFENSES]+=2; /* protection field +2 */
		c[PROTECTIONTIME] += 250;   
		return;

	case 1: 
		i = rnd(((clev+1)<<1)) + clev + 3;
		godirect(x,i,(clev>=2)?"  Your missiles hit the %s":"  Your missile hit the %s",100,'+'); /* magic missile */
		return;

	case 2:	
		if (c[DEXCOUNT]==0)	
			c[DEXTERITY]+=3; /*	dexterity	*/
		c[DEXCOUNT] += 400;  	
		return;

	case 3: 
		i=rnd(3)+1;
		p="  While the %s slept, you smashed it %d times";
ws:			
		direct(x,fullhit(i),p,i); /*	sleep	*/
		return;

	case 4:	/* charm monster */

		c[CHARMCOUNT] += c[CHARISMA]<<1;	
		return;

		/* sonic spear */
	case 5:	
		godirect(x,rnd(10)+15+clev,"  The sound damages the %s",70,'@'); 
		return;

		/* ----- LEVEL 2 SPELLS ----- */

	case 6: 
		i=rnd(3)+2;	
		p="  While the %s is entangled, you hit %d times";
		goto ws; /* web */

	case 7:	
		if (c[STRCOUNT]==0) c[STREXTRA]+=3;/*	strength*/
		c[STRCOUNT] += 150+rnd(100);    
		return;

	case 8:	
		yl = playery-5;     /* enlightenment */
		yh = playery+6;   
		xl = playerx-15;   
		xh = playerx+16;
		vxy(&xl,&yl);   
		vxy(&xh,&yh); /* check bounds */
		for (i=yl; i<=yh; i++) /* enlightenment	*/
			for (j=xl; j<=xh; j++)	know[j][i]=1;
		draws(xl,xh+1,yl,yh+1);	
		return;

	case 9:	
		raisehp(20+(clev<<1));  
		return;  /* healing */

	case 10:	
		c[BLINDCOUNT]=0;	
		return;	/* cure blindness	*/

	case 11:	
		createmonster(makemonst(level+1)+8);  
		return;

	case 12: 
		if (rnd(11)+7 <= c[WISDOM]) 
			direct(x,rnd(20)+20+clev,"  The %s believed!",0);
		else 
		    lprcat("  It didn't believe the illusions!");
		return;

		/* if he has the amulet of invisibility then add more time */
	case 13:	
		for (j=i=0; i<26; i++)
			if (iven[i]==OAMULET) 
				j+= 1+ivenarg[i];
		c[INVISIBILITY] += (j<<7)+12;   
		return;

		/* ----- LEVEL 3 SPELLS ----- */

	case 14:	
		godirect(x,rnd(25+clev)+25+clev,"  The fireball hits the %s",40,'*'); 
		return; /*	fireball */

	case 15:	
		godirect(x,rnd(25)+20+clev,"  Your cone of cold strikes the %s",60,'O');	/*	cold */
		return;

	case 16:	
		dirpoly(x);  
		return;	/*	polymorph */

	case 17:	
		c[CANCELLATION]+= 5+clev;	
		return;	/*	cancellation	*/

	case 18:	
		c[HASTESELF]+= 7+clev;  
		return;  /*	haste self	*/

		/* cloud kill */
	case 19:    
		omnidirect(x,30+rnd(10),"  The %s gasps for air");	
		return;

		/* vaporize rock */
	case 20:	
		xh = min(playerx+1,MAXX-2);		
		yh = min(playery+1,MAXY-2);
		for (i=max(playerx-1,1); i<=xh; i++) 
			for (j=max(playery-1,1); j<=yh; j++) {
				kn = &know[i][j];    
				pm = &mitem[i][j];
				switch(*(p= &item[i][j])) {
				case OWALL: 
					if (level<MAXLEVEL+MAXVLEVEL-3)
						*p = *kn = 0;
					break;

				case OSTATUE:
					if (c[HARDGAME]>3 && rnd(60)<30)
						break;
					*p=OBOOK; 
					iarg[i][j]=level;  
					*kn=0;
					break;

				case OTHRONE: 
					*pm=GNOMEKING;  
					*kn=0;  
					*p= OTHRONE2;
					hitp[i][j]=monster[GNOMEKING].hitpoints; 
					break;

				case OALTAR:	
					*pm=DEMONPRINCE;  
					*kn=0;
					hitp[i][j]=monster[DEMONPRINCE].hitpoints; 
					createmonster(DEMONPRINCE);
					createmonster(DEMONPRINCE);
					createmonster(DEMONPRINCE);
					createmonster(DEMONPRINCE);
					break;
				};
				switch(*pm)
				{	/* Xorn takes damage from vpr */
				case XORN:	
					ifblind(i,j);  
					hitm(i,j,200); 
					break; 
				case TROLL:
					ifblind(i,j);  
					hitm(i,j,200); 
					break; 
				}
			}
		return;

		/* ----- LEVEL 4 SPELLS ----- */

	case 21:/* dehydration */

		direct(x,100+clev,"  The %s shrivels up",0); 
		return;

	case 22:	/*	lightning */
		godirect(x,rnd(25)+20+(clev<<1),"  A lightning bolt hits the %s",1,'~');	
		return;

	case 23:	
		i=min(c[HP]-1,c[HPMAX]/2);	/* drain life */
		direct(x,i+i,"",0);	
		c[HP] -= i;  	
		return;

	case 24:	
		if (c[GLOBE]==0) c[MOREDEFENSES] += 10;
		c[GLOBE] += 200;  
		loseint();  /* globe of invulnerability */
		return;

	case 25:	
		omnidirect(x,32+clev,"  The %s struggles for air in your flood!"); /* flood */
		return;

		/* finger of death */
	case 26:	
		if (rnd(151)==63) { 
			beep(); 
			lprcat("\nYour heart stopped!\n"); 
			nap(4000);  
			died(270); 
			return; 
		}
		if (c[WISDOM]>rnd(10)+10) direct(x,2000,"  The %s's heart stopped",0); 
		else lprcat("  It didn't work"); 
		return;

		/* ----- LEVEL 5 SPELLS ----- */

		/* scare monster */
	case 27:	
		c[SCAREMONST] += rnd(10)+clev;

		/* if have HANDofFEAR make last longer */
		for (j=i=0; i<26; i++)
			if (iven[i]==OHANDofFEAR) {
				c[SCAREMONST] *= 3;
				break;
			}
		return;

	case 28:	
		c[HOLDMONST] += rnd(10)+clev;  
		return;  /* hold monster */

	case 29:	
		c[TIMESTOP] += rnd(20)+(clev<<1);  
		return;  /* time stop */

	case 30:	
		tdirect(x);  
		return;  /* teleport away */

		/* magic fire */
	case 31:	
		omnidirect(x,35+rnd(10)+clev,"  The %s cringes from the flame"); 
		return;

		/* ----- LEVEL 6 SPELLS ----- */

	case 32:	/* make wall */
		makewall(x);
		return;

		/* sphere of annihilation */
	case 33:	
		if ((rnd(23)==5) && (wizard==0)) 
		{ 	
			beep(); 
			lprcat("\nYou have been enveloped by the zone of nothingness!\n");
			nap(4000);  
			died(258); 
			return;
		}
		xl=playerx; 
		yl=playery;
		loseint();
		i=dirsub(&xl,&yl); /* get direction of sphere */
		newsphere(xl,yl,i,rnd(20)+11);/*make a sphere */
		return;

	case 34:	
		genmonst();  
		spelknow[34]=0;  /* genocide */
		loseint();
		return;

	case 35:/* summon demon */
		if (rnd(100) > 30) { 
			direct(x-1,150,"  The demon strikes at the %s",0);  
			return; 
		}
		if (rnd(100) > 15) { 
			lprcat("  Nothing seems to have happened");  
			return; 
		}
		lprcat("  The demon turned on you and vanished!"); 
		beep();
		i=rnd(40)+30;  
		lastnum=277;
		losehp(i); /* must say killed by a demon */

		return;

	case 36:/* walk through walls */
		c[WTW] += rnd(10)+5;	
		return;

	case 37:/* alter reality */
		{
			struct isave *save;	
			/* pointer to item save structure */
			int sc;	
			sc=0;	/* # items saved */
			save = (struct isave *)malloc(sizeof(struct isave)*MAXX*MAXY*2);
			for (j=0; j<MAXY; j++)/* save all items and monsters */
				for (i=0; i<MAXX; i++)
				{
					xl = item[i][j];
					if (xl && xl!=OWALL && xl!=OANNIHILATION) 
					{
						save[sc].type=0;  
						save[sc].id=item[i][j];
						save[sc++].arg=iarg[i][j];
					}
					if (mitem[i][j]) 
					{
						save[sc].type=1;  
						save[sc].id=mitem[i][j];
						save[sc++].arg=hitp[i][j];
					}
					item[i][j]=OWALL;   
					mitem[i][j]=0;
					if (wizard) know[i][j]=1; 
					else know[i][j]=0;
				}
			eat(1,1);	
			if (level==1) item[33][MAXY-1]=0;
			for (j=rnd(MAXY-2), i=1; i<MAXX-1; i++) item[i][j]=0;
			while (sc>0) /* put objects back in level */
			{
				--sc;
				if (save[sc].type == 0)
				{
					int trys;
					for (trys=100, i=j=1; --trys>0 && item[i][j]; i=rnd(MAXX-1), j=rnd(MAXY-1));
					if (trys) { 
						item[i][j]=save[sc].id; 
						iarg[i][j]=save[sc].arg; 
					}
				}
				else
				{ /* put monsters back in */
					int trys;
					for (trys=100, i=j=1; --trys>0 && (item[i][j]==OWALL || mitem[i][j]); i=rnd(MAXX-1), j=rnd(MAXY-1));
					if (trys) { 
						mitem[i][j]=save[sc].id; 
						hitp[i][j]=save[sc].arg; 
					}
				}
			}
			loseint();
			draws(0,MAXX,0,MAXY);  
			if (wizard==0) spelknow[37]=0;
			free((char*)save);	 
			positionplayer();  
			return;
		}

	case 38:	/* permanence */

		adjtime(-99999L);  
		spelknow[38]=0; /* forget */
		loseint();
		return;

	default:	
		lprintf("  spell %d not available!",(long)x); 
		beep();  
		return;
	};
}

/*
 *	loseint()		
 *		Routine to subtract 1 from your int (intelligence) if > 3
 *
 *	No arguments and no return value
 */
loseint()
{
	if (--c[INTELLIGENCE]<3)  c[INTELLIGENCE]=3;
}

/*
 *	isconfuse() 		Routine to check to see if player is confused
 *
 *	This routine prints out a message saying "You can't aim your magic!"
 *	returns 0 if not confused, non-zero (time remaining confused) 
 *	if confused
 */
isconfuse()
{
	if (c[CONFUSE]) { 
		lprcat(" You can't aim your magic!"); 
		beep(); 
	}
	return(c[CONFUSE]);
}

/*		Routine to return 1 if a spell doesn't affect a monster
 *	nospell(x,monst)	
 *	int x,monst;
 *
 *	Subroutine to return 1 if the spell can't affect the monster
 *	  otherwise returns 0
 *	Enter with the spell number in x, and the monster number in monst.
 */
nospell(x,monst)
int x,monst;
{
	register int tmp;

	/* bad spell or monst */
	if (x>=SPNUM || monst>MAXMONST+8 || monst<0 || x<0) return(0);	

	if ((tmp=spelweird[monst-1][x])==0) 
		return(0);
	cursors();  
	lprc('\n');  
	lprintf(spelmes[tmp],monster[monst].name);  
	return(1);
}

/*
 *		Function to return full damage against a monster (aka web)
 *	fullhit(xx)		
 *		int xx;
 *
 *	Function to return hp damage to monster due to a number of full hits
 *	Enter with the number of full hits being done
 */
fullhit(xx)
int xx;
{
	register int i;

	if (xx<0 || xx>20) return(0);	/* fullhits are out of range */
	if (c[LANCEDEATH]) return(10000);	/* lance of death */

i = xx * ((c[WCLASS]>>1)+c[STRENGTH]+c[STREXTRA]-c[HARDGAME]-12+c[MOREDAM]); 

	return( (i>=1) ? i : xx );
}

/*
 *		Routine to direct spell damage 1 square in 1 dir
 *	direct(spnum,dam,str,arg)	
 *	int spnum,dam,arg;
 *	char *str;
 *
 *	Routine to ask for a direction to a spell and then hit the monster
 *	Enter with the spell number in spnum, the damage to be done in dam,
 *	  lprintf format string in str, and lprintf's argument in arg.
 *	Returns no value.
 */
direct(spnum,dam,str,arg)
int spnum,dam,arg;
char *str;
{
	int x,y;
	register int m;
	if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad arguments */
	if (isconfuse()) return;
	dirsub(&x,&y);
	m = mitem[x][y];
	if (item[x][y]==OMIRROR) {
		if (spnum==3) /* sleep */
		{
			lprcat("You fall asleep! "); 
			beep();
fool:
			arg += 2;
			while (arg-- > 0) { 
				parse2(); 
				nap(1000); 
			}
			return;
		}
		else if (spnum==6) /* web */
		{
			lprcat("You get stuck in your own web! "); 
			beep();
			goto fool;
		}
		else {
			lastnum=278; 
			lprintf(str,"spell caster (thats you)",(long)arg);
			beep(); 
			losehp(dam); 
			return;
		}
	}
	if (m==0) {	
		lprcat("  There wasn't anything there!");	
		return;  
	}
	ifblind(x,y);
	if (nospell(spnum,m)) { 
		lasthx=x;  
		lasthy=y; 
		return; 
	}
	lprintf(str,lastmonst,(long)arg);       
	hitm(x,y,dam);
}

/*
 *				Function to perform missile attacks
 *	godirect(spnum,dam,str,delay,cshow)		
 *		int spnum,dam,delay;
 *		char *str,cshow;
 *
 *	Function to hit in a direction from a missile weapon and have it keep
 *	on going in that direction until its power is exhausted
 *	Enter with the spell number in spnum, the power of the weapon in hp,
 *	  lprintf format string in str, the # of milliseconds to delay between 
 *	 locations in delay, and the character to represent the weapon in cshow.
 *	Returns no value.
 */
godirect(spnum,dam,str,delay,cshow)
int spnum,dam,delay;
char *str,cshow;
{
	register char *p;
	register int x,y,m;
	int dx,dy;

	if (spnum<0 || spnum>=SPNUM || str==0 || delay<0) return; /* bad args */

	if (isconfuse()) return;

	dirsub(&dx,&dy);	
	x=dx;	
	y=dy;
	dx = x-playerx;		
	dy = y-playery;		
	x = playerx;	
	y = playery;

	while (dam>0) {
		x += dx;    
		y += dy;
		if ((x > MAXX-1) || (y > MAXY-1) || (x < 0) || (y < 0)) {
			dam=0;	
			break;  /* out of bounds */
		}
		if ((x==playerx) && (y==playery)) /* if energy hits player */
		{
			cursors(); 
			lprcat("\nYou are hit my your own magic!"); 
			beep();
			lastnum=278;  
			losehp(dam);  
			return;
		}
		if (c[BLINDCOUNT]==0) /* if not blind show effect */
		{
			cursor(x+1,y+1); 
			lprc(cshow); 
			nap(delay); 
			show1cell(x,y);
		}
		if ((m=mitem[x][y]))	/* is there a monster there? */
		{
			ifblind(x,y);
			if (m == LUCIFER || (m>=DEMONLORD && rnd(100)<10) ) {
				dx *= -1;	
				dy *= -1;	
				cursors();
				lprc('\n');
				lprintf("\nthe %s returns your puny missile!", monster[m].name);
			} 
			else {
				if (nospell(spnum,m)) { 
					lasthx=x;  
					lasthy=y; 
					return; 
				}
				cursors(); 
				lprc('\n');
				lprintf(str,lastmonst);		
				dam -= hitm(x,y,dam);
				show1cell(x,y);  
				nap(1000);
				x -= dx;
				y -= dy;
			}
		}
		else switch (*(p= &item[x][y])) {
		case OWALL:	
			cursors(); 
			lprc('\n'); 
			lprintf(str,"wall");
			if (dam>=50+c[HARDGAME]) /* enough damage? */
				if (level<MAXLEVEL+MAXVLEVEL-3) /* not on V3 */
					if ((x<MAXX-1) && (y<MAXY-1) && (x) && (y))
					{
						lprcat("  The wall crumbles");
god3:	
						*p=0;
god:	
						know[x][y]=0;
						show1cell(x,y);
					}
god2:	
			dam = 0;	
			break;

		case OCLOSEDDOOR:	
			cursors(); 
			lprc('\n'); 
			lprintf(str,"door");
			if (dam>=40) {
				lprcat("  The door is blasted apart");
				goto god3;
			}
			goto god2;

		case OSTATUE:	
			cursors(); 
			lprc('\n'); 
			lprintf(str,"statue");
			if (dam>44) {
				if (c[HARDGAME] > 3 && rnd(60)<30)
					goto god2;
				lprcat("  The statue crumbles");
				*p=OBOOK; 
				iarg[x][y]=level;
				goto god;
			}
			goto god2;

		case OTHRONE:	
			cursors(); 
			lprc('\n'); 
			lprintf(str,"throne");
			if (dam>33) {
				mitem[x][y]=GNOMEKING; 
				hitp[x][y]=monster[GNOMEKING].hitpoints;
				*p = OTHRONE2;
				goto god;
			}
			goto god2;

		case OMIRROR:
			dx *= -1;	
			dy *= -1;	
			break;
		};
		dam -= 3 + (c[HARDGAME]>>1);
	}
}

/*
 *		Routine to put "monster" or the monster name into lastmosnt
 *	ifblind(x,y)	
 *	int x,y;
 *
 *	Subroutine to copy the word "monster" into lastmonst if the player is 
 * 	blind. Enter with the coordinates (x,y) of the monster
 *	Returns no value.
 */
ifblind(x,y)
int x,y;
{
	char *p;
	vxy(&x,&y);	/* verify correct x,y coordinates */
	if (c[BLINDCOUNT]) { 
		lastnum=279;  
		p="monster"; 
	}
	else { 
		lastnum=mitem[x][y];  
		p=monster[lastnum].name; 
	}
	strcpy(lastmonst,p);
}

/*
 *	tdirect(spnum)		Routine to teleport away a monster
 *	int spnum;
 *
 *	Routine to ask for a direction to a spell and then teleport away monster
 *	Enter with the spell number that wants to teleport away
 *	Returns no value.
 */
tdirect(spnum)
int spnum;
{
	int x,y;
	register int m;

	if (spnum<0 || spnum>=SPNUM) return; /* bad args */
	if (isconfuse()) return;
	dirsub(&x,&y);
	if ((m=mitem[x][y])==0)
	{	
		lprcat("  There wasn't anything there!");	
		return;  
	}
	ifblind(x,y);
	if (nospell(spnum,m)) { 
		lasthx=x;  
		lasthy=y; 
		return; 
	}
	fillmonst(m);  
	mitem[x][y]=know[x][y]=0;
}


makewall(spnum)
int spnum;
{
	int x,y;

	if (spnum<0 || spnum>=SPNUM) return; /* bad args */
	if (isconfuse()) return;
	dirsub(&x,&y);

	if ((y>=0) && (y<=MAXY-1) && (x>=0) && (x<=MAXX-1)) /* within bounds? */
		if (item[x][y]!=OWALL) {	/* can't make anything on walls */
			if (item[x][y]==0){	/* is it free of items? */
				if (mitem[x][y]==0){  /*is it free of monsters? */
					if ((level!=1) || (x!=33) || (y!=MAXY-1)) {
						item[x][y]=OWALL;
						know[x][y]=1;
						show1cell(x,y);
					}
					else lprcat("\nyou can't make a wall there!");
				}
				else lprcat("\nthere's a monster there!");
			}
			else lprcat("\nthere's something there already!");
		}
		else lprcat("\nthere's a wall there already!");

}

/*
 *	omnidirect(sp,dam,str)   Routine to damage all monsters 1 square from player
 *		int sp,dam;
 *		char *str;
 *
 *	Routine to cast a spell and then hit the monster in all directions
 *	Enter with the spell number in sp, the damage done to wach square in dam,
 *	  and the lprintf string to identify the spell in str.
 *	Returns no value.
 */
omnidirect(spnum,dam,str)
int spnum,dam;
char *str;
{
	register int x,y,m;
	if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad args */
	for (x=playerx-1; x<playerx+2; x++)
		for (y=playery-1; y<playery+2; y++)
		{
			if (m=mitem[x][y])
				if (nospell(spnum,m) == 0)
				{
					ifblind(x,y);
					cursors(); 
					lprc('\n'); 
					lprintf(str,lastmonst);
					hitm(x,y,dam);  
					nap(800);
				}
				else  { 
					lasthx=x;  
					lasthy=y; 
				}
		}
}

/*
 *		Routine to ask for direction, then modify x,y for it
 *	static dirsub(x,y)		
 *	int *x,*y;
 *
 *	Function to ask for a direction and modify an x,y for that direction
 *	Enter with the origination coordinates in (x,y).
 *	Returns index into diroffx[] (0-8).
 */
dirsub(x,y)
int *x,*y;
{
	register int i;
	lprcat("\nIn What Direction? ");
	for (i=0; ; )
		switch(getcharacter())
		{
		case 'b':	
			i++;
		case 'n':	
			i++;	
		case 'y':	
			i++;	
		case 'u':	
			i++;
		case 'h':	
			i++;	
		case 'k':	
			i++;
		case 'l':	
			i++;	
		case 'j':	
			i++;		
			goto out;
		};
out:
	*x = playerx+diroffx[i];		
	*y = playery+diroffy[i];
	vxy(x,y);  
	return(i);
}

/*
 *	vxy(x,y)	   Routine to verify/fix coordinates for being within bounds
 *		int *x,*y;
 *
 *	Function to verify x & y are within the bounds for a level
 *	If *x or *y is not within the absolute bounds for a level, fix them so that
 *	  they are on the level.
 *	Returns TRUE if it was out of bounds, and the *x & *y in the calling
 *	routine are affected.
 */
vxy(x,y)
int *x,*y;
{
	int flag=0;
	if (*x<0) { 
		*x=0; 
		flag++; 
	}
	if (*y<0) { 
		*y=0; 
		flag++; 
	}
	if (*x>=MAXX) { 
		*x=MAXX-1; 
		flag++; 
	}
	if (*y>=MAXY) { 
		*y=MAXY-1; 
		flag++; 
	}
	return(flag);
}

/*
 *	dirpoly(spnum)		Routine to ask for a direction and polymorph a monst
 *		int spnum;
 *
 *	Subroutine to polymorph a monster and ask for the direction its in
 *	Enter with the spell number in spmun.
 *	Returns no value.
 */
dirpoly(spnum)
int spnum;
{
	int x,y,m;
	if (spnum<0 || spnum>=SPNUM) return; /* bad args */
	if (isconfuse()) return;	/* if he is confused, he can't aim his magic */
	dirsub(&x,&y);
	if (mitem[x][y]==0)
	{	
		lprcat("  There wasn't anything there!");	
		return;  
	}
	ifblind(x,y);
	if (nospell(spnum,mitem[x][y])) { 
		lasthx=x;  
		lasthy=y; 
		return; 
	}
	while ( monster[m = mitem[x][y] = rnd(MAXMONST+7)].genocided );
	hitp[x][y] = monster[m].hitpoints;
	show1cell(x,y);  /* show the new monster */
}

/*
 *		Function to hit a monster at the designated coordinates
 *	hitmonster(x,y) 	
 *	int x,y;
 *
 *	This routine is used for a bash & slash type attack on a monster
 *	Enter with the coordinates of the monster in (x,y).
 *	Returns no value.
 */
hitmonster(x,y)
int x,y;
{
	register int tmp,monst,damag,flag;

	if (c[TIMESTOP])  return;  /* not if time stopped */

	vxy(&x,&y);	/* verify coordinates are within range */

	if ((monst = mitem[x][y]) == 0) return;

	hit3flag=1;  
	ifblind(x,y);

tmp = monster[monst].armorclass + c[LEVEL] + c[DEXTERITY] + c[WCLASS/4] -12 
	    - c[HARDGAME];

	cursors();

	/* need at least random chance to hit */
	if ((rnd(20) < tmp) || (rnd(71) < 5)) { 	
		lprcat("\nYou hit");  
		flag=1;
		damag = fullhit(1);  
		if (damag<9999) damag=rnd(damag)+1;
	}
	else { 	
		lprcat("\nYou missed");  
		flag=0;
	}
	lprcat(" the "); 

	lprcat(lastmonst);
	/*	lprintf(" (tmp = %d)", tmp); */

	if (flag)	/* if the monster was hit */
		if (iven[c[WIELD]] != OSWORDofSLASHING)
			if ((monst==RUSTMONSTER) || (monst==DISENCHANTRESS) || (monst==CUBE))
				if (c[WIELD]>0)
					if (ivenarg[c[WIELD]] > -10) {
						lprintf("\nYour weapon is dulled by the %s",lastmonst); 
						beep();
						--ivenarg[c[WIELD]];
					}
	if (flag) {
		hitm(x,y,damag);
		if ((monst >= DEMONLORD) && 
		    (c[LANCEDEATH]) && 
		    (hitp[x][y]) )
			lprintf("\nYour lance of death tickles the %s!",lastmonst);
	}
/*
	if (monst == VAMPIRE) 
		if (hitp[x][y]<25)
		{	mitem[x][y]=LEMMING; 
			know[x][y]=0; 
		}
*/

	if (monst == METAMORPH)
		if (hitp[x][y]<25 && hitp[x][y] > 0)
			mitem[x][y]=BRONZEDRAGON+rund(9);

	if (mitem[x][y]==LEMMING)
		if (rnd(100)<=40) createmonster(LEMMING);
}

/*
 *		Function to just hit a monster at a given coordinates
 *	hitm(x,y,amt)
 *		int x,y,amt;
 *
 *	Returns the number of hitpoints the monster absorbed
 *This routine is used to specifically damage a monster at a location (x,y)
 *	Called by hitmonster(x,y)
 */
hitm(x,y,amt)
int x,y;
register amt;
{
	register int monst;
	int hpoints,amt2;

	vxy(&x,&y);	/* verify coordinates are within range */
	amt2 = amt;	/* save initial damage so we can return it */
	monst = mitem[x][y];

	/* if half damage curse adjust damage points */
	if (c[HALFDAM]) amt >>= 1;	
	if (amt<=0) amt2 = amt = 1;

	lasthx=x;
	lasthy=y;

	/* make sure hitting monst breaks stealth condition */
	stealth[x][y]=1;	
	c[HOLDMONST]=0;	/* hit a monster breaks hold monster spell	*/
	switch(monst) /* if a dragon and orb(s) of dragon slaying	*/
	{
	case WHITEDRAGON:
	case REDDRAGON:
	case GREENDRAGON:
	case BRONZEDRAGON:
	case PLATINUMDRAGON:
	case SILVERDRAGON:
		if (c[SLAYING])
			amt *= 3;
		break;
	}
	/* invincible monster fix is here */
	if (hitp[x][y] > monster[monst].hitpoints)
		hitp[x][y] = monster[monst].hitpoints;

	if (monst >= DEMONLORD) {
		if (c[LANCEDEATH]) 
			amt=300;
		if (iven[c[WIELD]] == OSLAYER)
			amt=10000;
	}

	if ((hpoints = hitp[x][y]) <= amt) {
		lprintf("\nThe %s died!",lastmonst);
		raiseexperience((long)monster[monst].experience);
		amt = monster[monst].gold;  
		if (amt>0) dropgold(rnd(amt)+amt);
		dropsomething(monst);	
		disappear(x,y);	
		bottomline();
		hitp[x][y] = 0;
		return(hpoints);
	}
	hitp[x][y] = hpoints-amt;	
	return(amt2);
}

/*
 *			Function for the monster to hit the player from (x,y)
 *	hitplayer(x,y) 		
 *		int x,y;
 *
 *	Function for the monster to hit the player with monster at location x,y
 *	Returns nothing of value.
 */
hitplayer(x,y)
int x,y;
{
	register int dam,tmp,mster,bias;

	vxy(&x,&y);	/* verify coordinates are within range */

	lastnum = mster = mitem[x][y];

	if ((know[x][y]&1) == 0) {
		know[x][y]=1; 
		show1cell(x,y);
	}

	bias = (c[HARDGAME]) + 1;
	hitflag = hit2flag = hit3flag = 1;
	yrepcount=0;
	cursors();	
	ifblind(x,y);

	if (mster < DEMONLORD)
		if (c[INVISIBILITY]) if (rnd(33)<20) {
			lprintf("\nThe %s misses wildly",lastmonst);	
			return;
		}

	if ( (mster < DEMONLORD) && (mster != PLATINUMDRAGON) ) 
		if (c[CHARMCOUNT]) 
			if (rnd(30)+5*monster[mster].level-c[CHARISMA]<30) {
	lprintf("\nThe %s is awestruck at your magnificence!",lastmonst);
				return;
			}

	if (mster==LEMMING) return;
	else {
		dam = monster[mster].damage;
		dam += rnd( (int) ((dam<1)?1:dam) ) + monster[mster].level;
	}

	/* demon lords/prince/god of hellfire damage is reduced if wielding
			Slayer */
	if (mster >= DEMONLORD)
		if (iven[c[WIELD]]==OSLAYER)
			dam=(int) (1 - (0.1 * rnd(5)) * dam);

	/*	spirit naga's and poltergeist's damage is halved if scarab of 
	  	negate spirit	*/
	if (c[NEGATESPIRIT] || c[SPIRITPRO])  
		if ((mster ==POLTERGEIST) || (mster ==SPIRITNAGA)) 
			dam = (int) dam/2; 

	/*	halved if undead and cube of undead control	*/
	if (c[CUBEofUNDEAD] || c[UNDEADPRO]) 
		if ((mster ==VAMPIRE) || (mster ==WRAITH) || (mster ==ZOMBIE)) 
			dam = (int) dam/2;

	tmp = 0;
	if (monster[mster].attack>0)
		if (((dam + bias + 8) > c[AC]) 
	 	    || (rnd((int)((c[AC]>0)?c[AC]:1))==1)) { 	
			if (spattack(monster[mster].attack,x,y)) { 	
				flushall(); 
				return; 
			}
			tmp = 1;  
			bias -= 2; 
			cursors(); 
		}

	if (((dam + bias) > c[AC]) || (rnd((int)((c[AC]>0)?c[AC]:1))==1)) {
		lprintf("\n  The %s hit you ",lastmonst);	
		tmp = 1;
		if ((dam -= c[AC]) < 0) 
			dam=0;

		if (dam > 0) { 
			losehp(dam); 
			bottomhp(); 
			flushall(); 
		}
	}

	if (tmp == 0)  
		lprintf("\n  The %s missed ",lastmonst);
}

/*
 *	dropsomething(monst) 	Function to create an object when a monster dies
 *		int monst;
 *
 *	Function to create an object near the player when 
 *	certain monsters are killed
 *	Enter with the monster number 
 *	Returns nothing of value.
 */
dropsomething(monst)
int monst;
{
	switch(monst) {
	case ORC:  
	case NYMPH:
	case ELF:
	case TROGLODYTE:
	case TROLL:
	case ROTHE:
	case VIOLETFUNGI:
	case PLATINUMDRAGON:
	case GNOMEKING:
	case REDDRAGON:
		something(level); 
		return;

	case LEPRECHAUN: 
		if (rnd(101)>=75) creategem();
		if (rnd(5)==1) dropsomething(LEPRECHAUN);   
		return;
	case LEMMING:	/* createitem(OGOLDPILE,1); */
		return;
	}
}

/*
 *	dropgold(amount) 	Function to drop some gold around player
 *		int amount;
 *
 *	Enter with the number of gold pieces to drop
 *	Returns nothing of value.
 */
dropgold(amount)
register int amount;
{
	if (amount > 250) createitem(OMAXGOLD, amount);  
	else  createitem(OGOLDPILE,amount);
}

/*
 *	something(level) 	Function to create a random item around player
 *		int level;
 *
 *	Function to create an item from a designed probability around player
 *	Enter with the cave level on which something is to be dropped
 *	Returns nothing of value.
 */
something(lev)
int lev;
{
	register int j;
	int i;

	if (lev<0 || lev>MAXLEVEL+MAXVLEVEL) 
		return;	/* correct level? */
	if (rnd(101)<8) 
		something(lev); /* possibly more than one item */
	j = newobject(lev,&i);		
	createitem(j,i);
}

/*
 *	newobject(lev,i) 	Routine to return a randomly selected new object
 *		int lev,*i;
 *
 *	Routine to return a randomly selected object to be created
 *	Returns the object number created, and sets *i for its argument
 *	Enter with the cave level and a pointer to the items arg
 */
static char nobjtab[] = 
{ 
	0, OSCROLL,  OSCROLL,  OSCROLL,  OSCROLL, OPOTION,
	OPOTION, OPOTION, OPOTION, OGOLDPILE, OGOLDPILE, OGOLDPILE, OGOLDPILE, 
	OBOOK, OBOOK, OBOOK, OBOOK, ODAGGER, ODAGGER, ODAGGER, OLEATHER, OLEATHER,
	OLEATHER, OREGENRING, OPROTRING, OENERGYRING, ODEXRING, OSTRRING, OSPEAR,
	OBELT, ORING, OSTUDLEATHER, OSHIELD, OFLAIL, OCHAIN, O2SWORD, OPLATE,
	OLONGSWORD };

newobject(lev,i)
register int lev,*i;
{
	register int tmp=32,j;

	if (level<0 || level>MAXLEVEL+MAXVLEVEL) 
		return(0);	/* correct level? */

	if (lev>6) tmp=37; 
	else if (lev>4) tmp=35; 

	j = nobjtab[tmp=rnd(tmp)];	/* the object type */
	switch(tmp) {
	case 1: 
	case 2: 
	case 3: 
	case 4:	
		*i=newscroll();	
		break;
	case 5: 
	case 6: 
	case 7: 
	case 8:	
		*i=newpotion();	
		break;
	case 9: 
	case 10: 
	case 11: 
	case 12: 
		*i=rnd((lev+1)*10)+lev*10+10; 
		break;
	case 13: 
	case 14: 
	case 15:
	case 16:
		*i=lev;	
		break;
	case 17: 
	case 18: 
	case 19: 
		if (!(*i=newdagger()))  return(0);  
		break;
	case 20: 
	case 21: 
	case 22: 
		if (!(*i=newleather()))  return(0);  
		break;
	case 23: 
	case 32: 
	case 35: 
		*i=rund(lev/3+1); 
		break;
	case 24: 
	case 26: 
		*i=rnd(lev/4+1);   
		break;
	case 25: 
		*i=rund(lev/4+1); 
		break;
	case 27: 
		*i=rnd(lev/2+1);   
		break;
	case 28: 
		*i=rund(lev/3+1); 
		if (*i==0) return(0); 
		break;
	case 29: 
	case 31: 
		*i=rund(lev/2+1); 
		if (*i==0) return(0); 
		break;
	case 30: 
	case 33: 
		*i=rund(lev/2+1);   
		break;
	case 34: 
		*i=newchain();   	
		break;
	case 36: 
		*i=newplate();   	
		break;
	case 37: 
		*i=newsword();		
		break; 
	}
	return(j);
}

/*
 *			Function to process special attacks from monsters
 *  spattack(atckno,xx,yy) 	
 *  	int atckno,xx,yy;
 *
 *	Enter with the special attack number, and the coordinates (xx,yy)
 *		of the monster that is special attacking
 *	Returns 1 if must do a show1cell(xx,yy) upon return, 0 otherwise
 *
 * atckno   monster     effect
 * ---------------------------------------------------
 *	0	none
 *	1	rust monster		eat armor
 *	2	hell hound		breathe light fire
 *	3	dragon			breathe fire
 *	4	giant centipede		weakening sing
 *	5	white dragon		cold breath
 *	6	wraith			drain level
 *	7	waterlord		water gusher
 *	8	leprechaun		steal gold
 *	9	disenchantress		disenchant weapon or armor
 *	10	ice lizard		hits with barbed tail
 *	11	umber hulk		confusion
 *	12	spirit naga		cast spells taken from special attacks
 *	13	platinum dragon		psionics
 *	14	nymph			steal objects
 *	15	bugbear			bite
 *	16	osequip			bite
 *
 *	char rustarm[ARMORTYPES][2];
 *	special array for maximum rust damage to armor from rustmonster
 *	format is: { armor type , minimum attribute 
 */
#define ARMORTYPES 6

static char rustarm[ARMORTYPES][2] = 
{ 
	OSTUDLEATHER,-2,ORING,-4, OCHAIN,-5, OSPLINT,-6,OPLATE,-8,OPLATEARMOR,-9  };

static char spsel[] = { 
	1, 2, 3, 5, 6, 8, 9, 11, 13, 14 };
spattack(x,xx,yy)
int x,xx,yy;
{
	register int i,j=0,k,m;
	register char *p=0;

	vxy(&xx,&yy);	/* verify x & y coordinates */

	/* cancel only works 5% of time for demon prince
		   and god */
	if (c[CANCELLATION]) 
		if (mitem[xx][yy] >= DEMONPRINCE) {
			if (rnd(100) >= 95) return(0);
		}
		else return(0);

	/* staff of power cancels demonlords/wraiths/vampires 75% of time */
	if (mitem[xx][yy] != LUCIFER) {
		if ( (mitem[xx][yy] >= DEMONLORD) ||
		    (mitem[xx][yy] == WRAITH) ||
		    (mitem[xx][yy] == VAMPIRE) )
			for (i=0;i<26;i++)
				if (iven[i]==OPSTAFF) 
					if (rnd(100)<75)
						return(0);
	}

	/* if have cube of undead control,  wraiths and vampires do nothing */	
	if ( (mitem[xx][yy]==WRAITH) || (mitem[xx][yy]==VAMPIRE) )
		if ( (c[CUBEofUNDEAD]) || (c[UNDEADPRO]) )
			return(0);

	switch(x) {
	case 1:	/* rust your armor, j=1 when rusting has occurred */
		m = k = c[WEAR];
		if ((i=c[SHIELD]) != -1)
			if (--ivenarg[i] < -1) 
				ivenarg[i]= -1; 
			else j=1;
		if ((j==0) && (k != -1)) {
			m = iven[k];
			for (i=0; i<ARMORTYPES; i++)
				if (m == rustarm[i][0]) 
					/* find his armor in table */
				{
					if (--ivenarg[k]< rustarm[i][1])
						ivenarg[k]= rustarm[i][1]; 
					else j=1; 
					break;
				}
		}
		if (j==0)	/* if rusting did not occur */
			switch(m) {
			case OLEATHER:	
				p = "\nThe %s hit you -- You are lucky you have leather on";
				break;
			case OSSPLATE:	
				p = "\nThe %s hit you -- You are fortunate to have stainless steel armor!";
				break;
			case OELVENCHAIN:
				p = "\nThe %s hit you -- You are very lucky to have such strong elven chain!";
				break;
			}
		else  { 
			beep(); 
			p = "\nThe %s hit you -- your armor feels weaker"; 
		}
		break;

	case 2:		
		i = rnd(15)+8-c[AC];
spout:	
		p="\nThe %s breathes fire at you!";
		if (c[FIRERESISTANCE])
			p="\nThe %s's flame doesn't phase you!";
		else
spout2: 
			if (p) { 
				lprintf(p,lastmonst); 
				beep(); 
			}
		checkloss(i);
		return(0);

	case 3:		
		i = rnd(20)+25-c[AC];  
		goto spout;

	case 4:	
		if (c[STRENGTH]>3) {
			p="\nThe %s stung you!  You feel weaker"; 
			beep();
			if (--c[STRENGTH] < 3)
				c[STRENGTH] = 3;
		}
		else p="\nThe %s stung you!";
		break;

	case 5:		
		p="\nThe %s blasts you with his cold breath";
		i = rnd(15)+18-c[AC];  
		goto spout2;

	case 6:		
		lprintf("\nThe %s drains you of your life energy!",lastmonst);
		loselevel();
		if (mitem[xx][yy]==DEMONPRINCE) losemspells(1);
		if (mitem[xx][yy]==LUCIFER) {
			loselevel();
			losemspells(2);
			for (i=0;i<=5;i++) 
				if (c[i]-- < 3) c[i]=3;
		}
		beep();  
		return(0);

	case 7:		
		p="\nThe %s got you with a gusher!";
		i = rnd(15)+25-c[AC];  
		goto spout2;

	case 8:	
		if (c[NOTHEFT]) return(0); 
		/* he has a device of no theft */
		if (c[GOLD]) {
			p="\nThe %s hit you -- Your purse feels lighter";
			if (c[GOLD]>32767)  c[GOLD]>>=1;
			else c[GOLD] -= rnd((int)(1+(c[GOLD]>>1)));
			if (c[GOLD] < 0) c[GOLD]=0;
		}
		else  p="\nThe %s couldn't find any gold to steal";
		lprintf(p,lastmonst); 
		disappear(xx,yy); 
		beep();
		bottomgold();  
		return(1);

	case 9:	
		for(j=50; ; )	/* disenchant */
		{
			i=rund(26);  
			m=iven[i]; /* randomly select item */
			if (m>0 && ivenarg[i]>0 && m!=OSCROLL && m!=OPOTION)
			{
				if ((ivenarg[i] -= 3)<0) ivenarg[i]=0;
				lprintf("\nThe %s hits you with a spell of disenchantment! ",lastmonst);
				srcount=0; 
				beep(); 
				show3(i);  
				bottomline();  
				return(0);
			}
			if (--j<=0) { 	
				p="\nThe %s nearly misses"; 
				break;
			}
			break;
		}		
		break;

	case 10:   
		p="\nThe %s hit you with his barbed tail";
		i = rnd(25)-c[AC];  
		goto spout2;

	case 11:
		p="\nThe %s has confused you"; 
		beep();
		c[CONFUSE]+= 10+rnd(10);		
		break;

	case 12:/*performs any number of other special attacks	*/
		return(spattack(spsel[rund(10)],xx,yy));

	case 13:	
		p="\nThe %s flattens you with his psionics!";
		i = rnd(15)+30-c[AC];  
		goto spout2;

	case 14:	
		if (c[NOTHEFT]) return(0); 
		/* he has device of no theft */
		if (emptyhanded()==1) {
			p="\nThe %s couldn't find anything to steal";
			break;
		}
		lprintf("\nThe %s picks your pocket and takes:",lastmonst);
		beep();
		if (stealsomething()==0) lprcat("  nothing"); 
		disappear(xx,yy);
		bottomline();  
		return(1);

	case 15:
		i= rnd(10)+ 5-c[AC];
spout3:	
		p="\nThe %s bit you!";
		goto spout2;

	case 16:	
		i= rnd(15)+10-c[AC];  
		goto spout3;
	};

	if (p) { 
		lprintf(p,lastmonst); 
		bottomline(); 
	}
	return(0);
}

/*
 *		Routine to subtract hp from user and flag bottomline display
 *	checkloss(x) 	
 *		int x;
 *
 *	Enter with the number of hit points to lose
 *	Note: if x > c[HP] this routine could kill the player!
 */
checkloss(x)
int x;
{
	if (x>0) { 
		losehp(x);  
		bottomhp(); 
	}
}

/*
 *	Routine to annihilate all monsters around player (playerx,playery)
 *	annihilate() 	
 *
 *	Gives player experience, but no dropped objects
 *	Returns the experience gained from all monsters killed
 */
annihilate()
{
	int i,j;
	register long k;
	register char *p;

	for (k=0, i=playerx-1; i<=playerx+1; i++)
		for (j=playery-1; j<=playery+1; j++)
			if (!vxy(&i,&j)) /* if not out of bounds */
				if (*(p= &mitem[i][j]))	/* if a monster there */
					if (*p<DEMONLORD) {
						k += monster[*p].experience;	
						*p=know[i][j]=0;
					}
					else {
						lprintf("\nThe %s barely escapes being annihilated!",monster[*p].name);
						hitp[i][j] = (hitp[i][j]>>1) + 1; 
						/* lose half hit points*/
					}
	if (k>0) {
		lprcat("\nYou hear loud screams of agony!");	
		raiseexperience((long)k);
	}
	return(k);
}

/*
 *		Function to create a new sphere of annihilation
 *	newsphere(x,y,dir,lifetime)  
 *		int x,y,dir,lifetime;
 *
 *	Enter with the coordinates of the sphere in x,y
 *	  the direction (0-8 diroffx format) in dir, and the lifespan of the
 *	  sphere in lifetime (in turns)
 *	Returns the number of spheres currently in existence
 */
newsphere(x,y,dir,life)
int x,y,dir,life;
{
	int m,i;
	struct sphere *sp;

	if (((sp=(struct sphere *)malloc(sizeof(struct sphere)))) == 0)
		return(c[SPHCAST]);	/* can't malloc, therefore failure */
	if (dir>=9) dir=0;	/* no movement if direction not found */
	if (level==0) vxy(&x,&y);	/* don't go out of bounds */
	else {
		if (x<1) x=1;  
		if (x>=MAXX-1) x=MAXX-2;
		if (y<1) y=1;  
		if (y>=MAXY-1) y=MAXY-2;
	}

	for (i=0;i<26;i++) 
		if (iven[i]==OSPHTALISMAN) goto out;

	/* demons dispel spheres */
	if ((m=mitem[x][y]) >= DEMONLORD) {
		i = hitp[x][y];
		know[x][y]=1; 
		show1cell(x,y);	/* show the demon (ha ha) */
		cursors(); 
		lprintf("\nThe %s dispels the sphere!",monster[m].name);
		beep(); 
		rmsphere(x,y);	/* remove any spheres that are here */
		mitem[x][y] = m;
		hitp[x][y] = i;
		know[x][y]=0; 
		return(c[SPHCAST]);
	}

	/* disenchantress cancels spheres */
	if (m==DISENCHANTRESS) {
		cursors(); 
		lprintf("\nThe %s causes cancellation of the sphere!",monster[m].name); 
		beep();

boom:		
		sphboom(x,y);	/* blow up stuff around sphere */
		rmsphere(x,y);	/* remove any spheres that are here */
		return(c[SPHCAST]);
	}

	/* cancellation cancels spheres */
	if (c[CANCELLATION]) {
		cursors();
		lprcat("\nAs the cancellation takes effect, you hear a great earth shaking blast!"); 
		beep();
		goto boom;
	}
	/* collision of sphere and player! */
	if (playerx==x && playery==y) {
		cursors();
		lprcat("\nYou have been enveloped by the zone of nothingness!\n");
		beep(); 
		rmsphere(x,y);	/* remove any spheres that are here */
		nap(4000);  
		died(258);
	}
out:
	/* collision of spheres detonates spheres */
	if (item[x][y]==OANNIHILATION) {
		cursors(); 
		lprcat("\nTwo spheres of annihilation collide! You hear a great earth shaking blast!"); 
		beep();
		rmsphere(x,y);
		goto boom;
	}

	item[x][y]=OANNIHILATION;  
	mitem[x][y]=0;  
	know[x][y]=1;
	show1cell(x,y);	/* show the new sphere */
	sp->x=x;  
	sp->y=y;  
	sp->lev=level;  
	sp->dir=dir;  
	sp->lifetime=life;  
	sp->p=0;
	if (spheres==0) spheres=sp;	/* if first node in the sphere list */
	else	/* add sphere to beginning of linked list */
	{
		sp->p = spheres;	
		spheres = sp;
	}
	return(++c[SPHCAST]);	/* one more sphere in the world */
}

/*
 *	rmsphere(x,y)	Function to delete a sphere of annihilation from list
 *		int x,y;
 *
 *	Enter with the coordinates of the sphere (on current level)
 *	Returns the number of spheres currently in existence
 */
rmsphere(x,y)
int x,y;
{
	register struct sphere *sp,*sp2=0;

	for (sp=spheres; sp; sp2=sp,sp=sp->p)
		if (level==sp->lev)	/* is sphere on this level? */
			if ((x==sp->x) && (y==sp->y))	
				/* locate sphere at this location */
			{
				item[x][y]= mitem[x][y]= 0;  
				know[x][y]=1;
				show1cell(x,y);	/* show the now missing sphere */
				--c[SPHCAST];	
				if (sp==spheres) { 
					sp2=sp; 
					spheres=sp->p; 
					free((char*)sp2); 
				}
				else
				{ 
					sp2->p = sp->p;  
					free((char*)sp); 
				}
				break;
			}
	return(c[SPHCAST]);	/* return number of spheres in the world */
}

/*
 *	sphboom(x,y)	Function to perform the effects of a sphere detonation
 *		int x,y;
 *
 *	Enter with the coordinates of the blast, Returns no value
 */
sphboom(x,y)
int x,y;
{
	register int i,j,k;

	if (c[HOLDMONST]) c[HOLDMONST]=1;
	if (c[CANCELLATION]) c[CANCELLATION]=1;
	for (j=max(1,x-2); j<min(x+3,MAXX-1); j++)
		for (i=max(1,y-2); i<min(y+3,MAXY-1); i++)
		{
			item[j][i]=mitem[j][i]=0;
			show1cell(j,i);
			for (k=0;k<26;k++) if (iven[k]==OSPHTALISMAN) return;
			if (playerx==j && playery==i)
			{
				cursors(); 
				beep();
				lprcat("\nYou were too close to the sphere!");
				nap(3000);
				died(283); /* player killed in explosion */
			}
		}
}

/*
 *		Function to ask for monster and genocide from game
 *	genmonst()		
 *
 *	This is done by setting a flag in the monster[] structure
 */
genmonst()
{
	register int i,j;
	cursors();  
	lprcat("\nGenocide what monster? ");
	for (i=0; (!isalpha(i)) && (i!=' '); i=getcharacter());
	lprc(i);
	for (j=0; j<MAXMONST; j++)	/* search for the monster type */
		if (monstnamelist[j]==i)	/* have we found it? */
			if (monster[j].genocided==0) {
				monster[j].genocided=1;	/* genocided from game */
				lprintf("  There will be no more %s's",monster[j].name);
				/* now wipe out monsters on this level */
				newcavelevel(level); 
				draws(0,MAXX,0,MAXY); 
				bot_linex();
				return;
			}
	lprcat("  You sense failure!");
}