1 /* 2 * Copyright (c) 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Timothy C. Stoehr. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char sccsid[] = "@(#)move.c 5.3 (Berkeley) 06/01/90"; 13 #endif /* not lint */ 14 15 /* 16 * move.c 17 * 18 * This source herein may be modified and/or distributed by anybody who 19 * so desires, with the following restrictions: 20 * 1.) No portion of this notice shall be removed. 21 * 2.) Credit shall not be taken for the creation of this source. 22 * 3.) This code is not to be traded, sold, or used for personal 23 * gain or profit. 24 * 25 */ 26 27 #include "rogue.h" 28 29 short m_moves = 0; 30 boolean jump = 0; 31 char *you_can_move_again = "you can move again"; 32 33 extern short cur_room, halluc, blind, levitate; 34 extern short cur_level, max_level; 35 extern short bear_trap, haste_self, confused; 36 extern short e_rings, regeneration, auto_search; 37 extern char hunger_str[]; 38 extern boolean being_held, interrupted, r_teleport, passgo; 39 40 one_move_rogue(dirch, pickup) 41 short dirch, pickup; 42 { 43 short row, col; 44 object *obj; 45 char desc[DCOLS]; 46 short n, status, d; 47 48 row = rogue.row; 49 col = rogue.col; 50 51 if (confused) { 52 dirch = gr_dir(); 53 } 54 (void) is_direction(dirch, &d); 55 get_dir_rc(d, &row, &col, 1); 56 57 if (!can_move(rogue.row, rogue.col, row, col)) { 58 return(MOVE_FAILED); 59 } 60 if (being_held || bear_trap) { 61 if (!(dungeon[row][col] & MONSTER)) { 62 if (being_held) { 63 message("you are being held", 1); 64 } else { 65 message("you are still stuck in the bear trap", 0); 66 (void) reg_move(); 67 } 68 return(MOVE_FAILED); 69 } 70 } 71 if (r_teleport) { 72 if (rand_percent(R_TELE_PERCENT)) { 73 tele(); 74 return(STOPPED_ON_SOMETHING); 75 } 76 } 77 if (dungeon[row][col] & MONSTER) { 78 rogue_hit(object_at(&level_monsters, row, col), 0); 79 (void) reg_move(); 80 return(MOVE_FAILED); 81 } 82 if (dungeon[row][col] & DOOR) { 83 if (cur_room == PASSAGE) { 84 cur_room = get_room_number(row, col); 85 light_up_room(cur_room); 86 wake_room(cur_room, 1, row, col); 87 } else { 88 light_passage(row, col); 89 } 90 } else if ((dungeon[rogue.row][rogue.col] & DOOR) && 91 (dungeon[row][col] & TUNNEL)) { 92 light_passage(row, col); 93 wake_room(cur_room, 0, rogue.row, rogue.col); 94 darken_room(cur_room); 95 cur_room = PASSAGE; 96 } else if (dungeon[row][col] & TUNNEL) { 97 light_passage(row, col); 98 } 99 mvaddch(rogue.row, rogue.col, get_dungeon_char(rogue.row, rogue.col)); 100 mvaddch(row, col, rogue.fchar); 101 102 if (!jump) { 103 refresh(); 104 } 105 rogue.row = row; 106 rogue.col = col; 107 if (dungeon[row][col] & OBJECT) { 108 if (levitate && pickup) { 109 return(STOPPED_ON_SOMETHING); 110 } 111 if (pickup && !levitate) { 112 if (obj = pick_up(row, col, &status)) { 113 get_desc(obj, desc); 114 if (obj->what_is == GOLD) { 115 free_object(obj); 116 goto NOT_IN_PACK; 117 } 118 } else if (!status) { 119 goto MVED; 120 } else { 121 goto MOVE_ON; 122 } 123 } else { 124 MOVE_ON: 125 obj = object_at(&level_objects, row, col); 126 (void) strcpy(desc, "moved onto "); 127 get_desc(obj, desc+11); 128 goto NOT_IN_PACK; 129 } 130 n = strlen(desc); 131 desc[n] = '('; 132 desc[n+1] = obj->ichar; 133 desc[n+2] = ')'; 134 desc[n+3] = 0; 135 NOT_IN_PACK: 136 message(desc, 1); 137 (void) reg_move(); 138 return(STOPPED_ON_SOMETHING); 139 } 140 if (dungeon[row][col] & (DOOR | STAIRS | TRAP)) { 141 if ((!levitate) && (dungeon[row][col] & TRAP)) { 142 trap_player(row, col); 143 } 144 (void) reg_move(); 145 return(STOPPED_ON_SOMETHING); 146 } 147 MVED: if (reg_move()) { /* fainted from hunger */ 148 return(STOPPED_ON_SOMETHING); 149 } 150 return((confused ? STOPPED_ON_SOMETHING : MOVED)); 151 } 152 153 multiple_move_rogue(dirch) 154 short dirch; 155 { 156 short row, col; 157 short m; 158 159 switch(dirch) { 160 case '\010': 161 case '\012': 162 case '\013': 163 case '\014': 164 case '\031': 165 case '\025': 166 case '\016': 167 case '\002': 168 do { 169 row = rogue.row; 170 col = rogue.col; 171 if (((m = one_move_rogue((dirch + 96), 1)) == MOVE_FAILED) || 172 (m == STOPPED_ON_SOMETHING) || 173 interrupted) { 174 break; 175 } 176 } while (!next_to_something(row, col)); 177 if ( (!interrupted) && passgo && (m == MOVE_FAILED) && 178 (dungeon[rogue.row][rogue.col] & TUNNEL)) { 179 turn_passage(dirch + 96, 0); 180 } 181 break; 182 case 'H': 183 case 'J': 184 case 'K': 185 case 'L': 186 case 'B': 187 case 'Y': 188 case 'U': 189 case 'N': 190 while ((!interrupted) && (one_move_rogue((dirch + 32), 1) == MOVED)) ; 191 192 if ( (!interrupted) && passgo && 193 (dungeon[rogue.row][rogue.col] & TUNNEL)) { 194 turn_passage(dirch + 32, 1); 195 } 196 break; 197 } 198 } 199 200 is_passable(row, col) 201 register row, col; 202 { 203 if ((row < MIN_ROW) || (row > (DROWS - 2)) || (col < 0) || 204 (col > (DCOLS-1))) { 205 return(0); 206 } 207 if (dungeon[row][col] & HIDDEN) { 208 return((dungeon[row][col] & TRAP) ? 1 : 0); 209 } 210 return(dungeon[row][col] & (FLOOR | TUNNEL | DOOR | STAIRS | TRAP)); 211 } 212 213 next_to_something(drow, dcol) 214 register drow, dcol; 215 { 216 short i, j, i_end, j_end, row, col; 217 short pass_count = 0; 218 unsigned short s; 219 220 if (confused) { 221 return(1); 222 } 223 if (blind) { 224 return(0); 225 } 226 i_end = (rogue.row < (DROWS-2)) ? 1 : 0; 227 j_end = (rogue.col < (DCOLS-1)) ? 1 : 0; 228 229 for (i = ((rogue.row > MIN_ROW) ? -1 : 0); i <= i_end; i++) { 230 for (j = ((rogue.col > 0) ? -1 : 0); j <= j_end; j++) { 231 if ((i == 0) && (j == 0)) { 232 continue; 233 } 234 if (((rogue.row+i) == drow) && ((rogue.col+j) == dcol)) { 235 continue; 236 } 237 row = rogue.row + i; 238 col = rogue.col + j; 239 s = dungeon[row][col]; 240 if (s & HIDDEN) { 241 continue; 242 } 243 /* If the rogue used to be right, up, left, down, or right of 244 * row,col, and now isn't, then don't stop */ 245 if (s & (MONSTER | OBJECT | STAIRS)) { 246 if (((row == drow) || (col == dcol)) && 247 (!((row == rogue.row) || (col == rogue.col)))) { 248 continue; 249 } 250 return(1); 251 } 252 if (s & TRAP) { 253 if (!(s & HIDDEN)) { 254 if (((row == drow) || (col == dcol)) && 255 (!((row == rogue.row) || (col == rogue.col)))) { 256 continue; 257 } 258 return(1); 259 } 260 } 261 if ((((i - j) == 1) || ((i - j) == -1)) && (s & TUNNEL)) { 262 if (++pass_count > 1) { 263 return(1); 264 } 265 } 266 if ((s & DOOR) && ((i == 0) || (j == 0))) { 267 return(1); 268 } 269 } 270 } 271 return(0); 272 } 273 274 can_move(row1, col1, row2, col2) 275 { 276 if (!is_passable(row2, col2)) { 277 return(0); 278 } 279 if ((row1 != row2) && (col1 != col2)) { 280 if ((dungeon[row1][col1] & DOOR) || (dungeon[row2][col2] & DOOR)) { 281 return(0); 282 } 283 if ((!dungeon[row1][col2]) || (!dungeon[row2][col1])) { 284 return(0); 285 } 286 } 287 return(1); 288 } 289 290 move_onto() 291 { 292 short ch, d; 293 boolean first_miss = 1; 294 295 while (!is_direction(ch = rgetchar(), &d)) { 296 sound_bell(); 297 if (first_miss) { 298 message("direction? ", 0); 299 first_miss = 0; 300 } 301 } 302 check_message(); 303 if (ch != CANCEL) { 304 (void) one_move_rogue(ch, 0); 305 } 306 } 307 308 boolean 309 is_direction(c, d) 310 short c; 311 short *d; 312 { 313 switch(c) { 314 case 'h': 315 *d = LEFT; 316 break; 317 case 'j': 318 *d = DOWN; 319 break; 320 case 'k': 321 *d = UPWARD; 322 break; 323 case 'l': 324 *d = RIGHT; 325 break; 326 case 'b': 327 *d = DOWNLEFT; 328 break; 329 case 'y': 330 *d = UPLEFT; 331 break; 332 case 'u': 333 *d = UPRIGHT; 334 break; 335 case 'n': 336 *d = DOWNRIGHT; 337 break; 338 case CANCEL: 339 break; 340 default: 341 return(0); 342 } 343 return(1); 344 } 345 346 boolean 347 check_hunger(msg_only) 348 boolean msg_only; 349 { 350 register short i, n; 351 boolean fainted = 0; 352 353 if (rogue.moves_left == HUNGRY) { 354 (void) strcpy(hunger_str, "hungry"); 355 message(hunger_str, 0); 356 print_stats(STAT_HUNGER); 357 } 358 if (rogue.moves_left == WEAK) { 359 (void) strcpy(hunger_str, "weak"); 360 message(hunger_str, 1); 361 print_stats(STAT_HUNGER); 362 } 363 if (rogue.moves_left <= FAINT) { 364 if (rogue.moves_left == FAINT) { 365 (void) strcpy(hunger_str, "faint"); 366 message(hunger_str, 1); 367 print_stats(STAT_HUNGER); 368 } 369 n = get_rand(0, (FAINT - rogue.moves_left)); 370 if (n > 0) { 371 fainted = 1; 372 if (rand_percent(40)) { 373 rogue.moves_left++; 374 } 375 message("you faint", 1); 376 for (i = 0; i < n; i++) { 377 if (coin_toss()) { 378 mv_mons(); 379 } 380 } 381 message(you_can_move_again, 1); 382 } 383 } 384 if (msg_only) { 385 return(fainted); 386 } 387 if (rogue.moves_left <= STARVE) { 388 killed_by((object *) 0, STARVATION); 389 } 390 391 switch(e_rings) { 392 /*case -2: 393 Subtract 0, i.e. do nothing. 394 break;*/ 395 case -1: 396 rogue.moves_left -= (rogue.moves_left % 2); 397 break; 398 case 0: 399 rogue.moves_left--; 400 break; 401 case 1: 402 rogue.moves_left--; 403 (void) check_hunger(1); 404 rogue.moves_left -= (rogue.moves_left % 2); 405 break; 406 case 2: 407 rogue.moves_left--; 408 (void) check_hunger(1); 409 rogue.moves_left--; 410 break; 411 } 412 return(fainted); 413 } 414 415 boolean 416 reg_move() 417 { 418 boolean fainted; 419 420 if ((rogue.moves_left <= HUNGRY) || (cur_level >= max_level)) { 421 fainted = check_hunger(0); 422 } else { 423 fainted = 0; 424 } 425 426 mv_mons(); 427 428 if (++m_moves >= 120) { 429 m_moves = 0; 430 wanderer(); 431 } 432 if (halluc) { 433 if (!(--halluc)) { 434 unhallucinate(); 435 } else { 436 hallucinate(); 437 } 438 } 439 if (blind) { 440 if (!(--blind)) { 441 unblind(); 442 } 443 } 444 if (confused) { 445 if (!(--confused)) { 446 unconfuse(); 447 } 448 } 449 if (bear_trap) { 450 bear_trap--; 451 } 452 if (levitate) { 453 if (!(--levitate)) { 454 message("you float gently to the ground", 1); 455 if (dungeon[rogue.row][rogue.col] & TRAP) { 456 trap_player(rogue.row, rogue.col); 457 } 458 } 459 } 460 if (haste_self) { 461 if (!(--haste_self)) { 462 message("you feel yourself slowing down", 0); 463 } 464 } 465 heal(); 466 if (auto_search > 0) { 467 search(auto_search, auto_search); 468 } 469 return(fainted); 470 } 471 472 rest(count) 473 { 474 int i; 475 476 interrupted = 0; 477 478 for (i = 0; i < count; i++) { 479 if (interrupted) { 480 break; 481 } 482 (void) reg_move(); 483 } 484 } 485 486 gr_dir() 487 { 488 short d; 489 490 d = get_rand(1, 8); 491 492 switch(d) { 493 case 1: 494 d = 'j'; 495 break; 496 case 2: 497 d = 'k'; 498 break; 499 case 3: 500 d = 'l'; 501 break; 502 case 4: 503 d = 'h'; 504 break; 505 case 5: 506 d = 'y'; 507 break; 508 case 6: 509 d = 'u'; 510 break; 511 case 7: 512 d = 'b'; 513 break; 514 case 8: 515 d = 'n'; 516 break; 517 } 518 return(d); 519 } 520 521 heal() 522 { 523 static short heal_exp = -1, n, c = 0; 524 static boolean alt; 525 526 if (rogue.hp_current == rogue.hp_max) { 527 c = 0; 528 return; 529 } 530 if (rogue.exp != heal_exp) { 531 heal_exp = rogue.exp; 532 533 switch(heal_exp) { 534 case 1: 535 n = 20; 536 break; 537 case 2: 538 n = 18; 539 break; 540 case 3: 541 n = 17; 542 break; 543 case 4: 544 n = 14; 545 break; 546 case 5: 547 n = 13; 548 break; 549 case 6: 550 n = 10; 551 break; 552 case 7: 553 n = 9; 554 break; 555 case 8: 556 n = 8; 557 break; 558 case 9: 559 n = 7; 560 break; 561 case 10: 562 n = 4; 563 break; 564 case 11: 565 n = 3; 566 break; 567 case 12: 568 default: 569 n = 2; 570 } 571 } 572 if (++c >= n) { 573 c = 0; 574 rogue.hp_current++; 575 if (alt = !alt) { 576 rogue.hp_current++; 577 } 578 if ((rogue.hp_current += regeneration) > rogue.hp_max) { 579 rogue.hp_current = rogue.hp_max; 580 } 581 print_stats(STAT_HP); 582 } 583 } 584 585 static boolean 586 can_turn(nrow, ncol) 587 short nrow, ncol; 588 { 589 if ((dungeon[nrow][ncol] & TUNNEL) && is_passable(nrow, ncol)) { 590 return(1); 591 } 592 return(0); 593 } 594 595 turn_passage(dir, fast) 596 short dir; 597 boolean fast; 598 { 599 short crow = rogue.row, ccol = rogue.col, turns = 0; 600 short ndir; 601 602 if ((dir != 'h') && can_turn(crow, ccol + 1)) { 603 turns++; 604 ndir = 'l'; 605 } 606 if ((dir != 'l') && can_turn(crow, ccol - 1)) { 607 turns++; 608 ndir = 'h'; 609 } 610 if ((dir != 'k') && can_turn(crow + 1, ccol)) { 611 turns++; 612 ndir = 'j'; 613 } 614 if ((dir != 'j') && can_turn(crow - 1, ccol)) { 615 turns++; 616 ndir = 'k'; 617 } 618 if (turns == 1) { 619 multiple_move_rogue(ndir - (fast ? 32 : 96)); 620 } 621 } 622