xref: /dragonfly/games/rogue/level.c (revision 984263bc)
1 /*
2  * Copyright (c) 1988, 1993
3  *	The Regents of the University of California.  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 #if 0
39 static char sccsid[] = "@(#)level.c	8.1 (Berkeley) 5/31/93";
40 #endif
41 static const char rcsid[] =
42  "$FreeBSD: src/games/rogue/level.c,v 1.3 1999/11/30 03:49:23 billf Exp $";
43 #endif /* not lint */
44 
45 /*
46  * level.c
47  *
48  * This source herein may be modified and/or distributed by anybody who
49  * so desires, with the following restrictions:
50  *    1.)  No portion of this notice shall be removed.
51  *    2.)  Credit shall not be taken for the creation of this source.
52  *    3.)  This code is not to be traded, sold, or used for personal
53  *         gain or profit.
54  *
55  */
56 
57 #include "rogue.h"
58 
59 #define swap(x,y) {t = x; x = y; y = t;}
60 
61 short cur_level = 0;
62 short max_level = 1;
63 short cur_room;
64 const char *new_level_message = 0;
65 short party_room = NO_ROOM;
66 short r_de;
67 
68 const long level_points[MAX_EXP_LEVEL] = {
69 		  10L,
70 		  20L,
71 		  40L,
72 		  80L,
73 		 160L,
74 		 320L,
75 		 640L,
76 		1300L,
77 		2600L,
78 		5200L,
79 	   10000L,
80 	   20000L,
81 	   40000L,
82 	   80000L,
83 	  160000L,
84 	  320000L,
85 	 1000000L,
86 	 3333333L,
87 	 6666666L,
88 	  MAX_EXP,
89 	99900000L
90 };
91 
92 short random_rooms[MAXROOMS] = {3, 7, 5, 2, 0, 6, 1, 4, 8};
93 
94 extern boolean being_held, wizard, detect_monster;
95 extern boolean see_invisible;
96 extern short bear_trap, levitate, extra_hp, less_hp, cur_room;
97 
98 make_level()
99 {
100 	short i, j;
101 	short must_1, must_2, must_3;
102 	boolean big_room;
103 
104 	if (cur_level < LAST_DUNGEON) {
105 		cur_level++;
106 	}
107 	if (cur_level > max_level) {
108 		max_level = cur_level;
109 	}
110 	must_1 = get_rand(0, 5);
111 
112 	switch(must_1) {
113 	case 0:
114 		must_1 = 0;
115 		must_2 = 1;
116 		must_3 = 2;
117 		break;
118 	case 1:
119 		must_1 = 3;
120 		must_2 = 4;
121 		must_3 = 5;
122 		break;
123 	case 2:
124 		must_1 = 6;
125 		must_2 = 7;
126 		must_3 = 8;
127 		break;
128 	case 3:
129 		must_1 = 0;
130 		must_2 = 3;
131 		must_3 = 6;
132 		break;
133 	case 4:
134 		must_1 = 1;
135 		must_2 = 4;
136 		must_3 = 7;
137 		break;
138 	case 5:
139 		must_1 = 2;
140 		must_2 = 5;
141 		must_3 = 8;
142 		break;
143 	}
144 	if (rand_percent(8)) {
145 		party_room = 0;
146 	}
147 	big_room = ((party_room != NO_ROOM) && rand_percent(1));
148 	if (big_room) {
149 		make_room(BIG_ROOM, 0, 0, 0);
150 	} else {
151 		for (i = 0; i < MAXROOMS; i++) {
152 			make_room(i, must_1, must_2, must_3);
153 		}
154 	}
155 	if (!big_room) {
156 		add_mazes();
157 
158 		mix_random_rooms();
159 
160 		for (j = 0; j < MAXROOMS; j++) {
161 
162 			i = random_rooms[j];
163 
164 			if (i < (MAXROOMS-1)) {
165 				(void) connect_rooms(i, i+1);
166 			}
167 			if (i < (MAXROOMS-3)) {
168 				(void) connect_rooms(i, i+3);
169 			}
170 			if (i < (MAXROOMS-2)) {
171 				if (rooms[i+1].is_room & R_NOTHING) {
172 					if (connect_rooms(i, i+2)) {
173 						rooms[i+1].is_room = R_CROSS;
174 					}
175 				}
176 			}
177 			if (i < (MAXROOMS-6)) {
178 				if (rooms[i+3].is_room & R_NOTHING) {
179 					if (connect_rooms(i, i+6)) {
180 						rooms[i+3].is_room = R_CROSS;
181 					}
182 				}
183 			}
184 			if (is_all_connected()) {
185 				break;
186 			}
187 		}
188 		fill_out_level();
189 	}
190 	if (!has_amulet() && (cur_level >= AMULET_LEVEL)) {
191 		put_amulet();
192 	}
193 }
194 
195 make_room(rn, r1, r2, r3)
196 short rn, r1, r2, r3;
197 {
198 	short left_col, right_col, top_row, bottom_row;
199 	short width, height;
200 	short row_offset, col_offset;
201 	short i, j, ch;
202 
203 	switch(rn) {
204 	case 0:
205 		left_col = 0;
206 		right_col = COL1-1;
207 		top_row = MIN_ROW;
208 		bottom_row = ROW1-1;
209 		break;
210 	case 1:
211 		left_col = COL1+1;
212 		right_col = COL2-1;
213 		top_row = MIN_ROW;
214 		bottom_row = ROW1-1;
215 		break;
216 	case 2:
217 		left_col = COL2+1;
218 		right_col = DCOLS-1;
219 		top_row = MIN_ROW;
220 		bottom_row = ROW1-1;
221 		break;
222 	case 3:
223 		left_col = 0;
224 		right_col = COL1-1;
225 		top_row = ROW1+1;
226 		bottom_row = ROW2-1;
227 		break;
228 	case 4:
229 		left_col = COL1+1;
230 		right_col = COL2-1;
231 		top_row = ROW1+1;
232 		bottom_row = ROW2-1;
233 		break;
234 	case 5:
235 		left_col = COL2+1;
236 		right_col = DCOLS-1;
237 		top_row = ROW1+1;
238 		bottom_row = ROW2-1;
239 		break;
240 	case 6:
241 		left_col = 0;
242 		right_col = COL1-1;
243 		top_row = ROW2+1;
244 		bottom_row = DROWS - 2;
245 		break;
246 	case 7:
247 		left_col = COL1+1;
248 		right_col = COL2-1;
249 		top_row = ROW2+1;
250 		bottom_row = DROWS - 2;
251 		break;
252 	case 8:
253 		left_col = COL2+1;
254 		right_col = DCOLS-1;
255 		top_row = ROW2+1;
256 		bottom_row = DROWS - 2;
257 		break;
258 	case BIG_ROOM:
259 		top_row = get_rand(MIN_ROW, MIN_ROW+5);
260 		bottom_row = get_rand(DROWS-7, DROWS-2);
261 		left_col = get_rand(0, 10);;
262 		right_col = get_rand(DCOLS-11, DCOLS-1);
263 		rn = 0;
264 		goto B;
265 	}
266 	height = get_rand(4, (bottom_row - top_row + 1));
267 	width = get_rand(7, (right_col - left_col - 2));
268 
269 	row_offset = get_rand(0, ((bottom_row - top_row) - height + 1));
270 	col_offset = get_rand(0, ((right_col - left_col) - width + 1));
271 
272 	top_row += row_offset;
273 	bottom_row = top_row + height - 1;
274 
275 	left_col += col_offset;
276 	right_col = left_col + width - 1;
277 
278 	if ((rn != r1) && (rn != r2) && (rn != r3) && rand_percent(40)) {
279 		goto END;
280 	}
281 B:
282 	rooms[rn].is_room = R_ROOM;
283 
284 	for (i = top_row; i <= bottom_row; i++) {
285 		for (j = left_col; j <= right_col; j++) {
286 			if ((i == top_row) || (i == bottom_row)) {
287 				ch = HORWALL;
288 			} else if (	((i != top_row) && (i != bottom_row)) &&
289 						((j == left_col) || (j == right_col))) {
290 				ch = VERTWALL;
291 			} else {
292 				ch = FLOOR;
293 			}
294 			dungeon[i][j] = ch;
295 		}
296 	}
297 END:
298 	rooms[rn].top_row = top_row;
299 	rooms[rn].bottom_row = bottom_row;
300 	rooms[rn].left_col = left_col;
301 	rooms[rn].right_col = right_col;
302 }
303 
304 connect_rooms(room1, room2)
305 short room1, room2;
306 {
307 	short row1, col1, row2, col2, dir;
308 
309 	if ((!(rooms[room1].is_room & (R_ROOM | R_MAZE))) ||
310 		(!(rooms[room2].is_room & (R_ROOM | R_MAZE)))) {
311 		return(0);
312 	}
313 	if (same_row(room1, room2) &&
314 		(rooms[room1].left_col > rooms[room2].right_col)) {
315 		put_door(&rooms[room1], LEFT, &row1, &col1);
316 		put_door(&rooms[room2], RIGHT, &row2, &col2);
317 		dir = LEFT;
318 	} else if (same_row(room1, room2) &&
319 		(rooms[room2].left_col > rooms[room1].right_col)) {
320 		put_door(&rooms[room1], RIGHT, &row1, &col1);
321 		put_door(&rooms[room2], LEFT, &row2, &col2);
322 		dir = RIGHT;
323 	} else if (same_col(room1, room2) &&
324 		(rooms[room1].top_row > rooms[room2].bottom_row)) {
325 		put_door(&rooms[room1], UPWARD, &row1, &col1);
326 		put_door(&rooms[room2], DOWN, &row2, &col2);
327 		dir = UPWARD;
328 	} else if (same_col(room1, room2) &&
329 		(rooms[room2].top_row > rooms[room1].bottom_row)) {
330 		put_door(&rooms[room1], DOWN, &row1, &col1);
331 		put_door(&rooms[room2], UPWARD, &row2, &col2);
332 		dir = DOWN;
333 	} else {
334 		return(0);
335 	}
336 
337 	do {
338 		draw_simple_passage(row1, col1, row2, col2, dir);
339 	} while (rand_percent(4));
340 
341 	rooms[room1].doors[dir/2].oth_room = room2;
342 	rooms[room1].doors[dir/2].oth_row = row2;
343 	rooms[room1].doors[dir/2].oth_col = col2;
344 
345 	rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_room = room1;
346 	rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_row = row1;
347 	rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_col = col1;
348 	return(1);
349 }
350 
351 clear_level()
352 {
353 	short i, j;
354 
355 	for (i = 0; i < MAXROOMS; i++) {
356 		rooms[i].is_room = R_NOTHING;
357 		for (j = 0; j < 4; j++) {
358 			rooms[i].doors[j].oth_room = NO_ROOM;
359 		}
360 	}
361 
362 	for (i = 0; i < MAX_TRAPS; i++) {
363 		traps[i].trap_type = NO_TRAP;
364 	}
365 	for (i = 0; i < DROWS; i++) {
366 		for (j = 0; j < DCOLS; j++) {
367 			dungeon[i][j] = NOTHING;
368 		}
369 	}
370 	detect_monster = see_invisible = 0;
371 	being_held = bear_trap = 0;
372 	party_room = NO_ROOM;
373 	rogue.row = rogue.col = -1;
374 	clear();
375 }
376 
377 put_door(rm, dir, row, col)
378 room *rm;
379 short dir;
380 short *row, *col;
381 {
382 	short wall_width;
383 
384 	wall_width = (rm->is_room & R_MAZE) ? 0 : 1;
385 
386 	switch(dir) {
387 	case UPWARD:
388 	case DOWN:
389 		*row = ((dir == UPWARD) ? rm->top_row : rm->bottom_row);
390 		do {
391 			*col = get_rand(rm->left_col+wall_width,
392 				rm->right_col-wall_width);
393 		} while (!(dungeon[*row][*col] & (HORWALL | TUNNEL)));
394 		break;
395 	case RIGHT:
396 	case LEFT:
397 		*col = (dir == LEFT) ? rm->left_col : rm->right_col;
398 		do {
399 			*row = get_rand(rm->top_row+wall_width,
400 				rm->bottom_row-wall_width);
401 		} while (!(dungeon[*row][*col] & (VERTWALL | TUNNEL)));
402 		break;
403 	}
404 	if (rm->is_room & R_ROOM) {
405 		dungeon[*row][*col] = DOOR;
406 	}
407 	if ((cur_level > 2) && rand_percent(HIDE_PERCENT)) {
408 		dungeon[*row][*col] |= HIDDEN;
409 	}
410 	rm->doors[dir/2].door_row = *row;
411 	rm->doors[dir/2].door_col = *col;
412 }
413 
414 draw_simple_passage(row1, col1, row2, col2, dir)
415 short row1, col1, row2, col2, dir;
416 {
417 	short i, middle, t;
418 
419 	if ((dir == LEFT) || (dir == RIGHT)) {
420 		if (col1 > col2) {
421 			swap(row1, row2);
422 			swap(col1, col2);
423 		}
424 		middle = get_rand(col1+1, col2-1);
425 		for (i = col1+1; i != middle; i++) {
426 			dungeon[row1][i] = TUNNEL;
427 		}
428 		for (i = row1; i != row2; i += (row1 > row2) ? -1 : 1) {
429 			dungeon[i][middle] = TUNNEL;
430 		}
431 		for (i = middle; i != col2; i++) {
432 			dungeon[row2][i] = TUNNEL;
433 		}
434 	} else {
435 		if (row1 > row2) {
436 			swap(row1, row2);
437 			swap(col1, col2);
438 		}
439 		middle = get_rand(row1+1, row2-1);
440 		for (i = row1+1; i != middle; i++) {
441 			dungeon[i][col1] = TUNNEL;
442 		}
443 		for (i = col1; i != col2; i += (col1 > col2) ? -1 : 1) {
444 			dungeon[middle][i] = TUNNEL;
445 		}
446 		for (i = middle; i != row2; i++) {
447 			dungeon[i][col2] = TUNNEL;
448 		}
449 	}
450 	if (rand_percent(HIDE_PERCENT)) {
451 		hide_boxed_passage(row1, col1, row2, col2, 1);
452 	}
453 }
454 
455 same_row(room1, room2)
456 {
457 	return((room1 / 3) == (room2 / 3));
458 }
459 
460 same_col(room1, room2)
461 {
462 	return((room1 % 3) == (room2 % 3));
463 }
464 
465 add_mazes()
466 {
467 	short i, j;
468 	short start;
469 	short maze_percent;
470 
471 	if (cur_level > 1) {
472 		start = get_rand(0, (MAXROOMS-1));
473 		maze_percent = (cur_level * 5) / 4;
474 
475 		if (cur_level > 15) {
476 			maze_percent += cur_level;
477 		}
478 		for (i = 0; i < MAXROOMS; i++) {
479 			j = ((start + i) % MAXROOMS);
480 			if (rooms[j].is_room & R_NOTHING) {
481 				if (rand_percent(maze_percent)) {
482 				rooms[j].is_room = R_MAZE;
483 				make_maze(get_rand(rooms[j].top_row+1, rooms[j].bottom_row-1),
484 					get_rand(rooms[j].left_col+1, rooms[j].right_col-1),
485 					rooms[j].top_row, rooms[j].bottom_row,
486 					rooms[j].left_col, rooms[j].right_col);
487 				hide_boxed_passage(rooms[j].top_row, rooms[j].left_col,
488 					rooms[j].bottom_row, rooms[j].right_col,
489 					get_rand(0, 2));
490 				}
491 			}
492 		}
493 	}
494 }
495 
496 fill_out_level()
497 {
498 	short i, rn;
499 
500 	mix_random_rooms();
501 
502 	r_de = NO_ROOM;
503 
504 	for (i = 0; i < MAXROOMS; i++) {
505 		rn = random_rooms[i];
506 		if ((rooms[rn].is_room & R_NOTHING) ||
507 			((rooms[rn].is_room & R_CROSS) && coin_toss())) {
508 			fill_it(rn, 1);
509 		}
510 	}
511 	if (r_de != NO_ROOM) {
512 		fill_it(r_de, 0);
513 	}
514 }
515 
516 fill_it(rn, do_rec_de)
517 int rn;
518 boolean do_rec_de;
519 {
520 	short i, tunnel_dir, door_dir, drow, dcol;
521 	short target_room, rooms_found = 0;
522 	short srow, scol, t;
523 	static short offsets[4] = {-1, 1, 3, -3};
524 	boolean did_this = 0;
525 
526 	for (i = 0; i < 10; i++) {
527 		srow = get_rand(0, 3);
528 		scol = get_rand(0, 3);
529 		t = offsets[srow];
530 		offsets[srow] = offsets[scol];
531 		offsets[scol] = t;
532 	}
533 	for (i = 0; i < 4; i++) {
534 
535 		target_room = rn + offsets[i];
536 
537 		if (((target_room < 0) || (target_room >= MAXROOMS)) ||
538 			(!(same_row(rn,target_room) || same_col(rn,target_room))) ||
539 			(!(rooms[target_room].is_room & (R_ROOM | R_MAZE)))) {
540 			continue;
541 		}
542 		if (same_row(rn, target_room)) {
543 			tunnel_dir = (rooms[rn].left_col < rooms[target_room].left_col) ?
544 				RIGHT : LEFT;
545 		} else {
546 			tunnel_dir = (rooms[rn].top_row < rooms[target_room].top_row) ?
547 				DOWN : UPWARD;
548 		}
549 		door_dir = ((tunnel_dir + 4) % DIRS);
550 		if (rooms[target_room].doors[door_dir/2].oth_room != NO_ROOM) {
551 			continue;
552 		}
553 		if (((!do_rec_de) || did_this) ||
554 			(!mask_room(rn, &srow, &scol, TUNNEL))) {
555 			srow = (rooms[rn].top_row + rooms[rn].bottom_row) / 2;
556 			scol = (rooms[rn].left_col + rooms[rn].right_col) / 2;
557 		}
558 		put_door(&rooms[target_room], door_dir, &drow, &dcol);
559 		rooms_found++;
560 		draw_simple_passage(srow, scol, drow, dcol, tunnel_dir);
561 		rooms[rn].is_room = R_DEADEND;
562 		dungeon[srow][scol] = TUNNEL;
563 
564 		if ((i < 3) && (!did_this)) {
565 			did_this = 1;
566 			if (coin_toss()) {
567 				continue;
568 			}
569 		}
570 		if ((rooms_found < 2) && do_rec_de) {
571 			recursive_deadend(rn, offsets, srow, scol);
572 		}
573 		break;
574 	}
575 }
576 
577 recursive_deadend(rn, offsets, srow, scol)
578 short rn;
579 const short *offsets;
580 short srow, scol;
581 {
582 	short i, de;
583 	short drow, dcol, tunnel_dir;
584 
585 	rooms[rn].is_room = R_DEADEND;
586 	dungeon[srow][scol] = TUNNEL;
587 
588 	for (i = 0; i < 4; i++) {
589 		de = rn + offsets[i];
590 		if (((de < 0) || (de >= MAXROOMS)) ||
591 			(!(same_row(rn, de) || same_col(rn, de)))) {
592 			continue;
593 		}
594 		if (!(rooms[de].is_room & R_NOTHING)) {
595 			continue;
596 		}
597 		drow = (rooms[de].top_row + rooms[de].bottom_row) / 2;
598 		dcol = (rooms[de].left_col + rooms[de].right_col) / 2;
599 		if (same_row(rn, de)) {
600 			tunnel_dir = (rooms[rn].left_col < rooms[de].left_col) ?
601 				RIGHT : LEFT;
602 		} else {
603 			tunnel_dir = (rooms[rn].top_row < rooms[de].top_row) ?
604 				DOWN : UPWARD;
605 		}
606 		draw_simple_passage(srow, scol, drow, dcol, tunnel_dir);
607 		r_de = de;
608 		recursive_deadend(de, offsets, drow, dcol);
609 	}
610 }
611 
612 boolean
613 mask_room(rn, row, col, mask)
614 short rn;
615 short *row, *col;
616 unsigned short mask;
617 {
618 	short i, j;
619 
620 	for (i = rooms[rn].top_row; i <= rooms[rn].bottom_row; i++) {
621 		for (j = rooms[rn].left_col; j <= rooms[rn].right_col; j++) {
622 			if (dungeon[i][j] & mask) {
623 				*row = i;
624 				*col = j;
625 				return(1);
626 			}
627 		}
628 	}
629 	return(0);
630 }
631 
632 make_maze(r, c, tr, br, lc, rc)
633 short r, c, tr, br, lc, rc;
634 {
635 	char dirs[4];
636 	short i, t;
637 
638 	dirs[0] = UPWARD;
639 	dirs[1] = DOWN;
640 	dirs[2] = LEFT;
641 	dirs[3] = RIGHT;
642 
643 	dungeon[r][c] = TUNNEL;
644 
645 	if (rand_percent(20)) {
646 		for (i = 0; i < 10; i++) {
647 			short t1, t2;
648 
649 			t1 = get_rand(0, 3);
650 			t2 = get_rand(0, 3);
651 
652 			swap(dirs[t1], dirs[t2]);
653 		}
654 	}
655 	for (i = 0; i < 4; i++) {
656 		switch(dirs[i]) {
657 		case UPWARD:
658 			if (((r-1) >= tr) &&
659 				(dungeon[r-1][c] != TUNNEL) &&
660 				(dungeon[r-1][c-1] != TUNNEL) &&
661 				(dungeon[r-1][c+1] != TUNNEL) &&
662 				(dungeon[r-2][c] != TUNNEL)) {
663 				make_maze((r-1), c, tr, br, lc, rc);
664 			}
665 			break;
666 		case DOWN:
667 			if (((r+1) <= br) &&
668 				(dungeon[r+1][c] != TUNNEL) &&
669 				(dungeon[r+1][c-1] != TUNNEL) &&
670 				(dungeon[r+1][c+1] != TUNNEL) &&
671 				(dungeon[r+2][c] != TUNNEL)) {
672 				make_maze((r+1), c, tr, br, lc, rc);
673 			}
674 			break;
675 		case LEFT:
676 			if (((c-1) >= lc) &&
677 				(dungeon[r][c-1] != TUNNEL) &&
678 				(dungeon[r-1][c-1] != TUNNEL) &&
679 				(dungeon[r+1][c-1] != TUNNEL) &&
680 				(dungeon[r][c-2] != TUNNEL)) {
681 				make_maze(r, (c-1), tr, br, lc, rc);
682 			}
683 			break;
684 		case RIGHT:
685 			if (((c+1) <= rc) &&
686 				(dungeon[r][c+1] != TUNNEL) &&
687 				(dungeon[r-1][c+1] != TUNNEL) &&
688 				(dungeon[r+1][c+1] != TUNNEL) &&
689 				(dungeon[r][c+2] != TUNNEL)) {
690 				make_maze(r, (c+1), tr, br, lc, rc);
691 			}
692 			break;
693 		}
694 	}
695 }
696 
697 hide_boxed_passage(row1, col1, row2, col2, n)
698 short row1, col1, row2, col2, n;
699 {
700 	short i, j, t;
701 	short row, col, row_cut, col_cut;
702 	short h, w;
703 
704 	if (cur_level > 2) {
705 		if (row1 > row2) {
706 			swap(row1, row2);
707 		}
708 		if (col1 > col2) {
709 			swap(col1, col2);
710 		}
711 		h = row2 - row1;
712 		w = col2 - col1;
713 
714 		if ((w >= 5) || (h >= 5)) {
715 			row_cut = ((h >= 2) ? 1 : 0);
716 			col_cut = ((w >= 2) ? 1 : 0);
717 
718 			for (i = 0; i < n; i++) {
719 				for (j = 0; j < 10; j++) {
720 					row = get_rand(row1 + row_cut, row2 - row_cut);
721 					col = get_rand(col1 + col_cut, col2 - col_cut);
722 					if (dungeon[row][col] == TUNNEL) {
723 						dungeon[row][col] |= HIDDEN;
724 						break;
725 					}
726 				}
727 			}
728 		}
729 	}
730 }
731 
732 put_player(nr)
733 short nr;		/* try not to put in this room */
734 {
735 	short rn = nr, misses;
736 	short row, col;
737 
738 	for (misses = 0; ((misses < 2) && (rn == nr)); misses++) {
739 		gr_row_col(&row, &col, (FLOOR | TUNNEL | OBJECT | STAIRS));
740 		rn = get_room_number(row, col);
741 	}
742 	rogue.row = row;
743 	rogue.col = col;
744 
745 	if (dungeon[rogue.row][rogue.col] & TUNNEL) {
746 		cur_room = PASSAGE;
747 	} else {
748 		cur_room = rn;
749 	}
750 	if (cur_room != PASSAGE) {
751 		light_up_room(cur_room);
752 	} else {
753 		light_passage(rogue.row, rogue.col);
754 	}
755 	rn = get_room_number(rogue.row, rogue.col);
756 	wake_room(rn, 1, rogue.row, rogue.col);
757 	if (new_level_message) {
758 		message(new_level_message, 0);
759 		new_level_message = 0;
760 	}
761 	mvaddch(rogue.row, rogue.col, rogue.fchar);
762 }
763 
764 drop_check()
765 {
766 	if (wizard) {
767 		return(1);
768 	}
769 	if (dungeon[rogue.row][rogue.col] & STAIRS) {
770 		if (levitate) {
771 			message("you're floating in the air!", 0);
772 			return(0);
773 		}
774 		return(1);
775 	}
776 	message("I see no way down", 0);
777 	return(0);
778 }
779 
780 check_up()
781 {
782 	if (!wizard) {
783 		if (!(dungeon[rogue.row][rogue.col] & STAIRS)) {
784 			message("I see no way up", 0);
785 			return(0);
786 		}
787 		if (!has_amulet()) {
788 			message("your way is magically blocked", 0);
789 			return(0);
790 		}
791 	}
792 	new_level_message = "you feel a wrenching sensation in your gut";
793 	if (cur_level == 1) {
794 		win();
795 	} else {
796 		cur_level -= 2;
797 		return(1);
798 	}
799 	return(0);
800 }
801 
802 add_exp(e, promotion)
803 int e;
804 boolean promotion;
805 {
806 	char mbuf[40];
807 	short new_exp;
808 	short i, hp;
809 
810 	rogue.exp_points += e;
811 
812 	if (rogue.exp_points >= level_points[rogue.exp-1]) {
813 		new_exp = get_exp_level(rogue.exp_points);
814 		if (rogue.exp_points > MAX_EXP) {
815 			rogue.exp_points = MAX_EXP + 1;
816 		}
817 		for (i = rogue.exp+1; i <= new_exp; i++) {
818 			sprintf(mbuf, "welcome to level %d", i);
819 			message(mbuf, 0);
820 			if (promotion) {
821 				hp = hp_raise();
822 				rogue.hp_current += hp;
823 				rogue.hp_max += hp;
824 			}
825 			rogue.exp = i;
826 			print_stats(STAT_HP | STAT_EXP);
827 		}
828 	} else {
829 		print_stats(STAT_EXP);
830 	}
831 }
832 
833 get_exp_level(e)
834 long e;
835 {
836 	short i;
837 
838 	for (i = 0; i < (MAX_EXP_LEVEL - 1); i++) {
839 		if (level_points[i] > e) {
840 			break;
841 		}
842 	}
843 	return(i+1);
844 }
845 
846 hp_raise()
847 {
848 	int hp;
849 
850 	hp = (wizard ? 10 : get_rand(3, 10));
851 	return(hp);
852 }
853 
854 show_average_hp()
855 {
856 	char mbuf[80];
857 	float real_average;
858 	float effective_average;
859 
860 	if (rogue.exp == 1) {
861 		real_average = effective_average = 0.00;
862 	} else {
863 		real_average = (float)
864 			((rogue.hp_max - extra_hp - INIT_HP) + less_hp) / (rogue.exp - 1);
865 		effective_average = (float) (rogue.hp_max - INIT_HP) / (rogue.exp - 1);
866 
867 	}
868 	sprintf(mbuf, "R-Hp: %.2f, E-Hp: %.2f (!: %d, V: %d)", real_average,
869 		effective_average, extra_hp, less_hp);
870 	message(mbuf, 0);
871 }
872 
873 mix_random_rooms()
874 {
875 	short i, t;
876 	short x, y;
877 
878 	for (i = 0; i < (3 * MAXROOMS); i++) {
879 		do {
880 			x = get_rand(0, (MAXROOMS-1));
881 			y = get_rand(0, (MAXROOMS-1));
882 		} while (x == y);
883 		swap(random_rooms[x], random_rooms[y]);
884 	}
885 }
886