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