[comp.sources.games] v11i088: larn - dungeon type adventure game, Part05/11

billr@saab.CNA.TEK.COM (Bill Randle) (12/19/90)

Submitted-by: routley@tle.ENET.DEC.COM (Kevin Routley)
Posting-number: Volume 11, Issue 88
Archive-name: larn/Part05
Environment: Unix, VMS, MS-DOS, termcap



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 5 (of 11)."
# Contents:  Makefile movem.c savelev.c spells.c
# Wrapped by billr@saab on Tue Dec 18 10:14:18 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(402 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#
XOBJ=	action.o bill.o config.o create.o data.o diag.o display.o \
X	fortune.o global.o help.o io.o main.o monster.o \
X	moreobj.o movem.o msdos.o nap.o object.o regen.o savelev.o \
X	scores.o signal.o spells.o spheres.o store.o \
X	tok.o vms.o
X#
X#
X
XCFLAGS=-DDGK -DBSD -D'LARNHOME="/usr/users/routley/larncc/"'
X
Xlarn122: $(OBJ)
X	cc -o larn122 $(OBJ) -ltermcap
X
X.c.o: 
X	cc $(CFLAGS) -c $*.c 
X
X.c: header.h
X
END_OF_FILE
if test 402 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'movem.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'movem.c'\"
else
echo shar: Extracting \"'movem.c'\" \(18818 characters\)
sed "s/^X//" >'movem.c' <<'END_OF_FILE'
X/*
X *  movem.c (move monster)      Larn is copyrighted 1986 by Noah Morgan.
X *
X *  Here are the functions in this file:
X *
X *  movemonst()     Routine to move the monsters toward the player
X *  build_proximity_ripple()  Build proximity ripple for smart monster move
X *  move_scared()   Move scared monsters
X *  move_smart()    Move smart monsters
X *  move_dumb()     Move dumb monsters
X *  mmove(x,y,xd,yd)    Function to actually perform the monster movement
X */
X#include "header.h"
X#define min(x,y) (((x)>(y))?(y):(x))
X#define max(x,y) (((x)>(y))?(x):(y))
X
Xvoid movemonst();
Xvoid build_proximity_ripple();
Xvoid move_scared();
Xvoid move_smart();
Xvoid move_dumb();
Xvoid mmove();
X
X# define IDISTNORM   8  /* was 17 - dgk */
X# define IDISTAGGR  20  /* was 40 - dgk */
X
Xstatic short w1[9],w1x[9],w1y[9];
Xstatic int tmp1,tmp2,tmp3,tmp4,distance;
X
X/* list of monsters to move */
Xstatic struct foo { char x ; char y; char smart; } movelist[250] ;
X
X/*
X *  movemonst()     Routine to move the monsters toward the player
X *
X *  This routine has the responsibility to determine which monsters are to
X *  move, and call movemt() to do the move.
X *  Returns no value.
X */
Xvoid movemonst()
X    {
X    register int i,j,movecnt=0, smart_count, min_int ;
X
X    if (c[TIMESTOP]) return;    /* no action if time is stopped */
X    if (c[HASTESELF])  if ((c[HASTESELF]&1)==0)  return;
X    if (spheres) movsphere();   /* move the spheres of annihilation if any */
X    if (c[HOLDMONST])  return;  /* no action if monsters are held */
X
X    if (c[AGGRAVATE])   /* determine window of monsters to move */
X      {
X      tmp1=playery-5; tmp2=playery+6; tmp3=playerx-10; tmp4=playerx+11;
X      distance=IDISTAGGR; /* depth of intelligent monster movement */
X      }
X    else
X      {
X      tmp1=playery-3; tmp2=playery+4; tmp3=playerx-5; tmp4=playerx+6;
X      distance=IDISTNORM; /* depth of intelligent monster movement */
X      }
X
X    if (level == 0) /* if on outside level monsters can move in perimeter */
X        {
X        if (tmp1 < 0) tmp1=0;        if (tmp2 > MAXY) tmp2=MAXY;
X        if (tmp3 < 0) tmp3=0;        if (tmp4 > MAXX) tmp4=MAXX;
X        }
X    else /* if in a dungeon monsters can't be on the perimeter (wall there) */
X        {
X        if (tmp1 < 1) tmp1=1;        if (tmp2 > MAXY-1) tmp2=MAXY-1;
X        if (tmp3 < 1) tmp3=1;        if (tmp4 > MAXX-1) tmp4=MAXX-1;
X        }
X
X    /* We now have a window in which to move monsters.  First find all
X       monsters in the window, then decide whether or not to move them.
X       Its faster that way since the size of the window is usually larger
X       than the # of monsters in that window.
X
X       Find all monsters in the window.  The only time a monster cannot
X       move is if: monsters are not aggrevated, AND player is stealthed,
X       AND the monster is asleep due to stealth.  Split into two
X       separate loops in order to simplify the if statement inside the
X       loop for the most common case.
X
X       Also count # of smart monsters.
X    */
X    smart_count = 0 ;
X    min_int = 10 - c[HARDGAME] ;    /* minimum monster intelligence to move smart */
X    if ( c[AGGRAVATE] || !c[STEALTH] )
X        {
X        for ( j = tmp1 ; j < tmp2 ; j++ )
X            for ( i = tmp3 ; i < tmp4 ; i++ )
X                if (mitem[i][j])
X                    {
X                    movelist[movecnt].x = i;
X                    movelist[movecnt].y = j ;
X                    if ( monster[mitem[i][j]].intelligence > min_int )
X                        {
X                        movelist[movecnt].smart = TRUE ;
X                        smart_count++;
X                        }
X                    else
X                        movelist[movecnt].smart = FALSE ;
X                    movecnt++;
X                    }
X        }
X    else
X        {
X        for ( j = tmp1; j < tmp2 ; j++ )
X            for ( i = tmp3 ; i < tmp4 ; i++ )
X                if ( mitem[i][j] && stealth[i][j] )   /* stealth[x][y] = 1 when AWAKE! */
X                    {
X                    movelist[movecnt].x = i;
X                    movelist[movecnt].y = j ;
X                    if ( monster[mitem[i][j]].intelligence > min_int )
X                        {
X                        movelist[movecnt].smart = TRUE ;
X                        smart_count++;
X                        }
X                    else
X                        movelist[movecnt].smart = FALSE ;
X                    movecnt++;
X                    }
X        }
X
X    /* now move the monsters in the movelist.  If we have at least one
X       smart monster, build a proximity ripple and use it for all smart
X       monster movement.
X    */
X    if (movecnt > 0 )
X        {
X        if ( c[SCAREMONST] )
X            for ( i = 0 ; i < movecnt ; i++ )
X                move_scared( movelist[i].x, movelist[i].y );
X        else
X            {
X            if ( smart_count > 0 )
X                {
X                /* I was going to put in code that prevented the rebuilding
X                   of the proximity ripple if the player had not moved since
X                   the last turn.  Unfortunately, this permits the player to
X                   blast down doors to treasure rooms and not have a single
X                   intelligent monster move.
X                */
X                build_proximity_ripple();
X                for ( i = 0 ; i < movecnt ; i++ )
X                    if ( movelist[i].smart )
X                        move_smart( movelist[i].x, movelist[i].y );
X                    else
X                        move_dumb( movelist[i].x, movelist[i].y );
X                }
X            else
X                for ( i = 0 ; i < movecnt ; i++ )
X                    move_dumb( movelist[i].x, movelist[i].y );
X            }
X        }
X
X    /* Also check for the last monster hit.  This is necessary to prevent
X       the player from getting free hits on a monster with long range
X       spells or when stealthed.
X    */
X    if ( c[AGGRAVATE] || !c[STEALTH] )
X        {
X        /* If the last monster hit is within the move window, its already
X           been moved.
X        */
X    if ( ( ( lasthx < tmp3 || lasthx >= tmp4 ) ||
X           ( lasthy < tmp1 || lasthy >= tmp2 ) ) &&
X           mitem[lasthx][lasthy] )
X            {
X        if ( c[SCAREMONST] )
X                move_scared( lasthx, lasthy );
X            else
X        if ( monster[mitem[lasthx][lasthy]].intelligence > min_int )
X                    {
X            if ( smart_count == 0 )
X                        build_proximity_ripple( );
X                    move_smart( lasthx, lasthy );
X                    }
X                else
X                    move_dumb( lasthx, lasthy );
X            lasthx = w1x[0];   /* make sure the monster gets moved again */
X            lasthy = w1y[0];
X            }
X        }
X    else
X        {
X        /* If the last monster hit is within the move window, and not
X           asleep due to stealth, then it has already been moved.
X       Otherwise (monster outside window, asleep due to stealth),
X       move the monster and update the lasthit x,y position.
X        */
X    if ( ( lasthx < tmp3 || lasthx >= tmp4 ) ||
X             ( lasthy < tmp1 || lasthy >= tmp2 ) &&
X       mitem[lasthx][lasthy] || !stealth[lasthx][lasthy] )
X            {
X        if ( c[SCAREMONST] )
X                move_scared( lasthx, lasthy );
X            else
X        if ( monster[mitem[lasthx][lasthy]].intelligence > min_int )
X                    {
X            if ( smart_count == 0 )
X                        build_proximity_ripple( );
X                    move_smart( lasthx, lasthy );
X                    }
X                else
X                    move_dumb( lasthx, lasthy );
X            lasthx = w1x[0];   /* make sure the monster gets moved again */
X            lasthy = w1y[0];
X            }
X        }
X    }
X
Xstatic char screen[MAXX][MAXY];    /* proximity ripple storage */
X
X/* queue for breadth-first 'search' build of proximity ripple.
X*/
X#define MAX_QUEUE 100
X    struct queue_entry
X        {
X        char x ;
X        char y ;
X        char distance ;
X        } queue[MAX_QUEUE];
X    int queue_head = 0 ;
X    int queue_tail = 0 ;
X
X/* put a location on the proximity ripple queue
X*/
X#define PUTQUEUE( _x, _y, _d )          \
X    {                                   \
X    queue[queue_tail].x = (_x) ;        \
X    queue[queue_tail].y = (_y) ;        \
X    queue[queue_tail].distance = (_d);  \
X    queue_tail++;                       \
X    if (queue_tail == MAX_QUEUE)        \
X        queue_tail = 0 ;                \
X    }
X
X/* take a location from the proximity ripple queue
X*/
X#define GETQUEUE( _x, _y, _d )          \
X    {                                   \
X    (_x) = queue[queue_head].x ;        \
X    (_y) = queue[queue_head].y ;        \
X    (_d) = queue[queue_head].distance ; \
X    queue_head++;                       \
X    if (queue_head == MAX_QUEUE)        \
X        queue_head = 0 ;                \
X    }
X
X/* check for the proximity ripple queue being empty
X*/
X#define QUEUEEMPTY() (queue_head == queue_tail)
X
X/*
X    For smart monster movement, build a proximity ripple from the player's
X    position, out to a 'distance' of 20.  For example:
X
X    W 5 4 4 W W X    Player is at position marked 1
X    W 5 W 3 3 W W    W is a wall.  Monsters will attempt
X    W 6 W 2 W 4 W    to move to a location with a smaller
X    W 7 W 1 W 5 W    value than their current position.
X    W 8 W W W 6 W    Note that a monster at location X
X    W 9 9 8 7 7 7    will not move at all.
X    W W W 8 W W W
X*/
Xvoid build_proximity_ripple()
X    {
X    int xl, yl, xh, yh ;
X    int k, m, z, tmpx, tmpy;
X    int curx, cury, curdist;
X
X    xl=tmp3-2; yl=tmp1-2; xh=tmp4+2;  yh=tmp2+2;
X    vxy(&xl,&yl);  vxy(&xh,&yh);
X    for (k=yl; k<=yh; k++)
X    for (m=xl; m<=xh; m++)
X        {
X        switch(item[m][k])
X        {
X        case OWALL:
X        case OPIT:
X        case OTRAPARROW:
X        case ODARTRAP:
X        case OCLOSEDDOOR:
X        case OTRAPDOOR:
X        case OTELEPORTER:
X            screen[m][k]=127;
X            break;
X        default:
X            screen[m][k] = 0;
X            break;
X        };
X          }
X      screen[playerx][playery]=1;
X
X/* now perform proximity ripple from playerx,playery to monster */
X      xl=tmp3-1; yl=tmp1-1; xh=tmp4+1;  yh=tmp2+1;
X      vxy(&xl,&yl);  vxy(&xh,&yh);
X
X      PUTQUEUE( playerx, playery, 1 );
X      do
X      {
X      GETQUEUE( curx, cury, curdist );
X
X      /* test all spots around the current one being looked at.
X      */
X      if ( ( curx >= xl && curx < xh ) &&
X           ( cury >= yl && cury < yh ) )
X          {
X          for (z=1; z<9; z++)
X          {
X          tmpx = curx + diroffx[z] ;
X          tmpy = cury + diroffy[z] ;
X          if (screen[tmpx][tmpy] == 0 )
X              {
X              screen[tmpx][tmpy] = curdist + 1;
X              PUTQUEUE( tmpx, tmpy, curdist + 1 );
X              }
X          }
X          }
X      }
X      while (!QUEUEEMPTY());
X
X    }
X
X/*
X    Move scared monsters randomly away from the player position.
X*/
Xvoid move_scared( i, j )
Xint i, j ;
X    {
X    int xl, yl, tmp, tmpitem ;
X
X    /* check for a half-speed monster, and check if not to move.  Could be
X       done in the monster list build.
X    */
X    switch(mitem[i][j])
X        {
X        case TROGLODYTE:  case HOBGOBLIN:  case METAMORPH:  case XVART:
X        case INVISIBLESTALKER:  case ICELIZARD: if ((gtime & 1) == 1) return;
X        };
X
X    if ((xl = i+rnd(3)-2) < 0)
X    xl=0;
X    if (xl >= MAXX)
X    xl=MAXX-1;
X    if ((yl = j+rnd(3)-2) < 0)
X    yl=0;
X    if (yl >= MAXY)
X    yl=MAXY-1;
X
X    if ((tmp=item[xl][yl]) != OWALL)
X    if (mitem[xl][yl] == 0)
X        if ((mitem[i][j] != VAMPIRE) || (tmp != OMIRROR))
X        if (tmp != OCLOSEDDOOR)
X            mmove(i,j,xl,yl);
X    }
X
X/*
X    Move monsters that are moving intelligently, using the proximity
X    ripple.  Attempt to move to a position in the proximity ripple
X    that is closer to the player.
X
X    Parameters: the X,Y position of the monster to be moved.
X*/
Xvoid move_smart( i, j )
Xint i,j ;
X    {
X    int x,y,z ;
X
X    /* check for a half-speed monster, and check if not to move.  Could be
X       done in the monster list build.
X    */
X    switch(mitem[i][j])
X        {
X        case TROGLODYTE:  case HOBGOBLIN:  case METAMORPH:  case XVART:
X        case INVISIBLESTALKER:  case ICELIZARD: if ((gtime & 1) == 1) return;
X        };
X
X    /* find an adjoining location in the proximity ripple that is
X       closer to the player (has a lower value) than the monster's
X       current position.
X    */
X    if (mitem[i][j] != VAMPIRE)
X    for (z=1; z<9; z++) /* go around in a circle */
X        {
X        x = i + diroffx[z] ;
X        y = j + diroffy[z] ;
X        if ( screen[x][y] < screen[i][j] )
X        if ( !mitem[x][y] )
X            {
X            mmove(i,j,w1x[0]=x,w1y[0]=y);
X            return;
X            }
X        }
X    else
X    /* prevent vampires from moving onto mirrors
X    */
X    for (z=1; z<9; z++) /* go around in a circle */
X        {
X        x = i + diroffx[z] ;
X        y = j + diroffy[z] ;
X        if (( screen[x][y] < screen[i][j] ) &&
X        ( item[x][y] != OMIRROR ))
X        if ( !mitem[x][y] )
X            {
X            mmove(i,j,w1x[0]=x,w1y[0]=y);
X            return;
X            }
X        }
X
X    }
X
X/*
X   For monsters that are not moving in an intelligent fashion.  Move
X   in a direct fashion toward the player's current position.
X
X   Parameters: the X,Y position of the monster to move.
X*/
Xvoid move_dumb( i, j )
Xint i, j ;
X    {
X    int xl, yl, xh, yh ;
X    int k, m, tmp, tmpd, tmpx, tmpy ;
X
X    /* check for a half-speed monster, and check if not to move.  Could be
X       done in the monster list build.
X    */
X    switch(mitem[i][j])
X        {
X        case TROGLODYTE:  case HOBGOBLIN:  case METAMORPH:  case XVART:
X        case INVISIBLESTALKER:  case ICELIZARD: if ((gtime & 1) == 1) return;
X        };
X
X    /* dumb monsters move here */
X    /* set up range of spots to check.  instead of checking all points
X       around the monster, only check those closest to the player.  For
X       example, if the player is up and right of the monster, check only
X       the three spots up and right of the monster.
X    */
X    xl=i-1;  yl=j-1;  xh=i+2;  yh=j+2;
X    if (i<playerx) xl++; else if (i>playerx) --xh;
X    if (j<playery) yl++; else if (j>playery) --yh;
X
X    /* check all spots in the range.  find the one that is closest to
X       the player.  if the monster is already next to the player, exit
X       the check immediately.
X    */
X    tmpd = 10000 ;
X    tmpx = i ;  tmpy = j ;
X    for ( k = xl ; k < xh ; k++ )
X    for ( m = yl ; m < yh ; m++ )
X        if ( k == playerx && m == playery )
X        {
X        tmpd = 1 ;
X        tmpx = k ;
X        tmpy = m ;
X        break;       /* exitloop */
X        }
X        else if ((item[k][m] != OWALL) &&
X             (item[k][m] != OCLOSEDDOOR) &&
X             ((mitem[k][m] == 0 ) || (( k == i ) && ( m == j ))) &&
X             ((mitem[i][j] != VAMPIRE) || (item[k][m] != OMIRROR)))
X        {
X        tmp = (playerx-k)*(playerx-k)+(playery-m)*(playery-m);
X        if (tmp < tmpd)
X            {
X            tmpd = tmp;
X            tmpx = k;
X            tmpy = m;
X            }  /* end if */
X        }  /* end if */
X
X    /* we have finished checking the spaces around the monster.  if
X       any can be moved on and are closer to the player than the
X       current location, move the monster.
X    */
X    if ((tmpd < 10000) && ((tmpx != i) || (tmpy != j)))
X    {
X    mmove( i, j, tmpx, tmpy );
X    w1x[0] = tmpx ;              /* for last monster hit */
X    w1y[0] = tmpy ;
X    }
X    else
X    {
X    w1x[0] = i ;              /* for last monster hit */
X    w1y[0] = j ;
X    }
X    }  /* end move_dumb() */
X
X/*
X *  mmove(x,y,xd,yd)    Function to actually perform the monster movement
X *      int x,y,xd,yd;
X *
X *  Enter with the from coordinates in (x,y) and the destination coordinates
X *  in (xd,yd).
X */
Xvoid mmove(aa,bb,cc,dd)
X    int aa,bb,cc,dd;
X    {
X    register int tmp,i,flag;
X    char *who,*p;
X    flag=0; /* set to 1 if monster hit by arrow trap */
X    if ((cc==playerx) && (dd==playery))
X        {
X        hitplayer(aa,bb);
X        return;
X        }
X    i=item[cc][dd];
X    if ((i==OPIT) || (i==OTRAPDOOR))
X      switch(mitem[aa][bb])
X        {
X    case BAT:           case EYE:
X    case SPIRITNAGA:    case PLATINUMDRAGON:    case WRAITH:
X        case VAMPIRE:       case SILVERDRAGON:      case POLTERGEIST:
X        case DEMONLORD:     case DEMONLORD+1:       case DEMONLORD+2:
X        case DEMONLORD+3:   case DEMONLORD+4:       case DEMONLORD+5:
X        case DEMONLORD+6:   case DEMONPRINCE:   break;
X
X        default:    mitem[aa][bb]=0; /* fell in a pit or trapdoor */
X        };
X    tmp = mitem[aa][bb];
X    mitem[cc][dd] = tmp;
X    if (i==OANNIHILATION)
X        {
X        if (tmp>=DEMONLORD+3) /* demons dispel spheres */
X            {
X            cursors();
X            lprintf("\nThe %s dispels the sphere!",monster[tmp].name);
X            rmsphere(cc,dd);    /* delete the sphere */
X            }
X        else mitem[cc][dd]=i=tmp=0;
X        }
X    stealth[cc][dd]=1;
X    if ((hitp[cc][dd] = hitp[aa][bb]) < 0) hitp[cc][dd]=1;
X    mitem[aa][bb] = 0;              
X    if (tmp == LEPRECHAUN)
X        switch(i)
X            {
X            case OGOLDPILE:  case OMAXGOLD:  case OKGOLD:  case ODGOLD:
X            case ODIAMOND:   case ORUBY:     case OEMERALD: case OSAPPHIRE:
X                    item[cc][dd] = 0; /* leprechaun takes gold */
X            };
X
X    if (tmp == TROLL)  /* if a troll regenerate him */
X        if ((gtime & 1) == 0)
X            if (monster[tmp].hitpoints > hitp[cc][dd])  hitp[cc][dd]++;
X
X    if (i==OTRAPARROW)  /* arrow hits monster */
X        { who = "An arrow";  if ((hitp[cc][dd] -= rnd(10)+level) <= 0)
X            { mitem[cc][dd]=0;  flag=2; } else flag=1; }
X    if (i==ODARTRAP)    /* dart hits monster */
X        { who = "A dart";  if ((hitp[cc][dd] -= rnd(6)) <= 0)
X            { mitem[cc][dd]=0;  flag=2; } else flag=1; }
X    if (i==OTELEPORTER) /* monster hits teleport trap */
X        { flag=3; fillmonst(mitem[cc][dd]);  mitem[cc][dd]=0; }
X    if (c[BLINDCOUNT]) return;  /* if blind don't show where monsters are   */
X# ifdef DGK
X    if (know[cc][dd] & HAVESEEN) 
X# else
X    if (know[cc][dd] & 1) 
X# endif
X        {
X        p=0;
X        if (flag) cursors();
X        switch(flag)
X          {
X          case 1: p="\n%s hits the %s";  break;
X          case 2: p="\n%s hits and kills the %s";  break;
X          case 3: p="\nThe %s%s gets teleported"; who="";  break;
X          };
X        if (p) { lprintf(p,who,monster[tmp].name); beep(); }
X        }
X/*  if (yrepcount>1) { know[aa][bb] &= 2;  know[cc][dd] &= 2; return; } */
X# ifdef DGK
X    if (know[aa][bb] & HAVESEEN)   show1cell(aa,bb);
X    if (know[cc][dd] & HAVESEEN)   show1cell(cc,dd);
X# else
X    if (know[aa][bb] & 1)   show1cell(aa,bb);
X    if (know[cc][dd] & 1)   show1cell(cc,dd);
X# endif
X    }
END_OF_FILE
if test 18818 -ne `wc -c <'movem.c'`; then
    echo shar: \"'movem.c'\" unpacked with wrong size!
