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