/*	monster.c		*/
#include "header.h"
static char copyright[]="Larn is copyrighted 1986 by Noah Morgan.\n";

extern struct monst monster[];
extern int c[],srcount,yrepcount;
extern short playerx,playery,hitflag,hit2flag,hitp[MAXX][MAXY];
extern short lasthx,lasthy,lastnum;
extern char mitem[MAXX][MAXY],iarg[MAXX][MAXY],level,wizard;
extern char item[MAXX][MAXY],know[MAXX][MAXY];
extern char iven[],ivenarg[],spelknow[],stealth[MAXX][MAXY];
extern char *spelcode[],*spelname[],spelwierd[MAXMONST+8][SPNUM],*spelmes[];
extern char lastmonst[];	/*	the name of the monster presently fighting	*/
extern char diroffx[],diroffy[];
struct isave
	{
	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 around the player
 */
createmonster(mon)
	int mon;
	{
	register int i,j;
#ifdef EEXTRA
	if (mon<1 || mon>MAXMONST+8)	{ lprintf("\n\7can't createmonst(%d)\n",mon); nap(3000); return; }
#endif
	for (j=playery-1; j<=playery+1; j++)
		for (i=playerx-1; i<=playerx+1; i++)
			{
			if ((i != playerx) || (j != playery))
			  {
			  if (item[i][j]!=OWALL) if (mitem[i][j]==0) if (j<MAXY-1)
				{
				mitem[i][j] = mon;
				hitp[i][j] = monster[mon].hitpoints;
				know[i][j]=0;
				switch(mon) {
					case ROTHE:  case POLTERGEIST:  case VAMPIRE: stealth[i][j]=1; return;
					default:  stealth[i][j]=0; return;
					};
				}
			  }
			}
	}

createitem(it,arg)
	int it,arg;
	{
	register int i,j;
	for (i=playerx-1; i<=playerx+1; i++)
		for (j=playery-1; j<=playery+1; j++)
			if (item[i][j]==0) if ((i!=playerx) || (j!=playery))
				{
				item[i][j] = it;	know[i][j]=0; iarg[i][j]=arg;	return;
				}
	}

/*
	subroutine called by parse to case a spell for the user
 */
cast()
	{
	register int i,j;
	int a,b,d;
	cursor(1,21);
	if (c[SPELLS]<=0)
		{	lprcat("\nYou don't have any spells!");	return;	}
	lprcat("\nEnter your spell: ");		--c[SPELLS];
	a=getchar(); while (a=='D') { seemagic(-1); cursor(1,21);  lprcat("\nEnter your spell: "); a=getchar(); }
	if (a=='\33') { lprcat(" aborted"); c[SPELLS]++; return; }	/*	to escape casting a spell	*/
	if ((b=getchar())=='\33') { lprcat(" aborted"); c[SPELLS]++; return; } /*	to escape casting a spell	*/
	if ((d=getchar())=='\33') { lprcat(" aborted"); c[SPELLS]++; return; } /*	to escape casting a spell	*/
#ifdef EXTRA
	c[SPELLSCAST]++;
#endif
	lprc('\n');	j = -1;
	for (i=0; i<SPNUM; i++)
		{
		if (spelcode[i][0]==a) if (spelcode[i][1]==b) if (spelcode[i][2]==d) if (spelknow[i])
			{  speldamage(i);  j = 1;  i=SPNUM; }
		}
	if (j == -1)	lprcat("  Nothing Happened\n");
	bottomline();
	}


/*
	function to calculate damage due to spells
	returns the hit points of damage done to the monster
	2 spaces before all messages here
 */
static int xl,xh,yl,yh,clev;
speldamage(x)
	int x;
	{
	register int i,j;
	if (c[TIMESTOP])  { lprcat("  It didn't seem to work"); return; }  /* not if time stopped */
	clev = c[LEVEL];
	if ((rnd(23)==7) || (rnd(18) > c[INTELLIGENCE]))
		{ lprcat("  It didn't work!");  return; }
	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>0)?(clev<<1):1) + clev + clev + 3;
				if (clev>=2)	godirect(x,i,"  Your missiles hit the %s",100,'+'); /* magic missile */
				else	godirect(x,i,"  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;
				direct(x,(c[LANCEDEATH])?99999:fullhit(i),"  While the %s slept, you smashed it %d times",i);
				/*	sleep	*/	return;

		case 4:	/*	charm monster	*/	c[CHARMCOUNT] += c[CHARISMA]<<1;	return;

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

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

		case 6: i=rnd(3)+2;	direct(x,(c[LANCEDEATH])?99999:fullhit(i),"  While the %s is entangled, you hit %d times",i);
				return;

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

		case 8:	if ((yl = playery-5) < 0) yl=0;
				if ((yh = playery+6) > MAXY) yh=MAXY;
				if ((xl = playerx-15) < 0) xl=0;
				if ((xh = playerx+16) > MAXX) xh=MAXX;
				for (i=yl; i<yh; i++) /* enlightenment	*/
					for (j=xl; j<xh; j++)	know[j][i]=1;
				draws(xl,xh,yl,yh);	return;

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

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

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

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

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

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

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

						  case OSTATUE: if (c[HARDGAME]<3)
											 { item[i][j]=OBOOK; iarg[i][j]=level; know[i][j]=0; }
										break;
	
						  case OTHRONE: mitem[i][j]=GNOMEKING; know[i][j]=0; 
										hitp[i][j]=1000; break;

						  case OALTAR:	mitem[i][j]=DEMONPRINCE; know[i][j]=0;
										hitp[i][j]=1200; break;
						  };
					return;

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

		case 21:	direct(x,100+clev,"  The %s shrivels up"); /* dehydration */
					return;

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

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

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

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

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

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

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

		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 */

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

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

		case 32:	if (rnd(19)==5)	/* sphere of annialation */
						{
						lprcat("\n\7You have been enveloped by the zone of nothingness!\n");
						nap(4000);  died(258);
						}
					c[SPHCAST]++;	xl=playerx; yl=playery;
					dirsub(&xl,&yl);
					for (i=0; i<9; i++) /* translate new location into direction number */
						if ((xl==playerx+diroffx[i])&&(yl==playery+diroffy[i]))
							break;
					if (i>=9) i=0;	/* no movement if direction not found */
					if (xl<1) xl=1;  if (xl>=MAXX-1) xl=MAXX-2;
					if (yl<1) yl=1;  if (yl>=MAXY-1) yl=MAXY-2;
					item[xl][yl]=OANNIALATION;  mitem[xl][yl]=0;
					know[xl][yl]=1; show1cell(xl,yl);
					iarg[xl][yl]= (--i<<5) + rnd(20) + 11;
					if (c[INTELLIGENCE]>3)  c[INTELLIGENCE]--;
					return;

		case 33:	/* genocide */
					lprcat("Nothing seems to have happened."); break;

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

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

		case 36:	/* 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++)
						for (i=0; i<MAXX; i++) /* save all items and monsters */
							{
							if (item[i][j] && item[i][j]!=OWALL) 
								{
								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; }
							}
						}
					if (c[INTELLIGENCE]>3)  c[INTELLIGENCE]--;
					draws(0,MAXX,0,MAXY);  if (wizard==0) spelknow[36]=0;
					free(save);	 positionplayer();  return;
					}

		case 37:	/* permanence */ adjtime(-999999);  spelknow[37]=0; /* forget */
					if (c[INTELLIGENCE]>3)  c[INTELLIGENCE]--;
					return;

		default:	lprintf("  spell %d not available!\7",x);
		};
	}

