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