Home | History | Annotate | Line # | Download | only in rogue
move.c revision 1.7
      1 /*	$NetBSD: move.c,v 1.7 2006/03/30 04:19:38 jnemeth 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.7 2006/03/30 04:19:38 jnemeth 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 			if (cur_room == NO_ROOM)
    109 				clean_up("one_move_rogue: door to nowhere");
    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)) != NULL) {
    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 void
    179 multiple_move_rogue(dirch)
    180 	short dirch;
    181 {
    182 	short row, col;
    183 	short m;
    184 
    185 	switch(dirch) {
    186 	case '\010':
    187 	case '\012':
    188 	case '\013':
    189 	case '\014':
    190 	case '\031':
    191 	case '\025':
    192 	case '\016':
    193 	case '\002':
    194 		do {
    195 			row = rogue.row;
    196 			col = rogue.col;
    197 			if (((m = one_move_rogue((dirch + 96), 1)) == MOVE_FAILED) ||
    198 				(m == STOPPED_ON_SOMETHING) ||
    199 				interrupted) {
    200 				break;
    201 			}
    202 		} while (!next_to_something(row, col));
    203 		if (	(!interrupted) && passgo && (m == MOVE_FAILED) &&
    204 				(dungeon[rogue.row][rogue.col] & TUNNEL)) {
    205 			turn_passage(dirch + 96, 0);
    206 		}
    207 		break;
    208 	case 'H':
    209 	case 'J':
    210 	case 'K':
    211 	case 'L':
    212 	case 'B':
    213 	case 'Y':
    214 	case 'U':
    215 	case 'N':
    216 		while ((!interrupted) && (one_move_rogue((dirch + 32), 1) == MOVED)) ;
    217 
    218 		if (	(!interrupted) && passgo &&
    219 				(dungeon[rogue.row][rogue.col] & TUNNEL)) {
    220 			turn_passage(dirch + 32, 1);
    221 		}
    222 		break;
    223 	}
    224 }
    225 
    226 boolean
    227 is_passable(row, col)
    228 	int row, col;
    229 {
    230 	if ((row < MIN_ROW) || (row > (DROWS - 2)) || (col < 0) ||
    231 		(col > (DCOLS-1))) {
    232 		return(0);
    233 	}
    234 	if (dungeon[row][col] & HIDDEN) {
    235 		return((dungeon[row][col] & TRAP) ? 1 : 0);
    236 	}
    237 	return(dungeon[row][col] & (FLOOR | TUNNEL | DOOR | STAIRS | TRAP));
    238 }
    239 
    240 boolean
    241 next_to_something(drow, dcol)
    242 	int drow, 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(row1, col1, row2, col2)
    304 	int row1, col1, row2, col2;
    305 {
    306 	if (!is_passable(row2, col2)) {
    307 		return(0);
    308 	}
    309 	if ((row1 != row2) && (col1 != col2)) {
    310 		if ((dungeon[row1][col1] & DOOR) || (dungeon[row2][col2] & DOOR)) {
    311 			return(0);
    312 		}
    313 		if ((!dungeon[row1][col2]) || (!dungeon[row2][col1])) {
    314 			return(0);
    315 		}
    316 	}
    317 	return(1);
    318 }
    319 
    320 void
    321 move_onto()
    322 {
    323 	short ch, d;
    324 	boolean first_miss = 1;
    325 
    326 	while (!is_direction(ch = rgetchar(), &d)) {
    327 		sound_bell();
    328 		if (first_miss) {
    329 			message("direction? ", 0);
    330 			first_miss = 0;
    331 		}
    332 	}
    333 	check_message();
    334 	if (ch != CANCEL) {
    335 		(void) one_move_rogue(ch, 0);
    336 	}
    337 }
    338 
    339 boolean
    340 is_direction(c, d)
    341 	short c;
    342 	short *d;
    343 {
    344 	switch(c) {
    345 	case 'h':
    346 		*d = LEFT;
    347 		break;
    348 	case 'j':
    349 		*d = DOWN;
    350 		break;
    351 	case 'k':
    352 		*d = UPWARD;
    353 		break;
    354 	case 'l':
    355 		*d = RIGHT;
    356 		break;
    357 	case 'b':
    358 		*d = DOWNLEFT;
    359 		break;
    360 	case 'y':
    361 		*d = UPLEFT;
    362 		break;
    363 	case 'u':
    364 		*d = UPRIGHT;
    365 		break;
    366 	case 'n':
    367 		*d = DOWNRIGHT;
    368 		break;
    369 	case CANCEL:
    370 		break;
    371 	default:
    372 		return(0);
    373 	}
    374 	return(1);
    375 }
    376 
    377 boolean
    378 check_hunger(msg_only)
    379 	boolean msg_only;
    380 {
    381 	short i, n;
    382 	boolean fainted = 0;
    383 
    384 	if (rogue.moves_left == HUNGRY) {
    385 		(void) strcpy(hunger_str, "hungry");
    386 		message(hunger_str, 0);
    387 		print_stats(STAT_HUNGER);
    388 	}
    389 	if (rogue.moves_left == WEAK) {
    390 		(void) strcpy(hunger_str, "weak");
    391 		message(hunger_str, 1);
    392 		print_stats(STAT_HUNGER);
    393 	}
    394 	if (rogue.moves_left <= FAINT) {
    395 		if (rogue.moves_left == FAINT) {
    396 			(void) strcpy(hunger_str, "faint");
    397 			message(hunger_str, 1);
    398 			print_stats(STAT_HUNGER);
    399 		}
    400 		n = get_rand(0, (FAINT - rogue.moves_left));
    401 		if (n > 0) {
    402 			fainted = 1;
    403 			if (rand_percent(40)) {
    404 				rogue.moves_left++;
    405 			}
    406 			message("you faint", 1);
    407 			for (i = 0; i < n; i++) {
    408 				if (coin_toss()) {
    409 					mv_mons();
    410 				}
    411 			}
    412 			message(you_can_move_again, 1);
    413 		}
    414 	}
    415 	if (msg_only) {
    416 		return(fainted);
    417 	}
    418 	if (rogue.moves_left <= STARVE) {
    419 		killed_by((object *) 0, STARVATION);
    420 	}
    421 
    422 	switch(e_rings) {
    423 	/*case -2:
    424 		Subtract 0, i.e. do nothing.
    425 		break;*/
    426 	case -1:
    427 		rogue.moves_left -= (rogue.moves_left % 2);
    428 		break;
    429 	case 0:
    430 		rogue.moves_left--;
    431 		break;
    432 	case 1:
    433 		rogue.moves_left--;
    434 		(void) check_hunger(1);
    435 		rogue.moves_left -= (rogue.moves_left % 2);
    436 		break;
    437 	case 2:
    438 		rogue.moves_left--;
    439 		(void) check_hunger(1);
    440 		rogue.moves_left--;
    441 		break;
    442 	}
    443 	return(fainted);
    444 }
    445 
    446 boolean
    447 reg_move()
    448 {
    449 	boolean fainted;
    450 
    451 	if ((rogue.moves_left <= HUNGRY) || (cur_level >= max_level)) {
    452 		fainted = check_hunger(0);
    453 	} else {
    454 		fainted = 0;
    455 	}
    456 
    457 	mv_mons();
    458 
    459 	if (++m_moves >= 120) {
    460 		m_moves = 0;
    461 		wanderer();
    462 	}
    463 	if (halluc) {
    464 		if (!(--halluc)) {
    465 			unhallucinate();
    466 		} else {
    467 			hallucinate();
    468 		}
    469 	}
    470 	if (blind) {
    471 		if (!(--blind)) {
    472 			unblind();
    473 		}
    474 	}
    475 	if (confused) {
    476 		if (!(--confused)) {
    477 			unconfuse();
    478 		}
    479 	}
    480 	if (bear_trap) {
    481 		bear_trap--;
    482 	}
    483 	if (levitate) {
    484 		if (!(--levitate)) {
    485 			message("you float gently to the ground", 1);
    486 			if (dungeon[rogue.row][rogue.col] & TRAP) {
    487 				trap_player(rogue.row, rogue.col);
    488 			}
    489 		}
    490 	}
    491 	if (haste_self) {
    492 		if (!(--haste_self)) {
    493 			message("you feel yourself slowing down", 0);
    494 		}
    495 	}
    496 	heal();
    497 	if (auto_search > 0) {
    498 		search(auto_search, auto_search);
    499 	}
    500 	return(fainted);
    501 }
    502 
    503 void
    504 rest(count)
    505 	int count;
    506 {
    507 	int i;
    508 
    509 	interrupted = 0;
    510 
    511 	for (i = 0; i < count; i++) {
    512 		if (interrupted) {
    513 			break;
    514 		}
    515 		(void) reg_move();
    516 	}
    517 }
    518 
    519 char
    520 gr_dir()
    521 {
    522 	short d;
    523 
    524 	d = get_rand(1, 8);
    525 
    526 	switch(d) {
    527 		case 1:
    528 			d = 'j';
    529 			break;
    530 		case 2:
    531 			d = 'k';
    532 			break;
    533 		case 3:
    534 			d = 'l';
    535 			break;
    536 		case 4:
    537 			d = 'h';
    538 			break;
    539 		case 5:
    540 			d = 'y';
    541 			break;
    542 		case 6:
    543 			d = 'u';
    544 			break;
    545 		case 7:
    546 			d = 'b';
    547 			break;
    548 		case 8:
    549 			d = 'n';
    550 			break;
    551 	}
    552 	return(d);
    553 }
    554 
    555 void
    556 heal()
    557 {
    558 	static short heal_exp = -1, n, c = 0;
    559 	static boolean alt;
    560 
    561 	if (rogue.hp_current == rogue.hp_max) {
    562 		c = 0;
    563 		return;
    564 	}
    565 	if (rogue.exp != heal_exp) {
    566 		heal_exp = rogue.exp;
    567 
    568 		switch(heal_exp) {
    569 		case 1:
    570 			n = 20;
    571 			break;
    572 		case 2:
    573 			n = 18;
    574 			break;
    575 		case 3:
    576 			n = 17;
    577 			break;
    578 		case 4:
    579 			n = 14;
    580 			break;
    581 		case 5:
    582 			n = 13;
    583 			break;
    584 		case 6:
    585 			n = 10;
    586 			break;
    587 		case 7:
    588 			n = 9;
    589 			break;
    590 		case 8:
    591 			n = 8;
    592 			break;
    593 		case 9:
    594 			n = 7;
    595 			break;
    596 		case 10:
    597 			n = 4;
    598 			break;
    599 		case 11:
    600 			n = 3;
    601 			break;
    602 		case 12:
    603 		default:
    604 			n = 2;
    605 		}
    606 	}
    607 	if (++c >= n) {
    608 		c = 0;
    609 		rogue.hp_current++;
    610 		if ((alt = !alt) != 0) {
    611 			rogue.hp_current++;
    612 		}
    613 		if ((rogue.hp_current += regeneration) > rogue.hp_max) {
    614 			rogue.hp_current = rogue.hp_max;
    615 		}
    616 		print_stats(STAT_HP);
    617 	}
    618 }
    619 
    620 boolean
    621 can_turn(nrow, ncol)
    622 	short nrow, ncol;
    623 {
    624 	if ((dungeon[nrow][ncol] & TUNNEL) && is_passable(nrow, ncol)) {
    625 		return(1);
    626 	}
    627 	return(0);
    628 }
    629 
    630 void
    631 turn_passage(dir, fast)
    632 	short dir;
    633 	boolean fast;
    634 {
    635 	short crow = rogue.row, ccol = rogue.col, turns = 0;
    636 	short ndir = 0;
    637 
    638 	if ((dir != 'h') && can_turn(crow, ccol + 1)) {
    639 		turns++;
    640 		ndir = 'l';
    641 	}
    642 	if ((dir != 'l') && can_turn(crow, ccol - 1)) {
    643 		turns++;
    644 		ndir = 'h';
    645 	}
    646 	if ((dir != 'k') && can_turn(crow + 1, ccol)) {
    647 		turns++;
    648 		ndir = 'j';
    649 	}
    650 	if ((dir != 'j') && can_turn(crow - 1, ccol)) {
    651 		turns++;
    652 		ndir = 'k';
    653 	}
    654 	if (turns == 1) {
    655 		multiple_move_rogue(ndir - (fast ? 32 : 96));
    656 	}
    657 }
    658