Home | History | Annotate | Line # | Download | only in larn
monster.c revision 1.4
      1 #ifndef lint
      2 static char rcsid[] = "$NetBSD: monster.c,v 1.4 1995/04/24 12:24:05 cgd Exp $";
      3 #endif /* not lint */
      4 
      5 /*
      6  *	monster.c		Larn is copyrighted 1986 by Noah Morgan.
      7  *
      8  *	This file contains the following functions:
      9  *	----------------------------------------------------------------------------
     10  *
     11  *	createmonster(monstno) 		Function to create a monster next to the player
     12  *		int monstno;
     13  *
     14  *	int cgood(x,y,itm,monst)	Function to check location for emptiness
     15  *		int x,y,itm,monst;
     16  *
     17  *	createitem(it,arg) 			Routine to place an item next to the player
     18  *		int it,arg;
     19  *
     20  *	cast() 				Subroutine called by parse to cast a spell for the user
     21  *
     22  *	speldamage(x) 		Function to perform spell functions cast by the player
     23  *		int x;
     24  *
     25  *	loseint()			Routine to decrement your int (intelligence) if > 3
     26  *
     27  *	isconfuse() 		Routine to check to see if player is confused
     28  *
     29  *	nospell(x,monst)	Routine to return 1 if a spell doesn't affect a monster
     30  *		int x,monst;
     31  *
     32  *	fullhit(xx)			Function to return full damage against a monst (aka web)
     33  *		int xx;
     34  *
     35  *	direct(spnum,dam,str,arg)	Routine to direct spell damage 1 square in 1 dir
     36  *		int spnum,dam,arg;
     37  *		char *str;
     38  *
     39  *	godirect(spnum,dam,str,delay,cshow)		Function to perform missile attacks
     40  *		int spnum,dam,delay;
     41  *		char *str,cshow;
     42  *
     43  *	ifblind(x,y)	Routine to put "monster" or the monster name into lastmosnt
     44  *		int x,y;
     45  *
     46  *	tdirect(spnum)			Routine to teleport away a monster
     47  *		int spnum;
     48  *
     49  *	omnidirect(sp,dam,str)  Routine to damage all monsters 1 square from player
     50  *		int sp,dam;
     51  *		char *str;
     52  *
     53  *	dirsub(x,y)			Routine to ask for direction, then modify x,y for it
     54  *		int *x,*y;
     55  *
     56  *	vxy(x,y)		  	Routine to verify/fix (*x,*y) for being within bounds
     57  *		int *x,*y;
     58  *
     59  *	dirpoly(spnum)		Routine to ask for a direction and polymorph a monst
     60  *		int spnum;
     61  *
     62  *	hitmonster(x,y) 	Function to hit a monster at the designated coordinates
     63  *		int x,y;
     64  *
     65  *	hitm(x,y,amt)		Function to just hit a monster at a given coordinates
     66  *		int x,y,amt;
     67  *
     68  *	hitplayer(x,y) 		Function for the monster to hit the player from (x,y)
     69  *		int x,y;
     70  *
     71  *	dropsomething(monst) 	Function to create an object when a monster dies
     72  *		int monst;
     73  *
     74  *	dropgold(amount) 		Function to drop some gold around player
     75  *		int amount;
     76  *
     77  *	something(level) 		Function to create a random item around player
     78  *		int level;
     79  *
     80  *	newobject(lev,i) 		Routine to return a randomly selected new object
     81  *		int lev,*i;
     82  *
     83  *  spattack(atckno,xx,yy) 	Function to process special attacks from monsters
     84  *  	int atckno,xx,yy;
     85  *
     86  *	checkloss(x) 	Routine to subtract hp from user and flag bottomline display
     87  *		int x;
     88  *
     89  *	annihilate()   Routine to annihilate monsters around player, playerx,playery
     90  *
     91  *	newsphere(x,y,dir,lifetime)  Function to create a new sphere of annihilation
     92  *		int x,y,dir,lifetime;
     93  *
     94  *	rmsphere(x,y)		Function to delete a sphere of annihilation from list
     95  *		int x,y;
     96  *
     97  *	sphboom(x,y)		Function to perform the effects of a sphere detonation
     98  *		int x,y;
     99  *
    100  *	genmonst()			Function to ask for monster and genocide from game
    101  *
    102  */
    103 #include "header.h"
    104 #include <string.h>
    105 
    106 struct isave	/* used for altar reality */
    107 	{
    108 	char type;	/* 0=item,  1=monster */
    109 	char id;	/* item number or monster number */
    110 	short arg;	/* the type of item or hitpoints of monster */
    111 	};
    112 
    113 /*
    114  *	createmonster(monstno) 		Function to create a monster next to the player
    115  *		int monstno;
    116  *
    117  *	Enter with the monster number (1 to MAXMONST+8)
    118  *	Returns no value.
    119  */
    120 createmonster(mon)
    121 	int mon;
    122 	{
    123 	register int x,y,k,i;
    124 	if (mon<1 || mon>MAXMONST+8)	/* check for monster number out of bounds */
    125 		{
    126 		beep(); lprintf("\ncan't createmonst(%d)\n",(long)mon); nap(3000); return;
    127 		}
    128 	while (monster[mon].genocided && mon<MAXMONST) mon++; /* genocided? */
    129 	for (k=rnd(8), i= -8; i<0; i++,k++)	/* choose direction, then try all */
    130 		{
    131 		if (k>8) k=1;	/* wraparound the diroff arrays */
    132 		x = playerx + diroffx[k];		y = playery + diroffy[k];
    133 		if (cgood(x,y,0,1))	/* if we can create here */
    134 			{
    135 			mitem[x][y] = mon;
    136 			hitp[x][y] = monster[mon].hitpoints;
    137 			stealth[x][y]=know[x][y]=0;
    138 			switch(mon)
    139 				{
    140 				case ROTHE: case POLTERGEIST: case VAMPIRE: stealth[x][y]=1;
    141 				};
    142 			return;
    143 			}
    144 		}
    145 	}
    146 
    147 /*
    148  *	int cgood(x,y,itm,monst)	  Function to check location for emptiness
    149  *		int x,y,itm,monst;
    150  *
    151  *	Routine to return TRUE if a location does not have itm or monst there
    152  *	returns FALSE (0) otherwise
    153  *	Enter with itm or monst TRUE or FALSE if checking it
    154  *	Example:  if itm==TRUE check for no item at this location
    155  *			  if monst==TRUE check for no monster at this location
    156  *	This routine will return FALSE if at a wall or the dungeon exit on level 1
    157  */
    158 int cgood(x,y,itm,monst)
    159 	register int x,y;
    160 	int itm,monst;
    161 	{
    162 	if ((y>=0) && (y<=MAXY-1) && (x>=0) && (x<=MAXX-1)) /* within bounds? */
    163 	  if (item[x][y]!=OWALL)	/* can't make anything on walls */
    164 		if (itm==0 || (item[x][y]==0))	/* is it free of items? */
    165 		  if (monst==0 || (mitem[x][y]==0))	/* is it free of monsters? */
    166 		    if ((level!=1) || (x!=33) || (y!=MAXY-1)) /* not exit to level 1 */
    167 			  return(1);
    168 	return(0);
    169 	}
    170 
    171 /*
    172  *	createitem(it,arg) 		Routine to place an item next to the player
    173  *		int it,arg;
    174  *
    175  *	Enter with the item number and its argument (iven[], ivenarg[])
    176  *	Returns no value, thus we don't know about createitem() failures.
    177  */
    178 createitem(it,arg)
    179 	int it,arg;
    180 	{
    181 	register int x,y,k,i;
    182 	if (it >= MAXOBJ) return;	/* no such object */
    183 	for (k=rnd(8), i= -8; i<0; i++,k++)	/* choose direction, then try all */
    184 		{
    185 		if (k>8) k=1;	/* wraparound the diroff arrays */
    186 		x = playerx + diroffx[k];		y = playery + diroffy[k];
    187 		if (cgood(x,y,1,0))	/* if we can create here */
    188 			{
    189 			item[x][y] = it;  know[x][y]=0;  iarg[x][y]=arg;  return;
    190 			}
    191 		}
    192 	}
    193 
    194 /*
    195  *	cast() 		Subroutine called by parse to cast a spell for the user
    196  *
    197  *	No arguments and no return value.
    198  */
    199 static char eys[] = "\nEnter your spell: ";
    200 cast()
    201 	{
    202 	register int i,j,a,b,d;
    203 	cursors();
    204 	if (c[SPELLS]<=0) {	lprcat("\nYou don't have any spells!");	return;	}
    205 	lprcat(eys);		--c[SPELLS];
    206 	while ((a=getchar())=='D')
    207 		{ seemagic(-1); cursors();  lprcat(eys); }
    208 	if (a=='\33') goto over; /*	to escape casting a spell	*/
    209 	if ((b=getchar())=='\33') goto over; /*	to escape casting a spell	*/
    210 	if ((d=getchar())=='\33')
    211 		{ over: lprcat(aborted); c[SPELLS]++; return; } /*	to escape casting a spell	*/
    212 #ifdef EXTRA
    213 	c[SPELLSCAST]++;
    214 #endif
    215 	for (lprc('\n'),j= -1,i=0; i<SPNUM; i++) /*seq search for his spell, hash?*/
    216 		if ((spelcode[i][0]==a) && (spelcode[i][1]==b) && (spelcode[i][2]==d))
    217 			if (spelknow[i])
    218 				{  speldamage(i);  j = 1;  i=SPNUM; }
    219 
    220 	if (j == -1) lprcat("  Nothing Happened ");
    221 	bottomline();
    222 	}
    223 
    224 static int dirsub();
    225 
    226 /*
    227  *	speldamage(x) 		Function to perform spell functions cast by the player
    228  *		int x;
    229  *
    230  *	Enter with the spell number, returns no value.
    231  *	Please insure that there are 2 spaces before all messages here
    232  */
    233 speldamage(x)
    234 	int x;
    235 	{
    236 	register int i,j,clev;
    237 	int xl,xh,yl,yh;
    238 	register char *p,*kn,*pm;
    239 	if (x>=SPNUM) return;	/* no such spell */
    240 	if (c[TIMESTOP])  { lprcat("  It didn't seem to work"); return; }  /* not if time stopped */
    241 	clev = c[LEVEL];
    242 	if ((rnd(23)==7) || (rnd(18) > c[INTELLIGENCE]))
    243 		{ lprcat("  It didn't work!");  return; }
    244 	if (clev*3+2 < x) { lprcat("  Nothing happens.  You seem inexperienced at this"); return; }
    245 
    246 	switch(x)
    247 		{
    248 /* ----- LEVEL 1 SPELLS ----- */
    249 
    250 		case 0:	if (c[PROTECTIONTIME]==0)	c[MOREDEFENSES]+=2; /* protection field +2 */
    251 				c[PROTECTIONTIME] += 250;   return;
    252 
    253 		case 1: i = rnd(((clev+1)<<1)) + clev + 3;
    254 				godirect(x,i,(clev>=2)?"  Your missiles hit the %s":"  Your missile hit the %s",100,'+'); /* magic missile */
    255 
    256 				return;
    257 
    258 		case 2:	if (c[DEXCOUNT]==0)	c[DEXTERITY]+=3; /*	dexterity	*/
    259 				c[DEXCOUNT] += 400;  	return;
    260 
    261 		case 3: i=rnd(3)+1;
    262 				p="  While the %s slept, you smashed it %d times";
    263 			ws:	direct(x,fullhit(i),p,i); /*	sleep	*/	return;
    264 
    265 		case 4:	/*	charm monster	*/	c[CHARMCOUNT] += c[CHARISMA]<<1;	return;
    266 
    267 		case 5:	godirect(x,rnd(10)+15+clev,"  The sound damages the %s",70,'@'); /*	sonic spear */
    268 				return;
    269 
    270 /* ----- LEVEL 2 SPELLS ----- */
    271 
    272 		case 6: i=rnd(3)+2;	p="  While the %s is entangled, you hit %d times";
    273 				goto ws; /* web */
    274 
    275 		case 7:	if (c[STRCOUNT]==0) c[STREXTRA]+=3;	/*	strength	*/
    276 				c[STRCOUNT] += 150+rnd(100);    return;
    277 
    278 		case 8:	yl = playery-5;     /* enlightenment */
    279 				yh = playery+6;   xl = playerx-15;   xh = playerx+16;
    280 				vxy(&xl,&yl);   vxy(&xh,&yh); /* check bounds */
    281 				for (i=yl; i<=yh; i++) /* enlightenment	*/
    282 					for (j=xl; j<=xh; j++)	know[j][i]=1;
    283 				draws(xl,xh+1,yl,yh+1);	return;
    284 
    285 		case 9:	raisehp(20+(clev<<1));  return;  /* healing */
    286 
    287 		case 10:	c[BLINDCOUNT]=0;	return;	/* cure blindness	*/
    288 
    289 		case 11:	createmonster(makemonst(level+1)+8);  return;
    290 
    291 		case 12:	if (rnd(11)+7 <= c[WISDOM]) direct(x,rnd(20)+20+clev,"  The %s believed!",0);
    292 					else lprcat("  It didn't believe the illusions!");
    293 					return;
    294 
    295 		case 13:	/* if he has the amulet of invisibility then add more time */
    296 					for (j=i=0; i<26; i++)
    297 						if (iven[i]==OAMULET) j+= 1+ivenarg[i];
    298 					c[INVISIBILITY] += (j<<7)+12;   return;
    299 
    300 /* ----- LEVEL 3 SPELLS ----- */
    301 
    302 		case 14:	godirect(x,rnd(25+clev)+25+clev,"  The fireball hits the %s",40,'*'); return; /*	fireball */
    303 
    304 		case 15:	godirect(x,rnd(25)+20+clev,"  Your cone of cold strikes the %s",60,'O');	/*	cold */
    305 					return;
    306 
    307 		case 16:	dirpoly(x);  return;	/*	polymorph */
    308 
    309 		case 17:	c[CANCELLATION]+= 5+clev;	return;	/*	cancellation	*/
    310 
    311 		case 18:	c[HASTESELF]+= 7+clev;  return;  /*	haste self	*/
    312 
    313 		case 19:	omnidirect(x,30+rnd(10),"  The %s gasps for air");	/* cloud kill */
    314 					return;
    315 
    316 		case 20:	xh = min(playerx+1,MAXX-2);		yh = min(playery+1,MAXY-2);
    317 					for (i=max(playerx-1,1); i<=xh; i++) /* vaporize rock */
    318 					  for (j=max(playery-1,1); j<=yh; j++)
    319 						{
    320 						kn = &know[i][j];    pm = &mitem[i][j];
    321 						switch(*(p= &item[i][j]))
    322 						  {
    323 						  case OWALL: if (level < MAXLEVEL+MAXVLEVEL-1)
    324 											*p = *kn = 0;
    325 										break;
    326 
    327 						  case OSTATUE: if (c[HARDGAME]<3)
    328 											 {
    329 											 *p=OBOOK; iarg[i][j]=level;  *kn=0;
    330 											 }
    331 										break;
    332 
    333 						  case OTHRONE: *pm=GNOMEKING;  *kn=0;  *p= OTHRONE2;
    334 										hitp[i][j]=monster[GNOMEKING].hitpoints; break;
    335 
    336 						  case OALTAR:	*pm=DEMONPRINCE;  *kn=0;
    337 										hitp[i][j]=monster[DEMONPRINCE].hitpoints; break;
    338 						  };
    339 						switch(*pm)
    340 							{
    341 							case XORN:	ifblind(i,j);  hitm(i,j,200); break; /* Xorn takes damage from vpr */
    342 							}
    343 						}
    344 					return;
    345 
    346 /* ----- LEVEL 4 SPELLS ----- */
    347 
    348 		case 21:	direct(x,100+clev,"  The %s shrivels up",0); /* dehydration */
    349 					return;
    350 
    351 		case 22:	godirect(x,rnd(25)+20+(clev<<1),"  A lightning bolt hits the %s",1,'~');	/*	lightning */
    352 					return;
    353 
    354 		case 23:	i=min(c[HP]-1,c[HPMAX]/2);	/* drain life */
    355 					direct(x,i+i,"",0);	c[HP] -= i;  	return;
    356 
    357 		case 24:	if (c[GLOBE]==0) c[MOREDEFENSES] += 10;
    358 					c[GLOBE] += 200;  loseint();  /* globe of invulnerability */
    359 					return;
    360 
    361 		case 25:	omnidirect(x,32+clev,"  The %s struggles for air in your flood!"); /* flood */
    362 					return;
    363 
    364 		case 26:	if (rnd(151)==63) { beep(); lprcat("\nYour heart stopped!\n"); nap(4000);  died(270); return; }
    365 					if (c[WISDOM]>rnd(10)+10) direct(x,2000,"  The %s's heart stopped",0); /* finger of death */
    366 					else lprcat("  It didn't work"); return;
    367 
    368 /* ----- LEVEL 5 SPELLS ----- */
    369 
    370 		case 27:	c[SCAREMONST] += rnd(10)+clev;  return;  /* scare monster */
    371 
    372 		case 28:	c[HOLDMONST] += rnd(10)+clev;  return;  /* hold monster */
    373 
    374 		case 29:	c[TIMESTOP] += rnd(20)+(clev<<1);  return;  /* time stop */
    375 
    376 		case 30:	tdirect(x);  return;  /* teleport away */
    377 
    378 		case 31:	omnidirect(x,35+rnd(10)+clev,"  The %s cringes from the flame"); /* magic fire */
    379 					return;
    380 
    381 /* ----- LEVEL 6 SPELLS ----- */
    382 
    383 		case 32:	if ((rnd(23)==5) && (wizard==0)) /* sphere of annihilation */
    384 						{
    385 						beep(); lprcat("\nYou have been enveloped by the zone of nothingness!\n");
    386 						nap(4000);  died(258); return;
    387 						}
    388 					xl=playerx; yl=playery;
    389 					loseint();
    390 					i=dirsub(&xl,&yl); /* get direction of sphere */
    391 					newsphere(xl,yl,i,rnd(20)+11);	/* make a sphere */
    392 					return;
    393 
    394 		case 33:	genmonst();  spelknow[33]=0;  /* genocide */
    395 					loseint();
    396 					return;
    397 
    398 		case 34:	/* summon demon */
    399 					if (rnd(100) > 30) { direct(x,150,"  The demon strikes at the %s",0);  return; }
    400 					if (rnd(100) > 15) { lprcat("  Nothing seems to have happened");  return; }
    401 					lprcat("  The demon turned on you and vanished!"); beep();
    402 					i=rnd(40)+30;  lastnum=277;
    403 					losehp(i); /* must say killed by a demon */ return;
    404 
    405 		case 35:	/* walk through walls */
    406 					c[WTW] += rnd(10)+5;	return;
    407 
    408 		case 36:	/* alter reality */
    409 					{
    410 					struct isave *save;	/* pointer to item save structure */
    411 					int sc;	sc=0;	/* # items saved */
    412 					save = (struct isave *)malloc(sizeof(struct isave)*MAXX*MAXY*2);
    413 					for (j=0; j<MAXY; j++)
    414 						for (i=0; i<MAXX; i++) /* save all items and monsters */
    415 							{
    416 							xl = item[i][j];
    417 							if (xl && xl!=OWALL && xl!=OANNIHILATION)
    418 								{
    419 								save[sc].type=0;  save[sc].id=item[i][j];
    420 								save[sc++].arg=iarg[i][j];
    421 								}
    422 							if (mitem[i][j])
    423 								{
    424 								save[sc].type=1;  save[sc].id=mitem[i][j];
    425 								save[sc++].arg=hitp[i][j];
    426 								}
    427 							item[i][j]=OWALL;   mitem[i][j]=0;
    428 							if (wizard) know[i][j]=1; else know[i][j]=0;
    429 							}
    430 					eat(1,1);	if (level==1) item[33][MAXY-1]=0;
    431 					for (j=rnd(MAXY-2), i=1; i<MAXX-1; i++) item[i][j]=0;
    432 					while (sc>0) /* put objects back in level */
    433 						{
    434 						--sc;
    435 						if (save[sc].type == 0)
    436 							{
    437 							int trys;
    438 							for (trys=100, i=j=1; --trys>0 && item[i][j]; i=rnd(MAXX-1), j=rnd(MAXY-1));
    439 							if (trys) { item[i][j]=save[sc].id; iarg[i][j]=save[sc].arg; }
    440 							}
    441 						else
    442 							{ /* put monsters back in */
    443 							int trys;
    444 							for (trys=100, i=j=1; --trys>0 && (item[i][j]==OWALL || mitem[i][j]); i=rnd(MAXX-1), j=rnd(MAXY-1));
    445 							if (trys) { mitem[i][j]=save[sc].id; hitp[i][j]=save[sc].arg; }
    446 							}
    447 						}
    448 					loseint();
    449 					draws(0,MAXX,0,MAXY);  if (wizard==0) spelknow[36]=0;
    450 					free((char*)save);	 positionplayer();  return;
    451 					}
    452 
    453 		case 37:	/* permanence */ adjtime(-99999L);  spelknow[37]=0; /* forget */
    454 					loseint();
    455 					return;
    456 
    457 		default:	lprintf("  spell %d not available!",(long)x); beep();  return;
    458 		};
    459 	}
    460 
    461 /*
    462  *	loseint()		Routine to subtract 1 from your int (intelligence) if > 3
    463  *
    464  *	No arguments and no return value
    465  */
    466 loseint()
    467 	{
    468 	if (--c[INTELLIGENCE]<3)  c[INTELLIGENCE]=3;
    469 	}
    470 
    471 /*
    472  *	isconfuse() 		Routine to check to see if player is confused
    473  *
    474  *	This routine prints out a message saying "You can't aim your magic!"
    475  *	returns 0 if not confused, non-zero (time remaining confused) if confused
    476  */
    477 isconfuse()
    478 	{
    479 	if (c[CONFUSE]) { lprcat(" You can't aim your magic!"); beep(); }
    480 	return(c[CONFUSE]);
    481 	}
    482 
    483 /*
    484  *	nospell(x,monst)	Routine to return 1 if a spell doesn't affect a monster
    485  *		int x,monst;
    486  *
    487  *	Subroutine to return 1 if the spell can't affect the monster
    488  *	  otherwise returns 0
    489  *	Enter with the spell number in x, and the monster number in monst.
    490  */
    491 nospell(x,monst)
    492 	int x,monst;
    493 	{
    494 	register int tmp;
    495 	if (x>=SPNUM || monst>=MAXMONST+8 || monst<0 || x<0) return(0);	/* bad spell or monst */
    496 	if ((tmp=spelweird[monst-1][x])==0) return(0);
    497 	cursors();  lprc('\n');  lprintf(spelmes[tmp],monster[monst].name);  return(1);
    498 	}
    499 
    500 /*
    501  *	fullhit(xx)		Function to return full damage against a monster (aka web)
    502  *		int xx;
    503  *
    504  *	Function to return hp damage to monster due to a number of full hits
    505  *	Enter with the number of full hits being done
    506  */
    507 fullhit(xx)
    508 	int xx;
    509 	{
    510 	register int i;
    511 	if (xx<0 || xx>20) return(0);	/* fullhits are out of range */
    512 	if (c[LANCEDEATH]) return(10000);	/* lance of death */
    513 	i = xx * ((c[WCLASS]>>1)+c[STRENGTH]+c[STREXTRA]-c[HARDGAME]-12+c[MOREDAM]);
    514 	return( (i>=1) ? i : xx );
    515 	}
    516 
    517 /*
    518  *	direct(spnum,dam,str,arg)	Routine to direct spell damage 1 square in 1 dir
    519  *		int spnum,dam,arg;
    520  *		char *str;
    521  *
    522  *	Routine to ask for a direction to a spell and then hit the monster
    523  *	Enter with the spell number in spnum, the damage to be done in dam,
    524  *	  lprintf format string in str, and lprintf's argument in arg.
    525  *	Returns no value.
    526  */
    527 direct(spnum,dam,str,arg)
    528 	int spnum,dam,arg;
    529 	char *str;
    530 	{
    531 	int x,y;
    532 	register int m;
    533 	if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad arguments */
    534 	if (isconfuse()) return;
    535 	dirsub(&x,&y);
    536 	m = mitem[x][y];
    537 	if (item[x][y]==OMIRROR)
    538 		{
    539 		if (spnum==3) /* sleep */
    540 			{
    541 			lprcat("You fall asleep! "); beep();
    542 		fool:
    543 			arg += 2;
    544 			while (arg-- > 0) { parse2(); nap(1000); }
    545 			return;
    546 			}
    547 		else if (spnum==6) /* web */
    548 			{
    549 			lprcat("You get stuck in your own web! "); beep();
    550 			goto fool;
    551 			}
    552 		else
    553 			{
    554 			lastnum=278;
    555 			lprintf(str,"spell caster (thats you)",(long)arg);
    556 			beep(); losehp(dam); return;
    557 			}
    558 		}
    559 	if (m==0)
    560 		{	lprcat("  There wasn't anything there!");	return;  }
    561 	ifblind(x,y);
    562 	if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
    563 	lprintf(str,lastmonst,(long)arg);       hitm(x,y,dam);
    564 	}
    565 
    566 /*
    567  *	godirect(spnum,dam,str,delay,cshow)		Function to perform missile attacks
    568  *		int spnum,dam,delay;
    569  *		char *str,cshow;
    570  *
    571  *	Function to hit in a direction from a missile weapon and have it keep
    572  *	on going in that direction until its power is exhausted
    573  *	Enter with the spell number in spnum, the power of the weapon in hp,
    574  *	  lprintf format string in str, the # of milliseconds to delay between
    575  *	  locations in delay, and the character to represent the weapon in cshow.
    576  *	Returns no value.
    577  */
    578 godirect(spnum,dam,str,delay,cshow)
    579 	int spnum,dam,delay;
    580 	char *str,cshow;
    581 	{
    582 	register char *p;
    583 	register int x,y,m;
    584 	int dx,dy;
    585 	if (spnum<0 || spnum>=SPNUM || str==0 || delay<0) return; /* bad args */
    586 	if (isconfuse()) return;
    587 	dirsub(&dx,&dy);	x=dx;	y=dy;
    588 	dx = x-playerx;		dy = y-playery;		x = playerx;	y = playery;
    589 	while (dam>0)
    590 		{
    591 		x += dx;    y += dy;
    592 	    if ((x > MAXX-1) || (y > MAXY-1) || (x < 0) || (y < 0))
    593 			{
    594 			dam=0;	break;  /* out of bounds */
    595 			}
    596 		if ((x==playerx) && (y==playery)) /* if energy hits player */
    597 			{
    598 			cursors(); lprcat("\nYou are hit my your own magic!"); beep();
    599 			lastnum=278;  losehp(dam);  return;
    600 			}
    601 		if (c[BLINDCOUNT]==0) /* if not blind show effect */
    602 			{
    603 			cursor(x+1,y+1); lprc(cshow); nap(delay); show1cell(x,y);
    604 			}
    605 		if ((m=mitem[x][y]))	/* is there a monster there? */
    606 			{
    607 			ifblind(x,y);
    608 			if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
    609 			cursors(); lprc('\n');
    610 			lprintf(str,lastmonst);		dam -= hitm(x,y,dam);
    611 			show1cell(x,y);  nap(1000);		x -= dx;	y -= dy;
    612 			}
    613 		else switch (*(p= &item[x][y]))
    614 			{
    615 			case OWALL:	cursors(); lprc('\n'); lprintf(str,"wall");
    616 						if (dam>=50+c[HARDGAME]) /* enough damage? */
    617 						 if (level<MAXLEVEL+MAXVLEVEL-1) /* not on V3 */
    618 						  if ((x<MAXX-1) && (y<MAXY-1) && (x) && (y))
    619 							{
    620 							lprcat("  The wall crumbles");
    621 					god3:	*p=0;
    622 					god:	know[x][y]=0;
    623 							show1cell(x,y);
    624 							}
    625 				god2:	dam = 0;	break;
    626 
    627 			case OCLOSEDDOOR:	cursors(); lprc('\n'); lprintf(str,"door");
    628 						if (dam>=40)
    629 							{
    630 							lprcat("  The door is blasted apart");
    631 							goto god3;
    632 							}
    633 						goto god2;
    634 
    635 			case OSTATUE:	cursors(); lprc('\n'); lprintf(str,"statue");
    636 						if (c[HARDGAME]<3)
    637 						  if (dam>44)
    638 							{
    639 							lprcat("  The statue crumbles");
    640 							*p=OBOOK; iarg[x][y]=level;
    641 							goto god;
    642 							}
    643 						goto god2;
    644 
    645 			case OTHRONE:	cursors(); lprc('\n'); lprintf(str,"throne");
    646 					if (dam>39)
    647 						{
    648 						mitem[x][y]=GNOMEKING; hitp[x][y]=monster[GNOMEKING].hitpoints;
    649 						*p = OTHRONE2;
    650 						goto god;
    651 						}
    652 					goto god2;
    653 
    654 			case OMIRROR:	dx *= -1;	dy *= -1;	break;
    655 			};
    656 		dam -= 3 + (c[HARDGAME]>>1);
    657 		}
    658 	}
    659 
    660 /*
    661  *	ifblind(x,y)	Routine to put "monster" or the monster name into lastmosnt
    662  *		int x,y;
    663  *
    664  *	Subroutine to copy the word "monster" into lastmonst if the player is blind
    665  *	Enter with the coordinates (x,y) of the monster
    666  *	Returns no value.
    667  */
    668 ifblind(x,y)
    669 	int x,y;
    670 	{
    671 	char *p;
    672 	vxy(&x,&y);	/* verify correct x,y coordinates */
    673 	if (c[BLINDCOUNT]) { lastnum=279;  p="monster"; }
    674 		else { lastnum=mitem[x][y];  p=monster[lastnum].name; }
    675 	strcpy(lastmonst,p);
    676 	}
    677 
    678 /*
    679  *	tdirect(spnum)		Routine to teleport away a monster
    680  *		int spnum;
    681  *
    682  *	Routine to ask for a direction to a spell and then teleport away monster
    683  *	Enter with the spell number that wants to teleport away
    684  *	Returns no value.
    685  */
    686 tdirect(spnum)
    687 	int spnum;
    688 	{
    689 	int x,y;
    690 	register int m;
    691 	if (spnum<0 || spnum>=SPNUM) return; /* bad args */
    692 	if (isconfuse()) return;
    693 	dirsub(&x,&y);
    694 	if ((m=mitem[x][y])==0)
    695 		{	lprcat("  There wasn't anything there!");	return;  }
    696 	ifblind(x,y);
    697 	if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
    698 	fillmonst(m);  mitem[x][y]=know[x][y]=0;
    699 	}
    700 
    701 /*
    702  *	omnidirect(sp,dam,str)   Routine to damage all monsters 1 square from player
    703  *		int sp,dam;
    704  *		char *str;
    705  *
    706  *	Routine to cast a spell and then hit the monster in all directions
    707  *	Enter with the spell number in sp, the damage done to wach square in dam,
    708  *	  and the lprintf string to identify the spell in str.
    709  *	Returns no value.
    710  */
    711 omnidirect(spnum,dam,str)
    712 	int spnum,dam;
    713 	char *str;
    714 	{
    715 	register int x,y,m;
    716 	if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad args */
    717 	for (x=playerx-1; x<playerx+2; x++)
    718 		for (y=playery-1; y<playery+2; y++)
    719 			{
    720 			if (m=mitem[x][y])
    721 				if (nospell(spnum,m) == 0)
    722 					{
    723 					ifblind(x,y);
    724 					cursors(); lprc('\n'); lprintf(str,lastmonst);
    725 					hitm(x,y,dam);  nap(800);
    726 					}
    727 				else  { lasthx=x;  lasthy=y; }
    728 			}
    729 	}
    730 
    731 /*
    732  *	static dirsub(x,y)		Routine to ask for direction, then modify x,y for it
    733  *		int *x,*y;
    734  *
    735  *	Function to ask for a direction and modify an x,y for that direction
    736  *	Enter with the origination coordinates in (x,y).
    737  *	Returns index into diroffx[] (0-8).
    738  */
    739 static int
    740 dirsub(x,y)
    741 	int *x,*y;
    742 	{
    743 	register int i;
    744 	lprcat("\nIn What Direction? ");
    745 	for (i=0; ; )
    746 		switch(getchar())
    747 			{
    748 			case 'b':	i++;
    749 			case 'n':	i++;
    750 			case 'y':	i++;
    751 			case 'u':	i++;
    752 			case 'h':	i++;
    753 			case 'k':	i++;
    754 			case 'l':	i++;
    755 			case 'j':	i++;		goto out;
    756 			};
    757 out:
    758 	*x = playerx+diroffx[i];		*y = playery+diroffy[i];
    759 	vxy(x,y);  return(i);
    760 	}
    761 
    762 /*
    763  *	vxy(x,y)	   Routine to verify/fix coordinates for being within bounds
    764  *		int *x,*y;
    765  *
    766  *	Function to verify x & y are within the bounds for a level
    767  *	If *x or *y is not within the absolute bounds for a level, fix them so that
    768  *	  they are on the level.
    769  *	Returns TRUE if it was out of bounds, and the *x & *y in the calling
    770  *	routine are affected.
    771  */
    772 vxy(x,y)
    773 	int *x,*y;
    774 	{
    775 	int flag=0;
    776 	if (*x<0) { *x=0; flag++; }
    777 	if (*y<0) { *y=0; flag++; }
    778 	if (*x>=MAXX) { *x=MAXX-1; flag++; }
    779 	if (*y>=MAXY) { *y=MAXY-1; flag++; }
    780 	return(flag);
    781 	}
    782 
    783 /*
    784  *	dirpoly(spnum)		Routine to ask for a direction and polymorph a monst
    785  *		int spnum;
    786  *
    787  *	Subroutine to polymorph a monster and ask for the direction its in
    788  *	Enter with the spell number in spmun.
    789  *	Returns no value.
    790  */
    791 dirpoly(spnum)
    792 	int spnum;
    793 	{
    794 	int x,y,m;
    795 	if (spnum<0 || spnum>=SPNUM) return; /* bad args */
    796 	if (isconfuse()) return;	/* if he is confused, he can't aim his magic */
    797 	dirsub(&x,&y);
    798 	if (mitem[x][y]==0)
    799 		{	lprcat("  There wasn't anything there!");	return;  }
    800 	ifblind(x,y);
    801 	if (nospell(spnum,mitem[x][y])) { lasthx=x;  lasthy=y; return; }
    802 	while ( monster[m = mitem[x][y] = rnd(MAXMONST+7)].genocided );
    803 	hitp[x][y] = monster[m].hitpoints;
    804 	show1cell(x,y);  /* show the new monster */
    805 	}
    806 
    807 /*
    808  *	hitmonster(x,y) 	Function to hit a monster at the designated coordinates
    809  *		int x,y;
    810  *
    811  *	This routine is used for a bash & slash type attack on a monster
    812  *	Enter with the coordinates of the monster in (x,y).
    813  *	Returns no value.
    814  */
    815 hitmonster(x,y)
    816 	int x,y;
    817 	{
    818 	register int tmp,monst,damag,flag;
    819 	if (c[TIMESTOP])  return;  /* not if time stopped */
    820 	vxy(&x,&y);	/* verify coordinates are within range */
    821 	if ((monst = mitem[x][y]) == 0) return;
    822 	hit3flag=1;  ifblind(x,y);
    823 	tmp = monster[monst].armorclass + c[LEVEL] + c[DEXTERITY] + c[WCLASS]/4 - 12;
    824 	cursors();
    825 	if ((rnd(20) < tmp-c[HARDGAME]) || (rnd(71) < 5)) /* need at least random chance to hit */
    826 		{
    827 		lprcat("\nYou hit");  flag=1;
    828 		damag = fullhit(1);
    829 		if (damag<9999) damag=rnd(damag)+1;
    830 		}
    831 	else
    832 		{
    833 		lprcat("\nYou missed");  flag=0;
    834 		}
    835 	lprcat(" the "); lprcat(lastmonst);
    836 	if (flag)	/* if the monster was hit */
    837 	  if ((monst==RUSTMONSTER) || (monst==DISENCHANTRESS) || (monst==CUBE))
    838 		if (c[WIELD]>0)
    839 		  if (ivenarg[c[WIELD]] > -10)
    840 			{
    841 			lprintf("\nYour weapon is dulled by the %s",lastmonst); beep();
    842 			--ivenarg[c[WIELD]];
    843 			}
    844 	if (flag)  hitm(x,y,damag);
    845 	if (monst == VAMPIRE) if (hitp[x][y]<25)  { mitem[x][y]=BAT; know[x][y]=0; }
    846 	}
    847 
    848 /*
    849  *	hitm(x,y,amt)		Function to just hit a monster at a given coordinates
    850  *		int x,y,amt;
    851  *
    852  *	Returns the number of hitpoints the monster absorbed
    853  *	This routine is used to specifically damage a monster at a location (x,y)
    854  *	Called by hitmonster(x,y)
    855  */
    856 hitm(x,y,amt)
    857 	int x,y;
    858 	register amt;
    859 	{
    860 	register int monst;
    861 	int hpoints,amt2;
    862 	vxy(&x,&y);	/* verify coordinates are within range */
    863 	amt2 = amt;		/* save initial damage so we can return it */
    864 	monst = mitem[x][y];
    865 	if (c[HALFDAM]) amt >>= 1;	/* if half damage curse adjust damage points */
    866 	if (amt<=0) amt2 = amt = 1;
    867 	lasthx=x;  lasthy=y;
    868 	stealth[x][y]=1;	/* make sure hitting monst breaks stealth condition */
    869 	c[HOLDMONST]=0;	/* hit a monster breaks hold monster spell	*/
    870 	switch(monst) /* if a dragon and orb(s) of dragon slaying	*/
    871 		{
    872 		case WHITEDRAGON:		case REDDRAGON:			case GREENDRAGON:
    873 		case BRONZEDRAGON:		case PLATINUMDRAGON:	case SILVERDRAGON:
    874 			amt *= 1+(c[SLAYING]<<1);	break;
    875 		}
    876 /* invincible monster fix is here */
    877 	if (hitp[x][y] > monster[monst].hitpoints)
    878 		hitp[x][y] = monster[monst].hitpoints;
    879 	if ((hpoints = hitp[x][y]) <= amt)
    880 		{
    881 #ifdef EXTRA
    882 		c[MONSTKILLED]++;
    883 #endif
    884 		lprintf("\nThe %s died!",lastmonst);
    885 		raiseexperience((long)monster[monst].experience);
    886 		amt = monster[monst].gold;  if (amt>0) dropgold(rnd(amt)+amt);
    887 		dropsomething(monst);	disappear(x,y);	bottomline();
    888 		return(hpoints);
    889 		}
    890 	hitp[x][y] = hpoints-amt;	return(amt2);
    891 	}
    892 
    893 /*
    894  *	hitplayer(x,y) 		Function for the monster to hit the player from (x,y)
    895  *		int x,y;
    896  *
    897  *	Function for the monster to hit the player with monster at location x,y
    898  *	Returns nothing of value.
    899  */
    900 hitplayer(x,y)
    901 	int x,y;
    902 	{
    903 	register int dam,tmp,mster,bias;
    904 	vxy(&x,&y);	/* verify coordinates are within range */
    905 	lastnum = mster = mitem[x][y];
    906 /*	spirit naga's and poltergeist's do nothing if scarab of negate spirit	*/
    907 	if (c[NEGATESPIRIT] || c[SPIRITPRO])  if ((mster ==POLTERGEIST) || (mster ==SPIRITNAGA))  return;
    908 /*	if undead and cube of undead control	*/
    909 	if (c[CUBEofUNDEAD] || c[UNDEADPRO]) if ((mster ==VAMPIRE) || (mster ==WRAITH) || (mster ==ZOMBIE)) return;
    910 	if ((know[x][y]&1) == 0)
    911 		{
    912 		know[x][y]=1; show1cell(x,y);
    913 		}
    914 	bias = (c[HARDGAME]) + 1;
    915 	hitflag = hit2flag = hit3flag = 1;
    916 	yrepcount=0;
    917 	cursors();	ifblind(x,y);
    918 	if (c[INVISIBILITY]) if (rnd(33)<20)
    919 		{
    920 		lprintf("\nThe %s misses wildly",lastmonst);	return;
    921 		}
    922 	if (c[CHARMCOUNT]) if (rnd(30)+5*monster[mster].level-c[CHARISMA]<30)
    923 		{
    924 		lprintf("\nThe %s is awestruck at your magnificence!",lastmonst);
    925 		return;
    926 		}
    927 	if (mster==BAT) dam=1;
    928 	else
    929 		{
    930 		dam = monster[mster].damage;
    931 		dam += rnd((int)((dam<1)?1:dam)) + monster[mster].level;
    932 		}
    933 	tmp = 0;
    934 	if (monster[mster].attack>0)
    935 	  if (((dam + bias + 8) > c[AC]) || (rnd((int)((c[AC]>0)?c[AC]:1))==1))
    936 		{ if (spattack(monster[mster].attack,x,y)) { flushall(); return; }
    937 		  tmp = 1;  bias -= 2; cursors(); }
    938 	if (((dam + bias) > c[AC]) || (rnd((int)((c[AC]>0)?c[AC]:1))==1))
    939 		{
    940 		lprintf("\n  The %s hit you ",lastmonst);	tmp = 1;
    941 		if ((dam -= c[AC]) < 0) dam=0;
    942 		if (dam > 0) { losehp(dam); bottomhp(); flushall(); }
    943 		}
    944 	if (tmp == 0)  lprintf("\n  The %s missed ",lastmonst);
    945 	}
    946 
    947 /*
    948  *	dropsomething(monst) 	Function to create an object when a monster dies
    949  *		int monst;
    950  *
    951  *	Function to create an object near the player when certain monsters are killed
    952  *	Enter with the monster number
    953  *	Returns nothing of value.
    954  */
    955 dropsomething(monst)
    956 	int monst;
    957 	{
    958 	switch(monst)
    959 		{
    960 		case ORC:			  case NYMPH:	   case ELF:	  case TROGLODYTE:
    961 		case TROLL:			  case ROTHE:	   case VIOLETFUNGI:
    962 		case PLATINUMDRAGON:  case GNOMEKING:  case REDDRAGON:
    963 			something(level); return;
    964 
    965 		case LEPRECHAUN: if (rnd(101)>=75) creategem();
    966 						 if (rnd(5)==1) dropsomething(LEPRECHAUN);   return;
    967 		}
    968 	}
    969 
    970 /*
    971  *	dropgold(amount) 	Function to drop some gold around player
    972  *		int amount;
    973  *
    974  *	Enter with the number of gold pieces to drop
    975  *	Returns nothing of value.
    976  */
    977 dropgold(amount)
    978 	register int amount;
    979 	{
    980 	if (amount > 250) createitem(OMAXGOLD,amount/100);  else  createitem(OGOLDPILE,amount);
    981 	}
    982 
    983 /*
    984  *	something(level) 	Function to create a random item around player
    985  *		int level;
    986  *
    987  *	Function to create an item from a designed probability around player
    988  *	Enter with the cave level on which something is to be dropped
    989  *	Returns nothing of value.
    990  */
    991 something(level)
    992 	int level;
    993 	{
    994 	register int j;
    995 	int i;
    996 	if (level<0 || level>MAXLEVEL+MAXVLEVEL) return;	/* correct level? */
    997 	if (rnd(101)<8) something(level); /* possibly more than one item */
    998 	j = newobject(level,&i);		createitem(j,i);
    999 	}
   1000 
   1001 /*
   1002  *	newobject(lev,i) 	Routine to return a randomly selected new object
   1003  *		int lev,*i;
   1004  *
   1005  *	Routine to return a randomly selected object to be created
   1006  *	Returns the object number created, and sets *i for its argument
   1007  *	Enter with the cave level and a pointer to the items arg
   1008  */
   1009 static char nobjtab[] = { 0, OSCROLL,  OSCROLL,  OSCROLL,  OSCROLL, OPOTION,
   1010 	OPOTION, OPOTION, OPOTION, OGOLDPILE, OGOLDPILE, OGOLDPILE, OGOLDPILE,
   1011 	OBOOK, OBOOK, OBOOK, OBOOK, ODAGGER, ODAGGER, ODAGGER, OLEATHER, OLEATHER,
   1012 	OLEATHER, OREGENRING, OPROTRING, OENERGYRING, ODEXRING, OSTRRING, OSPEAR,
   1013 	OBELT, ORING, OSTUDLEATHER, OSHIELD, OFLAIL, OCHAIN, O2SWORD, OPLATE,
   1014 	OLONGSWORD };
   1015 
   1016 newobject(lev,i)
   1017 	register int lev,*i;
   1018 	{
   1019 	register int tmp=32,j;
   1020 	if (level<0 || level>MAXLEVEL+MAXVLEVEL) return(0);	/* correct level? */
   1021 	if (lev>6) tmp=37; else if (lev>4) tmp=35;
   1022 	j = nobjtab[tmp=rnd(tmp)];	/* the object type */
   1023 	switch(tmp)
   1024 		{
   1025 		case 1: case 2: case 3: case 4:	*i=newscroll();	break;
   1026 		case 5: case 6: case 7: case 8:	*i=newpotion();	break;
   1027 		case 9: case 10: case 11: case 12: *i=rnd((lev+1)*10)+lev*10+10; break;
   1028 		case 13: case 14: case 15: case 16:	*i=lev;	break;
   1029 		case 17: case 18: case 19: if (!(*i=newdagger()))  return(0);  break;
   1030 		case 20: case 21: case 22: if (!(*i=newleather()))  return(0);  break;
   1031 		case 23: case 32: case 35: *i=rund(lev/3+1); break;
   1032 		case 24: case 26: *i=rnd(lev/4+1);   break;
   1033 		case 25: *i=rund(lev/4+1); break;
   1034 		case 27: *i=rnd(lev/2+1);   break;
   1035 		case 30: case 33: *i=rund(lev/2+1);   break;
   1036 		case 28: *i=rund(lev/3+1); if (*i==0) return(0); break;
   1037 		case 29: case 31: *i=rund(lev/2+1); if (*i==0) return(0); break;
   1038 		case 34: *i=newchain();   	break;
   1039 		case 36: *i=newplate();   	break;
   1040 		case 37: *i=newsword();		break;
   1041 		}
   1042 	return(j);
   1043 	}
   1044 
   1045 /*
   1046  *  spattack(atckno,xx,yy) 	Function to process special attacks from monsters
   1047  *  	int atckno,xx,yy;
   1048  *
   1049  *	Enter with the special attack number, and the coordinates (xx,yy)
   1050  *		of the monster that is special attacking
   1051  *	Returns 1 if must do a show1cell(xx,yy) upon return, 0 otherwise
   1052  *
   1053  * atckno   monster     effect
   1054  * ---------------------------------------------------
   1055  *	0	none
   1056  *	1	rust monster	eat armor
   1057  *	2	hell hound		breathe light fire
   1058  *	3	dragon			breathe fire
   1059  *	4	giant centipede	weakening sing
   1060  *	5	white dragon	cold breath
   1061  *	6	wraith			drain level
   1062  *	7	waterlord		water gusher
   1063  *	8	leprechaun		steal gold
   1064  *	9	disenchantress	disenchant weapon or armor
   1065  *	10	ice lizard		hits with barbed tail
   1066  *	11	umber hulk		confusion
   1067  *	12	spirit naga		cast spells	taken from special attacks
   1068  *	13	platinum dragon	psionics
   1069  *	14	nymph			steal objects
   1070  *	15	bugbear			bite
   1071  *	16	osequip			bite
   1072  *
   1073  *	char rustarm[ARMORTYPES][2];
   1074  *	special array for maximum rust damage to armor from rustmonster
   1075  *	format is: { armor type , minimum attribute
   1076  */
   1077 #define ARMORTYPES 6
   1078 static char rustarm[ARMORTYPES][2] = { OSTUDLEATHER,-2,	ORING,-4, OCHAIN,-5,
   1079 	OSPLINT,-6,		OPLATE,-8,		OPLATEARMOR,-9  };
   1080 static char spsel[] = { 1, 2, 3, 5, 6, 8, 9, 11, 13, 14 };
   1081 spattack(x,xx,yy)
   1082 	int x,xx,yy;
   1083 	{
   1084 	register int i,j=0,k,m;
   1085 	register char *p=0;
   1086 	if (c[CANCELLATION]) return(0);
   1087 	vxy(&xx,&yy);	/* verify x & y coordinates */
   1088 	switch(x)
   1089 		{
   1090 		case 1:	/* rust your armor, j=1 when rusting has occurred */
   1091 				m = k = c[WEAR];
   1092 				if ((i=c[SHIELD]) != -1)
   1093 					if (--ivenarg[i] < -1) ivenarg[i]= -1; else j=1;
   1094 				if ((j==0) && (k != -1))
   1095 				  {
   1096 				  m = iven[k];
   1097 				  for (i=0; i<ARMORTYPES; i++)
   1098 					if (m == rustarm[i][0]) /* find his armor in table */
   1099 						{
   1100 						if (--ivenarg[k]< rustarm[i][1])
   1101 							ivenarg[k]= rustarm[i][1]; else j=1;
   1102 						break;
   1103 						}
   1104 				  }
   1105 				if (j==0)	/* if rusting did not occur */
   1106 				  switch(m)
   1107 					{
   1108 					case OLEATHER:	p = "\nThe %s hit you -- Your lucky you have leather on";
   1109 									break;
   1110 				    case OSSPLATE:	p = "\nThe %s hit you -- Your fortunate to have stainless steel armor!";
   1111 									break;
   1112 					}
   1113 				else  { beep(); p = "\nThe %s hit you -- your armor feels weaker"; }
   1114 				break;
   1115 
   1116 		case 2:		i = rnd(15)+8-c[AC];
   1117 			spout:	p="\nThe %s breathes fire at you!";
   1118 					if (c[FIRERESISTANCE])
   1119 					  p="\nThe %s's flame doesn't phase you!";
   1120 					else
   1121 			spout2: if (p) { lprintf(p,lastmonst); beep(); }
   1122 					checkloss(i);
   1123 					return(0);
   1124 
   1125 		case 3:		i = rnd(20)+25-c[AC];  goto spout;
   1126 
   1127 		case 4:	if (c[STRENGTH]>3)
   1128 					{
   1129 					p="\nThe %s stung you!  You feel weaker"; beep();
   1130 					--c[STRENGTH];
   1131 					}
   1132 				else p="\nThe %s stung you!";
   1133 				break;
   1134 
   1135 		case 5:		p="\nThe %s blasts you with his cold breath";
   1136 					i = rnd(15)+18-c[AC];  goto spout2;
   1137 
   1138 		case 6:		lprintf("\nThe %s drains you of your life energy!",lastmonst);
   1139 					loselevel();  beep();  return(0);
   1140 
   1141 		case 7:		p="\nThe %s got you with a gusher!";
   1142 					i = rnd(15)+25-c[AC];  goto spout2;
   1143 
   1144 		case 8:		if (c[NOTHEFT]) return(0); /* he has a device of no theft */
   1145 					if (c[GOLD])
   1146 						{
   1147 						p="\nThe %s hit you -- Your purse feels lighter";
   1148 						if (c[GOLD]>32767)  c[GOLD]>>=1;
   1149 							else c[GOLD] -= rnd((int)(1+(c[GOLD]>>1)));
   1150 						if (c[GOLD] < 0) c[GOLD]=0;
   1151 						}
   1152 					else  p="\nThe %s couldn't find any gold to steal";
   1153 					lprintf(p,lastmonst); disappear(xx,yy); beep();
   1154 					bottomgold();  return(1);
   1155 
   1156 		case 9:	for(j=50; ; )	/* disenchant */
   1157 					{
   1158 					i=rund(26);  m=iven[i]; /* randomly select item */
   1159 					if (m>0 && ivenarg[i]>0 && m!=OSCROLL && m!=OPOTION)
   1160 						{
   1161 						if ((ivenarg[i] -= 3)<0) ivenarg[i]=0;
   1162 						lprintf("\nThe %s hits you -- you feel a sense of loss",lastmonst);
   1163 						srcount=0; beep(); show3(i);  bottomline();  return(0);
   1164 						}
   1165 					if (--j<=0)
   1166 						{
   1167 						p="\nThe %s nearly misses"; break;
   1168 						}
   1169 					break;
   1170 					}
   1171 				break;
   1172 
   1173 		case 10:   p="\nThe %s hit you with his barbed tail";
   1174 				   i = rnd(25)-c[AC];  goto spout2;
   1175 
   1176 		case 11:	p="\nThe %s has confused you"; beep();
   1177 					c[CONFUSE]+= 10+rnd(10);		break;
   1178 
   1179 		case 12:	/*	performs any number of other special attacks	*/
   1180 					return(spattack(spsel[rund(10)],xx,yy));
   1181 
   1182 		case 13:	p="\nThe %s flattens you with his psionics!";
   1183 					i = rnd(15)+30-c[AC];  goto spout2;
   1184 
   1185 		case 14:	if (c[NOTHEFT]) return(0); /* he has device of no theft */
   1186 					if (emptyhanded()==1)
   1187 					  {
   1188 					  p="\nThe %s couldn't find anything to steal";
   1189 					  break;
   1190 					  }
   1191 					lprintf("\nThe %s picks your pocket and takes:",lastmonst);
   1192 					beep();
   1193 					if (stealsomething()==0) lprcat("  nothing"); disappear(xx,yy);
   1194 					bottomline();  return(1);
   1195 
   1196 		case 15:	i= rnd(10)+ 5-c[AC];
   1197 			spout3:	p="\nThe %s bit you!";
   1198 					goto spout2;
   1199 
   1200 		case 16:	i= rnd(15)+10-c[AC];  goto spout3;
   1201 		};
   1202 	if (p) { lprintf(p,lastmonst); bottomline(); }
   1203 	return(0);
   1204 	}
   1205 
   1206 /*
   1207  *	checkloss(x) 	Routine to subtract hp from user and flag bottomline display
   1208  *		int x;
   1209  *
   1210  *	Routine to subtract hitpoints from the user and flag the bottomline display
   1211  *	Enter with the number of hit points to lose
   1212  *	Note: if x > c[HP] this routine could kill the player!
   1213  */
   1214 checkloss(x)
   1215 	int x;
   1216 	{
   1217 	if (x>0) { losehp(x);  bottomhp(); }
   1218 	}
   1219 
   1220 /*
   1221  *	annihilate() 	Routine to annihilate all monsters around player (playerx,playery)
   1222  *
   1223  *	Gives player experience, but no dropped objects
   1224  *	Returns the experience gained from all monsters killed
   1225  */
   1226 annihilate()
   1227 	{
   1228 	int i,j;
   1229 	register long k;
   1230 	register char *p;
   1231 	for (k=0, i=playerx-1; i<=playerx+1; i++)
   1232 	  for (j=playery-1; j<=playery+1; j++)
   1233 		if (!vxy(&i,&j)) /* if not out of bounds */
   1234 			if (*(p= &mitem[i][j]))	/* if a monster there */
   1235 				if (*p<DEMONLORD+2)
   1236 					{
   1237 					k += monster[*p].experience;	*p=know[i][j]=0;
   1238 					}
   1239 				else
   1240 					{
   1241 					lprintf("\nThe %s barely escapes being annihilated!",monster[*p].name);
   1242 					hitp[i][j] = (hitp[i][j]>>1) + 1; /* lose half hit points*/
   1243 					}
   1244 	if (k>0)
   1245 		{
   1246 		lprcat("\nYou hear loud screams of agony!");	raiseexperience((long)k);
   1247 		}
   1248 	return(k);
   1249 	}
   1250 
   1251 /*
   1252  *	newsphere(x,y,dir,lifetime)  Function to create a new sphere of annihilation
   1253  *		int x,y,dir,lifetime;
   1254  *
   1255  *	Enter with the coordinates of the sphere in x,y
   1256  *	  the direction (0-8 diroffx format) in dir, and the lifespan of the
   1257  *	  sphere in lifetime (in turns)
   1258  *	Returns the number of spheres currently in existence
   1259  */
   1260 newsphere(x,y,dir,life)
   1261 	int x,y,dir,life;
   1262 	{
   1263 	int m;
   1264 	struct sphere *sp;
   1265 	if (((sp=(struct sphere *)malloc(sizeof(struct sphere)))) == 0)
   1266 		return(c[SPHCAST]);	/* can't malloc, therefore failure */
   1267 	if (dir>=9) dir=0;	/* no movement if direction not found */
   1268 	if (level==0) vxy(&x,&y);	/* don't go out of bounds */
   1269 	else
   1270 		{
   1271 		if (x<1) x=1;  if (x>=MAXX-1) x=MAXX-2;
   1272 		if (y<1) y=1;  if (y>=MAXY-1) y=MAXY-2;
   1273 		}
   1274 	if ((m=mitem[x][y]) >= DEMONLORD+4)	/* demons dispel spheres */
   1275 		{
   1276 		know[x][y]=1; show1cell(x,y);	/* show the demon (ha ha) */
   1277 		cursors(); lprintf("\nThe %s dispels the sphere!",monster[m].name);
   1278 		beep(); rmsphere(x,y);	/* remove any spheres that are here */
   1279 		return(c[SPHCAST]);
   1280 		}
   1281 	if (m==DISENCHANTRESS) /* disenchantress cancels spheres */
   1282 		{
   1283 		cursors(); lprintf("\nThe %s causes cancellation of the sphere!",monster[m].name); beep();
   1284 boom:	sphboom(x,y);	/* blow up stuff around sphere */
   1285 		rmsphere(x,y);	/* remove any spheres that are here */
   1286 		return(c[SPHCAST]);
   1287 		}
   1288 	if (c[CANCELLATION]) /* cancellation cancels spheres */
   1289 		{
   1290 		cursors(); lprcat("\nAs the cancellation takes effect, you hear a great earth shaking blast!"); beep();
   1291 		goto boom;
   1292 		}
   1293 	if (item[x][y]==OANNIHILATION) /* collision of spheres detonates spheres */
   1294 		{
   1295 		cursors(); lprcat("\nTwo spheres of annihilation collide! You hear a great earth shaking blast!"); beep();
   1296 		rmsphere(x,y);
   1297 		goto boom;
   1298 		}
   1299 	if (playerx==x && playery==y) /* collision of sphere and player! */
   1300 		{
   1301 		cursors();
   1302 		lprcat("\nYou have been enveloped by the zone of nothingness!\n");
   1303 		beep(); rmsphere(x,y);	/* remove any spheres that are here */
   1304 		nap(4000);  died(258);
   1305 		}
   1306 	item[x][y]=OANNIHILATION;  mitem[x][y]=0;  know[x][y]=1;
   1307 	show1cell(x,y);	/* show the new sphere */
   1308 	sp->x=x;  sp->y=y;  sp->lev=level;  sp->dir=dir;  sp->lifetime=life;  sp->p=0;
   1309 	if (spheres==0) spheres=sp;	/* if first node in the sphere list */
   1310 	else	/* add sphere to beginning of linked list */
   1311 		{
   1312 		sp->p = spheres;	spheres = sp;
   1313 		}
   1314 	return(++c[SPHCAST]);	/* one more sphere in the world */
   1315 	}
   1316 
   1317 /*
   1318  *	rmsphere(x,y)		Function to delete a sphere of annihilation from list
   1319  *		int x,y;
   1320  *
   1321  *	Enter with the coordinates of the sphere (on current level)
   1322  *	Returns the number of spheres currently in existence
   1323  */
   1324 rmsphere(x,y)
   1325 	int x,y;
   1326 	{
   1327 	register struct sphere *sp,*sp2=0;
   1328 	for (sp=spheres; sp; sp2=sp,sp=sp->p)
   1329 	  if (level==sp->lev)	/* is sphere on this level? */
   1330 	    if ((x==sp->x) && (y==sp->y))	/* locate sphere at this location */
   1331 			{
   1332 			item[x][y]=mitem[x][y]=0;  know[x][y]=1;
   1333 			show1cell(x,y);	/* show the now missing sphere */
   1334 			--c[SPHCAST];
   1335 			if (sp==spheres) { sp2=sp; spheres=sp->p; free((char*)sp2); }
   1336 			else
   1337 				{ sp2->p = sp->p;  free((char*)sp); }
   1338 			break;
   1339 			}
   1340 	return(c[SPHCAST]);	/* return number of spheres in the world */
   1341 	}
   1342 
   1343 /*
   1344  *	sphboom(x,y)	Function to perform the effects of a sphere detonation
   1345  *		int x,y;
   1346  *
   1347  *	Enter with the coordinates of the blast, Returns no value
   1348  */
   1349 sphboom(x,y)
   1350 	int x,y;
   1351 	{
   1352 	register int i,j;
   1353 	if (c[HOLDMONST]) c[HOLDMONST]=1;
   1354 	if (c[CANCELLATION]) c[CANCELLATION]=1;
   1355 	for (j=max(1,x-2); j<min(x+3,MAXX-1); j++)
   1356 	  for (i=max(1,y-2); i<min(y+3,MAXY-1); i++)
   1357 		{
   1358 		item[j][i]=mitem[j][i]=0;
   1359 		show1cell(j,i);
   1360 		if (playerx==j && playery==i)
   1361 			{
   1362 			cursors(); beep();
   1363 			lprcat("\nYou were too close to the sphere!");
   1364 			nap(3000);
   1365 			died(283); /* player killed in explosion */
   1366 			}
   1367 		}
   1368 	}
   1369 
   1370 /*
   1371  *	genmonst()		Function to ask for monster and genocide from game
   1372  *
   1373  *	This is done by setting a flag in the monster[] structure
   1374  */
   1375 genmonst()
   1376 	{
   1377 	register int i,j;
   1378 	cursors();  lprcat("\nGenocide what monster? ");
   1379 	for (i=0; (!isalpha(i)) && (i!=' '); i=getchar());
   1380 	lprc(i);
   1381 	for (j=0; j<MAXMONST; j++)	/* search for the monster type */
   1382 		if (monstnamelist[j]==i)	/* have we found it? */
   1383 			{
   1384 			monster[j].genocided=1;	/* genocided from game */
   1385 			lprintf("  There will be no more %s's",monster[j].name);
   1386 			/* now wipe out monsters on this level */
   1387 			newcavelevel(level); draws(0,MAXX,0,MAXY); bot_linex();
   1388 			return;
   1389 			}
   1390 	lprcat("  You sense failure!");
   1391 	}
   1392 
   1393