Mercurial > hg > early-roguelike
comparison rogue5/chase.c @ 33:f502bf60e6e4
Import Rogue 5.4 from the Roguelike Restoration Project (r1490)
| author | elwin |
|---|---|
| date | Mon, 24 May 2010 20:10:59 +0000 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 32:2dcd75e6a736 | 33:f502bf60e6e4 |
|---|---|
| 1 /* | |
| 2 * Code for one creature to chase another | |
| 3 * | |
| 4 * @(#)chase.c 4.57 (Berkeley) 02/05/99 | |
| 5 * | |
| 6 * Rogue: Exploring the Dungeons of Doom | |
| 7 * Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman | |
| 8 * All rights reserved. | |
| 9 * | |
| 10 * See the file LICENSE.TXT for full copyright and licensing information. | |
| 11 */ | |
| 12 | |
| 13 #include <stdlib.h> | |
| 14 #include <curses.h> | |
| 15 #include "rogue.h" | |
| 16 | |
| 17 #define DRAGONSHOT 5 /* one chance in DRAGONSHOT that a dragon will flame */ | |
| 18 | |
| 19 static coord ch_ret; /* Where chasing takes you */ | |
| 20 | |
| 21 /* | |
| 22 * runners: | |
| 23 * Make all the running monsters move. | |
| 24 */ | |
| 25 void | |
| 26 runners(void) | |
| 27 { | |
| 28 THING *tp; | |
| 29 THING *next; | |
| 30 int wastarget; | |
| 31 coord orig_pos; | |
| 32 | |
| 33 for (tp = mlist; tp != NULL; tp = next) | |
| 34 { | |
| 35 /* remember this in case the monster's "next" is changed */ | |
| 36 next = next(tp); | |
| 37 if (!on(*tp, ISHELD) && on(*tp, ISRUN)) | |
| 38 { | |
| 39 orig_pos = tp->t_pos; | |
| 40 wastarget = on(*tp, ISTARGET); | |
| 41 if (move_monst(tp) == -1) | |
| 42 continue; | |
| 43 if (on(*tp, ISFLY) && dist_cp(&hero, &tp->t_pos) >= 3) | |
| 44 move_monst(tp); | |
| 45 if (wastarget && !ce(orig_pos, tp->t_pos)) | |
| 46 { | |
| 47 tp->t_flags &= ~ISTARGET; | |
| 48 to_death = FALSE; | |
| 49 } | |
| 50 } | |
| 51 } | |
| 52 if (has_hit) | |
| 53 { | |
| 54 endmsg(); | |
| 55 has_hit = FALSE; | |
| 56 } | |
| 57 } | |
| 58 | |
| 59 /* | |
| 60 * move_monst: | |
| 61 * Execute a single turn of running for a monster | |
| 62 */ | |
| 63 int | |
| 64 move_monst(THING *tp) | |
| 65 { | |
| 66 if (!on(*tp, ISSLOW) || tp->t_turn) | |
| 67 if (do_chase(tp) == -1) | |
| 68 return(-1); | |
| 69 if (on(*tp, ISHASTE)) | |
| 70 if (do_chase(tp) == -1) | |
| 71 return(-1); | |
| 72 tp->t_turn ^= TRUE; | |
| 73 return(0); | |
| 74 } | |
| 75 | |
| 76 /* | |
| 77 * relocate: | |
| 78 * Make the monster's new location be the specified one, updating | |
| 79 * all the relevant state. | |
| 80 */ | |
| 81 void | |
| 82 relocate(THING *th, const coord *new_loc) | |
| 83 { | |
| 84 struct room *oroom; | |
| 85 | |
| 86 if (!ce(*new_loc, th->t_pos)) | |
| 87 { | |
| 88 mvaddch(th->t_pos.y, th->t_pos.x, th->t_oldch); | |
| 89 th->t_room = roomin(new_loc); | |
| 90 set_oldch(th, new_loc); | |
| 91 oroom = th->t_room; | |
| 92 moat(th->t_pos.y, th->t_pos.x) = NULL; | |
| 93 | |
| 94 if (oroom != th->t_room) | |
| 95 th->t_dest = find_dest(th); | |
| 96 th->t_pos = *new_loc; | |
| 97 moat(new_loc->y, new_loc->x) = th; | |
| 98 } | |
| 99 move(new_loc->y, new_loc->x); | |
| 100 if (see_monst(th)) | |
| 101 addch(th->t_disguise); | |
| 102 else if (on(player, SEEMONST)) | |
| 103 { | |
| 104 standout(); | |
| 105 addch(th->t_type); | |
| 106 standend(); | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 /* | |
| 111 * do_chase: | |
| 112 * Make one thing chase another. | |
| 113 */ | |
| 114 int | |
| 115 do_chase(THING *th) | |
| 116 { | |
| 117 coord *cp; | |
| 118 struct room *rer, *ree; /* room of chaser, room of chasee */ | |
| 119 int mindist = 32767, curdist; | |
| 120 int stoprun = FALSE; /* TRUE means we are there */ | |
| 121 int door; | |
| 122 THING *obj; | |
| 123 coord this; /* Temporary destination for chaser */ | |
| 124 | |
| 125 rer = th->t_room; /* Find room of chaser */ | |
| 126 if (on(*th, ISGREED) && rer->r_goldval == 0) | |
| 127 th->t_dest = &hero; /* If gold has been taken, run after hero */ | |
| 128 if (th->t_dest == &hero) /* Find room of chasee */ | |
| 129 ree = proom; | |
| 130 else | |
| 131 ree = roomin(th->t_dest); | |
| 132 /* | |
| 133 * We don't count doors as inside rooms for this routine | |
| 134 */ | |
| 135 door = (chat(th->t_pos.y, th->t_pos.x) == DOOR); | |
| 136 /* | |
| 137 * If the object of our desire is in a different room, | |
| 138 * and we are not in a corridor, run to the door nearest to | |
| 139 * our goal. | |
| 140 */ | |
| 141 over: | |
| 142 if (rer != ree) | |
| 143 { | |
| 144 for (cp = rer->r_exit; cp < &rer->r_exit[rer->r_nexits]; cp++) | |
| 145 { | |
| 146 curdist = dist_cp(th->t_dest, cp); | |
| 147 if (curdist < mindist) | |
| 148 { | |
| 149 this = *cp; | |
| 150 mindist = curdist; | |
| 151 } | |
| 152 } | |
| 153 if (door) | |
| 154 { | |
| 155 rer = &passages[flat(th->t_pos.y, th->t_pos.x) & F_PNUM]; | |
| 156 door = FALSE; | |
| 157 goto over; | |
| 158 } | |
| 159 } | |
| 160 else | |
| 161 { | |
| 162 this = *th->t_dest; | |
| 163 /* | |
| 164 * For dragons check and see if (a) the hero is on a straight | |
| 165 * line from it, and (b) that it is within shooting distance, | |
| 166 * but outside of striking range. | |
| 167 */ | |
| 168 if (th->t_type == 'D' && (th->t_pos.y == hero.y || th->t_pos.x == hero.x | |
| 169 || abs(th->t_pos.y - hero.y) == abs(th->t_pos.x - hero.x)) | |
| 170 && dist_cp(&th->t_pos, &hero) <= BOLT_LENGTH * BOLT_LENGTH | |
| 171 && !on(*th, ISCANC) && rnd(DRAGONSHOT) == 0) | |
| 172 { | |
| 173 delta.y = sign(hero.y - th->t_pos.y); | |
| 174 delta.x = sign(hero.x - th->t_pos.x); | |
| 175 if (has_hit) | |
| 176 endmsg(); | |
| 177 fire_bolt(&th->t_pos, &delta, "flame"); | |
| 178 running = FALSE; | |
| 179 count = 0; | |
| 180 quiet = 0; | |
| 181 if (to_death && !on(*th, ISTARGET)) | |
| 182 { | |
| 183 to_death = FALSE; | |
| 184 kamikaze = FALSE; | |
| 185 } | |
| 186 return(0); | |
| 187 } | |
| 188 } | |
| 189 /* | |
| 190 * This now contains what we want to run to this time | |
| 191 * so we run to it. If we hit it we either want to fight it | |
| 192 * or stop running | |
| 193 */ | |
| 194 if (!chase(th, &this)) | |
| 195 { | |
| 196 if (ce(this, hero)) | |
| 197 { | |
| 198 return( attack(th) ); | |
| 199 } | |
| 200 else if (ce(this, *th->t_dest)) | |
| 201 { | |
| 202 for (obj = lvl_obj; obj != NULL; obj = next(obj)) | |
| 203 if (th->t_dest == &obj->o_pos) | |
| 204 { | |
| 205 detach(lvl_obj, obj); | |
| 206 attach(th->t_pack, obj); | |
| 207 chat(obj->o_pos.y, obj->o_pos.x) = | |
| 208 (th->t_room->r_flags & ISGONE) ? PASSAGE : FLOOR; | |
| 209 th->t_dest = find_dest(th); | |
| 210 break; | |
| 211 } | |
| 212 if (th->t_type != 'F') | |
| 213 stoprun = TRUE; | |
| 214 } | |
| 215 } | |
| 216 else | |
| 217 { | |
| 218 if (th->t_type == 'F') | |
| 219 return(0); | |
| 220 } | |
| 221 relocate(th, &ch_ret); | |
| 222 /* | |
| 223 * And stop running if need be | |
| 224 */ | |
| 225 if (stoprun && ce(th->t_pos, *(th->t_dest))) | |
| 226 th->t_flags &= ~ISRUN; | |
| 227 return(0); | |
| 228 } | |
| 229 | |
| 230 /* | |
| 231 * set_oldch: | |
| 232 * Set the oldch character for the monster | |
| 233 */ | |
| 234 void | |
| 235 set_oldch(THING *tp, const coord *cp) | |
| 236 { | |
| 237 int sch; | |
| 238 | |
| 239 if (ce(tp->t_pos, *cp)) | |
| 240 return; | |
| 241 | |
| 242 sch = tp->t_oldch; | |
| 243 tp->t_oldch = CCHAR( mvinch(cp->y,cp->x) ); | |
| 244 if (!on(player, ISBLIND)) | |
| 245 { | |
| 246 if ((sch == FLOOR || tp->t_oldch == FLOOR) && | |
| 247 (tp->t_room->r_flags & ISDARK)) | |
| 248 tp->t_oldch = ' '; | |
| 249 else if (dist_cp(cp, &hero) <= LAMPDIST && see_floor) | |
| 250 tp->t_oldch = chat(cp->y, cp->x); | |
| 251 } | |
| 252 } | |
| 253 | |
| 254 /* | |
| 255 * see_monst: | |
| 256 * Return TRUE if the hero can see the monster | |
| 257 */ | |
| 258 int | |
| 259 see_monst(const THING *mp) | |
| 260 { | |
| 261 int y, x; | |
| 262 | |
| 263 if (on(player, ISBLIND)) | |
| 264 return FALSE; | |
| 265 if (on(*mp, ISINVIS) && !on(player, CANSEE)) | |
| 266 return FALSE; | |
| 267 y = mp->t_pos.y; | |
| 268 x = mp->t_pos.x; | |
| 269 if (dist(y, x, hero.y, hero.x) < LAMPDIST) | |
| 270 { | |
| 271 if (y != hero.y && x != hero.x && | |
| 272 !step_ok(chat(y, hero.x)) && !step_ok(chat(hero.y, x))) | |
| 273 return FALSE; | |
| 274 return TRUE; | |
| 275 } | |
| 276 if (mp->t_room != proom) | |
| 277 return FALSE; | |
| 278 return (!(mp->t_room->r_flags & ISDARK)); | |
| 279 } | |
| 280 | |
| 281 /* | |
| 282 * runto: | |
| 283 * Set a monster running after the hero. | |
| 284 */ | |
| 285 void | |
| 286 runto(const coord *runner) | |
| 287 { | |
| 288 THING *tp; | |
| 289 | |
| 290 /* | |
| 291 * If we couldn't find him, something is funny | |
| 292 */ | |
| 293 if ((tp = moat(runner->y, runner->x)) == NULL) | |
| 294 { | |
| 295 #ifdef MASTER | |
| 296 msg("couldn't find monster in runto at (%d,%d)", runner->y, runner->x); | |
| 297 #endif | |
| 298 return; | |
| 299 } | |
| 300 | |
| 301 /* | |
| 302 * Start the beastie running | |
| 303 */ | |
| 304 tp->t_flags |= ISRUN; | |
| 305 tp->t_flags &= ~ISHELD; | |
| 306 tp->t_dest = find_dest(tp); | |
| 307 } | |
| 308 | |
| 309 /* | |
| 310 * chase: | |
| 311 * Find the spot for the chaser(er) to move closer to the | |
| 312 * chasee(ee). Returns TRUE if we want to keep on chasing later | |
| 313 * FALSE if we reach the goal. | |
| 314 */ | |
| 315 int | |
| 316 chase(THING *tp, const coord *ee) | |
| 317 { | |
| 318 THING *obj; | |
| 319 int x, y; | |
| 320 int curdist, thisdist; | |
| 321 const coord *er = &tp->t_pos; | |
| 322 int ch; | |
| 323 int plcnt = 1; | |
| 324 coord tryp; | |
| 325 | |
| 326 /* | |
| 327 * If the thing is confused, let it move randomly. Invisible | |
| 328 * Stalkers are slightly confused all of the time, and bats are | |
| 329 * quite confused all the time | |
| 330 */ | |
| 331 if ((on(*tp, ISHUH) && rnd(5) != 0) || (tp->t_type == 'P' && rnd(5) == 0) | |
| 332 || (tp->t_type == 'B' && rnd(2) == 0)) | |
| 333 { | |
| 334 /* | |
| 335 * get a valid random move | |
| 336 */ | |
| 337 ch_ret = rndmove(tp); | |
| 338 curdist = dist_cp(&ch_ret, ee); | |
| 339 /* | |
| 340 * Small chance that it will become un-confused | |
| 341 */ | |
| 342 if (rnd(20) == 0) | |
| 343 tp->t_flags &= ~ISHUH; | |
| 344 } | |
| 345 /* | |
| 346 * Otherwise, find the empty spot next to the chaser that is | |
| 347 * closest to the chasee. | |
| 348 */ | |
| 349 else | |
| 350 { | |
| 351 int ey, ex; | |
| 352 /* | |
| 353 * This will eventually hold where we move to get closer | |
| 354 * If we can't find an empty spot, we stay where we are. | |
| 355 */ | |
| 356 curdist = dist_cp(er, ee); | |
| 357 ch_ret = *er; | |
| 358 | |
| 359 ey = er->y + 1; | |
| 360 if (ey >= NUMLINES - 1) | |
| 361 ey = NUMLINES - 2; | |
| 362 ex = er->x + 1; | |
| 363 if (ex >= NUMCOLS) | |
| 364 ex = NUMCOLS - 1; | |
| 365 | |
| 366 for (x = er->x - 1; x <= ex; x++) | |
| 367 { | |
| 368 if (x < 0) | |
| 369 continue; | |
| 370 tryp.x = x; | |
| 371 for (y = er->y - 1; y <= ey; y++) | |
| 372 { | |
| 373 tryp.y = y; | |
| 374 if (!diag_ok(er, &tryp)) | |
| 375 continue; | |
| 376 ch = winat(y, x); | |
| 377 if (step_ok(ch)) | |
| 378 { | |
| 379 /* | |
| 380 * If it is a scroll, it might be a scare monster scroll | |
| 381 * so we need to look it up to see what type it is. | |
| 382 */ | |
