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