/*
	routine to check to see if player is confused
	returns 0 if not confused, non-zero if confused
 */
isconfuse()
	{
	if (c[CONFUSE]) lprcat(" You can't aim your magic!\7");
	return(c[CONFUSE]);
	}

/*
	subroutine to return 1 if the spell can't affect the monster
	otherwise returns 0
 */
nospell(x,monst)
	int x,monst;
	{
	register int tmp;
	if ((tmp=spelwierd[monst-1][x])==0) return(0);
	cursor(1,21);  lprc('\n');  lprintf(spelmes[tmp],monster[monst].name);  return(1);
	}

/*
	function to return hp damage to monster due to a number of full hits
 */
fullhit(xx)
	int xx;
	{
	register int i;
	i = (c[WCLASS]>>1)+c[STRENGTH]-c[HARDGAME]; 
	return( (i>1) ? i : 2 );
	}

/*
	routine to ask for a direction to a spell and then hit the monster
 */
direct(spnum,dam,str,arg)
	int spnum,dam,arg;
	char *str;
	{
	int x,y;
	if (isconfuse()) return;
	dirsub(&x,&y);
	if (item[x][y]==OMIRROR)
		{ lastnum=278;   lprintf(str,"spell caster (thats you)\7",arg); loosehp(dam);  return; }
	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; }
	lprintf(str,lastmonst,arg);       hitm(x,y,dam);
	}

