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