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