xref: /csrg-svn/games/rogue/move.c (revision 36704)
132689Sbostic /*
2*36704Sbostic  * Copyright (c) 1988 The Regents of the University of California.
3*36704Sbostic  * All rights reserved.
4*36704Sbostic  *
5*36704Sbostic  * This code is derived from software contributed to Berkeley by
6*36704Sbostic  * Timothy C. Stoehr.
7*36704Sbostic  *
8*36704Sbostic  * Redistribution and use in source and binary forms are permitted
9*36704Sbostic  * provided that the above copyright notice and this paragraph are
10*36704Sbostic  * duplicated in all such forms and that any documentation,
11*36704Sbostic  * advertising materials, and other materials related to such
12*36704Sbostic  * distribution and use acknowledge that the software was developed
13*36704Sbostic  * by the University of California, Berkeley.  The name of the
14*36704Sbostic  * University may not be used to endorse or promote products derived
15*36704Sbostic  * from this software without specific prior written permission.
16*36704Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17*36704Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18*36704Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19*36704Sbostic  */
20*36704Sbostic 
21*36704Sbostic #ifndef lint
22*36704Sbostic static char sccsid[] = "@(#)move.c	5.2 (Berkeley) 02/07/89";
23*36704Sbostic #endif /* not lint */
24*36704Sbostic 
25*36704Sbostic /*
2632689Sbostic  * move.c
2732689Sbostic  *
2832689Sbostic  * This source herein may be modified and/or distributed by anybody who
2932689Sbostic  * so desires, with the following restrictions:
3032689Sbostic  *    1.)  No portion of this notice shall be removed.
3132689Sbostic  *    2.)  Credit shall not be taken for the creation of this source.
3232689Sbostic  *    3.)  This code is not to be traded, sold, or used for personal
3332689Sbostic  *         gain or profit.
3432689Sbostic  *
3532689Sbostic  */
3632689Sbostic 
3732689Sbostic #include "rogue.h"
3832689Sbostic 
3932689Sbostic short m_moves = 0;
4032689Sbostic boolean jump = 0;
4132689Sbostic char *you_can_move_again = "you can move again";
4232689Sbostic 
4332689Sbostic extern short cur_room, halluc, blind, levitate;
4432689Sbostic extern short cur_level, max_level;
4532689Sbostic extern short bear_trap, haste_self, confused;
4632689Sbostic extern short e_rings, regeneration, auto_search;
4732689Sbostic extern char hunger_str[];
4832689Sbostic extern boolean being_held, interrupted, r_teleport, passgo;
4932689Sbostic 
5032689Sbostic one_move_rogue(dirch, pickup)
5132689Sbostic short dirch, pickup;
5232689Sbostic {
5332689Sbostic 	short row, col;
5432689Sbostic 	object *obj;
5532689Sbostic 	char desc[DCOLS];
5632689Sbostic 	short n, status, d;
5732689Sbostic 
5832689Sbostic 	row = rogue.row;
5932689Sbostic 	col = rogue.col;
6032689Sbostic 
6132689Sbostic 	if (confused) {
6232689Sbostic 		dirch = gr_dir();
6332689Sbostic 	}
6432689Sbostic 	(void) is_direction(dirch, &d);
6532689Sbostic 	get_dir_rc(d, &row, &col, 1);
6632689Sbostic 
6732689Sbostic 	if (!can_move(rogue.row, rogue.col, row, col)) {
6832689Sbostic 		return(MOVE_FAILED);
6932689Sbostic 	}
7032689Sbostic 	if (being_held || bear_trap) {
7132689Sbostic 		if (!(dungeon[row][col] & MONSTER)) {
7232689Sbostic 			if (being_held) {
7332689Sbostic 				message("you are being held", 1);
7432689Sbostic 			} else {
7532689Sbostic 				message("you are still stuck in the bear trap", 0);
7632689Sbostic 				(void) reg_move();
7732689Sbostic 			}
7832689Sbostic 			return(MOVE_FAILED);
7932689Sbostic 		}
8032689Sbostic 	}
8132689Sbostic 	if (r_teleport) {
8232689Sbostic 		if (rand_percent(R_TELE_PERCENT)) {
8332689Sbostic 			tele();
8432689Sbostic 			return(STOPPED_ON_SOMETHING);
8532689Sbostic 		}
8632689Sbostic 	}
8732689Sbostic 	if (dungeon[row][col] & MONSTER) {
8832689Sbostic 		rogue_hit(object_at(&level_monsters, row, col), 0);
8932689Sbostic 		(void) reg_move();
9032689Sbostic 		return(MOVE_FAILED);
9132689Sbostic 	}
9232689Sbostic 	if (dungeon[row][col] & DOOR) {
9332689Sbostic 		if (cur_room == PASSAGE) {
9432689Sbostic 			cur_room = get_room_number(row, col);
9532689Sbostic 			light_up_room(cur_room);
9632689Sbostic 			wake_room(cur_room, 1, row, col);
9732689Sbostic 		} else {
9832689Sbostic 			light_passage(row, col);
9932689Sbostic 		}
10032689Sbostic 	} else if ((dungeon[rogue.row][rogue.col] & DOOR) &&
10132689Sbostic 		   (dungeon[row][col] & TUNNEL)) {
10232689Sbostic 		light_passage(row, col);
10332689Sbostic 		wake_room(cur_room, 0, rogue.row, rogue.col);
10432689Sbostic 		darken_room(cur_room);
10532689Sbostic 		cur_room = PASSAGE;
10632689Sbostic 	} else if (dungeon[row][col] & TUNNEL) {
10732689Sbostic 			light_passage(row, col);
10832689Sbostic 	}
10932689Sbostic 	mvaddch(rogue.row, rogue.col, get_dungeon_char(rogue.row, rogue.col));
11032689Sbostic 	mvaddch(row, col, rogue.fchar);
11132689Sbostic 
11232689Sbostic 	if (!jump) {
11332689Sbostic 		refresh();
11432689Sbostic 	}
11532689Sbostic 	rogue.row = row;
11632689Sbostic 	rogue.col = col;
11732689Sbostic 	if (dungeon[row][col] & OBJECT) {
11832689Sbostic 		if (levitate && pickup) {
11932689Sbostic 			return(STOPPED_ON_SOMETHING);
12032689Sbostic 		}
12132689Sbostic 		if (pickup && !levitate) {
12232689Sbostic 			if (obj = pick_up(row, col, &status)) {
12332689Sbostic 				get_desc(obj, desc);
12432689Sbostic 				if (obj->what_is == GOLD) {
12532689Sbostic 					free_object(obj);
12632689Sbostic 					goto NOT_IN_PACK;
12732689Sbostic 				}
12832689Sbostic 			} else if (!status) {
12932689Sbostic 				goto MVED;
13032689Sbostic 			} else {
13132689Sbostic 				goto MOVE_ON;
13232689Sbostic 			}
13332689Sbostic 		} else {
13432689Sbostic MOVE_ON:
13532689Sbostic 			obj = object_at(&level_objects, row, col);
13632689Sbostic 			(void) strcpy(desc, "moved onto ");
13732689Sbostic 			get_desc(obj, desc+11);
13832689Sbostic 			goto NOT_IN_PACK;
13932689Sbostic 		}
14032689Sbostic 		n = strlen(desc);
14132689Sbostic 		desc[n] = '(';
14232689Sbostic 		desc[n+1] = obj->ichar;
14332689Sbostic 		desc[n+2] = ')';
14432689Sbostic 		desc[n+3] = 0;
14532689Sbostic NOT_IN_PACK:
14632689Sbostic 		message(desc, 1);
14732689Sbostic 		(void) reg_move();
14832689Sbostic 		return(STOPPED_ON_SOMETHING);
14932689Sbostic 	}
15032689Sbostic 	if (dungeon[row][col] & (DOOR | STAIRS | TRAP)) {
15132689Sbostic 		if ((!levitate) && (dungeon[row][col] & TRAP)) {
15232689Sbostic 			trap_player(row, col);
15332689Sbostic 		}
15432689Sbostic 		(void) reg_move();
15532689Sbostic 		return(STOPPED_ON_SOMETHING);
15632689Sbostic 	}
15732689Sbostic MVED:	if (reg_move()) {			/* fainted from hunger */
15832689Sbostic 			return(STOPPED_ON_SOMETHING);
15932689Sbostic 	}
16032689Sbostic 	return((confused ? STOPPED_ON_SOMETHING : MOVED));
16132689Sbostic }
16232689Sbostic 
16332689Sbostic multiple_move_rogue(dirch)
16432689Sbostic short dirch;
16532689Sbostic {
16632689Sbostic 	short row, col;
16732689Sbostic 	short m;
16832689Sbostic 
16932689Sbostic 	switch(dirch) {
17032689Sbostic 	case '\010':
17132689Sbostic 	case '\012':
17232689Sbostic 	case '\013':
17332689Sbostic 	case '\014':
17432689Sbostic 	case '\031':
17532689Sbostic 	case '\025':
17632689Sbostic 	case '\016':
17732689Sbostic 	case '\002':
17832689Sbostic 		do {
17932689Sbostic 			row = rogue.row;
18032689Sbostic 			col = rogue.col;
18132689Sbostic 			if (((m = one_move_rogue((dirch + 96), 1)) == MOVE_FAILED) ||
18232689Sbostic 				(m == STOPPED_ON_SOMETHING) ||
18332689Sbostic 				interrupted) {
18432689Sbostic 				break;
18532689Sbostic 			}
18632689Sbostic 		} while (!next_to_something(row, col));
18732689Sbostic 		if (	(!interrupted) && passgo && (m == MOVE_FAILED) &&
18832689Sbostic 				(dungeon[rogue.row][rogue.col] & TUNNEL)) {
18932689Sbostic 			turn_passage(dirch + 96, 0);
19032689Sbostic 		}
19132689Sbostic 		break;
19232689Sbostic 	case 'H':
19332689Sbostic 	case 'J':
19432689Sbostic 	case 'K':
19532689Sbostic 	case 'L':
19632689Sbostic 	case 'B':
19732689Sbostic 	case 'Y':
19832689Sbostic 	case 'U':
19932689Sbostic 	case 'N':
20032689Sbostic 		while ((!interrupted) && (one_move_rogue((dirch + 32), 1) == MOVED)) ;
20132689Sbostic 
20232689Sbostic 		if (	(!interrupted) && passgo &&
20332689Sbostic 				(dungeon[rogue.row][rogue.col] & TUNNEL)) {
20432689Sbostic 			turn_passage(dirch + 32, 1);
20532689Sbostic 		}
20632689Sbostic 		break;
20732689Sbostic 	}
20832689Sbostic }
20932689Sbostic 
21032689Sbostic is_passable(row, col)
21132689Sbostic register row, col;
21232689Sbostic {
21332689Sbostic 	if ((row < MIN_ROW) || (row > (DROWS - 2)) || (col < 0) ||
21432689Sbostic 		(col > (DCOLS-1))) {
21532689Sbostic 		return(0);
21632689Sbostic 	}
21732689Sbostic 	if (dungeon[row][col] & HIDDEN) {
21832689Sbostic 		return((dungeon[row][col] & TRAP) ? 1 : 0);
21932689Sbostic 	}
22032689Sbostic 	return(dungeon[row][col] & (FLOOR | TUNNEL | DOOR | STAIRS | TRAP));
22132689Sbostic }
22232689Sbostic 
22332689Sbostic next_to_something(drow, dcol)
22432689Sbostic register drow, dcol;
22532689Sbostic {
22632689Sbostic 	short i, j, i_end, j_end, row, col;
22732689Sbostic 	short pass_count = 0;
22832689Sbostic 	unsigned short s;
22932689Sbostic 
23032689Sbostic 	if (confused) {
23132689Sbostic 		return(1);
23232689Sbostic 	}
23332689Sbostic 	if (blind) {
23432689Sbostic 		return(0);
23532689Sbostic 	}
23632689Sbostic 	i_end = (rogue.row < (DROWS-2)) ? 1 : 0;
23732689Sbostic 	j_end = (rogue.col < (DCOLS-1)) ? 1 : 0;
23832689Sbostic 
23932689Sbostic 	for (i = ((rogue.row > MIN_ROW) ? -1 : 0); i <= i_end; i++) {
24032689Sbostic 		for (j = ((rogue.col > 0) ? -1 : 0); j <= j_end; j++) {
24132689Sbostic 			if ((i == 0) && (j == 0)) {
24232689Sbostic 				continue;
24332689Sbostic 			}
24432689Sbostic 			if (((rogue.row+i) == drow) && ((rogue.col+j) == dcol)) {
24532689Sbostic 				continue;
24632689Sbostic 			}
24732689Sbostic 			row = rogue.row + i;
24832689Sbostic 			col = rogue.col + j;
24932689Sbostic 			s = dungeon[row][col];
25032689Sbostic 			if (s & HIDDEN) {
25132689Sbostic 				continue;
25232689Sbostic 			}
25332689Sbostic 			/* If the rogue used to be right, up, left, down, or right of
25432689Sbostic 			 * row,col, and now isn't, then don't stop */
25532689Sbostic 			if (s & (MONSTER | OBJECT | STAIRS)) {
25632689Sbostic 				if (((row == drow) || (col == dcol)) &&
25732689Sbostic 					(!((row == rogue.row) || (col == rogue.col)))) {
25832689Sbostic 					continue;
25932689Sbostic 				}
26032689Sbostic 				return(1);
26132689Sbostic 			}
26232689Sbostic 			if (s & TRAP) {
26332689Sbostic 				if (!(s & HIDDEN)) {
26432689Sbostic 					if (((row == drow) || (col == dcol)) &&
26532689Sbostic 						(!((row == rogue.row) || (col == rogue.col)))) {
26632689Sbostic 						continue;
26732689Sbostic 					}
26832689Sbostic 					return(1);
26932689Sbostic 				}
27032689Sbostic 			}
27132689Sbostic 			if ((((i - j) == 1) || ((i - j) == -1)) && (s & TUNNEL)) {
27232689Sbostic 				if (++pass_count > 1) {
27332689Sbostic 					return(1);
27432689Sbostic 				}
27532689Sbostic 			}
27632689Sbostic 			if ((s & DOOR) && ((i == 0) || (j == 0))) {
27732689Sbostic 					return(1);
27832689Sbostic 			}
27932689Sbostic 		}
28032689Sbostic 	}
28132689Sbostic 	return(0);
28232689Sbostic }
28332689Sbostic 
28432689Sbostic can_move(row1, col1, row2, col2)
28532689Sbostic {
28632689Sbostic 	if (!is_passable(row2, col2)) {
28732689Sbostic 		return(0);
28832689Sbostic 	}
28932689Sbostic 	if ((row1 != row2) && (col1 != col2)) {
29032689Sbostic 		if ((dungeon[row1][col1] & DOOR) || (dungeon[row2][col2] & DOOR)) {
29132689Sbostic 			return(0);
29232689Sbostic 		}
29332689Sbostic 		if ((!dungeon[row1][col2]) || (!dungeon[row2][col1])) {
29432689Sbostic 			return(0);
29532689Sbostic 		}
29632689Sbostic 	}
29732689Sbostic 	return(1);
29832689Sbostic }
29932689Sbostic 
30032689Sbostic move_onto()
30132689Sbostic {
30232689Sbostic 	short ch, d;
30332689Sbostic 	boolean first_miss = 1;
30432689Sbostic 
30532689Sbostic 	while (!is_direction(ch = rgetchar(), &d)) {
30632689Sbostic 		sound_bell();
30732689Sbostic 		if (first_miss) {
30832689Sbostic 			message("direction? ", 0);
30932689Sbostic 			first_miss = 0;
31032689Sbostic 		}
31132689Sbostic 	}
31232689Sbostic 	check_message();
31332689Sbostic 	if (ch != CANCEL) {
31432689Sbostic 		(void) one_move_rogue(ch, 0);
31532689Sbostic 	}
31632689Sbostic }
31732689Sbostic 
31832689Sbostic boolean
31932689Sbostic is_direction(c, d)
32032689Sbostic short c;
32132689Sbostic short *d;
32232689Sbostic {
32332689Sbostic 	switch(c) {
32432689Sbostic 	case 'h':
32532689Sbostic 		*d = LEFT;
32632689Sbostic 		break;
32732689Sbostic 	case 'j':
32832689Sbostic 		*d = DOWN;
32932689Sbostic 		break;
33032689Sbostic 	case 'k':
33132689Sbostic 		*d = UPWARD;
33232689Sbostic 		break;
33332689Sbostic 	case 'l':
33432689Sbostic 		*d = RIGHT;
33532689Sbostic 		break;
33632689Sbostic 	case 'b':
33732689Sbostic 		*d = DOWNLEFT;
33832689Sbostic 		break;
33932689Sbostic 	case 'y':
34032689Sbostic 		*d = UPLEFT;
34132689Sbostic 		break;
34232689Sbostic 	case 'u':
34332689Sbostic 		*d = UPRIGHT;
34432689Sbostic 		break;
34532689Sbostic 	case 'n':
34632689Sbostic 		*d = DOWNRIGHT;
34732689Sbostic 		break;
34832689Sbostic 	case CANCEL:
34932689Sbostic 		break;
35032689Sbostic 	default:
35132689Sbostic 		return(0);
35232689Sbostic 	}
35332689Sbostic 	return(1);
35432689Sbostic }
35532689Sbostic 
35632689Sbostic boolean
35732689Sbostic check_hunger(msg_only)
35832689Sbostic boolean msg_only;
35932689Sbostic {
36032689Sbostic 	register short i, n;
36132689Sbostic 	boolean fainted = 0;
36232689Sbostic 
36332689Sbostic 	if (rogue.moves_left == HUNGRY) {
36432689Sbostic 		(void) strcpy(hunger_str, "hungry");
36532689Sbostic 		message(hunger_str, 0);
36632689Sbostic 		print_stats(STAT_HUNGER);
36732689Sbostic 	}
36832689Sbostic 	if (rogue.moves_left == WEAK) {
36932689Sbostic 		(void) strcpy(hunger_str, "weak");
37032689Sbostic 		message(hunger_str, 1);
37132689Sbostic 		print_stats(STAT_HUNGER);
37232689Sbostic 	}
37332689Sbostic 	if (rogue.moves_left <= FAINT) {
37432689Sbostic 		if (rogue.moves_left == FAINT) {
37532689Sbostic 			(void) strcpy(hunger_str, "faint");
37632689Sbostic 			message(hunger_str, 1);
37732689Sbostic 			print_stats(STAT_HUNGER);
37832689Sbostic 		}
37932689Sbostic 		n = get_rand(0, (FAINT - rogue.moves_left));
38032689Sbostic 		if (n > 0) {
38132689Sbostic 			fainted = 1;
38232689Sbostic 			if (rand_percent(40)) {
38332689Sbostic 				rogue.moves_left++;
38432689Sbostic 			}
38532689Sbostic 			message("you faint", 1);
38632689Sbostic 			for (i = 0; i < n; i++) {
38732689Sbostic 				if (coin_toss()) {
38832689Sbostic 					mv_mons();
38932689Sbostic 				}
39032689Sbostic 			}
39132689Sbostic 			message(you_can_move_again, 1);
39232689Sbostic 		}
39332689Sbostic 	}
39432689Sbostic 	if (msg_only) {
39532689Sbostic 		return(fainted);
39632689Sbostic 	}
39732689Sbostic 	if (rogue.moves_left <= STARVE) {
39832689Sbostic 		killed_by((object *) 0, STARVATION);
39932689Sbostic 	}
40032689Sbostic 
40132689Sbostic 	switch(e_rings) {
40232689Sbostic 	/*case -2:
40332689Sbostic 		Subtract 0, i.e. do nothing.
40432689Sbostic 		break;*/
40532689Sbostic 	case -1:
40632689Sbostic 		rogue.moves_left -= (rogue.moves_left % 2);
40732689Sbostic 		break;
40832689Sbostic 	case 0:
40932689Sbostic 		rogue.moves_left--;
41032689Sbostic 		break;
41132689Sbostic 	case 1:
41232689Sbostic 		rogue.moves_left--;
41332689Sbostic 		(void) check_hunger(1);
41432689Sbostic 		rogue.moves_left -= (rogue.moves_left % 2);
41532689Sbostic 		break;
41632689Sbostic 	case 2:
41732689Sbostic 		rogue.moves_left--;
41832689Sbostic 		(void) check_hunger(1);
41932689Sbostic 		rogue.moves_left--;
42032689Sbostic 		break;
42132689Sbostic 	}
42232689Sbostic 	return(fainted);
42332689Sbostic }
42432689Sbostic 
42532689Sbostic boolean
42632689Sbostic reg_move()
42732689Sbostic {
42832689Sbostic 	boolean fainted;
42932689Sbostic 
43032689Sbostic 	if ((rogue.moves_left <= HUNGRY) || (cur_level >= max_level)) {
43132689Sbostic 		fainted = check_hunger(0);
43232689Sbostic 	} else {
43332689Sbostic 		fainted = 0;
43432689Sbostic 	}
43532689Sbostic 
43632689Sbostic 	mv_mons();
43732689Sbostic 
43832689Sbostic 	if (++m_moves >= 120) {
43932689Sbostic 		m_moves = 0;
44032689Sbostic 		wanderer();
44132689Sbostic 	}
44232689Sbostic 	if (halluc) {
44332689Sbostic 		if (!(--halluc)) {
44432689Sbostic 			unhallucinate();
44532689Sbostic 		} else {
44632689Sbostic 			hallucinate();
44732689Sbostic 		}
44832689Sbostic 	}
44932689Sbostic 	if (blind) {
45032689Sbostic 		if (!(--blind)) {
45132689Sbostic 			unblind();
45232689Sbostic 		}
45332689Sbostic 	}
45432689Sbostic 	if (confused) {
45532689Sbostic 		if (!(--confused)) {
45632689Sbostic 			unconfuse();
45732689Sbostic 		}
45832689Sbostic 	}
45932689Sbostic 	if (bear_trap) {
46032689Sbostic 		bear_trap--;
46132689Sbostic 	}
46232689Sbostic 	if (levitate) {
46332689Sbostic 		if (!(--levitate)) {
46432689Sbostic 			message("you float gently to the ground", 1);
46532689Sbostic 			if (dungeon[rogue.row][rogue.col] & TRAP) {
46632689Sbostic 				trap_player(rogue.row, rogue.col);
46732689Sbostic 			}
46832689Sbostic 		}
46932689Sbostic 	}
47032689Sbostic 	if (haste_self) {
47132689Sbostic 		if (!(--haste_self)) {
47232689Sbostic 			message("you feel yourself slowing down", 0);
47332689Sbostic 		}
47432689Sbostic 	}
47532689Sbostic 	heal();
47632689Sbostic 	if (auto_search > 0) {
47732689Sbostic 		search(auto_search, auto_search);
47832689Sbostic 	}
47932689Sbostic 	return(fainted);
48032689Sbostic }
48132689Sbostic 
48232689Sbostic rest(count)
48332689Sbostic {
48432689Sbostic 	int i;
48532689Sbostic 
48632689Sbostic 	interrupted = 0;
48732689Sbostic 
48832689Sbostic 	for (i = 0; i < count; i++) {
48932689Sbostic 		if (interrupted) {
49032689Sbostic 			break;
49132689Sbostic 		}
49232689Sbostic 		(void) reg_move();
49332689Sbostic 	}
49432689Sbostic }
49532689Sbostic 
49632689Sbostic gr_dir()
49732689Sbostic {
49832689Sbostic 	short d;
49932689Sbostic 
50032689Sbostic 	d = get_rand(1, 8);
50132689Sbostic 
50232689Sbostic 	switch(d) {
50332689Sbostic 		case 1:
50432689Sbostic 			d = 'j';
50532689Sbostic 			break;
50632689Sbostic 		case 2:
50732689Sbostic 			d = 'k';
50832689Sbostic 			break;
50932689Sbostic 		case 3:
51032689Sbostic 			d = 'l';
51132689Sbostic 			break;
51232689Sbostic 		case 4:
51332689Sbostic 			d = 'h';
51432689Sbostic 			break;
51532689Sbostic 		case 5:
51632689Sbostic 			d = 'y';
51732689Sbostic 			break;
51832689Sbostic 		case 6:
51932689Sbostic 			d = 'u';
52032689Sbostic 			break;
52132689Sbostic 		case 7:
52232689Sbostic 			d = 'b';
52332689Sbostic 			break;
52432689Sbostic 		case 8:
52532689Sbostic 			d = 'n';
52632689Sbostic 			break;
52732689Sbostic 	}
52832689Sbostic 	return(d);
52932689Sbostic }
53032689Sbostic 
53132689Sbostic heal()
53232689Sbostic {
53332689Sbostic 	static short heal_exp = -1, n, c = 0;
53432689Sbostic 	static boolean alt;
53532689Sbostic 
53632689Sbostic 	if (rogue.hp_current == rogue.hp_max) {
53732689Sbostic 		c = 0;
53832689Sbostic 		return;
53932689Sbostic 	}
54032689Sbostic 	if (rogue.exp != heal_exp) {
54132689Sbostic 		heal_exp = rogue.exp;
54232689Sbostic 
54332689Sbostic 		switch(heal_exp) {
54432689Sbostic 		case 1:
54532689Sbostic 			n = 20;
54632689Sbostic 			break;
54732689Sbostic 		case 2:
54832689Sbostic 			n = 18;
54932689Sbostic 			break;
55032689Sbostic 		case 3:
55132689Sbostic 			n = 17;
55232689Sbostic 			break;
55332689Sbostic 		case 4:
55432689Sbostic 			n = 14;
55532689Sbostic 			break;
55632689Sbostic 		case 5:
55732689Sbostic 			n = 13;
55832689Sbostic 			break;
55932689Sbostic 		case 6:
56032689Sbostic 			n = 10;
56132689Sbostic 			break;
56232689Sbostic 		case 7:
56332689Sbostic 			n = 9;
56432689Sbostic 			break;
56532689Sbostic 		case 8:
56632689Sbostic 			n = 8;
56732689Sbostic 			break;
56832689Sbostic 		case 9:
56932689Sbostic 			n = 7;
57032689Sbostic 			break;
57132689Sbostic 		case 10:
57232689Sbostic 			n = 4;
57332689Sbostic 			break;
57432689Sbostic 		case 11:
57532689Sbostic 			n = 3;
57632689Sbostic 			break;
57732689Sbostic 		case 12:
57832689Sbostic 		default:
57932689Sbostic 			n = 2;
58032689Sbostic 		}
58132689Sbostic 	}
58232689Sbostic 	if (++c >= n) {
58332689Sbostic 		c = 0;
58432689Sbostic 		rogue.hp_current++;
58532689Sbostic 		if (alt = !alt) {
58632689Sbostic 			rogue.hp_current++;
58732689Sbostic 		}
58832689Sbostic 		if ((rogue.hp_current += regeneration) > rogue.hp_max) {
58932689Sbostic 			rogue.hp_current = rogue.hp_max;
59032689Sbostic 		}
59132689Sbostic 		print_stats(STAT_HP);
59232689Sbostic 	}
59332689Sbostic }
59432689Sbostic 
59532689Sbostic static boolean
59632689Sbostic can_turn(nrow, ncol)
59732689Sbostic short nrow, ncol;
59832689Sbostic {
59932689Sbostic 	if ((dungeon[nrow][ncol] & TUNNEL) && is_passable(nrow, ncol)) {
60032689Sbostic 		return(1);
60132689Sbostic 	}
60232689Sbostic 	return(0);
60332689Sbostic }
60432689Sbostic 
60532689Sbostic turn_passage(dir, fast)
60632689Sbostic short dir;
60732689Sbostic boolean fast;
60832689Sbostic {
60932689Sbostic 	short crow = rogue.row, ccol = rogue.col, turns = 0;
61032689Sbostic 	short ndir;
61132689Sbostic 
61232689Sbostic 	if ((dir != 'h') && can_turn(crow, ccol + 1)) {
61332689Sbostic 		turns++;
61432689Sbostic 		ndir = 'l';
61532689Sbostic 	}
61632689Sbostic 	if ((dir != 'l') && can_turn(crow, ccol - 1)) {
61732689Sbostic 		turns++;
61832689Sbostic 		ndir = 'h';
61932689Sbostic 	}
62032689Sbostic 	if ((dir != 'k') && can_turn(crow + 1, ccol)) {
62132689Sbostic 		turns++;
62232689Sbostic 		ndir = 'j';
62332689Sbostic 	}
62432689Sbostic 	if ((dir != 'j') && can_turn(crow - 1, ccol)) {
62532689Sbostic 		turns++;
62632689Sbostic 		ndir = 'k';
62732689Sbostic 	}
62832689Sbostic 	if (turns == 1) {
62932689Sbostic 		multiple_move_rogue(ndir - (fast ? 32 : 96));
63032689Sbostic 	}
63132689Sbostic }
632