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