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