OSDN Git Service

shrink mine
[nethackexpress/trunk.git] / src / sp_lev.c
1 /*      SCCS Id: @(#)sp_lev.c   3.4     2001/09/06      */
2 /*      Copyright (c) 1989 by Jean-Christophe Collet */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /*
6  * This file contains the various functions that are related to the special
7  * levels.
8  * It contains also the special level loader.
9  *
10  */
11
12 #include "hack.h"
13 #include "dlb.h"
14 /* #define DEBUG */     /* uncomment to enable code debugging */
15
16 #ifdef DEBUG
17 # ifdef WIZARD
18 #define debugpline      if (wizard) pline
19 # else
20 #define debugpline      pline
21 # endif
22 #endif
23
24 #include "sp_lev.h"
25 #include "rect.h"
26
27 extern void FDECL(mkmap, (lev_init *));
28
29 STATIC_DCL void FDECL(get_room_loc, (schar *, schar *, struct mkroom *));
30 STATIC_DCL void FDECL(get_free_room_loc, (schar *, schar *, struct mkroom *));
31 STATIC_DCL void FDECL(create_trap, (trap *, struct mkroom *));
32 STATIC_DCL int FDECL(noncoalignment, (ALIGNTYP_P));
33 STATIC_DCL void FDECL(create_monster, (monster *, struct mkroom *));
34 STATIC_DCL void FDECL(create_object, (object *, struct mkroom *));
35 STATIC_DCL void FDECL(create_engraving, (engraving *,struct mkroom *));
36 STATIC_DCL void FDECL(create_stairs, (stair *, struct mkroom *));
37 STATIC_DCL void FDECL(create_altar, (altar *, struct mkroom *));
38 STATIC_DCL void FDECL(create_gold, (gold *, struct mkroom *));
39 STATIC_DCL void FDECL(create_feature, (int,int,struct mkroom *,int));
40 STATIC_DCL boolean FDECL(search_door, (struct mkroom *, xchar *, xchar *,
41                                         XCHAR_P, int));
42 STATIC_DCL void NDECL(fix_stair_rooms);
43 STATIC_DCL void FDECL(create_corridor, (corridor *));
44
45 STATIC_DCL boolean FDECL(create_subroom, (struct mkroom *, XCHAR_P, XCHAR_P,
46                                         XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P));
47
48 #define LEFT    1
49 #define H_LEFT  2
50 #define CENTER  3
51 #define H_RIGHT 4
52 #define RIGHT   5
53
54 #define TOP     1
55 #define BOTTOM  5
56
57 #define sq(x) ((x)*(x))
58
59 #define XLIM    4
60 #define YLIM    3
61
62 #define Fread   (void)dlb_fread
63 #define Fgetc   (schar)dlb_fgetc
64 #define New(type)               (type *) alloc(sizeof(type))
65 #define NewTab(type, size)      (type **) alloc(sizeof(type *) * (unsigned)size)
66 #define Free(ptr)               if(ptr) free((genericptr_t) (ptr))
67
68 static NEARDATA walk walklist[50];
69 extern int min_rx, max_rx, min_ry, max_ry; /* from mkmap.c */
70
71 static char Map[COLNO][ROWNO];
72 static char robjects[10], rloc_x[10], rloc_y[10], rmonst[10];
73 static aligntyp ralign[3] = { AM_CHAOTIC, AM_NEUTRAL, AM_LAWFUL };
74 static NEARDATA xchar xstart, ystart;
75 static NEARDATA char xsize, ysize;
76
77 STATIC_DCL void FDECL(set_wall_property, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,int));
78 STATIC_DCL int NDECL(rnddoor);
79 STATIC_DCL int NDECL(rndtrap);
80 STATIC_DCL void FDECL(get_location, (schar *,schar *,int));
81 STATIC_DCL void FDECL(sp_lev_shuffle, (char *,char *,int));
82 STATIC_DCL void FDECL(light_region, (region *));
83 STATIC_DCL void FDECL(load_common_data, (dlb *,int));
84 STATIC_DCL void FDECL(load_one_monster, (dlb *,monster *));
85 STATIC_DCL void FDECL(load_one_object, (dlb *,object *));
86 STATIC_DCL void FDECL(load_one_engraving, (dlb *,engraving *));
87 STATIC_DCL boolean FDECL(load_rooms, (dlb *));
88 STATIC_DCL void FDECL(maze1xy, (coord *,int));
89 STATIC_DCL boolean FDECL(load_maze, (dlb *));
90 STATIC_DCL void FDECL(create_door, (room_door *, struct mkroom *));
91 STATIC_DCL void FDECL(free_rooms,(room **, int));
92 STATIC_DCL void FDECL(build_room, (room *, room*));
93
94 char *lev_message = 0;
95 lev_region *lregions = 0;
96 int num_lregions = 0;
97 lev_init init_lev;
98
99 /*
100  * Make walls of the area (x1, y1, x2, y2) non diggable/non passwall-able
101  */
102
103 STATIC_OVL void
104 set_wall_property(x1,y1,x2,y2, prop)
105 xchar x1, y1, x2, y2;
106 int prop;
107 {
108         register xchar x, y;
109
110         for(y = y1; y <= y2; y++)
111             for(x = x1; x <= x2; x++)
112                 if(IS_STWALL(levl[x][y].typ))
113                     levl[x][y].wall_info |= prop;
114 }
115
116 /*
117  * Choose randomly the state (nodoor, open, closed or locked) for a door
118  */
119 STATIC_OVL int
120 rnddoor()
121 {
122         int i = 1 << rn2(5);
123         i >>= 1;
124         return i;
125 }
126
127 /*
128  * Select a random trap
129  */
130 STATIC_OVL int
131 rndtrap()
132 {
133         int rtrap;
134
135         do {
136             rtrap = rnd(TRAPNUM-1);
137             switch (rtrap) {
138              case HOLE:         /* no random holes on special levels */
139              case MAGIC_PORTAL: rtrap = NO_TRAP;
140                                 break;
141              case TRAPDOOR:     if (!Can_dig_down(&u.uz)) rtrap = NO_TRAP;
142                                 break;
143              case LEVEL_TELEP:
144              case TELEP_TRAP:   if (level.flags.noteleport) rtrap = NO_TRAP;
145                                 break;
146              case ROLLING_BOULDER_TRAP:
147              case ROCKTRAP:     if (In_endgame(&u.uz)) rtrap = NO_TRAP;
148                                 break;
149             }
150         } while (rtrap == NO_TRAP);
151         return rtrap;
152 }
153
154 /*
155  * Coordinates in special level files are handled specially:
156  *
157  *      if x or y is -11, we generate a random coordinate.
158  *      if x or y is between -1 and -10, we read one from the corresponding
159  *      register (x0, x1, ... x9).
160  *      if x or y is nonnegative, we convert it from relative to the local map
161  *      to global coordinates.
162  *      The "humidity" flag is used to insure that engravings aren't
163  *      created underwater, or eels on dry land.
164  */
165 #define DRY     0x1
166 #define WET     0x2
167
168 STATIC_DCL boolean FDECL(is_ok_location, (SCHAR_P, SCHAR_P, int));
169
170 STATIC_OVL void
171 get_location(x, y, humidity)
172 schar *x, *y;
173 int humidity;
174 {
175         int cpt = 0;
176
177         if (*x >= 0) {                  /* normal locations */
178                 *x += xstart;
179                 *y += ystart;
180         } else if (*x > -11) {          /* special locations */
181                 *y = ystart + rloc_y[ - *y - 1];
182                 *x = xstart + rloc_x[ - *x - 1];
183         } else {                        /* random location */
184             do {
185                 *x = xstart + rn2((int)xsize);
186                 *y = ystart + rn2((int)ysize);
187                 if (is_ok_location(*x,*y,humidity)) break;
188             } while (++cpt < 100);
189             if (cpt >= 100) {
190                 register int xx, yy;
191                 /* last try */
192                 for (xx = 0; xx < xsize; xx++)
193                     for (yy = 0; yy < ysize; yy++) {
194                         *x = xstart + xx;
195                         *y = ystart + yy;
196                         if (is_ok_location(*x,*y,humidity)) goto found_it;
197                     }
198                 panic("get_location:  can't find a place!");
199             }
200         }
201 found_it:;
202
203         if (!isok(*x,*y)) {
204             impossible("get_location:  (%d,%d) out of bounds", *x, *y);
205             *x = x_maze_max; *y = y_maze_max;
206         }
207 }
208
209 STATIC_OVL boolean
210 is_ok_location(x, y, humidity)
211 register schar x, y;
212 register int humidity;
213 {
214         register int typ;
215
216         if (Is_waterlevel(&u.uz)) return TRUE;  /* accept any spot */
217
218         if (humidity & DRY) {
219             typ = levl[x][y].typ;
220             if (typ == ROOM || typ == AIR ||
221                     typ == CLOUD || typ == ICE || typ == CORR)
222                 return TRUE;
223         }
224         if (humidity & WET) {
225             if (is_pool(x,y) || is_lava(x,y))
226                 return TRUE;
227         }
228         return FALSE;
229 }
230
231 /*
232  * Shuffle the registers for locations, objects or monsters
233  */
234
235 STATIC_OVL void
236 sp_lev_shuffle(list1, list2, n)
237 char list1[], list2[];
238 int n;
239 {
240         register int i, j;
241         register char k;
242
243         for (i = n - 1; i > 0; i--) {
244                 if ((j = rn2(i + 1)) == i) continue;
245                 k = list1[j];
246                 list1[j] = list1[i];
247                 list1[i] = k;
248                 if (list2) {
249                         k = list2[j];
250                         list2[j] = list2[i];
251                         list2[i] = k;
252                 }
253         }
254 }
255
256 /*
257  * Get a relative position inside a room.
258  * negative values for x or y means RANDOM!
259  */
260
261 STATIC_OVL void
262 get_room_loc(x,y, croom)
263 schar           *x, *y;
264 struct mkroom   *croom;
265 {
266         coord c;
267
268         if (*x <0 && *y <0) {
269                 if (somexy(croom, &c)) {
270                         *x = c.x;
271                         *y = c.y;
272                 } else
273                     panic("get_room_loc : can't find a place!");
274         } else {
275                 if (*x < 0)
276                     *x = rn2(croom->hx - croom->lx + 1);
277                 if (*y < 0)
278                     *y = rn2(croom->hy - croom->ly + 1);
279                 *x += croom->lx;
280                 *y += croom->ly;
281         }
282 }
283
284 /*
285  * Get a relative position inside a room.
286  * negative values for x or y means RANDOM!
287  */
288
289 STATIC_OVL void
290 get_free_room_loc(x,y, croom)
291 schar           *x, *y;
292 struct mkroom   *croom;
293 {
294         schar try_x, try_y;
295         register int trycnt = 0;
296
297         do {
298             try_x = *x,  try_y = *y;
299             get_room_loc(&try_x, &try_y, croom);
300         } while (levl[try_x][try_y].typ != ROOM && ++trycnt <= 100);
301
302         if (trycnt > 100)
303             panic("get_free_room_loc:  can't find a place!");
304         *x = try_x,  *y = try_y;
305 }
306
307 boolean
308 check_room(lowx, ddx, lowy, ddy, vault)
309 xchar *lowx, *ddx, *lowy, *ddy;
310 boolean vault;
311 {
312         register int x,y,hix = *lowx + *ddx, hiy = *lowy + *ddy;
313         register struct rm *lev;
314         int xlim, ylim, ymax;
315
316         xlim = XLIM + (vault ? 1 : 0);
317         ylim = YLIM + (vault ? 1 : 0);
318
319         if (*lowx < 3)          *lowx = 3;
320         if (*lowy < 2)          *lowy = 2;
321         if (hix > COLNO-3)      hix = COLNO-3;
322         if (hiy > ROWNO-3)      hiy = ROWNO-3;
323 chk:
324         if (hix <= *lowx || hiy <= *lowy)       return FALSE;
325
326         /* check area around room (and make room smaller if necessary) */
327         for (x = *lowx - xlim; x<= hix + xlim; x++) {
328                 if(x <= 0 || x >= COLNO) continue;
329                 y = *lowy - ylim;       ymax = hiy + ylim;
330                 if(y < 0) y = 0;
331                 if(ymax >= ROWNO) ymax = (ROWNO-1);
332                 lev = &levl[x][y];
333                 for (; y <= ymax; y++) {
334                         if (lev++->typ) {
335 #ifdef DEBUG
336                                 if(!vault)
337                                     debugpline("strange area [%d,%d] in check_room.",x,y);
338 #endif
339                                 if (!rn2(3))    return FALSE;
340                                 if (x < *lowx)
341                                     *lowx = x + xlim + 1;
342                                 else
343                                     hix = x - xlim - 1;
344                                 if (y < *lowy)
345                                     *lowy = y + ylim + 1;
346                                 else
347                                     hiy = y - ylim - 1;
348                                 goto chk;
349                         }
350                 }
351         }
352         *ddx = hix - *lowx;
353         *ddy = hiy - *lowy;
354         return TRUE;
355 }
356
357 /*
358  * Create a new room.
359  * This is still very incomplete...
360  */
361
362 boolean
363 create_room(x,y,w,h,xal,yal,rtype,rlit)
364 xchar   x,y;
365 xchar   w,h;
366 xchar   xal,yal;
367 xchar   rtype, rlit;
368 {
369         xchar   xabs, yabs;
370         int     wtmp, htmp, xaltmp, yaltmp, xtmp, ytmp;
371         NhRect  *r1 = 0, r2;
372         int     trycnt = 0;
373         boolean vault = FALSE;
374         int     xlim = XLIM, ylim = YLIM;
375
376         if (rtype == -1)        /* Is the type random ? */
377             rtype = OROOM;
378
379         if (rtype == VAULT) {
380                 vault = TRUE;
381                 xlim++;
382                 ylim++;
383         }
384
385         /* on low levels the room is lit (usually) */
386         /* some other rooms may require lighting */
387
388         /* is light state random ? */
389         if (rlit == -1)
390             rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE;
391
392         /*
393          * Here we will try to create a room. If some parameters are
394          * random we are willing to make several try before we give
395          * it up.
396          */
397         do {
398                 xchar xborder, yborder;
399                 wtmp = w; htmp = h;
400                 xtmp = x; ytmp = y;
401                 xaltmp = xal; yaltmp = yal;
402
403                 /* First case : a totaly random room */
404
405                 if((xtmp < 0 && ytmp <0 && wtmp < 0 && xaltmp < 0 &&
406                    yaltmp < 0) || vault) {
407                         xchar hx, hy, lx, ly, dx, dy;
408                         r1 = rnd_rect(); /* Get a random rectangle */
409
410                         if (!r1) { /* No more free rectangles ! */
411 #ifdef DEBUG
412                                 debugpline("No more rects...");
413 #endif
414                                 return FALSE;
415                         }
416                         hx = r1->hx;
417                         hy = r1->hy;
418                         lx = r1->lx;
419                         ly = r1->ly;
420                         if (vault)
421                             dx = dy = 1;
422                         else {
423                                 dx = 2 + rn2((hx-lx > 28) ? 12 : 8);
424                                 dy = 2 + rn2(4);
425                                 if(dx*dy > 50)
426                                     dy = 50/dx;
427                         }
428                         xborder = (lx > 0 && hx < COLNO -1) ? 2*xlim : xlim+1;
429                         yborder = (ly > 0 && hy < ROWNO -1) ? 2*ylim : ylim+1;
430                         if(hx-lx < dx + 3 + xborder ||
431                            hy-ly < dy + 3 + yborder) {
432                                 r1 = 0;
433                                 continue;
434                         }
435                         xabs = lx + (lx > 0 ? xlim : 3)
436                             + rn2(hx - (lx>0?lx : 3) - dx - xborder + 1);
437                         yabs = ly + (ly > 0 ? ylim : 2)
438                             + rn2(hy - (ly>0?ly : 2) - dy - yborder + 1);
439                         if (ly == 0 && hy >= (ROWNO-1) &&
440                             (!nroom || !rn2(nroom)) && (yabs+dy > ROWNO/2)) {
441                             yabs = rn1(3, 2);
442                             if(nroom < 4 && dy>1) dy--;
443                         }
444                         if (!check_room(&xabs, &dx, &yabs, &dy, vault)) {
445                                 r1 = 0;
446                                 continue;
447                         }
448                         wtmp = dx+1;
449                         htmp = dy+1;
450                         r2.lx = xabs-1; r2.ly = yabs-1;
451                         r2.hx = xabs + wtmp;
452                         r2.hy = yabs + htmp;
453                 } else {        /* Only some parameters are random */
454                         int rndpos = 0;
455                         if (xtmp < 0 && ytmp < 0) { /* Position is RANDOM */
456                                 xtmp = rnd(5);
457                                 ytmp = rnd(5);
458                                 rndpos = 1;
459                         }
460                         if (wtmp < 0 || htmp < 0) { /* Size is RANDOM */
461                                 wtmp = rn1(15, 3);
462                                 htmp = rn1(8, 2);
463                         }
464                         if (xaltmp == -1) /* Horizontal alignment is RANDOM */
465                             xaltmp = rnd(3);
466                         if (yaltmp == -1) /* Vertical alignment is RANDOM */
467                             yaltmp = rnd(3);
468
469                         /* Try to generate real (absolute) coordinates here! */
470
471                         xabs = (((xtmp-1) * COLNO) / 5) + 1;
472                         yabs = (((ytmp-1) * ROWNO) / 5) + 1;
473                         switch (xaltmp) {
474                               case LEFT:
475                                 break;
476                               case RIGHT:
477                                 xabs += (COLNO / 5) - wtmp;
478                                 break;
479                               case CENTER:
480                                 xabs += ((COLNO / 5) - wtmp) / 2;
481                                 break;
482                         }
483                         switch (yaltmp) {
484                               case TOP:
485                                 break;
486                               case BOTTOM:
487                                 yabs += (ROWNO / 5) - htmp;
488                                 break;
489                               case CENTER:
490                                 yabs += ((ROWNO / 5) - htmp) / 2;
491                                 break;
492                         }
493
494                         if (xabs + wtmp - 1 > COLNO - 2)
495                             xabs = COLNO - wtmp - 3;
496                         if (xabs < 2)
497                             xabs = 2;
498                         if (yabs + htmp - 1> ROWNO - 2)
499                             yabs = ROWNO - htmp - 3;
500                         if (yabs < 2)
501                             yabs = 2;
502
503                         /* Try to find a rectangle that fit our room ! */
504
505                         r2.lx = xabs-1; r2.ly = yabs-1;
506                         r2.hx = xabs + wtmp + rndpos;
507                         r2.hy = yabs + htmp + rndpos;
508                         r1 = get_rect(&r2);
509                 }
510         } while (++trycnt <= 100 && !r1);
511         if (!r1) {      /* creation of room failed ? */
512                 return FALSE;
513         }
514         split_rects(r1, &r2);
515
516         if (!vault) {
517                 smeq[nroom] = nroom;
518                 add_room(xabs, yabs, xabs+wtmp-1, yabs+htmp-1,
519                          rlit, rtype, FALSE);
520         } else {
521                 rooms[nroom].lx = xabs;
522                 rooms[nroom].ly = yabs;
523         }
524         return TRUE;
525 }
526
527 /*
528  * Create a subroom in room proom at pos x,y with width w & height h.
529  * x & y are relative to the parent room.
530  */
531
532 STATIC_OVL boolean
533 create_subroom(proom, x, y, w,  h, rtype, rlit)
534 struct mkroom *proom;
535 xchar x,y;
536 xchar w,h;
537 xchar rtype, rlit;
538 {
539         xchar width, height;
540
541         width = proom->hx - proom->lx + 1;
542         height = proom->hy - proom->ly + 1;
543
544         /* There is a minimum size for the parent room */
545         if (width < 4 || height < 4)
546             return FALSE;
547
548         /* Check for random position, size, etc... */
549
550         if (w == -1)
551             w = rnd(width - 3);
552         if (h == -1)
553             h = rnd(height - 3);
554         if (x == -1)
555             x = rnd(width - w - 1) - 1;
556         if (y == -1)
557             y = rnd(height - h - 1) - 1;
558         if (x == 1)
559             x = 0;
560         if (y == 1)
561             y = 0;
562         if ((x + w + 1) == width)
563             x++;
564         if ((y + h + 1) == height)
565             y++;
566         if (rtype == -1)
567             rtype = OROOM;
568         if (rlit == -1)
569             rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE;
570         add_subroom(proom, proom->lx + x, proom->ly + y,
571                     proom->lx + x + w - 1, proom->ly + y + h - 1,
572                     rlit, rtype, FALSE);
573         return TRUE;
574 }
575
576 /*
577  * Create a new door in a room.
578  * It's placed on a wall (north, south, east or west).
579  */
580
581 STATIC_OVL void
582 create_door(dd, broom)
583 room_door *dd;
584 struct mkroom *broom;
585 {
586         int     x, y;
587         int     trycnt = 0;
588
589         if (dd->secret == -1)
590             dd->secret = rn2(2);
591
592         if (dd->mask == -1) {
593                 /* is it a locked door, closed, or a doorway? */
594                 if (!dd->secret) {
595                         if(!rn2(3)) {
596                                 if(!rn2(5))
597                                     dd->mask = D_ISOPEN;
598                                 else if(!rn2(6))
599                                     dd->mask = D_LOCKED;
600                                 else
601                                     dd->mask = D_CLOSED;
602                                 if (dd->mask != D_ISOPEN && !rn2(25))
603                                     dd->mask |= D_TRAPPED;
604                         } else
605                             dd->mask = D_NODOOR;
606                 } else {
607                         if(!rn2(5))     dd->mask = D_LOCKED;
608                         else            dd->mask = D_CLOSED;
609
610                         if(!rn2(20)) dd->mask |= D_TRAPPED;
611                 }
612         }
613
614         do {
615                 register int dwall, dpos;
616
617                 dwall = dd->wall;
618                 if (dwall == -1)        /* The wall is RANDOM */
619                     dwall = 1 << rn2(4);
620
621                 dpos = dd->pos;
622                 if (dpos == -1) /* The position is RANDOM */
623                     dpos = rn2((dwall == W_WEST || dwall == W_EAST) ?
624                             (broom->hy - broom->ly) : (broom->hx - broom->lx));
625
626                 /* Convert wall and pos into an absolute coordinate! */
627
628                 switch (dwall) {
629                       case W_NORTH:
630                         y = broom->ly - 1;
631                         x = broom->lx + dpos;
632                         break;
633                       case W_SOUTH:
634                         y = broom->hy + 1;
635                         x = broom->lx + dpos;
636                         break;
637                       case W_WEST:
638                         x = broom->lx - 1;
639                         y = broom->ly + dpos;
640                         break;
641                       case W_EAST:
642                         x = broom->hx + 1;
643                         y = broom->ly + dpos;
644                         break;
645                       default:
646                         x = y = 0;
647                         panic("create_door: No wall for door!");
648                         break;
649                 }
650                 if (okdoor(x,y))
651                     break;
652         } while (++trycnt <= 100);
653         if (trycnt > 100) {
654                 impossible("create_door: Can't find a proper place!");
655                 return;
656         }
657         add_door(x,y,broom);
658         levl[x][y].typ = (dd->secret ? SDOOR : DOOR);
659         levl[x][y].doormask = dd->mask;
660 }
661
662 /*
663  * Create a secret door in croom on any one of the specified walls.
664  */
665 void
666 create_secret_door(croom, walls)
667     struct mkroom *croom;
668     xchar walls; /* any of W_NORTH | W_SOUTH | W_EAST | W_WEST (or W_ANY) */
669 {
670     xchar sx, sy; /* location of the secret door */
671     int count;
672
673     for(count = 0; count < 100; count++) {
674         sx = rn1(croom->hx - croom->lx + 1, croom->lx);
675         sy = rn1(croom->hy - croom->ly + 1, croom->ly);
676
677         switch(rn2(4)) {
678         case 0:  /* top */
679             if(!(walls & W_NORTH)) continue;
680             sy = croom->ly-1; break;
681         case 1: /* bottom */
682             if(!(walls & W_SOUTH)) continue;
683             sy = croom->hy+1; break;
684         case 2: /* left */
685             if(!(walls & W_EAST)) continue;
686             sx = croom->lx-1; break;
687         case 3: /* right */
688             if(!(walls & W_WEST)) continue;
689             sx = croom->hx+1; break;
690         }
691
692         if(okdoor(sx,sy)) {
693             levl[sx][sy].typ = SDOOR;
694             levl[sx][sy].doormask = D_CLOSED;
695             add_door(sx,sy,croom);
696             return;
697         }
698     }
699
700     impossible("couldn't create secret door on any walls 0x%x", walls);
701 }
702
703 /*
704  * Create a trap in a room.
705  */
706
707 STATIC_OVL void
708 create_trap(t,croom)
709 trap    *t;
710 struct mkroom   *croom;
711 {
712     schar       x,y;
713     coord       tm;
714
715     if (rn2(100) < t->chance) {
716         x = t->x;
717         y = t->y;
718         if (croom)
719             get_free_room_loc(&x, &y, croom);
720         else
721             get_location(&x, &y, DRY);
722
723         tm.x = x;
724         tm.y = y;
725
726         mktrap(t->type, 1, (struct mkroom*) 0, &tm);
727     }
728 }
729
730 /*
731  * Create a monster in a room.
732  */
733
734 STATIC_OVL int
735 noncoalignment(alignment)
736 aligntyp alignment;
737 {
738         int k;
739
740         k = rn2(2);
741         if (!alignment)
742                 return(k ? -1 : 1);
743         return(k ? -alignment : 0);
744 }
745
746 STATIC_OVL void
747 create_monster(m,croom)
748 monster *m;
749 struct mkroom   *croom;
750 {
751     struct monst *mtmp;
752     schar x, y;
753     char class;
754     aligntyp amask;
755     coord cc;
756     struct permonst *pm;
757     unsigned g_mvflags;
758
759     if (rn2(100) < m->chance) {
760
761         if (m->class >= 0)
762             class = (char) def_char_to_monclass((char)m->class);
763         else if (m->class > -11)
764             class = (char) def_char_to_monclass(rmonst[- m->class - 1]);
765         else
766             class = 0;
767
768         if (class == MAXMCLASSES)
769             panic("create_monster: unknown monster class '%c'", m->class);
770
771         amask = (m->align == AM_SPLEV_CO) ?
772                         Align2amask(u.ualignbase[A_ORIGINAL]) :
773                 (m->align == AM_SPLEV_NONCO) ?
774                         Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL])) :
775                 (m->align <= -11) ? induced_align(80) :
776                 (m->align < 0 ? ralign[-m->align-1] : m->align);
777
778         if (!class)
779             pm = (struct permonst *) 0;
780         else if (m->id != NON_PM) {
781             pm = &mons[m->id];
782             g_mvflags = (unsigned) mvitals[monsndx(pm)].mvflags;
783             if ((pm->geno & G_UNIQ) && (g_mvflags & G_EXTINCT))
784                 goto m_done;
785             else if (g_mvflags & G_GONE)        /* genocided or extinct */
786                 pm = (struct permonst *) 0;     /* make random monster */
787         } else {
788             pm = mkclass(class,G_NOGEN);
789             /* if we can't get a specific monster type (pm == 0) then the
790                class has been genocided, so settle for a random monster */
791         }
792         if (In_mines(&u.uz) && pm && your_race(pm) &&
793                         (Race_if(PM_DWARF) || Race_if(PM_GNOME)) && rn2(3))
794             pm = (struct permonst *) 0;
795
796         x = m->x;
797         y = m->y;
798         if (croom)
799             get_room_loc(&x, &y, croom);
800         else {
801             if (!pm || !is_swimmer(pm))
802                 get_location(&x, &y, DRY);
803             else if (pm->mlet == S_EEL)
804                 get_location(&x, &y, WET);
805             else
806                 get_location(&x, &y, DRY|WET);
807         }
808         /* try to find a close place if someone else is already there */
809         if (MON_AT(x,y) && enexto(&cc, x, y, pm))
810             x = cc.x,  y = cc.y;
811
812         if(m->align != -12)
813             mtmp = mk_roamer(pm, Amask2align(amask), x, y, m->peaceful);
814         else if(PM_ARCHEOLOGIST <= m->id && m->id <= PM_WIZARD)
815                  mtmp = mk_mplayer(pm, x, y, FALSE);
816         else mtmp = makemon(pm, x, y, NO_MM_FLAGS);
817
818         if (mtmp) {
819             /* handle specific attributes for some special monsters */
820             if (m->name.str) mtmp = christen_monst(mtmp, m->name.str);
821
822             /*
823              * This is currently hardwired for mimics only.  It should
824              * eventually be expanded.
825              */
826             if (m->appear_as.str && mtmp->data->mlet == S_MIMIC) {
827                 int i;
828
829                 switch (m->appear) {
830                     case M_AP_NOTHING:
831                         impossible(
832                 "create_monster: mon has an appearance, \"%s\", but no type",
833                                 m->appear_as.str);
834                         break;
835
836                     case M_AP_FURNITURE:
837                         for (i = 0; i < MAXPCHARS; i++)
838                             if (!strcmp(defsyms[i].explanation,
839                                         m->appear_as.str))
840                                 break;
841                         if (i == MAXPCHARS) {
842                             impossible(
843                                 "create_monster: can't find feature \"%s\"",
844                                 m->appear_as.str);
845                         } else {
846                             mtmp->m_ap_type = M_AP_FURNITURE;
847                             mtmp->mappearance = i;
848                         }
849                         break;
850
851                     case M_AP_OBJECT:
852                         for (i = 0; i < NUM_OBJECTS; i++)
853                             if (OBJ_NAME(objects[i]) &&
854                                 !strcmp(OBJ_NAME(objects[i]),m->appear_as.str))
855                                 break;
856                         if (i == NUM_OBJECTS) {
857                             impossible(
858                                 "create_monster: can't find object \"%s\"",
859                                 m->appear_as.str);
860                         } else {
861                             mtmp->m_ap_type = M_AP_OBJECT;
862                             mtmp->mappearance = i;
863                         }
864                         break;
865
866                     case M_AP_MONSTER:
867                         /* note: mimics don't appear as monsters! */
868                         /*       (but chameleons can :-)          */
869                     default:
870                         impossible(
871                 "create_monster: unimplemented mon appear type [%d,\"%s\"]",
872                                 m->appear, m->appear_as.str);
873                         break;
874                 }
875                 if (does_block(x, y, &levl[x][y]))
876                     block_point(x, y);
877             }
878
879             if (m->peaceful >= 0) {
880                 mtmp->mpeaceful = m->peaceful;
881                 /* changed mpeaceful again; have to reset malign */
882                 set_malign(mtmp);
883             }
884             if (m->asleep >= 0) {
885 #ifdef UNIXPC
886                 /* optimizer bug strikes again */
887                 if (m->asleep)
888                         mtmp->msleeping = 1;
889                 else
890                         mtmp->msleeping = 0;
891 #else
892                 mtmp->msleeping = m->asleep;
893 #endif
894             }
895         }
896
897     }           /* if (rn2(100) < m->chance) */
898  m_done:
899     Free(m->name.str);
900     Free(m->appear_as.str);
901 }
902
903 /*
904  * Create an object in a room.
905  */
906
907 STATIC_OVL void
908 create_object(o,croom)
909 object  *o;
910 struct mkroom   *croom;
911 {
912     struct obj *otmp;
913     schar x, y;
914     char c;
915     boolean named;      /* has a name been supplied in level description? */
916
917     if (rn2(100) < o->chance) {
918         named = o->name.str ? TRUE : FALSE;
919
920         x = o->x; y = o->y;
921         if (croom)
922             get_room_loc(&x, &y, croom);
923         else
924             get_location(&x, &y, DRY);
925
926         if (o->class >= 0)
927             c = o->class;
928         else if (o->class > -11)
929             c = robjects[ -(o->class+1)];
930         else
931             c = 0;
932
933         if (!c)
934             otmp = mkobj_at(RANDOM_CLASS, x, y, !named);
935         else if (o->id != -1)
936             otmp = mksobj_at(o->id, x, y, TRUE, !named);
937         else {
938             /*
939              * The special levels are compiled with the default "text" object
940              * class characters.  We must convert them to the internal format.
941              */
942             char oclass = (char) def_char_to_objclass(c);
943
944             if (oclass == MAXOCLASSES)
945                 panic("create_object:  unexpected object class '%c'",c);
946
947             /* KMH -- Create piles of gold properly */
948             if (oclass == COIN_CLASS)
949                 otmp = mkgold(0L, x, y);
950             else
951                 otmp = mkobj_at(oclass, x, y, !named);
952         }
953
954         if (o->spe != -127)     /* That means NOT RANDOM! */
955             otmp->spe = (schar)o->spe;
956
957         switch (o->curse_state) {
958               case 1:   bless(otmp); break; /* BLESSED */
959               case 2:   unbless(otmp); uncurse(otmp); break; /* uncursed */
960               case 3:   curse(otmp); break; /* CURSED */
961               default:  break;  /* Otherwise it's random and we're happy
962                                  * with what mkobj gave us! */
963         }
964
965         /*      corpsenm is "empty" if -1, random if -2, otherwise specific */
966         if (o->corpsenm == NON_PM - 1) otmp->corpsenm = rndmonnum();
967         else if (o->corpsenm != NON_PM) otmp->corpsenm = o->corpsenm;
968
969         /* assume we wouldn't be given an egg corpsenm unless it was
970            hatchable */
971         if (otmp->otyp == EGG && otmp->corpsenm != NON_PM) {
972             if (dead_species(otmp->otyp, TRUE))
973                 kill_egg(otmp); /* make sure nothing hatches */
974             else
975                 attach_egg_hatch_timeout(otmp); /* attach new hatch timeout */
976         }
977
978         if (named)
979             otmp = oname(otmp, o->name.str);
980
981         switch(o->containment) {
982             static struct obj *container = 0;
983
984             /* contents */
985             case 1:
986                 if (!container) {
987                     impossible("create_object: no container");
988                     break;
989                 }
990                 remove_object(otmp);
991                 (void) add_to_container(container, otmp);
992                 goto o_done;            /* don't stack, but do other cleanup */
993             /* container */
994             case 2:
995                 delete_contents(otmp);
996                 container = otmp;
997                 break;
998             /* nothing */
999             case 0: break;
1000
1001             default: impossible("containment type %d?", (int) o->containment);
1002         }
1003
1004         /* Medusa level special case: statues are petrified monsters, so they
1005          * are not stone-resistant and have monster inventory.  They also lack
1006          * other contents, but that can be specified as an empty container.
1007          */
1008         if (o->id == STATUE && Is_medusa_level(&u.uz) &&
1009                     o->corpsenm == NON_PM) {
1010             struct monst *was;
1011             struct obj *obj;
1012             int wastyp;
1013
1014             /* Named random statues are of player types, and aren't stone-
1015              * resistant (if they were, we'd have to reset the name as well as
1016              * setting corpsenm).
1017              */
1018             for (wastyp = otmp->corpsenm; ; wastyp = rndmonnum()) {
1019                 /* makemon without rndmonst() might create a group */
1020                 was = makemon(&mons[wastyp], 0, 0, NO_MM_FLAGS);
1021                 if (!resists_ston(was)) break;
1022                 mongone(was);
1023             }
1024             otmp->corpsenm = wastyp;
1025             while(was->minvent) {
1026                 obj = was->minvent;
1027                 obj->owornmask = 0;
1028                 obj_extract_self(obj);
1029                 (void) add_to_container(otmp, obj);
1030             }
1031             otmp->owt = weight(otmp);
1032             mongone(was);
1033         }
1034
1035         stackobj(otmp);
1036
1037     }           /* if (rn2(100) < o->chance) */
1038  o_done:
1039     Free(o->name.str);
1040 }
1041
1042 /*
1043  * Randomly place a specific engraving, then release its memory.
1044  */
1045 STATIC_OVL void
1046 create_engraving(e, croom)
1047 engraving *e;
1048 struct mkroom *croom;
1049 {
1050         xchar x, y;
1051
1052         x = e->x,  y = e->y;
1053         if (croom)
1054             get_room_loc(&x, &y, croom);
1055         else
1056             get_location(&x, &y, DRY);
1057
1058         make_engr_at(x, y, e->engr.str, 0L, e->etype);
1059         free((genericptr_t) e->engr.str);
1060 }
1061
1062 /*
1063  * Create stairs in a room.
1064  *
1065  */
1066
1067 STATIC_OVL void
1068 create_stairs(s,croom)
1069 stair   *s;
1070 struct mkroom   *croom;
1071 {
1072         schar           x,y;
1073
1074         x = s->x; y = s->y;
1075         get_free_room_loc(&x, &y, croom);
1076         mkstairs(x,y,(char)s->up, croom);
1077 }
1078
1079 /*
1080  * Create an altar in a room.
1081  */
1082
1083 STATIC_OVL void
1084 create_altar(a, croom)
1085         altar           *a;
1086         struct mkroom   *croom;
1087 {
1088         schar           sproom,x,y;
1089         aligntyp        amask;
1090         boolean         croom_is_temple = TRUE;
1091         int oldtyp; 
1092
1093         x = a->x; y = a->y;
1094
1095         if (croom) {
1096             get_free_room_loc(&x, &y, croom);
1097             if (croom->rtype != TEMPLE)
1098                 croom_is_temple = FALSE;
1099         } else {
1100             get_location(&x, &y, DRY);
1101             if ((sproom = (schar) *in_rooms(x, y, TEMPLE)) != 0)
1102                 croom = &rooms[sproom - ROOMOFFSET];
1103             else
1104                 croom_is_temple = FALSE;
1105         }
1106
1107         /* check for existing features */
1108         oldtyp = levl[x][y].typ;
1109         if (oldtyp == STAIRS || oldtyp == LADDER)
1110             return;
1111
1112         a->x = x;
1113         a->y = y;
1114
1115         /* Is the alignment random ?
1116          * If so, it's an 80% chance that the altar will be co-aligned.
1117          *
1118          * The alignment is encoded as amask values instead of alignment
1119          * values to avoid conflicting with the rest of the encoding,
1120          * shared by many other parts of the special level code.
1121          */
1122
1123         amask = (a->align == AM_SPLEV_CO) ?
1124                         Align2amask(u.ualignbase[A_ORIGINAL]) :
1125                 (a->align == AM_SPLEV_NONCO) ?
1126                         Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL])) :
1127                 (a->align == -11) ? induced_align(80) :
1128                 (a->align < 0 ? ralign[-a->align-1] : a->align);
1129
1130         levl[x][y].typ = ALTAR;
1131         levl[x][y].altarmask = amask;
1132
1133         if (a->shrine < 0) a->shrine = rn2(2);  /* handle random case */
1134
1135         if (oldtyp == FOUNTAIN)
1136             level.flags.nfountains--;
1137         else if (oldtyp == SINK)
1138             level.flags.nsinks--;
1139
1140         if (!croom_is_temple || !a->shrine) return;
1141
1142         if (a->shrine) {        /* Is it a shrine  or sanctum? */
1143             priestini(&u.uz, croom, x, y, (a->shrine > 1));
1144             levl[x][y].altarmask |= AM_SHRINE;
1145             level.flags.has_temple = TRUE;
1146         }
1147 }
1148
1149 /*
1150  * Create a gold pile in a room.
1151  */
1152
1153 STATIC_OVL void
1154 create_gold(g,croom)
1155 gold *g;
1156 struct mkroom   *croom;
1157 {
1158         schar           x,y;
1159
1160         x = g->x; y= g->y;
1161         if (croom)
1162             get_room_loc(&x, &y, croom);
1163         else
1164             get_location(&x, &y, DRY);
1165
1166         if (g->amount == -1)
1167             g->amount = rnd(200);
1168         (void) mkgold((long) g->amount, x, y);
1169 }
1170
1171 /*
1172  * Create a feature (e.g a fountain) in a room.
1173  */
1174
1175 STATIC_OVL void
1176 create_feature(fx, fy, croom, typ)
1177 int             fx, fy;
1178 struct mkroom   *croom;
1179 int             typ;
1180 {
1181         schar           x,y;
1182         int             trycnt = 0;
1183
1184         x = fx;  y = fy;
1185         if (croom) {
1186             if (x < 0 && y < 0)
1187                 do {
1188                     x = -1;  y = -1;
1189                     get_room_loc(&x, &y, croom);
1190                 } while (++trycnt <= 200 && occupied(x,y));
1191             else
1192                 get_room_loc(&x, &y, croom);
1193             if(trycnt > 200)
1194                 return;
1195         } else {
1196             get_location(&x, &y, DRY);
1197         }
1198         /* Don't cover up an existing feature (particularly randomly
1199            placed stairs).  However, if the _same_ feature is already
1200            here, it came from the map drawing and we still need to
1201            update the special counters. */
1202         if (IS_FURNITURE(levl[x][y].typ) && levl[x][y].typ != typ)
1203             return;
1204
1205         levl[x][y].typ = typ;
1206         if (typ == FOUNTAIN)
1207             level.flags.nfountains++;
1208         else if (typ == SINK)
1209             level.flags.nsinks++;
1210 }
1211
1212 /*
1213  * Search for a door in a room on a specified wall.
1214  */
1215
1216 STATIC_OVL boolean
1217 search_door(croom,x,y,wall,cnt)
1218 struct mkroom *croom;
1219 xchar *x, *y;
1220 xchar wall;
1221 int cnt;
1222 {
1223         int dx, dy;
1224         int xx,yy;
1225
1226         switch(wall) {
1227               case W_NORTH:
1228                 dy = 0; dx = 1;
1229                 xx = croom->lx;
1230                 yy = croom->hy + 1;
1231                 break;
1232               case W_SOUTH:
1233                 dy = 0; dx = 1;
1234                 xx = croom->lx;
1235                 yy = croom->ly - 1;
1236                 break;
1237               case W_EAST:
1238                 dy = 1; dx = 0;
1239                 xx = croom->hx + 1;
1240                 yy = croom->ly;
1241                 break;
1242               case W_WEST:
1243                 dy = 1; dx = 0;
1244                 xx = croom->lx - 1;
1245                 yy = croom->ly;
1246                 break;
1247               default:
1248                 dx = dy = xx = yy = 0;
1249                 panic("search_door: Bad wall!");
1250                 break;
1251         }
1252         while (xx <= croom->hx+1 && yy <= croom->hy+1) {
1253                 if (IS_DOOR(levl[xx][yy].typ) || levl[xx][yy].typ == SDOOR) {
1254                         *x = xx;
1255                         *y = yy;
1256                         if (cnt-- <= 0)
1257                             return TRUE;
1258                 }
1259                 xx += dx;
1260                 yy += dy;
1261         }
1262         return FALSE;
1263 }
1264
1265 /*
1266  * Dig a corridor between two points.
1267  */
1268
1269 boolean
1270 dig_corridor(org,dest,nxcor,ftyp,btyp)
1271 coord *org, *dest;
1272 boolean nxcor;
1273 schar ftyp, btyp;
1274 {
1275         register int dx=0, dy=0, dix, diy, cct;
1276         register struct rm *crm;
1277         register int tx, ty, xx, yy;
1278
1279         xx = org->x;  yy = org->y;
1280         tx = dest->x; ty = dest->y;
1281         if (xx <= 0 || yy <= 0 || tx <= 0 || ty <= 0 ||
1282             xx > COLNO-1 || tx > COLNO-1 ||
1283             yy > ROWNO-1 || ty > ROWNO-1) {
1284 #ifdef DEBUG
1285                 debugpline("dig_corridor: bad coords : (%d,%d) (%d,%d).",
1286                            xx,yy,tx,ty);
1287 #endif
1288                 return FALSE;
1289         }
1290         if (tx > xx)            dx = 1;
1291         else if (ty > yy)       dy = 1;
1292         else if (tx < xx)       dx = -1;
1293         else                    dy = -1;
1294
1295         xx -= dx;
1296         yy -= dy;
1297         cct = 0;
1298         while(xx != tx || yy != ty) {
1299             /* loop: dig corridor at [xx,yy] and find new [xx,yy] */
1300             if(cct++ > 500 || (nxcor && !rn2(35)))
1301                 return FALSE;
1302
1303             xx += dx;
1304             yy += dy;
1305
1306             if(xx >= COLNO-1 || xx <= 0 || yy <= 0 || yy >= ROWNO-1)
1307                 return FALSE;           /* impossible */
1308
1309             crm = &levl[xx][yy];
1310             if(crm->typ == btyp) {
1311                 if(ftyp != CORR || rn2(100)) {
1312                         crm->typ = ftyp;
1313                         if(nxcor && !rn2(50))
1314                                 (void) mksobj_at(BOULDER, xx, yy, TRUE, FALSE);
1315                 } else {
1316                         crm->typ = SCORR;
1317                 }
1318             } else
1319             if(crm->typ != ftyp && crm->typ != SCORR) {
1320                 /* strange ... */
1321                 return FALSE;
1322             }
1323
1324             /* find next corridor position */
1325             dix = abs(xx-tx);
1326             diy = abs(yy-ty);
1327
1328             /* do we have to change direction ? */
1329             if(dy && dix > diy) {
1330                 register int ddx = (xx > tx) ? -1 : 1;
1331
1332                 crm = &levl[xx+ddx][yy];
1333                 if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
1334                     dx = ddx;
1335                     dy = 0;
1336                     continue;
1337                 }
1338             } else if(dx && diy > dix) {
1339                 register int ddy = (yy > ty) ? -1 : 1;
1340
1341                 crm = &levl[xx][yy+ddy];
1342                 if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
1343                     dy = ddy;
1344                     dx = 0;
1345                     continue;
1346                 }
1347             }
1348
1349             /* continue straight on? */
1350             crm = &levl[xx+dx][yy+dy];
1351             if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
1352                 continue;
1353
1354             /* no, what must we do now?? */
1355             if(dx) {
1356                 dx = 0;
1357                 dy = (ty < yy) ? -1 : 1;
1358             } else {
1359                 dy = 0;
1360                 dx = (tx < xx) ? -1 : 1;
1361             }
1362             crm = &levl[xx+dx][yy+dy];
1363             if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
1364                 continue;
1365             dy = -dy;
1366             dx = -dx;
1367         }
1368         return TRUE;
1369 }
1370
1371 /*
1372  * Disgusting hack: since special levels have their rooms filled before
1373  * sorting the rooms, we have to re-arrange the speed values upstairs_room
1374  * and dnstairs_room after the rooms have been sorted.  On normal levels,
1375  * stairs don't get created until _after_ sorting takes place.
1376  */
1377 STATIC_OVL void
1378 fix_stair_rooms()
1379 {
1380     int i;
1381     struct mkroom *croom;
1382
1383     if(xdnstair &&
1384        !((dnstairs_room->lx <= xdnstair && xdnstair <= dnstairs_room->hx) &&
1385          (dnstairs_room->ly <= ydnstair && ydnstair <= dnstairs_room->hy))) {
1386         for(i=0; i < nroom; i++) {
1387             croom = &rooms[i];
1388             if((croom->lx <= xdnstair && xdnstair <= croom->hx) &&
1389                (croom->ly <= ydnstair && ydnstair <= croom->hy)) {
1390                 dnstairs_room = croom;
1391                 break;
1392             }
1393         }
1394         if(i == nroom)
1395             panic("Couldn't find dnstair room in fix_stair_rooms!");
1396     }
1397     if(xupstair &&
1398        !((upstairs_room->lx <= xupstair && xupstair <= upstairs_room->hx) &&
1399          (upstairs_room->ly <= yupstair && yupstair <= upstairs_room->hy))) {
1400         for(i=0; i < nroom; i++) {
1401             croom = &rooms[i];
1402             if((croom->lx <= xupstair && xupstair <= croom->hx) &&
1403                (croom->ly <= yupstair && yupstair <= croom->hy)) {
1404                 upstairs_room = croom;
1405                 break;
1406             }
1407         }
1408         if(i == nroom)
1409             panic("Couldn't find upstair room in fix_stair_rooms!");
1410     }
1411 }
1412
1413 /*
1414  * Corridors always start from a door. But it can end anywhere...
1415  * Basically we search for door coordinates or for endpoints coordinates
1416  * (from a distance).
1417  */
1418
1419 STATIC_OVL void
1420 create_corridor(c)
1421 corridor        *c;
1422 {
1423         coord org, dest;
1424
1425         if (c->src.room == -1) {
1426                 sort_rooms();
1427                 fix_stair_rooms();
1428                 makecorridors();
1429                 return;
1430         }
1431
1432         if( !search_door(&rooms[c->src.room], &org.x, &org.y, c->src.wall,
1433                          c->src.door))
1434             return;
1435
1436         if (c->dest.room != -1) {
1437                 if(!search_door(&rooms[c->dest.room], &dest.x, &dest.y,
1438                                 c->dest.wall, c->dest.door))
1439                     return;
1440                 switch(c->src.wall) {
1441                       case W_NORTH: org.y--; break;
1442                       case W_SOUTH: org.y++; break;
1443                       case W_WEST:  org.x--; break;
1444                       case W_EAST:  org.x++; break;
1445                 }
1446                 switch(c->dest.wall) {
1447                       case W_NORTH: dest.y--; break;
1448                       case W_SOUTH: dest.y++; break;
1449                       case W_WEST:  dest.x--; break;
1450                       case W_EAST:  dest.x++; break;
1451                 }
1452                 (void) dig_corridor(&org, &dest, FALSE, CORR, STONE);
1453         }
1454 }
1455
1456
1457 /*
1458  * Fill a room (shop, zoo, etc...) with appropriate stuff.
1459  */
1460
1461 void
1462 fill_room(croom, prefilled)
1463 struct mkroom *croom;
1464 boolean prefilled;
1465 {
1466         if (!croom || croom->rtype == OROOM)
1467             return;
1468
1469         if (!prefilled) {
1470             int x,y;
1471
1472             /* Shop ? */
1473             if (croom->rtype >= SHOPBASE) {
1474                     stock_room(croom->rtype - SHOPBASE, croom);
1475                     level.flags.has_shop = TRUE;
1476                     return;
1477             }
1478
1479             switch (croom->rtype) {
1480                 case VAULT:
1481                     for (x=croom->lx;x<=croom->hx;x++)
1482                         for (y=croom->ly;y<=croom->hy;y++)
1483                             (void) mkgold((long)rn1(abs(depth(&u.uz))*100, 51), x, y);
1484                     break;
1485                 case COURT:
1486                 case ZOO:
1487                 case BEEHIVE:
1488                 case MORGUE:
1489                 case BARRACKS:
1490                     fill_zoo(croom);
1491                     break;
1492             }
1493         }
1494         switch (croom->rtype) {
1495             case VAULT:
1496                 level.flags.has_vault = TRUE;
1497                 break;
1498             case ZOO:
1499                 level.flags.has_zoo = TRUE;
1500                 break;
1501             case COURT:
1502                 level.flags.has_court = TRUE;
1503                 break;
1504             case MORGUE:
1505                 level.flags.has_morgue = TRUE;
1506                 break;
1507             case BEEHIVE:
1508                 level.flags.has_beehive = TRUE;
1509                 break;
1510             case BARRACKS:
1511                 level.flags.has_barracks = TRUE;
1512                 break;
1513             case TEMPLE:
1514                 level.flags.has_temple = TRUE;
1515                 break;
1516             case SWAMP:
1517                 level.flags.has_swamp = TRUE;
1518                 break;
1519         }
1520 }
1521
1522 STATIC_OVL void
1523 free_rooms(ro, n)
1524 room **ro;
1525 int n;
1526 {
1527         short j;
1528         room *r;
1529
1530         while(n--) {
1531                 r = ro[n];
1532                 Free(r->name);
1533                 Free(r->parent);
1534                 if ((j = r->ndoor) != 0) {
1535                         while(j--)
1536                             Free(r->doors[j]);
1537                         Free(r->doors);
1538                 }
1539                 if ((j = r->nstair) != 0) {
1540                         while(j--)
1541                             Free(r->stairs[j]);
1542                         Free(r->stairs);
1543                 }
1544                 if ((j = r->naltar) != 0) {
1545                         while (j--)
1546                             Free(r->altars[j]);
1547                         Free(r->altars);
1548                 }
1549                 if ((j = r->nfountain) != 0) {
1550                         while(j--)
1551                             Free(r->fountains[j]);
1552                         Free(r->fountains);
1553                 }
1554                 if ((j = r->nsink) != 0) {
1555                         while(j--)
1556                             Free(r->sinks[j]);
1557                         Free(r->sinks);
1558                 }
1559                 if ((j = r->npool) != 0) {
1560                         while(j--)
1561                             Free(r->pools[j]);
1562                         Free(r->pools);
1563                 }
1564                 if ((j = r->ntrap) != 0) {
1565                         while (j--)
1566                             Free(r->traps[j]);
1567                         Free(r->traps);
1568                 }
1569                 if ((j = r->nmonster) != 0) {
1570                         while (j--)
1571                                 Free(r->monsters[j]);
1572                         Free(r->monsters);
1573                 }
1574                 if ((j = r->nobject) != 0) {
1575                         while (j--)
1576                                 Free(r->objects[j]);
1577                         Free(r->objects);
1578                 }
1579                 if ((j = r->ngold) != 0) {
1580                         while(j--)
1581                             Free(r->golds[j]);
1582                         Free(r->golds);
1583                 }
1584                 if ((j = r->nengraving) != 0) {
1585                         while (j--)
1586                                 Free(r->engravings[j]);
1587                         Free(r->engravings);
1588                 }
1589                 Free(r);
1590         }
1591         Free(ro);
1592 }
1593
1594 STATIC_OVL void
1595 build_room(r, pr)
1596 room *r, *pr;
1597 {
1598         boolean okroom;
1599         struct mkroom   *aroom;
1600         short i;
1601         xchar rtype = (!r->chance || rn2(100) < r->chance) ? r->rtype : OROOM;
1602
1603         if(pr) {
1604                 aroom = &subrooms[nsubroom];
1605                 okroom = create_subroom(pr->mkr, r->x, r->y, r->w, r->h,
1606                                         rtype, r->rlit);
1607         } else {
1608                 aroom = &rooms[nroom];
1609                 okroom = create_room(r->x, r->y, r->w, r->h, r->xalign,
1610                                      r->yalign, rtype, r->rlit);
1611                 r->mkr = aroom;
1612         }
1613
1614         if (okroom) {
1615                 /* Create subrooms if necessary... */
1616                 for(i=0; i < r->nsubroom; i++)
1617                     build_room(r->subrooms[i], r);
1618                 /* And now we can fill the room! */
1619
1620                 /* Priority to the stairs */
1621
1622                 for(i=0; i <r->nstair; i++)
1623                     create_stairs(r->stairs[i], aroom);
1624
1625                 /* Then to the various elements (sinks, etc..) */
1626                 for(i = 0; i<r->nsink; i++)
1627                     create_feature(r->sinks[i]->x, r->sinks[i]->y, aroom, SINK);
1628                 for(i = 0; i<r->npool; i++)
1629                     create_feature(r->pools[i]->x, r->pools[i]->y, aroom, POOL);
1630                 for(i = 0; i<r->nfountain; i++)
1631                     create_feature(r->fountains[i]->x, r->fountains[i]->y,
1632                                    aroom, FOUNTAIN);
1633                 for(i = 0; i<r->naltar; i++)
1634                     create_altar(r->altars[i], aroom);
1635                 for(i = 0; i<r->ndoor; i++)
1636                     create_door(r->doors[i], aroom);
1637
1638                 /* The traps */
1639                 for(i = 0; i<r->ntrap; i++)
1640                     create_trap(r->traps[i], aroom);
1641
1642                 /* The monsters */
1643                 for(i = 0; i<r->nmonster; i++)
1644                     create_monster(r->monsters[i], aroom);
1645
1646                 /* The objects */
1647                 for(i = 0; i<r->nobject; i++)
1648                     create_object(r->objects[i], aroom);
1649
1650                 /* The gold piles */
1651                 for(i = 0; i<r->ngold; i++)
1652                     create_gold(r->golds[i], aroom);
1653
1654                 /* The engravings */
1655                 for (i = 0; i < r->nengraving; i++)
1656                     create_engraving(r->engravings[i], aroom);
1657
1658 #ifdef SPECIALIZATION
1659                 topologize(aroom,FALSE);                /* set roomno */
1660 #else
1661                 topologize(aroom);                      /* set roomno */
1662 #endif
1663                 /* MRS - 07/04/91 - This is temporary but should result
1664                  * in proper filling of shops, etc.
1665                  * DLC - this can fail if corridors are added to this room
1666                  * at a later point.  Currently no good way to fix this.
1667                  */
1668                 if(aroom->rtype != OROOM && r->filled) fill_room(aroom, FALSE);
1669         }
1670 }
1671
1672 /*
1673  * set lighting in a region that will not become a room.
1674  */
1675 STATIC_OVL void
1676 light_region(tmpregion)
1677     region  *tmpregion;
1678 {
1679     register boolean litstate = tmpregion->rlit ? 1 : 0;
1680     register int hiy = tmpregion->y2;
1681     register int x, y;
1682     register struct rm *lev;
1683     int lowy = tmpregion->y1;
1684     int lowx = tmpregion->x1, hix = tmpregion->x2;
1685
1686     if(litstate) {
1687         /* adjust region size for walls, but only if lighted */
1688         lowx = max(lowx-1,1);
1689         hix = min(hix+1,COLNO-1);
1690         lowy = max(lowy-1,0);
1691         hiy = min(hiy+1, ROWNO-1);
1692     }
1693     for(x = lowx; x <= hix; x++) {
1694         lev = &levl[x][lowy];
1695         for(y = lowy; y <= hiy; y++) {
1696             if (lev->typ != LAVAPOOL) /* this overrides normal lighting */
1697                 lev->lit = litstate;
1698             lev++;
1699         }
1700     }
1701 }
1702
1703 /* initialization common to all special levels */
1704 STATIC_OVL void
1705 load_common_data(fd, typ)
1706 dlb *fd;
1707 int typ;
1708 {
1709         uchar   n;
1710         long    lev_flags;
1711         int     i;
1712
1713       {
1714         aligntyp atmp;
1715         /* shuffle 3 alignments; can't use sp_lev_shuffle() on aligntyp's */
1716         i = rn2(3);   atmp=ralign[2]; ralign[2]=ralign[i]; ralign[i]=atmp;
1717         if (rn2(2)) { atmp=ralign[1]; ralign[1]=ralign[0]; ralign[0]=atmp; }
1718       }
1719
1720         level.flags.is_maze_lev = typ == SP_LEV_MAZE;
1721
1722         /* Read the level initialization data */
1723         Fread((genericptr_t) &init_lev, 1, sizeof(lev_init), fd);
1724         if(init_lev.init_present) {
1725             if(init_lev.lit < 0)
1726                 init_lev.lit = rn2(2);
1727             mkmap(&init_lev);
1728         }
1729
1730         /* Read the per level flags */
1731         Fread((genericptr_t) &lev_flags, 1, sizeof(lev_flags), fd);
1732         if (lev_flags & NOTELEPORT)
1733             level.flags.noteleport = 1;
1734         if (lev_flags & HARDFLOOR)
1735             level.flags.hardfloor = 1;
1736         if (lev_flags & NOMMAP)
1737             level.flags.nommap = 1;
1738         if (lev_flags & SHORTSIGHTED)
1739             level.flags.shortsighted = 1;
1740         if (lev_flags & ARBOREAL)
1741             level.flags.arboreal = 1;
1742
1743         /* Read message */
1744         Fread((genericptr_t) &n, 1, sizeof(n), fd);
1745         if (n) {
1746             lev_message = (char *) alloc(n + 1);
1747             Fread((genericptr_t) lev_message, 1, (int) n, fd);
1748             lev_message[n] = 0;
1749         }
1750 }
1751
1752 STATIC_OVL void
1753 load_one_monster(fd, m)
1754 dlb *fd;
1755 monster *m;
1756 {
1757         int size;
1758
1759         Fread((genericptr_t) m, 1, sizeof *m, fd);
1760         if ((size = m->name.len) != 0) {
1761             m->name.str = (char *) alloc((unsigned)size + 1);
1762             Fread((genericptr_t) m->name.str, 1, size, fd);
1763             m->name.str[size] = '\0';
1764         } else
1765             m->name.str = (char *) 0;
1766         if ((size = m->appear_as.len) != 0) {
1767             m->appear_as.str = (char *) alloc((unsigned)size + 1);
1768             Fread((genericptr_t) m->appear_as.str, 1, size, fd);
1769             m->appear_as.str[size] = '\0';
1770         } else
1771             m->appear_as.str = (char *) 0;
1772 }
1773
1774 STATIC_OVL void
1775 load_one_object(fd, o)
1776 dlb *fd;
1777 object *o;
1778 {
1779         int size;
1780
1781         Fread((genericptr_t) o, 1, sizeof *o, fd);
1782         if ((size = o->name.len) != 0) {
1783             o->name.str = (char *) alloc((unsigned)size + 1);
1784             Fread((genericptr_t) o->name.str, 1, size, fd);
1785             o->name.str[size] = '\0';
1786         } else
1787             o->name.str = (char *) 0;
1788 }
1789
1790 STATIC_OVL void
1791 load_one_engraving(fd, e)
1792 dlb *fd;
1793 engraving *e;
1794 {
1795         int size;
1796
1797         Fread((genericptr_t) e, 1, sizeof *e, fd);
1798         size = e->engr.len;
1799         e->engr.str = (char *) alloc((unsigned)size+1);
1800         Fread((genericptr_t) e->engr.str, 1, size, fd);
1801         e->engr.str[size] = '\0';
1802 }
1803
1804 STATIC_OVL boolean
1805 load_rooms(fd)
1806 dlb *fd;
1807 {
1808         xchar           nrooms, ncorr;
1809         char            n;
1810         short           size;
1811         corridor        tmpcor;
1812         room**          tmproom;
1813         int             i, j;
1814
1815         load_common_data(fd, SP_LEV_ROOMS);
1816
1817         Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrobjects */
1818         if (n) {
1819                 Fread((genericptr_t)robjects, sizeof(*robjects), n, fd);
1820                 sp_lev_shuffle(robjects, (char *)0, (int)n);
1821         }
1822
1823         Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrmonst */
1824         if (n) {
1825                 Fread((genericptr_t)rmonst, sizeof(*rmonst), n, fd);
1826                 sp_lev_shuffle(rmonst, (char *)0, (int)n);
1827         }
1828
1829         Fread((genericptr_t) &nrooms, 1, sizeof(nrooms), fd);
1830                                                 /* Number of rooms to read */
1831         tmproom = NewTab(room,nrooms);
1832         for (i=0;i<nrooms;i++) {
1833                 room *r;
1834
1835                 r = tmproom[i] = New(room);
1836
1837                 /* Let's see if this room has a name */
1838                 Fread((genericptr_t) &size, 1, sizeof(size), fd);
1839                 if (size > 0) { /* Yup, it does! */
1840                         r->name = (char *) alloc((unsigned)size + 1);
1841                         Fread((genericptr_t) r->name, 1, size, fd);
1842                         r->name[size] = 0;
1843                 } else
1844                     r->name = (char *) 0;
1845
1846                 /* Let's see if this room has a parent */
1847                 Fread((genericptr_t) &size, 1, sizeof(size), fd);
1848                 if (size > 0) { /* Yup, it does! */
1849                         r->parent = (char *) alloc((unsigned)size + 1);
1850                         Fread((genericptr_t) r->parent, 1, size, fd);
1851                         r->parent[size] = 0;
1852                 } else
1853                     r->parent = (char *) 0;
1854
1855                 Fread((genericptr_t) &r->x, 1, sizeof(r->x), fd);
1856                                         /* x pos on the grid (1-5) */
1857                 Fread((genericptr_t) &r->y, 1, sizeof(r->y), fd);
1858                                          /* y pos on the grid (1-5) */
1859                 Fread((genericptr_t) &r->w, 1, sizeof(r->w), fd);
1860                                          /* width of the room */
1861                 Fread((genericptr_t) &r->h, 1, sizeof(r->h), fd);
1862                                          /* height of the room */
1863                 Fread((genericptr_t) &r->xalign, 1, sizeof(r->xalign), fd);
1864                                          /* horizontal alignment */
1865                 Fread((genericptr_t) &r->yalign, 1, sizeof(r->yalign), fd);
1866                                          /* vertical alignment */
1867                 Fread((genericptr_t) &r->rtype, 1, sizeof(r->rtype), fd);
1868                                          /* type of room (zoo, shop, etc.) */
1869                 Fread((genericptr_t) &r->chance, 1, sizeof(r->chance), fd);
1870                                          /* chance of room being special. */
1871                 Fread((genericptr_t) &r->rlit, 1, sizeof(r->rlit), fd);
1872                                          /* lit or not ? */
1873                 Fread((genericptr_t) &r->filled, 1, sizeof(r->filled), fd);
1874                                          /* to be filled? */
1875                 r->nsubroom= 0;
1876
1877                 /* read the doors */
1878                 Fread((genericptr_t) &r->ndoor, 1, sizeof(r->ndoor), fd);
1879                 if ((n = r->ndoor) != 0)
1880                     r->doors = NewTab(room_door, n);
1881                 while(n--) {
1882                         r->doors[(int)n] = New(room_door);
1883                         Fread((genericptr_t) r->doors[(int)n], 1,
1884                                 sizeof(room_door), fd);
1885                 }
1886
1887                 /* read the stairs */
1888                 Fread((genericptr_t) &r->nstair, 1, sizeof(r->nstair), fd);
1889                 if ((n = r->nstair) != 0)
1890                     r->stairs = NewTab(stair, n);
1891                 while (n--) {
1892                         r->stairs[(int)n] = New(stair);
1893                         Fread((genericptr_t) r->stairs[(int)n], 1,
1894                                 sizeof(stair), fd);
1895                 }
1896
1897                 /* read the altars */
1898                 Fread((genericptr_t) &r->naltar, 1, sizeof(r->naltar), fd);
1899                 if ((n = r->naltar) != 0)
1900                     r->altars = NewTab(altar, n);
1901                 while (n--) {
1902                         r->altars[(int)n] = New(altar);
1903                         Fread((genericptr_t) r->altars[(int)n], 1,
1904                                 sizeof(altar), fd);
1905                 }
1906
1907                 /* read the fountains */
1908                 Fread((genericptr_t) &r->nfountain, 1,
1909                         sizeof(r->nfountain), fd);
1910                 if ((n = r->nfountain) != 0)
1911                     r->fountains = NewTab(fountain, n);
1912                 while (n--) {
1913                         r->fountains[(int)n] = New(fountain);
1914                         Fread((genericptr_t) r->fountains[(int)n], 1,
1915                                 sizeof(fountain), fd);
1916                 }
1917
1918                 /* read the sinks */
1919                 Fread((genericptr_t) &r->nsink, 1, sizeof(r->nsink), fd);
1920                 if ((n = r->nsink) != 0)
1921                     r->sinks = NewTab(sink, n);
1922                 while (n--) {
1923                         r->sinks[(int)n] = New(sink);
1924                         Fread((genericptr_t) r->sinks[(int)n], 1, sizeof(sink), fd);
1925                 }
1926
1927                 /* read the pools */
1928                 Fread((genericptr_t) &r->npool, 1, sizeof(r->npool), fd);
1929                 if ((n = r->npool) != 0)
1930                     r->pools = NewTab(pool,n);
1931                 while (n--) {
1932                         r->pools[(int)n] = New(pool);
1933                         Fread((genericptr_t) r->pools[(int)n], 1, sizeof(pool), fd);
1934                 }
1935
1936                 /* read the traps */
1937                 Fread((genericptr_t) &r->ntrap, 1, sizeof(r->ntrap), fd);
1938                 if ((n = r->ntrap) != 0)
1939                     r->traps = NewTab(trap, n);
1940                 while(n--) {
1941                         r->traps[(int)n] = New(trap);
1942                         Fread((genericptr_t) r->traps[(int)n], 1, sizeof(trap), fd);
1943                 }
1944
1945                 /* read the monsters */
1946                 Fread((genericptr_t) &r->nmonster, 1, sizeof(r->nmonster), fd);
1947                 if ((n = r->nmonster) != 0) {
1948                     r->monsters = NewTab(monster, n);
1949                     while(n--) {
1950                         r->monsters[(int)n] = New(monster);
1951                         load_one_monster(fd, r->monsters[(int)n]);
1952                     }
1953                 } else
1954                     r->monsters = 0;
1955
1956                 /* read the objects, in same order as mazes */
1957                 Fread((genericptr_t) &r->nobject, 1, sizeof(r->nobject), fd);
1958                 if ((n = r->nobject) != 0) {
1959                     r->objects = NewTab(object, n);
1960                     for (j = 0; j < n; ++j) {
1961                         r->objects[j] = New(object);
1962                         load_one_object(fd, r->objects[j]);
1963                     }
1964                 } else
1965                     r->objects = 0;
1966
1967                 /* read the gold piles */
1968                 Fread((genericptr_t) &r->ngold, 1, sizeof(r->ngold), fd);
1969                 if ((n = r->ngold) != 0)
1970                     r->golds = NewTab(gold, n);
1971                 while (n--) {
1972                         r->golds[(int)n] = New(gold);
1973                         Fread((genericptr_t) r->golds[(int)n], 1, sizeof(gold), fd);
1974                 }
1975
1976                 /* read the engravings */
1977                 Fread((genericptr_t) &r->nengraving, 1,
1978                         sizeof(r->nengraving), fd);
1979                 if ((n = r->nengraving) != 0) {
1980                     r->engravings = NewTab(engraving,n);
1981                     while (n--) {
1982                         r->engravings[(int)n] = New(engraving);
1983                         load_one_engraving(fd, r->engravings[(int)n]);
1984                     }
1985                 } else
1986                     r->engravings = 0;
1987
1988         }
1989
1990         /* Now that we have loaded all the rooms, search the
1991          * subrooms and create the links.
1992          */
1993
1994         for (i = 0; i<nrooms; i++)
1995             if (tmproom[i]->parent) {
1996                     /* Search the parent room */
1997                     for(j=0; j<nrooms; j++)
1998                         if (tmproom[j]->name && !strcmp(tmproom[j]->name,
1999                                                        tmproom[i]->parent)) {
2000                                 n = tmproom[j]->nsubroom++;
2001                                 tmproom[j]->subrooms[(int)n] = tmproom[i];
2002                                 break;
2003                         }
2004             }
2005
2006         /*
2007          * Create the rooms now...
2008          */
2009
2010         for (i=0; i < nrooms; i++)
2011             if(!tmproom[i]->parent)
2012                 build_room(tmproom[i], (room *) 0);
2013
2014         free_rooms(tmproom, nrooms);
2015
2016         /* read the corridors */
2017
2018         Fread((genericptr_t) &ncorr, sizeof(ncorr), 1, fd);
2019         for (i=0; i<ncorr; i++) {
2020                 Fread((genericptr_t) &tmpcor, 1, sizeof(tmpcor), fd);
2021                 create_corridor(&tmpcor);
2022         }
2023
2024         return TRUE;
2025 }
2026
2027 /*
2028  * Select a random coordinate in the maze.
2029  *
2030  * We want a place not 'touched' by the loader.  That is, a place in
2031  * the maze outside every part of the special level.
2032  */
2033
2034 STATIC_OVL void
2035 maze1xy(m, humidity)
2036 coord *m;
2037 int humidity;
2038 {
2039         register int x, y, tryct = 2000;
2040         /* tryct:  normally it won't take more than ten or so tries due
2041            to the circumstances under which we'll be called, but the
2042            `humidity' screening might drastically change the chances */
2043
2044         do {
2045             x = rn1(x_maze_max - 3, 3);
2046             y = rn1(y_maze_max - 3, 3);
2047             if (--tryct < 0) break;     /* give up */
2048         } while (!(x % 2) || !(y % 2) || Map[x][y] ||
2049                  !is_ok_location((schar)x, (schar)y, humidity));
2050
2051         m->x = (xchar)x,  m->y = (xchar)y;
2052 }
2053
2054 /*
2055  * The Big Thing: special maze loader
2056  *
2057  * Could be cleaner, but it works.
2058  */
2059
2060 STATIC_OVL boolean
2061 load_maze(fd)
2062 dlb *fd;
2063 {
2064     xchar   x, y, typ;
2065     boolean prefilled, room_not_needed;
2066
2067     char    n, numpart = 0;
2068     xchar   nwalk = 0, nwalk_sav;
2069     schar   filling;
2070     char    halign, valign;
2071
2072     int     xi, dir, size;
2073     coord   mm;
2074     int     mapcount, mapcountmax, mapfact;
2075
2076     lev_region  tmplregion;
2077     region  tmpregion;
2078     door    tmpdoor;
2079     trap    tmptrap;
2080     monster tmpmons;
2081     object  tmpobj;
2082     drawbridge tmpdb;
2083     walk    tmpwalk;
2084     digpos  tmpdig;
2085     lad     tmplad;
2086     stair   tmpstair, prevstair;
2087     altar   tmpaltar;
2088     gold    tmpgold;
2089     fountain tmpfountain;
2090     engraving tmpengraving;
2091     xchar   mustfill[(MAXNROFROOMS+1)*2];
2092     struct trap *badtrap;
2093     boolean has_bounds;
2094
2095     (void) memset((genericptr_t)&Map[0][0], 0, sizeof Map);
2096     load_common_data(fd, SP_LEV_MAZE);
2097
2098     /* Initialize map */
2099     Fread((genericptr_t) &filling, 1, sizeof(filling), fd);
2100     if (!init_lev.init_present) { /* don't init if mkmap() has been called */
2101       for(x = 2; x <= x_maze_max; x++)
2102         for(y = 0; y <= y_maze_max; y++)
2103             if (filling == -1) {
2104 #ifndef WALLIFIED_MAZE
2105                     levl[x][y].typ = STONE;
2106 #else
2107                     levl[x][y].typ =
2108                         (y < 2 || ((x % 2) && (y % 2))) ? STONE : HWALL;
2109 #endif
2110             } else {
2111                     levl[x][y].typ = filling;
2112             }
2113     }
2114
2115     /* Start reading the file */
2116     Fread((genericptr_t) &numpart, 1, sizeof(numpart), fd);
2117                                                 /* Number of parts */
2118     if (!numpart || numpart > 9)
2119         panic("load_maze error: numpart = %d", (int) numpart);
2120
2121     while (numpart--) {
2122         Fread((genericptr_t) &halign, 1, sizeof(halign), fd);
2123                                         /* Horizontal alignment */
2124         Fread((genericptr_t) &valign, 1, sizeof(valign), fd);
2125                                         /* Vertical alignment */
2126         Fread((genericptr_t) &xsize, 1, sizeof(xsize), fd);
2127                                         /* size in X */
2128         Fread((genericptr_t) &ysize, 1, sizeof(ysize), fd);
2129                                         /* size in Y */
2130         switch((int) halign) {
2131             case LEFT:      xstart = 3;                                 break;
2132             case H_LEFT:    xstart = 2+((x_maze_max-2-xsize)/4);        break;
2133             case CENTER:    xstart = 2+((x_maze_max-2-xsize)/2);        break;
2134             case H_RIGHT:   xstart = 2+((x_maze_max-2-xsize)*3/4);      break;
2135             case RIGHT:     xstart = x_maze_max-xsize-1;                break;
2136         }
2137         switch((int) valign) {
2138             case TOP:       ystart = 3;                                 break;
2139             case CENTER:    ystart = 2+((y_maze_max-2-ysize)/2);        break;
2140             case BOTTOM:    ystart = y_maze_max-ysize-1;                break;
2141         }
2142         if (!(xstart % 2)) xstart++;
2143         if (!(ystart % 2)) ystart++;
2144         if ((ystart < 0) || (ystart + ysize > ROWNO)) {
2145             /* try to move the start a bit */
2146             ystart += (ystart > 0) ? -2 : 2;
2147             if(ysize == ROWNO) ystart = 0;
2148             if(ystart < 0 || ystart + ysize > ROWNO)
2149                 panic("reading special level with ysize too large");
2150         }
2151
2152         /*
2153          * If any CROSSWALLs are found, must change to ROOM after REGION's
2154          * are laid out.  CROSSWALLS are used to specify "invisible"
2155          * boundaries where DOOR syms look bad or aren't desirable.
2156          */
2157         has_bounds = FALSE;
2158
2159         if(init_lev.init_present && xsize <= 1 && ysize <= 1) {
2160             xstart = 1;
2161             ystart = 0;
2162             xsize = COLNO-1;
2163             ysize = ROWNO;
2164         } else {
2165             /* Load the map */
2166             for(y = ystart; y < ystart+ysize; y++)
2167                 for(x = xstart; x < xstart+xsize; x++) {
2168                     levl[x][y].typ = Fgetc(fd);
2169                     levl[x][y].lit = FALSE;
2170                     /* clear out levl: load_common_data may set them */
2171                     levl[x][y].flags = 0;
2172                     levl[x][y].horizontal = 0;
2173                     levl[x][y].roomno = 0;
2174                     levl[x][y].edge = 0;
2175                     /*
2176                      * Note: Even though levl[x][y].typ is type schar,
2177                      *   lev_comp.y saves it as type char. Since schar != char
2178                      *   all the time we must make this exception or hack
2179                      *   through lev_comp.y to fix.
2180                      */
2181
2182                     /*
2183                      *  Set secret doors to closed (why not trapped too?).  Set
2184                      *  the horizontal bit.
2185                      */
2186                     if (levl[x][y].typ == SDOOR || IS_DOOR(levl[x][y].typ)) {
2187                         if(levl[x][y].typ == SDOOR)
2188                             levl[x][y].doormask = D_CLOSED;
2189                         /*
2190                          *  If there is a wall to the left that connects to a
2191                          *  (secret) door, then it is horizontal.  This does
2192                          *  not allow (secret) doors to be corners of rooms.
2193                          */
2194                         if (x != xstart && (IS_WALL(levl[x-1][y].typ) ||
2195                                             levl[x-1][y].horizontal))
2196                             levl[x][y].horizontal = 1;
2197                     } else if(levl[x][y].typ == HWALL ||
2198                                 levl[x][y].typ == IRONBARS)
2199                         levl[x][y].horizontal = 1;
2200                     else if(levl[x][y].typ == LAVAPOOL)
2201                         levl[x][y].lit = 1;
2202                     else if(levl[x][y].typ == CROSSWALL)
2203                         has_bounds = TRUE;
2204                     Map[x][y] = 1;
2205                 }
2206             if (init_lev.init_present && init_lev.joined)
2207                 remove_rooms(xstart, ystart, xstart+xsize, ystart+ysize);
2208         }
2209
2210         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2211                                                 /* Number of level regions */
2212         if(n) {
2213             if(num_lregions) {
2214                 /* realloc the lregion space to add the new ones */
2215                 /* don't really free it up until the whole level is done */
2216                 lev_region *newl = (lev_region *) alloc(sizeof(lev_region) *
2217                                                 (unsigned)(n+num_lregions));
2218                 (void) memcpy((genericptr_t)(newl+n), (genericptr_t)lregions,
2219                                         sizeof(lev_region) * num_lregions);
2220                 Free(lregions);
2221                 num_lregions += n;
2222                 lregions = newl;
2223             } else {
2224                 num_lregions = n;
2225                 lregions = (lev_region *)
2226                                 alloc(sizeof(lev_region) * (unsigned)n);
2227             }
2228         }
2229
2230         while(n--) {
2231             Fread((genericptr_t) &tmplregion, sizeof(tmplregion), 1, fd);
2232             if ((size = tmplregion.rname.len) != 0) {
2233                 tmplregion.rname.str = (char *) alloc((unsigned)size + 1);
2234                 Fread((genericptr_t) tmplregion.rname.str, size, 1, fd);
2235                 tmplregion.rname.str[size] = '\0';
2236             } else
2237                 tmplregion.rname.str = (char *) 0;
2238             if(!tmplregion.in_islev) {
2239                 get_location(&tmplregion.inarea.x1, &tmplregion.inarea.y1,
2240                                                                 DRY|WET);
2241                 get_location(&tmplregion.inarea.x2, &tmplregion.inarea.y2,
2242                                                                 DRY|WET);
2243             }
2244             if(!tmplregion.del_islev) {
2245                 get_location(&tmplregion.delarea.x1, &tmplregion.delarea.y1,
2246                                                                 DRY|WET);
2247                 get_location(&tmplregion.delarea.x2, &tmplregion.delarea.y2,
2248                                                                 DRY|WET);
2249             }
2250             lregions[(int)n] = tmplregion;
2251         }
2252
2253         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2254                                                 /* Random objects */
2255         if(n) {
2256                 Fread((genericptr_t)robjects, sizeof(*robjects), (int) n, fd);
2257                 sp_lev_shuffle(robjects, (char *)0, (int)n);
2258         }
2259
2260         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2261                                                 /* Random locations */
2262         if(n) {
2263                 Fread((genericptr_t)rloc_x, sizeof(*rloc_x), (int) n, fd);
2264                 Fread((genericptr_t)rloc_y, sizeof(*rloc_y), (int) n, fd);
2265                 sp_lev_shuffle(rloc_x, rloc_y, (int)n);
2266         }
2267
2268         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2269                                                 /* Random monsters */
2270         if(n) {
2271                 Fread((genericptr_t)rmonst, sizeof(*rmonst), (int) n, fd);
2272                 sp_lev_shuffle(rmonst, (char *)0, (int)n);
2273         }
2274
2275         (void) memset((genericptr_t)mustfill, 0, sizeof(mustfill));
2276         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2277                                                 /* Number of subrooms */
2278         while(n--) {
2279                 register struct mkroom *troom;
2280
2281                 Fread((genericptr_t)&tmpregion, 1, sizeof(tmpregion), fd);
2282
2283                 if(tmpregion.rtype > MAXRTYPE) {
2284                     tmpregion.rtype -= MAXRTYPE+1;
2285                     prefilled = TRUE;
2286                 } else
2287                     prefilled = FALSE;
2288
2289                 if(tmpregion.rlit < 0)
2290                     tmpregion.rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77))
2291                         ? TRUE : FALSE;
2292
2293                 get_location(&tmpregion.x1, &tmpregion.y1, DRY|WET);
2294                 get_location(&tmpregion.x2, &tmpregion.y2, DRY|WET);
2295
2296                 /* for an ordinary room, `prefilled' is a flag to force
2297                    an actual room to be created (such rooms are used to
2298                    control placement of migrating monster arrivals) */
2299                 room_not_needed = (tmpregion.rtype == OROOM &&
2300                                    !tmpregion.rirreg && !prefilled);
2301                 if (room_not_needed || nroom >= MAXNROFROOMS) {
2302                     if (!room_not_needed)
2303                         impossible("Too many rooms on new level!");
2304                     light_region(&tmpregion);
2305                     continue;
2306                 }
2307
2308                 troom = &rooms[nroom];
2309
2310                 /* mark rooms that must be filled, but do it later */
2311                 if (tmpregion.rtype != OROOM)
2312                     mustfill[nroom] = (prefilled ? 2 : 1);
2313
2314                 if(tmpregion.rirreg) {
2315                     min_rx = max_rx = tmpregion.x1;
2316                     min_ry = max_ry = tmpregion.y1;
2317                     flood_fill_rm(tmpregion.x1, tmpregion.y1,
2318                                   nroom+ROOMOFFSET, tmpregion.rlit, TRUE);
2319                     add_room(min_rx, min_ry, max_rx, max_ry,
2320                              FALSE, tmpregion.rtype, TRUE);
2321                     troom->rlit = tmpregion.rlit;
2322                     troom->irregular = TRUE;
2323                 } else {
2324                     add_room(tmpregion.x1, tmpregion.y1,
2325                              tmpregion.x2, tmpregion.y2,
2326                              tmpregion.rlit, tmpregion.rtype, TRUE);
2327 #ifdef SPECIALIZATION
2328                     topologize(troom,FALSE);            /* set roomno */
2329 #else
2330                     topologize(troom);                  /* set roomno */
2331 #endif
2332                 }
2333         }
2334
2335         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2336                                                 /* Number of doors */
2337         while(n--) {
2338                 struct mkroom *croom = &rooms[0];
2339
2340                 Fread((genericptr_t)&tmpdoor, 1, sizeof(tmpdoor), fd);
2341
2342                 x = tmpdoor.x;  y = tmpdoor.y;
2343                 typ = tmpdoor.mask == -1 ? rnddoor() : tmpdoor.mask;
2344
2345                 get_location(&x, &y, DRY);
2346                 if(levl[x][y].typ != SDOOR)
2347                         levl[x][y].typ = DOOR;
2348                 else {
2349                         if(typ < D_CLOSED)
2350                             typ = D_CLOSED; /* force it to be closed */
2351                 }
2352                 levl[x][y].doormask = typ;
2353
2354                 /* Now the complicated part, list it with each subroom */
2355                 /* The dog move and mail daemon routines use this */
2356                 while(croom->hx >= 0 && doorindex < DOORMAX) {
2357                     if(croom->hx >= x-1 && croom->lx <= x+1 &&
2358                        croom->hy >= y-1 && croom->ly <= y+1) {
2359                         /* Found it */
2360                         add_door(x, y, croom);
2361                     }
2362                     croom++;
2363                 }
2364         }
2365
2366         /* now that we have rooms _and_ associated doors, fill the rooms */
2367         for(n = 0; n < SIZE(mustfill); n++)
2368             if(mustfill[(int)n])
2369                 fill_room(&rooms[(int)n], (mustfill[(int)n] == 2));
2370
2371         /* if special boundary syms (CROSSWALL) in map, remove them now */
2372         if(has_bounds) {
2373             for(x = xstart; x < xstart+xsize; x++)
2374                 for(y = ystart; y < ystart+ysize; y++)
2375                     if(levl[x][y].typ == CROSSWALL)
2376                         levl[x][y].typ = ROOM;
2377         }
2378
2379         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2380                                                 /* Number of drawbridges */
2381         while(n--) {
2382                 Fread((genericptr_t)&tmpdb, 1, sizeof(tmpdb), fd);
2383
2384                 x = tmpdb.x;  y = tmpdb.y;
2385                 get_location(&x, &y, DRY|WET);
2386
2387                 if (!create_drawbridge(x, y, tmpdb.dir, tmpdb.db_open))
2388                     impossible("Cannot create drawbridge.");
2389         }
2390
2391         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2392                                                 /* Number of mazewalks */
2393         while(n--) {
2394                 Fread((genericptr_t)&tmpwalk, 1, sizeof(tmpwalk), fd);
2395
2396                 get_location(&tmpwalk.x, &tmpwalk.y, DRY|WET);
2397
2398                 walklist[nwalk++] = tmpwalk;
2399         }
2400
2401         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2402                                                 /* Number of non_diggables */
2403         while(n--) {
2404                 Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd);
2405
2406                 get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET);
2407                 get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET);
2408
2409                 set_wall_property(tmpdig.x1, tmpdig.y1,
2410                                   tmpdig.x2, tmpdig.y2, W_NONDIGGABLE);
2411         }
2412
2413         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2414                                                 /* Number of non_passables */
2415         while(n--) {
2416                 Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd);
2417
2418                 get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET);
2419                 get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET);
2420
2421                 set_wall_property(tmpdig.x1, tmpdig.y1,
2422                                   tmpdig.x2, tmpdig.y2, W_NONPASSWALL);
2423         }
2424
2425         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2426                                                 /* Number of ladders */
2427         while(n--) {
2428                 Fread((genericptr_t)&tmplad, 1, sizeof(tmplad), fd);
2429
2430                 x = tmplad.x;  y = tmplad.y;
2431                 get_location(&x, &y, DRY);
2432
2433                 levl[x][y].typ = LADDER;
2434                 if (tmplad.up == 1) {
2435                         xupladder = x;  yupladder = y;
2436                         levl[x][y].ladder = LA_UP;
2437                 } else {
2438                         xdnladder = x;  ydnladder = y;
2439                         levl[x][y].ladder = LA_DOWN;
2440                 }
2441         }
2442
2443         prevstair.x = prevstair.y = 0;
2444         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2445                                                 /* Number of stairs */
2446         while(n--) {
2447                 Fread((genericptr_t)&tmpstair, 1, sizeof(tmpstair), fd);
2448
2449                 xi = 0;
2450                 do {
2451                     x = tmpstair.x;  y = tmpstair.y;
2452                     get_location(&x, &y, DRY);
2453                 } while(prevstair.x && xi++ < 100 &&
2454                         distmin(x,y,prevstair.x,prevstair.y) <= 8);
2455                 if ((badtrap = t_at(x,y)) != 0) deltrap(badtrap);
2456                 mkstairs(x, y, (char)tmpstair.up, (struct mkroom *)0);
2457                 prevstair.x = x;
2458                 prevstair.y = y;
2459         }
2460
2461         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2462                                                 /* Number of altars */
2463         while(n--) {
2464                 Fread((genericptr_t)&tmpaltar, 1, sizeof(tmpaltar), fd);
2465
2466                 create_altar(&tmpaltar, (struct mkroom *)0);
2467         }
2468
2469         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2470                                                 /* Number of fountains */
2471         while (n--) {
2472                 Fread((genericptr_t)&tmpfountain, 1, sizeof(tmpfountain), fd);
2473
2474                 create_feature(tmpfountain.x, tmpfountain.y,
2475                                (struct mkroom *)0, FOUNTAIN);
2476         }
2477
2478         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2479                                                 /* Number of traps */
2480         while(n--) {
2481                 Fread((genericptr_t)&tmptrap, 1, sizeof(tmptrap), fd);
2482
2483                 create_trap(&tmptrap, (struct mkroom *)0);
2484         }
2485
2486         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2487                                                 /* Number of monsters */
2488         while(n--) {
2489                 load_one_monster(fd, &tmpmons);
2490
2491                 create_monster(&tmpmons, (struct mkroom *)0);
2492         }
2493
2494         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2495                                                 /* Number of objects */
2496         while(n--) {
2497                 load_one_object(fd, &tmpobj);
2498
2499                 create_object(&tmpobj, (struct mkroom *)0);
2500         }
2501
2502         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2503                                                 /* Number of gold piles */
2504         while (n--) {
2505                 Fread((genericptr_t)&tmpgold, 1, sizeof(tmpgold), fd);
2506
2507                 create_gold(&tmpgold, (struct mkroom *)0);
2508         }
2509
2510         Fread((genericptr_t) &n, 1, sizeof(n), fd);
2511                                                 /* Number of engravings */
2512         while(n--) {
2513                 load_one_engraving(fd, &tmpengraving);
2514
2515                 create_engraving(&tmpengraving, (struct mkroom *)0);
2516         }
2517
2518     }           /* numpart loop */
2519
2520     nwalk_sav = nwalk;
2521     while(nwalk--) {
2522             x = (xchar) walklist[nwalk].x;
2523             y = (xchar) walklist[nwalk].y;
2524             dir = walklist[nwalk].dir;
2525
2526             /* don't use move() - it doesn't use W_NORTH, etc. */
2527             switch (dir) {
2528                 case W_NORTH: --y; break;
2529                 case W_SOUTH: y++; break;
2530                 case W_EAST:  x++; break;
2531                 case W_WEST:  --x; break;
2532                 default: panic("load_maze: bad MAZEWALK direction");
2533             }
2534
2535             if(!IS_DOOR(levl[x][y].typ)) {
2536 #ifndef WALLIFIED_MAZE
2537                 levl[x][y].typ = CORR;
2538 #else
2539                 levl[x][y].typ = ROOM;
2540 #endif
2541                 levl[x][y].flags = 0;
2542             }
2543
2544             /*
2545              * We must be sure that the parity of the coordinates for
2546              * walkfrom() is odd.  But we must also take into account
2547              * what direction was chosen.
2548              */
2549             if(!(x % 2)) {
2550                 if (dir == W_EAST)
2551                     x++;
2552                 else
2553                     x--;
2554
2555                 /* no need for IS_DOOR check; out of map bounds */
2556 #ifndef WALLIFIED_MAZE
2557                 levl[x][y].typ = CORR;
2558 #else
2559                 levl[x][y].typ = ROOM;
2560 #endif
2561                 levl[x][y].flags = 0;
2562             }
2563
2564             if (!(y % 2)) {
2565                 if (dir == W_SOUTH)
2566                     y++;
2567                 else
2568                     y--;
2569             }
2570
2571             walkfrom(x, y);
2572     }
2573     wallification(1, 0, COLNO-1, ROWNO-1);
2574
2575     /*
2576      * If there's a significant portion of maze unused by the special level,
2577      * we don't want it empty.
2578      *
2579      * Makes the number of traps, monsters, etc. proportional
2580      * to the size of the maze.
2581      */
2582     mapcountmax = mapcount = (x_maze_max - 2) * (y_maze_max - 2);
2583
2584     for(x = 2; x < x_maze_max; x++)
2585         for(y = 0; y < y_maze_max; y++)
2586             if(Map[x][y]) mapcount--;
2587
2588     if (nwalk_sav && (mapcount > (int) (mapcountmax / 10))) {
2589             mapfact = (int) ((mapcount * 100L) / mapcountmax);
2590             for(x = rnd((int) (20 * mapfact) / 100); x; x--) {
2591                     maze1xy(&mm, DRY);
2592                     (void) mkobj_at(rn2(2) ? GEM_CLASS : RANDOM_CLASS,
2593                                                         mm.x, mm.y, TRUE);
2594             }
2595             for(x = rnd((int) (12 * mapfact) / 100); x; x--) {
2596                     maze1xy(&mm, DRY);
2597                     (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE, FALSE);
2598             }
2599             for (x = rn2(2); x; x--) {
2600                 maze1xy(&mm, DRY);
2601                 (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y, NO_MM_FLAGS);
2602             }
2603             for(x = rnd((int) (12 * mapfact) / 100); x; x--) {
2604                     maze1xy(&mm, WET|DRY);
2605                     (void) makemon((struct permonst *) 0, mm.x, mm.y, NO_MM_FLAGS);
2606             }
2607             for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
2608                     maze1xy(&mm, DRY);
2609                     (void) mkgold(0L,mm.x,mm.y);
2610             }
2611             for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
2612                     int trytrap;
2613
2614                     maze1xy(&mm, DRY);
2615                     trytrap = rndtrap();
2616                     if (sobj_at(BOULDER, mm.x, mm.y))
2617                         while (trytrap == PIT || trytrap == SPIKED_PIT ||
2618                                 trytrap == TRAPDOOR || trytrap == HOLE)
2619                             trytrap = rndtrap();
2620                     (void) maketrap(mm.x, mm.y, trytrap);
2621             }
2622     }
2623     return TRUE;
2624 }
2625
2626 /*
2627  * General loader
2628  */
2629
2630 boolean
2631 load_special(name)
2632 const char *name;
2633 {
2634         dlb *fd;
2635         boolean result = FALSE;
2636         char c;
2637         struct version_info vers_info;
2638
2639         fd = dlb_fopen(name, RDBMODE);
2640         if (!fd) return FALSE;
2641
2642         Fread((genericptr_t) &vers_info, sizeof vers_info, 1, fd);
2643         if (!check_version(&vers_info, name, TRUE))
2644             goto give_up;
2645
2646         Fread((genericptr_t) &c, sizeof c, 1, fd); /* c Header */
2647
2648         switch (c) {
2649                 case SP_LEV_ROOMS:
2650                     result = load_rooms(fd);
2651                     break;
2652                 case SP_LEV_MAZE:
2653                     result = load_maze(fd);
2654                     break;
2655                 default:        /* ??? */
2656                     result = FALSE;
2657         }
2658  give_up:
2659         (void)dlb_fclose(fd);
2660         return result;
2661 }
2662
2663 /*sp_lev.c*/