DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T m

⟦ac8dc77d9⟧ TextFile

    Length: 11283 (0x2c13)
    Types: TextFile
    Names: »movem.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/General/Ularn/movem.c« 

TextFile

/*
 *	movem.c (move monster)		Larn is copyrighted 1986 by Noah Morgan.
 *
 *	Here are the functions in this file:
 *
 *	movemonst()		Routine to move the monsters toward the player
 *		Function to move a monster at (x,y) -- must determine where
 *	movemt(x,y)		
 *		Function to actually perform the monster movement
 *	mmove(x,y,xd,yd)	
 *		Function to look for and move spheres of annihilation
 *	movsphere() 		
 */
#include "header.h"

/*
 *	movemonst()		Routine to move the monsters toward the player
 *
 *	This routine has the responsibility to determine which monsters are to
 *	move, and call movemt() to do the move.
 *	Returns no value.
 */
static short w1[9],w1x[9],w1y[9];
static int tmp1,tmp2,tmp3,tmp4,distance;
movemonst()
{
	register int i,j;
	if (c[TIMESTOP]) return;	/* no action if time is stopped */
	if (c[HASTESELF])  if ((c[HASTESELF]&1)==0)  return;
	if (spheres) movsphere();	/* move the spheres of annihilation if any */
	if (c[HOLDMONST])  return;	/* no action if monsters are held */

	if (c[AGGRAVATE])	/* determine window of monsters to move */
	{
		tmp1=playery-5; 
		tmp2=playery+6; 
		tmp3=playerx-10; 
		tmp4=playerx+11;
		distance=40; /* depth of intelligent monster movement */
	}
	else
	{
		tmp1=playery-3; 
		tmp2=playery+4; 
		tmp3=playerx-5; 
		tmp4=playerx+6;
		distance=17; /* depth of intelligent monster movement */
	}

	if (level == 0) /* if on outside level monsters can move in perimeter */
	{
		if (tmp1 < 0) tmp1=0;		 
		if (tmp2 > MAXY) tmp2=MAXY;
		if (tmp3 < 0) tmp3=0;		 
		if (tmp4 > MAXX) tmp4=MAXX;
	}
	else /* if in a dungeon monsters can't be on the perimeter (wall there) */
	{
		if (tmp1 < 1) tmp1=1;		 
		if (tmp2 > MAXY-1) tmp2=MAXY-1;
		if (tmp3 < 1) tmp3=1;		 
		if (tmp4 > MAXX-1) tmp4=MAXX-1;
	}

	for (j=tmp1; j<tmp2; j++) /* now reset monster moved flags */
		for (i=tmp3; i<tmp4; i++)
			moved[i][j] = 0;
	moved[lasthx][lasthy]=0;

	if (c[AGGRAVATE] || !c[STEALTH]) /* who gets moved? split for efficiency */
	{
		for (j=tmp1; j<tmp2; j++) /* look thru all locations in window */
			for (i=tmp3; i<tmp4; i++)
				if (mitem[i][j])	/* if there is a monster to move */
					if (moved[i][j]==0)	/* if it has not already been moved */
						movemt(i,j);	/* go and move the monster */
	}
	else /* not aggravated and not stealth */
	{
		for (j=tmp1; j<tmp2; j++) /* look thru all locations in window */
			for (i=tmp3; i<tmp4; i++)
				if (mitem[i][j])	/* if there is a monster to move */
					if (moved[i][j]==0)	/* if it has not already been moved */
						if (stealth[i][j])	/* if it is asleep due to stealth */
							movemt(i,j);	/* go and move the monster */
	}

	if (mitem[lasthx][lasthy]) /* now move monster last hit by player if not already moved */
	{
		if (moved[lasthx][lasthy]==0)	/* if it has not already been moved */
		{
			movemt(lasthx,lasthy);
			lasthx = w1x[0];   
			lasthy = w1y[0];
		}
	}
}

