1 | /* SCCS Id: @(#)sp_lev.c 3.3 1999/11/16 */
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 (!strcmp(OBJ_NAME(objects[i]),
854 | 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 |
916 | if (rn2(100) < o->chance) {
917 |
918 | x = o->x; y = o->y;
919 | if (croom)
920 | get_room_loc(&x, &y, croom);
921 | else
922 | get_location(&x, &y, DRY);
923 |
924 | if (o->class >= 0)
925 | c = o->class;
926 | else if (o->class > -11)
927 | c = robjects[ -(o->class+1)];
928 | else
929 | c = 0;
930 |
931 | if (!c)
932 | otmp = mkobj_at(RANDOM_CLASS, x, y, TRUE);
933 | else if (o->id != -1)
934 | otmp = mksobj_at(o->id, x, y, TRUE);
935 | else {
936 | /*
937 | * The special levels are compiled with the default "text" object
938 | * class characters. We must convert them to the internal format.
939 | */
940 | char oclass = (char) def_char_to_objclass(c);
941 |
942 | if (oclass == MAXOCLASSES)
943 | panic("create_object: unexpected object class '%c'",c);
944 |
945 | /* KMH -- Create piles of gold properly */
946 | if (oclass == GOLD_CLASS)
947 | otmp = mkgold(0L, x, y);
948 | else
949 | otmp = mkobj_at(oclass, x, y, TRUE);
950 | }
951 |
952 | if (o->spe != -127) /* That means NOT RANDOM! */
953 | otmp->spe = (schar)o->spe;
954 |
955 | switch (o->curse_state) {
956 | case 1: bless(otmp); break; /* BLESSED */
957 | case 2: unbless(otmp); uncurse(otmp); break; /* uncursed */
958 | case 3: curse(otmp); break; /* CURSED */
959 | default: break; /* Otherwise it's random and we're happy
960 | * with what mkobj gave us! */
961 | }
962 |
963 | /* corpsenm is "empty" if -1, random if -2, otherwise specific */
964 | if (o->corpsenm == NON_PM - 1) otmp->corpsenm = rndmonnum();
965 | else if (o->corpsenm != NON_PM) otmp->corpsenm = o->corpsenm;
966 |
967 | /* assume we wouldn't be given an egg corpsenm unless it was
968 | hatchable */
969 | if (otmp->otyp == EGG && otmp->corpsenm != NON_PM) {
970 | if (dead_species(otmp->otyp, TRUE))
971 | kill_egg(otmp); /* make sure nothing hatches */
972 | else
973 | attach_egg_hatch_timeout(otmp); /* attach new hatch timeout */
974 | }
975 |
976 | if (o->name.str) { /* Give a name to that object */
977 | otmp = oname(otmp, o->name.str);
978 | }
979 |
980 | switch(o->containment) {
981 | static struct obj *container = 0;
982 |
983 | /* contents */
984 | case 1:
985 | if (!container) {
986 | impossible("create_object: no container");
987 | break;
988 | }
989 | remove_object(otmp);
990 | add_to_container(container, otmp);
991 | goto o_done; /* don't stack, but do other cleanup */
992 | /* container */
993 | case 2:
994 | delete_contents(otmp);
995 | container = otmp;
996 | break;
997 | /* nothing */
998 | case 0: break;
999 |
1000 | default: impossible("containment type %d?", (int) o->containment);
1001 | }
1002 |
1003 | /* Medusa level special case: statues are petrified monsters, so they
1004 | * are not stone-resistant and have monster inventory. They also lack
1005 | * other contents, but that can be specified as an empty container.
1006 | */
1007 | if (o->id == STATUE && Is_medusa_level(&u.uz) &&
1008 | o->corpsenm == NON_PM) {
1009 | struct monst *was;
1010 | struct obj *obj;
1011 | int wastyp;
1012 |
1013 | /* Named random statues are of player types, and aren't stone-
1014 | * resistant (if they were, we'd have to reset the name as well as
1015 | * setting corpsenm).
1016 | */
1017 | for (wastyp = otmp->corpsenm; ; wastyp = rndmonnum()) {
1018 | /* makemon without rndmonst() might create a group */
1019 | was = makemon(&mons[wastyp], 0, 0, NO_MM_FLAGS);
1020 | if (!resists_ston(was)) break;
1021 | mongone(was);
1022 | }
1023 | otmp->corpsenm = wastyp;
1024 | while(was->minvent) {
1025 | obj = was->minvent;
1026 | obj->owornmask = 0;
1027 | obj_extract_self(obj);
1028 | add_to_container(otmp, obj);
1029 | }
1030 | mongone(was);
1031 | }
1032 |
1033 | stackobj(otmp);
1034 |
1035 | } /* if (rn2(100) < o->chance) */
1036 | o_done:
1037 | Free(o->name.str);
1038 | }
1039 |
1040 | /*
1041 | * Randomly place a specific engraving, then release its memory.
1042 | */
1043 | STATIC_OVL void
1044 | create_engraving(e, croom)
1045 | engraving *e;
1046 | struct mkroom *croom;
1047 | {
1048 | xchar x, y;
1049 |
1050 | x = e->x, y = e->y;
1051 | if (croom)
1052 | get_room_loc(&x, &y, croom);
1053 | else
1054 | get_location(&x, &y, DRY);
1055 |
1056 | make_engr_at(x, y, e->engr.str, 0L, e->etype);
1057 | free((genericptr_t) e->engr.str);
1058 | }
1059 |
1060 | /*
1061 | * Create stairs in a room.
1062 | *
1063 | */
1064 |
1065 | STATIC_OVL void
1066 | create_stairs(s,croom)
1067 | stair *s;
1068 | struct mkroom *croom;
1069 | {
1070 | schar x,y;
1071 |
1072 | x = s->x; y = s->y;
1073 | get_free_room_loc(&x, &y, croom);
1074 | mkstairs(x,y,(char)s->up, croom);
1075 | }
1076 |
1077 | /*
1078 | * Create an altar in a room.
1079 | */
1080 |
1081 | STATIC_OVL void
1082 | create_altar(a, croom)
1083 | altar *a;
1084 | struct mkroom *croom;
1085 | {
1086 | schar sproom,x,y;
1087 | aligntyp amask;
1088 | boolean croom_is_temple = TRUE;
1089 | int oldtyp;
1090 |
1091 | x = a->x; y = a->y;
1092 |
1093 | if (croom) {
1094 | get_free_room_loc(&x, &y, croom);
1095 | if (croom->rtype != TEMPLE)
1096 | croom_is_temple = FALSE;
1097 | } else {
1098 | get_location(&x, &y, DRY);
1099 | if ((sproom = (schar) *in_rooms(x, y, TEMPLE)) != 0)
1100 | croom = &rooms[sproom - ROOMOFFSET];
1101 | else
1102 | croom_is_temple = FALSE;
1103 | }
1104 |
1105 | /* check for existing features */
1106 | oldtyp = levl[x][y].typ;
1107 | if (oldtyp == STAIRS || oldtyp == LADDER)
1108 | return;
1109 |
1110 | a->x = x;
1111 | a->y = y;
1112 |
1113 | /* Is the alignment random ?
1114 | * If so, it's an 80% chance that the altar will be co-aligned.
1115 | *
1116 | * The alignment is encoded as amask values instead of alignment
1117 | * values to avoid conflicting with the rest of the encoding,
1118 | * shared by many other parts of the special level code.
1119 | */
1120 |
1121 | amask = (a->align == AM_SPLEV_CO) ?
1122 | Align2amask(u.ualignbase[A_ORIGINAL]) :
1123 | (a->align == AM_SPLEV_NONCO) ?
1124 | Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL])) :
1125 | (a->align == -11) ? induced_align(80) :
1126 | (a->align < 0 ? ralign[-a->align-1] : a->align);
1127 |
1128 | levl[x][y].typ = ALTAR;
1129 | levl[x][y].altarmask = amask;
1130 |
1131 | if (a->shrine == -11) a->shrine = rn2(1); /* handle random case */
1132 |
1133 | if (oldtyp == FOUNTAIN)
1134 | level.flags.nfountains--;
1135 | else if (oldtyp == SINK)
1136 | level.flags.nsinks--;
1137 |
1138 | if (!croom_is_temple || !a->shrine) return;
1139 |
1140 | if (a->shrine) { /* Is it a shrine or sanctum? */
1141 | priestini(&u.uz, croom, x, y, (a->shrine > 1));
1142 | levl[x][y].altarmask |= AM_SHRINE;
1143 | level.flags.has_temple = TRUE;
1144 | }
1145 | }
1146 |
1147 | /*
1148 | * Create a gold pile in a room.
1149 | */
1150 |
1151 | STATIC_OVL void
1152 | create_gold(g,croom)
1153 | gold *g;
1154 | struct mkroom *croom;
1155 | {
1156 | schar x,y;
1157 |
1158 | x = g->x; y= g->y;
1159 | if (croom)
1160 | get_room_loc(&x, &y, croom);
1161 | else
1162 | get_location(&x, &y, DRY);
1163 |
1164 | if (g->amount == -1)
1165 | g->amount = rnd(200);
1166 | (void) mkgold((long) g->amount, x, y);
1167 | }
1168 |
1169 | /*
1170 | * Create a feature (e.g a fountain) in a room.
1171 | */
1172 |
1173 | STATIC_OVL void
1174 | create_feature(fx, fy, croom, typ)
1175 | int fx, fy;
1176 | struct mkroom *croom;
1177 | int typ;
1178 | {
1179 | schar x,y;
1180 | int trycnt = 0;
1181 |
1182 | x = fx; y = fy;
1183 | if (croom) {
1184 | if (x < 0 && y < 0)
1185 | do {
1186 | x = -1; y = -1;
1187 | get_room_loc(&x, &y, croom);
1188 | } while (++trycnt <= 200 && occupied(x,y));
1189 | else
1190 | get_room_loc(&x, &y, croom);
1191 | if(trycnt > 200)
1192 | return;
1193 | } else {
1194 | get_location(&x, &y, DRY);
1195 | }
1196 | /* Don't cover up an existing feature (particularly randomly
1197 | placed stairs). However, if the _same_ feature is already
1198 | here, it came from the map drawing and we still need to
1199 | update the special counters. */
1200 | if (IS_FURNITURE(levl[x][y].typ) && levl[x][y].typ != typ)
1201 | return;
1202 |
1203 | levl[x][y].typ = typ;
1204 | if (typ == FOUNTAIN)
1205 | level.flags.nfountains++;
1206 | else if (typ == SINK)
1207 | level.flags.nsinks++;
1208 | }
1209 |
1210 | /*
1211 | * Search for a door in a room on a specified wall.
1212 | */
1213 |
1214 | STATIC_OVL boolean
1215 | search_door(croom,x,y,wall,cnt)
1216 | struct mkroom *croom;
1217 | xchar *x, *y;
1218 | xchar wall;
1219 | int cnt;
1220 | {
1221 | int dx, dy;
1222 | int xx,yy;
1223 |
1224 | switch(wall) {
1225 | case W_NORTH:
1226 | dy = 0; dx = 1;
1227 | xx = croom->lx;
1228 | yy = croom->hy + 1;
1229 | break;
1230 | case W_SOUTH:
1231 | dy = 0; dx = 1;
1232 | xx = croom->lx;
1233 | yy = croom->ly - 1;
1234 | break;
1235 | case W_EAST:
1236 | dy = 1; dx = 0;
1237 | xx = croom->hx + 1;
1238 | yy = croom->ly;
1239 | break;
1240 | case W_WEST:
1241 | dy = 1; dx = 0;
1242 | xx = croom->lx - 1;
1243 | yy = croom->ly;
1244 | break;
1245 | default:
1246 | dx = dy = xx = yy = 0;
1247 | panic("search_door: Bad wall!");
1248 | break;
1249 | }
1250 | while (xx <= croom->hx+1 && yy <= croom->hy+1) {
1251 | if (IS_DOOR(levl[xx][yy].typ) || levl[xx][yy].typ == SDOOR) {
1252 | *x = xx;
1253 | *y = yy;
1254 | if (cnt-- <= 0)
1255 | return TRUE;
1256 | }
1257 | xx += dx;
1258 | yy += dy;
1259 | }
1260 | return FALSE;
1261 | }
1262 |
1263 | /*
1264 | * Dig a corridor between two points.
1265 | */
1266 |
1267 | boolean
1268 | dig_corridor(org,dest,nxcor,ftyp,btyp)
1269 | coord *org, *dest;
1270 | boolean nxcor;
1271 | schar ftyp, btyp;
1272 | {
1273 | register int dx=0, dy=0, dix, diy, cct;
1274 | register struct rm *crm;
1275 | register int tx, ty, xx, yy;
1276 |
1277 | xx = org->x; yy = org->y;
1278 | tx = dest->x; ty = dest->y;
1279 | if (xx <= 0 || yy <= 0 || tx <= 0 || ty <= 0 ||
1280 | xx > COLNO-1 || tx > COLNO-1 ||
1281 | yy > ROWNO-1 || ty > ROWNO-1) {
1282 | #ifdef DEBUG
1283 | debugpline("dig_corridor: bad coords : (%d,%d) (%d,%d).",
1284 | xx,yy,tx,ty);
1285 | #endif
1286 | return FALSE;
1287 | }
1288 | if (tx > xx) dx = 1;
1289 | else if (ty > yy) dy = 1;
1290 | else if (tx < xx) dx = -1;
1291 | else dy = -1;
1292 |
1293 | xx -= dx;
1294 | yy -= dy;
1295 | cct = 0;
1296 | while(xx != tx || yy != ty) {
1297 | /* loop: dig corridor at [xx,yy] and find new [xx,yy] */
1298 | if(cct++ > 500 || (nxcor && !rn2(35)))
1299 | return FALSE;
1300 |
1301 | xx += dx;
1302 | yy += dy;
1303 |
1304 | if(xx >= COLNO-1 || xx <= 0 || yy <= 0 || yy >= ROWNO-1)
1305 | return FALSE; /* impossible */
1306 |
1307 | crm = &levl[xx][yy];
1308 | if(crm->typ == btyp) {
1309 | if(ftyp != CORR || rn2(100)) {
1310 | crm->typ = ftyp;
1311 | if(nxcor && !rn2(50))
1312 | (void) mksobj_at(BOULDER, xx, yy, TRUE);
1313 | } else {
1314 | crm->typ = SCORR;
1315 | }
1316 | } else
1317 | if(crm->typ != ftyp && crm->typ != SCORR) {
1318 | /* strange ... */
1319 | return FALSE;
1320 | }
1321 |
1322 | /* find next corridor position */
1323 | dix = abs(xx-tx);
1324 | diy = abs(yy-ty);
1325 |
1326 | /* do we have to change direction ? */
1327 | if(dy && dix > diy) {
1328 | register int ddx = (xx > tx) ? -1 : 1;
1329 |
1330 | crm = &levl[xx+ddx][yy];
1331 | if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
1332 | dx = ddx;
1333 | dy = 0;
1334 | continue;
1335 | }
1336 | } else if(dx && diy > dix) {
1337 | register int ddy = (yy > ty) ? -1 : 1;
1338 |
1339 | crm = &levl[xx][yy+ddy];
1340 | if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) {
1341 | dy = ddy;
1342 | dx = 0;
1343 | continue;
1344 | }
1345 | }
1346 |
1347 | /* continue straight on? */
1348 | crm = &levl[xx+dx][yy+dy];
1349 | if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
1350 | continue;
1351 |
1352 | /* no, what must we do now?? */
1353 | if(dx) {
1354 | dx = 0;
1355 | dy = (ty < yy) ? -1 : 1;
1356 | } else {
1357 | dy = 0;
1358 | dx = (tx < xx) ? -1 : 1;
1359 | }
1360 | crm = &levl[xx+dx][yy+dy];
1361 | if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR)
1362 | continue;
1363 | dy = -dy;
1364 | dx = -dx;
1365 | }
1366 | return TRUE;
1367 | }
1368 |
1369 | /*
1370 | * Disgusting hack: since special levels have their rooms filled before
1371 | * sorting the rooms, we have to re-arrange the speed values upstairs_room
1372 | * and dnstairs_room after the rooms have been sorted. On normal levels,
1373 | * stairs don't get created until _after_ sorting takes place.
1374 | */
1375 | STATIC_OVL void
1376 | fix_stair_rooms()
1377 | {
1378 | int i;
1379 | struct mkroom *croom;
1380 |
1381 | if(xdnstair &&
1382 | !((dnstairs_room->lx <= xdnstair && xdnstair <= dnstairs_room->hx) &&
1383 | (dnstairs_room->ly <= ydnstair && ydnstair <= dnstairs_room->hy))) {
1384 | for(i=0; i < nroom; i++) {
1385 | croom = &rooms[i];
1386 | if((croom->lx <= xdnstair && xdnstair <= croom->hx) &&
1387 | (croom->ly <= ydnstair && ydnstair <= croom->hy)) {
1388 | dnstairs_room = croom;
1389 | break;
1390 | }
1391 | }
1392 | if(i == nroom)
1393 | panic("Couldn't find dnstair room in fix_stair_rooms!");
1394 | }
1395 | if(xupstair &&
1396 | !((upstairs_room->lx <= xupstair && xupstair <= upstairs_room->hx) &&
1397 | (upstairs_room->ly <= yupstair && yupstair <= upstairs_room->hy))) {
1398 | for(i=0; i < nroom; i++) {
1399 | croom = &rooms[i];
1400 | if((croom->lx <= xupstair && xupstair <= croom->hx) &&
1401 | (croom->ly <= yupstair && yupstair <= croom->hy)) {
1402 | upstairs_room = croom;
1403 | break;
1404 | }
1405 | }
1406 | if(i == nroom)
1407 | panic("Couldn't find upstair room in fix_stair_rooms!");
1408 | }
1409 | }
1410 |
1411 | /*
1412 | * Corridors always start from a door. But it can end anywhere...
1413 | * Basically we search for door coordinates or for endpoints coordinates
1414 | * (from a distance).
1415 | */
1416 |
1417 | STATIC_OVL void
1418 | create_corridor(c)
1419 | corridor *c;
1420 | {
1421 | coord org, dest;
1422 |
1423 | if (c->src.room == -1) {
1424 | sort_rooms();
1425 | fix_stair_rooms();
1426 | makecorridors();
1427 | return;
1428 | }
1429 |
1430 | if( !search_door(&rooms[c->src.room], &org.x, &org.y, c->src.wall,
1431 | c->src.door))
1432 | return;
1433 |
1434 | if (c->dest.room != -1) {
1435 | if(!search_door(&rooms[c->dest.room], &dest.x, &dest.y,
1436 | c->dest.wall, c->dest.door))
1437 | return;
1438 | switch(c->src.wall) {
1439 | case W_NORTH: org.y--; break;
1440 | case W_SOUTH: org.y++; break;
1441 | case W_WEST: org.x--; break;
1442 | case W_EAST: org.x++; break;
1443 | }
1444 | switch(c->dest.wall) {
1445 | case W_NORTH: dest.y--; break;
1446 | case W_SOUTH: dest.y++; break;
1447 | case W_WEST: dest.x--; break;
1448 | case W_EAST: dest.x++; break;
1449 | }
1450 | (void) dig_corridor(&org, &dest, FALSE, CORR, STONE);
1451 | }
1452 | }
1453 |
1454 |
1455 | /*
1456 | * Fill a room (shop, zoo, etc...) with appropriate stuff.
1457 | */
1458 |
1459 | void
1460 | fill_room(croom, prefilled)
1461 | struct mkroom *croom;
1462 | boolean prefilled;
1463 | {
1464 | if (!croom || croom->rtype == OROOM)
1465 | return;
1466 |
1467 | if (!prefilled) {
1468 | int x,y;
1469 |
1470 | /* Shop ? */
1471 | if (croom->rtype >= SHOPBASE) {
1472 | stock_room(croom->rtype - SHOPBASE, croom);
1473 | level.flags.has_shop = TRUE;
1474 | return;
1475 | }
1476 |
1477 | switch (croom->rtype) {
1478 | case VAULT:
1479 | for (x=croom->lx;x<=croom->hx;x++)
1480 | for (y=croom->ly;y<=croom->hy;y++)
1481 | (void) mkgold((long)rn1(abs(depth(&u.uz))*100, 51), x, y);
1482 | break;
1483 | case COURT:
1484 | case ZOO:
1485 | case BEEHIVE:
1486 | case MORGUE:
1487 | case BARRACKS:
1488 | fill_zoo(croom);
1489 | break;
1490 | }
1491 | }
1492 | switch (croom->rtype) {
1493 | case VAULT:
1494 | level.flags.has_vault = TRUE;
1495 | break;
1496 | case ZOO:
1497 | level.flags.has_zoo = TRUE;
1498 | break;
1499 | case COURT:
1500 | level.flags.has_court = TRUE;
1501 | break;
1502 | case MORGUE:
1503 | level.flags.has_morgue = TRUE;
1504 | break;
1505 | case BEEHIVE:
1506 | level.flags.has_beehive = TRUE;
1507 | break;
1508 | case BARRACKS:
1509 | level.flags.has_barracks = TRUE;
1510 | break;
1511 | case TEMPLE:
1512 | level.flags.has_temple = TRUE;
1513 | break;
1514 | case SWAMP:
1515 | level.flags.has_swamp = TRUE;
1516 | break;
1517 | }
1518 | }
1519 |
1520 | STATIC_OVL void
1521 | free_rooms(ro, n)
1522 | room **ro;
1523 | int n;
1524 | {
1525 | short j;
1526 | room *r;
1527 |
1528 | while(n--) {
1529 | r = ro[n];
1530 | Free(r->name);
1531 | Free(r->parent);
1532 | if ((j = r->ndoor) != 0) {
1533 | while(j--)
1534 | Free(r->doors[j]);
1535 | Free(r->doors);
1536 | }
1537 | if ((j = r->nstair) != 0) {
1538 | while(j--)
1539 | Free(r->stairs[j]);
1540 | Free(r->stairs);
1541 | }
1542 | if ((j = r->naltar) != 0) {
1543 | while (j--)
1544 | Free(r->altars[j]);
1545 | Free(r->altars);
1546 | }
1547 | if ((j = r->nfountain) != 0) {
1548 | while(j--)
1549 | Free(r->fountains[j]);
1550 | Free(r->fountains);
1551 | }
1552 | if ((j = r->nsink) != 0) {
1553 | while(j--)
1554 | Free(r->sinks[j]);
1555 | Free(r->sinks);
1556 | }
1557 | if ((j = r->npool) != 0) {
1558 | while(j--)
1559 | Free(r->pools[j]);
1560 | Free(r->pools);
1561 | }
1562 | if ((j = r->ntrap) != 0) {
1563 | while (j--)
1564 | Free(r->traps[j]);
1565 | Free(r->traps);
1566 | }
1567 | if ((j = r->nmonster) != 0) {
1568 | while (j--)
1569 | Free(r->monsters[j]);
1570 | Free(r->monsters);
1571 | }
1572 | if ((j = r->nobject) != 0) {
1573 | while (j--)
1574 | Free(r->objects[j]);
1575 | Free(r->objects);
1576 | }
1577 | if ((j = r->ngold) != 0) {
1578 | while(j--)
1579 | Free(r->golds[j]);
1580 | Free(r->golds);
1581 | }
1582 | if ((j = r->nengraving) != 0) {
1583 | while (j--)
1584 | Free(r->engravings[j]);
1585 | Free(r->engravings);
1586 | }
1587 | Free(r);
1588 | }
1589 | Free(ro);
1590 | }
1591 |
1592 | STATIC_OVL void
1593 | build_room(r, pr)
1594 | room *r, *pr;
1595 | {
1596 | boolean okroom;
1597 | struct mkroom *aroom;
1598 | short i;
1599 | xchar rtype = (!r->chance || rn2(100) < r->chance) ? r->rtype : OROOM;
1600 |
1601 | if(pr) {
1602 | aroom = &subrooms[nsubroom];
1603 | okroom = create_subroom(pr->mkr, r->x, r->y, r->w, r->h,
1604 | rtype, r->rlit);
1605 | } else {
1606 | aroom = &rooms[nroom];
1607 | okroom = create_room(r->x, r->y, r->w, r->h, r->xalign,
1608 | r->yalign, rtype, r->rlit);
1609 | r->mkr = aroom;
1610 | }
1611 |
1612 | if (okroom) {
1613 | /* Create subrooms if necessary... */
1614 | for(i=0; i < r->nsubroom; i++)
1615 | build_room(r->subrooms[i], r);
1616 | /* And now we can fill the room! */
1617 |
1618 | /* Priority to the stairs */
1619 |
1620 | for(i=0; i <r->nstair; i++)
1621 | create_stairs(r->stairs[i], aroom);
1622 |
1623 | /* Then to the various elements (sinks, etc..) */
1624 | for(i = 0; i<r->nsink; i++)
1625 | create_feature(r->sinks[i]->x, r->sinks[i]->y, aroom, SINK);
1626 | for(i = 0; i<r->npool; i++)
1627 | create_feature(r->pools[i]->x, r->pools[i]->y, aroom, POOL);
1628 | for(i = 0; i<r->nfountain; i++)
1629 | create_feature(r->fountains[i]->x, r->fountains[i]->y,
1630 | aroom, FOUNTAIN);
1631 | for(i = 0; i<r->naltar; i++)
1632 | create_altar(r->altars[i], aroom);
1633 | for(i = 0; i<r->ndoor; i++)
1634 | create_door(r->doors[i], aroom);
1635 |
1636 | /* The traps */
1637 | for(i = 0; i<r->ntrap; i++)
1638 | create_trap(r->traps[i], aroom);
1639 |
1640 | /* The monsters */
1641 | for(i = 0; i<r->nmonster; i++)
1642 | create_monster(r->monsters[i], aroom);
1643 |
1644 | /* The objects */
1645 | for(i = 0; i<r->nobject; i++)
1646 | create_object(r->objects[i], aroom);
1647 |
1648 | /* The gold piles */
1649 | for(i = 0; i<r->ngold; i++)
1650 | create_gold(r->golds[i], aroom);
1651 |
1652 | /* The engravings */
1653 | for (i = 0; i < r->nengraving; i++)
1654 | create_engraving(r->engravings[i], aroom);
1655 |
1656 | #ifdef SPECIALIZATION
1657 | topologize(aroom,FALSE); /* set roomno */
1658 | #else
1659 | topologize(aroom); /* set roomno */
1660 | #endif
1661 | /* MRS - 07/04/91 - This is temporary but should result
1662 | * in proper filling of shops, etc.
1663 | * DLC - this can fail if corridors are added to this room
1664 | * at a later point. Currently no good way to fix this.
1665 | */
1666 | if(aroom->rtype != OROOM && r->filled) fill_room(aroom, FALSE);
1667 | }
1668 | }
1669 |
1670 | /*
1671 | * set lighting in a region that will not become a room.
1672 | */
1673 | STATIC_OVL void
1674 | light_region(tmpregion)
1675 | region *tmpregion;
1676 | {
1677 | register boolean litstate = tmpregion->rlit ? 1 : 0;
1678 | register int hiy = tmpregion->y2;
1679 | register int x, y;
1680 | register struct rm *lev;
1681 | int lowy = tmpregion->y1;
1682 | int lowx = tmpregion->x1, hix = tmpregion->x2;
1683 |
1684 | if(litstate) {
1685 | /* adjust region size for walls, but only if lighted */
1686 | lowx = max(lowx-1,1);
1687 | hix = min(hix+1,COLNO-1);
1688 | lowy = max(lowy-1,0);
1689 | hiy = min(hiy+1, ROWNO-1);
1690 | }
1691 | for(x = lowx; x <= hix; x++) {
1692 | lev = &levl[x][lowy];
1693 | for(y = lowy; y <= hiy; y++) {
1694 | if (lev->typ != LAVAPOOL) /* this overrides normal lighting */
1695 | lev->lit = litstate;
1696 | lev++;
1697 | }
1698 | }
1699 | }
1700 |
1701 | /* initialization common to all special levels */
1702 | STATIC_OVL void
1703 | load_common_data(fd, typ)
1704 | dlb *fd;
1705 | int typ;
1706 | {
1707 | uchar n;
1708 | long lev_flags;
1709 | int i;
1710 |
1711 | {
1712 | aligntyp atmp;
1713 | /* shuffle 3 alignments; can't use sp_lev_shuffle() on aligntyp's */
1714 | i = rn2(3); atmp=ralign[2]; ralign[2]=ralign[i]; ralign[i]=atmp;
1715 | if (rn2(2)) { atmp=ralign[1]; ralign[1]=ralign[0]; ralign[0]=atmp; }
1716 | }
1717 |
1718 | level.flags.is_maze_lev = typ == SP_LEV_MAZE;
1719 |
1720 | /* Read the level initialization data */
1721 | Fread((genericptr_t) &init_lev, 1, sizeof(lev_init), fd);
1722 | if(init_lev.init_present) {
1723 | if(init_lev.lit < 0)
1724 | init_lev.lit = rn2(2);
1725 | mkmap(&init_lev);
1726 | }
1727 |
1728 | /* Read the per level flags */
1729 | Fread((genericptr_t) &lev_flags, 1, sizeof(lev_flags), fd);
1730 | if (lev_flags & NOTELEPORT)
1731 | level.flags.noteleport = 1;
1732 | if (lev_flags & HARDFLOOR)
1733 | level.flags.hardfloor = 1;
1734 | if (lev_flags & NOMMAP)
1735 | level.flags.nommap = 1;
1736 | if (lev_flags & SHORTSIGHTED)
1737 | level.flags.shortsighted = 1;
1738 | if (lev_flags & ARBOREAL)
1739 | level.flags.arboreal = 1;
1740 |
1741 | /* Read message */
1742 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
1743 | if (n) {
1744 | lev_message = (char *) alloc(n + 1);
1745 | Fread((genericptr_t) lev_message, 1, (int) n, fd);
1746 | lev_message[n] = 0;
1747 | }
1748 | }
1749 |
1750 | STATIC_OVL void
1751 | load_one_monster(fd, m)
1752 | dlb *fd;
1753 | monster *m;
1754 | {
1755 | int size;
1756 |
1757 | Fread((genericptr_t) m, 1, sizeof *m, fd);
1758 | if ((size = m->name.len) != 0) {
1759 | m->name.str = (char *) alloc((unsigned)size + 1);
1760 | Fread((genericptr_t) m->name.str, 1, size, fd);
1761 | m->name.str[size] = '\0';
1762 | } else
1763 | m->name.str = (char *) 0;
1764 | if ((size = m->appear_as.len) != 0) {
1765 | m->appear_as.str = (char *) alloc((unsigned)size + 1);
1766 | Fread((genericptr_t) m->appear_as.str, 1, size, fd);
1767 | m->appear_as.str[size] = '\0';
1768 | } else
1769 | m->appear_as.str = (char *) 0;
1770 | }
1771 |
1772 | STATIC_OVL void
1773 | load_one_object(fd, o)
1774 | dlb *fd;
1775 | object *o;
1776 | {
1777 | int size;
1778 |
1779 | Fread((genericptr_t) o, 1, sizeof *o, fd);
1780 | if ((size = o->name.len) != 0) {
1781 | o->name.str = (char *) alloc((unsigned)size + 1);
1782 | Fread((genericptr_t) o->name.str, 1, size, fd);
1783 | o->name.str[size] = '\0';
1784 | } else
1785 | o->name.str = (char *) 0;
1786 | }
1787 |
1788 | STATIC_OVL void
1789 | load_one_engraving(fd, e)
1790 | dlb *fd;
1791 | engraving *e;
1792 | {
1793 | int size;
1794 |
1795 | Fread((genericptr_t) e, 1, sizeof *e, fd);
1796 | size = e->engr.len;
1797 | e->engr.str = (char *) alloc((unsigned)size+1);
1798 | Fread((genericptr_t) e->engr.str, 1, size, fd);
1799 | e->engr.str[size] = '\0';
1800 | }
1801 |
1802 | STATIC_OVL boolean
1803 | load_rooms(fd)
1804 | dlb *fd;
1805 | {
1806 | xchar nrooms, ncorr;
1807 | char n;
1808 | short size;
1809 | corridor tmpcor;
1810 | room** tmproom;
1811 | int i, j;
1812 |
1813 | load_common_data(fd, SP_LEV_ROOMS);
1814 |
1815 | Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrobjects */
1816 | if (n) {
1817 | Fread((genericptr_t)robjects, sizeof(*robjects), n, fd);
1818 | sp_lev_shuffle(robjects, (char *)0, (int)n);
1819 | }
1820 |
1821 | Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrmonst */
1822 | if (n) {
1823 | Fread((genericptr_t)rmonst, sizeof(*rmonst), n, fd);
1824 | sp_lev_shuffle(rmonst, (char *)0, (int)n);
1825 | }
1826 |
1827 | Fread((genericptr_t) &nrooms, 1, sizeof(nrooms), fd);
1828 | /* Number of rooms to read */
1829 | tmproom = NewTab(room,nrooms);
1830 | for (i=0;i<nrooms;i++) {
1831 | room *r;
1832 |
1833 | r = tmproom[i] = New(room);
1834 |
1835 | /* Let's see if this room has a name */
1836 | Fread((genericptr_t) &size, 1, sizeof(size), fd);
1837 | if (size > 0) { /* Yup, it does! */
1838 | r->name = (char *) alloc((unsigned)size + 1);
1839 | Fread((genericptr_t) r->name, 1, size, fd);
1840 | r->name[size] = 0;
1841 | } else
1842 | r->name = (char *) 0;
1843 |
1844 | /* Let's see if this room has a parent */
1845 | Fread((genericptr_t) &size, 1, sizeof(size), fd);
1846 | if (size > 0) { /* Yup, it does! */
1847 | r->parent = (char *) alloc((unsigned)size + 1);
1848 | Fread((genericptr_t) r->parent, 1, size, fd);
1849 | r->parent[size] = 0;
1850 | } else
1851 | r->parent = (char *) 0;
1852 |
1853 | Fread((genericptr_t) &r->x, 1, sizeof(r->x), fd);
1854 | /* x pos on the grid (1-5) */
1855 | Fread((genericptr_t) &r->y, 1, sizeof(r->y), fd);
1856 | /* y pos on the grid (1-5) */
1857 | Fread((genericptr_t) &r->w, 1, sizeof(r->w), fd);
1858 | /* width of the room */
1859 | Fread((genericptr_t) &r->h, 1, sizeof(r->h), fd);
1860 | /* height of the room */
1861 | Fread((genericptr_t) &r->xalign, 1, sizeof(r->xalign), fd);
1862 | /* horizontal alignment */
1863 | Fread((genericptr_t) &r->yalign, 1, sizeof(r->yalign), fd);
1864 | /* vertical alignment */
1865 | Fread((genericptr_t) &r->rtype, 1, sizeof(r->rtype), fd);
1866 | /* type of room (zoo, shop, etc.) */
1867 | Fread((genericptr_t) &r->chance, 1, sizeof(r->chance), fd);
1868 | /* chance of room being special. */
1869 | Fread((genericptr_t) &r->rlit, 1, sizeof(r->rlit), fd);
1870 | /* lit or not ? */
1871 | Fread((genericptr_t) &r->filled, 1, sizeof(r->filled), fd);
1872 | /* to be filled? */
1873 | r->nsubroom= 0;
1874 |
1875 | /* read the doors */
1876 | Fread((genericptr_t) &r->ndoor, 1, sizeof(r->ndoor), fd);
1877 | if ((n = r->ndoor) != 0)
1878 | r->doors = NewTab(room_door, n);
1879 | while(n--) {
1880 | r->doors[(int)n] = New(room_door);
1881 | Fread((genericptr_t) r->doors[(int)n], 1,
1882 | sizeof(room_door), fd);
1883 | }
1884 |
1885 | /* read the stairs */
1886 | Fread((genericptr_t) &r->nstair, 1, sizeof(r->nstair), fd);
1887 | if ((n = r->nstair) != 0)
1888 | r->stairs = NewTab(stair, n);
1889 | while (n--) {
1890 | r->stairs[(int)n] = New(stair);
1891 | Fread((genericptr_t) r->stairs[(int)n], 1,
1892 | sizeof(stair), fd);
1893 | }
1894 |
1895 | /* read the altars */
1896 | Fread((genericptr_t) &r->naltar, 1, sizeof(r->naltar), fd);
1897 | if ((n = r->naltar) != 0)
1898 | r->altars = NewTab(altar, n);
1899 | while (n--) {
1900 | r->altars[(int)n] = New(altar);
1901 | Fread((genericptr_t) r->altars[(int)n], 1,
1902 | sizeof(altar), fd);
1903 | }
1904 |
1905 | /* read the fountains */
1906 | Fread((genericptr_t) &r->nfountain, 1,
1907 | sizeof(r->nfountain), fd);
1908 | if ((n = r->nfountain) != 0)
1909 | r->fountains = NewTab(fountain, n);
1910 | while (n--) {
1911 | r->fountains[(int)n] = New(fountain);
1912 | Fread((genericptr_t) r->fountains[(int)n], 1,
1913 | sizeof(fountain), fd);
1914 | }
1915 |
1916 | /* read the sinks */
1917 | Fread((genericptr_t) &r->nsink, 1, sizeof(r->nsink), fd);
1918 | if ((n = r->nsink) != 0)
1919 | r->sinks = NewTab(sink, n);
1920 | while (n--) {
1921 | r->sinks[(int)n] = New(sink);
1922 | Fread((genericptr_t) r->sinks[(int)n], 1, sizeof(sink), fd);
1923 | }
1924 |
1925 | /* read the pools */
1926 | Fread((genericptr_t) &r->npool, 1, sizeof(r->npool), fd);
1927 | if ((n = r->npool) != 0)
1928 | r->pools = NewTab(pool,n);
1929 | while (n--) {
1930 | r->pools[(int)n] = New(pool);
1931 | Fread((genericptr_t) r->pools[(int)n], 1, sizeof(pool), fd);
1932 | }
1933 |
1934 | /* read the traps */
1935 | Fread((genericptr_t) &r->ntrap, 1, sizeof(r->ntrap), fd);
1936 | if ((n = r->ntrap) != 0)
1937 | r->traps = NewTab(trap, n);
1938 | while(n--) {
1939 | r->traps[(int)n] = New(trap);
1940 | Fread((genericptr_t) r->traps[(int)n], 1, sizeof(trap), fd);
1941 | }
1942 |
1943 | /* read the monsters */
1944 | Fread((genericptr_t) &r->nmonster, 1, sizeof(r->nmonster), fd);
1945 | if ((n = r->nmonster) != 0) {
1946 | r->monsters = NewTab(monster, n);
1947 | while(n--) {
1948 | r->monsters[(int)n] = New(monster);
1949 | load_one_monster(fd, r->monsters[(int)n]);
1950 | }
1951 | } else
1952 | r->monsters = 0;
1953 |
1954 | /* read the objects */
1955 | Fread((genericptr_t) &r->nobject, 1, sizeof(r->nobject), fd);
1956 | if ((n = r->nobject) != 0) {
1957 | r->objects = NewTab(object, n);
1958 | while (n--) {
1959 | r->objects[(int)n] = New(object);
1960 | load_one_object(fd, r->objects[(int)n]);
1961 | }
1962 | } else
1963 | r->objects = 0;
1964 |
1965 | /* read the gold piles */
1966 | Fread((genericptr_t) &r->ngold, 1, sizeof(r->ngold), fd);
1967 | if ((n = r->ngold) != 0)
1968 | r->golds = NewTab(gold, n);
1969 | while (n--) {
1970 | r->golds[(int)n] = New(gold);
1971 | Fread((genericptr_t) r->golds[(int)n], 1, sizeof(gold), fd);
1972 | }
1973 |
1974 | /* read the engravings */
1975 | Fread((genericptr_t) &r->nengraving, 1,
1976 | sizeof(r->nengraving), fd);
1977 | if ((n = r->nengraving) != 0) {
1978 | r->engravings = NewTab(engraving,n);
1979 | while (n--) {
1980 | r->engravings[(int)n] = New(engraving);
1981 | load_one_engraving(fd, r->engravings[(int)n]);
1982 | }
1983 | } else
1984 | r->engravings = 0;
1985 |
1986 | }
1987 |
1988 | /* Now that we have loaded all the rooms, search the
1989 | * subrooms and create the links.
1990 | */
1991 |
1992 | for (i = 0; i<nrooms; i++)
1993 | if (tmproom[i]->parent) {
1994 | /* Search the parent room */
1995 | for(j=0; j<nrooms; j++)
1996 | if (tmproom[j]->name && !strcmp(tmproom[j]->name,
1997 | tmproom[i]->parent)) {
1998 | n = tmproom[j]->nsubroom++;
1999 | tmproom[j]->subrooms[(int)n] = tmproom[i];
2000 | break;
2001 | }
2002 | }
2003 |
2004 | /*
2005 | * Create the rooms now...
2006 | */
2007 |
2008 | for (i=0; i < nrooms; i++)
2009 | if(!tmproom[i]->parent)
2010 | build_room(tmproom[i], (room *) 0);
2011 |
2012 | free_rooms(tmproom, nrooms);
2013 |
2014 | /* read the corridors */
2015 |
2016 | Fread((genericptr_t) &ncorr, sizeof(ncorr), 1, fd);
2017 | for (i=0; i<ncorr; i++) {
2018 | Fread((genericptr_t) &tmpcor, 1, sizeof(tmpcor), fd);
2019 | create_corridor(&tmpcor);
2020 | }
2021 |
2022 | return TRUE;
2023 | }
2024 |
2025 | /*
2026 | * Select a random coordinate in the maze.
2027 | *
2028 | * We want a place not 'touched' by the loader. That is, a place in
2029 | * the maze outside every part of the special level.
2030 | */
2031 |
2032 | STATIC_OVL void
2033 | maze1xy(m, humidity)
2034 | coord *m;
2035 | int humidity;
2036 | {
2037 | register int x, y, tryct = 2000;
2038 | /* tryct: normally it won't take more than ten or so tries due
2039 | to the circumstances under which we'll be called, but the
2040 | `humidity' screening might drastically change the chances */
2041 |
2042 | do {
2043 | x = rn1(x_maze_max - 3, 3);
2044 | y = rn1(y_maze_max - 3, 3);
2045 | if (--tryct < 0) break; /* give up */
2046 | } while (!(x % 2) || !(y % 2) || Map[x][y] ||
2047 | !is_ok_location((schar)x, (schar)y, humidity));
2048 |
2049 | m->x = (xchar)x, m->y = (xchar)y;
2050 | }
2051 |
2052 | /*
2053 | * The Big Thing: special maze loader
2054 | *
2055 | * Could be cleaner, but it works.
2056 | */
2057 |
2058 | STATIC_OVL boolean
2059 | load_maze(fd)
2060 | dlb *fd;
2061 | {
2062 | xchar x, y, typ;
2063 | boolean prefilled, room_not_needed;
2064 |
2065 | char n, numpart = 0;
2066 | xchar nwalk = 0, nwalk_sav;
2067 | schar filling;
2068 | char halign, valign;
2069 |
2070 | int xi, dir, size;
2071 | coord mm;
2072 | int mapcount, mapcountmax, mapfact;
2073 |
2074 | lev_region tmplregion;
2075 | region tmpregion;
2076 | door tmpdoor;
2077 | trap tmptrap;
2078 | monster tmpmons;
2079 | object tmpobj;
2080 | drawbridge tmpdb;
2081 | walk tmpwalk;
2082 | digpos tmpdig;
2083 | lad tmplad;
2084 | stair tmpstair, prevstair;
2085 | altar tmpaltar;
2086 | gold tmpgold;
2087 | fountain tmpfountain;
2088 | engraving tmpengraving;
2089 | xchar mustfill[(MAXNROFROOMS+1)*2];
2090 | struct trap *badtrap;
2091 | boolean has_bounds;
2092 |
2093 | (void) memset((genericptr_t)&Map[0][0], 0, sizeof Map);
2094 | load_common_data(fd, SP_LEV_MAZE);
2095 |
2096 | /* Initialize map */
2097 | Fread((genericptr_t) &filling, 1, sizeof(filling), fd);
2098 | if (!init_lev.init_present) { /* don't init if mkmap() has been called */
2099 | for(x = 2; x <= x_maze_max; x++)
2100 | for(y = 0; y <= y_maze_max; y++)
2101 | if (filling == -1) {
2102 | #ifndef WALLIFIED_MAZE
2103 | levl[x][y].typ = STONE;
2104 | #else
2105 | levl[x][y].typ =
2106 | (y < 2 || ((x % 2) && (y % 2))) ? STONE : HWALL;
2107 | #endif
2108 | } else {
2109 | levl[x][y].typ = filling;
2110 | }
2111 | }
2112 |
2113 | /* Start reading the file */
2114 | Fread((genericptr_t) &numpart, 1, sizeof(numpart), fd);
2115 | /* Number of parts */
2116 | if (!numpart || numpart > 9)
2117 | panic("load_maze error: numpart = %d", (int) numpart);
2118 |
2119 | while (numpart--) {
2120 | Fread((genericptr_t) &halign, 1, sizeof(halign), fd);
2121 | /* Horizontal alignment */
2122 | Fread((genericptr_t) &valign, 1, sizeof(valign), fd);
2123 | /* Vertical alignment */
2124 | Fread((genericptr_t) &xsize, 1, sizeof(xsize), fd);
2125 | /* size in X */
2126 | Fread((genericptr_t) &ysize, 1, sizeof(ysize), fd);
2127 | /* size in Y */
2128 | switch((int) halign) {
2129 | case LEFT: xstart = 3; break;
2130 | case H_LEFT: xstart = 2+((x_maze_max-2-xsize)/4); break;
2131 | case CENTER: xstart = 2+((x_maze_max-2-xsize)/2); break;
2132 | case H_RIGHT: xstart = 2+((x_maze_max-2-xsize)*3/4); break;
2133 | case RIGHT: xstart = x_maze_max-xsize-1; break;
2134 | }
2135 | switch((int) valign) {
2136 | case TOP: ystart = 3; break;
2137 | case CENTER: ystart = 2+((y_maze_max-2-ysize)/2); break;
2138 | case BOTTOM: ystart = y_maze_max-ysize-1; break;
2139 | }
2140 | if (!(xstart % 2)) xstart++;
2141 | if (!(ystart % 2)) ystart++;
2142 | if ((ystart < 0) || (ystart + ysize > ROWNO)) {
2143 | /* try to move the start a bit */
2144 | ystart += (ystart > 0) ? -2 : 2;
2145 | if(ysize == ROWNO) ystart = 0;
2146 | if(ystart < 0 || ystart + ysize > ROWNO)
2147 | panic("reading special level with ysize too large");
2148 | }
2149 |
2150 | /*
2151 | * If any CROSSWALLs are found, must change to ROOM after REGION's
2152 | * are laid out. CROSSWALLS are used to specify "invisible"
2153 | * boundaries where DOOR syms look bad or aren't desirable.
2154 | */
2155 | has_bounds = FALSE;
2156 |
2157 | if(init_lev.init_present && xsize <= 1 && ysize <= 1) {
2158 | xstart = 1;
2159 | ystart = 0;
2160 | xsize = COLNO-1;
2161 | ysize = ROWNO;
2162 | } else {
2163 | /* Load the map */
2164 | for(y = ystart; y < ystart+ysize; y++)
2165 | for(x = xstart; x < xstart+xsize; x++) {
2166 | levl[x][y].typ = Fgetc(fd);
2167 | levl[x][y].lit = FALSE;
2168 | /*
2169 | * Note: Even though levl[x][y].typ is type schar,
2170 | * lev_comp.y saves it as type char. Since schar != char
2171 | * all the time we must make this exception or hack
2172 | * through lev_comp.y to fix.
2173 | */
2174 |
2175 | /*
2176 | * Set secret doors to closed (why not trapped too?). Set
2177 | * the horizontal bit.
2178 | */
2179 | if (levl[x][y].typ == SDOOR || IS_DOOR(levl[x][y].typ)) {
2180 | if(levl[x][y].typ == SDOOR)
2181 | levl[x][y].doormask = D_CLOSED;
2182 | /*
2183 | * If there is a wall to the left that connects to a
2184 | * (secret) door, then it is horizontal. This does
2185 | * not allow (secret) doors to be corners of rooms.
2186 | */
2187 | if (x != xstart && (IS_WALL(levl[x-1][y].typ) ||
2188 | levl[x-1][y].horizontal))
2189 | levl[x][y].horizontal = 1;
2190 | } else if(levl[x][y].typ == HWALL)
2191 | levl[x][y].horizontal = 1;
2192 | else if(levl[x][y].typ == LAVAPOOL)
2193 | levl[x][y].lit = 1;
2194 | else if(levl[x][y].typ == CROSSWALL)
2195 | has_bounds = TRUE;
2196 | Map[x][y] = 1;
2197 | }
2198 | }
2199 |
2200 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2201 | /* Number of level regions */
2202 | if(n) {
2203 | if(num_lregions) {
2204 | /* realloc the lregion space to add the new ones */
2205 | /* don't really free it up until the whole level is done */
2206 | lev_region *newl = (lev_region *) alloc(sizeof(lev_region) *
2207 | (unsigned)(n+num_lregions));
2208 | (void) memcpy((genericptr_t)(newl+n), (genericptr_t)lregions,
2209 | sizeof(lev_region) * num_lregions);
2210 | Free(lregions);
2211 | num_lregions += n;
2212 | lregions = newl;
2213 | } else {
2214 | num_lregions = n;
2215 | lregions = (lev_region *)
2216 | alloc(sizeof(lev_region) * (unsigned)n);
2217 | }
2218 | }
2219 |
2220 | while(n--) {
2221 | Fread((genericptr_t) &tmplregion, sizeof(tmplregion), 1, fd);
2222 | if ((size = tmplregion.rname.len) != 0) {
2223 | tmplregion.rname.str = (char *) alloc((unsigned)size + 1);
2224 | Fread((genericptr_t) tmplregion.rname.str, size, 1, fd);
2225 | tmplregion.rname.str[size] = '\0';
2226 | } else
2227 | tmplregion.rname.str = (char *) 0;
2228 | if(!tmplregion.in_islev) {
2229 | get_location(&tmplregion.inarea.x1, &tmplregion.inarea.y1,
2230 | DRY|WET);
2231 | get_location(&tmplregion.inarea.x2, &tmplregion.inarea.y2,
2232 | DRY|WET);
2233 | }
2234 | if(!tmplregion.del_islev) {
2235 | get_location(&tmplregion.delarea.x1, &tmplregion.delarea.y1,
2236 | DRY|WET);
2237 | get_location(&tmplregion.delarea.x2, &tmplregion.delarea.y2,
2238 | DRY|WET);
2239 | }
2240 | lregions[(int)n] = tmplregion;
2241 | }
2242 |
2243 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2244 | /* Random objects */
2245 | if(n) {
2246 | Fread((genericptr_t)robjects, sizeof(*robjects), (int) n, fd);
2247 | sp_lev_shuffle(robjects, (char *)0, (int)n);
2248 | }
2249 |
2250 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2251 | /* Random locations */
2252 | if(n) {
2253 | Fread((genericptr_t)rloc_x, sizeof(*rloc_x), (int) n, fd);
2254 | Fread((genericptr_t)rloc_y, sizeof(*rloc_y), (int) n, fd);
2255 | sp_lev_shuffle(rloc_x, rloc_y, (int)n);
2256 | }
2257 |
2258 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2259 | /* Random monsters */
2260 | if(n) {
2261 | Fread((genericptr_t)rmonst, sizeof(*rmonst), (int) n, fd);
2262 | sp_lev_shuffle(rmonst, (char *)0, (int)n);
2263 | }
2264 |
2265 | (void) memset((genericptr_t)mustfill, 0, sizeof(mustfill));
2266 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2267 | /* Number of subrooms */
2268 | while(n--) {
2269 | register struct mkroom *troom;
2270 |
2271 | Fread((genericptr_t)&tmpregion, 1, sizeof(tmpregion), fd);
2272 |
2273 | if(tmpregion.rtype > MAXRTYPE) {
2274 | tmpregion.rtype -= MAXRTYPE+1;
2275 | prefilled = TRUE;
2276 | } else
2277 | prefilled = FALSE;
2278 |
2279 | if(tmpregion.rlit < 0)
2280 | tmpregion.rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77))
2281 | ? TRUE : FALSE;
2282 |
2283 | get_location(&tmpregion.x1, &tmpregion.y1, DRY|WET);
2284 | get_location(&tmpregion.x2, &tmpregion.y2, DRY|WET);
2285 |
2286 | /* for an ordinary room, `prefilled' is a flag to force
2287 | an actual room to be created (such rooms are used to
2288 | control placement of migrating monster arrivals) */
2289 | room_not_needed = (tmpregion.rtype == OROOM &&
2290 | !tmpregion.rirreg && !prefilled);
2291 | if (room_not_needed || nroom >= MAXNROFROOMS) {
2292 | if (!room_not_needed)
2293 | impossible("Too many rooms on new level!");
2294 | light_region(&tmpregion);
2295 | continue;
2296 | }
2297 |
2298 | troom = &rooms[nroom];
2299 |
2300 | /* mark rooms that must be filled, but do it later */
2301 | if (tmpregion.rtype != OROOM)
2302 | mustfill[nroom] = (prefilled ? 2 : 1);
2303 |
2304 | if(tmpregion.rirreg) {
2305 | min_rx = max_rx = tmpregion.x1;
2306 | min_ry = max_ry = tmpregion.y1;
2307 | flood_fill_rm(tmpregion.x1, tmpregion.y1,
2308 | nroom+ROOMOFFSET, tmpregion.rlit, TRUE);
2309 | add_room(min_rx, min_ry, max_rx, max_ry,
2310 | FALSE, tmpregion.rtype, TRUE);
2311 | troom->rlit = tmpregion.rlit;
2312 | troom->irregular = TRUE;
2313 | } else {
2314 | add_room(tmpregion.x1, tmpregion.y1,
2315 | tmpregion.x2, tmpregion.y2,
2316 | tmpregion.rlit, tmpregion.rtype, TRUE);
2317 | #ifdef SPECIALIZATION
2318 | topologize(troom,FALSE); /* set roomno */
2319 | #else
2320 | topologize(troom); /* set roomno */
2321 | #endif
2322 | }
2323 | }
2324 |
2325 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2326 | /* Number of doors */
2327 | while(n--) {
2328 | struct mkroom *croom = &rooms[0];
2329 |
2330 | Fread((genericptr_t)&tmpdoor, 1, sizeof(tmpdoor), fd);
2331 |
2332 | x = tmpdoor.x; y = tmpdoor.y;
2333 | typ = tmpdoor.mask == -1 ? rnddoor() : tmpdoor.mask;
2334 |
2335 | get_location(&x, &y, DRY);
2336 | if(levl[x][y].typ != SDOOR)
2337 | levl[x][y].typ = DOOR;
2338 | else {
2339 | if(typ < D_CLOSED)
2340 | typ = D_CLOSED; /* force it to be closed */
2341 | }
2342 | levl[x][y].doormask = typ;
2343 |
2344 | /* Now the complicated part, list it with each subroom */
2345 | /* The dog move and mail daemon routines use this */
2346 | while(croom->hx >= 0 && doorindex < DOORMAX) {
2347 | if(croom->hx >= x-1 && croom->lx <= x+1 &&
2348 | croom->hy >= y-1 && croom->ly <= y+1) {
2349 | /* Found it */
2350 | add_door(x, y, croom);
2351 | }
2352 | croom++;
2353 | }
2354 | }
2355 |
2356 | /* now that we have rooms _and_ associated doors, fill the rooms */
2357 | for(n = 0; n < SIZE(mustfill); n++)
2358 | if(mustfill[(int)n])
2359 | fill_room(&rooms[(int)n], (mustfill[(int)n] == 2));
2360 |
2361 | /* if special boundary syms (CROSSWALL) in map, remove them now */
2362 | if(has_bounds) {
2363 | for(x = xstart; x < xstart+xsize; x++)
2364 | for(y = ystart; y < ystart+ysize; y++)
2365 | if(levl[x][y].typ == CROSSWALL)
2366 | levl[x][y].typ = ROOM;
2367 | }
2368 |
2369 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2370 | /* Number of drawbridges */
2371 | while(n--) {
2372 | Fread((genericptr_t)&tmpdb, 1, sizeof(tmpdb), fd);
2373 |
2374 | x = tmpdb.x; y = tmpdb.y;
2375 | get_location(&x, &y, DRY|WET);
2376 |
2377 | if (!create_drawbridge(x, y, tmpdb.dir, tmpdb.db_open))
2378 | impossible("Cannot create drawbridge.");
2379 | }
2380 |
2381 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2382 | /* Number of mazewalks */
2383 | while(n--) {
2384 | Fread((genericptr_t)&tmpwalk, 1, sizeof(tmpwalk), fd);
2385 |
2386 | get_location(&tmpwalk.x, &tmpwalk.y, DRY|WET);
2387 |
2388 | walklist[nwalk++] = tmpwalk;
2389 | }
2390 |
2391 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2392 | /* Number of non_diggables */
2393 | while(n--) {
2394 | Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd);
2395 |
2396 | get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET);
2397 | get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET);
2398 |
2399 | set_wall_property(tmpdig.x1, tmpdig.y1,
2400 | tmpdig.x2, tmpdig.y2, W_NONDIGGABLE);
2401 | }
2402 |
2403 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2404 | /* Number of non_passables */
2405 | while(n--) {
2406 | Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd);
2407 |
2408 | get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET);
2409 | get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET);
2410 |
2411 | set_wall_property(tmpdig.x1, tmpdig.y1,
2412 | tmpdig.x2, tmpdig.y2, W_NONPASSWALL);
2413 | }
2414 |
2415 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2416 | /* Number of ladders */
2417 | while(n--) {
2418 | Fread((genericptr_t)&tmplad, 1, sizeof(tmplad), fd);
2419 |
2420 | x = tmplad.x; y = tmplad.y;
2421 | get_location(&x, &y, DRY);
2422 |
2423 | levl[x][y].typ = LADDER;
2424 | if (tmplad.up == 1) {
2425 | xupladder = x; yupladder = y;
2426 | levl[x][y].ladder = LA_UP;
2427 | } else {
2428 | xdnladder = x; ydnladder = y;
2429 | levl[x][y].ladder = LA_DOWN;
2430 | }
2431 | }
2432 |
2433 | prevstair.x = prevstair.y = 0;
2434 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2435 | /* Number of stairs */
2436 | while(n--) {
2437 | Fread((genericptr_t)&tmpstair, 1, sizeof(tmpstair), fd);
2438 |
2439 | xi = 0;
2440 | do {
2441 | x = tmpstair.x; y = tmpstair.y;
2442 | get_location(&x, &y, DRY);
2443 | } while(prevstair.x && xi++ < 100 &&
2444 | distmin(x,y,prevstair.x,prevstair.y) <= 8);
2445 | if ((badtrap = t_at(x,y)) != 0) deltrap(badtrap);
2446 | mkstairs(x, y, (char)tmpstair.up, (struct mkroom *)0);
2447 | prevstair.x = x;
2448 | prevstair.y = y;
2449 | }
2450 |
2451 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2452 | /* Number of altars */
2453 | while(n--) {
2454 | Fread((genericptr_t)&tmpaltar, 1, sizeof(tmpaltar), fd);
2455 |
2456 | create_altar(&tmpaltar, (struct mkroom *)0);
2457 | }
2458 |
2459 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2460 | /* Number of fountains */
2461 | while (n--) {
2462 | Fread((genericptr_t)&tmpfountain, 1, sizeof(tmpfountain), fd);
2463 |
2464 | create_feature(tmpfountain.x, tmpfountain.y,
2465 | (struct mkroom *)0, FOUNTAIN);
2466 | }
2467 |
2468 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2469 | /* Number of traps */
2470 | while(n--) {
2471 | Fread((genericptr_t)&tmptrap, 1, sizeof(tmptrap), fd);
2472 |
2473 | create_trap(&tmptrap, (struct mkroom *)0);
2474 | }
2475 |
2476 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2477 | /* Number of monsters */
2478 | while(n--) {
2479 | load_one_monster(fd, &tmpmons);
2480 |
2481 | create_monster(&tmpmons, (struct mkroom *)0);
2482 | }
2483 |
2484 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2485 | /* Number of objects */
2486 | while(n--) {
2487 | load_one_object(fd, &tmpobj);
2488 |
2489 | create_object(&tmpobj, (struct mkroom *)0);
2490 | }
2491 |
2492 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2493 | /* Number of gold piles */
2494 | while (n--) {
2495 | Fread((genericptr_t)&tmpgold, 1, sizeof(tmpgold), fd);
2496 |
2497 | create_gold(&tmpgold, (struct mkroom *)0);
2498 | }
2499 |
2500 | Fread((genericptr_t) &n, 1, sizeof(n), fd);
2501 | /* Number of engravings */
2502 | while(n--) {
2503 | load_one_engraving(fd, &tmpengraving);
2504 |
2505 | create_engraving(&tmpengraving, (struct mkroom *)0);
2506 | }
2507 |
2508 | } /* numpart loop */
2509 |
2510 | nwalk_sav = nwalk;
2511 | while(nwalk--) {
2512 | x = (xchar) walklist[nwalk].x;
2513 | y = (xchar) walklist[nwalk].y;
2514 | dir = walklist[nwalk].dir;
2515 |
2516 | /* don't use move() - it doesn't use W_NORTH, etc. */
2517 | switch (dir) {
2518 | case W_NORTH: --y; break;
2519 | case W_SOUTH: y++; break;
2520 | case W_EAST: x++; break;
2521 | case W_WEST: --x; break;
2522 | default: panic("load_maze: bad MAZEWALK direction");
2523 | }
2524 |
2525 | if(!IS_DOOR(levl[x][y].typ)) {
2526 | #ifndef WALLIFIED_MAZE
2527 | levl[x][y].typ = CORR;
2528 | #else
2529 | levl[x][y].typ = ROOM;
2530 | #endif
2531 | levl[x][y].flags = 0;
2532 | }
2533 |
2534 | /*
2535 | * We must be sure that the parity of the coordinates for
2536 | * walkfrom() is odd. But we must also take into account
2537 | * what direction was chosen.
2538 | */
2539 | if(!(x % 2)) {
2540 | if (dir == W_EAST)
2541 | x++;
2542 | else
2543 | x--;
2544 |
2545 | /* no need for IS_DOOR check; out of map bounds */
2546 | #ifndef WALLIFIED_MAZE
2547 | levl[x][y].typ = CORR;
2548 | #else
2549 | levl[x][y].typ = ROOM;
2550 | #endif
2551 | levl[x][y].flags = 0;
2552 | }
2553 |
2554 | if (!(y % 2)) {
2555 | if (dir == W_SOUTH)
2556 | y++;
2557 | else
2558 | y--;
2559 | }
2560 |
2561 | walkfrom(x, y);
2562 | }
2563 | wallification(1, 0, COLNO-1, ROWNO-1);
2564 |
2565 | /*
2566 | * If there's a significant portion of maze unused by the special level,
2567 | * we don't want it empty.
2568 | *
2569 | * Makes the number of traps, monsters, etc. proportional
2570 | * to the size of the maze.
2571 | */
2572 | mapcountmax = mapcount = (x_maze_max - 2) * (y_maze_max - 2);
2573 |
2574 | for(x = 2; x < x_maze_max; x++)
2575 | for(y = 0; y < y_maze_max; y++)
2576 | if(Map[x][y]) mapcount--;
2577 |
2578 | if (nwalk_sav && (mapcount > (int) (mapcountmax / 10))) {
2579 | mapfact = (int) ((mapcount * 100L) / mapcountmax);
2580 | for(x = rnd((int) (20 * mapfact) / 100); x; x--) {
2581 | maze1xy(&mm, DRY);
2582 | (void) mkobj_at(rn2(2) ? GEM_CLASS : RANDOM_CLASS,
2583 | mm.x, mm.y, TRUE);
2584 | }
2585 | for(x = rnd((int) (12 * mapfact) / 100); x; x--) {
2586 | maze1xy(&mm, DRY);
2587 | (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE);
2588 | }
2589 | for (x = rn2(2); x; x--) {
2590 | maze1xy(&mm, DRY);
2591 | (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y, NO_MM_FLAGS);
2592 | }
2593 | for(x = rnd((int) (12 * mapfact) / 100); x; x--) {
2594 | maze1xy(&mm, WET|DRY);
2595 | (void) makemon((struct permonst *) 0, mm.x, mm.y, NO_MM_FLAGS);
2596 | }
2597 | for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
2598 | maze1xy(&mm, DRY);
2599 | (void) mkgold(0L,mm.x,mm.y);
2600 | }
2601 | for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
2602 | int trytrap;
2603 |
2604 | maze1xy(&mm, DRY);
2605 | trytrap = rndtrap();
2606 | if (sobj_at(BOULDER, mm.x, mm.y))
2607 | while (trytrap == PIT || trytrap == SPIKED_PIT ||
2608 | trytrap == TRAPDOOR || trytrap == HOLE)
2609 | trytrap = rndtrap();
2610 | (void) maketrap(mm.x, mm.y, trytrap);
2611 | }
2612 | }
2613 | return TRUE;
2614 | }
2615 |
2616 | /*
2617 | * General loader
2618 | */
2619 |
2620 | boolean
2621 | load_special(name)
2622 | const char *name;
2623 | {
2624 | dlb *fd;
2625 | boolean result = FALSE;
2626 | char c;
2627 | struct version_info vers_info;
2628 |
2629 | fd = dlb_fopen(name, RDBMODE);
2630 | if (!fd) return FALSE;
2631 |
2632 | Fread((genericptr_t) &vers_info, sizeof vers_info, 1, fd);
2633 | if (!check_version(&vers_info, name, TRUE))
2634 | goto give_up;
2635 |
2636 | Fread((genericptr_t) &c, sizeof c, 1, fd); /* c Header */
2637 |
2638 | switch (c) {
2639 | case SP_LEV_ROOMS:
2640 | result = load_rooms(fd);
2641 | break;
2642 | case SP_LEV_MAZE:
2643 | result = load_maze(fd);
2644 | break;
2645 | default: /* ??? */
2646 | result = FALSE;
2647 | }
2648 | give_up:
2649 | (void)dlb_fclose(fd);
2650 | return result;
2651 | }
2652 |
2653 | /*sp_lev.c*/