Home | History | Annotate | Line # | Download | only in rogue
level.c revision 1.6
      1 /*	$NetBSD: level.c,v 1.6 2003/01/20 05:29:55 simonb 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.6 2003/01/20 05:29:55 simonb 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 const char *new_level_message = 0;
     68 short party_room = NO_ROOM;
     69 short r_de;
     70 
     71 const 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 	const 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