/*
 *		Function to move a monster at (x,y) -- must determine where
 *	movemt(x,y)		
 *	int x,y;
 *
 *	This routine is responsible for determining where one monster at (x,y) 
 *	will move to.  Enter with the monsters coordinates in (x,y).
 *	Returns no value.
 */
static int tmpitem,xl,xh,yl,yh;

movemt(i,j)
int i,j;
{
	register int k,m,z,tmp,xtmp,ytmp,monst;
	switch(monst=mitem[i][j])  /* for half speed monsters */
	{
	case TROGLODYTE:  
	case HOBGOBLIN:  
	case METAMORPH:  
	case XVART:
	case INVISIBLESTALKER:  
	case ICELIZARD: 
		if ((gtime & 1) == 1) return;
	};
	/* choose destination randomly if scared */
	tmp=0;
	{
		register int i, j;
		for (i=0; i<26; i++)
			if (iven[i]==OHANDofFEAR){
				tmp=1;
				break;
			}
	}
	if (c[SCAREMONST]){
		if (tmp==1) tmp=2;
	}
	else if ((tmp==1) && (rnd(10) > 4)) tmp=0;

	if ((monst > DEMONLORD)||(monst == PLATINUMDRAGON)) {
		tmp = (tmp==1) ? 0 : (rnd(10) > 5);
	}
	if (tmp) {
		if ((xl = i+rnd(3)-2) < 0) xl=0;  
		if (xl >= MAXX) xl=MAXX-1;
		if ((yl = j+rnd(3)-2) < 0) yl=0;  
		if (yl >= MAXY) yl=MAXY-1;
		if ((tmp=item[xl][yl]) != OWALL)
			if (mitem[xl][yl] == 0)
				if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR))
					if (tmp != OCLOSEDDOOR)		
						mmove(i,j,xl,yl);
		return;
	}

	if (monster[monst].intelligence > 10-c[HARDGAME]) /* if smart monster */
		/* intelligent movement here -- first setup screen array */
	{
		xl=tmp3-2; 
		yl=tmp1-2; 
		xh=tmp4+2;  
		yh=tmp2+2;
		vxy(&xl,&yl);  
		vxy(&xh,&yh);
		for (k=yl; k<yh; k++)
			for (m=xl; m<xh; m++)
			{
				if (monst>=DEMONPRINCE) 
					screen[m][k]=0;
				else
					switch(item[m][k])
					{
					case OWALL: 
					case OELEVATORUP:
					case OELEVATORDOWN:
					case OPIT: 
					case OTRAPARROW: 
					case ODARTRAP:
					case OCLOSEDDOOR: 
					case OTRAPDOOR: 
					case OTELEPORTER:
smm:	  			
						screen[m][k]=127;  
						break;
					case OMIRROR: 
						if (mitem[m][k]==VAMPIRE) goto smm;
					default:  
						screen[m][k]=0;  
						break;
					};
			}
		screen[playerx][playery]=1;

		/* now perform proximity ripple from playerx,playery to monster */
		xl=tmp3-1; 
		yl=tmp1-1; 
		xh=tmp4+1;  
		yh=tmp2+1;
		vxy(&xl,&yl);  
		vxy(&xh,&yh);
		for (tmp=1; tmp<distance; tmp++)	/* only up to 20 squares away */
			for (k=yl; k<yh; k++)
				for (m=xl; m<xh; m++)
					if (screen[m][k]==tmp) /* if find proximity n advance it */
						for (z=1; z<9; z++) /* go around in a circle */
						{
							if (screen[xtmp=m+diroffx[z]][ytmp=k+diroffy[z]]==0)
								screen[xtmp][ytmp]=tmp+1;
							if (xtmp==i && ytmp==j) goto out;
						}

out:  
		if (tmp<distance) /* did find connectivity */
			/* now select lowest value around playerx,playery */
			for (z=1; z<9; z++) /* go around in a circle */
				if (screen[xl=i+diroffx[z]][yl=j+diroffy[z]]==tmp)
					if (!mitem[xl][yl]) { 
						mmove(i,j,w1x[0]=xl,w1y[0]=yl); 
						return; 
					}
	}

	/* dumb monsters move here */
	xl=i-1;  
	yl=j-1;  
	xh=i+2;  
	yh=j+2;
	if (i<playerx) xl++; 
	else if (i>playerx) --xh;
	if (j<playery) yl++; 
	else if (j>playery) --yh;
	for (k=0; k<9; k++) w1[k] = 10000;

	for (k=xl; k<xh; k++)
		for (m=yl; m<yh; m++) /* for each square compute distance to player */
		{
			tmp = k-i+4+3*(m-j);
			tmpitem = item[k][m];
			if (tmpitem!=OWALL || (k==playerx && m==playery))
				if (mitem[k][m]==0)
					if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR))
						if (tmpitem!=OCLOSEDDOOR)
						{
							w1[tmp] = (playerx-k)*(playerx-k)+(playery-m)*(playery-m);
							w1x[tmp] = k;  
							w1y[tmp] = m;
						}
		}

	tmp = 0;
	for (k=1; k<9; k++)  if (w1[tmp] > w1[k])  tmp=k;

	if (w1[tmp] < 10000)
		if ((i!=w1x[tmp]) || (j!=w1y[tmp]))
			mmove(i,j,w1x[tmp],w1y[tmp]);
}

