2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 static char sccsid[] = "@(#)level.c 8.1 (Berkeley) 5/31/93";
41 static const char rcsid[] =
48 * This source herein may be modified and/or distributed by anybody who
49 * so desires, with the following restrictions:
50 * 1.) No portion of this notice shall be removed.
51 * 2.) Credit shall not be taken for the creation of this source.
52 * 3.) This code is not to be traded, sold, or used for personal
59 #define swap(x,y) {t = x; x = y; y = t;}
64 const char *new_level_message = 0;
65 short party_room = NO_ROOM;
68 const long level_points[MAX_EXP_LEVEL] = {
92 short random_rooms[MAXROOMS] = {3, 7, 5, 2, 0, 6, 1, 4, 8};
94 extern boolean being_held, wizard, detect_monster;
95 extern boolean see_invisible;
96 extern short bear_trap, levitate, extra_hp, less_hp, cur_room;
101 short must_1, must_2, must_3;
104 if (cur_level < LAST_DUNGEON) {
107 if (cur_level > max_level) {
108 max_level = cur_level;
110 must_1 = get_rand(0, 5);
144 if (rand_percent(8)) {
147 big_room = ((party_room != NO_ROOM) && rand_percent(1));
149 make_room(BIG_ROOM, 0, 0, 0);
151 for (i = 0; i < MAXROOMS; i++) {
152 make_room(i, must_1, must_2, must_3);
160 for (j = 0; j < MAXROOMS; j++) {
164 if (i < (MAXROOMS-1)) {
165 (void) connect_rooms(i, i+1);
167 if (i < (MAXROOMS-3)) {
168 (void) connect_rooms(i, i+3);
170 if (i < (MAXROOMS-2)) {
171 if (rooms[i+1].is_room & R_NOTHING) {
172 if (connect_rooms(i, i+2)) {
173 rooms[i+1].is_room = R_CROSS;
177 if (i < (MAXROOMS-6)) {
178 if (rooms[i+3].is_room & R_NOTHING) {
179 if (connect_rooms(i, i+6)) {
180 rooms[i+3].is_room = R_CROSS;
184 if (is_all_connected()) {
190 if (!has_amulet() && (cur_level >= AMULET_LEVEL)) {
195 make_room(rn, r1, r2, r3)
196 short rn, r1, r2, r3;
198 short left_col, right_col, top_row, bottom_row;
200 short row_offset, col_offset;
244 bottom_row = DROWS - 2;
250 bottom_row = DROWS - 2;
256 bottom_row = DROWS - 2;
259 top_row = get_rand(MIN_ROW, MIN_ROW+5);
260 bottom_row = get_rand(DROWS-7, DROWS-2);
261 left_col = get_rand(0, 10);;
262 right_col = get_rand(DCOLS-11, DCOLS-1);
266 height = get_rand(4, (bottom_row - top_row + 1));
267 width = get_rand(7, (right_col - left_col - 2));
269 row_offset = get_rand(0, ((bottom_row - top_row) - height + 1));
270 col_offset = get_rand(0, ((right_col - left_col) - width + 1));
272 top_row += row_offset;
273 bottom_row = top_row + height - 1;
275 left_col += col_offset;
276 right_col = left_col + width - 1;
278 if ((rn != r1) && (rn != r2) && (rn != r3) && rand_percent(40)) {
282 rooms[rn].is_room = R_ROOM;
284 for (i = top_row; i <= bottom_row; i++) {
285 for (j = left_col; j <= right_col; j++) {
286 if ((i == top_row) || (i == bottom_row)) {
288 } else if ( ((i != top_row) && (i != bottom_row)) &&
289 ((j == left_col) || (j == right_col))) {
298 rooms[rn].top_row = top_row;
299 rooms[rn].bottom_row = bottom_row;
300 rooms[rn].left_col = left_col;
301 rooms[rn].right_col = right_col;
304 connect_rooms(room1, room2)
307 short row1, col1, row2, col2, dir;
309 if ((!(rooms[room1].is_room & (R_ROOM | R_MAZE))) ||
310 (!(rooms[room2].is_room & (R_ROOM | R_MAZE)))) {
313 if (same_row(room1, room2) &&
314 (rooms[room1].left_col > rooms[room2].right_col)) {
315 put_door(&rooms[room1], LEFT, &row1, &col1);
316 put_door(&rooms[room2], RIGHT, &row2, &col2);
318 } else if (same_row(room1, room2) &&
319 (rooms[room2].left_col > rooms[room1].right_col)) {
320 put_door(&rooms[room1], RIGHT, &row1, &col1);
321 put_door(&rooms[room2], LEFT, &row2, &col2);
323 } else if (same_col(room1, room2) &&
324 (rooms[room1].top_row > rooms[room2].bottom_row)) {
325 put_door(&rooms[room1], UPWARD, &row1, &col1);
326 put_door(&rooms[room2], DOWN, &row2, &col2);
328 } else if (same_col(room1, room2) &&
329 (rooms[room2].top_row > rooms[room1].bottom_row)) {
330 put_door(&rooms[room1], DOWN, &row1, &col1);
331 put_door(&rooms[room2], UPWARD, &row2, &col2);
338 draw_simple_passage(row1, col1, row2, col2, dir);
339 } while (rand_percent(4));
341 rooms[room1].doors[dir/2].oth_room = room2;
342 rooms[room1].doors[dir/2].oth_row = row2;
343 rooms[room1].doors[dir/2].oth_col = col2;
345 rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_room = room1;
346 rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_row = row1;
347 rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_col = col1;
355 for (i = 0; i < MAXROOMS; i++) {
356 rooms[i].is_room = R_NOTHING;
357 for (j = 0; j < 4; j++) {
358 rooms[i].doors[j].oth_room = NO_ROOM;
362 for (i = 0; i < MAX_TRAPS; i++) {
363 traps[i].trap_type = NO_TRAP;
365 for (i = 0; i < DROWS; i++) {
366 for (j = 0; j < DCOLS; j++) {
367 dungeon[i][j] = NOTHING;
370 detect_monster = see_invisible = 0;
371 being_held = bear_trap = 0;
372 party_room = NO_ROOM;
373 rogue.row = rogue.col = -1;
377 put_door(rm, dir, row, col)
384 wall_width = (rm->is_room & R_MAZE) ? 0 : 1;
389 *row = ((dir == UPWARD) ? rm->top_row : rm->bottom_row);
391 *col = get_rand(rm->left_col+wall_width,
392 rm->right_col-wall_width);
393 } while (!(dungeon[*row][*col] & (HORWALL | TUNNEL)));
397 *col = (dir == LEFT) ? rm->left_col : rm->right_col;
399 *row = get_rand(rm->top_row+wall_width,
400 rm->bottom_row-wall_width);
401 } while (!(dungeon[*row][*col] & (VERTWALL | TUNNEL)));
404 if (rm->is_room & R_ROOM) {
405 dungeon[*row][*col] = DOOR;
407 if ((cur_level > 2) && rand_percent(HIDE_PERCENT)) {
408 dungeon[*row][*col] |= HIDDEN;
410 rm->doors[dir/2].door_row = *row;
411 rm->doors[dir/2].door_col = *col;
414 draw_simple_passage(row1, col1, row2, col2, dir)
415 short row1, col1, row2, col2, dir;
419 if ((dir == LEFT) || (dir == RIGHT)) {
424 middle = get_rand(col1+1, col2-1);
425 for (i = col1+1; i != middle; i++) {
426 dungeon[row1][i] = TUNNEL;
428 for (i = row1; i != row2; i += (row1 > row2) ? -1 : 1) {
429 dungeon[i][middle] = TUNNEL;
431 for (i = middle; i != col2; i++) {
432 dungeon[row2][i] = TUNNEL;
439 middle = get_rand(row1+1, row2-1);
440 for (i = row1+1; i != middle; i++) {
441 dungeon[i][col1] = TUNNEL;
443 for (i = col1; i != col2; i += (col1 > col2) ? -1 : 1) {
444 dungeon[middle][i] = TUNNEL;
446 for (i = middle; i != row2; i++) {
447 dungeon[i][col2] = TUNNEL;
450 if (rand_percent(HIDE_PERCENT)) {
451 hide_boxed_passage(row1, col1, row2, col2, 1);
455 same_row(room1, room2)
457 return((room1 / 3) == (room2 / 3));
460 same_col(room1, room2)
462 return((room1 % 3) == (room2 % 3));
472 start = get_rand(0, (MAXROOMS-1));
473 maze_percent = (cur_level * 5) / 4;
475 if (cur_level > 15) {
476 maze_percent += cur_level;
478 for (i = 0; i < MAXROOMS; i++) {
479 j = ((start + i) % MAXROOMS);
480 if (rooms[j].is_room & R_NOTHING) {
481 if (rand_percent(maze_percent)) {
482 rooms[j].is_room = R_MAZE;
483 make_maze(get_rand(rooms[j].top_row+1, rooms[j].bottom_row-1),
484 get_rand(rooms[j].left_col+1, rooms[j].right_col-1),
485 rooms[j].top_row, rooms[j].bottom_row,
486 rooms[j].left_col, rooms[j].right_col);
487 hide_boxed_passage(rooms[j].top_row, rooms[j].left_col,
488 rooms[j].bottom_row, rooms[j].right_col,
504 for (i = 0; i < MAXROOMS; i++) {
505 rn = random_rooms[i];
506 if ((rooms[rn].is_room & R_NOTHING) ||
507 ((rooms[rn].is_room & R_CROSS) && coin_toss())) {
511 if (r_de != NO_ROOM) {
516 fill_it(rn, do_rec_de)
520 short i, tunnel_dir, door_dir, drow, dcol;
521 short target_room, rooms_found = 0;
523 static short offsets[4] = {-1, 1, 3, -3};
524 boolean did_this = 0;
526 for (i = 0; i < 10; i++) {
527 srow = get_rand(0, 3);
528 scol = get_rand(0, 3);
530 offsets[srow] = offsets[scol];
533 for (i = 0; i < 4; i++) {
535 target_room = rn + offsets[i];
537 if (((target_room < 0) || (target_room >= MAXROOMS)) ||
538 (!(same_row(rn,target_room) || same_col(rn,target_room))) ||
539 (!(rooms[target_room].is_room & (R_ROOM | R_MAZE)))) {
542 if (same_row(rn, target_room)) {
543 tunnel_dir = (rooms[rn].left_col < rooms[target_room].left_col) ?
546 tunnel_dir = (rooms[rn].top_row < rooms[target_room].top_row) ?
549 door_dir = ((tunnel_dir + 4) % DIRS);
550 if (rooms[target_room].doors[door_dir/2].oth_room != NO_ROOM) {
553 if (((!do_rec_de) || did_this) ||
554 (!mask_room(rn, &srow, &scol, TUNNEL))) {
555 srow = (rooms[rn].top_row + rooms[rn].bottom_row) / 2;
556 scol = (rooms[rn].left_col + rooms[rn].right_col) / 2;
558 put_door(&rooms[target_room], door_dir, &drow, &dcol);
560 draw_simple_passage(srow, scol, drow, dcol, tunnel_dir);
561 rooms[rn].is_room = R_DEADEND;
562 dungeon[srow][scol] = TUNNEL;
564 if ((i < 3) && (!did_this)) {
570 if ((rooms_found < 2) && do_rec_de) {
571 recursive_deadend(rn, offsets, srow, scol);
577 recursive_deadend(rn, offsets, srow, scol)
579 const short *offsets;
583 short drow, dcol, tunnel_dir;
585 rooms[rn].is_room = R_DEADEND;
586 dungeon[srow][scol] = TUNNEL;
588 for (i = 0; i < 4; i++) {
589 de = rn + offsets[i];
590 if (((de < 0) || (de >= MAXROOMS)) ||
591 (!(same_row(rn, de) || same_col(rn, de)))) {
594 if (!(rooms[de].is_room & R_NOTHING)) {
597 drow = (rooms[de].top_row + rooms[de].bottom_row) / 2;
598 dcol = (rooms[de].left_col + rooms[de].right_col) / 2;
599 if (same_row(rn, de)) {
600 tunnel_dir = (rooms[rn].left_col < rooms[de].left_col) ?
603 tunnel_dir = (rooms[rn].top_row < rooms[de].top_row) ?
606 draw_simple_passage(srow, scol, drow, dcol, tunnel_dir);
608 recursive_deadend(de, offsets, drow, dcol);
613 mask_room(rn, row, col, mask)
620 for (i = rooms[rn].top_row; i <= rooms[rn].bottom_row; i++) {
621 for (j = rooms[rn].left_col; j <= rooms[rn].right_col; j++) {
622 if (dungeon[i][j] & mask) {
632 make_maze(r, c, tr, br, lc, rc)
633 short r, c, tr, br, lc, rc;
643 dungeon[r][c] = TUNNEL;
645 if (rand_percent(20)) {
646 for (i = 0; i < 10; i++) {
652 swap(dirs[t1], dirs[t2]);
655 for (i = 0; i < 4; i++) {
659 (dungeon[r-1][c] != TUNNEL) &&
660 (dungeon[r-1][c-1] != TUNNEL) &&
661 (dungeon[r-1][c+1] != TUNNEL) &&
662 (dungeon[r-2][c] != TUNNEL)) {
663 make_maze((r-1), c, tr, br, lc, rc);
668 (dungeon[r+1][c] != TUNNEL) &&
669 (dungeon[r+1][c-1] != TUNNEL) &&
670 (dungeon[r+1][c+1] != TUNNEL) &&
671 (dungeon[r+2][c] != TUNNEL)) {
672 make_maze((r+1), c, tr, br, lc, rc);
677 (dungeon[r][c-1] != TUNNEL) &&
678 (dungeon[r-1][c-1] != TUNNEL) &&
679 (dungeon[r+1][c-1] != TUNNEL) &&
680 (dungeon[r][c-2] != TUNNEL)) {
681 make_maze(r, (c-1), tr, br, lc, rc);
686 (dungeon[r][c+1] != TUNNEL) &&
687 (dungeon[r-1][c+1] != TUNNEL) &&
688 (dungeon[r+1][c+1] != TUNNEL) &&
689 (dungeon[r][c+2] != TUNNEL)) {
690 make_maze(r, (c+1), tr, br, lc, rc);
697 hide_boxed_passage(row1, col1, row2, col2, n)
698 short row1, col1, row2, col2, n;
701 short row, col, row_cut, col_cut;
714 if ((w >= 5) || (h >= 5)) {
715 row_cut = ((h >= 2) ? 1 : 0);
716 col_cut = ((w >= 2) ? 1 : 0);
718 for (i = 0; i < n; i++) {
719 for (j = 0; j < 10; j++) {
720 row = get_rand(row1 + row_cut, row2 - row_cut);
721 col = get_rand(col1 + col_cut, col2 - col_cut);
722 if (dungeon[row][col] == TUNNEL) {
723 dungeon[row][col] |= HIDDEN;
733 short nr; /* try not to put in this room */
735 short rn = nr, misses;
738 for (misses = 0; ((misses < 2) && (rn == nr)); misses++) {
739 gr_row_col(&row, &col, (FLOOR | TUNNEL | OBJECT | STAIRS));
740 rn = get_room_number(row, col);
745 if (dungeon[rogue.row][rogue.col] & TUNNEL) {
750 if (cur_room != PASSAGE) {
751 light_up_room(cur_room);
753 light_passage(rogue.row, rogue.col);
755 rn = get_room_number(rogue.row, rogue.col);
756 wake_room(rn, 1, rogue.row, rogue.col);
757 if (new_level_message) {
758 message(new_level_message, 0);
759 new_level_message = 0;
761 mvaddch(rogue.row, rogue.col, rogue.fchar);
769 if (dungeon[rogue.row][rogue.col] & STAIRS) {
771 message("you're floating in the air!", 0);
776 message("I see no way down", 0);
783 if (!(dungeon[rogue.row][rogue.col] & STAIRS)) {
784 message("I see no way up", 0);
788 message("your way is magically blocked", 0);
792 new_level_message = "you feel a wrenching sensation in your gut";
793 if (cur_level == 1) {
802 add_exp(e, promotion)
810 rogue.exp_points += e;
812 if (rogue.exp_points >= level_points[rogue.exp-1]) {
813 new_exp = get_exp_level(rogue.exp_points);
814 if (rogue.exp_points > MAX_EXP) {
815 rogue.exp_points = MAX_EXP + 1;
817 for (i = rogue.exp+1; i <= new_exp; i++) {
818 sprintf(mbuf, "welcome to level %d", i);
822 rogue.hp_current += hp;
826 print_stats(STAT_HP | STAT_EXP);
829 print_stats(STAT_EXP);
838 for (i = 0; i < (MAX_EXP_LEVEL - 1); i++) {
839 if (level_points[i] > e) {
850 hp = (wizard ? 10 : get_rand(3, 10));
858 float effective_average;
860 if (rogue.exp == 1) {
861 real_average = effective_average = 0.00;
863 real_average = (float)
864 ((rogue.hp_max - extra_hp - INIT_HP) + less_hp) / (rogue.exp - 1);
865 effective_average = (float) (rogue.hp_max - INIT_HP) / (rogue.exp - 1);
868 sprintf(mbuf, "R-Hp: %.2f, E-Hp: %.2f (!: %d, V: %d)", real_average,
869 effective_average, extra_hp, less_hp);
878 for (i = 0; i < (3 * MAXROOMS); i++) {
880 x = get_rand(0, (MAXROOMS-1));
881 y = get_rand(0, (MAXROOMS-1));
883 swap(random_rooms[x], random_rooms[y]);