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