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. */
6 * This file contains the various functions that are related to the special
8 * It contains also the special level loader.
14 /* #define DEBUG */ /* uncomment to enable code debugging */
18 #define debugpline if (wizard) pline
20 #define debugpline pline
27 extern void FDECL(mkmap, (lev_init *));
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 *,
42 STATIC_DCL void NDECL(fix_stair_rooms);
43 STATIC_DCL void FDECL(create_corridor, (corridor *));
45 STATIC_DCL boolean FDECL(create_subroom, (struct mkroom *, XCHAR_P, XCHAR_P,
46 XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P));
57 #define sq(x) ((x)*(x))
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))
68 static NEARDATA walk walklist[50];
69 extern int min_rx, max_rx, min_ry, max_ry; /* from mkmap.c */
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;
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*));
94 char *lev_message = 0;
95 lev_region *lregions = 0;
100 * Make walls of the area (x1, y1, x2, y2) non diggable/non passwall-able
104 set_wall_property(x1,y1,x2,y2, prop)
105 xchar x1, y1, x2, y2;
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;
117 * Choose randomly the state (nodoor, open, closed or locked) for a door
128 * Select a random trap
136 rtrap = rnd(TRAPNUM-1);
138 case HOLE: /* no random holes on special levels */
139 case MAGIC_PORTAL: rtrap = NO_TRAP;
141 case TRAPDOOR: if (!Can_dig_down(&u.uz)) rtrap = NO_TRAP;
144 case TELEP_TRAP: if (level.flags.noteleport) rtrap = NO_TRAP;
146 case ROLLING_BOULDER_TRAP:
147 case ROCKTRAP: if (In_endgame(&u.uz)) rtrap = NO_TRAP;
150 } while (rtrap == NO_TRAP);
155 * Coordinates in special level files are handled specially:
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.
168 STATIC_DCL boolean FDECL(is_ok_location, (SCHAR_P, SCHAR_P, int));
171 get_location(x, y, humidity)
177 if (*x >= 0) { /* normal locations */
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 */
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);
192 for (xx = 0; xx < xsize; xx++)
193 for (yy = 0; yy < ysize; yy++) {
196 if (is_ok_location(*x,*y,humidity)) goto found_it;
198 panic("get_location: can't find a place!");
204 impossible("get_location: (%d,%d) out of bounds", *x, *y);
205 *x = x_maze_max; *y = y_maze_max;
210 is_ok_location(x, y, humidity)
212 register int humidity;
216 if (Is_waterlevel(&u.uz)) return TRUE; /* accept any spot */
218 if (humidity & DRY) {
219 typ = levl[x][y].typ;
220 if (typ == ROOM || typ == AIR ||
221 typ == CLOUD || typ == ICE || typ == CORR)
224 if (humidity & WET) {
225 if (is_pool(x,y) || is_lava(x,y))
232 * Shuffle the registers for locations, objects or monsters
236 sp_lev_shuffle(list1, list2, n)
237 char list1[], list2[];
243 for (i = n - 1; i > 0; i--) {
244 if ((j = rn2(i + 1)) == i) continue;
257 * Get a relative position inside a room.
258 * negative values for x or y means RANDOM!
262 get_room_loc(x,y, croom)
264 struct mkroom *croom;
268 if (*x <0 && *y <0) {
269 if (somexy(croom, &c)) {
273 panic("get_room_loc : can't find a place!");
276 *x = rn2(croom->hx - croom->lx + 1);
278 *y = rn2(croom->hy - croom->ly + 1);
285 * Get a relative position inside a room.
286 * negative values for x or y means RANDOM!
290 get_free_room_loc(x,y, croom)
292 struct mkroom *croom;
295 register int trycnt = 0;
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);
303 panic("get_free_room_loc: can't find a place!");
304 *x = try_x, *y = try_y;
308 check_room(lowx, ddx, lowy, ddy, vault)
309 xchar *lowx, *ddx, *lowy, *ddy;
312 register int x,y,hix = *lowx + *ddx, hiy = *lowy + *ddy;
313 register struct rm *lev;
314 int xlim, ylim, ymax;
316 xlim = XLIM + (vault ? 1 : 0);
317 ylim = YLIM + (vault ? 1 : 0);
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;
324 if (hix <= *lowx || hiy <= *lowy) return FALSE;
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;
331 if(ymax >= ROWNO) ymax = (ROWNO-1);
333 for (; y <= ymax; y++) {
337 debugpline("strange area [%d,%d] in check_room.",x,y);
339 if (!rn2(3)) return FALSE;
341 *lowx = x + xlim + 1;
345 *lowy = y + ylim + 1;
359 * This is still very incomplete...
363 create_room(x,y,w,h,xal,yal,rtype,rlit)
370 int wtmp, htmp, xaltmp, yaltmp, xtmp, ytmp;
373 boolean vault = FALSE;
374 int xlim = XLIM, ylim = YLIM;
376 if (rtype == -1) /* Is the type random ? */
379 if (rtype == VAULT) {
385 /* on low levels the room is lit (usually) */
386 /* some other rooms may require lighting */
388 /* is light state random ? */
390 rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE;
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
398 xchar xborder, yborder;
401 xaltmp = xal; yaltmp = yal;
403 /* First case : a totaly random room */
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 */
410 if (!r1) { /* No more free rectangles ! */
412 debugpline("No more rects...");
423 dx = 2 + rn2((hx-lx > 28) ? 12 : 8);
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) {
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)) {
442 if(nroom < 4 && dy>1) dy--;
444 if (!check_room(&xabs, &dx, &yabs, &dy, vault)) {
450 r2.lx = xabs-1; r2.ly = yabs-1;
453 } else { /* Only some parameters are random */
455 if (xtmp < 0 && ytmp < 0) { /* Position is RANDOM */
460 if (wtmp < 0 || htmp < 0) { /* Size is RANDOM */
464 if (xaltmp == -1) /* Horizontal alignment is RANDOM */
466 if (yaltmp == -1) /* Vertical alignment is RANDOM */
469 /* Try to generate real (absolute) coordinates here! */
471 xabs = (((xtmp-1) * COLNO) / 5) + 1;
472 yabs = (((ytmp-1) * ROWNO) / 5) + 1;
477 xabs += (COLNO / 5) - wtmp;
480 xabs += ((COLNO / 5) - wtmp) / 2;
487 yabs += (ROWNO / 5) - htmp;
490 yabs += ((ROWNO / 5) - htmp) / 2;
494 if (xabs + wtmp - 1 > COLNO - 2)
495 xabs = COLNO - wtmp - 3;
498 if (yabs + htmp - 1> ROWNO - 2)
499 yabs = ROWNO - htmp - 3;
503 /* Try to find a rectangle that fit our room ! */
505 r2.lx = xabs-1; r2.ly = yabs-1;
506 r2.hx = xabs + wtmp + rndpos;
507 r2.hy = yabs + htmp + rndpos;
510 } while (++trycnt <= 100 && !r1);
511 if (!r1) { /* creation of room failed ? */
514 split_rects(r1, &r2);
518 add_room(xabs, yabs, xabs+wtmp-1, yabs+htmp-1,
521 rooms[nroom].lx = xabs;
522 rooms[nroom].ly = yabs;
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.
533 create_subroom(proom, x, y, w, h, rtype, rlit)
534 struct mkroom *proom;
541 width = proom->hx - proom->lx + 1;
542 height = proom->hy - proom->ly + 1;
544 /* There is a minimum size for the parent room */
545 if (width < 4 || height < 4)
548 /* Check for random position, size, etc... */
555 x = rnd(width - w - 1) - 1;
557 y = rnd(height - h - 1) - 1;
562 if ((x + w + 1) == width)
564 if ((y + h + 1) == height)
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,
577 * Create a new door in a room.
578 * It's placed on a wall (north, south, east or west).
582 create_door(dd, broom)
584 struct mkroom *broom;
589 if (dd->secret == -1)
592 if (dd->mask == -1) {
593 /* is it a locked door, closed, or a doorway? */
602 if (dd->mask != D_ISOPEN && !rn2(25))
603 dd->mask |= D_TRAPPED;
607 if(!rn2(5)) dd->mask = D_LOCKED;
608 else dd->mask = D_CLOSED;
610 if(!rn2(20)) dd->mask |= D_TRAPPED;
615 register int dwall, dpos;
618 if (dwall == -1) /* The wall is RANDOM */
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));
626 /* Convert wall and pos into an absolute coordinate! */
631 x = broom->lx + dpos;
635 x = broom->lx + dpos;
639 y = broom->ly + dpos;
643 y = broom->ly + dpos;
647 panic("create_door: No wall for door!");
652 } while (++trycnt <= 100);
654 impossible("create_door: Can't find a proper place!");
658 levl[x][y].typ = (dd->secret ? SDOOR : DOOR);
659 levl[x][y].doormask = dd->mask;
663 * Create a secret door in croom on any one of the specified walls.
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) */
670 xchar sx, sy; /* location of the secret door */
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);
679 if(!(walls & W_NORTH)) continue;
680 sy = croom->ly-1; break;
682 if(!(walls & W_SOUTH)) continue;
683 sy = croom->hy+1; break;
685 if(!(walls & W_EAST)) continue;
686 sx = croom->lx-1; break;
688 if(!(walls & W_WEST)) continue;
689 sx = croom->hx+1; break;
693 levl[sx][sy].typ = SDOOR;
694 levl[sx][sy].doormask = D_CLOSED;
695 add_door(sx,sy,croom);
700 impossible("couldn't create secret door on any walls 0x%x", walls);
704 * Create a trap in a room.
710 struct mkroom *croom;
715 if (rn2(100) < t->chance) {
719 get_free_room_loc(&x, &y, croom);
721 get_location(&x, &y, DRY);
726 mktrap(t->type, 1, (struct mkroom*) 0, &tm);
731 * Create a monster in a room.
735 noncoalignment(alignment)
743 return(k ? -alignment : 0);
747 create_monster(m,croom)
749 struct mkroom *croom;
759 if (rn2(100) < m->chance) {
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]);
768 if (class == MAXMCLASSES)
769 panic("create_monster: unknown monster class '%c'", m->class);
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);
779 pm = (struct permonst *) 0;
780 else if (m->id != NON_PM) {
782 g_mvflags = (unsigned) mvitals[monsndx(pm)].mvflags;
783 if ((pm->geno & G_UNIQ) && (g_mvflags & G_EXTINCT))
785 else if (g_mvflags & G_GONE) /* genocided or extinct */
786 pm = (struct permonst *) 0; /* make random monster */
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 */
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;
799 get_room_loc(&x, &y, croom);
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);
806 get_location(&x, &y, DRY|WET);
808 /* try to find a close place if someone else is already there */
809 if (MON_AT(x,y) && enexto(&cc, x, y, pm))
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);
819 /* handle specific attributes for some special monsters */
820 if (m->name.str) mtmp = christen_monst(mtmp, m->name.str);
823 * This is currently hardwired for mimics only. It should
824 * eventually be expanded.
826 if (m->appear_as.str && mtmp->data->mlet == S_MIMIC) {
832 "create_monster: mon has an appearance, \"%s\", but no type",
837 for (i = 0; i < MAXPCHARS; i++)
838 if (!strcmp(defsyms[i].explanation,
841 if (i == MAXPCHARS) {
843 "create_monster: can't find feature \"%s\"",
846 mtmp->m_ap_type = M_AP_FURNITURE;
847 mtmp->mappearance = i;
852 for (i = 0; i < NUM_OBJECTS; i++)
853 if (OBJ_NAME(objects[i]) &&
854 !strcmp(OBJ_NAME(objects[i]),m->appear_as.str))
856 if (i == NUM_OBJECTS) {
858 "create_monster: can't find object \"%s\"",
861 mtmp->m_ap_type = M_AP_OBJECT;
862 mtmp->mappearance = i;
867 /* note: mimics don't appear as monsters! */
868 /* (but chameleons can :-) */
871 "create_monster: unimplemented mon appear type [%d,\"%s\"]",
872 m->appear, m->appear_as.str);
875 if (does_block(x, y, &levl[x][y]))
879 if (m->peaceful >= 0) {
880 mtmp->mpeaceful = m->peaceful;
881 /* changed mpeaceful again; have to reset malign */
884 if (m->asleep >= 0) {
886 /* optimizer bug strikes again */
892 mtmp->msleeping = m->asleep;
897 } /* if (rn2(100) < m->chance) */
900 Free(m->appear_as.str);
904 * Create an object in a room.
908 create_object(o,croom)
910 struct mkroom *croom;
915 boolean named; /* has a name been supplied in level description? */
917 if (rn2(100) < o->chance) {
918 named = o->name.str ? TRUE : FALSE;
922 get_room_loc(&x, &y, croom);
924 get_location(&x, &y, DRY);
928 else if (o->class > -11)
929 c = robjects[ -(o->class+1)];
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);
939 * The special levels are compiled with the default "text" object
940 * class characters. We must convert them to the internal format.
942 char oclass = (char) def_char_to_objclass(c);
944 if (oclass == MAXOCLASSES)
945 panic("create_object: unexpected object class '%c'",c);
947 /* KMH -- Create piles of gold properly */
948 if (oclass == COIN_CLASS)
949 otmp = mkgold(0L, x, y);
951 otmp = mkobj_at(oclass, x, y, !named);
954 if (o->spe != -127) /* That means NOT RANDOM! */
955 otmp->spe = (schar)o->spe;
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! */
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;
969 /* assume we wouldn't be given an egg corpsenm unless it was
971 if (otmp->otyp == EGG && otmp->corpsenm != NON_PM) {
972 if (dead_species(otmp->otyp, TRUE))
973 kill_egg(otmp); /* make sure nothing hatches */
975 attach_egg_hatch_timeout(otmp); /* attach new hatch timeout */
979 otmp = oname(otmp, o->name.str);
981 switch(o->containment) {
982 static struct obj *container = 0;
987 impossible("create_object: no container");
991 (void) add_to_container(container, otmp);
992 goto o_done; /* don't stack, but do other cleanup */
995 delete_contents(otmp);
1001 default: impossible("containment type %d?", (int) o->containment);
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.
1008 if (o->id == STATUE && Is_medusa_level(&u.uz) &&
1009 o->corpsenm == NON_PM) {
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).
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;
1024 otmp->corpsenm = wastyp;
1025 while(was->minvent) {
1028 obj_extract_self(obj);
1029 (void) add_to_container(otmp, obj);
1031 otmp->owt = weight(otmp);
1037 } /* if (rn2(100) < o->chance) */
1043 * Randomly place a specific engraving, then release its memory.
1046 create_engraving(e, croom)
1048 struct mkroom *croom;
1054 get_room_loc(&x, &y, croom);
1056 get_location(&x, &y, DRY);
1058 make_engr_at(x, y, e->engr.str, 0L, e->etype);
1059 free((genericptr_t) e->engr.str);
1063 * Create stairs in a room.
1068 create_stairs(s,croom)
1070 struct mkroom *croom;
1075 get_free_room_loc(&x, &y, croom);
1076 mkstairs(x,y,(char)s->up, croom);
1080 * Create an altar in a room.
1084 create_altar(a, croom)
1086 struct mkroom *croom;
1090 boolean croom_is_temple = TRUE;
1096 get_free_room_loc(&x, &y, croom);
1097 if (croom->rtype != TEMPLE)
1098 croom_is_temple = FALSE;
1100 get_location(&x, &y, DRY);
1101 if ((sproom = (schar) *in_rooms(x, y, TEMPLE)) != 0)
1102 croom = &rooms[sproom - ROOMOFFSET];
1104 croom_is_temple = FALSE;
1107 /* check for existing features */
1108 oldtyp = levl[x][y].typ;
1109 if (oldtyp == STAIRS || oldtyp == LADDER)
1115 /* Is the alignment random ?
1116 * If so, it's an 80% chance that the altar will be co-aligned.
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.
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);
1130 levl[x][y].typ = ALTAR;
1131 levl[x][y].altarmask = amask;
1133 if (a->shrine < 0) a->shrine = rn2(2); /* handle random case */
1135 if (oldtyp == FOUNTAIN)
1136 level.flags.nfountains--;
1137 else if (oldtyp == SINK)
1138 level.flags.nsinks--;
1140 if (!croom_is_temple || !a->shrine) return;
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;
1150 * Create a gold pile in a room.
1154 create_gold(g,croom)
1156 struct mkroom *croom;
1162 get_room_loc(&x, &y, croom);
1164 get_location(&x, &y, DRY);
1166 if (g->amount == -1)
1167 g->amount = rnd(200);
1168 (void) mkgold((long) g->amount, x, y);
1172 * Create a feature (e.g a fountain) in a room.
1176 create_feature(fx, fy, croom, typ)
1178 struct mkroom *croom;
1189 get_room_loc(&x, &y, croom);
1190 } while (++trycnt <= 200 && occupied(x,y));
1192 get_room_loc(&x, &y, croom);
1196 get_location(&x, &y, DRY);
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)
1205 levl[x][y].typ = typ;
1206 if (typ == FOUNTAIN)
1207 level.flags.nfountains++;
1208 else if (typ == SINK)
1209 level.flags.nsinks++;
1213 * Search for a door in a room on a specified wall.
1217 search_door(croom,x,y,wall,cnt)
1218 struct mkroom *croom;
1248 dx = dy = xx = yy = 0;
1249 panic("search_door: Bad wall!");
1252 while (xx <= croom->hx+1 && yy <= croom->hy+1) {
1253 if (IS_DOOR(levl[xx][yy].typ) || levl[xx][yy].typ == SDOOR) {
1266 * Dig a corridor between two points.
1270 dig_corridor(org,dest,nxcor,ftyp,btyp)
1275 register int dx=0, dy=0, dix, diy, cct;
1276 register struct rm *crm;
1277 register int tx, ty, xx, yy;
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) {
1285 debugpline("dig_corridor: bad coords : (%d,%d) (%d,%d).",
1290 if (tx > xx) dx = 1;
1291 else if (ty > yy) dy = 1;
1292 else if (tx < xx) dx = -1;
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)))
1306 if(xx >= COLNO-1 || xx <= 0 || yy <= 0 || yy >= ROWNO-1)
1307 return FALSE; /* impossible */
1309 crm = &levl[xx][yy];
1310 if(crm->typ == btyp) {
1311 if(ftyp != CORR || rn2(100)) {
1313 if(nxcor && !rn2(50))
1314 (void) mksobj_at(BOULDER, xx, yy, TRUE, FALSE);
1319 if(crm->typ != ftyp && crm->typ != SCORR) {
1324 /* find next corridor position */
1328 /* do we have to change direction ? */
1329 if(dy && dix > diy) {
1330 register int ddx = (xx > tx) ? -1 : 1;
1332 crm = &levl[xx+ddx][yy];
1333 if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
1338 } else if(dx && diy > dix) {
1339 register int ddy = (yy > ty) ? -1 : 1;
1341 crm = &levl[xx][yy+ddy];
1342 if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
1349 /* continue straight on? */
1350 crm = &levl[xx+dx][yy+dy];
1351 if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
1354 /* no, what must we do now?? */
1357 dy = (ty < yy) ? -1 : 1;
1360 dx = (tx < xx) ? -1 : 1;
1362 crm = &levl[xx+dx][yy+dy];
1363 if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
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.
1381 struct mkroom *croom;
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++) {
1388 if((croom->lx <= xdnstair && xdnstair <= croom->hx) &&
1389 (croom->ly <= ydnstair && ydnstair <= croom->hy)) {
1390 dnstairs_room = croom;
1395 panic("Couldn't find dnstair room in fix_stair_rooms!");
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++) {
1402 if((croom->lx <= xupstair && xupstair <= croom->hx) &&
1403 (croom->ly <= yupstair && yupstair <= croom->hy)) {
1404 upstairs_room = croom;
1409 panic("Couldn't find upstair room in fix_stair_rooms!");
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).
1425 if (c->src.room == -1) {
1432 if( !search_door(&rooms[c->src.room], &org.x, &org.y, c->src.wall,
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))
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;
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;
1452 (void) dig_corridor(&org, &dest, FALSE, CORR, STONE);
1458 * Fill a room (shop, zoo, etc...) with appropriate stuff.
1462 fill_room(croom, prefilled)
1463 struct mkroom *croom;
1466 if (!croom || croom->rtype == OROOM)
1473 if (croom->rtype >= SHOPBASE) {
1474 stock_room(croom->rtype - SHOPBASE, croom);
1475 level.flags.has_shop = TRUE;
1479 switch (croom->rtype) {
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);
1494 switch (croom->rtype) {
1496 level.flags.has_vault = TRUE;
1499 level.flags.has_zoo = TRUE;
1502 level.flags.has_court = TRUE;
1505 level.flags.has_morgue = TRUE;
1508 level.flags.has_beehive = TRUE;
1511 level.flags.has_barracks = TRUE;
1514 level.flags.has_temple = TRUE;
1517 level.flags.has_swamp = TRUE;
1534 if ((j = r->ndoor) != 0) {
1539 if ((j = r->nstair) != 0) {
1544 if ((j = r->naltar) != 0) {
1549 if ((j = r->nfountain) != 0) {
1551 Free(r->fountains[j]);
1554 if ((j = r->nsink) != 0) {
1559 if ((j = r->npool) != 0) {
1564 if ((j = r->ntrap) != 0) {
1569 if ((j = r->nmonster) != 0) {
1571 Free(r->monsters[j]);
1574 if ((j = r->nobject) != 0) {
1576 Free(r->objects[j]);
1579 if ((j = r->ngold) != 0) {
1584 if ((j = r->nengraving) != 0) {
1586 Free(r->engravings[j]);
1587 Free(r->engravings);
1599 struct mkroom *aroom;
1601 xchar rtype = (!r->chance || rn2(100) < r->chance) ? r->rtype : OROOM;
1604 aroom = &subrooms[nsubroom];
1605 okroom = create_subroom(pr->mkr, r->x, r->y, r->w, r->h,
1608 aroom = &rooms[nroom];
1609 okroom = create_room(r->x, r->y, r->w, r->h, r->xalign,
1610 r->yalign, rtype, r->rlit);
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! */
1620 /* Priority to the stairs */
1622 for(i=0; i <r->nstair; i++)
1623 create_stairs(r->stairs[i], aroom);
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,
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);
1639 for(i = 0; i<r->ntrap; i++)
1640 create_trap(r->traps[i], aroom);
1643 for(i = 0; i<r->nmonster; i++)
1644 create_monster(r->monsters[i], aroom);
1647 for(i = 0; i<r->nobject; i++)
1648 create_object(r->objects[i], aroom);
1650 /* The gold piles */
1651 for(i = 0; i<r->ngold; i++)
1652 create_gold(r->golds[i], aroom);
1654 /* The engravings */
1655 for (i = 0; i < r->nengraving; i++)
1656 create_engraving(r->engravings[i], aroom);
1658 #ifdef SPECIALIZATION
1659 topologize(aroom,FALSE); /* set roomno */
1661 topologize(aroom); /* set roomno */
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.
1668 if(aroom->rtype != OROOM && r->filled) fill_room(aroom, FALSE);
1673 * set lighting in a region that will not become a room.
1676 light_region(tmpregion)
1679 register boolean litstate = tmpregion->rlit ? 1 : 0;
1680 register int hiy = tmpregion->y2;
1682 register struct rm *lev;
1683 int lowy = tmpregion->y1;
1684 int lowx = tmpregion->x1, hix = tmpregion->x2;
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);
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;
1703 /* initialization common to all special levels */
1705 load_common_data(fd, typ)
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; }
1720 level.flags.is_maze_lev = typ == SP_LEV_MAZE;
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);
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;
1744 Fread((genericptr_t) &n, 1, sizeof(n), fd);
1746 lev_message = (char *) alloc(n + 1);
1747 Fread((genericptr_t) lev_message, 1, (int) n, fd);
1753 load_one_monster(fd, m)
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';
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';
1771 m->appear_as.str = (char *) 0;
1775 load_one_object(fd, o)
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';
1787 o->name.str = (char *) 0;
1791 load_one_engraving(fd, e)
1797 Fread((genericptr_t) e, 1, sizeof *e, fd);
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';
1808 xchar nrooms, ncorr;
1815 load_common_data(fd, SP_LEV_ROOMS);
1817 Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrobjects */
1819 Fread((genericptr_t)robjects, sizeof(*robjects), n, fd);
1820 sp_lev_shuffle(robjects, (char *)0, (int)n);
1823 Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrmonst */
1825 Fread((genericptr_t)rmonst, sizeof(*rmonst), n, fd);
1826 sp_lev_shuffle(rmonst, (char *)0, (int)n);
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++) {
1835 r = tmproom[i] = New(room);
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);
1844 r->name = (char *) 0;
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;
1853 r->parent = (char *) 0;
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);
1873 Fread((genericptr_t) &r->filled, 1, sizeof(r->filled), fd);
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);
1882 r->doors[(int)n] = New(room_door);
1883 Fread((genericptr_t) r->doors[(int)n], 1,
1884 sizeof(room_door), fd);
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);
1892 r->stairs[(int)n] = New(stair);
1893 Fread((genericptr_t) r->stairs[(int)n], 1,
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);
1902 r->altars[(int)n] = New(altar);
1903 Fread((genericptr_t) r->altars[(int)n], 1,
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);
1913 r->fountains[(int)n] = New(fountain);
1914 Fread((genericptr_t) r->fountains[(int)n], 1,
1915 sizeof(fountain), fd);
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);
1923 r->sinks[(int)n] = New(sink);
1924 Fread((genericptr_t) r->sinks[(int)n], 1, sizeof(sink), fd);
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);
1932 r->pools[(int)n] = New(pool);
1933 Fread((genericptr_t) r->pools[(int)n], 1, sizeof(pool), fd);
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);
1941 r->traps[(int)n] = New(trap);
1942 Fread((genericptr_t) r->traps[(int)n], 1, sizeof(trap), fd);
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);
1950 r->monsters[(int)n] = New(monster);
1951 load_one_monster(fd, r->monsters[(int)n]);
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]);
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);
1972 r->golds[(int)n] = New(gold);
1973 Fread((genericptr_t) r->golds[(int)n], 1, sizeof(gold), fd);
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);
1982 r->engravings[(int)n] = New(engraving);
1983 load_one_engraving(fd, r->engravings[(int)n]);
1990 /* Now that we have loaded all the rooms, search the
1991 * subrooms and create the links.
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];
2007 * Create the rooms now...
2010 for (i=0; i < nrooms; i++)
2011 if(!tmproom[i]->parent)
2012 build_room(tmproom[i], (room *) 0);
2014 free_rooms(tmproom, nrooms);
2016 /* read the corridors */
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);
2028 * Select a random coordinate in the maze.
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.
2035 maze1xy(m, humidity)
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 */
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));
2051 m->x = (xchar)x, m->y = (xchar)y;
2055 * The Big Thing: special maze loader
2057 * Could be cleaner, but it works.
2065 boolean prefilled, room_not_needed;
2067 char n, numpart = 0;
2068 xchar nwalk = 0, nwalk_sav;
2070 char halign, valign;
2074 int mapcount, mapcountmax, mapfact;
2076 lev_region tmplregion;
2086 stair tmpstair, prevstair;
2089 fountain tmpfountain;
2090 engraving tmpengraving;
2091 xchar mustfill[(MAXNROFROOMS+1)*2];
2092 struct trap *badtrap;
2095 (void) memset((genericptr_t)&Map[0][0], 0, sizeof Map);
2096 load_common_data(fd, SP_LEV_MAZE);
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;
2108 (y < 2 || ((x % 2) && (y % 2))) ? STONE : HWALL;
2111 levl[x][y].typ = filling;
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);
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);
2128 Fread((genericptr_t) &ysize, 1, sizeof(ysize), fd);
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;
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;
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");
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.
2159 if(init_lev.init_present && xsize <= 1 && ysize <= 1) {
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;
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.
2183 * Set secret doors to closed (why not trapped too?). Set
2184 * the horizontal bit.
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;
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.
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)
2202 else if(levl[x][y].typ == CROSSWALL)
2206 if (init_lev.init_present && init_lev.joined)
2207 remove_rooms(xstart, ystart, xstart+xsize, ystart+ysize);
2210 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2211 /* Number of level regions */
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);
2225 lregions = (lev_region *)
2226 alloc(sizeof(lev_region) * (unsigned)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';
2237 tmplregion.rname.str = (char *) 0;
2238 if(!tmplregion.in_islev) {
2239 get_location(&tmplregion.inarea.x1, &tmplregion.inarea.y1,
2241 get_location(&tmplregion.inarea.x2, &tmplregion.inarea.y2,
2244 if(!tmplregion.del_islev) {
2245 get_location(&tmplregion.delarea.x1, &tmplregion.delarea.y1,
2247 get_location(&tmplregion.delarea.x2, &tmplregion.delarea.y2,
2250 lregions[(int)n] = tmplregion;
2253 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2254 /* Random objects */
2256 Fread((genericptr_t)robjects, sizeof(*robjects), (int) n, fd);
2257 sp_lev_shuffle(robjects, (char *)0, (int)n);
2260 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2261 /* Random locations */
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);
2268 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2269 /* Random monsters */
2271 Fread((genericptr_t)rmonst, sizeof(*rmonst), (int) n, fd);
2272 sp_lev_shuffle(rmonst, (char *)0, (int)n);
2275 (void) memset((genericptr_t)mustfill, 0, sizeof(mustfill));
2276 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2277 /* Number of subrooms */
2279 register struct mkroom *troom;
2281 Fread((genericptr_t)&tmpregion, 1, sizeof(tmpregion), fd);
2283 if(tmpregion.rtype > MAXRTYPE) {
2284 tmpregion.rtype -= MAXRTYPE+1;
2289 if(tmpregion.rlit < 0)
2290 tmpregion.rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77))
2293 get_location(&tmpregion.x1, &tmpregion.y1, DRY|WET);
2294 get_location(&tmpregion.x2, &tmpregion.y2, DRY|WET);
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);
2308 troom = &rooms[nroom];
2310 /* mark rooms that must be filled, but do it later */
2311 if (tmpregion.rtype != OROOM)
2312 mustfill[nroom] = (prefilled ? 2 : 1);
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;
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 */
2330 topologize(troom); /* set roomno */
2335 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2336 /* Number of doors */
2338 struct mkroom *croom = &rooms[0];
2340 Fread((genericptr_t)&tmpdoor, 1, sizeof(tmpdoor), fd);
2342 x = tmpdoor.x; y = tmpdoor.y;
2343 typ = tmpdoor.mask == -1 ? rnddoor() : tmpdoor.mask;
2345 get_location(&x, &y, DRY);
2346 if(levl[x][y].typ != SDOOR)
2347 levl[x][y].typ = DOOR;
2350 typ = D_CLOSED; /* force it to be closed */
2352 levl[x][y].doormask = typ;
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) {
2360 add_door(x, y, croom);
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));
2371 /* if special boundary syms (CROSSWALL) in map, remove them now */
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;
2379 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2380 /* Number of drawbridges */
2382 Fread((genericptr_t)&tmpdb, 1, sizeof(tmpdb), fd);
2384 x = tmpdb.x; y = tmpdb.y;
2385 get_location(&x, &y, DRY|WET);
2387 if (!create_drawbridge(x, y, tmpdb.dir, tmpdb.db_open))
2388 impossible("Cannot create drawbridge.");
2391 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2392 /* Number of mazewalks */
2394 Fread((genericptr_t)&tmpwalk, 1, sizeof(tmpwalk), fd);
2396 get_location(&tmpwalk.x, &tmpwalk.y, DRY|WET);
2398 walklist[nwalk++] = tmpwalk;
2401 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2402 /* Number of non_diggables */
2404 Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd);
2406 get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET);
2407 get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET);
2409 set_wall_property(tmpdig.x1, tmpdig.y1,
2410 tmpdig.x2, tmpdig.y2, W_NONDIGGABLE);
2413 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2414 /* Number of non_passables */
2416 Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd);
2418 get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET);
2419 get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET);
2421 set_wall_property(tmpdig.x1, tmpdig.y1,
2422 tmpdig.x2, tmpdig.y2, W_NONPASSWALL);
2425 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2426 /* Number of ladders */
2428 Fread((genericptr_t)&tmplad, 1, sizeof(tmplad), fd);
2430 x = tmplad.x; y = tmplad.y;
2431 get_location(&x, &y, DRY);
2433 levl[x][y].typ = LADDER;
2434 if (tmplad.up == 1) {
2435 xupladder = x; yupladder = y;
2436 levl[x][y].ladder = LA_UP;
2438 xdnladder = x; ydnladder = y;
2439 levl[x][y].ladder = LA_DOWN;
2443 prevstair.x = prevstair.y = 0;
2444 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2445 /* Number of stairs */
2447 Fread((genericptr_t)&tmpstair, 1, sizeof(tmpstair), fd);
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);
2461 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2462 /* Number of altars */
2464 Fread((genericptr_t)&tmpaltar, 1, sizeof(tmpaltar), fd);
2466 create_altar(&tmpaltar, (struct mkroom *)0);
2469 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2470 /* Number of fountains */
2472 Fread((genericptr_t)&tmpfountain, 1, sizeof(tmpfountain), fd);
2474 create_feature(tmpfountain.x, tmpfountain.y,
2475 (struct mkroom *)0, FOUNTAIN);
2478 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2479 /* Number of traps */
2481 Fread((genericptr_t)&tmptrap, 1, sizeof(tmptrap), fd);
2483 create_trap(&tmptrap, (struct mkroom *)0);
2486 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2487 /* Number of monsters */
2489 load_one_monster(fd, &tmpmons);
2491 create_monster(&tmpmons, (struct mkroom *)0);
2494 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2495 /* Number of objects */
2497 load_one_object(fd, &tmpobj);
2499 create_object(&tmpobj, (struct mkroom *)0);
2502 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2503 /* Number of gold piles */
2505 Fread((genericptr_t)&tmpgold, 1, sizeof(tmpgold), fd);
2507 create_gold(&tmpgold, (struct mkroom *)0);
2510 Fread((genericptr_t) &n, 1, sizeof(n), fd);
2511 /* Number of engravings */
2513 load_one_engraving(fd, &tmpengraving);
2515 create_engraving(&tmpengraving, (struct mkroom *)0);
2518 } /* numpart loop */
2522 x = (xchar) walklist[nwalk].x;
2523 y = (xchar) walklist[nwalk].y;
2524 dir = walklist[nwalk].dir;
2526 /* don't use move() - it doesn't use W_NORTH, etc. */
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");
2535 if(!IS_DOOR(levl[x][y].typ)) {
2536 #ifndef WALLIFIED_MAZE
2537 levl[x][y].typ = CORR;
2539 levl[x][y].typ = ROOM;
2541 levl[x][y].flags = 0;
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.
2555 /* no need for IS_DOOR check; out of map bounds */
2556 #ifndef WALLIFIED_MAZE
2557 levl[x][y].typ = CORR;
2559 levl[x][y].typ = ROOM;
2561 levl[x][y].flags = 0;
2573 wallification(1, 0, COLNO-1, ROWNO-1);
2576 * If there's a significant portion of maze unused by the special level,
2577 * we don't want it empty.
2579 * Makes the number of traps, monsters, etc. proportional
2580 * to the size of the maze.
2582 mapcountmax = mapcount = (x_maze_max - 2) * (y_maze_max - 2);
2584 for(x = 2; x < x_maze_max; x++)
2585 for(y = 0; y < y_maze_max; y++)
2586 if(Map[x][y]) mapcount--;
2588 if (nwalk_sav && (mapcount > (int) (mapcountmax / 10))) {
2589 mapfact = (int) ((mapcount * 100L) / mapcountmax);
2590 for(x = rnd((int) (20 * mapfact) / 100); x; x--) {
2592 (void) mkobj_at(rn2(2) ? GEM_CLASS : RANDOM_CLASS,
2595 for(x = rnd((int) (12 * mapfact) / 100); x; x--) {
2597 (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE, FALSE);
2599 for (x = rn2(2); x; x--) {
2601 (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y, NO_MM_FLAGS);
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);
2607 for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
2609 (void) mkgold(0L,mm.x,mm.y);
2611 for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
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);
2635 boolean result = FALSE;
2637 struct version_info vers_info;
2639 fd = dlb_fopen(name, RDBMODE);
2640 if (!fd) return FALSE;
2642 Fread((genericptr_t) &vers_info, sizeof vers_info, 1, fd);
2643 if (!check_version(&vers_info, name, TRUE))
2646 Fread((genericptr_t) &c, sizeof c, 1, fd); /* c Header */
2650 result = load_rooms(fd);
2653 result = load_maze(fd);
2659 (void)dlb_fclose(fd);