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