date and time created 89/03/05 18:59:25 by bostic
authorKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Mon, 6 Mar 1989 10:59:25 +0000 (02:59 -0800)
committerKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Mon, 6 Mar 1989 10:59:25 +0000 (02:59 -0800)
SCCS-vsn: games/larn/monster.c 5.1

usr/src/games/larn/monster.c [new file with mode: 0644]

diff --git a/usr/src/games/larn/monster.c b/usr/src/games/larn/monster.c
new file mode 100644 (file)
index 0000000..e3d7b74
--- /dev/null
@@ -0,0 +1,1384 @@
+/*
+ *     monster.c               Larn is copyrighted 1986 by Noah Morgan. 
+ *
+ *     This file contains the following functions:
+ *     ----------------------------------------------------------------------------
+ *
+ *     createmonster(monstno)          Function to create a monster next to the player
+ *             int monstno;
+ *
+ *     int cgood(x,y,itm,monst)        Function to check location for emptiness
+ *             int x,y,itm,monst;
+ *
+ *     createitem(it,arg)                      Routine to place an item next to the player
+ *             int it,arg;
+ *
+ *     cast()                          Subroutine called by parse to cast a spell for the user
+ *
+ *     speldamage(x)           Function to perform spell functions cast by the player
+ *             int x;
+ *
+ *     loseint()                       Routine to decrement your int (intelligence) if > 3
+ *
+ *     isconfuse()             Routine to check to see if player is confused
+ *
+ *     nospell(x,monst)        Routine to return 1 if a spell doesn't affect a monster
+ *             int x,monst;
+ *
+ *     fullhit(xx)                     Function to return full damage against a monst (aka web)
+ *             int xx;
+ *
+ *     direct(spnum,dam,str,arg)       Routine to direct spell damage 1 square in 1 dir
+ *             int spnum,dam,arg;
+ *             char *str;
+ *
+ *     godirect(spnum,dam,str,delay,cshow)             Function to perform missile attacks
+ *             int spnum,dam,delay;
+ *             char *str,cshow;
+ *
+ *     ifblind(x,y)    Routine to put "monster" or the monster name into lastmosnt
+ *             int x,y;
+ *
+ *     tdirect(spnum)                  Routine to teleport away a monster
+ *             int spnum;
+ *
+ *     omnidirect(sp,dam,str)  Routine to damage all monsters 1 square from player
+ *             int sp,dam;
+ *             char *str;
+ *
+ *     dirsub(x,y)                     Routine to ask for direction, then modify x,y for it
+ *             int *x,*y;
+ *
+ *     vxy(x,y)                        Routine to verify/fix (*x,*y) for being within bounds
+ *             int *x,*y;
+ *
+ *     dirpoly(spnum)          Routine to ask for a direction and polymorph a monst
+ *             int spnum;
+ *
+ *     hitmonster(x,y)         Function to hit a monster at the designated coordinates
+ *             int x,y;
+ *
+ *     hitm(x,y,amt)           Function to just hit a monster at a given coordinates
+ *             int x,y,amt;
+ *
+ *     hitplayer(x,y)          Function for the monster to hit the player from (x,y)
+ *             int x,y;
+ *
+ *     dropsomething(monst)    Function to create an object when a monster dies
+ *             int monst;
+ *
+ *     dropgold(amount)                Function to drop some gold around player
+ *             int amount;
+ *
+ *     something(level)                Function to create a random item around player
+ *             int level;
+ *
+ *     newobject(lev,i)                Routine to return a randomly selected new object
+ *             int lev,*i;
+ *
+ *  spattack(atckno,xx,yy)     Function to process special attacks from monsters
+ *     int atckno,xx,yy;
+ *
+ *     checkloss(x)    Routine to subtract hp from user and flag bottomline display
+ *             int x;
+ *
+ *     annihilate()   Routine to annihilate monsters around player, playerx,playery
+ *
+ *     newsphere(x,y,dir,lifetime)  Function to create a new sphere of annihilation
+ *             int x,y,dir,lifetime;
+ *
+ *     rmsphere(x,y)           Function to delete a sphere of annihilation from list
+ *             int x,y;
+ *
+ *     sphboom(x,y)            Function to perform the effects of a sphere detonation
+ *             int x,y;
+ *
+ *     genmonst()                      Function to ask for monster and genocide from game
+ *
+ */
+#include "header.h"
+
+struct isave   /* used for altar reality */
+       {
+       char type;      /* 0=item,  1=monster */
+       char id;        /* item number or monster number */
+       short arg;      /* the type of item or hitpoints of monster */
+       };
+
+/*
+ *     createmonster(monstno)          Function to create a monster next to the player
+ *             int monstno;
+ *
+ *     Enter with the monster number (1 to MAXMONST+8)
+ *     Returns no value.
+ */
+createmonster(mon)
+       int mon;
+       {
+       register int x,y,k,i;
+       if (mon<1 || mon>MAXMONST+8)    /* check for monster number out of bounds */
+               {
+               beep(); lprintf("\ncan't createmonst(%d)\n",(long)mon); nap(3000); return;
+               }
+       while (monster[mon].genocided && mon<MAXMONST) mon++; /* genocided? */
+       for (k=rnd(8), i= -8; i<0; i++,k++)     /* choose direction, then try all */
+               {
+               if (k>8) k=1;   /* wraparound the diroff arrays */
+               x = playerx + diroffx[k];               y = playery + diroffy[k];
+               if (cgood(x,y,0,1))     /* if we can create here */
+                       {
+                       mitem[x][y] = mon;
+                       hitp[x][y] = monster[mon].hitpoints;
+                       stealth[x][y]=know[x][y]=0;
+                       switch(mon)
+                               {
+                               case ROTHE: case POLTERGEIST: case VAMPIRE: stealth[x][y]=1;
+                               };
+                       return;
+                       }
+               }
+       }
+
+/*
+ *     int cgood(x,y,itm,monst)          Function to check location for emptiness
+ *             int x,y,itm,monst;
+ *
+ *     Routine to return TRUE if a location does not have itm or monst there
+ *     returns FALSE (0) otherwise
+ *     Enter with itm or monst TRUE or FALSE if checking it
+ *     Example:  if itm==TRUE check for no item at this location
+ *                       if monst==TRUE check for no monster at this location
+ *     This routine will return FALSE if at a wall or the dungeon exit on level 1
+ */
+int cgood(x,y,itm,monst)
+       register int x,y;
+       int itm,monst;
+       {
+       if ((y>=0) && (y<=MAXY-1) && (x>=0) && (x<=MAXX-1)) /* within bounds? */
+         if (item[x][y]!=OWALL)        /* can't make anything on walls */
+               if (itm==0 || (item[x][y]==0))  /* is it free of items? */
+                 if (monst==0 || (mitem[x][y]==0))     /* is it free of monsters? */
+                   if ((level!=1) || (x!=33) || (y!=MAXY-1)) /* not exit to level 1 */
+                         return(1);
+       return(0);
+       }
+
+/*
+ *     createitem(it,arg)              Routine to place an item next to the player
+ *             int it,arg;
+ *
+ *     Enter with the item number and its argument (iven[], ivenarg[])
+ *     Returns no value, thus we don't know about createitem() failures.
+ */
+createitem(it,arg)
+       int it,arg;
+       {
+       register int x,y,k,i;
+       if (it >= MAXOBJ) return;       /* no such object */
+       for (k=rnd(8), i= -8; i<0; i++,k++)     /* choose direction, then try all */
+               {
+               if (k>8) k=1;   /* wraparound the diroff arrays */
+               x = playerx + diroffx[k];               y = playery + diroffy[k];
+               if (cgood(x,y,1,0))     /* if we can create here */
+                       {
+                       item[x][y] = it;  know[x][y]=0;  iarg[x][y]=arg;  return;
+                       }
+               }
+       }
+
+/*
+ *     cast()          Subroutine called by parse to cast a spell for the user
+ *
+ *     No arguments and no return value.
+ */
+static char eys[] = "\nEnter your spell: ";
+cast()
+       {
+       register int i,j,a,b,d;
+       cursors();
+       if (c[SPELLS]<=0) {     lprcat("\nYou don't have any spells!"); return; }
+       lprcat(eys);            --c[SPELLS];
+       while ((a=getchar())=='D')
+               { seemagic(-1); cursors();  lprcat(eys); }
+       if (a=='\33') goto over; /*     to escape casting a spell       */
+       if ((b=getchar())=='\33') goto over; /* to escape casting a spell       */
+       if ((d=getchar())=='\33')
+               { over: lprcat(aborted); c[SPELLS]++; return; } /*      to escape casting a spell       */
+#ifdef EXTRA
+       c[SPELLSCAST]++;
+#endif
+       for (lprc('\n'),j= -1,i=0; i<SPNUM; i++) /*seq search for his spell, hash?*/
+               if ((spelcode[i][0]==a) && (spelcode[i][1]==b) && (spelcode[i][2]==d))
+                       if (spelknow[i])
+                               {  speldamage(i);  j = 1;  i=SPNUM; }
+
+       if (j == -1) lprcat("  Nothing Happened ");
+       bottomline();
+       }
+
+/*
+ *     speldamage(x)           Function to perform spell functions cast by the player
+ *             int x;
+ *
+ *     Enter with the spell number, returns no value.
+ *     Please insure that there are 2 spaces before all messages here
+ */
+speldamage(x)
+       int x;
+       {
+       register int i,j,clev;
+       int xl,xh,yl,yh;
+       register char *p,*kn,*pm;
+       if (x>=SPNUM) return;   /* no such spell */
+       if (c[TIMESTOP])  { lprcat("  It didn't seem to work"); return; }  /* not if time stopped */
+       clev = c[LEVEL];
+       if ((rnd(23)==7) || (rnd(18) > c[INTELLIGENCE]))
+               { lprcat("  It didn't work!");  return; }
+       if (clev*3+2 < x) { lprcat("  Nothing happens.  You seem inexperienced at this"); return; }
+
+       switch(x)
+               {
+/* ----- LEVEL 1 SPELLS ----- */
+
+               case 0: if (c[PROTECTIONTIME]==0)       c[MOREDEFENSES]+=2; /* protection field +2 */
+                               c[PROTECTIONTIME] += 250;   return;
+
+               case 1: i = rnd(((clev+1)<<1)) + clev + 3;
+                               godirect(x,i,(clev>=2)?"  Your missiles hit the %s":"  Your missile hit the %s",100,'+'); /* magic missile */
+
+                               return;
+
+               case 2: if (c[DEXCOUNT]==0)     c[DEXTERITY]+=3; /*     dexterity       */
+                               c[DEXCOUNT] += 400;     return;
+
+               case 3: i=rnd(3)+1;
+                               p="  While the %s slept, you smashed it %d times";
+                       ws:     direct(x,fullhit(i),p,i); /*    sleep   */      return;
+
+               case 4: /*      charm monster   */      c[CHARMCOUNT] += c[CHARISMA]<<1;        return;
+
+               case 5: godirect(x,rnd(10)+15+clev,"  The sound damages the %s",70,'@'); /*     sonic spear */
+                               return;
+
+/* ----- LEVEL 2 SPELLS ----- */
+
+               case 6: i=rnd(3)+2;     p="  While the %s is entangled, you hit %d times";
+                               goto ws; /* web */
+
+               case 7: if (c[STRCOUNT]==0) c[STREXTRA]+=3;     /*      strength        */
+                               c[STRCOUNT] += 150+rnd(100);    return;
+
+               case 8: yl = playery-5;     /* enlightenment */
+                               yh = playery+6;   xl = playerx-15;   xh = playerx+16;
+                               vxy(&xl,&yl);   vxy(&xh,&yh); /* check bounds */
+                               for (i=yl; i<=yh; i++) /* enlightenment */
+                                       for (j=xl; j<=xh; j++)  know[j][i]=1;
+                               draws(xl,xh+1,yl,yh+1); return;
+
+               case 9: raisehp(20+(clev<<1));  return;  /* healing */
+
+               case 10:        c[BLINDCOUNT]=0;        return; /* cure blindness       */
+
+               case 11:        createmonster(makemonst(level+1)+8);  return;
+
+               case 12:        if (rnd(11)+7 <= c[WISDOM]) direct(x,rnd(20)+20+clev,"  The %s believed!",0);
+                                       else lprcat("  It didn't believe the illusions!");
+                                       return;
+
+               case 13:        /* if he has the amulet of invisibility then add more time */
+                                       for (j=i=0; i<26; i++)
+                                               if (iven[i]==OAMULET) j+= 1+ivenarg[i];
+                                       c[INVISIBILITY] += (j<<7)+12;   return;
+
+/* ----- LEVEL 3 SPELLS ----- */
+
+               case 14:        godirect(x,rnd(25+clev)+25+clev,"  The fireball hits the %s",40,'*'); return; /*        fireball */
+
+               case 15:        godirect(x,rnd(25)+20+clev,"  Your cone of cold strikes the %s",60,'O');        /*      cold */
+                                       return;
+
+               case 16:        dirpoly(x);  return;    /*      polymorph */
+
+               case 17:        c[CANCELLATION]+= 5+clev;       return; /*      cancellation    */
+
+               case 18:        c[HASTESELF]+= 7+clev;  return;  /*     haste self      */
+
+               case 19:        omnidirect(x,30+rnd(10),"  The %s gasps for air");      /* cloud kill */
+                                       return;
+
+               case 20:        xh = min(playerx+1,MAXX-2);             yh = min(playery+1,MAXY-2);
+                                       for (i=max(playerx-1,1); i<=xh; i++) /* vaporize rock */
+                                         for (j=max(playery-1,1); j<=yh; j++)
+                                               {
+                                               kn = &know[i][j];    pm = &mitem[i][j];
+                                               switch(*(p= &item[i][j]))
+                                                 {
+                                                 case OWALL: if (level < MAXLEVEL+MAXVLEVEL-1)
+                                                                                       *p = *kn = 0;
+                                                                               break;
+
+                                                 case OSTATUE: if (c[HARDGAME]<3)
+                                                                                        {
+                                                                                        *p=OBOOK; iarg[i][j]=level;  *kn=0;
+                                                                                        }
+                                                                               break;
+       
+                                                 case OTHRONE: *pm=GNOMEKING;  *kn=0;  *p= OTHRONE2;
+                                                                               hitp[i][j]=monster[GNOMEKING].hitpoints; break;
+
+                                                 case OALTAR:  *pm=DEMONPRINCE;  *kn=0;
+                                                                               hitp[i][j]=monster[DEMONPRINCE].hitpoints; break;
+                                                 };
+                                               switch(*pm)
+                                                       {
+                                                       case XORN:      ifblind(i,j);  hitm(i,j,200); break; /* Xorn takes damage from vpr */
+                                                       }
+                                               }
+                                       return;
+
+/* ----- LEVEL 4 SPELLS ----- */
+
+               case 21:        direct(x,100+clev,"  The %s shrivels up",0); /* dehydration */
+                                       return;
+
+               case 22:        godirect(x,rnd(25)+20+(clev<<1),"  A lightning bolt hits the %s",1,'~');        /*      lightning */
+                                       return;
+
+               case 23:        i=min(c[HP]-1,c[HPMAX]/2);      /* drain life */
+                                       direct(x,i+i,"",0);     c[HP] -= i;     return;
+
+               case 24:        if (c[GLOBE]==0) c[MOREDEFENSES] += 10;
+                                       c[GLOBE] += 200;  loseint();  /* globe of invulnerability */
+                                       return;
+
+               case 25:        omnidirect(x,32+clev,"  The %s struggles for air in your flood!"); /* flood */
+                                       return;
+
+               case 26:        if (rnd(151)==63) { beep(); lprcat("\nYour heart stopped!\n"); nap(4000);  died(270); return; }
+                                       if (c[WISDOM]>rnd(10)+10) direct(x,2000,"  The %s's heart stopped",0); /* finger of death */
+                                       else lprcat("  It didn't work"); return;
+
+/* ----- LEVEL 5 SPELLS ----- */
+
+               case 27:        c[SCAREMONST] += rnd(10)+clev;  return;  /* scare monster */
+
+               case 28:        c[HOLDMONST] += rnd(10)+clev;  return;  /* hold monster */
+
+               case 29:        c[TIMESTOP] += rnd(20)+(clev<<1);  return;  /* time stop */
+
+               case 30:        tdirect(x);  return;  /* teleport away */
+
+               case 31:        omnidirect(x,35+rnd(10)+clev,"  The %s cringes from the flame"); /* magic fire */
+                                       return;
+
+/* ----- LEVEL 6 SPELLS ----- */
+
+               case 32:        if ((rnd(23)==5) && (wizard==0)) /* sphere of annihilation */
+                                               {
+                                               beep(); lprcat("\nYou have been enveloped by the zone of nothingness!\n");
+                                               nap(4000);  died(258); return;
+                                               }
+                                       xl=playerx; yl=playery;
+                                       loseint();
+                                       i=dirsub(&xl,&yl); /* get direction of sphere */
+                                       newsphere(xl,yl,i,rnd(20)+11);  /* make a sphere */
+                                       return;
+
+               case 33:        genmonst();  spelknow[33]=0;  /* genocide */
+                                       loseint();
+                                       return;
+
+               case 34:        /* summon demon */
+                                       if (rnd(100) > 30) { direct(x,150,"  The demon strikes at the %s",0);  return; }
+                                       if (rnd(100) > 15) { lprcat("  Nothing seems to have happened");  return; }
+                                       lprcat("  The demon turned on you and vanished!"); beep();
+                                       i=rnd(40)+30;  lastnum=277;
+                                       losehp(i); /* must say killed by a demon */ return;
+
+               case 35:        /* walk through walls */
+                                       c[WTW] += rnd(10)+5;    return;
+
+               case 36:        /* alter reality */
+                                       {
+                                       struct isave *save;     /* pointer to item save structure */
+                                       int sc; sc=0;   /* # items saved */
+                                       save = (struct isave *)malloc(sizeof(struct isave)*MAXX*MAXY*2);
+                                       for (j=0; j<MAXY; j++)
+                                               for (i=0; i<MAXX; i++) /* save all items and monsters */
+                                                       {
+                                                       xl = item[i][j];
+                                                       if (xl && xl!=OWALL && xl!=OANNIHILATION) 
+                                                               {
+                                                               save[sc].type=0;  save[sc].id=item[i][j];
+                                                               save[sc++].arg=iarg[i][j];
+                                                               }
+                                                       if (mitem[i][j]) 
+                                                               {
+                                                               save[sc].type=1;  save[sc].id=mitem[i][j];
+                                                               save[sc++].arg=hitp[i][j];
+                                                               }
+                                                       item[i][j]=OWALL;   mitem[i][j]=0;
+                                                       if (wizard) know[i][j]=1; else know[i][j]=0;
+                                                       }
+                                       eat(1,1);       if (level==1) item[33][MAXY-1]=0;
+                                       for (j=rnd(MAXY-2), i=1; i<MAXX-1; i++) item[i][j]=0;
+                                       while (sc>0) /* put objects back in level */
+                                               {
+                                               --sc;
+                                               if (save[sc].type == 0)
+                                                       {
+                                                       int trys;
+                                                       for (trys=100, i=j=1; --trys>0 && item[i][j]; i=rnd(MAXX-1), j=rnd(MAXY-1));
+                                                       if (trys) { item[i][j]=save[sc].id; iarg[i][j]=save[sc].arg; }
+                                                       }
+                                               else
+                                                       { /* put monsters back in */
+                                                       int trys;
+                                                       for (trys=100, i=j=1; --trys>0 && (item[i][j]==OWALL || mitem[i][j]); i=rnd(MAXX-1), j=rnd(MAXY-1));
+                                                       if (trys) { mitem[i][j]=save[sc].id; hitp[i][j]=save[sc].arg; }
+                                                       }
+                                               }
+                                       loseint();
+                                       draws(0,MAXX,0,MAXY);  if (wizard==0) spelknow[36]=0;
+                                       free((char*)save);       positionplayer();  return;
+                                       }
+
+               case 37:        /* permanence */ adjtime(-99999L);  spelknow[37]=0; /* forget */
+                                       loseint();
+                                       return;
+
+               default:        lprintf("  spell %d not available!",(long)x); beep();  return;
+               };
+       }
+
+/*
+ *     loseint()               Routine to subtract 1 from your int (intelligence) if > 3
+ *
+ *     No arguments and no return value
+ */
+loseint()
+       {
+       if (--c[INTELLIGENCE]<3)  c[INTELLIGENCE]=3;
+       }
+
+/*
+ *     isconfuse()             Routine to check to see if player is confused
+ *
+ *     This routine prints out a message saying "You can't aim your magic!"
+ *     returns 0 if not confused, non-zero (time remaining confused) if confused
+ */
+isconfuse()
+       {
+       if (c[CONFUSE]) { lprcat(" You can't aim your magic!"); beep(); }
+       return(c[CONFUSE]);
+       }
+
+/*
+ *     nospell(x,monst)        Routine to return 1 if a spell doesn't affect a monster
+ *             int x,monst;
+ *
+ *     Subroutine to return 1 if the spell can't affect the monster
+ *       otherwise returns 0
+ *     Enter with the spell number in x, and the monster number in monst.
+ */
+nospell(x,monst)
+       int x,monst;
+       {
+       register int tmp;
+       if (x>=SPNUM || monst>=MAXMONST+8 || monst<0 || x<0) return(0); /* bad spell or monst */
+       if ((tmp=spelweird[monst-1][x])==0) return(0);
+       cursors();  lprc('\n');  lprintf(spelmes[tmp],monster[monst].name);  return(1);
+       }
+
+/*
+ *     fullhit(xx)             Function to return full damage against a monster (aka web)
+ *             int xx;
+ *
+ *     Function to return hp damage to monster due to a number of full hits
+ *     Enter with the number of full hits being done
+ */
+fullhit(xx)
+       int xx;
+       {
+       register int i;
+       if (xx<0 || xx>20) return(0);   /* fullhits are out of range */
+       if (c[LANCEDEATH]) return(10000);       /* lance of death */
+       i = xx * ((c[WCLASS]>>1)+c[STRENGTH]+c[STREXTRA]-c[HARDGAME]-12+c[MOREDAM]); 
+       return( (i>=1) ? i : xx );
+       }
+
+/*
+ *     direct(spnum,dam,str,arg)       Routine to direct spell damage 1 square in 1 dir
+ *             int spnum,dam,arg;
+ *             char *str;
+ *
+ *     Routine to ask for a direction to a spell and then hit the monster
+ *     Enter with the spell number in spnum, the damage to be done in dam,
+ *       lprintf format string in str, and lprintf's argument in arg.
+ *     Returns no value.
+ */
+direct(spnum,dam,str,arg)
+       int spnum,dam,arg;
+       char *str;
+       {
+       int x,y;
+       register int m;
+       if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad arguments */
+       if (isconfuse()) return;
+       dirsub(&x,&y);
+       m = mitem[x][y];
+       if (item[x][y]==OMIRROR)
+               {
+               if (spnum==3) /* sleep */
+                       {
+                       lprcat("You fall asleep! "); beep();
+               fool:
+                       arg += 2;
+                       while (arg-- > 0) { parse2(); nap(1000); }
+                       return;
+                       }
+               else if (spnum==6) /* web */
+                       {
+                       lprcat("You get stuck in your own web! "); beep();
+                       goto fool;
+                       }
+               else
+                       {
+                       lastnum=278; 
+                       lprintf(str,"spell caster (thats you)",(long)arg);
+                       beep(); losehp(dam); return;
+                       }
+               }
+       if (m==0)
+               {       lprcat("  There wasn't anything there!");       return;  }
+       ifblind(x,y);
+       if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
+       lprintf(str,lastmonst,(long)arg);       hitm(x,y,dam);
+       }
+
+/*
+ *     godirect(spnum,dam,str,delay,cshow)             Function to perform missile attacks
+ *             int spnum,dam,delay;
+ *             char *str,cshow;
+ *
+ *     Function to hit in a direction from a missile weapon and have it keep
+ *     on going in that direction until its power is exhausted
+ *     Enter with the spell number in spnum, the power of the weapon in hp,
+ *       lprintf format string in str, the # of milliseconds to delay between 
+ *       locations in delay, and the character to represent the weapon in cshow.
+ *     Returns no value.
+ */
+godirect(spnum,dam,str,delay,cshow)
+       int spnum,dam,delay;
+       char *str,cshow;
+       {
+       register char *p;
+       register int x,y,m;
+       int dx,dy;
+       if (spnum<0 || spnum>=SPNUM || str==0 || delay<0) return; /* bad args */
+       if (isconfuse()) return;
+       dirsub(&dx,&dy);        x=dx;   y=dy;
+       dx = x-playerx;         dy = y-playery;         x = playerx;    y = playery;
+       while (dam>0)
+               {
+               x += dx;    y += dy;
+           if ((x > MAXX-1) || (y > MAXY-1) || (x < 0) || (y < 0))
+                       {
+                       dam=0;  break;  /* out of bounds */
+                       }
+               if ((x==playerx) && (y==playery)) /* if energy hits player */
+                       {
+                       cursors(); lprcat("\nYou are hit my your own magic!"); beep();
+                       lastnum=278;  losehp(dam);  return;
+                       }
+               if (c[BLINDCOUNT]==0) /* if not blind show effect */
+                       {
+                       cursor(x+1,y+1); lprc(cshow); nap(delay); show1cell(x,y);
+                       }
+               if ((m=mitem[x][y]))    /* is there a monster there? */
+                       {
+                       ifblind(x,y);
+                       if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
+                       cursors(); lprc('\n');
+                       lprintf(str,lastmonst);         dam -= hitm(x,y,dam);
+                       show1cell(x,y);  nap(1000);             x -= dx;        y -= dy;
+                       }
+               else switch (*(p= &item[x][y]))
+                       {
+                       case OWALL:     cursors(); lprc('\n'); lprintf(str,"wall");
+                                               if (dam>=50+c[HARDGAME]) /* enough damage? */
+                                                if (level<MAXLEVEL+MAXVLEVEL-1) /* not on V3 */
+                                                 if ((x<MAXX-1) && (y<MAXY-1) && (x) && (y))
+                                                       {
+                                                       lprcat("  The wall crumbles");
+                                       god3:   *p=0;
+                                       god:    know[x][y]=0;
+                                                       show1cell(x,y);
+                                                       }
+                               god2:   dam = 0;        break;
+
+                       case OCLOSEDDOOR:       cursors(); lprc('\n'); lprintf(str,"door");
+                                               if (dam>=40)
+                                                       {
+                                                       lprcat("  The door is blasted apart");
+                                                       goto god3;
+                                                       }
+                                               goto god2;
+
+                       case OSTATUE:   cursors(); lprc('\n'); lprintf(str,"statue");
+                                               if (c[HARDGAME]<3)
+                                                 if (dam>44)
+                                                       {
+                                                       lprcat("  The statue crumbles");
+                                                       *p=OBOOK; iarg[x][y]=level;
+                                                       goto god;
+                                                       }
+                                               goto god2;
+
+                       case OTHRONE:   cursors(); lprc('\n'); lprintf(str,"throne");
+                                       if (dam>39)
+                                               {
+                                               mitem[x][y]=GNOMEKING; hitp[x][y]=monster[GNOMEKING].hitpoints;
+                                               *p = OTHRONE2;
+                                               goto god;
+                                               }
+                                       goto god2;
+
+                       case OMIRROR:   dx *= -1;       dy *= -1;       break;
+                       };
+               dam -= 3 + (c[HARDGAME]>>1);
+               }
+       }
+
+/*
+ *     ifblind(x,y)    Routine to put "monster" or the monster name into lastmosnt
+ *             int x,y;
+ *
+ *     Subroutine to copy the word "monster" into lastmonst if the player is blind
+ *     Enter with the coordinates (x,y) of the monster
+ *     Returns no value.
+ */
+ifblind(x,y)
+       int x,y;
+       {
+       char *p;
+       vxy(&x,&y);     /* verify correct x,y coordinates */
+       if (c[BLINDCOUNT]) { lastnum=279;  p="monster"; }
+               else { lastnum=mitem[x][y];  p=monster[lastnum].name; }
+       strcpy(lastmonst,p);
+       }
+
+/*
+ *     tdirect(spnum)          Routine to teleport away a monster
+ *             int spnum;
+ *
+ *     Routine to ask for a direction to a spell and then teleport away monster
+ *     Enter with the spell number that wants to teleport away
+ *     Returns no value.
+ */
+tdirect(spnum)
+       int spnum;
+       {
+       int x,y;
+       register int m;
+       if (spnum<0 || spnum>=SPNUM) return; /* bad args */
+       if (isconfuse()) return;
+       dirsub(&x,&y);
+       if ((m=mitem[x][y])==0)
+               {       lprcat("  There wasn't anything there!");       return;  }
+       ifblind(x,y);
+       if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
+       fillmonst(m);  mitem[x][y]=know[x][y]=0;
+       }
+
+/*
+ *     omnidirect(sp,dam,str)   Routine to damage all monsters 1 square from player
+ *             int sp,dam;
+ *             char *str;
+ *
+ *     Routine to cast a spell and then hit the monster in all directions
+ *     Enter with the spell number in sp, the damage done to wach square in dam,
+ *       and the lprintf string to identify the spell in str.
+ *     Returns no value.
+ */
+omnidirect(spnum,dam,str)
+       int spnum,dam;
+       char *str;
+       {
+       register int x,y,m;
+       if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad args */
+       for (x=playerx-1; x<playerx+2; x++)
+               for (y=playery-1; y<playery+2; y++)
+                       {
+                       if (m=mitem[x][y])
+                               if (nospell(spnum,m) == 0)
+                                       {
+                                       ifblind(x,y);
+                                       cursors(); lprc('\n'); lprintf(str,lastmonst);
+                                       hitm(x,y,dam);  nap(800);
+                                       }
+                               else  { lasthx=x;  lasthy=y; }
+                       }
+       }
+
+/*
+ *     static dirsub(x,y)              Routine to ask for direction, then modify x,y for it
+ *             int *x,*y;
+ *
+ *     Function to ask for a direction and modify an x,y for that direction
+ *     Enter with the origination coordinates in (x,y).
+ *     Returns index into diroffx[] (0-8).
+ */
+static dirsub(x,y)
+       int *x,*y;
+       {
+       register int i;
+       lprcat("\nIn What Direction? ");
+       for (i=0; ; )
+               switch(getchar())
+                       {
+                       case 'b':       i++;
+                       case 'n':       i++;    
+                       case 'y':       i++;    
+                       case 'u':       i++;
+                       case 'h':       i++;    
+                       case 'k':       i++;
+                       case 'l':       i++;    
+                       case 'j':       i++;            goto out;
+                       };
+out:
+       *x = playerx+diroffx[i];                *y = playery+diroffy[i];
+       vxy(x,y);  return(i);
+       }
+
+/*
+ *     vxy(x,y)           Routine to verify/fix coordinates for being within bounds
+ *             int *x,*y;
+ *
+ *     Function to verify x & y are within the bounds for a level
+ *     If *x or *y is not within the absolute bounds for a level, fix them so that
+ *       they are on the level.
+ *     Returns TRUE if it was out of bounds, and the *x & *y in the calling
+ *     routine are affected.
+ */
+vxy(x,y)
+       int *x,*y;
+       {
+       int flag=0;
+       if (*x<0) { *x=0; flag++; }
+       if (*y<0) { *y=0; flag++; }
+       if (*x>=MAXX) { *x=MAXX-1; flag++; }
+       if (*y>=MAXY) { *y=MAXY-1; flag++; }
+       return(flag);
+       }
+
+/*
+ *     dirpoly(spnum)          Routine to ask for a direction and polymorph a monst
+ *             int spnum;
+ *
+ *     Subroutine to polymorph a monster and ask for the direction its in
+ *     Enter with the spell number in spmun.
+ *     Returns no value.
+ */
+dirpoly(spnum)
+       int spnum;
+       {
+       int x,y,m;
+       if (spnum<0 || spnum>=SPNUM) return; /* bad args */
+       if (isconfuse()) return;        /* if he is confused, he can't aim his magic */
+       dirsub(&x,&y);
+       if (mitem[x][y]==0)
+               {       lprcat("  There wasn't anything there!");       return;  }
+       ifblind(x,y);
+       if (nospell(spnum,mitem[x][y])) { lasthx=x;  lasthy=y; return; }
+       while ( monster[m = mitem[x][y] = rnd(MAXMONST+7)].genocided );
+       hitp[x][y] = monster[m].hitpoints;
+       show1cell(x,y);  /* show the new monster */
+       }
+
+/*
+ *     hitmonster(x,y)         Function to hit a monster at the designated coordinates
+ *             int x,y;
+ *
+ *     This routine is used for a bash & slash type attack on a monster
+ *     Enter with the coordinates of the monster in (x,y).
+ *     Returns no value.
+ */
+hitmonster(x,y)
+       int x,y;
+       {
+       register int tmp,monst,damag,flag;
+       if (c[TIMESTOP])  return;  /* not if time stopped */
+       vxy(&x,&y);     /* verify coordinates are within range */
+       if ((monst = mitem[x][y]) == 0) return;
+       hit3flag=1;  ifblind(x,y);
+       tmp = monster[monst].armorclass + c[LEVEL] + c[DEXTERITY] + c[WCLASS]/4 - 12;
+       cursors();
+       if ((rnd(20) < tmp-c[HARDGAME]) || (rnd(71) < 5)) /* need at least random chance to hit */
+               {
+               lprcat("\nYou hit");  flag=1;
+               damag = fullhit(1);  
+               if (damag<9999) damag=rnd(damag)+1;
+               }
+       else
+               {
+               lprcat("\nYou missed");  flag=0;
+               }
+       lprcat(" the "); lprcat(lastmonst);
+       if (flag)       /* if the monster was hit */
+         if ((monst==RUSTMONSTER) || (monst==DISENCHANTRESS) || (monst==CUBE))
+               if (c[WIELD]>0)
+                 if (ivenarg[c[WIELD]] > -10)
+                       {
+                       lprintf("\nYour weapon is dulled by the %s",lastmonst); beep();
+                       --ivenarg[c[WIELD]];
+                       }
+       if (flag)  hitm(x,y,damag);
+       if (monst == VAMPIRE) if (hitp[x][y]<25)  { mitem[x][y]=BAT; know[x][y]=0; }
+       }
+
+/*
+ *     hitm(x,y,amt)           Function to just hit a monster at a given coordinates
+ *             int x,y,amt;
+ *
+ *     Returns the number of hitpoints the monster absorbed
+ *     This routine is used to specifically damage a monster at a location (x,y)
+ *     Called by hitmonster(x,y)
+ */
+hitm(x,y,amt)
+       int x,y;
+       register amt;
+       {
+       register int monst;
+       int hpoints,amt2;
+       vxy(&x,&y);     /* verify coordinates are within range */
+       amt2 = amt;             /* save initial damage so we can return it */
+       monst = mitem[x][y];
+       if (c[HALFDAM]) amt >>= 1;      /* if half damage curse adjust damage points */
+       if (amt<=0) amt2 = amt = 1;
+       lasthx=x;  lasthy=y;
+       stealth[x][y]=1;        /* make sure hitting monst breaks stealth condition */
+       c[HOLDMONST]=0; /* hit a monster breaks hold monster spell      */
+       switch(monst) /* if a dragon and orb(s) of dragon slaying       */
+               {
+               case WHITEDRAGON:               case REDDRAGON:                 case GREENDRAGON:
+               case BRONZEDRAGON:              case PLATINUMDRAGON:    case SILVERDRAGON:
+                       amt *= 1+(c[SLAYING]<<1);       break;
+               }
+/* invincible monster fix is here */
+       if (hitp[x][y] > monster[monst].hitpoints)
+               hitp[x][y] = monster[monst].hitpoints;
+       if ((hpoints = hitp[x][y]) <= amt)
+               {
+#ifdef EXTRA
+               c[MONSTKILLED]++;
+#endif
+               lprintf("\nThe %s died!",lastmonst);
+               raiseexperience((long)monster[monst].experience);
+               amt = monster[monst].gold;  if (amt>0) dropgold(rnd(amt)+amt);
+               dropsomething(monst);   disappear(x,y); bottomline();
+               return(hpoints);
+               }
+       hitp[x][y] = hpoints-amt;       return(amt2);
+       }
+
+/*
+ *     hitplayer(x,y)          Function for the monster to hit the player from (x,y)
+ *             int x,y;
+ *
+ *     Function for the monster to hit the player with monster at location x,y
+ *     Returns nothing of value.
+ */
+hitplayer(x,y)
+       int x,y;
+       {
+       register int dam,tmp,mster,bias;
+       vxy(&x,&y);     /* verify coordinates are within range */
+       lastnum = mster = mitem[x][y];
+/*     spirit naga's and poltergeist's do nothing if scarab of negate spirit   */
+       if (c[NEGATESPIRIT] || c[SPIRITPRO])  if ((mster ==POLTERGEIST) || (mster ==SPIRITNAGA))  return;
+/*     if undead and cube of undead control    */
+       if (c[CUBEofUNDEAD] || c[UNDEADPRO]) if ((mster ==VAMPIRE) || (mster ==WRAITH) || (mster ==ZOMBIE)) return;
+       if ((know[x][y]&1) == 0)
+               {
+               know[x][y]=1; show1cell(x,y);
+               }
+       bias = (c[HARDGAME]) + 1;
+       hitflag = hit2flag = hit3flag = 1;
+       yrepcount=0;
+       cursors();      ifblind(x,y);
+       if (c[INVISIBILITY]) if (rnd(33)<20) 
+               {
+               lprintf("\nThe %s misses wildly",lastmonst);    return;
+               }
+       if (c[CHARMCOUNT]) if (rnd(30)+5*monster[mster].level-c[CHARISMA]<30)
+               {
+               lprintf("\nThe %s is awestruck at your magnificence!",lastmonst);
+               return;
+               }
+       if (mster==BAT) dam=1;
+       else
+               {
+               dam = monster[mster].damage;
+               dam += rnd((int)((dam<1)?1:dam)) + monster[mster].level;
+               }
+       tmp = 0;
+       if (monster[mster].attack>0)
+         if (((dam + bias + 8) > c[AC]) || (rnd((int)((c[AC]>0)?c[AC]:1))==1))
+               { if (spattack(monster[mster].attack,x,y)) { flushall(); return; }
+                 tmp = 1;  bias -= 2; cursors(); }
+       if (((dam + bias) > c[AC]) || (rnd((int)((c[AC]>0)?c[AC]:1))==1))
+               {
+               lprintf("\n  The %s hit you ",lastmonst);       tmp = 1;
+               if ((dam -= c[AC]) < 0) dam=0;
+               if (dam > 0) { losehp(dam); bottomhp(); flushall(); }
+               }
+       if (tmp == 0)  lprintf("\n  The %s missed ",lastmonst);
+       }
+
+/*
+ *     dropsomething(monst)    Function to create an object when a monster dies
+ *             int monst;
+ *
+ *     Function to create an object near the player when certain monsters are killed
+ *     Enter with the monster number
+ *     Returns nothing of value.
+ */
+dropsomething(monst)
+       int monst;
+       {
+       switch(monst)
+               {
+               case ORC:                         case NYMPH:      case ELF:      case TROGLODYTE:
+               case TROLL:                       case ROTHE:      case VIOLETFUNGI:
+               case PLATINUMDRAGON:  case GNOMEKING:  case REDDRAGON:
+                       something(level); return;
+
+               case LEPRECHAUN: if (rnd(101)>=75) creategem();
+                                                if (rnd(5)==1) dropsomething(LEPRECHAUN);   return;
+               }
+       }
+
+/*
+ *     dropgold(amount)        Function to drop some gold around player
+ *             int amount;
+ *
+ *     Enter with the number of gold pieces to drop
+ *     Returns nothing of value.
+ */
+dropgold(amount)
+       register int amount;
+       {
+       if (amount > 250) createitem(OMAXGOLD,amount/100);  else  createitem(OGOLDPILE,amount);
+       }
+
+/*
+ *     something(level)        Function to create a random item around player
+ *             int level;
+ *
+ *     Function to create an item from a designed probability around player
+ *     Enter with the cave level on which something is to be dropped
+ *     Returns nothing of value.
+ */
+something(level)
+       int level;
+       {
+       register int j;
+       int i;
+       if (level<0 || level>MAXLEVEL+MAXVLEVEL) return;        /* correct level? */
+       if (rnd(101)<8) something(level); /* possibly more than one item */
+       j = newobject(level,&i);                createitem(j,i);
+       }
+
+/*
+ *     newobject(lev,i)        Routine to return a randomly selected new object
+ *             int lev,*i;
+ *
+ *     Routine to return a randomly selected object to be created
+ *     Returns the object number created, and sets *i for its argument
+ *     Enter with the cave level and a pointer to the items arg
+ */
+static char nobjtab[] = { 0, OSCROLL,  OSCROLL,  OSCROLL,  OSCROLL, OPOTION,
+       OPOTION, OPOTION, OPOTION, OGOLDPILE, OGOLDPILE, OGOLDPILE, OGOLDPILE, 
+       OBOOK, OBOOK, OBOOK, OBOOK, ODAGGER, ODAGGER, ODAGGER, OLEATHER, OLEATHER,
+       OLEATHER, OREGENRING, OPROTRING, OENERGYRING, ODEXRING, OSTRRING, OSPEAR,
+       OBELT, ORING, OSTUDLEATHER, OSHIELD, OFLAIL, OCHAIN, O2SWORD, OPLATE,
+       OLONGSWORD };
+
+newobject(lev,i)
+       register int lev,*i;
+       {
+       register int tmp=32,j;
+       if (level<0 || level>MAXLEVEL+MAXVLEVEL) return(0);     /* correct level? */
+       if (lev>6) tmp=37; else if (lev>4) tmp=35; 
+       j = nobjtab[tmp=rnd(tmp)];      /* the object type */
+       switch(tmp)
+               {
+               case 1: case 2: case 3: case 4: *i=newscroll(); break;
+               case 5: case 6: case 7: case 8: *i=newpotion(); break;
+               case 9: case 10: case 11: case 12: *i=rnd((lev+1)*10)+lev*10+10; break;
+               case 13: case 14: case 15: case 16:     *i=lev; break;
+               case 17: case 18: case 19: if (!(*i=newdagger()))  return(0);  break;
+               case 20: case 21: case 22: if (!(*i=newleather()))  return(0);  break;
+               case 23: case 32: case 35: *i=rund(lev/3+1); break;
+               case 24: case 26: *i=rnd(lev/4+1);   break;
+               case 25: *i=rund(lev/4+1); break;
+               case 27: *i=rnd(lev/2+1);   break;
+               case 30: case 33: *i=rund(lev/2+1);   break;
+               case 28: *i=rund(lev/3+1); if (*i==0) return(0); break;
+               case 29: case 31: *i=rund(lev/2+1); if (*i==0) return(0); break;
+               case 34: *i=newchain();         break;
+               case 36: *i=newplate();         break;
+               case 37: *i=newsword();         break; 
+               }
+       return(j);
+       }
+
+/*
+ *  spattack(atckno,xx,yy)     Function to process special attacks from monsters
+ *     int atckno,xx,yy;
+ *
+ *     Enter with the special attack number, and the coordinates (xx,yy)
+ *             of the monster that is special attacking
+ *     Returns 1 if must do a show1cell(xx,yy) upon return, 0 otherwise
+ *
+ * atckno   monster     effect
+ * ---------------------------------------------------
+ *     0       none
+ *     1       rust monster    eat armor
+ *     2       hell hound              breathe light fire
+ *     3       dragon                  breathe fire
+ *     4       giant centipede weakening sing
+ *     5       white dragon    cold breath
+ *     6       wraith                  drain level
+ *     7       waterlord               water gusher
+ *     8       leprechaun              steal gold
+ *     9       disenchantress  disenchant weapon or armor
+ *     10      ice lizard              hits with barbed tail
+ *     11      umber hulk              confusion
+ *     12      spirit naga             cast spells     taken from special attacks
+ *     13      platinum dragon psionics
+ *     14      nymph                   steal objects
+ *     15      bugbear                 bite
+ *     16      osequip                 bite
+ *
+ *     char rustarm[ARMORTYPES][2];
+ *     special array for maximum rust damage to armor from rustmonster
+ *     format is: { armor type , minimum attribute 
+ */
+#define ARMORTYPES 6
+static char rustarm[ARMORTYPES][2] = { OSTUDLEATHER,-2,        ORING,-4, OCHAIN,-5,
+       OSPLINT,-6,             OPLATE,-8,              OPLATEARMOR,-9  };
+static char spsel[] = { 1, 2, 3, 5, 6, 8, 9, 11, 13, 14 };
+spattack(x,xx,yy)
+       int x,xx,yy;
+       {
+       register int i,j=0,k,m;
+       register char *p=0;
+       if (c[CANCELLATION]) return(0);
+       vxy(&xx,&yy);   /* verify x & y coordinates */
+       switch(x)
+               {
+               case 1: /* rust your armor, j=1 when rusting has occurred */
+                               m = k = c[WEAR];
+                               if ((i=c[SHIELD]) != -1)
+                                       if (--ivenarg[i] < -1) ivenarg[i]= -1; else j=1;
+                               if ((j==0) && (k != -1))
+                                 {
+                                 m = iven[k];
+                                 for (i=0; i<ARMORTYPES; i++)
+                                       if (m == rustarm[i][0]) /* find his armor in table */
+                                               {
+                                               if (--ivenarg[k]< rustarm[i][1])
+                                                       ivenarg[k]= rustarm[i][1]; else j=1; 
+                                               break;
+                                               }
+                                 }
+                               if (j==0)       /* if rusting did not occur */
+                                 switch(m)
+                                       {
+                                       case OLEATHER:  p = "\nThe %s hit you -- Your lucky you have leather on";
+                                                                       break;
+                                   case OSSPLATE:      p = "\nThe %s hit you -- Your fortunate to have stainless steel armor!";
+                                                                       break;
+                                       }
+                               else  { beep(); p = "\nThe %s hit you -- your armor feels weaker"; }
+                               break;
+
+               case 2:         i = rnd(15)+8-c[AC];
+                       spout:  p="\nThe %s breathes fire at you!";
+                                       if (c[FIRERESISTANCE])
+                                         p="\nThe %s's flame doesn't phase you!";
+                                       else
+                       spout2: if (p) { lprintf(p,lastmonst); beep(); }
+                                       checkloss(i);
+                                       return(0);
+
+               case 3:         i = rnd(20)+25-c[AC];  goto spout;
+
+               case 4: if (c[STRENGTH]>3)
+                                       {
+                                       p="\nThe %s stung you!  You feel weaker"; beep();
+                                       --c[STRENGTH];
+                                       }
+                               else p="\nThe %s stung you!";
+                               break;
+
+               case 5:         p="\nThe %s blasts you with his cold breath";
+                                       i = rnd(15)+18-c[AC];  goto spout2;
+
+               case 6:         lprintf("\nThe %s drains you of your life energy!",lastmonst);
+                                       loselevel();  beep();  return(0);
+
+               case 7:         p="\nThe %s got you with a gusher!";
+                                       i = rnd(15)+25-c[AC];  goto spout2;
+
+               case 8:         if (c[NOTHEFT]) return(0); /* he has a device of no theft */
+                                       if (c[GOLD])
+                                               {
+                                               p="\nThe %s hit you -- Your purse feels lighter";
+                                               if (c[GOLD]>32767)  c[GOLD]>>=1;
+                                                       else c[GOLD] -= rnd((int)(1+(c[GOLD]>>1)));
+                                               if (c[GOLD] < 0) c[GOLD]=0;
+                                               }
+                                       else  p="\nThe %s couldn't find any gold to steal";
+                                       lprintf(p,lastmonst); disappear(xx,yy); beep();
+                                       bottomgold();  return(1);
+
+               case 9: for(j=50; ; )   /* disenchant */
+                                       {
+                                       i=rund(26);  m=iven[i]; /* randomly select item */
+                                       if (m>0 && ivenarg[i]>0 && m!=OSCROLL && m!=OPOTION)
+                                               {
+                                               if ((ivenarg[i] -= 3)<0) ivenarg[i]=0;
+                                               lprintf("\nThe %s hits you -- you feel a sense of loss",lastmonst);
+                                               srcount=0; beep(); show3(i);  bottomline();  return(0);
+                                               }
+                                       if (--j<=0)
+                                               {
+                                               p="\nThe %s nearly misses"; break;
+                                               }
+                                       break;
+                                       }               
+                               break;
+
+               case 10:   p="\nThe %s hit you with his barbed tail";
+                                  i = rnd(25)-c[AC];  goto spout2;
+
+               case 11:        p="\nThe %s has confused you"; beep();
+                                       c[CONFUSE]+= 10+rnd(10);                break;
+
+               case 12:        /*      performs any number of other special attacks    */
+                                       return(spattack(spsel[rund(10)],xx,yy));
+
+               case 13:        p="\nThe %s flattens you with his psionics!";
+                                       i = rnd(15)+30-c[AC];  goto spout2;
+
+               case 14:        if (c[NOTHEFT]) return(0); /* he has device of no theft */
+                                       if (emptyhanded()==1)
+                                         {
+                                         p="\nThe %s couldn't find anything to steal";
+                                         break;
+                                         }
+                                       lprintf("\nThe %s picks your pocket and takes:",lastmonst);
+                                       beep();
+                                       if (stealsomething()==0) lprcat("  nothing"); disappear(xx,yy);
+                                       bottomline();  return(1);
+
+               case 15:        i= rnd(10)+ 5-c[AC];
+                       spout3: p="\nThe %s bit you!";
+                                       goto spout2;
+
+               case 16:        i= rnd(15)+10-c[AC];  goto spout3;
+               };
+       if (p) { lprintf(p,lastmonst); bottomline(); }
+       return(0);
+       }
+
+/*
+ *     checkloss(x)    Routine to subtract hp from user and flag bottomline display
+ *             int x;
+ *
+ *     Routine to subtract hitpoints from the user and flag the bottomline display
+ *     Enter with the number of hit points to lose
+ *     Note: if x > c[HP] this routine could kill the player!
+ */
+checkloss(x)
+       int x;
+       {
+       if (x>0) { losehp(x);  bottomhp(); }
+       }
+
+/*
+ *     annihilate()    Routine to annihilate all monsters around player (playerx,playery)
+ *
+ *     Gives player experience, but no dropped objects
+ *     Returns the experience gained from all monsters killed
+ */
+annihilate()
+       {
+       int i,j;
+       register long k;
+       register char *p;
+       for (k=0, i=playerx-1; i<=playerx+1; i++)
+         for (j=playery-1; j<=playery+1; j++)
+               if (!vxy(&i,&j)) /* if not out of bounds */
+                       if (*(p= &mitem[i][j])) /* if a monster there */
+                               if (*p<DEMONLORD+2)
+                                       {
+                                       k += monster[*p].experience;    *p=know[i][j]=0;
+                                       }
+                               else
+                                       {
+                                       lprintf("\nThe %s barely escapes being annihilated!",monster[*p].name);
+                                       hitp[i][j] = (hitp[i][j]>>1) + 1; /* lose half hit points*/
+                                       }
+       if (k>0)
+               {
+               lprcat("\nYou hear loud screams of agony!");    raiseexperience((long)k);
+               }
+       return(k);
+       }
+
+/*
+ *     newsphere(x,y,dir,lifetime)  Function to create a new sphere of annihilation
+ *             int x,y,dir,lifetime;
+ *
+ *     Enter with the coordinates of the sphere in x,y
+ *       the direction (0-8 diroffx format) in dir, and the lifespan of the
+ *       sphere in lifetime (in turns)
+ *     Returns the number of spheres currently in existence
+ */
+newsphere(x,y,dir,life)
+       int x,y,dir,life;
+       {
+       int m;
+       struct sphere *sp;
+       if (((sp=(struct sphere *)malloc(sizeof(struct sphere)))) == 0)
+               return(c[SPHCAST]);     /* can't malloc, therefore failure */
+       if (dir>=9) dir=0;      /* no movement if direction not found */
+       if (level==0) vxy(&x,&y);       /* don't go out of bounds */
+       else
+               {
+               if (x<1) x=1;  if (x>=MAXX-1) x=MAXX-2;
+               if (y<1) y=1;  if (y>=MAXY-1) y=MAXY-2;
+               }
+       if ((m=mitem[x][y]) >= DEMONLORD+4)     /* demons dispel spheres */
+               {
+               know[x][y]=1; show1cell(x,y);   /* show the demon (ha ha) */
+               cursors(); lprintf("\nThe %s dispels the sphere!",monster[m].name);
+               beep(); rmsphere(x,y);  /* remove any spheres that are here */
+               return(c[SPHCAST]);
+               }
+       if (m==DISENCHANTRESS) /* disenchantress cancels spheres */
+               {
+               cursors(); lprintf("\nThe %s causes cancellation of the sphere!",monster[m].name); beep();
+boom:  sphboom(x,y);   /* blow up stuff around sphere */
+               rmsphere(x,y);  /* remove any spheres that are here */
+               return(c[SPHCAST]);
+               }
+       if (c[CANCELLATION]) /* cancellation cancels spheres */
+               {
+               cursors(); lprcat("\nAs the cancellation takes effect, you hear a great earth shaking blast!"); beep();
+               goto boom;
+               }
+       if (item[x][y]==OANNIHILATION) /* collision of spheres detonates spheres */
+               {
+               cursors(); lprcat("\nTwo spheres of annihilation collide! You hear a great earth shaking blast!"); beep();
+               rmsphere(x,y);
+               goto boom;
+               }
+       if (playerx==x && playery==y) /* collision of sphere and player! */
+               {
+               cursors();
+               lprcat("\nYou have been enveloped by the zone of nothingness!\n");
+               beep(); rmsphere(x,y);  /* remove any spheres that are here */
+               nap(4000);  died(258);
+               }
+       item[x][y]=OANNIHILATION;  mitem[x][y]=0;  know[x][y]=1;
+       show1cell(x,y); /* show the new sphere */
+       sp->x=x;  sp->y=y;  sp->lev=level;  sp->dir=dir;  sp->lifetime=life;  sp->p=0;
+       if (spheres==0) spheres=sp;     /* if first node in the sphere list */
+       else    /* add sphere to beginning of linked list */
+               {
+               sp->p = spheres;        spheres = sp;
+               }
+       return(++c[SPHCAST]);   /* one more sphere in the world */
+       }
+
+/*
+ *     rmsphere(x,y)           Function to delete a sphere of annihilation from list
+ *             int x,y;
+ *
+ *     Enter with the coordinates of the sphere (on current level)
+ *     Returns the number of spheres currently in existence
+ */
+rmsphere(x,y)
+       int x,y;
+       {
+       register struct sphere *sp,*sp2=0;
+       for (sp=spheres; sp; sp2=sp,sp=sp->p)
+         if (level==sp->lev)   /* is sphere on this level? */
+           if ((x==sp->x) && (y==sp->y))       /* locate sphere at this location */
+                       {
+                       item[x][y]=mitem[x][y]=0;  know[x][y]=1;
+                       show1cell(x,y); /* show the now missing sphere */
+                       --c[SPHCAST];   
+                       if (sp==spheres) { sp2=sp; spheres=sp->p; free((char*)sp2); }
+                       else
+                               { sp2->p = sp->p;  free((char*)sp); }
+                       break;
+                       }
+       return(c[SPHCAST]);     /* return number of spheres in the world */
+       }
+
+/*
+ *     sphboom(x,y)    Function to perform the effects of a sphere detonation
+ *             int x,y;
+ *
+ *     Enter with the coordinates of the blast, Returns no value
+ */
+sphboom(x,y)
+       int x,y;
+       {
+       register int i,j;
+       if (c[HOLDMONST]) c[HOLDMONST]=1;
+       if (c[CANCELLATION]) c[CANCELLATION]=1;
+       for (j=max(1,x-2); j<min(x+3,MAXX-1); j++)
+         for (i=max(1,y-2); i<min(y+3,MAXY-1); i++)
+               {
+               item[j][i]=mitem[j][i]=0;
+               show1cell(j,i);
+               if (playerx==j && playery==i)
+                       {
+                       cursors(); beep();
+                       lprcat("\nYou were too close to the sphere!");
+                       nap(3000);
+                       died(283); /* player killed in explosion */
+                       }
+               }
+       }
+
+/*
+ *     genmonst()              Function to ask for monster and genocide from game
+ *
+ *     This is done by setting a flag in the monster[] structure
+ */
+genmonst()
+       {
+       register int i,j;
+       cursors();  lprcat("\nGenocide what monster? ");
+       for (i=0; (!isalpha(i)) && (i!=' '); i=getchar());
+       lprc(i);
+       for (j=0; j<MAXMONST; j++)      /* search for the monster type */
+               if (monstnamelist[j]==i)        /* have we found it? */
+                       {
+                       monster[j].genocided=1; /* genocided from game */
+                       lprintf("  There will be no more %s's",monster[j].name);
+                       /* now wipe out monsters on this level */
+                       newcavelevel(level); draws(0,MAXX,0,MAXY); bot_linex();
+                       return;
+                       }
+       lprcat("  You sense failure!");
+       }
+