fi
# end of 'movem.c'
fi
if test -f 'savelev.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'savelev.c'\"
else
echo shar: Extracting \"'savelev.c'\" \(3594 characters\)
sed "s/^X//" >'savelev.c' <<'END_OF_FILE'
X/* savelev.c		 Larn is copyrighted 1986 by Noah Morgan. */
X#include "header.h"
X
X# ifdef MSDOS
X
Xextern int swapfd;		/* swap file file descriptor */
X
X
XDISKBLOCK *
Xgetfreediskblk()
X{
X	DISKBLOCK	*dp;
X
X	for (dp = diskblks; dp; dp = dp->next)
X		if (dp->level == FREEBLOCK)
X			return dp;
X	levelinfo();
X	error("Can't find a free disk block ?\n");
X}
X
XRAMBLOCK *
Xgetramblk(lev)
X{
X	RAMBLOCK	*rp, *orp;
X	DISKBLOCK	*dp;
X	long		otime;
X	unsigned int	bytes;
X
X	/* Check if the level is in memory already.
X	 */
X	for (rp = ramblks; rp; rp = rp->next)
X		if (rp->level == lev)
X			return rp;
X
X	/* Else grab the first available one.
X	 */
X	for (rp = ramblks; rp; rp = rp->next)
X		if (rp->level == FREEBLOCK)
X			return rp;
X
X	/* No ramblocks free, so swap out the oldest level
X	 */
X	dp = getfreediskblk();
X
X# ifdef ndef
Xwarn("\nTrying to swap\n");
X# endif
X
X	/* Find the oldest level for swapping out.
X	 */
X	otime = ramblks->gtime;
X	orp = ramblks;
X	for (rp = ramblks->next; rp; rp = rp->next) {
X		if (rp->gtime < otime) {
X			otime = rp->gtime;
X			orp = rp;
X		}
X	}
X
X	/* Send the oldest level out to disk.
X	 */
X	if (lseek(swapfd, dp->fpos, 0) < 0)
X		error("Can't seek to %ld\n", dp->fpos);
X
X	bytes = sizeof rp->cell;
X	if (write(swapfd, (char *) orp->cell, bytes) != bytes)
X		error("Out of space writing swap file !\n");
X
X	/* Update the level information
X	 */
X	dp->level = orp->level;
X	dp->gtime = orp->gtime;
X	orp->level = FREEBLOCK;
X# ifdef ndef
Xwarn("Successful swap\n");
X# endif
X	return orp;
X}
X
X
X# endif
X
X/*
X *	routine to save the present level into storage
X */
Xsavelevel()
X	{
X	register struct cel *pcel;
X	register char *pitem,*pknow,*pmitem;
X	register short *phitp,*piarg;
X	register struct cel *pecel;
X
X# ifdef MSDOS
X	RAMBLOCK	*rp;
X
X	rp = getramblk(level);
X	pcel = rp->cell;
X	rp->gtime = gtime;
X	rp->level = level;
X# else
X	pcel = &cell[level*MAXX*MAXY];	/* pointer to this level's cells */
X# endif
X	pecel = pcel + MAXX*MAXY;	/* pointer to past end of this level's cells */
X	pitem=item[0]; piarg=iarg[0]; pknow=know[0]; pmitem=mitem[0]; phitp=hitp[0];
X	while (pcel < pecel)
X		{
X		pcel->mitem  = *pmitem++;
X		pcel->hitp   = *phitp++;
X		pcel->item   = *pitem++;
X		pcel->know   = *pknow++;
X		pcel->iarg   = *piarg++;
X		pcel++;
X		}
X	}
X
X
X/*
X *	routine to restore a level from storage
X */
Xgetlevel()
X	{
X	register struct cel *pcel;
X	register char *pitem,*pknow,*pmitem;
X	register short *phitp,*piarg;
X	register struct cel *pecel;
X
X# ifdef MSDOS
X	RAMBLOCK	*rp;
X	DISKBLOCK	*dp;
X	unsigned int	bytes;
X
X	/* Is the level in memory already ?
X	 */
X	for (rp = ramblks; rp; rp = rp->next)
X		if (rp->level == level)
X			goto haverp;
X
X	/* Is it on disk ?
X	 */
X	for (dp = diskblks; dp; dp = dp->next)
X		if (dp->level == level)
X			break;
X	if (dp == NULL) {
X		levelinfo();
X		error("Level %d is neither in memory nor on disk\n", level);
X	}
X
X	/* Make room for it and read it in.
X	 */
X	rp = getramblk(level);
X	if (lseek(swapfd, dp->fpos, 0) < 0)
X		error("Can't seek to %ld\n", dp->fpos);
X	bytes = sizeof rp->cell;
X	if (read(swapfd, (char *) rp->cell, bytes) != bytes)
X		error("Didn't read %u bytes\n", bytes);
X
X	/* The disk space is available for future swaps.
X	 */
X	dp->level = FREEBLOCK;
Xhaverp:
X	pcel = rp->cell;
X	rp->level = FREEBLOCK;
X# else
X	pcel = &cell[level*MAXX*MAXY];	/* pointer to this level's cells */
X# endif
X	pecel = pcel + MAXX*MAXY;	/* pointer to past end of this level's cells */
X	pitem=item[0]; piarg=iarg[0]; pknow=know[0]; pmitem=mitem[0]; phitp=hitp[0];
X	while (pcel < pecel)
X		{
X		*pmitem++ = pcel->mitem;
X		*phitp++ = pcel->hitp;
X		*pitem++ = pcel->item;
X		*pknow++ = pcel->know;
X		*piarg++ = pcel->iarg;
X		pcel++;
X		}
X	}
END_OF_FILE
if test 3594 -ne `wc -c <'savelev.c'`; then
    echo shar: \"'savelev.c'\" unpacked with wrong size!
