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