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