1 | /* SCCS Id: @(#)mklev.c 3.3 99/04/22 */
2 | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 | /* NetHack may be freely redistributed. See license for details. */
4 |
5 | #include "hack.h"
6 | /* #define DEBUG */ /* uncomment to enable code debugging */
7 |
8 | #ifdef DEBUG
9 | # ifdef WIZARD
10 | #define debugpline if (wizard) pline
11 | # else
12 | #define debugpline pline
13 | # endif
14 | #endif
15 |
16 | /* for UNIX, Rand #def'd to (long)lrand48() or (long)random() */
17 | /* croom->lx etc are schar (width <= int), so % arith ensures that */
18 | /* conversion of result to int is reasonable */
19 |
20 |
21 | STATIC_DCL void FDECL(mkfount,(int,struct mkroom *));
22 | #ifdef SINKS
23 | STATIC_DCL void FDECL(mksink,(struct mkroom *));
24 | #endif
25 | STATIC_DCL void FDECL(mkaltar,(struct mkroom *));
26 | STATIC_DCL void FDECL(mkgrave,(struct mkroom *));
27 | STATIC_DCL void NDECL(makevtele);
28 | STATIC_DCL void NDECL(clear_level_structures);
29 | STATIC_DCL void NDECL(makelevel);
30 | STATIC_DCL void NDECL(mineralize);
31 | STATIC_DCL boolean FDECL(bydoor,(XCHAR_P,XCHAR_P));
32 | STATIC_DCL struct mkroom *FDECL(find_branch_room, (coord *));
33 | STATIC_DCL struct mkroom *FDECL(pos_to_room, (XCHAR_P, XCHAR_P));
34 | STATIC_DCL boolean FDECL(place_niche,(struct mkroom *,int*,int*,int*));
35 | STATIC_DCL void FDECL(makeniche,(int));
36 | STATIC_DCL void NDECL(make_niches);
37 | STATIC_PTR int FDECL(do_comp,(const genericptr,const genericptr));
38 | STATIC_DCL void FDECL(dosdoor,(XCHAR_P,XCHAR_P,struct mkroom *,int));
39 | STATIC_DCL void FDECL(join,(int,int,BOOLEAN_P));
40 | STATIC_DCL void FDECL(do_room_or_subroom, (struct mkroom *,int,int,int,int,
41 | BOOLEAN_P,SCHAR_P,BOOLEAN_P,BOOLEAN_P));
42 | STATIC_DCL void NDECL(makerooms);
43 | STATIC_DCL void FDECL(finddpos,(coord *,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
44 | STATIC_DCL void FDECL(mkinvpos, (XCHAR_P,XCHAR_P,int));
45 | STATIC_DCL void FDECL(mk_knox_portal, (XCHAR_P,XCHAR_P));
46 |
47 | #define create_vault() create_room(-1, -1, 2, 2, -1, -1, VAULT, TRUE)
48 | #define init_vault() vault_x = -1
49 | #define do_vault() (vault_x != -1)
50 | static xchar vault_x, vault_y;
51 | boolean goldseen;
52 | static boolean made_branch; /* used only during level creation */
53 |
54 | /* Args must be (const genericptr) so that qsort will always be happy. */
55 |
56 | STATIC_PTR int
57 | do_comp(vx,vy)
58 | const genericptr vx;
59 | const genericptr vy;
60 | {
61 | #ifdef LINT
62 | /* lint complains about possible pointer alignment problems, but we know
63 | that vx and vy are always properly aligned. Hence, the following
64 | bogus definition:
65 | */
66 | return (vx == vy) ? 0 : -1;
67 | #else
68 | register const struct mkroom *x, *y;
69 |
70 | x = (const struct mkroom *)vx;
71 | y = (const struct mkroom *)vy;
72 | if(x->lx < y->lx) return(-1);
73 | return(x->lx > y->lx);
74 | #endif /* LINT */
75 | }
76 |
77 | STATIC_OVL void
78 | finddpos(cc, xl,yl,xh,yh)
79 | coord *cc;
80 | xchar xl,yl,xh,yh;
81 | {
82 | register xchar x, y;
83 |
84 | x = (xl == xh) ? xl : (xl + rn2(xh-xl+1));
85 | y = (yl == yh) ? yl : (yl + rn2(yh-yl+1));
86 | if(okdoor(x, y))
87 | goto gotit;
88 |
89 | for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
90 | if(okdoor(x, y))
91 | goto gotit;
92 |
93 | for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++)
94 | if(IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR)
95 | goto gotit;
96 | /* cannot find something reasonable -- strange */
97 | x = xl;
98 | y = yh;
99 | gotit:
100 | cc->x = x;
101 | cc->y = y;
102 | return;
103 | }
104 |
105 | void
106 | sort_rooms()
107 | {
108 | #if defined(SYSV) || defined(DGUX)
109 | qsort((genericptr_t) rooms, (unsigned)nroom, sizeof(struct mkroom), do_comp);
110 | #else
111 | qsort((genericptr_t) rooms, nroom, sizeof(struct mkroom), do_comp);
112 | #endif
113 | }
114 |
115 | STATIC_OVL void
116 | do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, is_room)
117 | register struct mkroom *croom;
118 | int lowx, lowy;
119 | register int hix, hiy;
120 | boolean lit;
121 | schar rtype;
122 | boolean special;
123 | boolean is_room;
124 | {
125 | register int x, y;
126 | struct rm *lev;
127 |
128 | /* locations might bump level edges in wall-less rooms */
129 | /* add/subtract 1 to allow for edge locations */
130 | if(!lowx) lowx++;
131 | if(!lowy) lowy++;
132 | if(hix >= COLNO-1) hix = COLNO-2;
133 | if(hiy >= ROWNO-1) hiy = ROWNO-2;
134 |
135 | if(lit) {
136 | for(x = lowx-1; x <= hix+1; x++) {
137 | lev = &levl[x][max(lowy-1,0)];
138 | for(y = lowy-1; y <= hiy+1; y++)
139 | lev++->lit = 1;
140 | }
141 | croom->rlit = 1;
142 | } else
143 | croom->rlit = 0;
144 |
145 | croom->lx = lowx;
146 | croom->hx = hix;
147 | croom->ly = lowy;
148 | croom->hy = hiy;
149 | croom->rtype = rtype;
150 | croom->doorct = 0;
151 | /* if we're not making a vault, doorindex will still be 0
152 | * if we are, we'll have problems adding niches to the previous room
153 | * unless fdoor is at least doorindex
154 | */
155 | croom->fdoor = doorindex;
156 | croom->irregular = FALSE;
157 |
158 | croom->nsubrooms = 0;
159 | croom->sbrooms[0] = (struct mkroom *) 0;
160 | if (!special) {
161 | for(x = lowx-1; x <= hix+1; x++)
162 | for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
163 | levl[x][y].typ = HWALL;
164 | levl[x][y].horizontal = 1; /* For open/secret doors. */
165 | }
166 | for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
167 | for(y = lowy; y <= hiy; y++) {
168 | levl[x][y].typ = VWALL;
169 | levl[x][y].horizontal = 0; /* For open/secret doors. */
170 | }
171 | for(x = lowx; x <= hix; x++) {
172 | lev = &levl[x][lowy];
173 | for(y = lowy; y <= hiy; y++)
174 | lev++->typ = ROOM;
175 | }
176 | if (is_room) {
177 | levl[lowx-1][lowy-1].typ = TLCORNER;
178 | levl[hix+1][lowy-1].typ = TRCORNER;
179 | levl[lowx-1][hiy+1].typ = BLCORNER;
180 | levl[hix+1][hiy+1].typ = BRCORNER;
181 | } else { /* a subroom */
182 | wallification(lowx-1, lowy-1, hix+1, hiy+1);
183 | }
184 | }
185 | }
186 |
187 |
188 | void
189 | add_room(lowx, lowy, hix, hiy, lit, rtype, special)
190 | register int lowx, lowy, hix, hiy;
191 | boolean lit;
192 | schar rtype;
193 | boolean special;
194 | {
195 | register struct mkroom *croom;
196 |
197 | croom = &rooms[nroom];
198 | do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit,
199 | rtype, special, (boolean) TRUE);
200 | croom++;
201 | croom->hx = -1;
202 | nroom++;
203 | }
204 |
205 | void
206 | add_subroom(proom, lowx, lowy, hix, hiy, lit, rtype, special)
207 | struct mkroom *proom;
208 | register int lowx, lowy, hix, hiy;
209 | boolean lit;
210 | schar rtype;
211 | boolean special;
212 | {
213 | register struct mkroom *croom;
214 |
215 | croom = &subrooms[nsubroom];
216 | do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit,
217 | rtype, special, (boolean) FALSE);
218 | proom->sbrooms[proom->nsubrooms++] = croom;
219 | croom++;
220 | croom->hx = -1;
221 | nsubroom++;
222 | }
223 |
224 | STATIC_OVL void
225 | makerooms()
226 | {
227 | boolean tried_vault = FALSE;
228 |
229 | /* make rooms until satisfied */
230 | /* rnd_rect() will returns 0 if no more rects are available... */
231 | while(nroom < MAXNROFROOMS && rnd_rect()) {
232 | if(nroom >= (MAXNROFROOMS/6) && rn2(2) && !tried_vault) {
233 | tried_vault = TRUE;
234 | if (create_vault()) {
235 | vault_x = rooms[nroom].lx;
236 | vault_y = rooms[nroom].ly;
237 | rooms[nroom].hx = -1;
238 | }
239 | } else
240 | if (!create_room(-1, -1, -1, -1, -1, -1, OROOM, -1))
241 | return;
242 | }
243 | return;
244 | }
245 |
246 | STATIC_OVL void
247 | join(a,b,nxcor)
248 | register int a, b;
249 | boolean nxcor;
250 | {
251 | coord cc,tt, org, dest;
252 | register xchar tx, ty, xx, yy;
253 | register struct mkroom *croom, *troom;
254 | register int dx, dy;
255 |
256 | croom = &rooms[a];
257 | troom = &rooms[b];
258 |
259 | /* find positions cc and tt for doors in croom and troom
260 | and direction for a corridor between them */
261 |
262 | if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return;
263 | if(troom->lx > croom->hx) {
264 | dx = 1;
265 | dy = 0;
266 | xx = croom->hx+1;
267 | tx = troom->lx-1;
268 | finddpos(&cc, xx, croom->ly, xx, croom->hy);
269 | finddpos(&tt, tx, troom->ly, tx, troom->hy);
270 | } else if(troom->hy < croom->ly) {
271 | dy = -1;
272 | dx = 0;
273 | yy = croom->ly-1;
274 | finddpos(&cc, croom->lx, yy, croom->hx, yy);
275 | ty = troom->hy+1;
276 | finddpos(&tt, troom->lx, ty, troom->hx, ty);
277 | } else if(troom->hx < croom->lx) {
278 | dx = -1;
279 | dy = 0;
280 | xx = croom->lx-1;
281 | tx = troom->hx+1;
282 | finddpos(&cc, xx, croom->ly, xx, croom->hy);
283 | finddpos(&tt, tx, troom->ly, tx, troom->hy);
284 | } else {
285 | dy = 1;
286 | dx = 0;
287 | yy = croom->hy+1;
288 | ty = troom->ly-1;
289 | finddpos(&cc, croom->lx, yy, croom->hx, yy);
290 | finddpos(&tt, troom->lx, ty, troom->hx, ty);
291 | }
292 | xx = cc.x;
293 | yy = cc.y;
294 | tx = tt.x - dx;
295 | ty = tt.y - dy;
296 | if(nxcor && levl[xx+dx][yy+dy].typ)
297 | return;
298 | if (okdoor(xx,yy) || !nxcor)
299 | dodoor(xx,yy,croom);
300 |
301 | org.x = xx+dx; org.y = yy+dy;
302 | dest.x = tx; dest.y = ty;
303 |
304 | if (!dig_corridor(&org, &dest, nxcor,
305 | level.flags.arboreal ? ROOM : CORR, STONE))
306 | return;
307 |
308 | /* we succeeded in digging the corridor */
309 | if (okdoor(tt.x, tt.y) || !nxcor)
310 | dodoor(tt.x, tt.y, troom);
311 |
312 | if(smeq[a] < smeq[b])
313 | smeq[b] = smeq[a];
314 | else
315 | smeq[a] = smeq[b];
316 | }
317 |
318 | void
319 | makecorridors()
320 | {
321 | int a, b, i;
322 | boolean any = TRUE;
323 |
324 | for(a = 0; a < nroom-1; a++) {
325 | join(a, a+1, FALSE);
326 | if(!rn2(50)) break; /* allow some randomness */
327 | }
328 | for(a = 0; a < nroom-2; a++)
329 | if(smeq[a] != smeq[a+2])
330 | join(a, a+2, FALSE);
331 | for(a = 0; any && a < nroom; a++) {
332 | any = FALSE;
333 | for(b = 0; b < nroom; b++)
334 | if(smeq[a] != smeq[b]) {
335 | join(a, b, FALSE);
336 | any = TRUE;
337 | }
338 | }
339 | if(nroom > 2)
340 | for(i = rn2(nroom) + 4; i; i--) {
341 | a = rn2(nroom);
342 | b = rn2(nroom-2);
343 | if(b >= a) b += 2;
344 | join(a, b, TRUE);
345 | }
346 | }
347 |
348 | void
349 | add_door(x,y,aroom)
350 | register int x, y;
351 | register struct mkroom *aroom;
352 | {
353 | register struct mkroom *broom;
354 | register int tmp;
355 |
356 | aroom->doorct++;
357 | broom = aroom+1;
358 | if(broom->hx < 0)
359 | tmp = doorindex;
360 | else
361 | for(tmp = doorindex; tmp > broom->fdoor; tmp--)
362 | doors[tmp] = doors[tmp-1];
363 | doorindex++;
364 | doors[tmp].x = x;
365 | doors[tmp].y = y;
366 | for( ; broom->hx >= 0; broom++) broom->fdoor++;
367 | }
368 |
369 | STATIC_OVL void
370 | dosdoor(x,y,aroom,type)
371 | register xchar x, y;
372 | register struct mkroom *aroom;
373 | register int type;
374 | {
375 | boolean shdoor = ((*in_rooms(x, y, SHOPBASE))? TRUE : FALSE);
376 |
377 | if(!IS_WALL(levl[x][y].typ)) /* avoid SDOORs on already made doors */
378 | type = DOOR;
379 | levl[x][y].typ = type;
380 | if(type == DOOR) {
381 | if(!rn2(3)) { /* is it a locked door, closed, or a doorway? */
382 | if(!rn2(5))
383 | levl[x][y].doormask = D_ISOPEN;
384 | else if(!rn2(6))
385 | levl[x][y].doormask = D_LOCKED;
386 | else
387 | levl[x][y].doormask = D_CLOSED;
388 |
389 | if (levl[x][y].doormask != D_ISOPEN && !shdoor &&
390 | level_difficulty() >= 5 && !rn2(25))
391 | levl[x][y].doormask |= D_TRAPPED;
392 | } else
393 | #ifdef STUPID
394 | if (shdoor)
395 | levl[x][y].doormask = D_ISOPEN;
396 | else
397 | levl[x][y].doormask = D_NODOOR;
398 | #else
399 | levl[x][y].doormask = (shdoor ? D_ISOPEN : D_NODOOR);
400 | #endif
401 | if(levl[x][y].doormask & D_TRAPPED) {
402 | struct monst *mtmp;
403 |
404 | if (level_difficulty() >= 9 && !rn2(5) &&
405 | !((mvitals[PM_SMALL_MIMIC].mvflags & G_GONE) &&
406 | (mvitals[PM_LARGE_MIMIC].mvflags & G_GONE) &&
407 | (mvitals[PM_GIANT_MIMIC].mvflags & G_GONE))) {
408 | /* make a mimic instead */
409 | levl[x][y].doormask = D_NODOOR;
410 | mtmp = makemon(mkclass(S_MIMIC,0), x, y, NO_MM_FLAGS);
411 | if (mtmp)
412 | set_mimic_sym(mtmp);
413 | }
414 | }
415 | /* newsym(x,y); */
416 | } else { /* SDOOR */
417 | if(shdoor || !rn2(5)) levl[x][y].doormask = D_LOCKED;
418 | else levl[x][y].doormask = D_CLOSED;
419 |
420 | if(!shdoor && level_difficulty() >= 4 && !rn2(20))
421 | levl[x][y].doormask |= D_TRAPPED;
422 | }
423 |
424 | add_door(x,y,aroom);
425 | }
426 |
427 | STATIC_OVL boolean
428 | place_niche(aroom,dy,xx,yy)
429 | register struct mkroom *aroom;
430 | int *dy, *xx, *yy;
431 | {
432 | coord dd;
433 |
434 | if(rn2(2)) {
435 | *dy = 1;
436 | finddpos(&dd, aroom->lx, aroom->hy+1, aroom->hx, aroom->hy+1);
437 | } else {
438 | *dy = -1;
439 | finddpos(&dd, aroom->lx, aroom->ly-1, aroom->hx, aroom->ly-1);
440 | }
441 | *xx = dd.x;
442 | *yy = dd.y;
443 | return((boolean)((isok(*xx,*yy+*dy) && levl[*xx][*yy+*dy].typ == STONE)
444 | && (isok(*xx,*yy-*dy) && !IS_POOL(levl[*xx][*yy-*dy].typ)
445 | && !IS_FURNITURE(levl[*xx][*yy-*dy].typ))));
446 | }
447 |
448 | /* there should be one of these per trap, in the same order as trap.h */
449 | static NEARDATA const char *trap_engravings[TRAPNUM] = {
450 | (char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
451 | (char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
452 | (char *)0, (char *)0, (char *)0, (char *)0,
453 | /* 14..16: trap door, teleport, level-teleport */
454 | "Vlad was here", "ad aerarium", "ad aerarium",
455 | (char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
456 | (char *)0,
457 | };
458 |
459 | STATIC_OVL void
460 | makeniche(trap_type)
461 | int trap_type;
462 | {
463 | register struct mkroom *aroom;
464 | register struct rm *rm;
465 | register int vct = 8;
466 | int dy, xx, yy;
467 | register struct trap *ttmp;
468 |
469 | if(doorindex < DOORMAX)
470 | while(vct--) {
471 | aroom = &rooms[rn2(nroom)];
472 | if(aroom->rtype != OROOM) continue; /* not an ordinary room */
473 | if(aroom->doorct == 1 && rn2(5)) continue;
474 | if(!place_niche(aroom,&dy,&xx,&yy)) continue;
475 |
476 | rm = &levl[xx][yy+dy];
477 | if(trap_type || !rn2(4)) {
478 |
479 | rm->typ = SCORR;
480 | if(trap_type) {
481 | if((trap_type == HOLE || trap_type == TRAPDOOR)
482 | && !Can_fall_thru(&u.uz))
483 | trap_type = ROCKTRAP;
484 | ttmp = maketrap(xx, yy+dy, trap_type);
485 | if (ttmp) {
486 | ttmp->once = 1;
487 | if (trap_engravings[trap_type]) {
488 | make_engr_at(xx, yy-dy,
489 | trap_engravings[trap_type], 0L, DUST);
490 | wipe_engr_at(xx, yy-dy, 5); /* age it a little */
491 | }
492 | }
493 | }
494 | dosdoor(xx, yy, aroom, SDOOR);
495 | } else {
496 | rm->typ = CORR;
497 | if(rn2(7))
498 | dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR);
499 | else {
500 | if (!level.flags.noteleport)
501 | (void) mksobj_at(SCR_TELEPORTATION, xx, yy+dy, TRUE);
502 | if(!rn2(3)) (void) mkobj_at(0, xx, yy+dy, TRUE);
503 | }
504 | }
505 | return;
506 | }
507 | }
508 |
509 | STATIC_OVL void
510 | make_niches()
511 | {
512 | register int ct = rnd((nroom>>1) + 1), dep = depth(&u.uz);
513 |
514 | boolean ltptr = (!level.flags.noteleport && dep > 15),
515 | vamp = (dep > 5 && dep < 25);
516 |
517 | while(ct--) {
518 | if (ltptr && !rn2(6)) {
519 | ltptr = FALSE;
520 | makeniche(LEVEL_TELEP);
521 | } else if (vamp && !rn2(6)) {
522 | vamp = FALSE;
523 | makeniche(TRAPDOOR);
524 | } else makeniche(NO_TRAP);
525 | }
526 | }
527 |
528 | STATIC_OVL void
529 | makevtele()
530 | {
531 | makeniche(TELEP_TRAP);
532 | }
533 |
534 | /* clear out various globals that keep information on the current level.
535 | * some of this is only necessary for some types of levels (maze, normal,
536 | * special) but it's easier to put it all in one place than make sure
537 | * each type initializes what it needs to separately.
538 | */
539 | STATIC_OVL void
540 | clear_level_structures()
541 | {
542 | static struct rm zerorm = { cmap_to_glyph(S_stone),
543 | 0, 0, 0, 0, 0, 0, 0, 0 };
544 | register int x,y;
545 | register struct rm *lev;
546 |
547 | for(x=0; x<COLNO; x++) {
548 | lev = &levl[x][0];
549 | for(y=0; y<ROWNO; y++) {
550 | *lev++ = zerorm;
551 | #ifdef MICROPORT_BUG
552 | level.objects[x][y] = (struct obj *)0;
553 | level.monsters[x][y] = (struct monst *)0;
554 | #endif
555 | }
556 | }
557 | #ifndef MICROPORT_BUG
558 | (void) memset((genericptr_t)level.objects, 0, sizeof(level.objects));
559 | (void) memset((genericptr_t)level.monsters, 0, sizeof(level.monsters));
560 | #endif
561 | level.objlist = (struct obj *)0;
562 | level.buriedobjlist = (struct obj *)0;
563 | level.monlist = (struct monst *)0;
564 | level.damagelist = (struct damage *)0;
565 |
566 | level.flags.nfountains = 0;
567 | level.flags.nsinks = 0;
568 | level.flags.has_shop = 0;
569 | level.flags.has_vault = 0;
570 | level.flags.has_zoo = 0;
571 | level.flags.has_court = 0;
572 | level.flags.has_morgue = level.flags.graveyard = 0;
573 | level.flags.has_beehive = 0;
574 | level.flags.has_barracks = 0;
575 | level.flags.has_temple = 0;
576 | level.flags.has_swamp = 0;
577 | level.flags.noteleport = 0;
578 | level.flags.hardfloor = 0;
579 | level.flags.nommap = 0;
580 | level.flags.hero_memory = 1;
581 | level.flags.shortsighted = 0;
582 | level.flags.arboreal = 0;
583 | level.flags.is_maze_lev = 0;
584 | level.flags.is_cavernous_lev = 0;
585 |
586 | nroom = 0;
587 | rooms[0].hx = -1;
588 | nsubroom = 0;
589 | subrooms[0].hx = -1;
590 | doorindex = 0;
591 | init_rect();
592 | init_vault();
593 | xdnstair = ydnstair = xupstair = yupstair = 0;
594 | sstairs.sx = sstairs.sy = 0;
595 | xdnladder = ydnladder = xupladder = yupladder = 0;
596 | made_branch = FALSE;
597 | clear_regions();
598 | }
599 |
600 | STATIC_OVL void
601 | makelevel()
602 | {
603 | register struct mkroom *croom, *troom;
604 | register int tryct;
605 | register int x, y;
606 | struct monst *tmonst; /* always put a web with a spider */
607 | branch *branchp;
608 | int room_threshold;
609 |
610 | if(wiz1_level.dlevel == 0) init_dungeons();
611 | oinit(); /* assign level dependent obj probabilities */
612 | clear_level_structures();
613 |
614 | {
615 | register s_level *slev = Is_special(&u.uz);
616 |
617 | /* check for special levels */
618 | #ifdef REINCARNATION
619 | if (slev && !Is_rogue_level(&u.uz))
620 | #else
621 | if (slev)
622 | #endif
623 | {
624 | makemaz(slev->proto);
625 | return;
626 | } else if (dungeons[u.uz.dnum].proto[0]) {
627 | makemaz("");
628 | return;
629 | } else if (In_mines(&u.uz)) {
630 | makemaz("minefill");
631 | return;
632 | } else if (In_quest(&u.uz)) {
633 | char fillname[9];
634 | s_level *loc_lev;
635 |
636 | Sprintf(fillname, "%s-loca", urole.filecode);
637 | loc_lev = find_level(fillname);
638 |
639 | Sprintf(fillname, "%s-fil", urole.filecode);
640 | Strcat(fillname,
641 | (u.uz.dlevel < loc_lev->dlevel.dlevel) ? "a" : "b");
642 | makemaz(fillname);
643 | return;
644 | } else if(In_hell(&u.uz) ||
645 | (rn2(5) && u.uz.dnum == medusa_level.dnum
646 | && depth(&u.uz) > depth(&medusa_level))) {
647 | makemaz("");
648 | return;
649 | }
650 | }
651 |
652 | /* otherwise, fall through - it's a "regular" level. */
653 |
654 | #ifdef REINCARNATION
655 | if (Is_rogue_level(&u.uz)) {
656 | makeroguerooms();
657 | makerogueghost();
658 | } else
659 | #endif
660 | makerooms();
661 | sort_rooms();
662 |
663 | /* construct stairs (up and down in different rooms if possible) */
664 | croom = &rooms[rn2(nroom)];
665 | if (!Is_botlevel(&u.uz))
666 | mkstairs(somex(croom), somey(croom), 0, croom); /* down */
667 | if (nroom > 1) {
668 | troom = croom;
669 | croom = &rooms[rn2(nroom-1)];
670 | if (croom == troom) croom++;
671 | }
672 |
673 | if (u.uz.dlevel != 1) {
674 | xchar sx, sy;
675 | do {
676 | sx = somex(croom);
677 | sy = somey(croom);
678 | } while(occupied(sx, sy));
679 | mkstairs(sx, sy, 1, croom); /* up */
680 | }
681 |
682 | branchp = Is_branchlev(&u.uz); /* possible dungeon branch */
683 | room_threshold = branchp ? 4 : 3; /* minimum number of rooms needed
684 | to allow a random special room */
685 | #ifdef REINCARNATION
686 | if (Is_rogue_level(&u.uz)) goto skip0;
687 | #endif
688 | makecorridors();
689 | make_niches();
690 |
691 | /* make a secret treasure vault, not connected to the rest */
692 | if(do_vault()) {
693 | xchar w,h;
694 | #ifdef DEBUG
695 | debugpline("trying to make a vault...");
696 | #endif
697 | w = 1;
698 | h = 1;
699 | if (check_room(&vault_x, &w, &vault_y, &h, TRUE)) {
700 | fill_vault:
701 | add_room(vault_x, vault_y, vault_x+w,
702 | vault_y+h, TRUE, VAULT, FALSE);
703 | level.flags.has_vault = 1;
704 | ++room_threshold;
705 | fill_room(&rooms[nroom - 1], FALSE);
706 | mk_knox_portal(vault_x+w, vault_y+h);
707 | if(!level.flags.noteleport && !rn2(3)) makevtele();
708 | } else if(rnd_rect() && create_vault()) {
709 | vault_x = rooms[nroom].lx;
710 | vault_y = rooms[nroom].ly;
711 | if (check_room(&vault_x, &w, &vault_y, &h, TRUE))
712 | goto fill_vault;
713 | else
714 | rooms[nroom].hx = -1;
715 | }
716 | }
717 |
718 | {
719 | register int u_depth = depth(&u.uz);
720 |
721 | #ifdef WIZARD
722 | if(wizard && nh_getenv("SHOPTYPE")) mkroom(SHOPBASE); else
723 | #endif
724 | if (u_depth > 1 &&
725 | u_depth < depth(&medusa_level) &&
726 | nroom >= room_threshold &&
727 | rn2(u_depth) < 3) mkroom(SHOPBASE);
728 | else if (u_depth > 4 && !rn2(6)) mkroom(COURT);
729 | else if (u_depth > 5 && !rn2(8) &&
730 | !(mvitals[PM_LEPRECHAUN].mvflags & G_GONE)) mkroom(LEPREHALL);
731 | else if (u_depth > 6 && !rn2(7)) mkroom(ZOO);
732 | else if (u_depth > 8 && !rn2(5)) mkroom(TEMPLE);
733 | else if (u_depth > 9 && !rn2(5) &&
734 | !(mvitals[PM_KILLER_BEE].mvflags & G_GONE)) mkroom(BEEHIVE);
735 | else if (u_depth > 11 && !rn2(6)) mkroom(MORGUE);
736 | else if (u_depth > 12 && !rn2(8)) mkroom(ANTHOLE);
737 | else if (u_depth > 14 && !rn2(4) &&
738 | !(mvitals[PM_SOLDIER].mvflags & G_GONE)) mkroom(BARRACKS);
739 | else if (u_depth > 15 && !rn2(6)) mkroom(SWAMP);
740 | else if (u_depth > 16 && !rn2(8) &&
741 | !(mvitals[PM_COCKATRICE].mvflags & G_GONE)) mkroom(COCKNEST);
742 | }
743 |
744 | #ifdef REINCARNATION
745 | skip0:
746 | #endif
747 | /* Place multi-dungeon branch. */
748 | place_branch(branchp, 0, 0);
749 |
750 | /* for each room: put things inside */
751 | for(croom = rooms; croom->hx > 0; croom++) {
752 | if(croom->rtype != OROOM) continue;
753 |
754 | /* put a sleeping monster inside */
755 | /* Note: monster may be on the stairs. This cannot be
756 | avoided: maybe the player fell through a trap door
757 | while a monster was on the stairs. Conclusion:
758 | we have to check for monsters on the stairs anyway. */
759 |
760 | if(u.uhave.amulet || !rn2(3)) {
761 | x = somex(croom); y = somey(croom);
762 | tmonst = makemon((struct permonst *) 0, x,y,NO_MM_FLAGS);
763 | if (tmonst && tmonst->data == &mons[PM_GIANT_SPIDER] &&
764 | !is_pool(x,y))
765 | (void) maketrap (x,y,WEB);
766 | }
767 | /* put traps and mimics inside */
768 | goldseen = FALSE;
769 | x = 8 - (level_difficulty()/6);
770 | if (x <= 1) x = 2;
771 | while (!rn2(x))
772 | mktrap(0,0,croom,(coord*)0);
773 | if (!goldseen && !rn2(3))
774 | (void) mkgold(0L, somex(croom), somey(croom));
775 | #ifdef REINCARNATION
776 | if(Is_rogue_level(&u.uz)) goto skip_nonrogue;
777 | #endif
778 | if(!rn2(10)) mkfount(0,croom);
779 | #ifdef SINKS
780 | if(!rn2(60)) mksink(croom);
781 | #endif
782 | if(!rn2(60)) mkaltar(croom);
783 | x = 80 - (depth(&u.uz) * 2);
784 | if (x < 2) x = 2;
785 | if(!rn2(x)) mkgrave(croom);
786 |
787 | /* put statues inside */
788 | if(!rn2(20))
789 | (void) mkcorpstat(STATUE, (struct monst *)0,
790 | (struct permonst *)0,
791 | somex(croom), somey(croom), TRUE);
792 | /* put box/chest inside;
793 | * 40% chance for at least 1 box, regardless of number
794 | * of rooms; about 5 - 7.5% for 2 boxes, least likely
795 | * when few rooms; chance for 3 or more is neglible.
796 | */
797 | if(!rn2(nroom * 5 / 2))
798 | (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
799 | somex(croom), somey(croom), TRUE);
800 |
801 | /* maybe make some graffiti */
802 | if(!rn2(27 + 3 * abs(depth(&u.uz)))) {
803 | char buf[BUFSZ];
804 | const char *mesg = random_engraving(buf);
805 | if (mesg) {
806 | do {
807 | x = somex(croom); y = somey(croom);
808 | } while(levl[x][y].typ != ROOM && !rn2(40));
809 | if (!(IS_POOL(levl[x][y].typ) ||
810 | IS_FURNITURE(levl[x][y].typ)))
811 | make_engr_at(x, y, mesg, 0L, MARK);
812 | }
813 | }
814 |
815 | #ifdef REINCARNATION
816 | skip_nonrogue:
817 | #endif
818 | if(!rn2(3)) {
819 | (void) mkobj_at(0, somex(croom), somey(croom), TRUE);
820 | tryct = 0;
821 | while(!rn2(5)) {
822 | if(++tryct > 100) {
823 | impossible("tryct overflow4");
824 | break;
825 | }
826 | (void) mkobj_at(0, somex(croom), somey(croom), TRUE);
827 | }
828 | }
829 | }
830 | }
831 |
832 | /*
833 | * Place deposits of minerals (gold and misc gems) in the stone
834 | * surrounding the rooms on the map.
835 | * Also place kelp in water.
836 | */
837 | STATIC_OVL void
838 | mineralize()
839 | {
840 | s_level *sp;
841 | struct obj *otmp;
842 | int goldprob, gemprob, x, y, cnt;
843 |
844 |
845 | /* Place kelp, except on the plane of water */
846 | if (In_endgame(&u.uz)) return;
847 | for (x = 2; x < (COLNO - 2); x++)
848 | for (y = 1; y < (ROWNO - 1); y++)
849 | if ((levl[x][y].typ == POOL && !rn2(10)) ||
850 | (levl[x][y].typ == MOAT && !rn2(30)))
851 | (void)mksobj_at(KELP_FROND, x, y, TRUE);
852 |
853 | /* determine if it is even allowed;
854 | almost all special levels are excluded */
855 | if (In_hell(&u.uz) || In_V_tower(&u.uz) ||
856 | #ifdef REINCARNATION
857 | Is_rogue_level(&u.uz) ||
858 | #endif
859 | level.flags.arboreal ||
860 | ((sp = Is_special(&u.uz)) != 0 && !Is_oracle_level(&u.uz)
861 | && (!In_mines(&u.uz) || sp->flags.town)
862 | )) return;
863 |
864 | /* basic level-related probabilities */
865 | goldprob = 20 + depth(&u.uz) / 3;
866 | gemprob = goldprob / 4;
867 |
868 | /* mines have ***MORE*** goodies - otherwise why mine? */
869 | if (In_mines(&u.uz)) {
870 | goldprob *= 2;
871 | gemprob *= 3;
872 | } else if (In_quest(&u.uz)) {
873 | goldprob /= 4;
874 | gemprob /= 6;
875 | }
876 |
877 | /*
878 | * Seed rock areas with gold and/or gems.
879 | * We use fairly low level object handling to avoid unnecessary
880 | * overhead from placing things in the floor chain prior to burial.
881 | */
882 | for (x = 2; x < (COLNO - 2); x++)
883 | for (y = 1; y < (ROWNO - 1); y++)
884 | if (levl[x][y+1].typ != STONE) { /* <x,y> spot not eligible */
885 | y += 2; /* next two spots aren't eligible either */
886 | } else if (levl[x][y].typ != STONE) { /* this spot not eligible */
887 | y += 1; /* next spot isn't eligible either */
888 | } else if (!(levl[x][y].wall_info & W_NONDIGGABLE) &&
889 | levl[x][y-1].typ == STONE &&
890 | levl[x+1][y-1].typ == STONE && levl[x-1][y-1].typ == STONE &&
891 | levl[x+1][y].typ == STONE && levl[x-1][y].typ == STONE &&
892 | levl[x+1][y+1].typ == STONE && levl[x-1][y+1].typ == STONE) {
893 | if (rn2(1000) < goldprob) {
894 | if ((otmp = mksobj(GOLD_PIECE, FALSE, FALSE)) != 0) {
895 | otmp->ox = x, otmp->oy = y;
896 | otmp->quan = 1L + rnd(goldprob * 3);
897 | otmp->owt = weight(otmp);
898 | if (!rn2(3)) add_to_buried(otmp);
899 | else place_object(otmp, x, y);
900 | }
901 | }
902 | if (rn2(1000) < gemprob) {
903 | for (cnt = rnd(2 + dunlev(&u.uz) / 3); cnt > 0; cnt--)
904 | if ((otmp = mkobj(GEM_CLASS, FALSE)) != 0) {
905 | if (otmp->otyp == ROCK) {
906 | dealloc_obj(otmp); /* discard it */
907 | } else {
908 | otmp->ox = x, otmp->oy = y;
909 | if (!rn2(3)) add_to_buried(otmp);
910 | else place_object(otmp, x, y);
911 | }
912 | }
913 | }
914 | }
915 | }
916 |
917 | void
918 | mklev()
919 | {
920 | struct mkroom *croom;
921 |
922 | if(getbones()) return;
923 | in_mklev = TRUE;
924 | makelevel();
925 | bound_digging();
926 | mineralize();
927 | in_mklev = FALSE;
928 | /* has_morgue gets cleared once morgue is entered; graveyard stays
929 | set (graveyard might already be set even when has_morgue is clear
930 | [see fixup_special()], so don't update it unconditionally) */
931 | if (level.flags.has_morgue)
932 | level.flags.graveyard = 1;
933 | if (!level.flags.is_maze_lev) {
934 | for (croom = &rooms[0]; croom != &rooms[nroom]; croom++)
935 | #ifdef SPECIALIZATION
936 | topologize(croom, FALSE);
937 | #else
938 | topologize(croom);
939 | #endif
940 | }
941 | set_wall_state();
942 | }
943 |
944 | void
945 | #ifdef SPECIALIZATION
946 | topologize(croom, do_ordinary)
947 | register struct mkroom *croom;
948 | boolean do_ordinary;
949 | #else
950 | topologize(croom)
951 | register struct mkroom *croom;
952 | #endif
953 | {
954 | register int x, y, roomno = (croom - rooms) + ROOMOFFSET;
955 | register int lowx = croom->lx, lowy = croom->ly;
956 | register int hix = croom->hx, hiy = croom->hy;
957 | #ifdef SPECIALIZATION
958 | register schar rtype = croom->rtype;
959 | #endif
960 | register int subindex, nsubrooms = croom->nsubrooms;
961 |
962 | /* skip the room if already done; i.e. a shop handled out of order */
963 | /* also skip if this is non-rectangular (it _must_ be done already) */
964 | if ((int) levl[lowx][lowy].roomno == roomno || croom->irregular)
965 | return;
966 | #ifdef SPECIALIZATION
967 | # ifdef REINCARNATION
968 | if (Is_rogue_level(&u.uz))
969 | do_ordinary = TRUE; /* vision routine helper */
970 | # endif
971 | if ((rtype != OROOM) || do_ordinary)
972 | #endif
973 | {
974 | /* do innards first */
975 | for(x = lowx; x <= hix; x++)
976 | for(y = lowy; y <= hiy; y++)
977 | #ifdef SPECIALIZATION
978 | if (rtype == OROOM)
979 | levl[x][y].roomno = NO_ROOM;
980 | else
981 | #endif
982 | levl[x][y].roomno = roomno;
983 | /* top and bottom edges */
984 | for(x = lowx-1; x <= hix+1; x++)
985 | for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) {
986 | levl[x][y].edge = 1;
987 | if (levl[x][y].roomno)
988 | levl[x][y].roomno = SHARED;
989 | else
990 | levl[x][y].roomno = roomno;
991 | }
992 | /* sides */
993 | for(x = lowx-1; x <= hix+1; x += (hix-lowx+2))
994 | for(y = lowy; y <= hiy; y++) {
995 | levl[x][y].edge = 1;
996 | if (levl[x][y].roomno)
997 | levl[x][y].roomno = SHARED;
998 | else
999 | levl[x][y].roomno = roomno;
1000 | }
1001 | }
1002 | /* subrooms */
1003 | for (subindex = 0; subindex < nsubrooms; subindex++)
1004 | #ifdef SPECIALIZATION
1005 | topologize(croom->sbrooms[subindex], (rtype != OROOM));
1006 | #else
1007 | topologize(croom->sbrooms[subindex]);
1008 | #endif
1009 | }
1010 |
1011 | /* Find an unused room for a branch location. */
1012 | STATIC_OVL struct mkroom *
1013 | find_branch_room(mp)
1014 | coord *mp;
1015 | {
1016 | struct mkroom *croom = 0;
1017 |
1018 | if (nroom == 0) {
1019 | mazexy(mp); /* already verifies location */
1020 | } else {
1021 | /* not perfect - there may be only one stairway */
1022 | if(nroom > 2) {
1023 | int tryct = 0;
1024 |
1025 | do
1026 | croom = &rooms[rn2(nroom)];
1027 | while((croom == dnstairs_room || croom == upstairs_room ||
1028 | croom->rtype != OROOM) && (++tryct < 100));
1029 | } else
1030 | croom = &rooms[rn2(nroom)];
1031 |
1032 | do {
1033 | if (!somexy(croom, mp))
1034 | impossible("Can't place branch!");
1035 | } while(occupied(mp->x, mp->y) ||
1036 | (levl[mp->x][mp->y].typ != CORR && levl[mp->x][mp->y].typ != ROOM));
1037 | }
1038 | return croom;
1039 | }
1040 |
1041 | /* Find the room for (x,y). Return null if not in a room. */
1042 | STATIC_OVL struct mkroom *
1043 | pos_to_room(x, y)
1044 | xchar x, y;
1045 | {
1046 | int i;
1047 | struct mkroom *curr;
1048 |
1049 | for (curr = rooms, i = 0; i < nroom; curr++, i++)
1050 | if (inside_room(curr, x, y)) return curr;;
1051 | return (struct mkroom *) 0;
1052 | }
1053 |
1054 |
1055 | /* If given a branch, randomly place a special stair or portal. */
1056 | void
1057 | place_branch(br, x, y)
1058 | branch *br; /* branch to place */
1059 | xchar x, y; /* location */
1060 | {
1061 | coord m;
1062 | d_level *dest;
1063 | boolean make_stairs;
1064 | struct mkroom *br_room;
1065 |
1066 | /*
1067 | * Return immediately if there is no branch to make or we have
1068 | * already made one. This routine can be called twice when
1069 | * a special level is loaded that specifies an SSTAIR location
1070 | * as a favored spot for a branch.
1071 | */
1072 | if (!br || made_branch) return;
1073 |
1074 | if (!x) { /* find random coordinates for branch */
1075 | br_room = find_branch_room(&m);
1076 | x = m.x;
1077 | y = m.y;
1078 | } else {
1079 | br_room = pos_to_room(x, y);
1080 | }
1081 |
1082 | if (on_level(&br->end1, &u.uz)) {
1083 | /* we're on end1 */
1084 | make_stairs = br->type != BR_NO_END1;
1085 | dest = &br->end2;
1086 | } else {
1087 | /* we're on end2 */
1088 | make_stairs = br->type != BR_NO_END2;
1089 | dest = &br->end1;
1090 | }
1091 |
1092 | if (br->type == BR_PORTAL) {
1093 | mkportal(x, y, dest->dnum, dest->dlevel);
1094 | } else if (make_stairs) {
1095 | sstairs.sx = x;
1096 | sstairs.sy = y;
1097 | sstairs.up = (char) on_level(&br->end1, &u.uz) ?
1098 | br->end1_up : !br->end1_up;
1099 | assign_level(&sstairs.tolev, dest);
1100 | sstairs_room = br_room;
1101 |
1102 | levl[x][y].ladder = sstairs.up ? LA_UP : LA_DOWN;
1103 | levl[x][y].typ = STAIRS;
1104 | }
1105 | /*
1106 | * Set made_branch to TRUE even if we didn't make a stairwell (i.e.
1107 | * make_stairs is false) since there is currently only one branch
1108 | * per level, if we failed once, we're going to fail again on the
1109 | * next call.
1110 | */
1111 | made_branch = TRUE;
1112 | }
1113 |
1114 | STATIC_OVL boolean
1115 | bydoor(x, y)
1116 | register xchar x, y;
1117 | {
1118 | register int typ;
1119 |
1120 | if (isok(x+1, y)) {
1121 | typ = levl[x+1][y].typ;
1122 | if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
1123 | }
1124 | if (isok(x-1, y)) {
1125 | typ = levl[x-1][y].typ;
1126 | if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
1127 | }
1128 | if (isok(x, y+1)) {
1129 | typ = levl[x][y+1].typ;
1130 | if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
1131 | }
1132 | if (isok(x, y-1)) {
1133 | typ = levl[x][y-1].typ;
1134 | if (IS_DOOR(typ) || typ == SDOOR) return TRUE;
1135 | }
1136 | return FALSE;
1137 | }
1138 |
1139 | /* see whether it is allowable to create a door at [x,y] */
1140 | int
1141 | okdoor(x,y)
1142 | register xchar x, y;
1143 | {
1144 | register boolean near_door = bydoor(x, y);
1145 |
1146 | return((levl[x][y].typ == HWALL || levl[x][y].typ == VWALL) &&
1147 | doorindex < DOORMAX && !near_door);
1148 | }
1149 |
1150 | void
1151 | dodoor(x,y,aroom)
1152 | register int x, y;
1153 | register struct mkroom *aroom;
1154 | {
1155 | if(doorindex >= DOORMAX) {
1156 | impossible("DOORMAX exceeded?");
1157 | return;
1158 | }
1159 |
1160 | dosdoor(x,y,aroom,rn2(8) ? DOOR : SDOOR);
1161 | }
1162 |
1163 | boolean
1164 | occupied(x, y)
1165 | register xchar x, y;
1166 | {
1167 | return((boolean)(t_at(x, y)
1168 | || IS_FURNITURE(levl[x][y].typ)
1169 | || is_lava(x,y)
1170 | || is_pool(x,y)
1171 | || invocation_pos(x,y)
1172 | ));
1173 | }
1174 |
1175 | /* make a trap somewhere (in croom if mazeflag = 0 && !tm) */
1176 | /* if tm != null, make trap at that location */
1177 | void
1178 | mktrap(num, mazeflag, croom, tm)
1179 | register int num, mazeflag;
1180 | register struct mkroom *croom;
1181 | coord *tm;
1182 | {
1183 | register int kind;
1184 | coord m;
1185 |
1186 | /* no traps in pools */
1187 | if (tm && is_pool(tm->x,tm->y)) return;
1188 |
1189 | if (num > 0 && num < TRAPNUM) {
1190 | kind = num;
1191 | #ifdef REINCARNATION
1192 | } else if (Is_rogue_level(&u.uz)) {
1193 | switch (rn2(7)) {
1194 | default: kind = BEAR_TRAP; break; /* 0 */
1195 | case 1: kind = ARROW_TRAP; break;
1196 | case 2: kind = DART_TRAP; break;
1197 | case 3: kind = TRAPDOOR; break;
1198 | case 4: kind = PIT; break;
1199 | case 5: kind = SLP_GAS_TRAP; break;
1200 | case 6: kind = RUST_TRAP; break;
1201 | }
1202 | #endif
1203 | } else if (Inhell && !rn2(5)) {
1204 | /* bias the frequency of fire traps in Gehennom */
1205 | kind = FIRE_TRAP;
1206 | } else {
1207 | unsigned lvl = level_difficulty();
1208 |
1209 | do {
1210 | kind = rnd(TRAPNUM-1);
1211 | /* reject "too hard" traps */
1212 | switch (kind) {
1213 | case MAGIC_PORTAL:
1214 | kind = NO_TRAP; break;
1215 | case ROLLING_BOULDER_TRAP:
1216 | case SLP_GAS_TRAP:
1217 | if (lvl < 2) kind = NO_TRAP; break;
1218 | case LEVEL_TELEP:
1219 | if (lvl < 5 || level.flags.noteleport)
1220 | kind = NO_TRAP; break;
1221 | case SPIKED_PIT:
1222 | if (lvl < 5) kind = NO_TRAP; break;
1223 | case LANDMINE:
1224 | if (lvl < 6) kind = NO_TRAP; break;
1225 | case WEB:
1226 | if (lvl < 7) kind = NO_TRAP; break;
1227 | case STATUE_TRAP:
1228 | case POLY_TRAP:
1229 | if (lvl < 8) kind = NO_TRAP; break;
1230 | case FIRE_TRAP:
1231 | if (!Inhell) kind = NO_TRAP; break;
1232 | case TELEP_TRAP:
1233 | if (level.flags.noteleport) kind = NO_TRAP; break;
1234 | case HOLE:
1235 | /* make these much less often than other traps */
1236 | if (rn2(7)) kind = NO_TRAP; break;
1237 | }
1238 | } while (kind == NO_TRAP);
1239 | }
1240 |
1241 | if ((kind == TRAPDOOR || kind == HOLE) && !Can_fall_thru(&u.uz))
1242 | kind = ROCKTRAP;
1243 |
1244 | if (tm)
1245 | m = *tm;
1246 | else {
1247 | register int tryct = 0;
1248 | boolean avoid_boulder = (kind == PIT || kind == SPIKED_PIT ||
1249 | kind == TRAPDOOR || kind == HOLE);
1250 |
1251 | do {
1252 | if (++tryct > 200)
1253 | return;
1254 | if (mazeflag)
1255 | mazexy(&m);
1256 | else if (!somexy(croom,&m))
1257 | return;
1258 | } while (occupied(m.x, m.y) ||
1259 | (avoid_boulder && sobj_at(BOULDER, m.x, m.y)));
1260 | }
1261 |
1262 | (void) maketrap(m.x, m.y, kind);
1263 | if (kind == WEB) (void) makemon(&mons[PM_GIANT_SPIDER],
1264 | m.x, m.y, NO_MM_FLAGS);
1265 | }
1266 |
1267 | void
1268 | mkstairs(x, y, up, croom)
1269 | xchar x, y;
1270 | char up;
1271 | struct mkroom *croom;
1272 | {
1273 | if (!x) {
1274 | impossible("mkstairs: bogus stair attempt at <%d,%d>", x, y);
1275 | return;
1276 | }
1277 |
1278 | /*
1279 | * We can't make a regular stair off an end of the dungeon. This
1280 | * attempt can happen when a special level is placed at an end and
1281 | * has an up or down stair specified in its description file.
1282 | */
1283 | if ((dunlev(&u.uz) == 1 && up) ||
1284 | (dunlev(&u.uz) == dunlevs_in_dungeon(&u.uz) && !up))
1285 | return;
1286 |
1287 | if(up) {
1288 | xupstair = x;
1289 | yupstair = y;
1290 | upstairs_room = croom;
1291 | } else {
1292 | xdnstair = x;
1293 | ydnstair = y;
1294 | dnstairs_room = croom;
1295 | }
1296 |
1297 | levl[x][y].typ = STAIRS;
1298 | levl[x][y].ladder = up ? LA_UP : LA_DOWN;
1299 | }
1300 |
1301 | STATIC_OVL
1302 | void
1303 | mkfount(mazeflag,croom)
1304 | register int mazeflag;
1305 | register struct mkroom *croom;
1306 | {
1307 | coord m;
1308 | register int tryct = 0;
1309 |
1310 | do {
1311 | if(++tryct > 200) return;
1312 | if(mazeflag)
1313 | mazexy(&m);
1314 | else
1315 | if (!somexy(croom, &m))
1316 | return;
1317 | } while(occupied(m.x, m.y) || bydoor(m.x, m.y));
1318 |
1319 | /* Put a fountain at m.x, m.y */
1320 | levl[m.x][m.y].typ = FOUNTAIN;
1321 | /* Is it a "blessed" fountain? (affects drinking from fountain) */
1322 | if(!rn2(7)) levl[m.x][m.y].blessedftn = 1;
1323 |
1324 | level.flags.nfountains++;
1325 | }
1326 |
1327 | #ifdef SINKS
1328 | STATIC_OVL void
1329 | mksink(croom)
1330 | register struct mkroom *croom;
1331 | {
1332 | coord m;
1333 | register int tryct = 0;
1334 |
1335 | do {
1336 | if(++tryct > 200) return;
1337 | if (!somexy(croom, &m))
1338 | return;
1339 | } while(occupied(m.x, m.y) || bydoor(m.x, m.y));
1340 |
1341 | /* Put a sink at m.x, m.y */
1342 | levl[m.x][m.y].typ = SINK;
1343 |
1344 | level.flags.nsinks++;
1345 | }
1346 | #endif /* SINKS */
1347 |
1348 |
1349 | STATIC_OVL void
1350 | mkaltar(croom)
1351 | register struct mkroom *croom;
1352 | {
1353 | coord m;
1354 | register int tryct = 0;
1355 | aligntyp al;
1356 |
1357 | if (croom->rtype != OROOM) return;
1358 |
1359 | do {
1360 | if(++tryct > 200) return;
1361 | if (!somexy(croom, &m))
1362 | return;
1363 | } while (occupied(m.x, m.y) || bydoor(m.x, m.y));
1364 |
1365 | /* Put an altar at m.x, m.y */
1366 | levl[m.x][m.y].typ = ALTAR;
1367 |
1368 | /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */
1369 | al = rn2((int)A_LAWFUL+2) - 1;
1370 | levl[m.x][m.y].altarmask = Align2amask( al );
1371 | }
1372 |
1373 | static void
1374 | mkgrave(croom)
1375 | struct mkroom *croom;
1376 | {
1377 | coord m;
1378 | register int tryct = 0;
1379 | register struct obj *otmp;
1380 | boolean dobell = !rn2(10);
1381 |
1382 |
1383 | if(croom->rtype != OROOM) return;
1384 |
1385 | do {
1386 | if(++tryct > 200) return;
1387 | if (!somexy(croom, &m))
1388 | return;
1389 | } while (occupied(m.x, m.y) || bydoor(m.x, m.y));
1390 |
1391 | /* Put a grave at m.x, m.y */
1392 | make_grave(m.x, m.y, dobell ? "Saved by the bell!" : (char *) 0);
1393 |
1394 | /* Possibly fill it with objects */
1395 | if (!rn2(3)) (void) mkgold(0L, m.x, m.y);
1396 | for (tryct = rn2(5); tryct; tryct--) {
1397 | otmp = mkobj(RANDOM_CLASS, TRUE);
1398 | if (!otmp) return;
1399 | curse(otmp);
1400 | otmp->ox = m.x;
1401 | otmp->oy = m.y;
1402 | add_to_buried(otmp);
1403 | }
1404 |
1405 | /* Leave a bell, in case we accidentally buried someone alive */
1406 | if (dobell) (void) mksobj_at(BELL, m.x, m.y, TRUE);
1407 | return;
1408 | }
1409 |
1410 |
1411 | /* maze levels have slightly different constraints from normal levels */
1412 | #define x_maze_min 2
1413 | #define y_maze_min 2
1414 | /*
1415 | * Major level transmutation: add a set of stairs (to the Sanctum) after
1416 | * an earthquake that leaves behind a a new topology, centered at inv_pos.
1417 | * Assumes there are no rooms within the invocation area and that inv_pos
1418 | * is not too close to the edge of the map. Also assume the hero can see,
1419 | * which is guaranteed for normal play due to the fact that sight is needed
1420 | * to read the Book of the Dead.
1421 | */
1422 | void
1423 | mkinvokearea()
1424 | {
1425 | int dist;
1426 | xchar xmin = inv_pos.x, xmax = inv_pos.x;
1427 | xchar ymin = inv_pos.y, ymax = inv_pos.y;
1428 | register xchar i;
1429 |
1430 | pline_The("floor shakes violently under you!");
1431 | pline_The("walls around you begin to bend and crumble!");
1432 | display_nhwindow(WIN_MESSAGE, TRUE);
1433 |
1434 | mkinvpos(xmin, ymin, 0); /* middle, before placing stairs */
1435 |
1436 | for(dist = 1; dist < 7; dist++) {
1437 | xmin--; xmax++;
1438 |
1439 | /* top and bottom */
1440 | if(dist != 3) { /* the area is wider that it is high */
1441 | ymin--; ymax++;
1442 | for(i = xmin+1; i < xmax; i++) {
1443 | mkinvpos(i, ymin, dist);
1444 | mkinvpos(i, ymax, dist);
1445 | }
1446 | }
1447 |
1448 | /* left and right */
1449 | for(i = ymin; i <= ymax; i++) {
1450 | mkinvpos(xmin, i, dist);
1451 | mkinvpos(xmax, i, dist);
1452 | }
1453 |
1454 | flush_screen(1); /* make sure the new glyphs shows up */
1455 | delay_output();
1456 | }
1457 |
1458 | You("are standing at the top of a stairwell leading down!");
1459 | mkstairs(u.ux, u.uy, 0, (struct mkroom *)0); /* down */
1460 | newsym(u.ux, u.uy);
1461 | vision_full_recalc = 1; /* everything changed */
1462 | }
1463 |
1464 | /* Change level topology. Boulders in the vicinity are eliminated.
1465 | * Temporarily overrides vision in the name of a nice effect.
1466 | */
1467 | STATIC_OVL void
1468 | mkinvpos(x,y,dist)
1469 | xchar x,y;
1470 | int dist;
1471 | {
1472 | struct trap *ttmp;
1473 | struct obj *otmp;
1474 | boolean make_rocks;
1475 | register struct rm *lev = &levl[x][y];
1476 |
1477 | /* clip at existing map borders if necessary */
1478 | if (!within_bounded_area(x, y, x_maze_min + 1, y_maze_min + 1,
1479 | x_maze_max - 1, y_maze_max - 1)) {
1480 | /* only outermost 2 columns and/or rows may be truncated due to edge */
1481 | if (dist < (7 - 2))
1482 | panic("mkinvpos: <%d,%d> (%d) off map edge!", x, y, dist);
1483 | return;
1484 | }
1485 |
1486 | /* clear traps */
1487 | if ((ttmp = t_at(x,y)) != 0) deltrap(ttmp);
1488 |
1489 | /* clear boulders; leave some rocks for non-{moat|trap} locations */
1490 | make_rocks = (dist != 1 && dist != 4 && dist != 5) ? TRUE : FALSE;
1491 | while ((otmp = sobj_at(BOULDER, x, y)) != 0) {
1492 | if (make_rocks) {
1493 | fracture_rock(otmp);
1494 | make_rocks = FALSE; /* don't bother with more rocks */
1495 | } else {
1496 | obj_extract_self(otmp);
1497 | obfree(otmp, (struct obj *)0);
1498 | }
1499 | }
1500 | unblock_point(x,y); /* make sure vision knows this location is open */
1501 |
1502 | /* fake out saved state */
1503 | lev->seenv = 0;
1504 | lev->doormask = 0;
1505 | if(dist < 6) lev->lit = TRUE;
1506 | lev->waslit = TRUE;
1507 | lev->horizontal = FALSE;
1508 | viz_array[y][x] = (dist < 6 ) ?
1509 | (IN_SIGHT|COULD_SEE) : /* short-circuit vision recalc */
1510 | COULD_SEE;
1511 |
1512 | switch(dist) {
1513 | case 1: /* fire traps */
1514 | if (is_pool(x,y)) break;
1515 | lev->typ = ROOM;
1516 | ttmp = maketrap(x, y, FIRE_TRAP);
1517 | if (ttmp) ttmp->tseen = TRUE;
1518 | break;
1519 | case 0: /* lit room locations */
1520 | case 2:
1521 | case 3:
1522 | case 6: /* unlit room locations */
1523 | lev->typ = ROOM;
1524 | break;
1525 | case 4: /* pools (aka a wide moat) */
1526 | case 5:
1527 | lev->typ = MOAT;
1528 | /* No kelp! */
1529 | break;
1530 | default:
1531 | impossible("mkinvpos called with dist %d", dist);
1532 | break;
1533 | }
1534 |
1535 | /* display new value of position; could have a monster/object on it */
1536 | newsym(x,y);
1537 | }
1538 |
1539 | /*
1540 | * The portal to Ludios is special. The entrance can only occur within a
1541 | * vault in the main dungeon at a depth greater than 10. The Ludios branch
1542 | * structure reflects this by having a bogus "source" dungeon: the value
1543 | * of n_dgns (thus, Is_branchlev() will never find it).
1544 | *
1545 | * Ludios will remain isolated until the branch is corrected by this function.
1546 | */
1547 | STATIC_OVL void
1548 | mk_knox_portal(x, y)
1549 | xchar x, y;
1550 | {
1551 | extern int n_dgns; /* from dungeon.c */
1552 | d_level *source;
1553 | branch *br;
1554 | schar u_depth;
1555 |
1556 | br = dungeon_branch("Fort Ludios");
1557 | if (on_level(&knox_level, &br->end1)) {
1558 | source = &br->end2;
1559 | } else {
1560 | /* disallow Knox branch on a level with one branch already */
1561 | if(Is_branchlev(&u.uz))
1562 | return;
1563 | source = &br->end1;
1564 | }
1565 |
1566 | /* Already set or 2/3 chance of deferring until a later level. */
1567 | if (source->dnum < n_dgns || (rn2(3)
1568 | #ifdef WIZARD
1569 | && !wizard
1570 | #endif
1571 | )) return;
1572 |
1573 | if (! (u.uz.dnum == oracle_level.dnum /* in main dungeon */
1574 | && !at_dgn_entrance("The Quest") /* but not Quest's entry */
1575 | && (u_depth = depth(&u.uz)) > 10 /* beneath 10 */
1576 | && u_depth < depth(&medusa_level))) /* and above Medusa */
1577 | return;
1578 |
1579 | /* Adjust source to be current level and re-insert branch. */
1580 | *source = u.uz;
1581 | insert_branch(br, TRUE);
1582 |
1583 | #ifdef DEBUG
1584 | pline("Made knox portal.");
1585 | #endif
1586 | place_branch(br, x, y);
1587 | }
1588 |
1589 | /*mklev.c*/