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