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