1*130a8172Sdholland /* $NetBSD: level.c,v 1.10 2008/01/14 03:50:01 dholland Exp $ */
27ee35daaScgd
361f28255Scgd /*
47ee35daaScgd * Copyright (c) 1988, 1993
57ee35daaScgd * The Regents of the University of California. All rights reserved.
661f28255Scgd *
761f28255Scgd * This code is derived from software contributed to Berkeley by
861f28255Scgd * Timothy C. Stoehr.
961f28255Scgd *
1061f28255Scgd * Redistribution and use in source and binary forms, with or without
1161f28255Scgd * modification, are permitted provided that the following conditions
1261f28255Scgd * are met:
1361f28255Scgd * 1. Redistributions of source code must retain the above copyright
1461f28255Scgd * notice, this list of conditions and the following disclaimer.
1561f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1661f28255Scgd * notice, this list of conditions and the following disclaimer in the
1761f28255Scgd * documentation and/or other materials provided with the distribution.
18e5aeb4eaSagc * 3. Neither the name of the University nor the names of its contributors
1961f28255Scgd * may be used to endorse or promote products derived from this software
2061f28255Scgd * without specific prior written permission.
2161f28255Scgd *
2261f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2361f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2461f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2561f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2661f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2761f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2861f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2961f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3061f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3161f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3261f28255Scgd * SUCH DAMAGE.
3361f28255Scgd */
3461f28255Scgd
352736b511Slukem #include <sys/cdefs.h>
3661f28255Scgd #ifndef lint
377ee35daaScgd #if 0
387ee35daaScgd static char sccsid[] = "@(#)level.c 8.1 (Berkeley) 5/31/93";
397ee35daaScgd #else
40*130a8172Sdholland __RCSID("$NetBSD: level.c,v 1.10 2008/01/14 03:50:01 dholland Exp $");
417ee35daaScgd #endif
4261f28255Scgd #endif /* not lint */
4361f28255Scgd
4461f28255Scgd /*
4561f28255Scgd * level.c
4661f28255Scgd *
4761f28255Scgd * This source herein may be modified and/or distributed by anybody who
4861f28255Scgd * so desires, with the following restrictions:
4961f28255Scgd * 1.) No portion of this notice shall be removed.
5061f28255Scgd * 2.) Credit shall not be taken for the creation of this source.
5161f28255Scgd * 3.) This code is not to be traded, sold, or used for personal
5261f28255Scgd * gain or profit.
5361f28255Scgd *
5461f28255Scgd */
5561f28255Scgd
5661f28255Scgd #include "rogue.h"
5761f28255Scgd
58*130a8172Sdholland #define SWAP(x,y) (t = (x), (x) = (y), (y) = t)
59*130a8172Sdholland
60*130a8172Sdholland static void add_mazes(void);
61*130a8172Sdholland static int connect_rooms(short, short);
62*130a8172Sdholland static void draw_simple_passage(short, short, short, short, short);
63*130a8172Sdholland static void fill_it(int, boolean);
64*130a8172Sdholland static void fill_out_level(void);
65*130a8172Sdholland static int get_exp_level(long);
66*130a8172Sdholland static void hide_boxed_passage(short, short, short, short, short);
67*130a8172Sdholland static void make_maze(short, short, short, short, short, short);
68*130a8172Sdholland static void make_room(short, short, short, short);
69*130a8172Sdholland static boolean mask_room(short, short *, short *, unsigned short);
70*130a8172Sdholland static void mix_random_rooms(void);
71*130a8172Sdholland static void put_door(room *, short, short *, short *);
72*130a8172Sdholland static void recursive_deadend(short, const short *, short, short);
73*130a8172Sdholland static int same_col(int, int);
74*130a8172Sdholland static int same_row(int, int);
7561f28255Scgd
7661f28255Scgd short cur_level = 0;
7761f28255Scgd short max_level = 1;
7861f28255Scgd short cur_room;
79*130a8172Sdholland const char *new_level_message = NULL;
8061f28255Scgd short party_room = NO_ROOM;
81*130a8172Sdholland
82*130a8172Sdholland static short r_de;
8361f28255Scgd
846d265b32Shubertf const long level_points[MAX_EXP_LEVEL] = {
8561f28255Scgd 10L,
8661f28255Scgd 20L,
8761f28255Scgd 40L,
8861f28255Scgd 80L,
8961f28255Scgd 160L,
9061f28255Scgd 320L,
9161f28255Scgd 640L,
9261f28255Scgd 1300L,
9361f28255Scgd 2600L,
9461f28255Scgd 5200L,
9561f28255Scgd 10000L,
9661f28255Scgd 20000L,
9761f28255Scgd 40000L,
9861f28255Scgd 80000L,
9961f28255Scgd 160000L,
10061f28255Scgd 320000L,
10161f28255Scgd 1000000L,
10261f28255Scgd 3333333L,
10361f28255Scgd 6666666L,
10461f28255Scgd MAX_EXP,
10561f28255Scgd 99900000L
10661f28255Scgd };
10761f28255Scgd
108*130a8172Sdholland static short random_rooms[MAXROOMS] = {3, 7, 5, 2, 0, 6, 1, 4, 8};
10961f28255Scgd
1102736b511Slukem void
make_level(void)111*130a8172Sdholland make_level(void)
11261f28255Scgd {
11361f28255Scgd short i, j;
11461f28255Scgd short must_1, must_2, must_3;
11561f28255Scgd boolean big_room;
11661f28255Scgd
1172736b511Slukem must_2 = must_3 = 0;
11861f28255Scgd if (cur_level < LAST_DUNGEON) {
11961f28255Scgd cur_level++;
12061f28255Scgd }
12161f28255Scgd if (cur_level > max_level) {
12261f28255Scgd max_level = cur_level;
12361f28255Scgd }
12461f28255Scgd must_1 = get_rand(0, 5);
12561f28255Scgd
12661f28255Scgd switch(must_1) {
12761f28255Scgd case 0:
12861f28255Scgd must_1 = 0;
12961f28255Scgd must_2 = 1;
13061f28255Scgd must_3 = 2;
13161f28255Scgd break;
13261f28255Scgd case 1:
13361f28255Scgd must_1 = 3;
13461f28255Scgd must_2 = 4;
13561f28255Scgd must_3 = 5;
13661f28255Scgd break;
13761f28255Scgd case 2:
13861f28255Scgd must_1 = 6;
13961f28255Scgd must_2 = 7;
14061f28255Scgd must_3 = 8;
14161f28255Scgd break;
14261f28255Scgd case 3:
14361f28255Scgd must_1 = 0;
14461f28255Scgd must_2 = 3;
14561f28255Scgd must_3 = 6;
14661f28255Scgd break;
14761f28255Scgd case 4:
14861f28255Scgd must_1 = 1;
14961f28255Scgd must_2 = 4;
15061f28255Scgd must_3 = 7;
15161f28255Scgd break;
15261f28255Scgd case 5:
15361f28255Scgd must_1 = 2;
15461f28255Scgd must_2 = 5;
15561f28255Scgd must_3 = 8;
15661f28255Scgd break;
15761f28255Scgd }
15861f28255Scgd if (rand_percent(8)) {
15961f28255Scgd party_room = 0;
16061f28255Scgd }
16161f28255Scgd big_room = ((party_room != NO_ROOM) && rand_percent(1));
16261f28255Scgd if (big_room) {
16361f28255Scgd make_room(BIG_ROOM, 0, 0, 0);
16461f28255Scgd } else {
16561f28255Scgd for (i = 0; i < MAXROOMS; i++) {
16661f28255Scgd make_room(i, must_1, must_2, must_3);
16761f28255Scgd }
16861f28255Scgd }
16961f28255Scgd if (!big_room) {
17061f28255Scgd add_mazes();
17161f28255Scgd
17261f28255Scgd mix_random_rooms();
17361f28255Scgd
17461f28255Scgd for (j = 0; j < MAXROOMS; j++) {
17561f28255Scgd
17661f28255Scgd i = random_rooms[j];
17761f28255Scgd
17861f28255Scgd if (i < (MAXROOMS-1)) {
17961f28255Scgd (void)connect_rooms(i, i+1);
18061f28255Scgd }
18161f28255Scgd if (i < (MAXROOMS-3)) {
18261f28255Scgd (void)connect_rooms(i, i+3);
18361f28255Scgd }
18461f28255Scgd if (i < (MAXROOMS-2)) {
18561f28255Scgd if (rooms[i+1].is_room & R_NOTHING) {
18661f28255Scgd if (connect_rooms(i, i+2)) {
18761f28255Scgd rooms[i+1].is_room = R_CROSS;
18861f28255Scgd }
18961f28255Scgd }
19061f28255Scgd }
19161f28255Scgd if (i < (MAXROOMS-6)) {
19261f28255Scgd if (rooms[i+3].is_room & R_NOTHING) {
19361f28255Scgd if (connect_rooms(i, i+6)) {
19461f28255Scgd rooms[i+3].is_room = R_CROSS;
19561f28255Scgd }
19661f28255Scgd }
19761f28255Scgd }
19861f28255Scgd if (is_all_connected()) {
19961f28255Scgd break;
20061f28255Scgd }
20161f28255Scgd }
20261f28255Scgd fill_out_level();
20361f28255Scgd }
20461f28255Scgd if (!has_amulet() && (cur_level >= AMULET_LEVEL)) {
20561f28255Scgd put_amulet();
20661f28255Scgd }
20761f28255Scgd }
20861f28255Scgd
209*130a8172Sdholland static void
make_room(short rn,short r1,short r2,short r3)210*130a8172Sdholland make_room(short rn, short r1, short r2, short r3)
21161f28255Scgd {
21261f28255Scgd short left_col, right_col, top_row, bottom_row;
21361f28255Scgd short width, height;
21461f28255Scgd short row_offset, col_offset;
21561f28255Scgd short i, j, ch;
21661f28255Scgd
2172736b511Slukem left_col = right_col = top_row = bottom_row = 0;
21861f28255Scgd switch(rn) {
21961f28255Scgd case 0:
22061f28255Scgd left_col = 0;
22161f28255Scgd right_col = COL1-1;
22261f28255Scgd top_row = MIN_ROW;
22361f28255Scgd bottom_row = ROW1-1;
22461f28255Scgd break;
22561f28255Scgd case 1:
22661f28255Scgd left_col = COL1+1;
22761f28255Scgd right_col = COL2-1;
22861f28255Scgd top_row = MIN_ROW;
22961f28255Scgd bottom_row = ROW1-1;
23061f28255Scgd break;
23161f28255Scgd case 2:
23261f28255Scgd left_col = COL2+1;
23361f28255Scgd right_col = DCOLS-1;
23461f28255Scgd top_row = MIN_ROW;
23561f28255Scgd bottom_row = ROW1-1;
23661f28255Scgd break;
23761f28255Scgd case 3:
23861f28255Scgd left_col = 0;
23961f28255Scgd right_col = COL1-1;
24061f28255Scgd top_row = ROW1+1;
24161f28255Scgd bottom_row = ROW2-1;
24261f28255Scgd break;
24361f28255Scgd case 4:
24461f28255Scgd left_col = COL1+1;
24561f28255Scgd right_col = COL2-1;
24661f28255Scgd top_row = ROW1+1;
24761f28255Scgd bottom_row = ROW2-1;
24861f28255Scgd break;
24961f28255Scgd case 5:
25061f28255Scgd left_col = COL2+1;
25161f28255Scgd right_col = DCOLS-1;
25261f28255Scgd top_row = ROW1+1;
25361f28255Scgd bottom_row = ROW2-1;
25461f28255Scgd break;
25561f28255Scgd case 6:
25661f28255Scgd left_col = 0;
25761f28255Scgd right_col = COL1-1;
25861f28255Scgd top_row = ROW2+1;
25961f28255Scgd bottom_row = DROWS - 2;
26061f28255Scgd break;
26161f28255Scgd case 7:
26261f28255Scgd left_col = COL1+1;
26361f28255Scgd right_col = COL2-1;
26461f28255Scgd top_row = ROW2+1;
26561f28255Scgd bottom_row = DROWS - 2;
26661f28255Scgd break;
26761f28255Scgd case 8:
26861f28255Scgd left_col = COL2+1;
26961f28255Scgd right_col = DCOLS-1;
27061f28255Scgd top_row = ROW2+1;
27161f28255Scgd bottom_row = DROWS - 2;
27261f28255Scgd break;
27361f28255Scgd case BIG_ROOM:
27461f28255Scgd top_row = get_rand(MIN_ROW, MIN_ROW+5);
27561f28255Scgd bottom_row = get_rand(DROWS-7, DROWS-2);
276276fd166Ssimonb left_col = get_rand(0, 10);
27761f28255Scgd right_col = get_rand(DCOLS-11, DCOLS-1);
27861f28255Scgd rn = 0;
27961f28255Scgd goto B;
28061f28255Scgd }
28161f28255Scgd height = get_rand(4, (bottom_row - top_row + 1));
28261f28255Scgd width = get_rand(7, (right_col - left_col - 2));
28361f28255Scgd
28461f28255Scgd row_offset = get_rand(0, ((bottom_row - top_row) - height + 1));
28561f28255Scgd col_offset = get_rand(0, ((right_col - left_col) - width + 1));
28661f28255Scgd
28761f28255Scgd top_row += row_offset;
28861f28255Scgd bottom_row = top_row + height - 1;
28961f28255Scgd
29061f28255Scgd left_col += col_offset;
29161f28255Scgd right_col = left_col + width - 1;
29261f28255Scgd
29361f28255Scgd if ((rn != r1) && (rn != r2) && (rn != r3) && rand_percent(40)) {
29461f28255Scgd goto END;
29561f28255Scgd }
29661f28255Scgd B:
29761f28255Scgd rooms[rn].is_room = R_ROOM;
29861f28255Scgd
29961f28255Scgd for (i = top_row; i <= bottom_row; i++) {
30061f28255Scgd for (j = left_col; j <= right_col; j++) {
30161f28255Scgd if ((i == top_row) || (i == bottom_row)) {
30261f28255Scgd ch = HORWALL;
30361f28255Scgd } else if ( ((i != top_row) && (i != bottom_row)) &&
30461f28255Scgd ((j == left_col) || (j == right_col))) {
30561f28255Scgd ch = VERTWALL;
30661f28255Scgd } else {
30761f28255Scgd ch = FLOOR;
30861f28255Scgd }
30961f28255Scgd dungeon[i][j] = ch;
31061f28255Scgd }
31161f28255Scgd }
31261f28255Scgd END:
31361f28255Scgd rooms[rn].top_row = top_row;
31461f28255Scgd rooms[rn].bottom_row = bottom_row;
31561f28255Scgd rooms[rn].left_col = left_col;
31661f28255Scgd rooms[rn].right_col = right_col;
31761f28255Scgd }
31861f28255Scgd
319*130a8172Sdholland static int
connect_rooms(short room1,short room2)320*130a8172Sdholland connect_rooms(short room1, short room2)
32161f28255Scgd {
32261f28255Scgd short row1, col1, row2, col2, dir;
32361f28255Scgd
32461f28255Scgd if ((!(rooms[room1].is_room & (R_ROOM | R_MAZE))) ||
32561f28255Scgd (!(rooms[room2].is_room & (R_ROOM | R_MAZE)))) {
32661f28255Scgd return(0);
32761f28255Scgd }
32861f28255Scgd if (same_row(room1, room2) &&
32961f28255Scgd (rooms[room1].left_col > rooms[room2].right_col)) {
33061f28255Scgd put_door(&rooms[room1], LEFT, &row1, &col1);
33161f28255Scgd put_door(&rooms[room2], RIGHT, &row2, &col2);
33261f28255Scgd dir = LEFT;
33361f28255Scgd } else if (same_row(room1, room2) &&
33461f28255Scgd (rooms[room2].left_col > rooms[room1].right_col)) {
33561f28255Scgd put_door(&rooms[room1], RIGHT, &row1, &col1);
33661f28255Scgd put_door(&rooms[room2], LEFT, &row2, &col2);
33761f28255Scgd dir = RIGHT;
33861f28255Scgd } else if (same_col(room1, room2) &&
33961f28255Scgd (rooms[room1].top_row > rooms[room2].bottom_row)) {
34061f28255Scgd put_door(&rooms[room1], UPWARD, &row1, &col1);
34161f28255Scgd put_door(&rooms[room2], DOWN, &row2, &col2);
34261f28255Scgd dir = UPWARD;
34361f28255Scgd } else if (same_col(room1, room2) &&
34461f28255Scgd (rooms[room2].top_row > rooms[room1].bottom_row)) {
34561f28255Scgd put_door(&rooms[room1], DOWN, &row1, &col1);
34661f28255Scgd put_door(&rooms[room2], UPWARD, &row2, &col2);
34761f28255Scgd dir = DOWN;
34861f28255Scgd } else {
34961f28255Scgd return(0);
35061f28255Scgd }
35161f28255Scgd
35261f28255Scgd do {
35361f28255Scgd draw_simple_passage(row1, col1, row2, col2, dir);
35461f28255Scgd } while (rand_percent(4));
35561f28255Scgd
35661f28255Scgd rooms[room1].doors[dir/2].oth_room = room2;
35761f28255Scgd rooms[room1].doors[dir/2].oth_row = row2;
35861f28255Scgd rooms[room1].doors[dir/2].oth_col = col2;
35961f28255Scgd
36061f28255Scgd rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_room = room1;
36161f28255Scgd rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_row = row1;
36261f28255Scgd rooms[room2].doors[(((dir+4)%DIRS)/2)].oth_col = col1;
36361f28255Scgd return(1);
36461f28255Scgd }
36561f28255Scgd
3662736b511Slukem void
clear_level(void)367*130a8172Sdholland clear_level(void)
36861f28255Scgd {
36961f28255Scgd short i, j;
37061f28255Scgd
37161f28255Scgd for (i = 0; i < MAXROOMS; i++) {
37261f28255Scgd rooms[i].is_room = R_NOTHING;
37361f28255Scgd for (j = 0; j < 4; j++) {
37461f28255Scgd rooms[i].doors[j].oth_room = NO_ROOM;
37561f28255Scgd }
37661f28255Scgd }
37761f28255Scgd
37861f28255Scgd for (i = 0; i < MAX_TRAPS; i++) {
37961f28255Scgd traps[i].trap_type = NO_TRAP;
38061f28255Scgd }
38161f28255Scgd for (i = 0; i < DROWS; i++) {
38261f28255Scgd for (j = 0; j < DCOLS; j++) {
38361f28255Scgd dungeon[i][j] = NOTHING;
38461f28255Scgd }
38561f28255Scgd }
38661f28255Scgd detect_monster = see_invisible = 0;
38761f28255Scgd being_held = bear_trap = 0;
38861f28255Scgd party_room = NO_ROOM;
38961f28255Scgd rogue.row = rogue.col = -1;
39061f28255Scgd clear();
39161f28255Scgd }
39261f28255Scgd
393*130a8172Sdholland static void
put_door(room * rm,short dir,short * row,short * col)394*130a8172Sdholland put_door(room *rm, short dir, short *row, short *col)
39561f28255Scgd {
39661f28255Scgd short wall_width;
39761f28255Scgd
39861f28255Scgd wall_width = (rm->is_room & R_MAZE) ? 0 : 1;
39961f28255Scgd
40061f28255Scgd switch(dir) {
40161f28255Scgd case UPWARD:
40261f28255Scgd case DOWN:
40361f28255Scgd *row = ((dir == UPWARD) ? rm->top_row : rm->bottom_row);
40461f28255Scgd do {
40561f28255Scgd *col = get_rand(rm->left_col+wall_width,
40661f28255Scgd rm->right_col-wall_width);
40761f28255Scgd } while (!(dungeon[*row][*col] & (HORWALL | TUNNEL)));
40861f28255Scgd break;
40961f28255Scgd case RIGHT:
41061f28255Scgd case LEFT:
41161f28255Scgd *col = (dir == LEFT) ? rm->left_col : rm->right_col;
41261f28255Scgd do {
41361f28255Scgd *row = get_rand(rm->top_row+wall_width,
41461f28255Scgd rm->bottom_row-wall_width);
41561f28255Scgd } while (!(dungeon[*row][*col] & (VERTWALL | TUNNEL)));
41661f28255Scgd break;
41761f28255Scgd }
41861f28255Scgd if (rm->is_room & R_ROOM) {
41961f28255Scgd dungeon[*row][*col] = DOOR;
42061f28255Scgd }
42161f28255Scgd if ((cur_level > 2) && rand_percent(HIDE_PERCENT)) {
42261f28255Scgd dungeon[*row][*col] |= HIDDEN;
42361f28255Scgd }
42461f28255Scgd rm->doors[dir/2].door_row = *row;
42561f28255Scgd rm->doors[dir/2].door_col = *col;
42661f28255Scgd }
42761f28255Scgd
428*130a8172Sdholland static void
draw_simple_passage(short row1,short col1,short row2,short col2,short dir)429*130a8172Sdholland draw_simple_passage(short row1, short col1, short row2, short col2, short dir)
43061f28255Scgd {
43161f28255Scgd short i, middle, t;
43261f28255Scgd
43361f28255Scgd if ((dir == LEFT) || (dir == RIGHT)) {
43461f28255Scgd if (col1 > col2) {
435*130a8172Sdholland SWAP(row1, row2);
436*130a8172Sdholland SWAP(col1, col2);
43761f28255Scgd }
43861f28255Scgd middle = get_rand(col1+1, col2-1);
43961f28255Scgd for (i = col1+1; i != middle; i++) {
44061f28255Scgd dungeon[row1][i] = TUNNEL;
44161f28255Scgd }
44261f28255Scgd for (i = row1; i != row2; i += (row1 > row2) ? -1 : 1) {
44361f28255Scgd dungeon[i][middle] = TUNNEL;
44461f28255Scgd }
44561f28255Scgd for (i = middle; i != col2; i++) {
44661f28255Scgd dungeon[row2][i] = TUNNEL;
44761f28255Scgd }
44861f28255Scgd } else {
44961f28255Scgd if (row1 > row2) {
450*130a8172Sdholland SWAP(row1, row2);
451*130a8172Sdholland SWAP(col1, col2);
45261f28255Scgd }
45361f28255Scgd middle = get_rand(row1+1, row2-1);
45461f28255Scgd for (i = row1+1; i != middle; i++) {
45561f28255Scgd dungeon[i][col1] = TUNNEL;
45661f28255Scgd }
45761f28255Scgd for (i = col1; i != col2; i += (col1 > col2) ? -1 : 1) {
45861f28255Scgd dungeon[middle][i] = TUNNEL;
45961f28255Scgd }
46061f28255Scgd for (i = middle; i != row2; i++) {
46161f28255Scgd dungeon[i][col2] = TUNNEL;
46261f28255Scgd }
46361f28255Scgd }
46461f28255Scgd if (rand_percent(HIDE_PERCENT)) {
46561f28255Scgd hide_boxed_passage(row1, col1, row2, col2, 1);
46661f28255Scgd }
46761f28255Scgd }
46861f28255Scgd
469*130a8172Sdholland static int
same_row(int room1,int room2)470*130a8172Sdholland same_row(int room1, int room2)
47161f28255Scgd {
47261f28255Scgd return((room1 / 3) == (room2 / 3));
47361f28255Scgd }
47461f28255Scgd
475*130a8172Sdholland static int
same_col(int room1,int room2)476*130a8172Sdholland same_col(int room1, int room2)
47761f28255Scgd {
47861f28255Scgd return((room1 % 3) == (room2 % 3));
47961f28255Scgd }
48061f28255Scgd
481*130a8172Sdholland static void
add_mazes(void)482*130a8172Sdholland add_mazes(void)
48361f28255Scgd {
48461f28255Scgd short i, j;
48561f28255Scgd short start;
48661f28255Scgd short maze_percent;
48761f28255Scgd
48861f28255Scgd if (cur_level > 1) {
48961f28255Scgd start = get_rand(0, (MAXROOMS-1));
49061f28255Scgd maze_percent = (cur_level * 5) / 4;
49161f28255Scgd
49261f28255Scgd if (cur_level > 15) {
49361f28255Scgd maze_percent += cur_level;
49461f28255Scgd }
49561f28255Scgd for (i = 0; i < MAXROOMS; i++) {
49661f28255Scgd j = ((start + i) % MAXROOMS);
49761f28255Scgd if (rooms[j].is_room & R_NOTHING) {
49861f28255Scgd if (rand_percent(maze_percent)) {
49961f28255Scgd rooms[j].is_room = R_MAZE;
50061f28255Scgd make_maze(get_rand(rooms[j].top_row+1, rooms[j].bottom_row-1),
50161f28255Scgd get_rand(rooms[j].left_col+1, rooms[j].right_col-1),
50261f28255Scgd rooms[j].top_row, rooms[j].bottom_row,
50361f28255Scgd rooms[j].left_col, rooms[j].right_col);
50461f28255Scgd hide_boxed_passage(rooms[j].top_row, rooms[j].left_col,
50561f28255Scgd rooms[j].bottom_row, rooms[j].right_col,
50661f28255Scgd get_rand(0, 2));
50761f28255Scgd }
50861f28255Scgd }
50961f28255Scgd }
51061f28255Scgd }
51161f28255Scgd }
51261f28255Scgd
513*130a8172Sdholland static void
fill_out_level(void)514*130a8172Sdholland fill_out_level(void)
51561f28255Scgd {
51661f28255Scgd short i, rn;
51761f28255Scgd
51861f28255Scgd mix_random_rooms();
51961f28255Scgd
52061f28255Scgd r_de = NO_ROOM;
52161f28255Scgd
52261f28255Scgd for (i = 0; i < MAXROOMS; i++) {
52361f28255Scgd rn = random_rooms[i];
52461f28255Scgd if ((rooms[rn].is_room & R_NOTHING) ||
52561f28255Scgd ((rooms[rn].is_room & R_CROSS) && coin_toss())) {
52661f28255Scgd fill_it(rn, 1);
52761f28255Scgd }
52861f28255Scgd }
52961f28255Scgd if (r_de != NO_ROOM) {
53061f28255Scgd fill_it(r_de, 0);
53161f28255Scgd }
53261f28255Scgd }
53361f28255Scgd
534*130a8172Sdholland static void
fill_it(int rn,boolean do_rec_de)535*130a8172Sdholland fill_it(int rn, boolean do_rec_de)
53661f28255Scgd {
53761f28255Scgd short i, tunnel_dir, door_dir, drow, dcol;
53861f28255Scgd short target_room, rooms_found = 0;
53961f28255Scgd short srow, scol, t;
54061f28255Scgd static short offsets[4] = {-1, 1, 3, -3};
54161f28255Scgd boolean did_this = 0;
54261f28255Scgd
54361f28255Scgd for (i = 0; i < 10; i++) {
54461f28255Scgd srow = get_rand(0, 3);
54561f28255Scgd scol = get_rand(0, 3);
54661f28255Scgd t = offsets[srow];
54761f28255Scgd offsets[srow] = offsets[scol];
54861f28255Scgd offsets[scol] = t;
54961f28255Scgd }
55061f28255Scgd for (i = 0; i < 4; i++) {
55161f28255Scgd
55261f28255Scgd target_room = rn + offsets[i];
55361f28255Scgd
55461f28255Scgd if (((target_room < 0) || (target_room >= MAXROOMS)) ||
55561f28255Scgd (!(same_row(rn,target_room) || same_col(rn,target_room))) ||
55661f28255Scgd (!(rooms[target_room].is_room & (R_ROOM | R_MAZE)))) {
55761f28255Scgd continue;
55861f28255Scgd }
55961f28255Scgd if (same_row(rn, target_room)) {
56061f28255Scgd tunnel_dir = (rooms[rn].left_col < rooms[target_room].left_col) ?
56161f28255Scgd RIGHT : LEFT;
56261f28255Scgd } else {
56361f28255Scgd tunnel_dir = (rooms[rn].top_row < rooms[target_room].top_row) ?
56461f28255Scgd DOWN : UPWARD;
56561f28255Scgd }
56661f28255Scgd door_dir = ((tunnel_dir + 4) % DIRS);
56761f28255Scgd if (rooms[target_room].doors[door_dir/2].oth_room != NO_ROOM) {
56861f28255Scgd continue;
56961f28255Scgd }
57061f28255Scgd if (((!do_rec_de) || did_this) ||
57161f28255Scgd (!mask_room(rn, &srow, &scol, TUNNEL))) {
57261f28255Scgd srow = (rooms[rn].top_row + rooms[rn].bottom_row) / 2;
57361f28255Scgd scol = (rooms[rn].left_col + rooms[rn].right_col) / 2;
57461f28255Scgd }
57561f28255Scgd put_door(&rooms[target_room], door_dir, &drow, &dcol);
57661f28255Scgd rooms_found++;
57761f28255Scgd draw_simple_passage(srow, scol, drow, dcol, tunnel_dir);
57861f28255Scgd rooms[rn].is_room = R_DEADEND;
57961f28255Scgd dungeon[srow][scol] = TUNNEL;
58061f28255Scgd
58161f28255Scgd if ((i < 3) && (!did_this)) {
58261f28255Scgd did_this = 1;
58361f28255Scgd if (coin_toss()) {
58461f28255Scgd continue;
58561f28255Scgd }
58661f28255Scgd }
58761f28255Scgd if ((rooms_found < 2) && do_rec_de) {
58861f28255Scgd recursive_deadend(rn, offsets, srow, scol);
58961f28255Scgd }
59061f28255Scgd break;
59161f28255Scgd }
59261f28255Scgd }
59361f28255Scgd
594*130a8172Sdholland static void
recursive_deadend(short rn,const short * offsets,short srow,short scol)595*130a8172Sdholland recursive_deadend(short rn, const short *offsets, short srow, short scol)
59661f28255Scgd {
59761f28255Scgd short i, de;
59861f28255Scgd short drow, dcol, tunnel_dir;
59961f28255Scgd
60061f28255Scgd rooms[rn].is_room = R_DEADEND;
60161f28255Scgd dungeon[srow][scol] = TUNNEL;
60261f28255Scgd
60361f28255Scgd for (i = 0; i < 4; i++) {
60461f28255Scgd de = rn + offsets[i];
60561f28255Scgd if (((de < 0) || (de >= MAXROOMS)) ||
60661f28255Scgd (!(same_row(rn, de) || same_col(rn, de)))) {
60761f28255Scgd continue;
60861f28255Scgd }
60961f28255Scgd if (!(rooms[de].is_room & R_NOTHING)) {
61061f28255Scgd continue;
61161f28255Scgd }
61261f28255Scgd drow = (rooms[de].top_row + rooms[de].bottom_row) / 2;
61361f28255Scgd dcol = (rooms[de].left_col + rooms[de].right_col) / 2;
61461f28255Scgd if (same_row(rn, de)) {
61561f28255Scgd tunnel_dir = (rooms[rn].left_col < rooms[de].left_col) ?
61661f28255Scgd RIGHT : LEFT;
61761f28255Scgd } else {
61861f28255Scgd tunnel_dir = (rooms[rn].top_row < rooms[de].top_row) ?
61961f28255Scgd DOWN : UPWARD;
62061f28255Scgd }
62161f28255Scgd draw_simple_passage(srow, scol, drow, dcol, tunnel_dir);
62261f28255Scgd r_de = de;
62361f28255Scgd recursive_deadend(de, offsets, drow, dcol);
62461f28255Scgd }
62561f28255Scgd }
62661f28255Scgd
627*130a8172Sdholland static boolean
mask_room(short rn,short * row,short * col,unsigned short mask)628*130a8172Sdholland mask_room(short rn, short *row, short *col, unsigned short mask)
62961f28255Scgd {
63061f28255Scgd short i, j;
63161f28255Scgd
63261f28255Scgd for (i = rooms[rn].top_row; i <= rooms[rn].bottom_row; i++) {
63361f28255Scgd for (j = rooms[rn].left_col; j <= rooms[rn].right_col; j++) {
63461f28255Scgd if (dungeon[i][j] & mask) {
63561f28255Scgd *row = i;
63661f28255Scgd *col = j;
63761f28255Scgd return(1);
63861f28255Scgd }
63961f28255Scgd }
64061f28255Scgd }
64161f28255Scgd return(0);
64261f28255Scgd }
64361f28255Scgd
644*130a8172Sdholland static void
make_maze(short r,short c,short tr,short br,short lc,short rc)645*130a8172Sdholland make_maze(short r, short c, short tr, short br, short lc, short rc)
64661f28255Scgd {
64761f28255Scgd char dirs[4];
64861f28255Scgd short i, t;
64961f28255Scgd
65061f28255Scgd dirs[0] = UPWARD;
65161f28255Scgd dirs[1] = DOWN;
65261f28255Scgd dirs[2] = LEFT;
65361f28255Scgd dirs[3] = RIGHT;
65461f28255Scgd
65561f28255Scgd dungeon[r][c] = TUNNEL;
65661f28255Scgd
65761f28255Scgd if (rand_percent(20)) {
65861f28255Scgd for (i = 0; i < 10; i++) {
65961f28255Scgd short t1, t2;
66061f28255Scgd
66161f28255Scgd t1 = get_rand(0, 3);
66261f28255Scgd t2 = get_rand(0, 3);
66361f28255Scgd
664*130a8172Sdholland SWAP(dirs[t1], dirs[t2]);
66561f28255Scgd }
66661f28255Scgd }
66761f28255Scgd for (i = 0; i < 4; i++) {
66861f28255Scgd switch(dirs[i]) {
66961f28255Scgd case UPWARD:
67061f28255Scgd if (((r-1) >= tr) &&
67161f28255Scgd (dungeon[r-1][c] != TUNNEL) &&
67261f28255Scgd (dungeon[r-1][c-1] != TUNNEL) &&
67361f28255Scgd (dungeon[r-1][c+1] != TUNNEL) &&
67461f28255Scgd (dungeon[r-2][c] != TUNNEL)) {
67561f28255Scgd make_maze((r-1), c, tr, br, lc, rc);
67661f28255Scgd }
67761f28255Scgd break;
67861f28255Scgd case DOWN:
67961f28255Scgd if (((r+1) <= br) &&
68061f28255Scgd (dungeon[r+1][c] != TUNNEL) &&
68161f28255Scgd (dungeon[r+1][c-1] != TUNNEL) &&
68261f28255Scgd (dungeon[r+1][c+1] != TUNNEL) &&
68361f28255Scgd (dungeon[r+2][c] != TUNNEL)) {
68461f28255Scgd make_maze((r+1), c, tr, br, lc, rc);
68561f28255Scgd }
68661f28255Scgd break;
68761f28255Scgd case LEFT:
68861f28255Scgd if (((c-1) >= lc) &&
68961f28255Scgd (dungeon[r][c-1] != TUNNEL) &&
69061f28255Scgd (dungeon[r-1][c-1] != TUNNEL) &&
69161f28255Scgd (dungeon[r+1][c-1] != TUNNEL) &&
69261f28255Scgd (dungeon[r][c-2] != TUNNEL)) {
69361f28255Scgd make_maze(r, (c-1), tr, br, lc, rc);
69461f28255Scgd }
69561f28255Scgd break;
69661f28255Scgd case RIGHT:
69761f28255Scgd if (((c+1) <= rc) &&
69861f28255Scgd (dungeon[r][c+1] != TUNNEL) &&
69961f28255Scgd (dungeon[r-1][c+1] != TUNNEL) &&
70061f28255Scgd (dungeon[r+1][c+1] != TUNNEL) &&
70161f28255Scgd (dungeon[r][c+2] != TUNNEL)) {
70261f28255Scgd make_maze(r, (c+1), tr, br, lc, rc);
70361f28255Scgd }
70461f28255Scgd break;
70561f28255Scgd }
70661f28255Scgd }
70761f28255Scgd }
70861f28255Scgd
709*130a8172Sdholland static void
hide_boxed_passage(short row1,short col1,short row2,short col2,short n)710*130a8172Sdholland hide_boxed_passage(short row1, short col1, short row2, short col2, short n)
71161f28255Scgd {
71261f28255Scgd short i, j, t;
71361f28255Scgd short row, col, row_cut, col_cut;
71461f28255Scgd short h, w;
71561f28255Scgd
71661f28255Scgd if (cur_level > 2) {
71761f28255Scgd if (row1 > row2) {
718*130a8172Sdholland SWAP(row1, row2);
71961f28255Scgd }
72061f28255Scgd if (col1 > col2) {
721*130a8172Sdholland SWAP(col1, col2);
72261f28255Scgd }
72361f28255Scgd h = row2 - row1;
72461f28255Scgd w = col2 - col1;
72561f28255Scgd
72661f28255Scgd if ((w >= 5) || (h >= 5)) {
72761f28255Scgd row_cut = ((h >= 2) ? 1 : 0);
72861f28255Scgd col_cut = ((w >= 2) ? 1 : 0);
72961f28255Scgd
73061f28255Scgd for (i = 0; i < n; i++) {
73161f28255Scgd for (j = 0; j < 10; j++) {
73261f28255Scgd row = get_rand(row1 + row_cut, row2 - row_cut);
73361f28255Scgd col = get_rand(col1 + col_cut, col2 - col_cut);
73461f28255Scgd if (dungeon[row][col] == TUNNEL) {
73561f28255Scgd dungeon[row][col] |= HIDDEN;
73661f28255Scgd break;
73761f28255Scgd }
73861f28255Scgd }
73961f28255Scgd }
74061f28255Scgd }
74161f28255Scgd }
74261f28255Scgd }
74361f28255Scgd
744*130a8172Sdholland /*
745*130a8172Sdholland * try not to put in room NR
746*130a8172Sdholland */
7472736b511Slukem void
put_player(short nr)748*130a8172Sdholland put_player(short nr)
74961f28255Scgd {
75061f28255Scgd short rn = nr, misses;
75161f28255Scgd short row, col;
75261f28255Scgd
75361f28255Scgd for (misses = 0; ((misses < 2) && (rn == nr)); misses++) {
75461f28255Scgd gr_row_col(&row, &col, (FLOOR | TUNNEL | OBJECT | STAIRS));
75561f28255Scgd rn = get_room_number(row, col);
75661f28255Scgd }
75761f28255Scgd rogue.row = row;
75861f28255Scgd rogue.col = col;
75961f28255Scgd
76061f28255Scgd if (dungeon[rogue.row][rogue.col] & TUNNEL) {
76161f28255Scgd cur_room = PASSAGE;
76261f28255Scgd } else {
76361f28255Scgd cur_room = rn;
76461f28255Scgd }
76561f28255Scgd if (cur_room != PASSAGE) {
76661f28255Scgd light_up_room(cur_room);
76761f28255Scgd } else {
76861f28255Scgd light_passage(rogue.row, rogue.col);
76961f28255Scgd }
77061f28255Scgd rn = get_room_number(rogue.row, rogue.col);
77161f28255Scgd wake_room(rn, 1, rogue.row, rogue.col);
77261f28255Scgd if (new_level_message) {
773e94a5bc9Sdholland messagef(0, "%s", new_level_message);
774e94a5bc9Sdholland new_level_message = NULL;
77561f28255Scgd }
77661f28255Scgd mvaddch(rogue.row, rogue.col, rogue.fchar);
77761f28255Scgd }
77861f28255Scgd
7792736b511Slukem int
drop_check(void)780*130a8172Sdholland drop_check(void)
78161f28255Scgd {
78261f28255Scgd if (wizard) {
78361f28255Scgd return(1);
78461f28255Scgd }
78561f28255Scgd if (dungeon[rogue.row][rogue.col] & STAIRS) {
78661f28255Scgd if (levitate) {
787e94a5bc9Sdholland messagef(0, "you're floating in the air!");
78861f28255Scgd return(0);
78961f28255Scgd }
79061f28255Scgd return(1);
79161f28255Scgd }
792e94a5bc9Sdholland messagef(0, "I see no way down");
79361f28255Scgd return(0);
79461f28255Scgd }
79561f28255Scgd
7962736b511Slukem int
check_up(void)797*130a8172Sdholland check_up(void)
79861f28255Scgd {
79961f28255Scgd if (!wizard) {
80061f28255Scgd if (!(dungeon[rogue.row][rogue.col] & STAIRS)) {
801e94a5bc9Sdholland messagef(0, "I see no way up");
80261f28255Scgd return(0);
80361f28255Scgd }
80461f28255Scgd if (!has_amulet()) {
805e94a5bc9Sdholland messagef(0, "your way is magically blocked");
80661f28255Scgd return(0);
80761f28255Scgd }
80861f28255Scgd }
80961f28255Scgd new_level_message = "you feel a wrenching sensation in your gut";
81061f28255Scgd if (cur_level == 1) {
81161f28255Scgd win();
81261f28255Scgd } else {
81361f28255Scgd cur_level -= 2;
81461f28255Scgd return(1);
81561f28255Scgd }
81661f28255Scgd return(0);
81761f28255Scgd }
81861f28255Scgd
8192736b511Slukem void
add_exp(int e,boolean promotion)820*130a8172Sdholland add_exp(int e, boolean promotion)
82161f28255Scgd {
82261f28255Scgd short new_exp;
82361f28255Scgd short i, hp;
82461f28255Scgd
82561f28255Scgd rogue.exp_points += e;
82661f28255Scgd
82761f28255Scgd if (rogue.exp_points >= level_points[rogue.exp-1]) {
82861f28255Scgd new_exp = get_exp_level(rogue.exp_points);
82961f28255Scgd if (rogue.exp_points > MAX_EXP) {
83061f28255Scgd rogue.exp_points = MAX_EXP + 1;
83161f28255Scgd }
83261f28255Scgd for (i = rogue.exp+1; i <= new_exp; i++) {
833e94a5bc9Sdholland messagef(0, "welcome to level %d", i);
83461f28255Scgd if (promotion) {
83561f28255Scgd hp = hp_raise();
83661f28255Scgd rogue.hp_current += hp;
83761f28255Scgd rogue.hp_max += hp;
83861f28255Scgd }
83961f28255Scgd rogue.exp = i;
84061f28255Scgd print_stats(STAT_HP | STAT_EXP);
84161f28255Scgd }
84261f28255Scgd } else {
84361f28255Scgd print_stats(STAT_EXP);
84461f28255Scgd }
84561f28255Scgd }
84661f28255Scgd
847*130a8172Sdholland static int
get_exp_level(long e)848*130a8172Sdholland get_exp_level(long e)
84961f28255Scgd {
85061f28255Scgd short i;
85161f28255Scgd
85261f28255Scgd for (i = 0; i < (MAX_EXP_LEVEL - 1); i++) {
85361f28255Scgd if (level_points[i] > e) {
85461f28255Scgd break;
85561f28255Scgd }
85661f28255Scgd }
85761f28255Scgd return(i+1);
85861f28255Scgd }
85961f28255Scgd
8602736b511Slukem int
hp_raise(void)861*130a8172Sdholland hp_raise(void)
86261f28255Scgd {
86361f28255Scgd int hp;
86461f28255Scgd
86561f28255Scgd hp = (wizard ? 10 : get_rand(3, 10));
86661f28255Scgd return(hp);
86761f28255Scgd }
86861f28255Scgd
8692736b511Slukem void
show_average_hp(void)870*130a8172Sdholland show_average_hp(void)
87161f28255Scgd {
87261f28255Scgd float real_average;
87361f28255Scgd float effective_average;
87461f28255Scgd
87561f28255Scgd if (rogue.exp == 1) {
87661f28255Scgd real_average = effective_average = 0.00;
87761f28255Scgd } else {
87861f28255Scgd real_average = (float)
87961f28255Scgd ((rogue.hp_max - extra_hp - INIT_HP) + less_hp) / (rogue.exp - 1);
88061f28255Scgd effective_average = (float)(rogue.hp_max - INIT_HP) / (rogue.exp - 1);
88161f28255Scgd
88261f28255Scgd }
883e94a5bc9Sdholland messagef(0, "R-Hp: %.2f, E-Hp: %.2f (!: %d, V: %d)", real_average,
88461f28255Scgd effective_average, extra_hp, less_hp);
88561f28255Scgd }
88661f28255Scgd
887*130a8172Sdholland static void
mix_random_rooms(void)888*130a8172Sdholland mix_random_rooms(void)
88961f28255Scgd {
89061f28255Scgd short i, t;
89161f28255Scgd short x, y;
89261f28255Scgd
89361f28255Scgd for (i = 0; i < (3 * MAXROOMS); i++) {
89461f28255Scgd do {
89561f28255Scgd x = get_rand(0, (MAXROOMS-1));
89661f28255Scgd y = get_rand(0, (MAXROOMS-1));
89761f28255Scgd } while (x == y);
898*130a8172Sdholland SWAP(random_rooms[x], random_rooms[y]);
89961f28255Scgd }
90061f28255Scgd }
901