xref: /dragonfly/games/larn/monster.c (revision 2cd2d2b5)
1 /*
2  *	monster.c		Larn is copyrighted 1986 by Noah Morgan.
3  * $FreeBSD: src/games/larn/monster.c,v 1.6 1999/11/16 11:47:40 marcel Exp $
4  * $DragonFly: src/games/larn/monster.c,v 1.2 2003/06/17 04:25:24 dillon Exp $
5  *
6  *	This file contains the following functions:
7  *	----------------------------------------------------------------------------
8  *
9  *	createmonster(monstno) 		Function to create a monster next to the player
10  *		int monstno;
11  *
12  *	int cgood(x,y,itm,monst)	Function to check location for emptiness
13  *		int x,y,itm,monst;
14  *
15  *	createitem(it,arg) 			Routine to place an item next to the player
16  *		int it,arg;
17  *
18  *	cast() 				Subroutine called by parse to cast a spell for the user
19  *
20  *	speldamage(x) 		Function to perform spell functions cast by the player
21  *		int x;
22  *
23  *	loseint()			Routine to decrement your int (intelligence) if > 3
24  *
25  *	isconfuse() 		Routine to check to see if player is confused
26  *
27  *	nospell(x,monst)	Routine to return 1 if a spell doesn't affect a monster
28  *		int x,monst;
29  *
30  *	fullhit(xx)			Function to return full damage against a monst (aka web)
31  *		int xx;
32  *
33  *	direct(spnum,dam,str,arg)	Routine to direct spell damage 1 square in 1 dir
34  *		int spnum,dam,arg;
35  *		char *str;
36  *
37  *	godirect(spnum,dam,str,delay,cshow)		Function to perform missile attacks
38  *		int spnum,dam,delay;
39  *		char *str,cshow;
40  *
41  *	ifblind(x,y)	Routine to put "monster" or the monster name into lastmosnt
42  *		int x,y;
43  *
44  *	tdirect(spnum)			Routine to teleport away a monster
45  *		int spnum;
46  *
47  *	omnidirect(sp,dam,str)  Routine to damage all monsters 1 square from player
48  *		int sp,dam;
49  *		char *str;
50  *
51  *	dirsub(x,y)			Routine to ask for direction, then modify x,y for it
52  *		int *x,*y;
53  *
54  *	vxy(x,y)		  	Routine to verify/fix (*x,*y) for being within bounds
55  *		int *x,*y;
56  *
57  *	dirpoly(spnum)		Routine to ask for a direction and polymorph a monst
58  *		int spnum;
59  *
60  *	hitmonster(x,y) 	Function to hit a monster at the designated coordinates
61  *		int x,y;
62  *
63  *	hitm(x,y,amt)		Function to just hit a monster at a given coordinates
64  *		int x,y,amt;
65  *
66  *	hitplayer(x,y) 		Function for the monster to hit the player from (x,y)
67  *		int x,y;
68  *
69  *	dropsomething(monst) 	Function to create an object when a monster dies
70  *		int monst;
71  *
72  *	dropgold(amount) 		Function to drop some gold around player
73  *		int amount;
74  *
75  *	something(level) 		Function to create a random item around player
76  *		int level;
77  *
78  *	newobject(lev,i) 		Routine to return a randomly selected new object
79  *		int lev,*i;
80  *
81  *  spattack(atckno,xx,yy) 	Function to process special attacks from monsters
82  *  	int atckno,xx,yy;
83  *
84  *	checkloss(x) 	Routine to subtract hp from user and flag bottomline display
85  *		int x;
86  *
87  *	annihilate()   Routine to annihilate monsters around player, playerx,playery
88  *
89  *	newsphere(x,y,dir,lifetime)  Function to create a new sphere of annihilation
90  *		int x,y,dir,lifetime;
91  *
92  *	rmsphere(x,y)		Function to delete a sphere of annihilation from list
93  *		int x,y;
94  *
95  *	sphboom(x,y)		Function to perform the effects of a sphere detonation
96  *		int x,y;
97  *
98  *	genmonst()			Function to ask for monster and genocide from game
99  *
100  */
101 #include "header.h"
102 
103 struct isave	/* used for altar reality */
104 	{
105 	char type;	/* 0=item,  1=monster */
106 	char id;	/* item number or monster number */
107 	short arg;	/* the type of item or hitpoints of monster */
108 	};
109 
110 /*
111  *	createmonster(monstno) 		Function to create a monster next to the player
112  *		int monstno;
113  *
114  *	Enter with the monster number (1 to MAXMONST+8)
115  *	Returns no value.
116  */
117 createmonster(mon)
118 	int mon;
119 	{
120 	int x,y,k,i;
121 	if (mon<1 || mon>MAXMONST+8)	/* check for monster number out of bounds */
122 		{
123 		beep(); lprintf("\ncan't createmonst(%d)\n",(long)mon); nap(3000); return;
124 		}
125 	while (monster[mon].genocided && mon<MAXMONST) mon++; /* genocided? */
126 	for (k=rnd(8), i= -8; i<0; i++,k++)	/* choose direction, then try all */
127 		{
128 		if (k>8) k=1;	/* wraparound the diroff arrays */
129 		x = playerx + diroffx[k];		y = playery + diroffy[k];
130 		if (cgood(x,y,0,1))	/* if we can create here */
131 			{
132 			mitem[x][y] = mon;
133 			hitp[x][y] = monster[mon].hitpoints;
134 			stealth[x][y]=know[x][y]=0;
135 			switch(mon)
136 				{
137 				case ROTHE: case POLTERGEIST: case VAMPIRE: stealth[x][y]=1;
138 				};
139 			return;
140 			}
141 		}
142 	}
143 
144 /*
145  *	int cgood(x,y,itm,monst)	  Function to check location for emptiness
146  *		int x,y,itm,monst;
147  *
148  *	Routine to return TRUE if a location does not have itm or monst there
149  *	returns FALSE (0) otherwise
150  *	Enter with itm or monst TRUE or FALSE if checking it
151  *	Example:  if itm==TRUE check for no item at this location
152  *			  if monst==TRUE check for no monster at this location
153  *	This routine will return FALSE if at a wall or the dungeon exit on level 1
154  */
155 int cgood(x,y,itm,monst)
156 	int x,y;
157 	int itm,monst;
158 	{
159 	if ((y>=0) && (y<=MAXY-1) && (x>=0) && (x<=MAXX-1)) /* within bounds? */
160 	  if (item[x][y]!=OWALL)	/* can't make anything on walls */
161 		if (itm==0 || (item[x][y]==0))	/* is it free of items? */
162 		  if (monst==0 || (mitem[x][y]==0))	/* is it free of monsters? */
163 		    if ((level!=1) || (x!=33) || (y!=MAXY-1)) /* not exit to level 1 */
164 			  return(1);
165 	return(0);
166 	}
167 
168 /*
169  *	createitem(it,arg) 		Routine to place an item next to the player
170  *		int it,arg;
171  *
172  *	Enter with the item number and its argument (iven[], ivenarg[])
173  *	Returns no value, thus we don't know about createitem() failures.
174  */
175 createitem(it,arg)
176 	int it,arg;
177 	{
178 	int x,y,k,i;
179 	if (it >= MAXOBJ) return;	/* no such object */
180 	for (k=rnd(8), i= -8; i<0; i++,k++)	/* choose direction, then try all */
181 		{
182 		if (k>8) k=1;	/* wraparound the diroff arrays */
183 		x = playerx + diroffx[k];		y = playery + diroffy[k];
184 		if (cgood(x,y,1,0))	/* if we can create here */
185 			{
186 			item[x][y] = it;  know[x][y]=0;  iarg[x][y]=arg;  return;
187 			}
188 		}
189 	}
190 
191 /*
192  *	cast() 		Subroutine called by parse to cast a spell for the user
193  *
194  *	No arguments and no return value.
195  */
196 static char eys[] = "\nEnter your spell: ";
197 cast()
198 	{
199 	int i,j,a,b,d;
200 	cursors();
201 	if (c[SPELLS]<=0) {	lprcat("\nYou don't have any spells!");	return;	}
202 	lprcat(eys);		--c[SPELLS];
203 	while ((a=getchar())=='D')
204 		{ seemagic(-1); cursors();  lprcat(eys); }
205 	if (a=='\33') goto over; /*	to escape casting a spell	*/
206 	if ((b=getchar())=='\33') goto over; /*	to escape casting a spell	*/
207 	if ((d=getchar())=='\33')
208 		{ over: lprcat(aborted); c[SPELLS]++; return; } /*	to escape casting a spell	*/
209 #ifdef EXTRA
210 	c[SPELLSCAST]++;
211 #endif
212 	for (lprc('\n'),j= -1,i=0; i<SPNUM; i++) /*seq search for his spell, hash?*/
213 		if ((spelcode[i][0]==a) && (spelcode[i][1]==b) && (spelcode[i][2]==d))
214 			if (spelknow[i])
215 				{  speldamage(i);  j = 1;  i=SPNUM; }
216 
217 	if (j == -1) lprcat("  Nothing Happened ");
218 	bottomline();
219 	}
220 
221 static int dirsub();
222 
223 /*
224  *	speldamage(x) 		Function to perform spell functions cast by the player
225  *		int x;
226  *
227  *	Enter with the spell number, returns no value.
228  *	Please insure that there are 2 spaces before all messages here
229  */
230 speldamage(x)
231 	int x;
232 	{
233 	int i,j,clev;
234 	int xl,xh,yl,yh;
235 	char *p,*kn,*pm;
236 	if (x>=SPNUM) return;	/* no such spell */
237 	if (c[TIMESTOP])  { lprcat("  It didn't seem to work"); return; }  /* not if time stopped */
238 	clev = c[LEVEL];
239 	if ((rnd(23)==7) || (rnd(18) > c[INTELLIGENCE]))
240 		{ lprcat("  It didn't work!");  return; }
241 	if (clev*3+2 < x) { lprcat("  Nothing happens.  You seem inexperienced at this"); return; }
242 
243 	switch(x)
244 		{
245 /* ----- LEVEL 1 SPELLS ----- */
246 
247 		case 0:	if (c[PROTECTIONTIME]==0)	c[MOREDEFENSES]+=2; /* protection field +2 */
248 				c[PROTECTIONTIME] += 250;   return;
249 
250 		case 1: i = rnd(((clev+1)<<1)) + clev + 3;
251 				godirect(x,i,(clev>=2)?"  Your missiles hit the %s":"  Your missile hit the %s",100,'+'); /* magic missile */
252 
253 				return;
254 
255 		case 2:	if (c[DEXCOUNT]==0)	c[DEXTERITY]+=3; /*	dexterity	*/
256 				c[DEXCOUNT] += 400;  	return;
257 
258 		case 3: i=rnd(3)+1;
259 				p="  While the %s slept, you smashed it %d times";
260 			ws:	direct(x,fullhit(i),p,i); /*	sleep	*/	return;
261 
262 		case 4:	/*	charm monster	*/	c[CHARMCOUNT] += c[CHARISMA]<<1;	return;
263 
264 		case 5:	godirect(x,rnd(10)+15+clev,"  The sound damages the %s",70,'@'); /*	sonic spear */
265 				return;
266 
267 /* ----- LEVEL 2 SPELLS ----- */
268 
269 		case 6: i=rnd(3)+2;	p="  While the %s is entangled, you hit %d times";
270 				goto ws; /* web */
271 
272 		case 7:	if (c[STRCOUNT]==0) c[STREXTRA]+=3;	/*	strength	*/
273 				c[STRCOUNT] += 150+rnd(100);    return;
274 
275 		case 8:	yl = playery-5;     /* enlightenment */
276 				yh = playery+6;   xl = playerx-15;   xh = playerx+16;
277 				vxy(&xl,&yl);   vxy(&xh,&yh); /* check bounds */
278 				for (i=yl; i<=yh; i++) /* enlightenment	*/
279 					for (j=xl; j<=xh; j++)	know[j][i]=1;
280 				draws(xl,xh+1,yl,yh+1);	return;
281 
282 		case 9:	raisehp(20+(clev<<1));  return;  /* healing */
283 
284 		case 10:	c[BLINDCOUNT]=0;	return;	/* cure blindness	*/
285 
286 		case 11:	createmonster(makemonst(level+1)+8);  return;
287 
288 		case 12:	if (rnd(11)+7 <= c[WISDOM]) direct(x,rnd(20)+20+clev,"  The %s believed!",0);
289 					else lprcat("  It didn't believe the illusions!");
290 					return;
291 
292 		case 13:	/* if he has the amulet of invisibility then add more time */
293 					for (j=i=0; i<26; i++)
294 						if (iven[i]==OAMULET) j+= 1+ivenarg[i];
295 					c[INVISIBILITY] += (j<<7)+12;   return;
296 
297 /* ----- LEVEL 3 SPELLS ----- */
298 
299 		case 14:	godirect(x,rnd(25+clev)+25+clev,"  The fireball hits the %s",40,'*'); return; /*	fireball */
300 
301 		case 15:	godirect(x,rnd(25)+20+clev,"  Your cone of cold strikes the %s",60,'O');	/*	cold */
302 					return;
303 
304 		case 16:	dirpoly(x);  return;	/*	polymorph */
305 
306 		case 17:	c[CANCELLATION]+= 5+clev;	return;	/*	cancellation	*/
307 
308 		case 18:	c[HASTESELF]+= 7+clev;  return;  /*	haste self	*/
309 
310 		case 19:	omnidirect(x,30+rnd(10),"  The %s gasps for air");	/* cloud kill */
311 					return;
312 
313 		case 20:	xh = min(playerx+1,MAXX-2);		yh = min(playery+1,MAXY-2);
314 					for (i=max(playerx-1,1); i<=xh; i++) /* vaporize rock */
315 					  for (j=max(playery-1,1); j<=yh; j++)
316 						{
317 						kn = &know[i][j];    pm = &mitem[i][j];
318 						switch(*(p= &item[i][j]))
319 						  {
320 						  case OWALL: if (level < MAXLEVEL+MAXVLEVEL-1)
321 											*p = *kn = 0;
322 										break;
323 
324 						  case OSTATUE: if (c[HARDGAME]<3)
325 											 {
326 											 *p=OBOOK; iarg[i][j]=level;  *kn=0;
327 											 }
328 										break;
329 
330 						  case OTHRONE: *pm=GNOMEKING;  *kn=0;  *p= OTHRONE2;
331 										hitp[i][j]=monster[GNOMEKING].hitpoints; break;
332 
333 						  case OALTAR:	*pm=DEMONPRINCE;  *kn=0;
334 										hitp[i][j]=monster[DEMONPRINCE].hitpoints; break;
335 						  };
336 						switch(*pm)
337 							{
338 							case XORN:	ifblind(i,j);  hitm(i,j,200); break; /* Xorn takes damage from vpr */
339 							}
340 						}
341 					return;
342 
343 /* ----- LEVEL 4 SPELLS ----- */
344 
345 		case 21:	direct(x,100+clev,"  The %s shrivels up",0); /* dehydration */
346 					return;
347 
348 		case 22:	godirect(x,rnd(25)+20+(clev<<1),"  A lightning bolt hits the %s",1,'~');	/*	lightning */
349 					return;
350 
351 		case 23:	i=min(c[HP]-1,c[HPMAX]/2);	/* drain life */
352 					direct(x,i+i,"",0);	c[HP] -= i;  	return;
353 
354 		case 24:	if (c[GLOBE]==0) c[MOREDEFENSES] += 10;
355 					c[GLOBE] += 200;  loseint();  /* globe of invulnerability */
356 					return;
357 
358 		case 25:	omnidirect(x,32+clev,"  The %s struggles for air in your flood!"); /* flood */
359 					return;
360 
361 		case 26:	if (rnd(151)==63) { beep(); lprcat("\nYour heart stopped!\n"); nap(4000);  died(270); return; }
362 					if (c[WISDOM]>rnd(10)+10) direct(x,2000,"  The %s's heart stopped",0); /* finger of death */
363 					else lprcat("  It didn't work"); return;
364 
365 /* ----- LEVEL 5 SPELLS ----- */
366 
367 		case 27:	c[SCAREMONST] += rnd(10)+clev;  return;  /* scare monster */
368 
369 		case 28:	c[HOLDMONST] += rnd(10)+clev;  return;  /* hold monster */
370 
371 		case 29:	c[TIMESTOP] += rnd(20)+(clev<<1);  return;  /* time stop */
372 
373 		case 30:	tdirect(x);  return;  /* teleport away */
374 
375 		case 31:	omnidirect(x,35+rnd(10)+clev,"  The %s cringes from the flame"); /* magic fire */
376 					return;
377 
378 /* ----- LEVEL 6 SPELLS ----- */
379 
380 		case 32:	if ((rnd(23)==5) && (wizard==0)) /* sphere of annihilation */
381 						{
382 						beep(); lprcat("\nYou have been enveloped by the zone of nothingness!\n");
383 						nap(4000);  died(258); return;
384 						}
385 					xl=playerx; yl=playery;
386 					loseint();
387 					i=dirsub(&xl,&yl); /* get direction of sphere */
388 					newsphere(xl,yl,i,rnd(20)+11);	/* make a sphere */
389 					return;
390 
391 		case 33:	genmonst();  spelknow[33]=0;  /* genocide */
392 					loseint();
393 					return;
394 
395 		case 34:	/* summon demon */
396 					if (rnd(100) > 30) { direct(x,150,"  The demon strikes at the %s",0);  return; }
397 					if (rnd(100) > 15) { lprcat("  Nothing seems to have happened");  return; }
398 					lprcat("  The demon turned on you and vanished!"); beep();
399 					i=rnd(40)+30;  lastnum=277;
400 					losehp(i); /* must say killed by a demon */ return;
401 
402 		case 35:	/* walk through walls */
403 					c[WTW] += rnd(10)+5;	return;
404 
405 		case 36:	/* alter reality */
406 					{
407 					struct isave *save;	/* pointer to item save structure */
408 					int sc;	sc=0;	/* # items saved */
409 					save = (struct isave *)malloc(sizeof(struct isave)*MAXX*MAXY*2);
410 					for (j=0; j<MAXY; j++)
411 						for (i=0; i<MAXX; i++) /* save all items and monsters */
412 							{
413 							xl = item[i][j];
414 							if (xl && xl!=OWALL && xl!=OANNIHILATION)
415 								{
416 								save[sc].type=0;  save[sc].id=item[i][j];
417 								save[sc++].arg=iarg[i][j];
418 								}
419 							if (mitem[i][j])
420 								{
421 								save[sc].type=1;  save[sc].id=mitem[i][j];
422 								save[sc++].arg=hitp[i][j];
423 								}
424 							item[i][j]=OWALL;   mitem[i][j]=0;
425 							if (wizard) know[i][j]=1; else know[i][j]=0;
426 							}
427 					eat(1,1);	if (level==1) item[33][MAXY-1]=0;
428 					for (j=rnd(MAXY-2), i=1; i<MAXX-1; i++) item[i][j]=0;
429 					while (sc>0) /* put objects back in level */
430 						{
431 						--sc;
432 						if (save[sc].type == 0)
433 							{
434 							int trys;
435 							for (trys=100, i=j=1; --trys>0 && item[i][j]; i=rnd(MAXX-1), j=rnd(MAXY-1));
436 							if (trys) { item[i][j]=save[sc].id; iarg[i][j]=save[sc].arg; }
437 							}
438 						else
439 							{ /* put monsters back in */
440 							int trys;
441 							for (trys=100, i=j=1; --trys>0 && (item[i][j]==OWALL || mitem[i][j]); i=rnd(MAXX-1), j=rnd(MAXY-1));
442 							if (trys) { mitem[i][j]=save[sc].id; hitp[i][j]=save[sc].arg; }
443 							}
444 						}
445 					loseint();
446 					draws(0,MAXX,0,MAXY);  if (wizard==0) spelknow[36]=0;
447 					free((char*)save);	 positionplayer();  return;
448 					}
449 
450 		case 37:	/* permanence */ adjtime(-99999L);  spelknow[37]=0; /* forget */
451 					loseint();
452 					return;
453 
454 		default:	lprintf("  spell %d not available!",(long)x); beep();  return;
455 		};
456 	}
457 
458 /*
459  *	loseint()		Routine to subtract 1 from your int (intelligence) if > 3
460  *
461  *	No arguments and no return value
462  */
463 loseint()
464 	{
465 	if (--c[INTELLIGENCE]<3)  c[INTELLIGENCE]=3;
466 	}
467 
468 /*
469  *	isconfuse() 		Routine to check to see if player is confused
470  *
471  *	This routine prints out a message saying "You can't aim your magic!"
472  *	returns 0 if not confused, non-zero (time remaining confused) if confused
473  */
474 isconfuse()
475 	{
476 	if (c[CONFUSE]) { lprcat(" You can't aim your magic!"); beep(); }
477 	return(c[CONFUSE]);
478 	}
479 
480 /*
481  *	nospell(x,monst)	Routine to return 1 if a spell doesn't affect a monster
482  *		int x,monst;
483  *
484  *	Subroutine to return 1 if the spell can't affect the monster
485  *	  otherwise returns 0
486  *	Enter with the spell number in x, and the monster number in monst.
487  */
488 nospell(x,monst)
489 	int x,monst;
490 	{
491 	int tmp;
492 	if (x>=SPNUM || monst>=MAXMONST+8 || monst<0 || x<0) return(0);	/* bad spell or monst */
493 	if ((tmp=spelweird[monst-1][x])==0) return(0);
494 	cursors();  lprc('\n');  lprintf(spelmes[tmp],monster[monst].name);  return(1);
495 	}
496 
497 /*
498  *	fullhit(xx)		Function to return full damage against a monster (aka web)
499  *		int xx;
500  *
501  *	Function to return hp damage to monster due to a number of full hits
502  *	Enter with the number of full hits being done
503  */
504 fullhit(xx)
505 	int xx;
506 	{
507 	int i;
508 	if (xx<0 || xx>20) return(0);	/* fullhits are out of range */
509 	if (c[LANCEDEATH]) return(10000);	/* lance of death */
510 	i = xx * ((c[WCLASS]>>1)+c[STRENGTH]+c[STREXTRA]-c[HARDGAME]-12+c[MOREDAM]);
511 	return( (i>=1) ? i : xx );
512 	}
513 
514 /*
515  *	direct(spnum,dam,str,arg)	Routine to direct spell damage 1 square in 1 dir
516  *		int spnum,dam,arg;
517  *		char *str;
518  *
519  *	Routine to ask for a direction to a spell and then hit the monster
520  *	Enter with the spell number in spnum, the damage to be done in dam,
521  *	  lprintf format string in str, and lprintf's argument in arg.
522  *	Returns no value.
523  */
524 direct(spnum,dam,str,arg)
525 	int spnum,dam,arg;
526 	char *str;
527 	{
528 	int x,y;
529 	int m;
530 	if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad arguments */
531 	if (isconfuse()) return;
532 	dirsub(&x,&y);
533 	m = mitem[x][y];
534 	if (item[x][y]==OMIRROR)
535 		{
536 		if (spnum==3) /* sleep */
537 			{
538 			lprcat("You fall asleep! "); beep();
539 		fool:
540 			arg += 2;
541 			while (arg-- > 0) { parse2(); nap(1000); }
542 			return;
543 			}
544 		else if (spnum==6) /* web */
545 			{
546 			lprcat("You get stuck in your own web! "); beep();
547 			goto fool;
548 			}
549 		else
550 			{
551 			lastnum=278;
552 			lprintf(str,"spell caster (thats you)",(long)arg);
553 			beep(); losehp(dam); return;
554 			}
555 		}
556 	if (m==0)
557 		{	lprcat("  There wasn't anything there!");	return;  }
558 	ifblind(x,y);
559 	if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
560 	lprintf(str,lastmonst,(long)arg);       hitm(x,y,dam);
561 	}
562 
563 /*
564  *	godirect(spnum,dam,str,delay,cshow)		Function to perform missile attacks
565  *		int spnum,dam,delay;
566  *		char *str,cshow;
567  *
568  *	Function to hit in a direction from a missile weapon and have it keep
569  *	on going in that direction until its power is exhausted
570  *	Enter with the spell number in spnum, the power of the weapon in hp,
571  *	  lprintf format string in str, the # of milliseconds to delay between
572  *	  locations in delay, and the character to represent the weapon in cshow.
573  *	Returns no value.
574  */
575 godirect(spnum,dam,str,delay,cshow)
576 	int spnum,dam,delay;
577 	char *str,cshow;
578 	{
579 	char *p;
580 	int x,y,m;
581 	int dx,dy;
582 	if (spnum<0 || spnum>=SPNUM || str==0 || delay<0) return; /* bad args */
583 	if (isconfuse()) return;
584 	dirsub(&dx,&dy);	x=dx;	y=dy;
585 	dx = x-playerx;		dy = y-playery;		x = playerx;	y = playery;
586 	while (dam>0)
587 		{
588 		x += dx;    y += dy;
589 	    if ((x > MAXX-1) || (y > MAXY-1) || (x < 0) || (y < 0))
590 			{
591 			dam=0;	break;  /* out of bounds */
592 			}
593 		if ((x==playerx) && (y==playery)) /* if energy hits player */
594 			{
595 			cursors(); lprcat("\nYou are hit my your own magic!"); beep();
596 			lastnum=278;  losehp(dam);  return;
597 			}
598 		if (c[BLINDCOUNT]==0) /* if not blind show effect */
599 			{
600 			cursor(x+1,y+1); lprc(cshow); nap(delay); show1cell(x,y);
601 			}
602 		if ((m=mitem[x][y]))	/* is there a monster there? */
603 			{
604 			ifblind(x,y);
605 			if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
606 			cursors(); lprc('\n');
607 			lprintf(str,lastmonst);		dam -= hitm(x,y,dam);
608 			show1cell(x,y);  nap(1000);		x -= dx;	y -= dy;
609 			}
610 		else switch (*(p= &item[x][y]))
611 			{
612 			case OWALL:	cursors(); lprc('\n'); lprintf(str,"wall");
613 						if (dam>=50+c[HARDGAME]) /* enough damage? */
614 						 if (level<MAXLEVEL+MAXVLEVEL-1) /* not on V3 */
615 						  if ((x<MAXX-1) && (y<MAXY-1) && (x) && (y))
616 							{
617 							lprcat("  The wall crumbles");
618 					god3:	*p=0;
619 					god:	know[x][y]=0;
620 							show1cell(x,y);
621 							}
622 				god2:	dam = 0;	break;
623 
624 			case OCLOSEDDOOR:	cursors(); lprc('\n'); lprintf(str,"door");
625 						if (dam>=40)
626 							{
627 							lprcat("  The door is blasted apart");
628 							goto god3;
629 							}
630 						goto god2;
631 
632 			case OSTATUE:	cursors(); lprc('\n'); lprintf(str,"statue");
633 						if (c[HARDGAME]<3)
634 						  if (dam>44)
635 							{
636 							lprcat("  The statue crumbles");
637 							*p=OBOOK; iarg[x][y]=level;
638 							goto god;
639 							}
640 						goto god2;
641 
642 			case OTHRONE:	cursors(); lprc('\n'); lprintf(str,"throne");
643 					if (dam>39)
644 						{
645 						mitem[x][y]=GNOMEKING; hitp[x][y]=monster[GNOMEKING].hitpoints;
646 						*p = OTHRONE2;
647 						goto god;
648 						}
649 					goto god2;
650 
651 			case OMIRROR:	dx *= -1;	dy *= -1;	break;
652 			};
653 		dam -= 3 + (c[HARDGAME]>>1);
654 		}
655 	}
656 
657 /*
658  *	ifblind(x,y)	Routine to put "monster" or the monster name into lastmosnt
659  *		int x,y;
660  *
661  *	Subroutine to copy the word "monster" into lastmonst if the player is blind
662  *	Enter with the coordinates (x,y) of the monster
663  *	Returns no value.
664  */
665 ifblind(x,y)
666 	int x,y;
667 	{
668 	char *p;
669 	vxy(&x,&y);	/* verify correct x,y coordinates */
670 	if (c[BLINDCOUNT]) { lastnum=279;  p="monster"; }
671 		else { lastnum=mitem[x][y];  p=monster[lastnum].name; }
672 	strcpy(lastmonst,p);
673 	}
674 
675 /*
676  *	tdirect(spnum)		Routine to teleport away a monster
677  *		int spnum;
678  *
679  *	Routine to ask for a direction to a spell and then teleport away monster
680  *	Enter with the spell number that wants to teleport away
681  *	Returns no value.
682  */
683 tdirect(spnum)
684 	int spnum;
685 	{
686 	int x,y;
687 	int m;
688 	if (spnum<0 || spnum>=SPNUM) return; /* bad args */
689 	if (isconfuse()) return;
690 	dirsub(&x,&y);
691 	if ((m=mitem[x][y])==0)
692 		{	lprcat("  There wasn't anything there!");	return;  }
693 	ifblind(x,y);
694 	if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
695 	fillmonst(m);  mitem[x][y]=know[x][y]=0;
696 	}
697 
698 /*
699  *	omnidirect(sp,dam,str)   Routine to damage all monsters 1 square from player
700  *		int sp,dam;
701  *		char *str;
702  *
703  *	Routine to cast a spell and then hit the monster in all directions
704  *	Enter with the spell number in sp, the damage done to wach square in dam,
705  *	  and the lprintf string to identify the spell in str.
706  *	Returns no value.
707  */
708 omnidirect(spnum,dam,str)
709 	int spnum,dam;
710 	char *str;
711 	{
712 	int x,y,m;
713 	if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad args */
714 	for (x=playerx-1; x<playerx+2; x++)
715 		for (y=playery-1; y<playery+2; y++)
716 			{
717 			if (m=mitem[x][y])
718 				{
719 				if (nospell(spnum,m) == 0)
720 					{
721 					ifblind(x,y);
722 					cursors(); lprc('\n'); lprintf(str,lastmonst);
723 					hitm(x,y,dam);  nap(800);
724 					}
725 				else  { lasthx=x;  lasthy=y; }
726 				}
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 	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 	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 	int amt;
858 	{
859 	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 	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 	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 	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 	int lev,*i;
1017 	{
1018 	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 	int i,j=0,k,m;
1084 	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 				  {
1093 					if (--ivenarg[i] < -1) ivenarg[i]= -1; else j=1;
1094 				  }
1095 				if ((j==0) && (k != -1))
1096 				  {
1097 				  m = iven[k];
1098 				  for (i=0; i<ARMORTYPES; i++)
1099 					if (m == rustarm[i][0]) /* find his armor in table */
1100 						{
1101 						if (--ivenarg[k]< rustarm[i][1])
1102 							ivenarg[k]= rustarm[i][1]; else j=1;
1103 						break;
1104 						}
1105 				  }
1106 				if (j==0)	/* if rusting did not occur */
1107 				  switch(m)
1108 					{
1109 					case OLEATHER:	p = "\nThe %s hit you -- Your lucky you have leather on";
1110 									break;
1111 				    case OSSPLATE:	p = "\nThe %s hit you -- Your fortunate to have stainless steel armor!";
1112 									break;
1113 					}
1114 				else  { beep(); p = "\nThe %s hit you -- your armor feels weaker"; }
1115 				break;
1116 
1117 		case 2:		i = rnd(15)+8-c[AC];
1118 			spout:	p="\nThe %s breathes fire at you!";
1119 					if (c[FIRERESISTANCE])
1120 					  p="\nThe %s's flame doesn't phase you!";
1121 					else
1122 			spout2: if (p) { lprintf(p,lastmonst); beep(); }
1123 					checkloss(i);
1124 					return(0);
1125 
1126 		case 3:		i = rnd(20)+25-c[AC];  goto spout;
1127 
1128 		case 4:	if (c[STRENGTH]>3)
1129 					{
1130 					p="\nThe %s stung you!  You feel weaker"; beep();
1131 					--c[STRENGTH];
1132 					}
1133 				else p="\nThe %s stung you!";
1134 				break;
1135 
1136 		case 5:		p="\nThe %s blasts you with his cold breath";
1137 					i = rnd(15)+18-c[AC];  goto spout2;
1138 
1139 		case 6:		lprintf("\nThe %s drains you of your life energy!",lastmonst);
1140 					loselevel();  beep();  return(0);
1141 
1142 		case 7:		p="\nThe %s got you with a gusher!";
1143 					i = rnd(15)+25-c[AC];  goto spout2;
1144 
1145 		case 8:		if (c[NOTHEFT]) return(0); /* he has a device of no theft */
1146 					if (c[GOLD])
1147 						{
1148 						p="\nThe %s hit you -- Your purse feels lighter";
1149 						if (c[GOLD]>32767)  c[GOLD]>>=1;
1150 							else c[GOLD] -= rnd((int)(1+(c[GOLD]>>1)));
1151 						if (c[GOLD] < 0) c[GOLD]=0;
1152 						}
1153 					else  p="\nThe %s couldn't find any gold to steal";
1154 					lprintf(p,lastmonst); disappear(xx,yy); beep();
1155 					bottomgold();  return(1);
1156 
1157 		case 9:	for(j=50; ; )	/* disenchant */
1158 					{
1159 					i=rund(26);  m=iven[i]; /* randomly select item */
1160 					if (m>0 && ivenarg[i]>0 && m!=OSCROLL && m!=OPOTION)
1161 						{
1162 						if ((ivenarg[i] -= 3)<0) ivenarg[i]=0;
1163 						lprintf("\nThe %s hits you -- you feel a sense of loss",lastmonst);
1164 						srcount=0; beep(); show3(i);  bottomline();  return(0);
1165 						}
1166 					if (--j<=0)
1167 						{
1168 						p="\nThe %s nearly misses"; break;
1169 						}
1170 					break;
1171 					}
1172 				break;
1173 
1174 		case 10:   p="\nThe %s hit you with his barbed tail";
1175 				   i = rnd(25)-c[AC];  goto spout2;
1176 
1177 		case 11:	p="\nThe %s has confused you"; beep();
1178 					c[CONFUSE]+= 10+rnd(10);		break;
1179 
1180 		case 12:	/*	performs any number of other special attacks	*/
1181 					return(spattack(spsel[rund(10)],xx,yy));
1182 
1183 		case 13:	p="\nThe %s flattens you with his psionics!";
1184 					i = rnd(15)+30-c[AC];  goto spout2;
1185 
1186 		case 14:	if (c[NOTHEFT]) return(0); /* he has device of no theft */
1187 					if (emptyhanded()==1)
1188 					  {
1189 					  p="\nThe %s couldn't find anything to steal";
1190 					  break;
1191 					  }
1192 					lprintf("\nThe %s picks your pocket and takes:",lastmonst);
1193 					beep();
1194 					if (stealsomething()==0) lprcat("  nothing"); disappear(xx,yy);
1195 					bottomline();  return(1);
1196 
1197 		case 15:	i= rnd(10)+ 5-c[AC];
1198 			spout3:	p="\nThe %s bit you!";
1199 					goto spout2;
1200 
1201 		case 16:	i= rnd(15)+10-c[AC];  goto spout3;
1202 		};
1203 	if (p) { lprintf(p,lastmonst); bottomline(); }
1204 	return(0);
1205 	}
1206 
1207 /*
1208  *	checkloss(x) 	Routine to subtract hp from user and flag bottomline display
1209  *		int x;
1210  *
1211  *	Routine to subtract hitpoints from the user and flag the bottomline display
1212  *	Enter with the number of hit points to lose
1213  *	Note: if x > c[HP] this routine could kill the player!
1214  */
1215 checkloss(x)
1216 	int x;
1217 	{
1218 	if (x>0) { losehp(x);  bottomhp(); }
1219 	}
1220 
1221 /*
1222  *	annihilate() 	Routine to annihilate all monsters around player (playerx,playery)
1223  *
1224  *	Gives player experience, but no dropped objects
1225  *	Returns the experience gained from all monsters killed
1226  */
1227 annihilate()
1228 	{
1229 	int i,j;
1230 	long k;
1231 	char *p;
1232 	for (k=0, i=playerx-1; i<=playerx+1; i++)
1233 	  for (j=playery-1; j<=playery+1; j++)
1234 		if (!vxy(&i,&j)) /* if not out of bounds */
1235 			{
1236 			if (*(p= &mitem[i][j]))	/* if a monster there */
1237 				if (*p<DEMONLORD+2)
1238 					{
1239 					k += monster[*p].experience;	*p=know[i][j]=0;
1240 					}
1241 				else
1242 					{
1243 					lprintf("\nThe %s barely escapes being annihilated!",monster[*p].name);
1244 					hitp[i][j] = (hitp[i][j]>>1) + 1; /* lose half hit points*/
1245 					}
1246 			}
1247 	if (k>0)
1248 		{
1249 		lprcat("\nYou hear loud screams of agony!");	raiseexperience((long)k);
1250 		}
1251 	return(k);
1252 	}
1253 
1254 /*
1255  *	newsphere(x,y,dir,lifetime)  Function to create a new sphere of annihilation
1256  *		int x,y,dir,lifetime;
1257  *
1258  *	Enter with the coordinates of the sphere in x,y
1259  *	  the direction (0-8 diroffx format) in dir, and the lifespan of the
1260  *	  sphere in lifetime (in turns)
1261  *	Returns the number of spheres currently in existence
1262  */
1263 newsphere(x,y,dir,life)
1264 	int x,y,dir,life;
1265 	{
1266 	int m;
1267 	struct sphere *sp;
1268 	if (((sp=(struct sphere *)malloc(sizeof(struct sphere)))) == 0)
1269 		return(c[SPHCAST]);	/* can't malloc, therefore failure */
1270 	if (dir>=9) dir=0;	/* no movement if direction not found */
1271 	if (level==0) vxy(&x,&y);	/* don't go out of bounds */
1272 	else
1273 		{
1274 		if (x<1) x=1;  if (x>=MAXX-1) x=MAXX-2;
1275 		if (y<1) y=1;  if (y>=MAXY-1) y=MAXY-2;
1276 		}
1277 	if ((m=mitem[x][y]) >= DEMONLORD+4)	/* demons dispel spheres */
1278 		{
1279 		know[x][y]=1; show1cell(x,y);	/* show the demon (ha ha) */
1280 		cursors(); lprintf("\nThe %s dispels the sphere!",monster[m].name);
1281 		beep(); rmsphere(x,y);	/* remove any spheres that are here */
1282 		return(c[SPHCAST]);
1283 		}
1284 	if (m==DISENCHANTRESS) /* disenchantress cancels spheres */
1285 		{
1286 		cursors(); lprintf("\nThe %s causes cancellation of the sphere!",monster[m].name); beep();
1287 boom:	sphboom(x,y);	/* blow up stuff around sphere */
1288 		rmsphere(x,y);	/* remove any spheres that are here */
1289 		return(c[SPHCAST]);
1290 		}
1291 	if (c[CANCELLATION]) /* cancellation cancels spheres */
1292 		{
1293 		cursors(); lprcat("\nAs the cancellation takes effect, you hear a great earth shaking blast!"); beep();
1294 		goto boom;
1295 		}
1296 	if (item[x][y]==OANNIHILATION) /* collision of spheres detonates spheres */
1297 		{
1298 		cursors(); lprcat("\nTwo spheres of annihilation collide! You hear a great earth shaking blast!"); beep();
1299 		rmsphere(x,y);
1300 		goto boom;
1301 		}
1302 	if (playerx==x && playery==y) /* collision of sphere and player! */
1303 		{
1304 		cursors();
1305 		lprcat("\nYou have been enveloped by the zone of nothingness!\n");
1306 		beep(); rmsphere(x,y);	/* remove any spheres that are here */
1307 		nap(4000);  died(258);
1308 		}
1309 	item[x][y]=OANNIHILATION;  mitem[x][y]=0;  know[x][y]=1;
1310 	show1cell(x,y);	/* show the new sphere */
1311 	sp->x=x;  sp->y=y;  sp->lev=level;  sp->dir=dir;  sp->lifetime=life;  sp->p=0;
1312 	if (spheres==0) spheres=sp;	/* if first node in the sphere list */
1313 	else	/* add sphere to beginning of linked list */
1314 		{
1315 		sp->p = spheres;	spheres = sp;
1316 		}
1317 	return(++c[SPHCAST]);	/* one more sphere in the world */
1318 	}
1319 
1320 /*
1321  *	rmsphere(x,y)		Function to delete a sphere of annihilation from list
1322  *		int x,y;
1323  *
1324  *	Enter with the coordinates of the sphere (on current level)
1325  *	Returns the number of spheres currently in existence
1326  */
1327 rmsphere(x,y)
1328 	int x,y;
1329 	{
1330 	struct sphere *sp,*sp2=0;
1331 	for (sp=spheres; sp; sp2=sp,sp=sp->p)
1332 	  if (level==sp->lev)	/* is sphere on this level? */
1333 	    if ((x==sp->x) && (y==sp->y))	/* locate sphere at this location */
1334 			{
1335 			item[x][y]=mitem[x][y]=0;  know[x][y]=1;
1336 			show1cell(x,y);	/* show the now missing sphere */
1337 			--c[SPHCAST];
1338 			if (sp==spheres) { sp2=sp; spheres=sp->p; free((char*)sp2); }
1339 			else
1340 				{ sp2->p = sp->p;  free((char*)sp); }
1341 			break;
1342 			}
1343 	return(c[SPHCAST]);	/* return number of spheres in the world */
1344 	}
1345 
1346 /*
1347  *	sphboom(x,y)	Function to perform the effects of a sphere detonation
1348  *		int x,y;
1349  *
1350  *	Enter with the coordinates of the blast, Returns no value
1351  */
1352 sphboom(x,y)
1353 	int x,y;
1354 	{
1355 	int i,j;
1356 	if (c[HOLDMONST]) c[HOLDMONST]=1;
1357 	if (c[CANCELLATION]) c[CANCELLATION]=1;
1358 	for (j=max(1,x-2); j<min(x+3,MAXX-1); j++)
1359 	  for (i=max(1,y-2); i<min(y+3,MAXY-1); i++)
1360 		{
1361 		item[j][i]=mitem[j][i]=0;
1362 		show1cell(j,i);
1363 		if (playerx==j && playery==i)
1364 			{
1365 			cursors(); beep();
1366 			lprcat("\nYou were too close to the sphere!");
1367 			nap(3000);
1368 			died(283); /* player killed in explosion */
1369 			}
1370 		}
1371 	}
1372 
1373 /*
1374  *	genmonst()		Function to ask for monster and genocide from game
1375  *
1376  *	This is done by setting a flag in the monster[] structure
1377  */
1378 genmonst()
1379 	{
1380 	int i,j;
1381 	cursors();  lprcat("\nGenocide what monster? ");
1382 	for (i=0; (!isalpha(i)) && (i!=' '); i=getchar());
1383 	lprc(i);
1384 	for (j=0; j<MAXMONST; j++)	/* search for the monster type */
1385 		if (monstnamelist[j]==i)	/* have we found it? */
1386 			{
1387 			monster[j].genocided=1;	/* genocided from game */
1388 			lprintf("  There will be no more %s's",monster[j].name);
1389 			/* now wipe out monsters on this level */
1390 			newcavelevel(level); draws(0,MAXX,0,MAXY); bot_linex();
1391 			return;
1392 			}
1393 	lprcat("  You sense failure!");
1394 	}
1395 
1396