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