/*
	function to hit in a direction from a missile weapon and have it keep
	on going in that direction until its power is exhausted
 */
godirect(spnum,dam,str,delay,cshow)
	int spnum,dam,delay;
	char *str,cshow;
	{
	int x,y,dx,dy,m;
	if (isconfuse()) return;
	dirsub(&x,&y);
	dx = x-playerx;		dy = y-playery;		x = playerx;	y = playery;
	while (dam>0)
		{
		x += dx;    y += dy;
		if ((x==playerx) && (y==playery))
			{
			cursor(1,21); lprcat("\nYou are hit my your own magic!\7");
			lastnum=278;  loosehp(dam);  return;
			}
		if (c[BLINDCOUNT]==0)
			{
			cursor(x+1,y+1); lprc(cshow); nap(delay); show1cell(x,y);
			}
		if ((m=mitem[x][y]))
			{
			ifblind(x,y);
			if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
			cursor(1,21); lprc('\n');  lprintf(str,lastmonst);		dam -= hitm(x,y,dam);
			show1cell(x,y);  nap(1000);		x -= dx;	y -= dy;
			}
		else switch (item[x][y])
			{
			case OWALL:	cursor(1,21); lprc('\n'); lprintf(str,"wall");
						if (dam>=50+c[HARDGAME]) if (level<MAXLEVEL+MAXVLEVEL-1)
						  if (x<MAXX-1) if (y<MAXY-1) if (x) if (y)
							{
							lprcat("  The wall crumbles");
							item[x][y]=0;  know[x][y]=0;
							show1cell(x,y);
							}
						dam = 0;	break;

			case OCLOSEDDOOR:	cursor(1,21); lprc('\n'); lprintf(str,"door");
						if (dam>=40) if (x<MAXX-1) if (y<MAXY-1) if (x) if (y)
							{
							lprcat("  The door is blasted apart");
							item[x][y] = know[x][y]=0;
							show1cell(x,y);
							}
						dam = 0;	break;

			case OSTATUE:	cursor(1,21); lprc('\n'); lprintf(str,"statue");
						if (c[HARDGAME]<3)
						  if (dam>44) if (x<MAXX-1) if (y<MAXY-1) if (x) if (y)
							{
							lprcat("  The statue crumbles");
							item[x][y]=OBOOK;  know[x][y]=0;
							iarg[x][y]=level;
							show1cell(x,y);
							}
						dam = 0;	break;

			case OTHRONE:	cursor(1,21); lprc('\n'); lprintf(str,"throne");
					if (dam>39) if (x<MAXX-1) if (y<MAXY-1) if (x) if (y)
						{
						mitem[x][y]=GNOMEKING; hitp[x][y]=1000;
						know[x][y]=0; 
						}
						dam = 0;	break;

			case OMIRROR:	dx *= -1;	dy *= -1;	break;
			};

		if (c[HARDGAME]<2)  dam -= 3;  else if (c[HARDGAME]<5) dam -= 4;  else dam -= 5;
		}
	}

/*
	subroutine to copy the word "monster" into lastmonst if the player is blind
 */
