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