Mercurial > hg > early-roguelike
comparison srogue/chase.c @ 36:2128c7dc8a40
Import Super-Rogue 9.0 from the Roguelike Restoration Project (r1490)
| author | elwin |
|---|---|
| date | Thu, 25 Nov 2010 12:21:41 +0000 |
| parents | |
| children | 94a0d9dd5ce1 |
comparison
equal
deleted
inserted
replaced
| 35:05018c63a721 | 36:2128c7dc8a40 |
|---|---|
| 1 /* | |
| 2 * Code for one object to chase another | |
| 3 * | |
| 4 * @(#)chase.c 9.0 (rdk) 7/17/84 | |
| 5 * | |
| 6 * Super-Rogue | |
| 7 * Copyright (C) 1984 Robert D. Kindelberger | |
| 8 * All rights reserved. | |
| 9 * | |
| 10 * Based on "Rogue: Exploring the Dungeons of Doom" | |
| 11 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman | |
| 12 * All rights reserved. | |
| 13 * | |
| 14 * See the file LICENSE.TXT for full copyright and licensing information. | |
| 15 */ | |
| 16 | |
| 17 #include "rogue.h" | |
| 18 #include "rogue.ext" | |
| 19 | |
| 20 #define FARAWAY 32767 | |
| 21 #define RDIST(a, b) (DISTANCE((a)->y, (a)->x, (b).y, (b).x)) | |
| 22 | |
| 23 struct coord ch_ret; /* Where chasing takes you */ | |
| 24 | |
| 25 /* | |
| 26 * runners: | |
| 27 * Make all the running monsters move. | |
| 28 */ | |
| 29 runners() | |
| 30 { | |
| 31 reg struct thing *tp; | |
| 32 reg struct linked_list *mon,*nextmon; | |
| 33 | |
| 34 for (mon = mlist; mon != NULL; mon = nextmon) { | |
| 35 tp = THINGPTR(mon); | |
| 36 nextmon = next(mon); | |
| 37 if (off(*tp, ISHELD) && on(*tp, ISRUN)) { | |
| 38 if (tp->t_nomove > 0) | |
| 39 if (--tp->t_nomove > 0) | |
| 40 continue; | |
| 41 if (on(*tp, ISHASTE)) | |
| 42 if (do_chase(mon) == -1) | |
| 43 continue; | |
| 44 if (off(*tp, ISSLOW) || tp->t_turn) | |
| 45 if (do_chase(mon) == -1) | |
| 46 continue; | |
| 47 tp->t_turn ^= TRUE; | |
| 48 } | |
| 49 } | |
| 50 } | |
| 51 | |
| 52 | |
| 53 /* | |
| 54 * do_chase: | |
| 55 * Make one thing chase another. | |
| 56 */ | |
| 57 do_chase(mon) | |
| 58 struct linked_list *mon; | |
| 59 { | |
| 60 reg struct thing *th; | |
| 61 reg struct room *rer, *ree, *rxx; | |
| 62 reg int mindist, i, dist; | |
| 63 struct stats *st; | |
| 64 bool stoprun = FALSE, ondoor = FALSE, link = FALSE; | |
| 65 char runaway, dofight, wound, sch, ch; | |
| 66 struct coord this; | |
| 67 struct trap *trp; | |
| 68 | |
| 69 th = THINGPTR(mon); | |
| 70 wound = th->t_flags & ISWOUND; | |
| 71 if (wound) | |
| 72 mindist = 0; | |
| 73 else | |
| 74 mindist = FARAWAY; | |
| 75 runaway = wound; | |
| 76 dofight = !runaway; | |
| 77 rer = th->t_room; | |
| 78 if (th->t_type == 'V') { | |
| 79 if (rer != NULL && !rf_on(rer, ISDARK)) { | |
| 80 /* | |
| 81 * Vampires can't stand the light | |
| 82 */ | |
| 83 if (cansee(th->t_pos.y, th->t_pos.x)) | |
| 84 msg("The vampire vaporizes into thin air !"); | |
| 85 killed(mon, FALSE); | |
| 86 return(-1); | |
| 87 } | |
| 88 } | |
| 89 ree = roomin(th->t_dest); /* room of chasee */ | |
| 90 this = *th->t_dest; | |
| 91 /* | |
| 92 * If the object of our desire is in a different | |
| 93 * room, then run to the door nearest to our goal. | |
| 94 */ | |
| 95 if (mvinch(th->t_pos.y, th->t_pos.x) == DOOR) | |
| 96 ondoor = TRUE; | |
| 97 rxx = NULL; | |
| 98 if (rer != NULL || ree != NULL) { | |
| 99 /* | |
| 100 * Monster not in room, hero in room. Run to closest door | |
| 101 * in hero's room if not wounded. Run away if wounded. | |
| 102 */ | |
| 103 if (rer == NULL && ree != NULL) { | |
| 104 if (!wound) | |
| 105 rxx = ree; | |
| 106 } | |
| 107 /* | |
| 108 * Monster in a room, hero not in room. If on a door, | |
| 109 * then use closest distance. If not on a door, then | |
| 110 * run to closest door in monsters room. | |
| 111 */ | |
| 112 else if (rer != NULL && ree == NULL) { | |
| 113 if (!ondoor) { | |
| 114 rxx = rer; | |
| 115 if (wound) | |
| 116 runaway = FALSE; | |
| 117 } | |
| 118 } | |
| 119 /* | |
| 120 * Both hero and monster in a DIFFERENT room. Set flag to | |
| 121 * check for links between the monster's and hero's rooms. | |
| 122 * If no links are found, then the closest door in the | |
| 123 * monster's room is used. | |
| 124 */ | |
| 125 else if (rer != ree) { | |
| 126 if (!wound) { | |
| 127 link = TRUE; | |
| 128 if (ondoor) | |
| 129 rxx = ree; /* if on door, run to heros room */ | |
| 130 else | |
| 131 rxx = rer; /* else to nearest door this room */ | |
| 132 } | |
| 133 } | |
| 134 /* | |
| 135 * Both hero and monster in same room. If monster is | |
| 136 * wounded, find the best door to run to. | |
| 137 */ | |
| 138 else if (wound) { | |
| 139 struct coord *ex; | |
| 140 int poss, mdtd, hdtd, ghdtd, nx, gx = 0, best; | |
| 141 | |
| 142 best = ghdtd = -FARAWAY; | |
| 143 for (nx = 0; nx < ree->r_nexits; nx++) { | |
| 144 ex = &ree->r_exit[nx]; | |
| 145 if (mvinch(ex->y, ex->x) == SECRETDOOR) | |
| 146 continue; | |
| 147 gx += 1; | |
| 148 mdtd = abs(th->t_pos.y - ex->y) + abs(th->t_pos.x - ex->x); | |
| 149 hdtd = abs(hero.y - ex->y) + abs(hero.x - ex->x); | |
| 150 poss = hdtd - mdtd; /* possible move */ | |
| 151 if (poss > best) { | |
| 152 best = poss; | |
| 153 this = *ex; | |
| 154 } | |
| 155 else if (poss == best && hdtd > ghdtd) { | |
| 156 ghdtd = hdtd; | |
| 157 best = poss; | |
| 158 this = *ex; | |
| 159 } | |
| 160 } | |
| 161 runaway = FALSE; /* go for target */ | |
| 162 if (best < 1) | |
| 163 dofight = TRUE; /* fight if we must */ | |
| 164 mdtd = (gx <= 1 && best < 1); | |
| 165 if (ondoor || mdtd) { | |
| 166 this = hero; | |
| 167 runaway = TRUE; | |
| 168 if (!mdtd) | |
| 169 dofight = FALSE; | |
| 170 } | |
| 171 } | |
| 172 if (rxx != NULL) { | |
| 173 for (i = 0; i < rxx->r_nexits; i += 1) { | |
| 174 dist = RDIST(th->t_dest, rxx->r_exit[i]); | |
| 175 if (link && rxx->r_ptr[i] == ree) | |
| 176 dist = -1; | |
| 177 if ((!wound && dist < mindist) || | |
| 178 (wound && dist > mindist)) { | |
| 179 this = rxx->r_exit[i]; | |
| 180 mindist = dist; | |
| 181 } | |
| 182 } | |
| 183 } | |
| 184 } | |
| 185 else if (DISTANCE(hero.y, hero.x, th->t_pos.y, th->t_pos.x) <= 3) | |
| 186 dofight = TRUE; | |
| 187 /* | |
| 188 * this now contains what we want to run to this time | |
| 189 * so we run to it. If we hit it we either want to | |
| 190 * fight it or stop running. | |
| 191 */ | |
| 192 if (chase(th, &this, runaway, dofight) == FIGHT) { | |
| 193 return( attack(th) ); | |
| 194 } | |
| 195 else if ((th->t_flags & (ISSTUCK | ISPARA))) | |
| 196 return(0); /* if paralyzed or stuck */ | |
| 197 if ((trp = trap_at(ch_ret.y, ch_ret.x)) != NULL) { | |
| 198 ch = be_trapped(&ch_ret, th); | |
| 199 if (ch == GONER || nlmove) { | |
| 200 if (ch == GONER) | |
| 201 remove_monster(&th->t_pos, mon); | |
| 202 nlmove = FALSE; | |
| 203 return((ch == GONER) ? -1 : 0); | |
| 204 } | |
| 205 } | |
| 206 if (pl_off(ISBLIND)) | |
| 207 mvwaddch(cw,th->t_pos.y,th->t_pos.x,th->t_oldch); | |
| 208 sch = mvwinch(cw, ch_ret.y, ch_ret.x); | |
| 209 if (rer != NULL && rf_on(rer,ISDARK) && sch == FLOOR && | |
| 210 DISTANCE(ch_ret.y,ch_ret.x,th->t_pos.y,th->t_pos.x) < 3 && | |
| 211 pl_off(ISBLIND)) | |
| 212 th->t_oldch = ' '; | |
| 213 else | |
| 214 th->t_oldch = sch; | |
| 215 if (cansee(unc(ch_ret)) && off(*th, ISINVIS)) | |
| 216 mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type); | |
| 217 mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); | |
| 218 mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type); | |
| 219 th->t_oldpos = th->t_pos; | |
| 220 th->t_pos = ch_ret; | |
| 221 th->t_room = roomin(&ch_ret); | |
| 222 i = 5; | |
| 223 if (th->t_flags & ISREGEN) | |
| 224 i = 40; | |
| 225 st = &th->t_stats; | |
| 226 if (rnd(100) < i) { | |
| 227 if (++st->s_hpt > st->s_maxhp) | |
| 228 st->s_hpt = st->s_maxhp; | |
| 229 if (!monhurt(th)) | |
| 230 th->t_flags &= ~ISWOUND; | |
| 231 } | |
| 232 if (stoprun && ce(th->t_pos, *(th->t_dest))) | |
| 233 th->t_flags &= ~ISRUN; | |
| 234 return CHASE; | |
| 235 } | |
| 236 | |
| 237 | |
| 238 /* | |
| 239 * chase: | |
| 240 * Find the spot for the chaser to move closer to the | |
| 241 * chasee. Returns TRUE if we want to keep on chasing | |
| 242 * later FALSE if we reach the goal. | |
| 243 */ | |
| 244 chase(tp, ee, runaway, dofight) | |
| 245 struct thing *tp; | |
| 246 struct coord *ee; | |
| 247 bool runaway, dofight; | |
| 248 { | |
| 249 reg int x, y, ch; | |
| 250 reg int dist, thisdist, closest; | |
| 251 reg struct coord *er = &tp->t_pos; | |
| 252 struct coord try, closecoord; | |
| 253 int numsteps, onscare; | |
| 254 | |
| 255 /* | |
| 256 * If the thing is confused, let it move randomly. | |
| 257 */ | |
| 258 ch = CHASE; | |
| 259 onscare = FALSE; | |
| 260 if (on(*tp, ISHUH)) { | |
| 261 ch_ret = *rndmove(tp); | |
| 262 dist = DISTANCE(hero.y, hero.x, ch_ret.y, ch_ret.x); | |
| 263 if (rnd(1000) < 5) | |
| 264 tp->t_flags &= ~ISHUH; | |
| 265 if (dist == 0) | |
| 266 ch = FIGHT; | |
| 267 } | |
| 268 else { | |
| 269 /* | |
| 270 * Otherwise, find the the best spot to run to | |
| 271 * in order to get to your goal. | |
| 272 */ | |
| 273 numsteps = 0; | |
| 274 if (runaway) | |
| 275 closest = 0; | |
| 276 else | |
| 277 closest = FARAWAY; | |
| 278 ch_ret = *er; | |
| 279 closecoord = tp->t_oldpos; | |
| 280 for (y = er->y - 1; y <= er->y + 1; y += 1) { | |
| 281 for (x = er->x - 1; x <= er->x + 1; x += 1) { | |
| 282 if (!cordok(y, x)) | |
| 283 continue; | |
| 284 try.x = x; | |
| 285 try.y = y; | |
| 286 if (!diag_ok(er, &try)) | |
| 287 continue; | |
| 288 ch = winat(y, x); | |
| 289 if (step_ok(ch)) { | |
| 290 struct trap *trp; | |
| 291 | |
| 292 if (isatrap(ch)) { | |
| 293 trp = trap_at(y, x); | |
| 294 if (trp != NULL && off(*tp, ISHUH)) { | |
| 295 /* | |
| 296 * Dont run over found traps unless | |
| 297 * the hero is standing on it. If confused, | |
| 298 * then he can run into them. | |
| 299 */ | |
| 300 if (trp->tr_flags & ISFOUND) { | |
| 301 if (trp->tr_type == POOL && rnd(100) < 80) | |
| 302 continue; | |
| 303 else if (y != hero.y || x != hero.x) | |
| 304 continue; | |
| 305 } | |
| 306 } | |
| 307 } | |
| 308 /* | |
| 309 * Check for scare monster scrolls. | |
| 310 */ | |
| 311 if (ch == SCROLL) { | |
| 312 struct linked_list *item; | |
| 313 | |
| 314 item = find_obj(y, x); | |
| 315 if (item != NULL) | |
| 316 if ((OBJPTR(item))->o_which == S_SCARE) { | |
| 317 if (ce(hero, try)) | |
| 318 onscare = TRUE; | |
| 319 continue; | |
| 320 } | |
| 321 } | |
| 322 /* | |
| 323 * Vampires will not run into a lit room. | |
| 324 */ | |
| 325 if (tp->t_type == 'V') { | |
| 326 struct room *lr; | |
| 327 | |
| 328 lr = roomin(&try); | |
| 329 if (lr != NULL && !rf_on(lr, ISDARK)) | |
| 330 continue; | |
| 331 } | |
| 332 /* | |
| 333 * This is a valid place to step | |
| 334 */ | |
| 335 if (y == hero.y && x == hero.x) { | |
| 336 if (dofight) { | |
| 337 ch_ret = try; /* if fighting */ | |
| 338 return FIGHT; /* hit hero */ | |
| 339 } | |
| 340 else | |
| 341 continue; | |
| 342 } | |
| 343 thisdist = DISTANCE(y, x, ee->y, ee->x); | |
| 344 if (thisdist <= 0) { | |
| 345 ch_ret = try; /* got here but */ | |
| 346 return CHASE; /* dont fight */ | |
| 347 } | |
| 348 numsteps += 1; | |
| 349 if ((!runaway && thisdist < closest) || | |
| 350 (runaway && thisdist > closest)) { | |
| 351 /* | |
| 352 * dont count the monsters last position as | |
| 353 * the closest spot, unless running away and | |
| 354 * in the same room. | |
| 355 */ | |
| 356 if (!ce(try, tp->t_oldpos) || (runaway | |
| 357 && player.t_room == tp->t_room | |
| 358 && tp->t_room != NULL)) { | |
| 359 closest = thisdist; | |
| 360 closecoord = try; | |
| 361 } | |
| 362 } | |
| 363 } | |
| 364 } | |
| 365 } | |
| 366 /* | |
| 367 * If dead end, then go back from whence you came. | |
| 368 * Otherwise, pick the closest of the remaining spots. | |
| 369 */ | |
| 370 if (numsteps > 0) /* move to best spot */ | |
| 371 ch_ret = closecoord; | |
| 372 else { /* nowhere to go */ | |
| 373 if (DISTANCE(tp->t_pos.y, tp->t_pos.x, hero.y, hero.x) < 2) | |
| 374 if (!onscare) | |
| 375 ch_ret = hero; | |
| 376 } | |
