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