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