home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / games / larn / monster.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-28  |  40.6 KB  |  1,388 lines

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