/*
 *		Function to actually perform the monster movement
 *	mmove(x,y,xd,yd)	
 *		int x,y,xd,yd;
 *
 *	Enter with the from coordinates in (x,y) and the destination coordinates
 *	in (xd,yd).
 */
mmove(aa,bb,cc,dd)
int aa,bb,cc,dd;
{
	register int tmp,i,x,flag;
	char *who,*p;

	flag=0;	/* set to 1 if monster hit by arrow trap */
	if ((cc==playerx) && (dd==playery)) {
		hitplayer(aa,bb);  
		moved[aa][bb] = 1;  
		return;
	}
	i=item[cc][dd];
	if ((i==OPIT) || (i==OTRAPDOOR))
		switch(mitem[aa][bb]) {
		case SPIRITNAGA:
		case PLATINUMDRAGON:
		case WRAITH:
		case VAMPIRE:
		case SILVERDRAGON:
		case POLTERGEIST:
		case DEMONLORD:	
		case DEMONLORD+1:
		case DEMONLORD+2:
		case DEMONLORD+3:
		case DEMONLORD+4:
		case DEMONLORD+5:
		case DEMONLORD+6:
		case DEMONPRINCE:
		case LUCIFER:
			break;

		default:
			mitem[aa][bb]=0; /* fell in a pit or trapdoor */
		};
	tmp = mitem[cc][dd] = mitem[aa][bb];
	if (i==OANNIHILATION)
		if (tmp>=DEMONLORD) /* demons dispel spheres */
		{
			flag=0;
			for (x=0;x<26;x++)
				if(iven[x]==OSPHTALISMAN) flag++;
			if (flag==0 
			    || (flag && tmp == LUCIFER && (rnd(10) > 7))) {
				cursors();
			lprintf("\nThe %s dispels the sphere!",
				monster[tmp].name);
				rmsphere(cc,dd);	/* delete the sphere */
			}
			else i=tmp=mitem[cc][dd]=0;
		}
		else i=tmp=mitem[cc][dd]=0;

	stealth[cc][dd]=1;
	flag=0;

	if ((hitp[cc][dd] = hitp[aa][bb]) < 0) hitp[cc][dd]=1;

	if (tmp==LEMMING) {
		if (rnd(100)<=9) {
			mitem[aa][bb] = LEMMING;
			know[aa][bb]=1;
		}
		else mitem[aa][bb] = 0;
	}
	else mitem[aa][bb] = 0;

	moved[cc][dd] = 1;

	if (tmp == LEPRECHAUN)/* leprechaun takes gold */
		switch(i) {
		case OGOLDPILE:  
		case OMAXGOLD:  
		case OKGOLD:
		case ODGOLD:
		case ODIAMOND:   
		case ORUBY:     
		case OEMERALD: 
		case OSAPPHIRE:
			item[cc][dd] = 0; 
		};

	if (tmp == TROLL)  /* if a troll regenerate him */
		if ((gtime & 1) == 0)
			if (monster[tmp].hitpoints > hitp[cc][dd])  hitp[cc][dd]++;

	if (i==OTRAPARROW)	/* arrow hits monster */
	{ 
		who = "An arrow";  
		if ((hitp[cc][dd] -= rnd(10)+level) <= 0) { 
			mitem[cc][dd]=0;  
			flag=2; 
		} 
		else flag=1; 
	}

	if (i==ODARTRAP)	/* dart hits monster */
	{ 
		who = "A dart";  
		if ((hitp[cc][dd] -= rnd(6)) <= 0) { 
			mitem[cc][dd]=0;  
			flag=2; 
		} 
		else flag=1; 
	}

	if (tmp < DEMONLORD)
		if (i==OTELEPORTER)	/* monster hits teleport trap */
		{ 
			flag=3; 
			fillmonst(mitem[cc][dd]);  
			mitem[cc][dd]=0; 
		}

	if (tmp < DEMONLORD)
		if ((i==OELEVATORUP) || (i==OELEVATORDOWN)) {
			mitem[cc][dd]=0;
			flag=4;
		}

	if (c[BLINDCOUNT]) return;	
	/* if blind don't show where monsters are	*/
	if (know[cc][dd] & 1) {
		p=0;
		if (flag) cursors();
		switch(flag) {
		case 1: 
			p="\n%s hits the %s";  
			break;
		case 2: 
			p="\n%s hits and kills the %s";  
			break;
		case 3: 
			p="\nThe %s%s gets teleported"; 
			who="";  
			break;
		case 4: 
			p="\nThe %s%s is carried away by an elevator!";
			who="";
			break;
		};
		if (p) { 
			lprintf(p,who,monster[tmp].name); 
			beep(); 
		}
	}

	if (know[aa][bb] & 1)   show1cell(aa,bb);
	if (know[cc][dd] & 1)   show1cell(cc,dd);
}

