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