ifblind(x,y)
	int x,y;
	{
	if (c[BLINDCOUNT]) { lastnum=279;  strcpy(lastmonst,"monster"); }
		else { lastnum=mitem[x][y];  strcpy(lastmonst,monster[mitem[x][y]].name); }
	}

/*
	routine to ask for a direction to a spell and then teleport away monster
 */
tdirect(spnum)
	int spnum;
	{
	int x,y;
	if (isconfuse()) return;
	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; }
	fillmonst(mitem[x][y]);  mitem[x][y]=0;
	know[x][y]=0;
	}

/*
	routine to cast a spell and then hit the monster in all directions
 */
omnidirect(spnum,dam,str)
	int spnum,dam;
	char *str;
	{
	register int x,y;
	for (x=playerx-1; x<playerx+2; x++)
		for (y=playery-1; y<playery+2; y++)
			{
			if (mitem[x][y])
				if (nospell(spnum,mitem[x][y]) == 0)
					{
					ifblind(x,y);
					cursor(1,21); lprc('\n'); lprintf(str,lastmonst);
					hitm(x,y,dam);  nap(800);
					}
				else  { lasthx=x;  lasthy=y; }
			}
	}

dirsub(x,y)
	int *x,*y;
	{
	int i;
	lprcat("\nIn What Direction? ");
	while (i=getchar())
		switch(i)
			{
			case 'h':	*x = playerx-1;		*y = playery;	return;
			case 'j':	*x = playerx;		*y = playery+1;	return;
			case 'k':	*x = playerx;		*y = playery-1;	return;
			case 'l':	*x = playerx+1;		*y = playery;	return;
			case 'y':	*x = playerx-1;		*y = playery-1;	return;
			case 'u':	*x = playerx+1;		*y = playery-1;	return;
			case 'b':	*x = playerx-1;		*y = playery+1;	return;
			case 'n':	*x = playerx+1;		*y = playery+1;	return;
			};
	}

/*
	subroutine to polymorph a monster and ask for the direction its in
 */
dirpoly(spnum)
	int spnum;
	{
	int x,y;
	if (isconfuse()) return;
	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; }
	mitem[x][y] = rnd(MAXMONST+7);
	hitp[x][y] = monster[mitem[x][y]].hitpoints;
	show1cell(x,y);  /* show the new monster */
	}


/*
	hitmonster(x,y)
		int x,y;

	function to hit the monster at the designated coordinates
 */
hitmonster(x,y)
	int x,y;
	{
	register int tmp,monst,damag,flag;
	if (c[TIMESTOP])  return;  /* not if time stopped */
	monst = mitem[x][y];
	ifblind(x,y);
	tmp = monster[monst].armorclass + c[LEVEL] + c[DEXTERITY] + c[WCLASS]/4 - 12;
	cursor(1,21);
	if ((rnd(20) < tmp-c[HARDGAME]) || (rnd(71) < 5)) /* need at least random chance to hit */
		{
		lprcat("\nYou hit");  flag=1;
		damag = rnd(8)+(c[WCLASS]>>1)+c[STRENGTH]-c[HARDGAME]-12; 
		if (damag <= 0)  damag=1;
		}
	else
		{
		lprcat("\nYou missed");  flag=0;
		}
	lprcat(" the "); lprcat(lastmonst);
	if (flag)	/* if the monster was hit */
	  if ((monst==RUSTMONSTER) || (monst==DISENCHANTRESS) || (monst==CUBE))
		if (c[WIELD]>0)
		  if (ivenarg[c[WIELD]] > -10)
			{
			lprintf("\n\7Your weapon is dulled by the %s",lastmonst);
			--ivenarg[c[WIELD]];
			}
	if (c[LANCEDEATH] && flag) damag=10000;
	if (flag)  hitm(x,y,damag);
	if (monst == VAMPIRE) if (hitp[x][y]<25)  { mitem[x][y]=BAT; know[x][y]=0; }
	}

