1/* $NetBSD: movem.c,v 1.10 2019/02/03 03:19:25 mrg Exp $ */ 2 3/* 4 * movem.c (move monster) Larn is copyrighted 1986 by Noah Morgan. 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 <sys/cdefs.h> 14#ifndef lint 15__RCSID("$NetBSD: movem.c,v 1.10 2019/02/03 03:19:25 mrg Exp $"); 16#endif /* not lint */ 17 18#include "header.h" 19#include "extern.h" 20 21static void movemt(int, int); 22static void mmove(int, int, int, int); 23static void movsphere(void); 24 25/* 26 * movemonst() Routine to move the monsters toward the player 27 * 28 * This routine has the responsibility to determine which monsters are to 29 * move, and call movemt() to do the move. 30 * Returns no value. 31 */ 32static short w1[9], w1x[9], w1y[9]; 33static int tmp1, tmp2, tmp3, tmp4, distance; 34void 35movemonst(void) 36{ 37 int i, j; 38 if (c[TIMESTOP]) 39 return; /* no action if time is stopped */ 40 if (c[HASTESELF]) 41 if ((c[HASTESELF] & 1) == 0) 42 return; 43 if (spheres) 44 movsphere(); /* move the spheres of annihilation if any */ 45 if (c[HOLDMONST]) 46 return; /* no action if monsters are held */ 47 48 if (c[AGGRAVATE]) { /* determine window of monsters to move */ 49 tmp1 = playery - 5; 50 tmp2 = playery + 6; 51 tmp3 = playerx - 10; 52 tmp4 = playerx + 11; 53 distance = 40; /* depth of intelligent monster movement */ 54 } else { 55 tmp1 = playery - 3; 56 tmp2 = playery + 4; 57 tmp3 = playerx - 5; 58 tmp4 = playerx + 6; 59 distance = 17; /* depth of intelligent monster movement */ 60 } 61 62 if (level == 0) { /* if on outside level monsters can move in 63 * perimeter */ 64 if (tmp1 < 0) 65 tmp1 = 0; 66 if (tmp2 > MAXY) 67 tmp2 = MAXY; 68 if (tmp3 < 0) 69 tmp3 = 0; 70 if (tmp4 > MAXX) 71 tmp4 = MAXX; 72 } else { /* if in a dungeon monsters can't be on the 73 * perimeter (wall there) */ 74 if (tmp1 < 1) 75 tmp1 = 1; 76 if (tmp2 > MAXY - 1) 77 tmp2 = MAXY - 1; 78 if (tmp3 < 1) 79 tmp3 = 1; 80 if (tmp4 > MAXX - 1) 81 tmp4 = MAXX - 1; 82 } 83 84 for (j = tmp1; j < tmp2; j++) /* now reset monster moved flags */ 85 for (i = tmp3; i < tmp4; i++) 86 moved[i][j] = 0; 87 moved[lasthx][lasthy] = 0; 88 89 if (c[AGGRAVATE] || !c[STEALTH]) { /* who gets moved? split for 90 * efficiency */ 91 for (j = tmp1; j < tmp2; j++) /* look thru all locations in 92 * window */ 93 for (i = tmp3; i < tmp4; i++) 94 if (mitem[i][j]) /* if there is a monster 95 * to move */ 96 if (moved[i][j] == 0) /* if it has not already 97 * been moved */ 98 movemt(i, j); /* go and move the 99 * monster */ 100 } else { /* not aggravated and not stealth */ 101 for (j = tmp1; j < tmp2; j++) /* look thru all locations in 102 * window */ 103 for (i = tmp3; i < tmp4; i++) 104 if (mitem[i][j]) /* if there is a monster 105 * to move */ 106 if (moved[i][j] == 0) /* if it has not already 107 * been moved */ 108 if (stealth[i][j]) /* if it is asleep due 109 * to stealth */ 110 movemt(i, j); /* go and move the 111 * monster */ 112 } 113 114 if (mitem[lasthx][lasthy]) { /* now move monster last hit by 115 * player if not already moved */ 116 if (moved[lasthx][lasthy] == 0) { /* if it has not already 117 * been moved */ 118 movemt(lasthx, lasthy); 119 lasthx = w1x[0]; 120 lasthy = w1y[0]; 121 } 122 } 123} 124 125/* 126 * movemt(x,y) Function to move a monster at (x,y) -- must determine where 127 * int x,y; 128 * 129 * This routine is responsible for determining where one monster at (x,y) will 130 * move to. Enter with the monsters coordinates in (x,y). 131 * Returns no value. 132 */ 133static int tmpitem, xl, xh, yl, yh; 134static void 135movemt(int i, int j) 136{ 137 int k, m, z, tmp, xtmp, ytmp, monst; 138 switch (monst = mitem[i][j]) { /* for half speed monsters */ 139 case TROGLODYTE: 140 case HOBGOBLIN: 141 case METAMORPH: 142 case XVART: 143 case INVISIBLESTALKER: 144 case ICELIZARD: 145 if ((gltime & 1) == 1) 146 return; 147 }; 148 149 if (c[SCAREMONST]) { /* choose destination randomly if scared */ 150 if ((xl = i + rnd(3) - 2) < 0) 151 xl = 0; 152 if (xl >= MAXX) 153 xl = MAXX - 1; 154 if ((yl = j + rnd(3) - 2) < 0) 155 yl = 0; 156 if (yl >= MAXY) 157 yl = MAXY - 1; 158 if ((tmp = item[xl][yl]) != OWALL) 159 if (mitem[xl][yl] == 0) 160 if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR)) 161 if (tmp != OCLOSEDDOOR) 162 mmove(i, j, xl, yl); 163 return; 164 } 165 if (monster[monst].intelligence > 10 - c[HARDGAME]) { /* if smart monster */ 166 /* intelligent movement here -- first setup screen array */ 167 xl = tmp3 - 2; 168 yl = tmp1 - 2; 169 xh = tmp4 + 2; 170 yh = tmp2 + 2; 171 vxy(&xl, &yl); 172 vxy(&xh, &yh); 173 for (k = yl; k < yh; k++) 174 for (m = xl; m < xh; m++) { 175 switch (item[m][k]) { 176 case OWALL: 177 case OPIT: 178 case OTRAPARROW: 179 case ODARTRAP: 180 case OCLOSEDDOOR: 181 case OTRAPDOOR: 182 case OTELEPORTER: 183 smm: screen[m][k] = 127; 184 break; 185 case OMIRROR: 186 if (mitem[m][k] == VAMPIRE) 187 goto smm; 188 /* FALLTHROUGH */ 189 default: 190 screen[m][k] = 0; 191 break; 192 }; 193 } 194 screen[playerx][playery] = 1; 195 196 /* 197 * now perform proximity ripple from playerx,playery to 198 * monster 199 */ 200 xl = tmp3 - 1; 201 yl = tmp1 - 1; 202 xh = tmp4 + 1; 203 yh = tmp2 + 1; 204 vxy(&xl, &yl); 205 vxy(&xh, &yh); 206 for (tmp = 1; tmp < distance; tmp++) /* only up to 20 squares 207 * away */ 208 for (k = yl; k < yh; k++) 209 for (m = xl; m < xh; m++) 210 if (screen[m][k] == tmp) /* if find proximity n 211 * advance it */ 212 for (z = 1; z < 9; z++) { /* go around in a circle */ 213 if (screen[xtmp = m + diroffx[z]][ytmp = k + diroffy[z]] == 0) 214 screen[xtmp][ytmp] = tmp + 1; 215 if (xtmp == i && ytmp == j) 216 goto out; 217 } 218 219out: if (tmp < distance) /* did find connectivity */ 220 /* now select lowest value around playerx,playery */ 221 for (z = 1; z < 9; z++) /* go around in a circle */ 222 if (screen[xl = i + diroffx[z]][yl = j + diroffy[z]] == tmp) 223 if (!mitem[xl][yl]) { 224 mmove(i, j, w1x[0] = xl, w1y[0] = yl); 225 return; 226 } 227 } 228 /* dumb monsters move here */ 229 xl = i - 1; 230 yl = j - 1; 231 xh = i + 2; 232 yh = j + 2; 233 if (i < playerx) 234 xl++; 235 else if (i > playerx) 236 --xh; 237 if (j < playery) 238 yl++; 239 else if (j > playery) 240 --yh; 241 for (k = 0; k < 9; k++) 242 w1[k] = 10000; 243 244 for (k = xl; k < xh; k++) 245 for (m = yl; m < yh; m++) { /* for each square compute 246 * distance to player */ 247 tmp = k - i + 4 + 3 * (m - j); 248 tmpitem = item[k][m]; 249 if (tmpitem != OWALL || (k == playerx && m == playery)) 250 if (mitem[k][m] == 0) 251 if ((mitem[i][j] != VAMPIRE) || (tmpitem != OMIRROR)) 252 if (tmpitem != OCLOSEDDOOR) { 253 w1[tmp] = (playerx - k) * (playerx - k) + (playery - m) * (playery - m); 254 w1x[tmp] = k; 255 w1y[tmp] = m; 256 } 257 } 258 259 tmp = 0; 260 for (k = 1; k < 9; k++) 261 if (w1[tmp] > w1[k]) 262 tmp = k; 263 264 if (w1[tmp] < 10000) 265 if ((i != w1x[tmp]) || (j != w1y[tmp])) 266 mmove(i, j, w1x[tmp], w1y[tmp]); 267} 268 269/* 270 * mmove(x,y,xd,yd) Function to actually perform the monster movement 271 * int x,y,xd,yd; 272 * 273 * Enter with the from coordinates in (x,y) and the destination coordinates 274 * in (xd,yd). 275 */ 276static void 277mmove(int aa, int bb, int cc, int dd) 278{ 279 int tmp, i, flag; 280 const char *who = NULL; 281 282 flag = 0; /* set to 1 if monster hit by arrow trap */ 283 if ((cc == playerx) && (dd == playery)) { 284 hitplayer(aa, bb); 285 moved[aa][bb] = 1; 286 return; 287 } 288 i = item[cc][dd]; 289 if ((i == OPIT) || (i == OTRAPDOOR)) 290 switch (mitem[aa][bb]) { 291 case SPIRITNAGA: 292 case PLATINUMDRAGON: 293 case WRAITH: 294 case VAMPIRE: 295 case SILVERDRAGON: 296 case POLTERGEIST: 297 case DEMONLORD: 298 case DEMONLORD + 1: 299 case DEMONLORD + 2: 300 case DEMONLORD + 3: 301 case DEMONLORD + 4: 302 case DEMONLORD + 5: 303 case DEMONLORD + 6: 304 case DEMONPRINCE: 305 break; 306 307 default: 308 mitem[aa][bb] = 0; /* fell in a pit or trapdoor */ 309 }; 310 tmp = mitem[cc][dd] = mitem[aa][bb]; 311 if (i == OANNIHILATION) { 312 if (tmp >= DEMONLORD + 3) { /* demons dispel spheres */ 313 cursors(); 314 lprintf("\nThe %s dispels the sphere!", monster[tmp].name); 315 rmsphere(cc, dd); /* delete the sphere */ 316 } else 317 i = tmp = mitem[cc][dd] = 0; 318 } 319 stealth[cc][dd] = 1; 320 if ((hitp[cc][dd] = hitp[aa][bb]) < 0) 321 hitp[cc][dd] = 1; 322 mitem[aa][bb] = 0; 323 moved[cc][dd] = 1; 324 if (tmp == LEPRECHAUN) 325 switch (i) { 326 case OGOLDPILE: 327 case OMAXGOLD: 328 case OKGOLD: 329 case ODGOLD: 330 case ODIAMOND: 331 case ORUBY: 332 case OEMERALD: 333 case OSAPPHIRE: 334 item[cc][dd] = 0; /* leprechaun takes gold */ 335 }; 336 337 if (tmp == TROLL) /* if a troll regenerate him */ 338 if ((gltime & 1) == 0) 339 if (monster[tmp].hitpoints > hitp[cc][dd]) 340 hitp[cc][dd]++; 341 342 if (i == OTRAPARROW) { /* arrow hits monster */ 343 who = "An arrow"; 344 if ((hitp[cc][dd] -= rnd(10) + level) <= 0) { 345 mitem[cc][dd] = 0; 346 flag = 2; 347 } else 348 flag = 1; 349 } 350 if (i == ODARTRAP) { /* dart hits monster */ 351 who = "A dart"; 352 if ((hitp[cc][dd] -= rnd(6)) <= 0) { 353 mitem[cc][dd] = 0; 354 flag = 2; 355 } else 356 flag = 1; 357 } 358 if (i == OTELEPORTER) { /* monster hits teleport trap */ 359 flag = 3; 360 fillmonst(mitem[cc][dd]); 361 mitem[cc][dd] = 0; 362 } 363 if (c[BLINDCOUNT]) 364 return; /* if blind don't show where monsters are */ 365 if (know[cc][dd] & 1) { 366 if (flag) 367 cursors(); 368 switch (flag) { 369 case 1: 370 lprintf("\n%s hits the %s", who, monster[tmp].name); 371 beep(); 372 break; 373 case 2: 374 lprintf("\n%s hits and kills the %s", 375 who, monster[tmp].name); 376 beep(); 377 break; 378 case 3: 379 lprintf("\nThe %s gets teleported", monster[tmp].name); 380 beep(); 381 break; 382 } 383 } 384 /* 385 * if (yrepcount>1) { know[aa][bb] &= 2; know[cc][dd] &= 2; return; 386 * } 387 */ 388 if (know[aa][bb] & 1) 389 show1cell(aa, bb); 390 if (know[cc][dd] & 1) 391 show1cell(cc, dd); 392} 393 394/* 395 * movsphere() Function to look for and move spheres of annihilation 396 * 397 * This function works on the sphere linked list, first duplicating the list 398 * (the act of moving changes the list), then processing each sphere in order 399 * to move it. They eat anything in their way, including stairs, volcanic 400 * shafts, potions, etc, except for upper level demons, who can dispel 401 * spheres. 402 * No value is returned. 403 */ 404#define SPHMAX 20 /* maximum number of spheres movsphere can 405 * handle */ 406static void 407movsphere(void) 408{ 409 int x, y, dir, len; 410 struct sphere *sp, *sp2; 411 struct sphere sph[SPHMAX]; 412 413 /* first duplicate sphere list */ 414 for (sp = 0, x = 0, sp2 = spheres; sp2; sp2 = sp2->p) /* look through sphere 415 * list */ 416 if (sp2->lev == level) { /* only if this level */ 417 sph[x] = *sp2; 418 sph[x++].p = 0; /* copy the struct */ 419 if (x > 1) 420 sph[x - 2].p = &sph[x - 1]; /* link pointers */ 421 } 422 if (x) 423 sp = sph; /* if any spheres, point to them */ 424 else 425 return; /* no spheres */ 426 427 for (sp = sph; sp; sp = sp->p) { /* look through sphere list */ 428 x = sp->x; 429 y = sp->y; 430 if (item[x][y] != OANNIHILATION) 431 continue; /* not really there */ 432 if (--(sp->lifetime) < 0) { /* has sphere run out of gas? */ 433 rmsphere(x, y); /* delete sphere */ 434 continue; 435 } 436 switch (rnd((int) max(7, c[INTELLIGENCE] >> 1))) { /* time to move the 437 * sphere */ 438 case 1: 439 case 2: /* change direction to a random one */ 440 sp->dir = rnd(8); 441 /* FALLTHROUGH */ 442 default: /* move in normal direction */ 443 dir = sp->dir; 444 len = sp->lifetime; 445 rmsphere(x, y); 446 newsphere(x + diroffx[dir], y + diroffy[dir], dir, len); 447 }; 448 } 449} 450