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