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