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