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