Home | History | Annotate | Line # | Download | only in larn
movem.c revision 1.4
      1  1.2   mycroft #ifndef lint
      2  1.4  christos static char rcsid[] = "$NetBSD: movem.c,v 1.4 1997/07/13 20:21:37 christos Exp $";
      3  1.2   mycroft #endif /* not lint */
      4  1.2   mycroft 
      5  1.1       cgd /*
      6  1.1       cgd  *	movem.c (move monster)		Larn is copyrighted 1986 by Noah Morgan.
      7  1.1       cgd  *
      8  1.1       cgd  *	Here are the functions in this file:
      9  1.1       cgd  *
     10  1.1       cgd  *	movemonst()		Routine to move the monsters toward the player
     11  1.1       cgd  *	movemt(x,y)		Function to move a monster at (x,y) -- must determine where
     12  1.1       cgd  *	mmove(x,y,xd,yd)	Function to actually perform the monster movement
     13  1.1       cgd  *	movsphere() 		Function to look for and move spheres of annihilation
     14  1.1       cgd  */
     15  1.1       cgd #include "header.h"
     16  1.1       cgd 
     17  1.1       cgd /*
     18  1.1       cgd  *	movemonst()		Routine to move the monsters toward the player
     19  1.1       cgd  *
     20  1.1       cgd  *	This routine has the responsibility to determine which monsters are to
     21  1.1       cgd  *	move, and call movemt() to do the move.
     22  1.1       cgd  *	Returns no value.
     23  1.1       cgd  */
     24  1.1       cgd static short w1[9],w1x[9],w1y[9];
     25  1.1       cgd static int tmp1,tmp2,tmp3,tmp4,distance;
     26  1.1       cgd movemonst()
     27  1.1       cgd 	{
     28  1.1       cgd 	register int i,j;
     29  1.1       cgd 	if (c[TIMESTOP]) return;	/* no action if time is stopped */
     30  1.1       cgd 	if (c[HASTESELF])  if ((c[HASTESELF]&1)==0)  return;
     31  1.1       cgd 	if (spheres) movsphere();	/* move the spheres of annihilation if any */
     32  1.1       cgd 	if (c[HOLDMONST])  return;	/* no action if monsters are held */
     33  1.1       cgd 
     34  1.1       cgd 	if (c[AGGRAVATE])	/* determine window of monsters to move */
     35  1.1       cgd 	  {
     36  1.1       cgd 	  tmp1=playery-5; tmp2=playery+6; tmp3=playerx-10; tmp4=playerx+11;
     37  1.1       cgd 	  distance=40; /* depth of intelligent monster movement */
     38  1.1       cgd 	  }
     39  1.1       cgd 	else
     40  1.1       cgd 	  {
     41  1.1       cgd 	  tmp1=playery-3; tmp2=playery+4; tmp3=playerx-5; tmp4=playerx+6;
     42  1.1       cgd 	  distance=17; /* depth of intelligent monster movement */
     43  1.1       cgd 	  }
     44  1.1       cgd 
     45  1.1       cgd 	if (level == 0) /* if on outside level monsters can move in perimeter */
     46  1.1       cgd 		{
     47  1.1       cgd 		if (tmp1 < 0) tmp1=0;		 if (tmp2 > MAXY) tmp2=MAXY;
     48  1.1       cgd 		if (tmp3 < 0) tmp3=0;		 if (tmp4 > MAXX) tmp4=MAXX;
     49  1.1       cgd 		}
     50  1.1       cgd 	else /* if in a dungeon monsters can't be on the perimeter (wall there) */
     51  1.1       cgd 		{
     52  1.1       cgd 		if (tmp1 < 1) tmp1=1;		 if (tmp2 > MAXY-1) tmp2=MAXY-1;
     53  1.1       cgd 		if (tmp3 < 1) tmp3=1;		 if (tmp4 > MAXX-1) tmp4=MAXX-1;
     54  1.1       cgd 		}
     55  1.1       cgd 
     56  1.1       cgd 	for (j=tmp1; j<tmp2; j++) /* now reset monster moved flags */
     57  1.1       cgd 		for (i=tmp3; i<tmp4; i++)
     58  1.1       cgd 			moved[i][j] = 0;
     59  1.1       cgd     moved[lasthx][lasthy]=0;
     60  1.1       cgd 
     61  1.1       cgd 	if (c[AGGRAVATE] || !c[STEALTH]) /* who gets moved? split for efficiency */
     62  1.1       cgd 	  {
     63  1.1       cgd 	  for (j=tmp1; j<tmp2; j++) /* look thru all locations in window */
     64  1.1       cgd 	    for (i=tmp3; i<tmp4; i++)
     65  1.1       cgd 		  if (mitem[i][j])	/* if there is a monster to move */
     66  1.1       cgd 		    if (moved[i][j]==0)	/* if it has not already been moved */
     67  1.1       cgd 			  movemt(i,j);	/* go and move the monster */
     68  1.1       cgd 	  }
     69  1.1       cgd 	else /* not aggravated and not stealth */
     70  1.1       cgd 	  {
     71  1.1       cgd 	  for (j=tmp1; j<tmp2; j++) /* look thru all locations in window */
     72  1.1       cgd 	    for (i=tmp3; i<tmp4; i++)
     73  1.1       cgd 		  if (mitem[i][j])	/* if there is a monster to move */
     74  1.1       cgd 		    if (moved[i][j]==0)	/* if it has not already been moved */
     75  1.1       cgd 			  if (stealth[i][j])	/* if it is asleep due to stealth */
     76  1.1       cgd 			    movemt(i,j);	/* go and move the monster */
     77  1.1       cgd 	  }
     78  1.1       cgd 
     79  1.1       cgd 	if (mitem[lasthx][lasthy]) /* now move monster last hit by player if not already moved */
     80  1.1       cgd 		{
     81  1.1       cgd 	    if (moved[lasthx][lasthy]==0)	/* if it has not already been moved */
     82  1.1       cgd 			{
     83  1.1       cgd 			movemt(lasthx,lasthy);
     84  1.1       cgd 			lasthx = w1x[0];   lasthy = w1y[0];
     85  1.1       cgd 			}
     86  1.1       cgd 		}
     87  1.1       cgd 	}
     88  1.1       cgd 
     89  1.1       cgd /*
     90  1.1       cgd  *	movemt(x,y)		Function to move a monster at (x,y) -- must determine where
     91  1.1       cgd  *		int x,y;
     92  1.1       cgd  *
     93  1.1       cgd  *	This routine is responsible for determining where one monster at (x,y) will
     94  1.1       cgd  *	move to.  Enter with the monsters coordinates in (x,y).
     95  1.1       cgd  *	Returns no value.
     96  1.1       cgd  */
     97  1.1       cgd static int tmpitem,xl,xh,yl,yh;
     98  1.1       cgd movemt(i,j)
     99  1.1       cgd 	int i,j;
    100  1.1       cgd 	{
    101  1.1       cgd 	register int k,m,z,tmp,xtmp,ytmp,monst;
    102  1.1       cgd 	switch(monst=mitem[i][j])  /* for half speed monsters */
    103  1.1       cgd 		{
    104  1.1       cgd 		case TROGLODYTE:  case HOBGOBLIN:  case METAMORPH:  case XVART:
    105  1.4  christos 		case INVISIBLESTALKER:  case ICELIZARD: if ((gltime & 1) == 1) return;
    106  1.1       cgd 		};
    107  1.1       cgd 
    108  1.1       cgd 	if (c[SCAREMONST]) /* choose destination randomly if scared */
    109  1.1       cgd 		{
    110  1.1       cgd 		if ((xl = i+rnd(3)-2) < 0) xl=0;  if (xl >= MAXX) xl=MAXX-1;
    111  1.1       cgd 		if ((yl = j+rnd(3)-2) < 0) yl=0;  if (yl >= MAXY) yl=MAXY-1;
    112  1.1       cgd 		if ((tmp=item[xl][yl]) != OWALL)
    113  1.1       cgd 		  if (mitem[xl][yl] == 0)
    114  1.1       cgd 			if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR))
    115  1.1       cgd 			  if (tmp != OCLOSEDDOOR)		mmove(i,j,xl,yl);
    116  1.1       cgd 		return;
    117  1.1       cgd 		}
    118  1.1       cgd 
    119  1.1       cgd 	if (monster[monst].intelligence > 10-c[HARDGAME]) /* if smart monster */
    120  1.1       cgd /* intelligent movement here -- first setup screen array */
    121  1.1       cgd 	  {
    122  1.1       cgd 	  xl=tmp3-2; yl=tmp1-2; xh=tmp4+2;  yh=tmp2+2;
    123  1.1       cgd 	  vxy(&xl,&yl);  vxy(&xh,&yh);
    124  1.1       cgd 	  for (k=yl; k<yh; k++)
    125  1.1       cgd 	    for (m=xl; m<xh; m++)
    126  1.1       cgd 		  {
    127  1.1       cgd 		  switch(item[m][k])
    128  1.1       cgd 			{
    129  1.1       cgd 		  	case OWALL: case OPIT: case OTRAPARROW: case ODARTRAP:
    130  1.1       cgd 			case OCLOSEDDOOR: case OTRAPDOOR: case OTELEPORTER:
    131  1.1       cgd 				smm:	  screen[m][k]=127;  break;
    132  1.1       cgd 			case OMIRROR: if (mitem[m][k]==VAMPIRE) goto smm;
    133  1.1       cgd 			default:  screen[m][k]=  0;  break;
    134  1.1       cgd 			};
    135  1.1       cgd 		  }
    136  1.1       cgd 	  screen[playerx][playery]=1;
    137  1.1       cgd 
    138  1.1       cgd /* now perform proximity ripple from playerx,playery to monster */
    139  1.1       cgd 	  xl=tmp3-1; yl=tmp1-1; xh=tmp4+1;  yh=tmp2+1;
    140  1.1       cgd 	  vxy(&xl,&yl);  vxy(&xh,&yh);
    141  1.1       cgd 	  for (tmp=1; tmp<distance; tmp++)	/* only up to 20 squares away */
    142  1.1       cgd 	    for (k=yl; k<yh; k++)
    143  1.1       cgd 	      for (m=xl; m<xh; m++)
    144  1.1       cgd 		    if (screen[m][k]==tmp) /* if find proximity n advance it */
    145  1.1       cgd 			  for (z=1; z<9; z++) /* go around in a circle */
    146  1.1       cgd 			    {
    147  1.1       cgd 			    if (screen[xtmp=m+diroffx[z]][ytmp=k+diroffy[z]]==0)
    148  1.1       cgd 				  screen[xtmp][ytmp]=tmp+1;
    149  1.1       cgd 			    if (xtmp==i && ytmp==j) goto out;
    150  1.1       cgd 			    }
    151  1.1       cgd 
    152  1.1       cgd out:  if (tmp<distance) /* did find connectivity */
    153  1.1       cgd 		/* now select lowest value around playerx,playery */
    154  1.1       cgd 		for (z=1; z<9; z++) /* go around in a circle */
    155  1.1       cgd 		  if (screen[xl=i+diroffx[z]][yl=j+diroffy[z]]==tmp)
    156  1.1       cgd 			if (!mitem[xl][yl]) { mmove(i,j,w1x[0]=xl,w1y[0]=yl); return; }
    157  1.1       cgd 	  }
    158  1.1       cgd 
    159  1.1       cgd 	/* dumb monsters move here */
    160  1.1       cgd 	xl=i-1;  yl=j-1;  xh=i+2;  yh=j+2;
    161  1.1       cgd 	if (i<playerx) xl++; else if (i>playerx) --xh;
    162  1.1       cgd 	if (j<playery) yl++; else if (j>playery) --yh;
    163  1.1       cgd 	for (k=0; k<9; k++) w1[k] = 10000;
    164  1.1       cgd 
    165  1.1       cgd 	for (k=xl; k<xh; k++)
    166  1.1       cgd 		for (m=yl; m<yh; m++) /* for each square compute distance to player */
    167  1.1       cgd 			{
    168  1.1       cgd 			tmp = k-i+4+3*(m-j);
    169  1.1       cgd 			tmpitem = item[k][m];
    170  1.1       cgd 			if (tmpitem!=OWALL || (k==playerx && m==playery))
    171  1.1       cgd 			 if (mitem[k][m]==0)
    172  1.1       cgd 			  if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR))
    173  1.1       cgd 				 if (tmpitem!=OCLOSEDDOOR)
    174  1.1       cgd 					{
    175  1.1       cgd 					w1[tmp] = (playerx-k)*(playerx-k)+(playery-m)*(playery-m);
    176  1.1       cgd 					w1x[tmp] = k;  w1y[tmp] = m;
    177  1.1       cgd 					}
    178  1.1       cgd 			}
    179  1.1       cgd 
    180  1.1       cgd 	tmp = 0;
    181  1.1       cgd 	for (k=1; k<9; k++)  if (w1[tmp] > w1[k])  tmp=k;
    182  1.1       cgd 
    183  1.1       cgd 	if (w1[tmp] < 10000)
    184  1.1       cgd 		if ((i!=w1x[tmp]) || (j!=w1y[tmp]))
    185  1.1       cgd 			mmove(i,j,w1x[tmp],w1y[tmp]);
    186  1.1       cgd 	}
    187  1.1       cgd 
    188  1.1       cgd /*
    189  1.1       cgd  *	mmove(x,y,xd,yd)	Function to actually perform the monster movement
    190  1.1       cgd  *		int x,y,xd,yd;
    191  1.1       cgd  *
    192  1.1       cgd  *	Enter with the from coordinates in (x,y) and the destination coordinates
    193  1.1       cgd  *	in (xd,yd).
    194  1.1       cgd  */
    195  1.1       cgd mmove(aa,bb,cc,dd)
    196  1.1       cgd 	int aa,bb,cc,dd;
    197  1.1       cgd 	{
    198  1.1       cgd 	register int tmp,i,flag;
    199  1.1       cgd 	char *who,*p;
    200  1.1       cgd 	flag=0;	/* set to 1 if monster hit by arrow trap */
    201  1.1       cgd 	if ((cc==playerx) && (dd==playery))
    202  1.1       cgd 		{
    203  1.1       cgd 		hitplayer(aa,bb);  moved[aa][bb] = 1;  return;
    204  1.1       cgd 		}
    205  1.1       cgd 	i=item[cc][dd];
    206  1.1       cgd 	if ((i==OPIT) || (i==OTRAPDOOR))
    207  1.1       cgd 	  switch(mitem[aa][bb])
    208  1.1       cgd 		{
    209  1.1       cgd 		case SPIRITNAGA:	case PLATINUMDRAGON:	case WRAITH:
    210  1.1       cgd 		case VAMPIRE:		case SILVERDRAGON:		case POLTERGEIST:
    211  1.1       cgd 		case DEMONLORD:		case DEMONLORD+1:		case DEMONLORD+2:
    212  1.1       cgd 		case DEMONLORD+3:	case DEMONLORD+4:		case DEMONLORD+5:
    213  1.1       cgd 		case DEMONLORD+6:	case DEMONPRINCE:	break;
    214  1.1       cgd 
    215  1.1       cgd 		default:	mitem[aa][bb]=0; /* fell in a pit or trapdoor */
    216  1.1       cgd 		};
    217  1.1       cgd 	tmp = mitem[cc][dd] = mitem[aa][bb];
    218  1.1       cgd 	if (i==OANNIHILATION)
    219  1.1       cgd 		{
    220  1.1       cgd 		if (tmp>=DEMONLORD+3) /* demons dispel spheres */
    221  1.1       cgd 			{
    222  1.1       cgd 			cursors();
    223  1.1       cgd 			lprintf("\nThe %s dispels the sphere!",monster[tmp].name);
    224  1.1       cgd 			rmsphere(cc,dd);	/* delete the sphere */
    225  1.1       cgd 			}
    226  1.1       cgd 		else i=tmp=mitem[cc][dd]=0;
    227  1.1       cgd 		}
    228  1.1       cgd 	stealth[cc][dd]=1;
    229  1.1       cgd 	if ((hitp[cc][dd] = hitp[aa][bb]) < 0) hitp[cc][dd]=1;
    230  1.1       cgd 	mitem[aa][bb] = 0;				moved[cc][dd] = 1;
    231  1.1       cgd 	if (tmp == LEPRECHAUN)
    232  1.1       cgd 		switch(i)
    233  1.1       cgd 			{
    234  1.1       cgd 			case OGOLDPILE:  case OMAXGOLD:  case OKGOLD:  case ODGOLD:
    235  1.1       cgd 			case ODIAMOND:   case ORUBY:     case OEMERALD: case OSAPPHIRE:
    236  1.1       cgd 					item[cc][dd] = 0; /* leprechaun takes gold */
    237  1.1       cgd 			};
    238  1.1       cgd 
    239  1.1       cgd 	if (tmp == TROLL)  /* if a troll regenerate him */
    240  1.4  christos 		if ((gltime & 1) == 0)
    241  1.1       cgd 			if (monster[tmp].hitpoints > hitp[cc][dd])  hitp[cc][dd]++;
    242  1.1       cgd 
    243  1.1       cgd 	if (i==OTRAPARROW)	/* arrow hits monster */
    244  1.1       cgd 		{ who = "An arrow";  if ((hitp[cc][dd] -= rnd(10)+level) <= 0)
    245  1.1       cgd 			{ mitem[cc][dd]=0;  flag=2; } else flag=1; }
    246  1.1       cgd 	if (i==ODARTRAP)	/* dart hits monster */
    247  1.1       cgd 		{ who = "A dart";  if ((hitp[cc][dd] -= rnd(6)) <= 0)
    248  1.1       cgd 			{ mitem[cc][dd]=0;  flag=2; } else flag=1; }
    249  1.1       cgd 	if (i==OTELEPORTER)	/* monster hits teleport trap */
    250  1.1       cgd 		{ flag=3; fillmonst(mitem[cc][dd]);  mitem[cc][dd]=0; }
    251  1.1       cgd 	if (c[BLINDCOUNT]) return;	/* if blind don't show where monsters are	*/
    252  1.1       cgd 	if (know[cc][dd] & 1)
    253  1.1       cgd 		{
    254  1.1       cgd 		p=0;
    255  1.1       cgd 		if (flag) cursors();
    256  1.1       cgd 		switch(flag)
    257  1.1       cgd 		  {
    258  1.1       cgd 		  case 1: p="\n%s hits the %s";  break;
    259  1.1       cgd 		  case 2: p="\n%s hits and kills the %s";  break;
    260  1.1       cgd 		  case 3: p="\nThe %s%s gets teleported"; who="";  break;
    261  1.1       cgd 		  };
    262  1.1       cgd 		if (p) { lprintf(p,who,monster[tmp].name); beep(); }
    263  1.1       cgd 		}
    264  1.1       cgd /*	if (yrepcount>1) { know[aa][bb] &= 2;  know[cc][dd] &= 2; return; } */
    265  1.1       cgd 	if (know[aa][bb] & 1)   show1cell(aa,bb);
    266  1.1       cgd 	if (know[cc][dd] & 1)   show1cell(cc,dd);
    267  1.1       cgd 	}
    268  1.1       cgd 
    269  1.1       cgd /*
    270  1.1       cgd  *	movsphere() 	Function to look for and move spheres of annihilation
    271  1.1       cgd  *
    272  1.1       cgd  *	This function works on the sphere linked list, first duplicating the list
    273  1.1       cgd  *	(the act of moving changes the list), then processing each sphere in order
    274  1.1       cgd  *	to move it.  They eat anything in their way, including stairs, volcanic
    275  1.1       cgd  *	shafts, potions, etc, except for upper level demons, who can dispel
    276  1.1       cgd  *	spheres.
    277  1.1       cgd  *	No value is returned.
    278  1.1       cgd  */
    279  1.1       cgd #define SPHMAX 20	/* maximum number of spheres movsphere can handle */
    280  1.1       cgd movsphere()
    281  1.1       cgd 	{
    282  1.1       cgd 	register int x,y,dir,len;
    283  1.1       cgd 	register struct sphere *sp,*sp2;
    284  1.1       cgd 	struct sphere sph[SPHMAX];
    285  1.1       cgd 
    286  1.1       cgd 	/* first duplicate sphere list */
    287  1.1       cgd 	for (sp=0,x=0,sp2=spheres; sp2; sp2=sp2->p)	/* look through sphere list */
    288  1.1       cgd 	  if (sp2->lev == level)	/* only if this level */
    289  1.1       cgd 		{
    290  1.1       cgd 		sph[x] = *sp2;	sph[x++].p = 0;  /* copy the struct */
    291  1.1       cgd 		if (x>1)  sph[x-2].p = &sph[x-1]; /* link pointers */
    292  1.1       cgd 		}
    293  1.1       cgd 	if (x) sp= sph;	/* if any spheres, point to them */
    294  1.1       cgd 		else return;	/* no spheres */
    295  1.1       cgd 
    296  1.1       cgd 	for (sp=sph; sp; sp=sp->p)	/* look through sphere list */
    297  1.1       cgd 		{
    298  1.1       cgd 		x = sp->x;	  y = sp->y;
    299  1.1       cgd 		if (item[x][y]!=OANNIHILATION) continue;	/* not really there */
    300  1.1       cgd 		if (--(sp->lifetime) < 0)	/* has sphere run out of gas? */
    301  1.1       cgd 			{
    302  1.1       cgd 			rmsphere(x,y); /* delete sphere */
    303  1.1       cgd 			continue;
    304  1.1       cgd 			}
    305  1.1       cgd 		switch(rnd((int)max(7,c[INTELLIGENCE]>>1))) /* time to move the sphere */
    306  1.1       cgd 			{
    307  1.1       cgd 			case 1:
    308  1.1       cgd 			case 2:		/* change direction to a random one */
    309  1.1       cgd 						sp->dir = rnd(8);
    310  1.1       cgd 			default:	/* move in normal direction */
    311  1.1       cgd 						dir = sp->dir;		len = sp->lifetime;
    312  1.1       cgd 						rmsphere(x,y);
    313  1.1       cgd 						newsphere(x+diroffx[dir],y+diroffy[dir],dir,len);
    314  1.1       cgd 			};
    315  1.1       cgd 		}
    316  1.1       cgd 	}
    317