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