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