/*
	function to just hit a monster at a given coordinates
	returns the number of hitpoints the monster absorbed
 */
hitm(x,y,amt)
	register int x,y,amt;
	{
	register int i;
	int hpoints,amt2;
	amt2 = amt;		/* save initial damage so we can return it */
	if (c[HALFDAM]) amt >>= 1;	/* if half damage curse adjust damage points */
	if (amt<=0) amt2 = amt = 1;
	lasthx=x;  lasthy=y;
	stealth[x][y]=1;	/* make sure hitting monst breaks stealth condition */
	c[HOLDMONST]=0;	/* hit a monster breaks hold monster spell	*/
	switch(i=mitem[x][y]) /* if a dragon and orb(s) of dragon slaying	*/
		{
		case WHITEDRAGON:		case REDDRAGON:			case GREENDRAGON:
		case BRONZEDRAGON:		case PLATINUMDRAGON:	case SILVERDRAGON:
			amt *= 1+(c[SLAYING]<<1);	break;
		}
/* invinceable monster fix is here */
	if (hitp[x][y] > monster[i].hitpoints) hitp[x][y] = monster[i].hitpoints;
	if ((hpoints = hitp[x][y]) <= amt)
		{
#ifdef EXTRA
		c[MONSTKILLED]++;
#endif
		lprintf("\nThe %s died!",lastmonst);
		raiseexperience(monster[mitem[x][y]].experience);
		amt = monster[mitem[x][y]].gold;  if (amt>0) dropgold(rnd(amt)+amt);
		dropsomething(mitem[x][y]);	dissappear(x,y);	bottomline();
		return(hpoints);
		}
	hitp[x][y] = hpoints-amt;	return(amt2);
	}

/*
	hitplayer(x,y)
		int x,y;

	function for the monster to hit the player with monster at location x,y
 */
hitplayer(x,y)
	int x,y;
	{
	int tmp,mster,dam,bias;
	lastnum = mster = mitem[x][y];
/*	spirit naga's and poltergeist's do nothing if scarab of negate spirit	*/
	if (c[NEGATESPIRIT] || c[SPIRITPRO])  if ((mster ==POLTERGEIST) || (mster ==SPIRITNAGA))  return;
/*	if undead and cube of undead control	*/
	if (c[CUBEofUNDEAD] || c[UNDEADPRO]) if ((mster ==VAMPIRE) || (mster ==WRAITH) || (mster ==ZOMBIE)) return;
	if ((know[x][y]&1) == 0)
		{
		know[x][y]=1; show1cell(x,y);
		}
	bias = (c[HARDGAME]>>1) + 1;	hitflag = hit2flag = 1;  yrepcount=0;
	cursor(1,21);	ifblind(x,y);
	if (c[INVISIBILITY]) if (rnd(33)<20) 
		{
		lprintf("\nThe %s misses wildly",lastmonst);	return;
		}
	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==BAT) dam=1;
	else
		{
		dam = monster[mster].damage;
		dam += rnd((dam<1)?1:dam) + monster[mster].level;
		}
	tmp = 0;
	if (monster[mster].attack>0)
	  if (((dam + bias + 8) > c[AC]) || (rnd(c[AC]?c[AC]:1)==1))
		{ if (spattack(monster[mster].attack,x,y)) return;
		  tmp = 1;  bias -= 5; cursor(1,21); }
	if (((dam + bias) > c[AC]) || (rnd(c[AC]?c[AC]:1)==1))
		{
		lprintf("\n  The %s hit you ",lastmonst);	tmp = 1;
		if ((dam -= c[AC]) < 0) dam=0;
		if (dam > 0) { loosehp(dam); bottomhp(); }
		}
	if (tmp == 0)  lprintf("\n  The %s missed ",lastmonst);
	}

/*
	function to create an object when certain monsters are killed
 */
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;
		}
	}

/*
	function to drop some gold
 */
dropgold(amount)
	int amount;
	{
	if (amount > 250) createitem(OMAXGOLD,amount/100);  else  createitem(OGOLDPILE,amount);
	}

