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