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
make_level(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
make_room(short rn,short r1,short r2,short r3)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
connect_rooms(short room1,short room2)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
clear_level(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
put_door(room * rm,short dir,short * row,short * col)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
draw_simple_passage(short row1,short col1,short row2,short col2,short dir)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
same_row(int room1,int room2)470 same_row(int room1, int room2)
471 {
472           return((room1 / 3) == (room2 / 3));
473 }
474 
475 static int
same_col(int room1,int room2)476 same_col(int room1, int room2)
477 {
478           return((room1 % 3) == (room2 % 3));
479 }
480 
481 static void
add_mazes(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
fill_out_level(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
fill_it(int rn,boolean do_rec_de)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
recursive_deadend(short rn,const short * offsets,short srow,short scol)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
mask_room(short rn,short * row,short * col,unsigned short mask)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
make_maze(short r,short c,short tr,short br,short lc,short rc)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
hide_boxed_passage(short row1,short col1,short row2,short col2,short n)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
put_player(short nr)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
drop_check(void)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
check_up(void)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
add_exp(int e,boolean promotion)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
get_exp_level(long e)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
hp_raise(void)861 hp_raise(void)
862 {
863           int hp;
864 
865           hp = (wizard ? 10 : get_rand(3, 10));
866           return(hp);
867 }
868 
869 void
show_average_hp(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
mix_random_rooms(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