/*
	function to create an item from a designed probability
 */
something(level)
	int level;
	{
	register int j,tmp;
	int i;
	if (rnd(101)<8) something(level); /* possible more than one item */
	j = newobject(level,&i);		createitem(j,i);
	}

/*
 *	routine to return a randomly selected object to be created
 */
newobject(level,i)
	int level,*i;
	{
	register int tmp,j;
	if (level>6) tmp=rnd(37); else if (level>4) tmp=rnd(35); else tmp=rnd(32);
	switch(tmp)
		{
		case 1: case 2: case 3:
		case 4:	j=OSCROLL;	*i=newscroll();	break;
		case 5: case 6: case 7:
		case 8:	j=OPOTION;	*i=newpotion();	break;
		case 9: case 10: case 11:
		case 12:	j=OGOLDPILE; *i=rnd((level+1)*10)+level*10+10;	break;
		case 13: case 14: case 15:
		case 16:	j=OBOOK;	*i=level;	break;
		case 17: case 18:
		case 19: j=ODAGGER;  if ((*i=newdagger()) == 0)  return(0);  break;
		case 20: case 21:
		case 22: j=OLEATHER;    *i=newleather(); if (*i==0) return(0);  break;
		case 23: j=OREGENRING;  *i=rund(level/3+1); break;
		case 24: j=OPROTRING;   *i=rnd(level/4+1);   break;
		case 25: j=OENERGYRING; *i=rund(level/4+1); break;
		case 26: j=ODEXRING;    *i=rnd(level/4+1);   break;
		case 27: j=OSTRRING;    *i=rnd(level/2+1);   break;
		case 28: j=OSPEAR;		*i=rund(level/3+1); if (*i==0) return(0); break;
		case 29: j=OBELT;       *i=rund(level/2+1); if (*i==0) return(0); break;
		case 30: j=ORING;		*i=rund(level/2+1); break;
		case 31: j=OSTUDLEATHER; *i=rund(level/2+1); if (*i==0) return(0); break;
		case 32: j=OSHIELD;		*i=rund(level/3+1); break;
		case 33: j=OFLAIL;		*i=rund(level/2+1); break;
		case 34: j=OCHAIN;   	*i=newchain();   	break;
		case 35: j=O2SWORD;		*i=rund(level/3+1); break;
		case 36: j=OPLATE;   	*i=newplate();   	break;
		case 37: j=OLONGSWORD; 	*i=newsword();  		break; 
		}
	return(j);
	}

/*
	function for special attacks from monsters

	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
 */
/* special array for maximum rust damage to armor from rustmonster	*/
static char rustarm[6][2] = { OSTUDLEATHER,-2,	ORING,-4,
	OCHAIN,-5,		OSPLINT,-6,		OPLATE,-8,		OPLATEARMOR,-9  };