fi
# end of 'savelev.c'
fi
if test -f 'spells.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'spells.c'\"
else
echo shar: Extracting \"'spells.c'\" \(27476 characters\)
sed "s/^X//" >'spells.c' <<'END_OF_FILE'
X/*
X  cast()             Subroutine called by parse to cast a spell for the user
X  speldamage(x)      Function to perform spell functions cast by the player
X  loseint()          Routine to decrement your int (intelligence) if > 3
X  isconfuse()        Routine to check to see if player is confused
X  nospell(x,monst)   Routine to return 1 if a spell doesn't affect a monster
X  fullhit(xx)        Function to return full damage against a monst (aka web)
X  direct(spnum,dam,str,arg)   Routine to direct spell damage 1 square in 1 dir
X  godirect(spnum,dam,str,delay,cshow)     Function to perform missile attacks
X  ifblind(x,y)       Routine to put "monster" or the monster name into lastmosnt
X  tdirect(spnum)     Routine to teleport away a monster
X  omnidirect(sp,dam,str)  Routine to damage all monsters 1 square from player
X  dirsub(x,y)        Routine to ask for direction, then modify x,y for it
X  dirpoly(spnum)     Routine to ask for a direction and polymorph a monst
X  annihilate()   Routine to annihilate monsters around player, playerx,playery
X  genmonst()         Function to ask for monster and genocide from game
X*/
X
X#include "header.h"
X#include <ctype.h>
X
X#define min(x,y) (((x)>(y))?(y):(x))
X#define max(x,y) (((x)>(y))?(x):(y))
X
Xstruct isave    /* used for altar reality */
X    {
X    char type;  /* 0=item,  1=monster */
X    char id;    /* item number or monster number */
X    short arg;  /* the type of item or hitpoints of monster */
X    };
X
X/* Forward declarations
X*/
Xstatic void create_guardian();
Xextern hitm();
X
X/*
X *  cast()      Subroutine called by parse to cast a spell for the user
X *
X *  No arguments and no return value.
X */
Xstatic char eys[] = "\nEnter your spell: ";
Xcast()
X    {
X    register int i,j,a,b,d;
X    cursors();
X    if (c[SPELLS]<=0) 
X        {   
X        lprcat("\nYou don't have any spells!"); 
X        return; 
X        }
X    lprcat(eys);
X    --c[SPELLS];
X    while ((a=ttgetch())=='I')
X        { 
X        seemagic(-1); 
X        cursors();  
X        lprcat(eys);
X        }
X    if (a=='\33') 
X        goto over;                  /*  to escape casting a spell   */
X    if ((b=ttgetch())=='\33') 
X        goto over;                  /*  to escape casting a spell   */
X    if ((d=ttgetch())=='\33')
X        { 
Xover: 
X        lprcat(aborted); 
X        c[SPELLS]++; 
X        return;
X        }                           /*  to escape casting a spell   */
X#ifdef EXTRA
X    c[SPELLSCAST]++;
X#endif
X    for (lprc('\n'),j= -1,i=0; i<SPNUM; i++) /*seq search for his spell, hash?*/
X        if ((spelcode[i][0]==a) && (spelcode[i][1]==b) && (spelcode[i][2]==d))
X            if (spelknow[i])
X                {  speldamage(i);  j = 1;  i=SPNUM; }
X
X    if (j == -1) lprcat("  Nothing Happened ");
X    bottomline();
X    }
X
X/*
X *  speldamage(x)       Function to perform spell functions cast by the player
X *      int x;
X *
X *  Enter with the spell number, returns no value.
X *  Please insure that there are 2 spaces before all messages here
X */
Xstatic speldamage(x)
X    int x;
X    {
X    register int i,j,clev;
X    int xl,xh,yl,yh;
X    register char *p,*kn,*pm;
X
X    if (x>=SPNUM) return;   /* no such spell */
X    if (c[TIMESTOP])  { lprcat("  It didn't seem to work"); return; }  /* not if time stopped */
X    clev = c[LEVEL];
X    if ((rnd(23)==7) || (rnd(18) > c[INTELLIGENCE]))
X        { lprcat("  It didn't work!");  return; }
X    if (clev*3+2 < x)
X    {
X    lprcat("  Nothing happens.  You seem inexperienced at this");
X    return;
X    }
X
X    switch(x)
X        {
X/* ----- LEVEL 1 SPELLS ----- */
X
X        case 0: if (c[PROTECTIONTIME]==0)   c[MOREDEFENSES]+=2; /* protection field +2 */
X                c[PROTECTIONTIME] += 250;   return;
X
X        case 1: i = rnd(((clev+1)<<1)) + clev + 3;
X                godirect(x,i,(clev>=2)?"  Your missiles hit the %s":"  Your missile hit the %s",100,'+'); /* magic missile */
X
X                return;
X
X        case 2: if (c[DEXCOUNT]==0) c[DEXTERITY]+=3; /* dexterity   */
X                c[DEXCOUNT] += 400;     return;
X
X        case 3: i=rnd(3)+1;
X                p="  While the %s slept, you smashed it %d times";
X            ws: direct(x,fullhit(i),p,i); /*    sleep   */  return;
X
X        case 4: /*  charm monster   */  c[CHARMCOUNT] += c[CHARISMA]<<1;    return;
X
X        case 5: godirect(x,rnd(10)+15+clev,"  The sound damages the %s",70,'@'); /* sonic spear */
X                return;
X
X/* ----- LEVEL 2 SPELLS ----- */
X
X        case 6: i=rnd(3)+2; p="  While the %s is entangled, you hit %d times";
X                goto ws; /* web */
X
X        case 7: if (c[STRCOUNT]==0) c[STREXTRA]+=3; /*  strength    */
X                c[STRCOUNT] += 150+rnd(100);    return;
X
X        case 8: yl = playery-5;     /* enlightenment */
X                yh = playery+6;   xl = playerx-15;   xh = playerx+16;
X                vxy(&xl,&yl);   vxy(&xh,&yh); /* check bounds */
X                for (i=yl; i<=yh; i++) /* enlightenment */
X# ifdef DGK
X                    for (j=xl; j<=xh; j++)
X                        know[j][i]=KNOWALL;
X# else
X                    for (j=xl; j<=xh; j++)  know[j][i]=1;
X# endif
X                draws(xl,xh+1,yl,yh+1); return;
X
X        case 9: raisehp(20+(clev<<1));  return;  /* healing */
X
X        case 10:    c[BLINDCOUNT]=0;    return; /* cure blindness   */
X
X        case 11:    createmonster(makemonst(level+1)+8);  return;
X
X        case 12:    if (rnd(11)+7 <= c[WISDOM]) direct(x,rnd(20)+20+clev,"  The %s believed!",0);
X                    else lprcat("  It didn't believe the illusions!");
X                    return;
X
X        case 13:    /* if he has the amulet of invisibility then add more time */
X                    for (j=i=0; i<26; i++)
X                        if (iven[i]==OAMULET) j+= 1+ivenarg[i];
X                    c[INVISIBILITY] += (j<<7)+12;   return;
X
X/* ----- LEVEL 3 SPELLS ----- */
X
X        case 14:    godirect(x,rnd(25+clev)+25+clev,"  The fireball hits the %s",40,'*'); return; /*    fireball */
X
X        case 15:    godirect(x,rnd(25)+20+clev,"  Your cone of cold strikes the %s",60,'O');    /*  cold */
X                    return;
X
X        case 16:    dirpoly(x);  return;    /*  polymorph */
X
X        case 17:    c[CANCELLATION]+= 5+clev;   return; /*  cancellation    */
X
X        case 18:    c[HASTESELF]+= 7+clev;  return;  /* haste self  */
X
X        case 19:    omnidirect(x,30+rnd(10),"  The %s gasps for air");  /* cloud kill */
X                    return;
X
X        case 20:    xh = min(playerx+1,MAXX-2);     yh = min(playery+1,MAXY-2);
X                    for (i=max(playerx-1,1); i<=xh; i++) /* vaporize rock */
X                      for (j=max(playery-1,1); j<=yh; j++)
X                        {
X                        kn = &know[i][j];
X                            pm = &mitem[i][j];
X                        switch(*(p= &item[i][j]))
X                          {
X                          case OWALL: if (level < MAXLEVEL+MAXVLEVEL-1)
X                                            *p = *kn = 0;
X                                        break;
X
X                          case OSTATUE: if (c[HARDGAME]<3)
X                                             {
X                                             *p=OBOOK; iarg[i][j]=level;  *kn=0;
X                                             }
X                                        break;
X
X              case OTHRONE:
X                  *p= OTHRONE2;
X                  create_guardian( GNOMEKING, i, j );
X                  break;
X
X              case OALTAR:
X                  create_guardian( DEMONPRINCE, i, j );
X                  break;
X
X              case OFOUNTAIN:
X                  create_guardian( WATERLORD, i, j );
X                  break;
X              };
X                        switch(*pm)
X                            {
X                            case XORN:  ifblind(i,j);  hitm(i,j,200); break; /* Xorn takes damage from vpr */
X                            }
X                        }
X                    return;
X
X/* ----- LEVEL 4 SPELLS ----- */
X
X        case 21:    direct(x,100+clev,"  The %s shrivels up",0); /* dehydration */
X                    return;
X
X        case 22:    godirect(x,rnd(25)+20+(clev<<1),"  A lightning bolt hits the %s",1,'~');    /*  lightning */
X                    return;
X
X        case 23:    i=min(c[HP]-1,c[HPMAX]/2);  /* drain life */
X                    direct(x,i+i,"",0); c[HP] -= i;     return;
X
X        case 24:    if (c[GLOBE]==0) c[MOREDEFENSES] += 10;
X                    c[GLOBE] += 200;  loseint();  /* globe of invulnerability */
X                    return;
X
X        case 25:    omnidirect(x,32+clev,"  The %s struggles for air in your flood!"); /* flood */
X                    return;
X
X        case 26:    if (rnd(151)==63) { beep(); lprcat("\nYour heart stopped!\n"); nap(4000);  died(270); return; }
X                    if (c[WISDOM]>rnd(10)+10) direct(x,2000,"  The %s's heart stopped",0); /* finger of death */
X                    else lprcat("  It didn't work"); return;
X
X/* ----- LEVEL 5 SPELLS ----- */
X
X        case 27:    c[SCAREMONST] += rnd(10)+clev;  return;  /* scare monster */
X
X        case 28:    c[HOLDMONST] += rnd(10)+clev;  return;  /* hold monster */
X
X        case 29:    c[TIMESTOP] += rnd(20)+(clev<<1);  return;  /* time stop */
X
X        case 30:    tdirect(x);  return;  /* teleport away */
X
X        case 31:    omnidirect(x,35+rnd(10)+clev,"  The %s cringes from the flame"); /* magic fire */
X                    return;
X
X/* ----- LEVEL 6 SPELLS ----- */
X
X        case 32:    if ((rnd(23)==5) && (wizard==0)) /* sphere of annihilation */
X                        {
X                        beep(); lprcat("\nYou have been enveloped by the zone of nothingness!\n");
X                        nap(4000);  died(258); return;
X                        }
X                    xl=playerx; yl=playery;
X                    loseint();
X                    i=dirsub(&xl,&yl); /* get direction of sphere */
X                    newsphere(xl,yl,i,rnd(20)+11);  /* make a sphere */
X                    return;
X
X        case 33:    genmonst();  spelknow[33]=0;  /* genocide */
X                    loseint();
X                    return;
X
X        case 34:    /* summon demon */
X                    if (rnd(100) > 30) { direct(x,150,"  The demon strikes at the %s",0);  return; }
X                    if (rnd(100) > 15) { lprcat("  Nothing seems to have happened");  return; }
X                    lprcat("  The demon turned on you and vanished!"); beep();
X                    i=rnd(40)+30;  lastnum=277;
X                    losehp(i); /* must say killed by a demon */ return;
X
X        case 35:    /* walk through walls */
X                    c[WTW] += rnd(10)+5;    return;
X
X        case 36:    /* alter reality */
X                    {
X                    struct isave *save; /* pointer to item save structure */
X                    int sc; sc=0;   /* # items saved */
X                    save = (struct isave *)malloc(sizeof(struct isave)*MAXX*MAXY*2);
X            if (save == NULL)
X            {
X            lprcat("\nPolinneaus won't let you mess with his dungeon!");
X            return;
X            }
X            for (j=0; j<MAXY; j++)
X                        for (i=0; i<MAXX; i++) /* save all items and monsters */
X                            {
X                            xl = item[i][j];
X                            if (xl && xl!=OWALL && xl!=OANNIHILATION) 
X                                {
X                                save[sc].type=0;  save[sc].id=item[i][j];
X                                save[sc++].arg=iarg[i][j];
X                                }
X                            if (mitem[i][j]) 
X                                {
X                                save[sc].type=1;  save[sc].id=mitem[i][j];
X                                save[sc++].arg=hitp[i][j];
X                                }
X                            item[i][j]=OWALL;   mitem[i][j]=0;
X# ifdef DGK
X                        if (wizard)
X                            know[i][j]=KNOWALL;
X                        else
X                            know[i][j]=0;
X# else
X                            if (wizard) know[i][j]=1; else know[i][j]=0;
X# endif
X                            }
X                    eat(1,1);   if (level==1) item[33][MAXY-1]=0;
X                    for (j=rnd(MAXY-2), i=1; i<MAXX-1; i++) item[i][j]=0;
X                    while (sc>0) /* put objects back in level */
X                        {
X                        --sc;
X                        if (save[sc].type == 0)
X                            {
X                            int trys;
X                            for (trys=100, i=j=1; --trys>0 && item[i][j]; i=rnd(MAXX-1), j=rnd(MAXY-1));
X                            if (trys) { item[i][j]=save[sc].id; iarg[i][j]=save[sc].arg; }
X                            }
X                        else
X                            { /* put monsters back in */
X                            int trys;
X                            for (trys=100, i=j=1; --trys>0 && (item[i][j]==OWALL || mitem[i][j]); i=rnd(MAXX-1), j=rnd(MAXY-1));
X                            if (trys) { mitem[i][j]=save[sc].id; hitp[i][j]=save[sc].arg; }
X                            }
X                        }
X                    loseint();
X                    draws(0,MAXX,0,MAXY);  if (wizard==0) spelknow[36]=0;
X                    free((char*)save);   positionplayer();  return;
X                    }
X
X        case 37:    /* permanence */ adjtime(-99999L);  spelknow[37]=0; /* forget */
X                    loseint();
X                    return;
X
X        default:    lprintf("  spell %d not available!",(long)x); beep();  return;
X        };
X    }
X
X/*
X    Create a guardian for a throne/altar/fountain, as a result of the player
X    using a VPR spell or pulverization scroll on it.
X*/
Xstatic void create_guardian( monst, x, y )
Xint monst;  /* monster code for the guardian */
Xint x, y;   /* coords of the object being guarded */
X    {
X    int k ;
X
X    /* prevent the guardian from being created on top of the player
X    */
X    if ((x == playerx) && (y == playery))
X    {
X    k = rnd(8);
X    x += diroffx[k];
X    y += diroffy[k];
X    }
X    know[x][y] = 0;
X    mitem[x][y] = monst ;
X    hitp[x][y]  = monster[monst].hitpoints;
X    }
X
X/*
X *  loseint()       Routine to subtract 1 from your int (intelligence) if > 3
X *
X *  No arguments and no return value
X */
Xstatic loseint()
X    {
X    if (--c[INTELLIGENCE]<3)  c[INTELLIGENCE]=3;
X    }
X
X/*
X *  isconfuse()         Routine to check to see if player is confused
X *
X *  This routine prints out a message saying "You can't aim your magic!"
X *  returns 0 if not confused, non-zero (time remaining confused) if confused
X */
Xstatic isconfuse()
X    {
X    if (c[CONFUSE]) { lprcat(" You can't aim your magic!"); beep(); }
X    return(c[CONFUSE]);
X    }
X
X/*
X *  nospell(x,monst)    Routine to return 1 if a spell doesn't affect a monster
X *      int x,monst;
X *
X *  Subroutine to return 1 if the spell can't affect the monster
X *    otherwise returns 0
X *  Enter with the spell number in x, and the monster number in monst.
X */
Xstatic nospell(x,monst)
X    int x,monst;
X    {
X    register int tmp;
X    if (x>=SPNUM || monst>=MAXMONST+8 || monst<0 || x<0) return(0); /* bad spell or monst */
X    if ((tmp=spelweird[monst-1][x])==0) return(0);
X    cursors();  lprc('\n');  lprintf(spelmes[tmp],monster[monst].name);  return(1);
X    }
X
X/*
X *  fullhit(xx)     Function to return full damage against a monster (aka web)
X *      int xx;
X *
X *  Function to return hp damage to monster due to a number of full hits
X *  Enter with the number of full hits being done
X */
Xfullhit(xx)
X    int xx;
X    {
X    register int i;
X    if (xx<0 || xx>20) return(0);   /* fullhits are out of range */
X    if (c[LANCEDEATH]) return(10000);   /* lance of death */
X    i = xx * ((c[WCLASS]>>1)+c[STRENGTH]+c[STREXTRA]-c[HARDGAME]-12+c[MOREDAM]);
X    return( (i>=1) ? i : xx );
X    }
X
X/*
X *  direct(spnum,dam,str,arg)   Routine to direct spell damage 1 square in 1 dir
X *      int spnum,dam,arg;
X *      char *str;
X *
X *  Routine to ask for a direction to a spell and then hit the monster
X *  Enter with the spell number in spnum, the damage to be done in dam,
X *    lprintf format string in str, and lprintf's argument in arg.
X *  Returns no value.
X */
Xstatic direct(spnum,dam,str,arg)
X    int spnum,dam,arg;
X    char *str;
X    {
X    extern char lastmonst[];
X    int x,y;
X    register int m;
X    if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad arguments */
X    if (isconfuse()) return;
X    dirsub(&x,&y);
X    m = mitem[x][y];
X    if (item[x][y]==OMIRROR)
X        {
X        if (spnum==3) /* sleep */
X            {
X            lprcat("You fall asleep! "); beep();
X        fool:
X            arg += 2;
X            while (arg-- > 0) { parse2(); nap(1000); }
X            return;
X            }
X        else if (spnum==6) /* web */
X            {
X            lprcat("You get stuck in your own web! "); beep();
X            goto fool;
X            }
X        else
X            {
X            lastnum=278; 
X            lprintf(str,"spell caster (thats you)",(long)arg);
X            beep(); losehp(dam); return;
X            }
X        }
X    if (m==0)
X        {   lprcat("  There wasn't anything there!");   return;  }
X    ifblind(x,y);
X    if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
X    lprintf(str,lastmonst,(long)arg);       hitm(x,y,dam);
X    }
X
X/*
X *  godirect(spnum,dam,str,delay,cshow)     Function to perform missile attacks
X *      int spnum,dam,delay;
X *      char *str,cshow;
X *
X *  Function to hit in a direction from a missile weapon and have it keep
X *  on going in that direction until its power is exhausted
X *  Enter with the spell number in spnum, the power of the weapon in hp,
X *    lprintf format string in str, the # of milliseconds to delay between 
X *    locations in delay, and the character to represent the weapon in cshow.
X *  Returns no value.
X */
Xgodirect(spnum,dam,str,delay,cshow)
X    int spnum,dam,delay;
X    char *str,cshow;
X    {
X    extern char lastmonst[] ;
X    register char *p;
X    register int x,y,m;
X    int dx,dy;
X    if (spnum<0 || spnum>=SPNUM || str==0 || delay<0) return; /* bad args */
X    if (isconfuse()) return;
X    dirsub(&dx,&dy);    x=dx;   y=dy;
X    dx = x-playerx;     dy = y-playery;     x = playerx;    y = playery;
X    while (dam>0)
X        {
X        x += dx;    y += dy;
X        if ((x > MAXX-1) || (y > MAXY-1) || (x < 0) || (y < 0))
X            {
X            dam=0;  break;  /* out of bounds */
X            }
X        if ((x==playerx) && (y==playery)) /* if energy hits player */
X            {
X            cursors(); lprcat("\nYou are hit my your own magic!"); beep();
X            lastnum=278;  losehp(dam);  return;
X            }
X        if (c[BLINDCOUNT]==0) /* if not blind show effect */
X            {
X            cursor(x+1,y+1); lprc(cshow); nap(delay); show1cell(x,y);
X            }
X        if ((m=mitem[x][y]))    /* is there a monster there? */
X            {
X            ifblind(x,y);
X            if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
X            cursors(); lprc('\n');
X            lprintf(str,lastmonst);     dam -= hitm(x,y,dam);
X            show1cell(x,y);  nap(1000);     x -= dx;    y -= dy;
X            }
X        else switch (*(p= &item[x][y]))
X            {
X        case OWALL:
X        cursors();
X        lprc('\n');
X        lprintf(str,"wall");
X        if (dam>=50+c[HARDGAME]) /* enough damage? */
X            if (level<MAXLEVEL+MAXVLEVEL-1) /* not on V3 */
X            if ((x<MAXX-1) && (y<MAXY-1) && (x) && (y))
X                            {
X                            lprcat("  The wall crumbles");
X                *p=0;
X                know[x][y]=0;
X                            show1cell(x,y);
X                            }
X        dam = 0;
X        break;
X
X        case OCLOSEDDOOR:
X        cursors();
X        lprc('\n');
X        lprintf(str,"door");
X        if (dam>=40)
X            {
X            lprcat("  The door is blasted apart");
X            *p = 0;
X            know[x][y] = 0;
X            show1cell( x, y );
X            }
X        dam = 0 ;
X        break;
X
X        case OSTATUE:
X        cursors();
X        lprc('\n');
X        lprintf(str,"statue");
X        if (c[HARDGAME]<3)
X            if (dam>44)
X            {
X            lprcat("  The statue crumbles");
X            *p=OBOOK;
X            iarg[x][y]=level;
X            know[x][y] = 0;
X            show1cell( x, y );
X            }
X        dam = 0 ;
X        break;
X
X        case OTHRONE:
X        cursors();
X        lprc('\n');
X        lprintf(str,"throne");
X        if (dam>39)
X            {
X            *p = OTHRONE2;
X            create_guardian( GNOMEKING, x, y );
X            show1cell( x, y );
X            }
X        dam = 0;
X        break;
X
X        case OALTAR:
X        cursors();
X        lprc('\n');
X        lprintf(str, "altar");
X        if ( dam > 75 - ( c[HARDGAME] >> 2 ))
X            {
X            create_guardian( DEMONPRINCE, x, y );
X            show1cell( x, y );
X            }
X        dam = 0 ;
X        break;
X
X        case OFOUNTAIN:
X        cursors();
X        lprc('\n');
X        lprintf(str, "fountain");
X        if ( dam > 55 )
X            {
X            create_guardian( WATERLORD, x, y );
X            show1cell( x, y );
X            }
X        dam = 0 ;
X        break;
X
X        case OMIRROR:
X	{
X	int bounce = FALSE, odx=dx, ody=dy ;
X        /* spells may bounce directly back or off at an angle
X        */
X        if (rnd(100) < 50 )
X        {
X        bounce = TRUE ;
X        dx *= -1;
X        }
X        if (rnd(100) < 50 )
X        {
X        bounce = TRUE ;
X        dy *= -1;
X        }
X	if (!bounce || ((odx==dx) && (ody==dy)))    /* guarentee a bounce */
X        {
X	dx = -odx;
X	dy = -ody;
X        }
X        }
X        break;
X            };
X        dam -= 3 + (c[HARDGAME]>>1);
X        }
X    }
X
X/*
X *  ifblind(x,y)    Routine to put "monster" or the monster name into lastmosnt
X *      int x,y;
X *
X *  Subroutine to copy the word "monster" into lastmonst if the player is blind
X *  Enter with the coordinates (x,y) of the monster
X *  Returns no value.
X */
Xifblind(x,y)
X    int x,y;
X    {
X    extern char lastmonst[] ;
X    char *p;
X    vxy(&x,&y); /* verify correct x,y coordinates */
X    if (c[BLINDCOUNT]) { lastnum=279;  p="monster"; }
X        else { lastnum=mitem[x][y];  p=monster[lastnum].name; }
X    strcpy(lastmonst,p);
X    }
X
X/*
X *  tdirect(spnum)      Routine to teleport away a monster
X *      int spnum;
X *
X *  Routine to ask for a direction to a spell and then teleport away monster
X *  Enter with the spell number that wants to teleport away
X *  Returns no value.
X */
Xstatic tdirect(spnum)
X    int spnum;
X    {
X    int x,y;
X    register int m;
X    if (spnum<0 || spnum>=SPNUM) return; /* bad args */
X    if (isconfuse()) return;
X    dirsub(&x,&y);
X    if ((m=mitem[x][y])==0)
X        {   lprcat("  There wasn't anything there!");   return;  }
X    ifblind(x,y);
X    if (nospell(spnum,m)) { lasthx=x;  lasthy=y; return; }
X    fillmonst(m);  mitem[x][y]=0; know[x][y] &= ~KNOWHERE;
X    }
X
X/*
X *  omnidirect(sp,dam,str)   Routine to damage all monsters 1 square from player
X *      int sp,dam;
X *      char *str;
X *
X *  Routine to cast a spell and then hit the monster in all directions
X *  Enter with the spell number in sp, the damage done to wach square in dam,
X *    and the lprintf string to identify the spell in str.
X *  Returns no value.
X */
Xstatic omnidirect(spnum,dam,str)
X    int spnum,dam;
X    char *str;
X    {
X    extern char lastmonst[] ;
X    register int x,y,m;
X    if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad args */
X    for (x=playerx-1; x<playerx+2; x++)
X        for (y=playery-1; y<playery+2; y++)
X            {
X            if (m=mitem[x][y])
X                if (nospell(spnum,m) == 0)
X                    {
X                    ifblind(x,y);
X                    cursors(); lprc('\n'); lprintf(str,lastmonst);
X                    hitm(x,y,dam);  nap(800);
X                    }
X                else  { lasthx=x;  lasthy=y; }
X            }
X    }
X
X/*
X *  dirsub(x,y)      Routine to ask for direction, then modify playerx,
X *                   playery for it
X *      int *x,*y;
X *
X *  Function to ask for a direction and modify an x,y for that direction
X *  Enter with the coordinate destination (x,y).
X *  Returns index into diroffx[] (0-8).
X */
Xdirsub(x,y)
X    int *x,*y;
X    {
X    register int i;
X    lprcat("\nIn What Direction? ");
X    for (i=0; ; )
X        switch(ttgetch())
X            {
X            case 'b':   i++;
X            case 'n':   i++;
X            case 'y':   i++;
X            case 'u':   i++;
X            case 'h':   i++;
X            case 'k':   i++;
X            case 'l':   i++;
X            case 'j':   i++;        goto out;
X            };
Xout:
X    *x = playerx+diroffx[i];        *y = playery+diroffy[i];
X    vxy(x,y);  return(i);
X    }
X
X/*
X *  dirpoly(spnum)      Routine to ask for a direction and polymorph a monst
X *      int spnum;
X *
X *  Subroutine to polymorph a monster and ask for the direction its in
X *  Enter with the spell number in spmun.
X *  Returns no value.
X */
Xstatic dirpoly(spnum)
X    int spnum;
X    {
X    int x,y,m;
X    if (spnum<0 || spnum>=SPNUM) return; /* bad args */
X    if (isconfuse()) return;    /* if he is confused, he can't aim his magic */
X    dirsub(&x,&y);
X    if (mitem[x][y]==0)
X        {   lprcat("  There wasn't anything there!");   return;  }
X    ifblind(x,y);
X    if (nospell(spnum,mitem[x][y])) { lasthx=x;  lasthy=y; return; }
X# ifdef MSDOS
X    do {
X        m = rnd(MAXMONST+7);
X        mitem[x][y] = m;
X    } while ( monster[m].genocided );
X# else
X    while ( monster[m = mitem[x][y] = rnd(MAXMONST+7)].genocided );
X# endif
X    hitp[x][y] = monster[m].hitpoints;
X    show1cell(x,y);  /* show the new monster */
X    }
X
X/*
X *  annihilate()    Routine to annihilate all monsters around player (playerx,playery)
X *
X *  Gives player experience, but no dropped objects
X *  Returns the experience gained from all monsters killed
X */
Xannihilate()
X    {
X    int i,j;
X    register long k;
X    register char *p;
X    for (k=0, i=playerx-1; i<=playerx+1; i++)
X      for (j=playery-1; j<=playery+1; j++)
X        if (!vxy(&i,&j)) /* if not out of bounds */
X            if (*(p= &mitem[i][j])) /* if a monster there */
X                if (*p<DEMONLORD+2)
X                    {
X# ifdef DGK
X                    k += monster[*p].experience;    *p=know[i][j] &= ~KNOWHERE;
X# else
X                    k += monster[*p].experience;    *p=know[i][j]=0;
X# endif
X                    }
X                else
X                    {
X                    lprintf("\nThe %s barely escapes being annihilated!",monster[*p].name);
X                    hitp[i][j] = (hitp[i][j]>>1) + 1; /* lose half hit points*/
X                    }
X    if (k>0)
X        {
X        lprcat("\nYou hear loud screams of agony!");    raiseexperience((long)k);
X        }
X    return(k);
X    }
X
X/*
X *  genmonst()      Function to ask for monster and genocide from game
X *
X *  This is done by setting a flag in the monster[] structure
X */
Xstatic genmonst()
X    {
X    register int i,j;
X    cursors();  lprcat("\nGenocide what monster? ");
X    for (i=0; (!isalpha(i)) && (i!=' '); i=ttgetch());
X    lprc(i);
X    for (j=0; j<MAXMONST; j++)  /* search for the monster type */
X        if (monstnamelist[j]==i)    /* have we found it? */
X            {
X            monster[j].genocided=1; /* genocided from game */
X            lprintf("  There will be no more %s's",monster[j].name);
X            /* now wipe out monsters on this level */
X            newcavelevel(level); draws(0,MAXX,0,MAXY); bot_linex();
X            return;
X            }
X    lprcat("  You sense failure!");
X    }
END_OF_FILE
if test 27476 -ne `wc -c <'spells.c'`; then
    echo shar: \"'spells.c'\" unpacked with wrong size!
fi
# end of 'spells.c'
fi
echo shar: End of archive 5 \(of 11\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 11 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0