Home | History | Annotate | Line # | Download | only in rogue
      1 /*	$NetBSD: level.c,v 1.10 2008/01/14 03:50:01 dholland 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. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #include <sys/cdefs.h>
     36 #ifndef lint
     37 #if 0
     38 static char sccsid[] = "@(#)level.c	8.1 (Berkeley) 5/31/93";
     39 #else
     40 __RCSID("$NetBSD: level.c,v 1.10 2008/01/14 03:50:01 dholland Exp $");
     41 #endif
     42 #endif /* not lint */
     43 
     44 /*
     45  * level.c
     46  *
     47  * This source herein may be modified and/or distributed by anybody who
     48  * so desires, with the following restrictions:
     49  *    1.)  No portion of this notice shall be removed.
     50  *    2.)  Credit shall not be taken for the creation of this source.
     51  *    3.)  This code is not to be traded, sold, or used for personal
     52  *         gain or profit.
     53  *
     54  */
     55 
     56 #include "rogue.h"
     57 
     58 #define SWAP(x,y) (t = (x), (x) = (y), (y) = t)
     59 
     60 static void	add_mazes(void);
     61 static int	connect_rooms(short, short);
     62 static void	draw_simple_passage(short, short, short, short, short);
     63 static void	fill_it(int, boolean);
     64 static void	fill_out_level(void);
     65 static int	get_exp_level(long);
     66 static void	hide_boxed_passage(short, short, short, short, short);
     67 static void	make_maze(short, short, short, short, short, short);
     68 static void	make_room(short, short, short, short);
     69 static boolean	mask_room(short, short *, short *, unsigned short);
     70 static void	mix_random_rooms(void);
     71 static void	put_door(room *, short, short *, short *);
     72 static void	recursive_deadend(short, const short *, short, short);
     73 static int	same_col(int, int);
     74 static int	same_row(int, int);
     75 
     76 short cur_level = 0;
     77 short max_level = 1;
     78 short cur_room;
     79 const char *new_level_message = NULL;
     80 short party_room = NO_ROOM;
     81 
     82 static short r_de;
     83 
     84 const long level_points[MAX_EXP_LEVEL] = {
     85 		  10L,
     86 		  20L,
     87 		  40L,
     88 		  80L,
     89 		 160L,
     90 		 320L,
     91 		 640L,
     92 		1300L,
     93 		2600L,
     94 		5200L,
     95 	   10000L,
     96 	   20000L,
     97 	   40000L,
     98 	   80000L,
     99 	  160000L,
    100 	  320000L,
    101 	 1000000L,
    102 	 3333333L,
    103 	 6666666L,
    104 	  MAX_EXP,
    105 	99900000L
    106 };
    107 
    108 static short random_rooms[MAXROOMS] = {3, 7, 5, 2, 0, 6, 1, 4, 8};
    109 
    110 void
    111 make_level(void)
    112 {
    113 	short i, j;
    114 	short must_1, must_2, must_3;
    115 	boolean big_room;
    116 
    117 	must_2 = must_3 = 0;
    118 	if (cur_level < LAST_DUNGEON) {
    119 		cur_level++;
    120 	}
    121 	if (cur_level > max_level) {
    122 		max_level = cur_level;
    123 	}
    124 	must_1 = get_rand(0, 5);
    125 
    126 	switch(must_1) {
    127 	case 0:
    128 		must_1 = 0;
    129 		must_2 = 1;
    130 		must_3 = 2;
    131 		break;
    132 	case 1:
    133 		must_1 = 3;
    134 		must_2 = 4;
    135 		must_3 = 5;
    136 		break;
    137 	case 2:
    138 		must_1 = 6;
    139 		must_2 = 7;
    140 		must_3 = 8;
    141 		break;
    142 	case 3:
    143 		must_1 = 0;
    144 		must_2 = 3;
    145 		must_3 = 6;
    146 		break;
    147 	case 4:
    148 		must_1 = 1;
    149 		must_2 = 4;
    150 		must_3 = 7;
    151 		break;
    152 	case 5:
    153 		must_1 = 2;
    154 		must_2 = 5;
    155 		must_3 = 8;
    156 		break;
    157 	}
    158 	if (rand_percent(8)) {
    159 		party_room = 0;
    160 	}
    161 	big_room = ((party_room != NO_ROOM) && rand_percent(1));
    162 	if (big_room) {
    163 		make_room(BIG_ROOM, 0, 0, 0);
    164 	} else {
    165 		for (i = 0; i < MAXROOMS; i++) {
    166 			make_room(i, must_1, must_2, must_3);
    167 		}
    168 	}
    169 	if (!big_room) {
    170 		add_mazes();
    171 
    172 		mix_random_rooms();
    173 
    174 		for (j = 0; j < MAXROOMS; j++) {
    175 
    176 			i = random_rooms[j];
    177 
    178 			if (i < (MAXROOMS-1)) {
    179 				(void)connect_rooms(i, i+1);
    180 			}
    181 			if (i < (MAXROOMS-3)) {
    182 				(void)connect_rooms(i, i+3);
    183 			}
    184 			if (i < (MAXROOMS-2)) {
    185 				if (rooms[i+1].is_room & R_NOTHING) {
    186 					if (connect_rooms(i, i+2)) {
    187 						rooms[i+1].is_room = R_CROSS;
    188 					}
    189 				}
    190 			}
    191 			if (i < (MAXROOMS-6)) {
    192 				if (rooms[i+3].is_room & R_NOTHING) {
    193 					if (connect_rooms(i, i+6)) {
    194 						rooms[i+3].is_room = R_CROSS;
    195 					}
    196 				}
    197 			}
    198 			if (is_all_connected()) {
    199 				break;
    200 			}
    201 		}
    202 		fill_out_level();
    203 	}
    204 	if (!has_amulet() && (cur_level >= AMULET_LEVEL)) {
    205 		put_amulet();
    206 	}
    207 }
    208 
    209 static void
    210 make_room(short rn, short r1, short r2, short r3)
    211 {
    212 	short left_col, right_col, top_row, bottom_row;
    213 	short width, height;
    214 	short row_offset, col_offset;
    215 	short i, j, ch;
    216 
    217 	left_col = right_col = top_row = bottom_row = 0;
    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 int
    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 	being_held = bear_trap = 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 int
    470 same_row(int room1, int room2)
    471 {
    472 	return((room1 / 3) == (room2 / 3));
    473 }
    474 
    475 static int
    476 same_col(int room1, int 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 /*
    745  * try not to put in room NR
    746  */
    747 void
    748 put_player(short nr)
    749 {
    750 	short rn = nr, misses;
    751 	short row, col;
    752 
    753 	for (misses = 0; ((misses < 2) && (rn == nr)); misses++) {
    754 		gr_row_col(&row, &col, (FLOOR | TUNNEL | OBJECT | STAIRS));
    755 		rn = get_room_number(row, col);
    756 	}
    757 	rogue.row = row;
    758 	rogue.col = col;
    759 
    760 	if (dungeon[rogue.row][rogue.col] & TUNNEL) {
    761 		cur_room = PASSAGE;
    762 	} else {
    763 		cur_room = rn;
    764 	}
    765 	if (cur_room != PASSAGE) {
    766 		light_up_room(cur_room);
    767 	} else {
    768 		light_passage(rogue.row, rogue.col);
    769 	}
    770 	rn = get_room_number(rogue.row, rogue.col);
    771 	wake_room(rn, 1, rogue.row, rogue.col);
    772 	if (new_level_message) {
    773 		messagef(0, "%s", new_level_message);
    774 		new_level_message = NULL;
    775 	}
    776 	mvaddch(rogue.row, rogue.col, rogue.fchar);
    777 }
    778 
    779 int
    780 drop_check(void)
    781 {
    782 	if (wizard) {
    783 		return(1);
    784 	}
    785 	if (dungeon[rogue.row][rogue.col] & STAIRS) {
    786 		if (levitate) {
    787 			messagef(0, "you're floating in the air!");
    788 			return(0);
    789 		}
    790 		return(1);
    791 	}
    792 	messagef(0, "I see no way down");
    793 	return(0);
    794 }
    795 
    796 int
    797 check_up(void)
    798 {
    799 	if (!wizard) {
    800 		if (!(dungeon[rogue.row][rogue.col] & STAIRS)) {
    801 			messagef(0, "I see no way up");
    802 			return(0);
    803 		}
    804 		if (!has_amulet()) {
    805 			messagef(0, "your way is magically blocked");
    806 			return(0);
    807 		}
    808 	}
    809 	new_level_message = "you feel a wrenching sensation in your gut";
    810 	if (cur_level == 1) {
    811 		win();
    812 	} else {
    813 		cur_level -= 2;
    814 		return(1);
    815 	}
    816 	return(0);
    817 }
    818 
    819 void
    820 add_exp(int e, boolean promotion)
    821 {
    822 	short new_exp;
    823 	short i, hp;
    824 
    825 	rogue.exp_points += e;
    826 
    827 	if (rogue.exp_points >= level_points[rogue.exp-1]) {
    828 		new_exp = get_exp_level(rogue.exp_points);
    829 		if (rogue.exp_points > MAX_EXP) {
    830 			rogue.exp_points = MAX_EXP + 1;
    831 		}
    832 		for (i = rogue.exp+1; i <= new_exp; i++) {
    833 			messagef(0, "welcome to level %d", i);
    834 			if (promotion) {
    835 				hp = hp_raise();
    836 				rogue.hp_current += hp;
    837 				rogue.hp_max += hp;
    838 			}
    839 			rogue.exp = i;
    840 			print_stats(STAT_HP | STAT_EXP);
    841 		}
    842 	} else {
    843 		print_stats(STAT_EXP);
    844 	}
    845 }
    846 
    847 static int
    848 get_exp_level(long e)
    849 {
    850 	short i;
    851 
    852 	for (i = 0; i < (MAX_EXP_LEVEL - 1); i++) {
    853 		if (level_points[i] > e) {
    854 			break;
    855 		}
    856 	}
    857 	return(i+1);
    858 }
    859 
    860 int
    861 hp_raise(void)
    862 {
    863 	int hp;
    864 
    865 	hp = (wizard ? 10 : get_rand(3, 10));
    866 	return(hp);
    867 }
    868 
    869 void
    870 show_average_hp(void)
    871 {
    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 	messagef(0, "R-Hp: %.2f, E-Hp: %.2f (!: %d, V: %d)", real_average,
    884 		effective_average, extra_hp, less_hp);
    885 }
    886 
    887 static void
    888 mix_random_rooms(void)
    889 {
    890 	short i, t;
    891 	short x, y;
    892 
    893 	for (i = 0; i < (3 * MAXROOMS); i++) {
    894 		do {
    895 			x = get_rand(0, (MAXROOMS-1));
    896 			y = get_rand(0, (MAXROOMS-1));
    897 		} while (x == y);
    898 		SWAP(random_rooms[x], random_rooms[y]);
    899 	}
    900 }
    901