Mercurial > hg > early-roguelike
comparison urogue/chase.c @ 256:c495a4f288c6
Import UltraRogue from the Roguelike Restoration Project (r1490)
| author | John "Elwin" Edwards |
|---|---|
| date | Tue, 31 Jan 2017 19:56:04 -0500 |
| parents | |
| children | 0250220d8cdd |
comparison
equal
deleted
inserted
replaced
| 253:d9badb9c0179 | 256:c495a4f288c6 |
|---|---|
| 1 /* | |
| 2 chase.c - Code for one creature to chase another | |
| 3 | |
| 4 UltraRogue: The Ultimate Adventure in the Dungeons of Doom | |
| 5 Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong | |
| 6 All rights reserved. | |
| 7 | |
| 8 Based on "Advanced Rogue" | |
| 9 Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka | |
| 10 All rights reserved. | |
| 11 | |
| 12 Based on "Rogue: Exploring the Dungeons of Doom" | |
| 13 Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman | |
| 14 All rights reserved. | |
| 15 | |
| 16 See the file LICENSE.TXT for full copyright and licensing information. | |
| 17 */ | |
| 18 | |
| 19 #include <stdlib.h> | |
| 20 #include <ctype.h> | |
| 21 #include <limits.h> | |
| 22 #include "rogue.h" | |
| 23 | |
| 24 /* | |
| 25 do_chase() | |
| 26 Make one thing chase another. | |
| 27 */ | |
| 28 | |
| 29 void | |
| 30 do_chase(struct thing *th, int flee) | |
| 31 { | |
| 32 struct room *rer; /* room of chaser */ | |
| 33 struct room *ree; /* room of chasee */ | |
| 34 struct room *old_room; /* old room of monster */ | |
| 35 struct room *new_room; /* new room of monster */ | |
| 36 | |
| 37 int i, mindist = INT_MAX, maxdist = INT_MIN, dist = INT_MIN; | |
| 38 | |
| 39 int last_door = -1; /* Door we just came from */ | |
| 40 int stoprun = FALSE; /* TRUE means we are there */ | |
| 41 int rundoor; /* TRUE means run to a door */ | |
| 42 int hit_bad = FALSE; /* TRUE means hit bad monster */ | |
| 43 int mon_attack; /* TRUE means find a monster to hit */ | |
| 44 | |
| 45 char sch; | |
| 46 struct linked_list *item; | |
| 47 coord this; /* Temporary destination for chaser */ | |
| 48 | |
| 49 if (!th->t_ischasing) | |
| 50 return; | |
| 51 | |
| 52 /* Make sure the monster can move */ | |
| 53 | |
| 54 if (th->t_no_move != 0) | |
| 55 { | |
| 56 th->t_no_move--; | |
| 57 return; | |
| 58 } | |
| 59 | |
| 60 /* | |
| 61 * Bad monsters check for a good monster to hit, friendly monsters | |
| 62 * check for a bad monster to hit. | |
| 63 */ | |
| 64 | |
| 65 mon_attack = FALSE; | |
| 66 | |
| 67 if (good_monster(*th)) | |
| 68 { | |
| 69 hit_bad = TRUE; | |
| 70 mon_attack = TRUE; | |
| 71 } | |
| 72 else if (on(*th, ISMEAN)) | |
| 73 { | |
| 74 hit_bad = FALSE; | |
| 75 mon_attack = TRUE; | |
| 76 } | |
| 77 | |
| 78 if (mon_attack) | |
| 79 { | |
| 80 struct linked_list *mon_to_hit; | |
| 81 | |
| 82 mon_to_hit = f_mons_a(th->t_pos.y, th->t_pos.x, hit_bad); | |
| 83 | |
| 84 if (mon_to_hit) | |
| 85 { | |
| 86 mon_mon_attack(th, mon_to_hit, pick_weap(th), NOTHROWN); | |
| 87 return; | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 /* no nearby monster to hit */ | |
| 92 | |
| 93 rer = roomin(th->t_pos); /* Find room of chaser */ | |
| 94 ree = roomin(th->t_chasee->t_pos); /* Find room of chasee */ | |
| 95 | |
| 96 /* | |
| 97 * We don't count doors as inside rooms for this routine | |
| 98 */ | |
| 99 | |
| 100 if (mvwinch(stdscr, th->t_pos.y, th->t_pos.x) == DOOR) | |
| 101 rer = NULL; | |
| 102 | |
| 103 this = th->t_chasee->t_pos; | |
| 104 | |
| 105 /* | |
| 106 * If we are not in a corridor and not a phasing monster, then if we | |
| 107 * are running after the player, we run to a door if he is not in the | |
| 108 * same room. If we are fleeing, we run to a door if he IS in the | |
| 109 * same room. Note: We don't bother with doors in mazes. Phasing | |
| 110 * monsters don't need to look for doors. There are no doors in mazes | |
| 111 * and throne rooms. | |
| 112 */ | |
| 113 | |
| 114 if (levtype != MAZELEV && levtype != THRONE && rer != NULL && off(*th, CANINWALL)) | |
| 115 { | |
| 116 if (flee) | |
| 117 rundoor = (rer == ree); | |
| 118 else | |
| 119 rundoor = (rer != ree); | |
| 120 } | |
| 121 else | |
| 122 rundoor = FALSE; | |
| 123 | |
| 124 if (rundoor) | |
| 125 { | |
| 126 coord d_exit; /* A particular door */ | |
| 127 int exity, exitx; /* Door's coordinates */ | |
| 128 | |
| 129 if (th->t_doorgoal != -1) | |
| 130 { /* Do we already have the goal? */ | |
| 131 this = rer->r_exit[th->t_doorgoal]; | |
| 132 dist = 0; /* Indicate that we have our door */ | |
| 133 } | |
| 134 else | |
| 135 for (i = 0; i < rer->r_nexits; i++) | |
| 136 { /* Loop through doors */ | |
| 137 d_exit = rer->r_exit[i]; | |
| 138 exity = d_exit.y; | |
| 139 exitx = d_exit.x; | |
| 140 | |
| 141 /* Avoid secret doors */ | |
| 142 if (mvwinch(stdscr, exity, exitx) == DOOR) | |
| 143 { | |
| 144 /* Were we just on this door? */ | |
| 145 if (ce(d_exit, th->t_oldpos)) | |
| 146 last_door = i; | |
| 147 else | |
| 148 { | |
| 149 dist = DISTANCE(th->t_chasee->t_pos, d_exit); | |
| 150 | |
| 151 /* | |
| 152 * If fleeing, we want to | |
| 153 * maximize distance from | |
| 154 * door to what we flee, and | |
| 155 * minimize distance from | |
| 156 * door to us. | |
| 157 */ | |
| 158 | |
| 159 if (flee) | |
| 160 dist-=DISTANCE(th->t_pos,d_exit); | |
| 161 | |
| 162 /* | |
| 163 * Maximize distance if | |
| 164 * fleeing, otherwise | |
| 165 * minimize it | |
| 166 */ | |
| 167 | |
| 168 if ((flee && (dist > maxdist)) || | |
| 169 (!flee && (dist < mindist))) | |
| 170 { | |
| 171 th->t_doorgoal = i; /* Use this door */ | |
| 172 this = d_exit; | |
| 173 mindist = maxdist = dist; | |
| 174 } | |
| 175 } | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 /* Could we not find a door? */ | |
| 180 if (dist == INT_MIN) | |
| 181 { | |
| 182 /* If we were on a door, go ahead and use it */ | |
| 183 if (last_door != -1) | |
| 184 { | |
| 185 th->t_doorgoal = last_door; | |
| 186 this = th->t_oldpos; | |
| 187 dist = 0; /* Indicate that we found a door */ | |
| 188 } | |
| 189 } | |
| 190 | |
| 191 /* Indicate that we do not want to flee from the door */ | |
| 192 if (dist != INT_MIN) | |
| 193 flee = FALSE; | |
| 194 } | |
| 195 else | |
| 196 th->t_doorgoal = -1; /* Not going to any door */ | |
| 197 | |
| 198 /* | |
| 199 * this now contains what we want to run to this time so we run to | |
| 200 * it. If we hit it we either want to fight it or stop running | |
| 201 */ | |
| 202 | |
| 203 if (!chase(th, &this, flee)) | |
| 204 { | |
| 205 if (ce(th->t_nxtpos, hero)) | |
| 206 { | |
| 207 /* merchants try to sell something */ | |
| 208 | |
| 209 if (on(*th, CANSELL)) | |
| 210 { | |
| 211 sell(th); | |
| 212 return; | |
| 213 } | |
| 214 else if (off(*th, ISFRIENDLY) && off(*th, ISCHARMED) | |
| 215 && (off(*th, CANFLY) || (on(*th, CANFLY) && rnd(2)))) | |
| 216 attack(th, pick_weap(th), FALSE); | |
| 217 return; | |
| 218 } | |
| 219 else if (on(*th, NOMOVE)) | |
| 220 stoprun = TRUE; | |
| 221 } | |
| 222 | |
| 223 if (!curr_mons) | |
| 224 return; /* Did monster get itself killed? */ | |
| 225 | |
| 226 if (on(*th, NOMOVE)) | |
| 227 return; | |
| 228 | |
| 229 /* If we have a scavenger, it can pick something up */ | |
| 230 | |
| 231 if ((item = find_obj(th->t_nxtpos.y, th->t_nxtpos.x)) != NULL) | |
| 232 { | |
| 233 struct linked_list *node, *top = item; | |
| 234 struct object *obt; | |
| 235 | |
| 236 while(top) | |
| 237 { | |
| 238 /* grab all objects that qualify */ | |
| 239 | |
| 240 struct object *obj = OBJPTR(item); | |
| 241 | |
| 242 obt = OBJPTR(top); | |
| 243 node = obt->next_obj; | |
| 244 | |
| 245 if (on(*th, ISSCAVENGE) || | |
| 246 ((on(*th, CANWIELD) || on(*th, CANSHOOT)) && | |
| 247 (obj->o_type == WEAPON || obj->o_type == ARMOR)) || | |
| 248 (on(*th, CANCAST) && is_magic(obj))) | |
| 249 { | |
| 250 rem_obj(top, FALSE); | |
| 251 attach(th->t_pack, top); | |
| 252 } | |
| 253 | |
| 254 top = node; | |
| 255 } | |
| 256 | |
| 257 light(&hero); | |
| 258 } | |
| 259 | |
| 260 mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); | |
| 261 sch = CCHAR( mvwinch(cw, th->t_nxtpos.y, th->t_nxtpos.x) ); | |
| 262 | |
| 263 /* Get old and new room of monster */ | |
| 264 old_room = roomin(th->t_pos); | |
| 265 new_room = roomin(th->t_nxtpos); | |
| 266 | |
| 267 /* If the monster can illuminate rooms, check for a change */ | |
| 268 if (on(*th, HASFIRE)) | |
| 269 { | |
| 270 /* Is monster entering a room? */ | |
| 271 if (old_room != new_room && new_room != NULL) | |
| 272 { | |
| 273 new_room->r_flags |= HASFIRE; | |
| 274 new_room->r_fires++; | |
| 275 if (cansee(th->t_nxtpos.y, th->t_nxtpos.x) && new_room->r_fires==1) | |
| 276 light(&hero); | |
| 277 } | |
| 278 | |
| 279 /* Is monster leaving a room? */ | |
| 280 if (old_room != new_room && old_room != NULL) | |
| 281 { | |
| 282 if (--(old_room->r_fires) <= 0) | |
| 283 { | |
| 284 old_room->r_flags &= ~HASFIRE; | |
| 285 if (cansee(th->t_pos.y, th->t_pos.x)) | |
| 286 light(&th->t_pos); | |
| 287 } | |
| 288 } | |
| 289 } | |
| 290 | |
| 291 /* | |
| 292 * If monster is entering player's room and player can see it, stop | |
| 293 * the player's running. | |
| 294 */ | |
| 295 | |
| 296 if (new_room != old_room && new_room != NULL && | |
| 297 new_room == ree && cansee(th->t_nxtpos.y, th->t_nxtpos.x) && | |
| 298 (off(*th, ISINVIS) || (off(*th, ISSHADOW) || rnd(10) == 0) || | |
| 299 on(player, CANSEE)) && off(*th, CANSURPRISE)) | |
| 300 running = FALSE; | |
| 301 | |
| 302 if (rer != NULL && (rer->r_flags & ISDARK) && | |
| 303 !(rer->r_flags & HASFIRE) && sch == FLOOR && | |
| 304 DISTANCE(th->t_nxtpos, th->t_pos) < see_dist && | |
| 305 off(player, ISBLIND)) | |
| 306 th->t_oldch = ' '; | |
| 307 else | |
| 308 th->t_oldch = sch; | |
| 309 | |
| 310 if (cansee(th->t_nxtpos.y, th->t_nxtpos.x) && | |
| 311 off(*th, ISINWALL) && | |
| 312 ((off(*th, ISINVIS) && (off(*th, ISSHADOW) || rnd(100) < 10)) || | |
| 313 on(player, CANSEE)) && | |
| 314 off(*th, CANSURPRISE)) | |
| 315 mvwaddch(cw, th->t_nxtpos.y, th->t_nxtpos.x, th->t_type); | |
| 316 | |
| 317 mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); | |
| 318 mvwaddch(mw, th->t_nxtpos.y, th->t_nxtpos.x, th->t_type); | |
| 319 | |
| 320 /* Record monster's last position (if new one is different) */ | |
| 321 | |
| 322 if (!ce(th->t_nxtpos, th->t_pos)) | |
| 323 th->t_oldpos = th->t_pos; | |
| 324 | |
| 325 th->t_pos = th->t_nxtpos; /* Mark the monster's new position */ | |
| 326 | |
| 327 /* If the monster is on a trap, trap it */ | |
| 328 | |
| 329 sch = CCHAR(mvinch(th->t_nxtpos.y, th->t_nxtpos.x)); | |
| 330 | |
| 331 if (isatrap(sch)) | |
| 332 { | |
| 333 debug("Monster trapped by %c.", sch); | |
| 334 | |
| 335 if (cansee(th->t_nxtpos.y, th->t_nxtpos.x)) | |
| 336 th->t_oldch = sch; | |
| 337 | |
| 338 be_trapped(th, th->t_nxtpos); | |
| 339 } | |
| 340 | |
| 341 /* And stop running if need be */ | |
| 342 | |
| 343 if (stoprun && ce(th->t_pos, th->t_chasee->t_pos)) | |
| 344 { | |
| 345 th->t_ischasing = FALSE; | |
| 346 turn_off(*th, ISRUN); | |
| 347 } | |
| 348 } | |
| 349 | |
| 350 /* | |
| 351 chase_it() | |
| 352 Set a monster running after something or stop it from running (for | |
| 353 when it dies) | |
| 354 */ | |
| 355 | |
| 356 void | |
| 357 chase_it(coord *runner, struct thing *th) | |
| 358 { | |
| 359 struct linked_list *item; | |
| 360 struct thing *tp; | |
| 361 | |
| 362 /* If we couldn't find him, something is funny */ | |
| 363 | |
| 364 if ((item = find_mons(runner->y, runner->x)) == NULL) | |
| 365 { | |
| 366 debug("CHASER '%s'", unctrl(winat(runner->y, runner->x))); | |
| 367 return; | |
| 368 } |
