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