Mercurial > hg > early-roguelike
comparison arogue5/chase.c @ 63:0ed67132cf10
Import Advanced Rogue 5.8 from the Roguelike Restoration Project (r1490)
| author | elwin | 
|---|---|
| date | Thu, 09 Aug 2012 22:58:48 +0000 | 
| parents | |
| children | 56e748983fa8 | 
   comparison
  equal
  deleted
  inserted
  replaced
| 62:0ef99244acb8 | 63:0ed67132cf10 | 
|---|---|
| 1 /* | |
| 2 * Code for one object to chase another | |
| 3 * | |
| 4 * Advanced Rogue | |
| 5 * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T | |
| 6 * All rights reserved. | |
| 7 * | |
| 8 * Based on "Rogue: Exploring the Dungeons of Doom" | |
| 9 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman | |
| 10 * All rights reserved. | |
| 11 * | |
| 12 * See the file LICENSE.TXT for full copyright and licensing information. | |
| 13 */ | |
| 14 | |
| 15 #include <ctype.h> | |
| 16 #include <limits.h> | |
| 17 #include "curses.h" | |
| 18 #include "rogue.h" | |
| 19 #define MAXINT INT_MAX | |
| 20 #define MININT INT_MIN | |
| 21 | |
| 22 coord ch_ret; /* Where chasing takes you */ | |
| 23 | |
| 24 | |
| 25 | |
| 26 | |
| 27 | |
| 28 /* | |
| 29 * Canblink checks if the monster can teleport (blink). If so, it will | |
| 30 * try to blink the monster next to the player. | |
| 31 */ | |
| 32 | |
| 33 bool | |
| 34 can_blink(tp) | |
| 35 register struct thing *tp; | |
| 36 { | |
| 37 register int y, x, index=9; | |
| 38 coord tryp; /* To hold the coordinates for use in diag_ok */ | |
| 39 bool spots[9], found_one=FALSE; | |
| 40 | |
| 41 /* | |
| 42 * First, can the monster even blink? And if so, there is only a 50% | |
| 43 * chance that it will do so. And it won't blink if it is running or | |
| 44 * held. | |
| 45 */ | |
| 46 if (off(*tp, CANBLINK) || (on(*tp, ISHELD)) || | |
| 47 on(*tp, ISFLEE) || | |
| 48 (on(*tp, ISSLOW) && off(*tp, ISHASTE) && !(tp->t_turn)) || | |
| 49 tp->t_no_move || | |
| 50 (rnd(12) < 6)) return(FALSE); | |
| 51 | |
| 52 | |
| 53 /* Initialize the spots as illegal */ | |
| 54 do { | |
| 55 spots[--index] = FALSE; | |
| 56 } while (index > 0); | |
| 57 | |
| 58 /* Find a suitable spot next to the player */ | |
| 59 for (y=hero.y-1; y<hero.y+2; y++) | |
| 60 for (x=hero.x-1; x<hero.x+2; x++, index++) { | |
| 61 /* Make sure x coordinate is in range and that we are | |
| 62 * not at the player's position | |
| 63 */ | |
| 64 if (x<0 || x >= COLS || index == 4) continue; | |
| 65 | |
| 66 /* Is it OK to move there? */ | |
| 67 if (step_ok(y, x, NOMONST, tp) && | |
| 68 (!isatrap(mvwinch(cw, y, x)) || | |
| 69 rnd(10) >= tp->t_stats.s_intel || | |
| 70 on(*tp, ISFLY))) { | |
| 71 /* OK, we can go here. But don't go there if | |
| 72 * monster can't get at player from there | |
| 73 */ | |
| 74 tryp.y = y; | |
| 75 tryp.x = x; | |
| 76 if (diag_ok(&tryp, &hero, tp)) { | |
| 77 spots[index] = TRUE; | |
| 78 found_one = TRUE; | |
| 79 } | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 /* If we found one, go to it */ | |
| 84 if (found_one) { | |
| 85 char rch; /* What's really where the creatures moves to */ | |
| 86 | |
| 87 /* Find a legal spot */ | |
| 88 while (spots[index=rnd(9)] == FALSE) continue; | |
| 89 | |
| 90 /* Get the coordinates */ | |
| 91 y = hero.y + (index/3) - 1; | |
| 92 x = hero.x + (index % 3) - 1; | |
| 93 | |
| 94 /* Move the monster from the old space */ | |
| 95 mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch); | |
| 96 | |
| 97 /* Move it to the new space */ | |
| 98 tp->t_oldch = CCHAR( mvwinch(cw, y, x) ); | |
| 99 | |
| 100 /* Display the creature if our hero can see it */ | |
| 101 if (cansee(y, x) && | |
| 102 off(*tp, ISINWALL) && | |
| 103 !invisible(tp)) | |
| 104 mvwaddch(cw, y, x, tp->t_type); | |
| 105 | |
| 106 /* Fix the monster window */ | |
| 107 mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' '); /* Clear old position */ | |
| 108 mvwaddch(mw, y, x, tp->t_type); | |
| 109 | |
| 110 /* Record the new position */ | |
| 111 tp->t_pos.y = y; | |
| 112 tp->t_pos.x = x; | |
| 113 | |
| 114 /* If the monster is on a trap, trap it */ | |
| 115 rch = CCHAR( mvinch(y, x) ); | |
| 116 if (isatrap(rch)) { | |
| 117 if (cansee(y, x)) tp->t_oldch = rch; | |
| 118 be_trapped(tp, &(tp->t_pos)); | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 return(found_one); | |
| 123 } | |
| 124 | |
| 125 /* | |
| 126 * Can_shoot determines if the monster (er) has a direct line of shot | |
| 127 * at the player (ee). If so, it returns the direction in which to shoot. | |
| 128 */ | |
| 129 | |
| 130 coord * | |
| 131 can_shoot(er, ee) | |
| 132 register coord *er, *ee; | |
| 133 { | |
| 134 static coord shoot_dir; | |
| 135 | |
| 136 /* Make sure we are chasing the player */ | |
| 137 if (!ce((*ee), hero)) return(NULL); | |
| 138 | |
| 139 /* | |
| 140 * They must be in the same room or very close (at door) | |
| 141 */ | |
| 142 if (roomin(er) != roomin(&hero) && DISTANCE(er->y,er->x,ee->y,ee->x) > 1) | |
| 143 return(NULL); | |
| 144 | |
| 145 /* Do we have a straight shot? */ | |
| 146 if (!straight_shot(er->y, er->x, ee->y, ee->x, &shoot_dir)) return(NULL); | |
| 147 else return(&shoot_dir); | |
| 148 } | |
| 149 | |
| 150 /* | |
| 151 * chase: | |
| 152 * Find the spot for the chaser(er) to move closer to the | |
| 153 * chasee(ee). Returns TRUE if we want to keep on chasing later | |
| 154 * FALSE if we reach the goal. | |
| 155 */ | |
| 156 | |
| 157 chase(tp, ee, flee, mdead) | |
| 158 register struct thing *tp; | |
| 159 register coord *ee; | |
| 160 bool flee; /* True if destination (ee) is player and monster is running away | |
| 161 * or the player is in a wall and the monster can't get to it | |
| 162 */ | |
| 163 bool *mdead; | |
| 164 { | |
| 165 int damage, dist, thisdist, monst_dist = MAXINT; | |
| 166 struct linked_list *weapon; | |
| 167 register coord *er = &tp->t_pos; | |
| 168 coord *shoot_dir; | |
| 169 char ch, mch; | |
| 170 bool next_player = FALSE; | |
| 171 | |
| 172 if (mdead != NULL) | |
| 173 *mdead = 0; | |
| 174 | |
| 175 /* | |
| 176 * set the distance from the chas(er) to the chas(ee) here and then | |
| 177 * we won't have to reset it unless the chas(er) moves (instead of shoots) | |
| 178 */ | |
| 179 dist = DISTANCE(er->y, er->x, ee->y, ee->x); | |
| 180 | |
| 181 /* | |
| 182 * If the thing is confused or it can't see the player, | |
| 183 * let it move randomly. | |
| 184 */ | |
| 185 if ((on(*tp, ISHUH) && rnd(10) < 8) || | |
| 186 (on(player, ISINVIS) && off(*tp, CANSEE))) { /* Player is invisible */ | |
| 187 /* | |
| 188 * get a valid random move | |
| 189 */ | |
| 190 ch_ret = *rndmove(tp); | |
| 191 dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x); | |
| 192 /* | |
| 193 * check to see if random move takes creature away from player | |
| 194 * if it does then turn off ISHELD | |
| 195 */ | |
| 196 if (dist > 2) { | |
| 197 if (on(*tp, DIDHOLD)) { | |
| 198 turn_off(*tp, DIDHOLD); | |
| 199 turn_on(*tp, CANHOLD); | |
| 200 if (--hold_count == 0) | |
| 201 turn_off(player, ISHELD); | |
| 202 } | |
| 203 | |
| 204 /* If monster was suffocating, stop it */ | |
| 205 if (on(*tp, DIDSUFFOCATE)) { | |
| 206 turn_off(*tp, DIDSUFFOCATE); | |
| 207 turn_on(*tp, CANSUFFOCATE); | |
| 208 extinguish(suffocate); | |
| 209 } | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 /* If we can breathe, we may do so */ | |
| 214 else if (on(*tp, CANBREATHE) && | |
| 215 (dist < BOLT_LENGTH*BOLT_LENGTH) && | |
| 216 (shoot_dir = can_shoot(er, ee)) && | |
| 217 !on(player, ISINWALL) && | |
| 218 (rnd(100) < 75)) { | |
| 219 register char *breath = NULL; | |
| 220 | |
| 221 damage = tp->t_stats.s_hpt; | |
| 222 /* Will it breathe at random */ | |
| 223 if (on(*tp, CANBRANDOM)) { | |
| 224 /* Turn off random breath */ | |
| 225 turn_off(*tp, CANBRANDOM); | |
| 226 | |
| 227 /* Select type of breath */ | |
| 228 switch (rnd(10)) { | |
| 229 case 0: breath = "acid"; | |
| 230 turn_on(*tp, NOACID); | |
| 231 when 1: breath = "flame"; | |
| 232 turn_on(*tp, NOFIRE); | |
| 233 when 2: breath = "lightning bolt"; | |
| 234 turn_on(*tp, NOBOLT); | |
| 235 when 3: breath = "chlorine gas"; | |
| 236 turn_on(*tp, NOGAS); | |
| 237 when 4: breath = "ice"; | |
| 238 turn_on(*tp, NOCOLD); | |
| 239 when 5: breath = "nerve gas"; | |
| 240 turn_on(*tp, NOPARALYZE); | |
| 241 when 6: breath = "sleeping gas"; | |
| 242 turn_on(*tp, NOSLEEP); | |
| 243 when 7: breath = "slow gas"; | |
| 244 turn_on(*tp, NOSLOW); | |
| 245 when 8: breath = "confusion gas"; | |
| 246 turn_on(*tp, ISCLEAR); | |
| 247 when 9: breath = "fear gas"; | |
| 248 turn_on(*tp, NOFEAR); | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 /* Or can it breathe acid? */ | |
| 253 else if (on(*tp, CANBACID)) { | |
| 254 turn_off(*tp, CANBACID); | |
| 255 breath = "acid"; | |
| 256 } | |
| 257 | |
| 258 /* Or can it breathe fire */ | |
| 259 else if (on(*tp, CANBFIRE)) { | |
| 260 turn_off(*tp, CANBFIRE); | |
| 261 breath = "flame"; | |
| 262 } | |
| 263 | |
| 264 /* Or can it breathe electricity? */ | |
| 265 else if (on(*tp, CANBBOLT)) { | |
| 266 turn_off(*tp, CANBBOLT); | |
| 267 breath = "lightning bolt"; | |
| 268 } | |
| 269 | |
| 270 /* Or can it breathe gas? */ | |
| 271 else if (on(*tp, CANBGAS)) { | |
| 272 turn_off(*tp, CANBGAS); | |
| 273 breath = "chlorine gas"; | |
| 274 } | |
| 275 | |
| 276 /* Or can it breathe ice? */ | |
| 277 else if (on(*tp, CANBICE)) { | |
| 278 turn_off(*tp, CANBICE); | |
| 279 breath = "ice"; | |
| 280 } | |
| 281 | |
| 282 else if (on(*tp, CANBPGAS)) { | |
| 283 turn_off(*tp, CANBPGAS); | |
| 284 breath = "nerve gas"; | |
| 285 } | |
| 286 | |
| 287 /* can it breathe sleeping gas */ | |
| 288 else if (on(*tp, CANBSGAS)) { | |
| 289 turn_off(*tp, CANBSGAS); | |
| 290 breath = "sleeping gas"; | |
| 291 } | |
| 292 | |
| 293 /* can it breathe slow gas */ | |
| 294 else if (on(*tp, CANBSLGAS)) { | |
| 295 turn_off(*tp, CANBSLGAS); | |
| 296 breath = "slow gas"; | |
| 297 } | |
| 298 /* can it breathe confusion gas */ | |
| 299 else if (on(*tp, CANBCGAS)) { | |
| 300 turn_off(*tp, CANBCGAS); | |
| 301 breath = "confusion gas"; | |
| 302 } | |
| 303 /* can it breathe fear gas */ | |
| 304 else { | |
| 305 turn_off(*tp, CANBFGAS); | |
| 306 breath = "fear gas"; | |
| 307 } | |
| 308 | |
| 309 /* Now breathe -- sets "monst_dead" if it kills someone */ | |
| 310 *mdead = shoot_bolt( tp, *er, *shoot_dir, FALSE, | |
| 311 tp->t_index, breath, damage); | |
| 312 | |
| 313 ch_ret = *er; | |
| 314 running = FALSE; | |
| 315 if (*mdead) return(TRUE); | |
| 316 } | |
| 317 | |
| 318 /* We may shoot missiles if we can */ | |
| 319 else if (on(*tp, CANMISSILE) && | |
| 320 (shoot_dir = can_shoot(er, ee)) && | |
| 321 !on(player, ISINWALL) && | |
| 322 (rnd(100) < 75)) { | |
| 323 static struct object missile = | |
| 324 { | |
| 325 MISSILE, {0, 0}, "", 0, "", "0d4 " , NULL, 0, WS_MISSILE, 100, 1 | |
| 326 }; | |
| 327 | |
| 328 sprintf(missile.o_hurldmg, "%dd4", tp->t_stats.s_lvl); | |
| 329 do_motion(&missile, shoot_dir->y, shoot_dir->x, tp); | |
| 330 hit_monster(unc(missile.o_pos), &missile, tp); | |
| 331 turn_off(*tp, CANMISSILE); | |
| 332 ch_ret = *er; | |
| 333 running = FALSE; | |
| 334 } | |
| 335 | |
| 336 /* We may use a sonic blast if we can */ | |
| 337 else if (on(*tp, CANSONIC) && | |
| 338 (dist < BOLT_LENGTH*2) && | |
| 339 (shoot_dir = can_shoot(er, ee)) && | |
| 340 !on(player, ISINWALL) && | |
| 341 (rnd(100) < 50)) { | |
| 342 static struct object blast = | |
| 343 { | |
| 344 MISSILE, {0, 0}, "", 0, "", "150" , NULL, 0, 0, 0, 0 | |
| 345 }; | |
| 346 | |
| 347 turn_off(*tp, CANSONIC); | |
| 348 do_motion(&blast, shoot_dir->y, shoot_dir->x, tp); | |
| 349 damage = 150; | |
| 350 if (save(VS_BREATH, &player, -3)) | |
| 351 damage /= 2; | |
| 352 msg ("The %s's sonic blast hits you", monsters[tp->t_index].m_name); | |
| 353 if ((pstats.s_hpt -= damage) <= 0) | |
| 354 death(tp->t_index); | |
| 355 ch_ret = *er; | |
| 356 running = FALSE; | |
| 357 } | |
| 358 /* | |
| 359 * If we have a special magic item, we might use it. We will restrict | |
| 360 * this options to uniques with relics for now. | |
| 361 */ | |
| 362 else if (on(*tp, ISUNIQUE) && m_use_item(tp, er, ee)) { | |
| 363 ch_ret = *er; | |
| 364 running = FALSE; | |
| 365 } | |
| 366 /* | |
| 367 * If we can shoot or throw something, we might do so. | |
| 368 * If next to player, then 80% prob will fight. | |
| 369 */ | |
| 370 else if(on(*tp, CANSHOOT) && | |
| 371 (shoot_dir = can_shoot(er, ee)) && | |
| 372 !on(player, ISINWALL) && | |