spattack(x,xx,yy)
	int x,xx,yy;
	{
	register int i,j;
	if ((x==0) || (c[CANCELLATION])) return(0);
	switch(x)
		{
		case 1:	if ((c[WEAR]== -1) && (c[SHIELD]== -1)) return(0); /* not wearing anything */
				j=0; /* j=1 when rusting has occurred */
				if (c[SHIELD] != -1)
					{ j=1; if (--ivenarg[c[SHIELD]] < -1) { ivenarg[c[SHIELD]] = -1; j=0; } } 
				if (j==0) for (i=0; i<6; i++)
					if (iven[c[WEAR]] == rustarm[i][0])
						{
						j=1; if (--ivenarg[c[WEAR]]< rustarm[i][1]) { ivenarg[c[WEAR]]= rustarm[i][1]; j=0; } i=8;
						}
				if (j==0)
				  {
				  if (iven[c[WEAR]]==OLEATHER)
					{ lprintf("\n\7The %s hit you -- Your lucky you have leather on",lastmonst); }
				  if (j==0 && iven[c[WEAR]]==OSSPLATE)
					{ lprintf("\n\7The %s hit you -- Your lucky your armor is stainless steel!",lastmonst); }
				  }
				else {  lprintf("\n\7The %s hit you -- your armor feels weaker",lastmonst); bottomline(); }
				return;

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

		case 3:		lprintf("\n\7The %s breathes fire at you!",lastmonst);
					if (c[FIRERESISTANCE]) { lprintf("\nThe %s's flame doesn't phase you!",lastmonst); return(0); }
					i = rnd(20)+25-c[AC];  checkloss(i); return(0);

		case 4:		if (c[STRENGTH]>3) lprintf("\n\7The %s stung you!  You feel weaker",lastmonst);
					if (--c[STRENGTH] < 3)  c[STRENGTH]=3; bottomline(); return(0);

		case 5:		lprintf("\n\7The %s blasts you with his cold breath",lastmonst);
					i = rnd(15)+18-c[AC];  checkloss(i); return(0);

		case 6:		lprintf("\n\7The %s drains you of your life energy!",lastmonst);
					looselevel();		return(0);

		case 7:		lprintf("\n\7The %s got you with a gusher!",lastmonst);
					i = rnd(15)+25-c[AC];  checkloss(i); return(0);

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

		case 9:		j=100; while(1)
					{
					i=rund(26);  if (iven[i]>0 && ivenarg[i]>0 && iven[i]!=OSCROLL && iven[i]!=OPOTION)
						{ if ((ivenarg[i] -= 3)<0) ivenarg[i]=0;
						  lprintf("\n\7The %s hits you -- you feel a sense of loss",lastmonst);
						  srcount=0;  show3(i);  bottomline();  return(0);
						}
					if (--j<=0) { lprintf("\nThe %s nearly misses",lastmonst); return(0); }
					}		

		case 10:	lprintf("\n\7The %s hit you with his barbed tail",lastmonst);
					i = rnd(25)-c[AC];  checkloss(i); return(0);

		case 11:	lprintf("\n\7The %s has confused you",lastmonst);
					c[CONFUSE]+= 10+rnd(10);		return(0);

		case 12:	switch(rnd(10))		/*	performs any number of other special attacks	*/
					{
					case 1:	return(spattack(1,xx,yy));
					case 2:	return(spattack(2,xx,yy));
					case 3:	return(spattack(3,xx,yy));
					case 4:	return(spattack(5,xx,yy));
					case 5:	return(spattack(6,xx,yy));
					case 6:	return(spattack(8,xx,yy));
					case 7:	return(spattack(9,xx,yy));
					case 8:	return(spattack(11,xx,yy));
					case 9: return(spattack(13,xx,yy));
					case 10: return(spattack(14,xx,yy));
					}

		case 13:	lprintf("\n\7The %s flattens you with his psionics!",lastmonst);
					i = rnd(15)+30-c[AC];  checkloss(i); return(0);

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

		case 15:	lprintf("\n\7The %s bit you!",lastmonst);
					i = rnd(10)+5-c[AC];  checkloss(i); return(0);

		case 16:	lprintf("\n\7The %s bit you!",lastmonst);
					i = rnd(15)+10-c[AC];  checkloss(i); return(0);
		};
	}

/*
	routine to subtract hitpoints from the user and flag the bottomline display
 */
checkloss(x)
	int x;
	{
	if (x>0) { loosehp(x);  bottomhp(); }
	}

/*
 *	routine to annialate all monsters around player
 */
annialate()
	{
	register int i,j,k;
	int p;
	for (k=0, i=playerx-1; i<=playerx+1; i++)
		for (j=playery-1; j<=playery+1; j++)
			{
			if (p=mitem[i][j])
				{
				if (p<DEMONLORD+2)
					{
					k += monster[p].experience;
					mitem[i][j]=0;	know[i][j]=0;
					}
				else
					{
					lprintf("\nThe %s barely escapes being annialated!",monster[p].name);
					hitp[i][j] = (hitp[i][j]>>1) + 1; /* loose half hit points*/
					}
				}
			}
	if (k>0)
		{
		lprcat("\nYou hear loud screams of agony!");
		raiseexperience(k);
		}
	return(k);
	}