/*
 *	movsphere() 	Function to look for and move spheres of annihilation
 *
 *	This function works on the sphere linked list, first duplicating the list
 *	(the act of moving changes the list), then processing each sphere in order
 *	to move it.  They eat anything in their way, including stairs, volcanic
 *	shafts, potions, etc, except for upper level demons, who can dispel
 *	spheres.
 *	No value is returned.
 */
#define SPHMAX 20	/* maximum number of spheres movsphere can handle */
movsphere()
{
	register int x,y,dir,len;
	register struct sphere *sp,*sp2;
	struct sphere sph[SPHMAX];

	/* first duplicate sphere list */
	/* look through sphere list */
	for (sp=0,x=0,sp2=spheres; sp2; sp2=sp2->p)
		/* only if this level */
		if (sp2->lev == level) {
			sph[x] = *sp2;	
			sph[x++].p = 0;  /* copy the struct */
			if (x>1)  
				sph[x-2].p = &sph[x-1]; /* link pointers */
		}
	if (x) sp= sph;	/* if any spheres, point to them */
	else return;	/* no spheres */

	/* look through sphere list */
	for (sp=sph; sp; sp=sp->p) {
		x = sp->x;	  
		y = sp->y;
		if (item[x][y]!=OANNIHILATION) continue;/* not really there */

		/* has sphere run out of gas? */
		if (--(sp->lifetime) < 0) {
			rmsphere(x,y); /* delete sphere */
			continue;
		}
		/* time to move the sphere */
		switch(rnd((int)max(7,c[INTELLIGENCE]>>1))) {
		case 1:
		case 2:		/* change direction to a random one */
			sp->dir = rnd(8);
		default:	/* move in normal direction */
			dir = sp->dir;		
			len = sp->lifetime;
			rmsphere(x,y);
			newsphere(x+diroffx[dir],y+diroffy[dir],dir,len);
		};
	}
}