1 /* SCCS Id: @(#)mkmaze.c 3.4 2002/04/04 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
7 #include "lev.h" /* save & restore info */
9 /* from sp_lev.c, for fixup_special() */
10 extern char *lev_message
;
11 extern lev_region
*lregions
;
12 extern int num_lregions
;
14 STATIC_DCL boolean
iswall(int,int);
15 STATIC_DCL boolean
iswall_or_stone(int,int);
16 STATIC_DCL boolean
is_solid(int,int);
17 STATIC_DCL
int extend_spine(int [3][3], int, int, int);
18 STATIC_DCL boolean
okay(int,int,int);
19 STATIC_DCL
void maze0xy(coord
*);
20 STATIC_DCL boolean
put_lregion_here(XCHAR_P
,XCHAR_P
,XCHAR_P
,
21 XCHAR_P
,XCHAR_P
,XCHAR_P
,XCHAR_P
,BOOLEAN_P
,d_level
*);
22 STATIC_DCL boolean
really_put_lregion_here(XCHAR_P
,XCHAR_P
,XCHAR_P
,
23 XCHAR_P
,XCHAR_P
,XCHAR_P
,XCHAR_P
,BOOLEAN_P
,d_level
*);
24 STATIC_DCL
void fixup_special(void);
25 STATIC_DCL
void move(int *,int *,int);
26 STATIC_DCL
void setup_waterlevel(void);
27 STATIC_DCL
void unsetup_waterlevel(void);
35 if (!isok(x
,y
)) return FALSE
;
36 type
= levl
[x
][y
].typ
;
37 return (IS_WALL(type
) || IS_DOOR(type
) ||
38 type
== SDOOR
|| type
== IRONBARS
);
47 /* out of bounds = stone */
48 if (!isok(x
,y
)) return TRUE
;
50 type
= levl
[x
][y
].typ
;
51 return (type
== STONE
|| IS_WALL(type
) || IS_DOOR(type
) ||
52 type
== SDOOR
|| type
== IRONBARS
);
55 /* return TRUE if out of bounds, wall or rock */
60 return (!isok(x
,y
) || IS_STWALL(levl
[x
][y
].typ
));
65 * Return 1 (not TRUE - we're doing bit vectors here) if we want to extend
66 * a wall spine in the (dx,dy) direction. Return 0 otherwise.
68 * To extend a wall spine in that direction, first there must be a wall there.
69 * Then, extend a spine unless the current position is surrounded by walls
70 * in the direction given by (dx,dy). E.g. if 'x' is our location, 'W'
71 * a wall, '.' a room, 'a' anything (we don't care), and our direction is
72 * (0,1) - South or down - then:
75 * W x W This would not extend a spine from x down
76 * W W W (a corridor of walls is formed).
79 * W x W This would extend a spine from x down.
83 extend_spine(locale
, wall_there
, dx
, dy
)
85 int wall_there
, dx
, dy
;
92 if (wall_there
) { /* wall in that direction */
94 if (locale
[ 1][0] && locale
[ 1][2] && /* EW are wall/stone */
95 locale
[nx
][0] && locale
[nx
][2]) { /* diag are wall/stone */
101 if (locale
[0][ 1] && locale
[2][ 1] && /* NS are wall/stone */
102 locale
[0][ny
] && locale
[2][ny
]) { /* diag are wall/stone */
117 * Walls to surprise jaded Gehennom-haters :)
119 * Wall cleanup. This function turns all wall squares into 'floortype' squares.
123 wallify_special(x1
, y1
, x2
, y2
, floortype
)
125 int floortype
; /* The 'wall' floortype */
131 int density
= 3 + rn2(8);
132 if (!rn2(5)) density
+= rnd(6);
133 if (!rn2(10)) density
+= rnd(15);
134 if (!rn2(25)) density
+= rnd(30);
135 if (!rn2(125)) density
+= rnd(40);
136 if (!rn2(750)) density
+= rnd(50);
138 /* sanity check on incoming variables */
139 if (x1
<0 || x2
>=COLNO
|| x1
>x2
|| y1
<0 || y2
>=ROWNO
|| y1
>y2
)
140 panic("wallify_fire: bad bounds (%d,%d) to (%d,%d)",x1
,y1
,x2
,y2
);
142 /* Translate the maze... */
143 for(x
= x1
; x
<= x2
; x
++)
144 for(y
= y1
; y
<= y2
; y
++) {
147 if ( IS_WALL(type
) && type
!= GRAVEWALL
&& (rnd(density
) < 4))
148 lev
->typ
= (floortype
== CROSSWALL
) ? randomwalltype() : floortype
;
149 else if IS_WALL(type
)
151 /* Doors become room squares. Does this make sense? */
152 else if (IS_DOOR(type
))
154 else if (type
== SDOOR
)
156 else if (type
== SCORR
)
164 * Wall cleanup. This function has two purposes: (1) remove walls that
165 * are totally surrounded by stone - they are redundant. (2) correct
166 * the types so that they extend and connect to each other.
170 wallify_stone(x1
, y1
, x2
, y2
) /* [Lethe] Classic stone walls */
177 int locale
[3][3]; /* rock or wall status surrounding positions */
179 * Value 0 represents a free-standing wall. It could be anything,
180 * so even though this table says VWALL, we actually leave whatever
181 * typ was there alone.
183 static xchar spine_array
[16] = {
184 VWALL
, HWALL
, HWALL
, HWALL
,
185 VWALL
, TRCORNER
, TLCORNER
, TDWALL
,
186 VWALL
, BRCORNER
, BLCORNER
, TUWALL
,
187 VWALL
, TLWALL
, TRWALL
, CROSSWALL
190 /* sanity check on incoming variables */
191 if (x1
<0 || x2
>=COLNO
|| x1
>x2
|| y1
<0 || y2
>=ROWNO
|| y1
>y2
)
192 panic("wallify_stone: bad bounds (%d,%d) to (%d,%d)",x1
,y1
,x2
,y2
);
194 /* Step 1: change walls surrounded by rock to rock. */
195 for(x
= x1
; x
<= x2
; x
++)
196 for(y
= y1
; y
<= y2
; y
++) {
199 if (IS_WALL(type
) && type
!= DBWALL
&& type
!= ROCKWALL
&& type
!= TUNNELWALL
&& type
!= GRAVEWALL
) {
200 if (is_solid(x
-1,y
-1) &&
213 * Step 2: set the correct wall type. We can't combine steps
214 * 1 and 2 into a single sweep because we depend on knowing if
215 * the surrounding positions are stone.
217 for(x
= x1
; x
<= x2
; x
++)
218 for(y
= y1
; y
<= y2
; y
++) {
221 if ( !(IS_WALL(type
) && type
!= DBWALL
&& type
!= ROCKWALL
&& type
!= TUNNELWALL
&& type
!= GRAVEWALL
)) continue;
223 /* set the locations TRUE if rock or wall or out of bounds */
224 locale
[0][0] = iswall_or_stone(x
-1,y
-1);
225 locale
[1][0] = iswall_or_stone( x
,y
-1);
226 locale
[2][0] = iswall_or_stone(x
+1,y
-1);
228 locale
[0][1] = iswall_or_stone(x
-1, y
);
229 locale
[2][1] = iswall_or_stone(x
+1, y
);
231 locale
[0][2] = iswall_or_stone(x
-1,y
+1);
232 locale
[1][2] = iswall_or_stone( x
,y
+1);
233 locale
[2][2] = iswall_or_stone(x
+1,y
+1);
235 /* determine if wall should extend to each direction NSEW */
236 bits
= (extend_spine(locale
, iswall(x
,y
-1), 0, -1) << 3)
237 | (extend_spine(locale
, iswall(x
,y
+1), 0, 1) << 2)
238 | (extend_spine(locale
, iswall(x
+1,y
), 1, 0) << 1)
239 | extend_spine(locale
, iswall(x
-1,y
), -1, 0);
241 /* don't change typ if wall is free-standing */
242 if (bits
) lev
->typ
= spine_array
[bits
];
247 * Wall cleanup. This selects an appropriate function to sort out the
251 wallification(x1
, y1
, x2
, y2
, initial
)
255 /* Wallify normally unless creating a full maze level */
257 wallify_stone(x1
, y1
, x2
, y2
);
261 /* Put in the walls... */
263 int wallchoice
= rn2(450);
265 if (wallchoice
< 417)
266 wallify_stone(x1
, y1
, x2
, y2
);
267 else if (wallchoice
< 418)
268 wallify_special(x1
, y1
, x2
, y2
, CROSSWALL
);
269 else if (wallchoice
< 419)
270 wallify_special(x1
, y1
, x2
, y2
, CLOUD
);
271 else if (wallchoice
< 421)
272 wallify_special(x1
, y1
, x2
, y2
, MOAT
);
273 else if (wallchoice
< 423)
274 wallify_special(x1
, y1
, x2
, y2
, ICE
);
275 else if (wallchoice
< 425)
276 wallify_special(x1
, y1
, x2
, y2
, LAVAPOOL
);
277 else if (wallchoice
< 426)
278 wallify_special(x1
, y1
, x2
, y2
, TREE
);
279 else if (wallchoice
< 427)
280 wallify_special(x1
, y1
, x2
, y2
, GRAVEWALL
);
281 else if (wallchoice
< 428)
282 wallify_special(x1
, y1
, x2
, y2
, TUNNELWALL
);
283 else if (wallchoice
< 429)
284 wallify_special(x1
, y1
, x2
, y2
, FARMLAND
);
285 else if (wallchoice
< 430)
286 wallify_special(x1
, y1
, x2
, y2
, MOUNTAIN
);
287 else if (wallchoice
< 431)
288 wallify_special(x1
, y1
, x2
, y2
, WATERTUNNEL
);
289 else if (wallchoice
< 432)
290 wallify_special(x1
, y1
, x2
, y2
, CRYSTALWATER
);
291 else if (wallchoice
< 433)
292 wallify_special(x1
, y1
, x2
, y2
, MOORLAND
);
293 else if (wallchoice
< 434)
294 wallify_special(x1
, y1
, x2
, y2
, URINELAKE
);
295 else if (wallchoice
< 435)
296 wallify_special(x1
, y1
, x2
, y2
, SHIFTINGSAND
);
297 else if (wallchoice
< 436)
298 wallify_special(x1
, y1
, x2
, y2
, STYXRIVER
);
299 else if (wallchoice
< 437)
300 wallify_special(x1
, y1
, x2
, y2
, SNOW
);
301 else if (wallchoice
< 438)
302 wallify_special(x1
, y1
, x2
, y2
, ASH
);
303 else if (wallchoice
< 439)
304 wallify_special(x1
, y1
, x2
, y2
, SAND
);
305 else if (wallchoice
< 440)
306 wallify_special(x1
, y1
, x2
, y2
, PAVEDFLOOR
);
307 else if (wallchoice
< 441)
308 wallify_special(x1
, y1
, x2
, y2
, HIGHWAY
);
309 else if (wallchoice
< 442)
310 wallify_special(x1
, y1
, x2
, y2
, GRASSLAND
);
311 else if (wallchoice
< 443)
312 wallify_special(x1
, y1
, x2
, y2
, NETHERMIST
);
313 else if (wallchoice
< 444)
314 wallify_special(x1
, y1
, x2
, y2
, STALACTITE
);
315 else if (wallchoice
< 445)
316 wallify_special(x1
, y1
, x2
, y2
, CRYPTFLOOR
);
317 else if (wallchoice
< 446)
318 wallify_special(x1
, y1
, x2
, y2
, BUBBLES
);
319 else if (wallchoice
< 447)
320 wallify_special(x1
, y1
, x2
, y2
, RAINCLOUD
);
322 wallify_special(x1
, y1
, x2
, y2
, IRONBARS
);
334 if(x
<3 || y
<3 || x
>x_maze_max
|| y
>y_maze_max
|| levl
[x
][y
].typ
!= 0)
340 maze0xy(cc
) /* find random starting point for maze generation */
343 cc
->x
= 3 + 2*rn2((x_maze_max
>>1) - 1);
344 cc
->y
= 3 + 2*rn2((y_maze_max
>>1) - 1);
351 * pos is inside restricted region (lx,ly,hx,hy) OR
352 * NOT (pos is corridor and a maze level OR pos is a room OR pos is air)
355 bad_location(x
, y
, lx
, ly
, hx
, hy
)
357 xchar lx
, ly
, hx
, hy
;
359 return((boolean
)(occupied(x
, y
) ||
360 within_bounded_area(x
,y
, lx
,ly
, hx
,hy
) ||
361 !((levl
[x
][y
].typ
== CORR
/*&& level.flags.is_maze_lev*/) ||
362 levl
[x
][y
].typ
== ROOM
|| levl
[x
][y
].typ
== AIR
|| levl
[x
][y
].typ
== CLOUD
|| levl
[x
][y
].typ
== ICE
|| levl
[x
][y
].typ
== SNOW
|| levl
[x
][y
].typ
== ASH
|| levl
[x
][y
].typ
== SAND
|| levl
[x
][y
].typ
== PAVEDFLOOR
|| levl
[x
][y
].typ
== HIGHWAY
|| levl
[x
][y
].typ
== GRASSLAND
|| levl
[x
][y
].typ
== NETHERMIST
|| levl
[x
][y
].typ
== STALACTITE
|| levl
[x
][y
].typ
== CRYPTFLOOR
|| levl
[x
][y
].typ
== BUBBLES
|| levl
[x
][y
].typ
== RAINCLOUD
)));
366 really_bad_location(x
, y
, lx
, ly
, hx
, hy
)
368 xchar lx
, ly
, hx
, hy
;
370 return((boolean
) within_bounded_area(x
,y
, lx
,ly
, hx
,hy
) );
373 /* pick a location in area (lx, ly, hx, hy) but not in (nlx, nly, nhx, nhy) */
374 /* and place something (based on rtype) in that region */
376 place_lregion(lx
, ly
, hx
, hy
, nlx
, nly
, nhx
, nhy
, rtype
, lev
)
377 xchar lx
, ly
, hx
, hy
;
378 xchar nlx
, nly
, nhx
, nhy
;
386 if(!lx
) { /* default to whole level */
388 * if there are rooms and this a branch, let place_branch choose
389 * the branch location (to avoid putting branches in corridors).
390 * Amy edit: but only if it's a plot-critical branch that you must find in order to win the game, and even then
391 * only if you're not playing the evil variant. Otherwise, let them be randomly placed.
392 * Note that it's not a bug that the sanctum-to-yendortower portal is exempt - otherwise, we'd always place it
393 * either in the temple or the graveyard, which we definitely don't want!
394 * Also, the flipside of those branches is free to be placed completely randomly, because you (normally) don't
395 * have to look for it - to any would-be slex modders reading this, I only want to avoid the player having to search
396 * the entirety of every level for branches that absolutely MUST be done to win the game.
397 * Stairseeker hybrid race should also allow them all to be placed randomly, like evilvariant mode
399 if(rtype
== LR_BRANCH
&& nroom
) {
401 if (!evilfriday
&& !isstairseeker
&& (at_dgn_entrance("Green Cross") || at_dgn_entrance("The Subquest") || at_dgn_entrance("The Quest") || at_dgn_entrance("Lawful Quest") || at_dgn_entrance("Neutral Quest") || at_dgn_entrance("Chaotic Quest") || at_dgn_entrance("The Elemental Planes") || at_dgn_entrance("Sheol") || at_dgn_entrance("Bell Caves") || at_dgn_entrance("Vlad's Tower") || at_dgn_entrance("Forging Chamber") || at_dgn_entrance("Dead Grounds") || at_dgn_entrance("Ordered Chaos") ) ) {
403 place_branch(Is_branchlev(&u
.uz
), 0, 0);
410 lx
= 1; hx
= COLNO
-1;
411 ly
= 1; hy
= ROWNO
-1;
414 /* first a probabilistic approach */
416 oneshot
= (lx
== hx
&& ly
== hy
);
417 for (trycnt
= 0; trycnt
< 200; trycnt
++) {
418 x
= rn1((hx
- lx
) + 1, lx
);
419 y
= rn1((hy
- ly
) + 1, ly
);
420 if (put_lregion_here(x
,y
,nlx
,nly
,nhx
,nhy
,rtype
,oneshot
,lev
))
424 /* then a deterministic one */
427 for (x
= lx
; x
<= hx
; x
++)
428 for (y
= ly
; y
<= hy
; y
++)
429 if (put_lregion_here(x
,y
,nlx
,nly
,nhx
,nhy
,rtype
,oneshot
,lev
))
432 /* and finally, brute force the shit out of it because we're making a motherfucking BRANCH and the game might be
433 * rendered unwinnable if it cannot be placed! --Amy */
436 pline("Trying to force a location for lregion type %d", rtype
);
440 for (x
= lx
; x
<= hx
; x
++)
441 for (y
= ly
; y
<= hy
; y
++)
442 if (really_put_lregion_here(x
,y
,nlx
,nly
,nhx
,nhy
,rtype
,oneshot
,lev
))
445 impossible("Couldn't place lregion type %d!", rtype
);
449 put_lregion_here(x
,y
,nlx
,nly
,nhx
,nhy
,rtype
,oneshot
,lev
)
451 xchar nlx
, nly
, nhx
, nhy
;
456 if (bad_location(x
, y
, nlx
, nly
, nhx
, nhy
)) {
458 return FALSE
; /* caller should try again */
460 /* Must make do with the only location possible;
461 avoid failure due to a misplaced trap.
462 It might still fail if there's a dungeon feature here. */
463 struct trap
*t
= t_at(x
,y
);
465 if (t
&& t
->ttyp
!= MAGIC_PORTAL
) deltrap(t
);
466 if (bad_location(x
, y
, nlx
, nly
, nhx
, nhy
)) return FALSE
;
473 /* "something" means the player in this case */
475 /* move the monster if no choice, or just try again */
476 if(oneshot
) (void) rloc(m_at(x
,y
), FALSE
);
482 mkportal(x
, y
, lev
->dnum
, lev
->dlevel
);
486 mkstairs(x
, y
, (char)rtype
, (struct mkroom
*)0);
489 place_branch(Is_branchlev(&u
.uz
), x
, y
);
496 really_put_lregion_here(x
,y
,nlx
,nly
,nhx
,nhy
,rtype
,oneshot
,lev
)
498 xchar nlx
, nly
, nhx
, nhy
;
503 if (really_bad_location(x
, y
, nlx
, nly
, nhx
, nhy
)) {
505 return FALSE
; /* caller should try again */
507 /* Must make do with the only location possible;
508 avoid failure due to a misplaced trap.
509 It may not fail, no matter what happens. Missing ladder + lost soul mode == unwinnable game! --Amy */
510 struct trap
*t
= t_at(x
,y
);
512 if (t
&& t
->ttyp
!= MAGIC_PORTAL
) deltrap(t
);
513 if (really_bad_location(x
, y
, nlx
, nly
, nhx
, nhy
)) return FALSE
;
520 /* "something" means the player in this case */
522 /* move the monster if no choice, or just try again */
523 if(oneshot
) (void) rloc(m_at(x
,y
), FALSE
);
529 mkportal(x
, y
, lev
->dnum
, lev
->dlevel
);
533 mkstairs(x
, y
, (char)rtype
, (struct mkroom
*)0);
536 place_branch(Is_branchlev(&u
.uz
), x
, y
);
542 static boolean was_waterlevel
; /* ugh... this shouldn't be needed */
544 /* this is special stuff that the level compiler cannot (yet) handle */
548 register lev_region
*r
= lregions
;
551 struct mkroom
*croom
;
552 boolean added_branch
= FALSE
;
554 if (was_waterlevel
) {
555 was_waterlevel
= FALSE
;
557 unsetup_waterlevel();
558 } else if (Is_waterlevel(&u
.uz
)) {
559 level
.flags
.hero_memory
= 0;
560 was_waterlevel
= TRUE
;
561 /* water level is an odd beast - it has to be set up
562 before calling place_lregions etc. */
565 for(x
= 0; x
< num_lregions
; x
++, r
++) {
572 if(*r
->rname
.str
>= '0' && *r
->rname
.str
<= '9') {
573 /* "chutes and ladders" */
575 lev
.dlevel
= atoi(r
->rname
.str
);
577 s_level
*sp
= find_level(r
->rname
.str
);
585 place_lregion(r
->inarea
.x1
, r
->inarea
.y1
,
586 r
->inarea
.x2
, r
->inarea
.y2
,
587 r
->delarea
.x1
, r
->delarea
.y1
,
588 r
->delarea
.x2
, r
->delarea
.y2
,
595 /* save the region outlines for goto_level() */
596 if(r
->rtype
== LR_TELE
|| r
->rtype
== LR_UPTELE
) {
597 updest
.lx
= r
->inarea
.x1
; updest
.ly
= r
->inarea
.y1
;
598 updest
.hx
= r
->inarea
.x2
; updest
.hy
= r
->inarea
.y2
;
599 updest
.nlx
= r
->delarea
.x1
; updest
.nly
= r
->delarea
.y1
;
600 updest
.nhx
= r
->delarea
.x2
; updest
.nhy
= r
->delarea
.y2
;
602 if(r
->rtype
== LR_TELE
|| r
->rtype
== LR_DOWNTELE
) {
603 dndest
.lx
= r
->inarea
.x1
; dndest
.ly
= r
->inarea
.y1
;
604 dndest
.hx
= r
->inarea
.x2
; dndest
.hy
= r
->inarea
.y2
;
605 dndest
.nlx
= r
->delarea
.x1
; dndest
.nly
= r
->delarea
.y1
;
606 dndest
.nhx
= r
->delarea
.x2
; dndest
.nhy
= r
->delarea
.y2
;
608 /* place_lregion gets called from goto_level() */
612 if (r
->rname
.str
) free((void *) r
->rname
.str
), r
->rname
.str
= 0;
615 /* place dungeon branch if not placed above */
616 if (!added_branch
&& Is_branchlev(&u
.uz
)) {
617 place_lregion(0,0,0,0,0,0,0,0,LR_BRANCH
,(d_level
*)0);
620 /* KMH -- arboreal levels */
621 /* if (level.flags.arboreal)
622 for(x = 2; x < x_maze_max; x++)
623 for(y = 2; y < y_maze_max; y++)
624 if (levl[x][y].typ == STONE)
625 levl[x][y].typ = TREE;*/
627 /* KMH -- Sokoban levels */
628 if(In_sokoban(&u
.uz
))
631 /* Still need to add some stuff to level file */
632 if (Is_medusa_level(&u
.uz
)) {
636 croom
= &rooms
[0]; /* only one room on the medusa level */
637 for (tryct
= rnd(4); tryct
; tryct
--) {
638 x
= somex(croom
); y
= somey(croom
);
639 if (goodpos(x
, y
, (struct monst
*)0, 0)) {
640 otmp
= mk_tt_object(STATUE
, x
, y
);
641 while (otmp
&& (poly_when_stoned(&mons
[otmp
->corpsenm
]) ||
642 pm_resistance(&mons
[otmp
->corpsenm
],MR_STONE
))) {
643 otmp
->corpsenm
= rndmonnum();
644 otmp
->owt
= weight(otmp
);
650 otmp
= mk_tt_object(STATUE
, somex(croom
), somey(croom
));
651 else /* Medusa statues don't contain books */
652 otmp
= mkcorpstat(STATUE
, (struct monst
*)0, (struct permonst
*)0,
653 somex(croom
), somey(croom
), FALSE
);
655 while (pm_resistance(&mons
[otmp
->corpsenm
],MR_STONE
)
656 || poly_when_stoned(&mons
[otmp
->corpsenm
])) {
657 otmp
->corpsenm
= rndmonnum();
658 otmp
->owt
= weight(otmp
);
661 } else if(Is_wiz1_level(&u
.uz
)) {
662 croom
= search_special(MORGUE
);
664 create_secret_door(croom
, W_SOUTH
|W_EAST
|W_WEST
);
665 } else if(Is_knox(&u
.uz
)) {
666 /* using an unfilled morgue for rm id */
667 croom
= search_special(MORGUE
);
668 /* avoid inappropriate morgue-related messages */
669 level
.flags
.graveyard
= level
.flags
.has_morgue
= 0;
670 croom
->rtype
= OROOM
; /* perhaps it should be set to VAULT? */
671 /* stock the main vault */
672 for(x
= croom
->lx
; x
<= croom
->hx
; x
++)
673 for(y
= croom
->ly
; y
<= croom
->hy
; y
++) {
674 (void) mkgold((long) rn1(300, 600), x
, y
);
675 if (!rn2(3) && !is_waterypool(x
,y
))
676 (void)maketrap(x
, y
, rn2(3) ? LANDMINE
: SPIKED_PIT
, 5, TRUE
);
678 } else if (Role_if(PM_PRIEST
) && In_quest(&u
.uz
)) {
679 /* less chance for undead corpses (lured from lower morgues) */
680 level
.flags
.graveyard
= 1;
681 } else if (Is_stronghold(&u
.uz
)) {
682 level
.flags
.graveyard
= 1;
683 } else if(Is_sanctum(&u
.uz
)) {
684 croom
= search_special(TEMPLE
);
686 create_secret_door(croom
, W_ANY
);
687 } else if(on_level(&u
.uz
, &orcus_level
)) {
688 register struct monst
*mtmp
, *mtmp2
;
690 /* it's a ghost town, get rid of shopkeepers */
691 for(mtmp
= fmon
; mtmp
; mtmp
= mtmp2
) {
693 if(mtmp
->isshk
) mongone(mtmp
);
699 for(str
= lev_message
; (nl
= index(str
, '\n')) != 0; str
= nl
+1) {
705 free((void *)lev_message
);
710 free((void *) lregions
), lregions
= 0;
715 * Select a random coordinate in the maze.
717 * We want a place not 'touched' by the loader. That is, a place in
718 * the maze outside every part of the special level.
723 register const char *s
;
727 s_level
*sp
= Is_special(&u
.uz
);
732 if(sp
&& sp
->rndlevs
) sprintf(protofile
, "%s-%d", s
,
733 rnd((int) sp
->rndlevs
));
734 else strcpy(protofile
, s
);
735 } else if(*(dungeons
[u
.uz
.dnum
].proto
)) {
736 if(dunlevs_in_dungeon(&u
.uz
) > 1) {
737 if(sp
&& sp
->rndlevs
)
738 sprintf(protofile
, "%s%d-%d", dungeons
[u
.uz
.dnum
].proto
,
740 rnd((int) sp
->rndlevs
));
741 else sprintf(protofile
, "%s%d", dungeons
[u
.uz
.dnum
].proto
,
743 } else if(sp
&& sp
->rndlevs
) {
744 sprintf(protofile
, "%s-%d", dungeons
[u
.uz
.dnum
].proto
,
745 rnd((int) sp
->rndlevs
));
746 } else strcpy(protofile
, dungeons
[u
.uz
.dnum
].proto
);
748 } else strcpy(protofile
, "");
751 /* SPLEVTYPE format is "level-choice,level-choice"... */
752 if (wizard
&& *protofile
&& sp
&& sp
->rndlevs
) {
753 char *ep
= getenv("SPLEVTYPE"); /* not nh_getenv */
755 /* rindex always succeeds due to code in prior block */
756 int len
= (rindex(protofile
, '-') - protofile
) + 1;
759 if (!strncmp(ep
, protofile
, len
)) {
760 int pick
= atoi(ep
+ len
);
761 /* use choice only if valid */
762 if (pick
> 0 && pick
<= (int) sp
->rndlevs
)
763 sprintf(protofile
+ len
, "%d", pick
);
775 strcat(protofile
, LEV_EXT
);
776 if(load_special(protofile
)) {
778 /* some levels can end up with monsters
779 on dead mon list, including light source monsters */
781 return; /* no mazification right now */
783 /* impossible("Couldn't load \"%s\" - making a maze.", protofile); */
784 if (strncmpi(protofile
, "makemase.lev", 13) && strncmpi(protofile
, "makemais.lev", 13) ) pline("Couldn't load \"%s\" - making a maze.", protofile
);
787 if (rn2(2)) level
.flags
.is_maze_lev
= TRUE
;
789 #ifndef WALLIFIED_MAZE
790 for(x
= 2; x
< x_maze_max
; x
++)
791 for(y
= 2; y
< y_maze_max
; y
++)
792 levl
[x
][y
].typ
= STONE
;
794 for(x
= 2; x
<= x_maze_max
; x
++)
795 for(y
= 2; y
<= y_maze_max
; y
++)
796 levl
[x
][y
].typ
= ((x
% 2) && (y
% 2)) ? STONE
: HWALL
;
800 walkfrom((int) mm
.x
, (int) mm
.y
);
801 /* put a boulder at the maze center */
802 (void) mksobj_at(BOULDER
, (int) mm
.x
, (int) mm
.y
, TRUE
, FALSE
, FALSE
);
804 #ifdef WALLIFIED_MAZE
805 wallification(2, 2, x_maze_max
, y_maze_max
, TRUE
);
808 mkstairs(mm
.x
, mm
.y
, 1, (struct mkroom
*)0); /* up */
809 if (!Invocation_lev(&u
.uz
)) {
811 mkstairs(mm
.x
, mm
.y
, 0, (struct mkroom
*)0); /* down */
812 } else { /* choose "vibrating square" location */
816 * Pick a position where the stairs down to Moloch's Sanctum
817 * level will ultimately be created. At that time, an area
818 * will be altered: walls removed, moat and traps generated,
819 * boulders destroyed. The position picked here must ensure
820 * that that invocation area won't extend off the map.
822 * We actually allow up to 2 squares around the usual edge of
823 * the area to get truncated; see mkinvokearea(mklev.c).
825 #define INVPOS_X_MARGIN (6 - 2)
826 #define INVPOS_Y_MARGIN (5 - 2)
827 #define INVPOS_DISTANCE 11
828 int x_range
= x_maze_max
- x_maze_min
- 2*INVPOS_X_MARGIN
- 1,
829 y_range
= y_maze_max
- y_maze_min
- 2*INVPOS_Y_MARGIN
- 1;
832 if (x_range
<= INVPOS_X_MARGIN
|| y_range
<= INVPOS_Y_MARGIN
||
833 (x_range
* y_range
) <= (INVPOS_DISTANCE
* INVPOS_DISTANCE
))
834 panic("inv_pos: maze is too small! (%d x %d)",
835 x_maze_max
, y_maze_max
);
837 inv_pos
.x
= inv_pos
.y
= 0; /*{occupied() => invocation_pos()}*/
839 x
= rn1(x_range
, x_maze_min
+ INVPOS_X_MARGIN
+ 1);
840 y
= rn1(y_range
, y_maze_min
+ INVPOS_Y_MARGIN
+ 1);
841 /* we don't want it to be too near the stairs, nor
842 to be on a spot that's already in use (wall|trap) */
843 } while (x
== xupstair
|| y
== yupstair
|| /*(direct line)*/
844 abs(x
- xupstair
) == abs(y
- yupstair
) ||
845 distmin(x
, y
, xupstair
, yupstair
) <= INVPOS_DISTANCE
||
846 !SPACE_POS(levl
[x
][y
].typ
) || occupied(x
, y
));
850 /* spice this boring maze up - seven deadly sins :D --Amy */
851 mtmp
= makemon(&mons
[PM_LUST
], 0, 0, NO_MM_FLAGS
);
852 if (mtmp
) (void) maketrap(mtmp
->mx
, mtmp
->my
, SIN_TRAP
, 0, FALSE
);
853 mtmp
= makemon(&mons
[PM_GLUTTONY
], 0, 0, NO_MM_FLAGS
);
854 if (mtmp
) (void) maketrap(mtmp
->mx
, mtmp
->my
, SIN_TRAP
, 0, FALSE
);
855 mtmp
= makemon(&mons
[PM_ENVY
], 0, 0, NO_MM_FLAGS
);
856 if (mtmp
) (void) maketrap(mtmp
->mx
, mtmp
->my
, SIN_TRAP
, 0, FALSE
);
857 mtmp
= makemon(&mons
[PM_PRIDE
], 0, 0, NO_MM_FLAGS
);
858 if (mtmp
) (void) maketrap(mtmp
->mx
, mtmp
->my
, SIN_TRAP
, 0, FALSE
);
859 mtmp
= makemon(&mons
[PM_GREED
], 0, 0, NO_MM_FLAGS
);
860 if (mtmp
) (void) maketrap(mtmp
->mx
, mtmp
->my
, SIN_TRAP
, 0, FALSE
);
861 mtmp
= makemon(&mons
[PM_SLOTH
], 0, 0, NO_MM_FLAGS
);
862 if (mtmp
) (void) maketrap(mtmp
->mx
, mtmp
->my
, SIN_TRAP
, 0, FALSE
);
863 mtmp
= makemon(&mons
[PM_WRATH
], 0, 0, NO_MM_FLAGS
);
864 if (mtmp
) (void) maketrap(mtmp
->mx
, mtmp
->my
, SIN_TRAP
, 0, FALSE
);
867 #undef INVPOS_X_MARGIN
868 #undef INVPOS_Y_MARGIN
869 #undef INVPOS_DISTANCE
874 /* place branch stair or portal */
875 place_branch(Is_branchlev(&u
.uz
), 0, 0);
878 for(x
= (rn2(4) ? rn1(12,24) : rn1(24, 48)); x
; x
--) {
880 for(x
= (rn2(4) ? rn1(8,16) : rn1(16, 32)); x
; x
--) {
882 if (timebasedlowerchance() || timebasedlowerchance() || timebasedlowerchance()) {
884 (void) mkobj_at(!rn2(25) ? GEM_CLASS
: 0, mm
.x
, mm
.y
, TRUE
, FALSE
);
888 if (moves
== 1) { /* some earlygame help... --Amy */
890 for(x
= (rn2(4) ? rn1(12,24) : rn1(24, 48)); x
; x
--) {
892 for(x
= (rn2(4) ? rn1(8,16) : rn1(16, 32)); x
; x
--) {
894 /* no timebasedlowerchance, this is not a mistake */
896 (void) mkobj_at(!rn2(25) ? GEM_CLASS
: 0, mm
.x
, mm
.y
, TRUE
, FALSE
);
900 /* full-screen mazes are capable of boring the player's ass off, so there should be at least some loot --Amy */
903 if (timebasedlowerchance()) {
905 (void) mksobj_at(LOOT_CHEST
, mm
.x
, mm
.y
, TRUE
, TRUE
, FALSE
);
909 if (timebasedlowerchance()) {
911 (void) mksobj_at(LOOT_CHEST
, mm
.x
, mm
.y
, TRUE
, TRUE
, FALSE
);
916 if (timebasedlowerchance()) {
918 (void) mksobj_at(LOOT_CHEST
, mm
.x
, mm
.y
, TRUE
, TRUE
, FALSE
);
923 for (x
= rn1(7,35); x
; x
--) {
925 for (x
= rn1(2,10); x
; x
--) {
929 const char *mesg
= random_engraving(buf
);
930 make_engr_at(mm
.x
, mm
.y
, mesg
, 0L, (xchar
)0);
932 for(x
= rn1(10,2); x
; x
--) {
934 (void) mksobj_at(BOULDER
, mm
.x
, mm
.y
, TRUE
, FALSE
, FALSE
);
936 if (!(iszapem
&& !(u
.zapemescape
)) && !(u
.preversionmode
&& !u
.preversionescape
) && (depth(&u
.uz
) > depth(&medusa_level
))) {
937 for (x
= rn2(3); x
; x
--) {
939 if (!ishomicider
) (void) makemon(minotaurvariant(), mm
.x
, mm
.y
, MM_MAYSLEEP
);
940 else makerandomtrap_at(mm
.x
, mm
.y
, TRUE
);
942 } /* cause they would be outta depth when mazes are generated at a shallow level --Amy */
944 for(x
= (rn2(2) ? rn1(70, 98) : rn2(4) ? rn1(18,24) : rn1(35, 49)); x
; x
--) {
946 for(x
= (rn2(2) ? rn1(20, 28) : rn2(4) ? rn1(5,7) : rn1(10, 14)); x
; x
--) {
949 if (!ishomicider
) (void) makemon((struct permonst
*) 0, mm
.x
, mm
.y
, MM_MAYSLEEP
);
950 else makerandomtrap_at(mm
.x
, mm
.y
, TRUE
);
952 for(x
= rn1(6,7); x
; x
--) {
954 (void) mkgold(0L,mm
.x
,mm
.y
);
957 for(x
= (!rn2(6) ? rn1(84, 98) : rn2(4) ? rn1(21,24) : rn1(42, 49)); x
; x
--) {
959 for(x
= (!rn2(6) ? rn1(24, 28) : rn2(4) ? rn1(6,7) : rn1(12, 14)); x
; x
--) {
961 if (!(depth(&u
.uz
) == 1 && In_dod(&u
.uz
) && rn2(3)) && !(depth(&u
.uz
) == 2 && In_dod(&u
.uz
) && rn2(2)) ) {
962 mktrap(0,1,(struct mkroom
*) 0, (coord
*) 0, TRUE
);
968 for(x
= (rn2(4) ? rn1(12,24) : rn1(24, 48)); x
; x
--) {
970 for(x
= (rn2(4) ? rn1(8,16) : rn1(16, 32)); x
; x
--) {
972 if (timebasedlowerchance() || timebasedlowerchance() || timebasedlowerchance()) {
974 (void) mkobj_at(!rn2(25) ? GEM_CLASS
: 0, mm
.x
, mm
.y
, TRUE
, FALSE
);
978 for (x
= rn1(7,35); x
; x
--) {
980 for (x
= rn1(2,10); x
; x
--) {
984 const char *mesg
= random_engraving(buf
);
985 make_engr_at(mm
.x
, mm
.y
, mesg
, 0L, (xchar
)0);
987 for(x
= rn1(10,2); x
; x
--) {
989 (void) mksobj_at(BOULDER
, mm
.x
, mm
.y
, TRUE
, FALSE
, FALSE
);
991 if (!(iszapem
&& !(u
.zapemescape
)) && !(u
.preversionmode
&& !u
.preversionescape
) && (depth(&u
.uz
) > depth(&medusa_level
))) {
992 for (x
= rn2(3); x
; x
--) {
994 if (!ishomicider
) (void) makemon(minotaurvariant(), mm
.x
, mm
.y
, MM_MAYSLEEP
);
995 else makerandomtrap_at(mm
.x
, mm
.y
, TRUE
);
997 } /* cause they would be outta depth when mazes are generated at a shallow level --Amy */
999 for(x
= (rn2(2) ? rn1(70, 98) : rn2(4) ? rn1(18,24) : rn1(35, 49)); x
; x
--) {
1001 for(x
= (rn2(2) ? rn1(20, 28) : rn2(4) ? rn1(5,7) : rn1(10, 14)); x
; x
--) {
1004 if (!ishomicider
) (void) makemon((struct permonst
*) 0, mm
.x
, mm
.y
, MM_MAYSLEEP
);
1005 else makerandomtrap_at(mm
.x
, mm
.y
, TRUE
);
1007 for(x
= rn1(6,7); x
; x
--) {
1009 (void) mkgold(0L,mm
.x
,mm
.y
);
1012 for(x
= (!rn2(6) ? rn1(84, 98) : rn2(4) ? rn1(21,24) : rn1(42, 49)); x
; x
--) {
1014 for(x
= (!rn2(6) ? rn1(24, 28) : rn2(4) ? rn1(6,7) : rn1(12, 14)); x
; x
--) {
1016 if (!(depth(&u
.uz
) == 1 && In_dod(&u
.uz
) && rn2(3)) && !(depth(&u
.uz
) == 2 && In_dod(&u
.uz
) && rn2(2)) ) {
1017 mktrap(0,1,(struct mkroom
*) 0, (coord
*) 0, TRUE
);
1024 /* chance to create Ludios portal, by Amy */
1025 if (In_dod(&u
.uz
)) {
1027 if (isok(mm
.x
, mm
.y
)) mk_knox_portal(mm
.x
, mm
.y
);
1033 /* Make the mazewalk iterative by faking a stack. This is needed to
1034 * ensure the mazewalk is successful in the limited stack space of
1035 * the program. This iterative version uses the minimum amount of stack
1036 * that is totally safe.
1042 #define CELLS (ROWNO * COLNO) / 4 /* a maze cell is 4 squares */
1043 char mazex
[CELLS
+ 1], mazey
[CELLS
+ 1]; /* char's are OK */
1047 register int tryct
= 0;
1048 register struct obj
*otmpX
;
1051 int specialcorridor
= 0;
1052 if (!rn2(iswarper
? 50 : 500)) specialcorridor
= rnd(2);
1055 mazex
[pos
] = (char) x
;
1056 mazey
[pos
] = (char) y
;
1058 x
= (int) mazex
[pos
];
1059 y
= (int) mazey
[pos
];
1060 if(!IS_DOOR(levl
[x
][y
].typ
) && !specialcorridor
) {
1061 /* might still be on edge of MAP, so don't overwrite */
1062 #ifndef WALLIFIED_MAZE
1063 levl
[x
][y
].typ
= CORR
;
1065 levl
[x
][y
].typ
= ROOM
;
1067 levl
[x
][y
].flags
= 0;
1069 if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1070 levl
[x
][y
].typ
= THRONE
;
1071 else if (!rn2(ishaxor
? 50000 : 100000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1072 levl
[x
][y
].typ
= PENTAGRAM
;
1073 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1074 levl
[x
][y
].typ
= WELL
;
1075 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1076 levl
[x
][y
].typ
= POISONEDWELL
;
1077 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1078 levl
[x
][y
].typ
= WAGON
;
1079 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1080 levl
[x
][y
].typ
= BURNINGWAGON
;
1081 else if (!rn2(ishaxor
? 20000 : 40000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1082 levl
[x
][y
].typ
= WOODENTABLE
;
1083 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1084 levl
[x
][y
].typ
= CARVEDBED
;
1085 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1086 levl
[x
][y
].typ
= STRAWMATTRESS
;
1087 else if (!rn2(ishaxor
? 2500 : 5000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))) {
1088 levl
[x
][y
].typ
= FOUNTAIN
;
1089 level
.flags
.nfountains
++;
1091 else if (!rn2(ishaxor
? 2500 : 5000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))) {
1092 levl
[x
][y
].typ
= SINK
;
1093 level
.flags
.nsinks
++;
1095 else if (!rn2(ishaxor
? 5000 : 10000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1096 levl
[x
][y
].typ
= TOILET
;
1097 else if (!rn2(ishaxor
? 1000 : 2000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))) {
1098 levl
[x
][y
].typ
= GRAVE
;
1099 str
= random_epitaph();
1101 make_engr_at(x
, y
, str
, 0L, HEADSTONE
);
1103 if (!rn2(3)) (void) mkgold(0L, x
, y
);
1104 for (tryct
= rn2(5); tryct
; tryct
--) {
1105 if (timebasedlowerchance()) {
1106 otmpX
= mkobj(RANDOM_CLASS
, TRUE
, FALSE
);
1111 add_to_buried(otmpX
);
1115 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))) {
1116 levl
[x
][y
].typ
= ALTAR
;
1117 if (rn2(10)) levl
[x
][y
].altarmask
= Align2amask( A_NONE
);
1118 else switch (rnd(3)) {
1119 case 1: levl
[x
][y
].altarmask
= Align2amask( A_LAWFUL
); break;
1120 case 2: levl
[x
][y
].altarmask
= Align2amask( A_NEUTRAL
); break;
1121 case 3: levl
[x
][y
].altarmask
= Align2amask( A_CHAOTIC
); break;
1125 register struct obj
*altarwater
;
1126 altarwater
= mksobj_at(POT_WATER
, x
, y
, FALSE
, FALSE
, FALSE
);
1128 if (Amask2align(levl
[x
][y
].altarmask
) == A_NONE
&& !rn2(5)) curse(altarwater
);
1129 else bless(altarwater
);
1134 else if (!rn2(ishaxor
? 1000 : 2000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1135 levl
[x
][y
].typ
= TREE
;
1136 else if (!rn2(ishaxor
? 1000 : 2000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1137 levl
[x
][y
].typ
= MOAT
;
1138 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1139 levl
[x
][y
].typ
= LAVAPOOL
;
1140 else if (!rn2(ishaxor
? 500 : 1000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1141 levl
[x
][y
].typ
= ICE
;
1142 else if (!rn2(ishaxor
? 500 : 1000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1143 levl
[x
][y
].typ
= CLOUD
;
1144 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1145 levl
[x
][y
].typ
= GRAVEWALL
;
1146 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1147 levl
[x
][y
].typ
= SNOW
;
1148 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1149 levl
[x
][y
].typ
= ASH
;
1150 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1151 levl
[x
][y
].typ
= SAND
;
1152 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1153 levl
[x
][y
].typ
= PAVEDFLOOR
;
1154 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1155 levl
[x
][y
].typ
= HIGHWAY
;
1156 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1157 levl
[x
][y
].typ
= GRASSLAND
;
1158 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1159 levl
[x
][y
].typ
= NETHERMIST
;
1160 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1161 levl
[x
][y
].typ
= STALACTITE
;
1162 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1163 levl
[x
][y
].typ
= CRYPTFLOOR
;
1164 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1165 levl
[x
][y
].typ
= BUBBLES
;
1166 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1167 levl
[x
][y
].typ
= RAINCLOUD
;
1168 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1169 levl
[x
][y
].typ
= TUNNELWALL
;
1170 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1171 levl
[x
][y
].typ
= FARMLAND
;
1172 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1173 levl
[x
][y
].typ
= MOUNTAIN
;
1174 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1175 levl
[x
][y
].typ
= WATERTUNNEL
;
1176 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1177 levl
[x
][y
].typ
= CRYSTALWATER
;
1178 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1179 levl
[x
][y
].typ
= MOORLAND
;
1180 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1181 levl
[x
][y
].typ
= URINELAKE
;
1182 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1183 levl
[x
][y
].typ
= SHIFTINGSAND
;
1184 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1185 levl
[x
][y
].typ
= STYXRIVER
;
1188 if(!IS_DOOR(levl
[x
][y
].typ
) && specialcorridor
) {
1190 levl
[x
][y
].typ
= walkableterrain();
1191 levl
[x
][y
].flags
= 0;
1195 for (a
= 0; a
< 4; a
++)
1196 if(okay(x
, y
, a
)) dirs
[q
++]= a
;
1203 if (!specialcorridor
) {
1204 #ifndef WALLIFIED_MAZE
1205 levl
[x
][y
].typ
= CORR
;
1207 levl
[x
][y
].typ
= ROOM
;
1210 if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1211 levl
[x
][y
].typ
= THRONE
;
1212 else if (!rn2(ishaxor
? 50000 : 100000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1213 levl
[x
][y
].typ
= PENTAGRAM
;
1214 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1215 levl
[x
][y
].typ
= WELL
;
1216 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1217 levl
[x
][y
].typ
= POISONEDWELL
;
1218 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1219 levl
[x
][y
].typ
= WAGON
;
1220 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1221 levl
[x
][y
].typ
= BURNINGWAGON
;
1222 else if (!rn2(ishaxor
? 20000 : 40000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1223 levl
[x
][y
].typ
= WOODENTABLE
;
1224 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1225 levl
[x
][y
].typ
= CARVEDBED
;
1226 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1227 levl
[x
][y
].typ
= STRAWMATTRESS
;
1228 else if (!rn2(ishaxor
? 2500 : 5000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))){
1229 levl
[x
][y
].typ
= FOUNTAIN
;
1230 level
.flags
.nfountains
++;
1232 else if (!rn2(ishaxor
? 2500 : 5000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))) {
1233 levl
[x
][y
].typ
= SINK
;
1234 level
.flags
.nsinks
++;
1236 else if (!rn2(ishaxor
? 5000 : 10000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1237 levl
[x
][y
].typ
= TOILET
;
1238 else if (!rn2(ishaxor
? 1000 : 2000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))) {
1239 levl
[x
][y
].typ
= GRAVE
;
1240 str
= random_epitaph();
1242 make_engr_at(x
, y
, str
, 0L, HEADSTONE
);
1244 if (!rn2(3)) (void) mkgold(0L, x
, y
);
1245 for (tryct
= rn2(5); tryct
; tryct
--) {
1246 if (timebasedlowerchance()) {
1247 otmpX
= mkobj(RANDOM_CLASS
, TRUE
, FALSE
);
1252 add_to_buried(otmpX
);
1256 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))) {
1257 levl
[x
][y
].typ
= ALTAR
;
1258 if (rn2(10)) levl
[x
][y
].altarmask
= Align2amask( A_NONE
);
1259 else switch (rnd(3)) {
1260 case 1: levl
[x
][y
].altarmask
= Align2amask( A_LAWFUL
); break;
1261 case 2: levl
[x
][y
].altarmask
= Align2amask( A_NEUTRAL
); break;
1262 case 3: levl
[x
][y
].altarmask
= Align2amask( A_CHAOTIC
); break;
1266 register struct obj
*altarwater
;
1267 altarwater
= mksobj_at(POT_WATER
, x
, y
, FALSE
, FALSE
, FALSE
);
1269 if (Amask2align(levl
[x
][y
].altarmask
) == A_NONE
&& !rn2(5)) curse(altarwater
);
1270 else bless(altarwater
);
1275 else if (!rn2(ishaxor
? 1000 : 2000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1276 levl
[x
][y
].typ
= TREE
;
1277 else if (!rn2(ishaxor
? 1000 : 2000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1278 levl
[x
][y
].typ
= MOAT
;
1279 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1280 levl
[x
][y
].typ
= LAVAPOOL
;
1281 else if (!rn2(ishaxor
? 500 : 1000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1282 levl
[x
][y
].typ
= ICE
;
1283 else if (!rn2(ishaxor
? 500 : 1000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1284 levl
[x
][y
].typ
= CLOUD
;
1285 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1286 levl
[x
][y
].typ
= GRAVEWALL
;
1287 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1288 levl
[x
][y
].typ
= SNOW
;
1289 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1290 levl
[x
][y
].typ
= ASH
;
1291 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1292 levl
[x
][y
].typ
= SAND
;
1293 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1294 levl
[x
][y
].typ
= PAVEDFLOOR
;
1295 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1296 levl
[x
][y
].typ
= HIGHWAY
;
1297 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1298 levl
[x
][y
].typ
= GRASSLAND
;
1299 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1300 levl
[x
][y
].typ
= NETHERMIST
;
1301 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1302 levl
[x
][y
].typ
= STALACTITE
;
1303 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1304 levl
[x
][y
].typ
= CRYPTFLOOR
;
1305 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1306 levl
[x
][y
].typ
= BUBBLES
;
1307 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1308 levl
[x
][y
].typ
= RAINCLOUD
;
1309 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1310 levl
[x
][y
].typ
= TUNNELWALL
;
1311 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1312 levl
[x
][y
].typ
= FARMLAND
;
1313 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1314 levl
[x
][y
].typ
= MOUNTAIN
;
1315 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1316 levl
[x
][y
].typ
= WATERTUNNEL
;
1317 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1318 levl
[x
][y
].typ
= CRYSTALWATER
;
1319 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1320 levl
[x
][y
].typ
= MOORLAND
;
1321 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1322 levl
[x
][y
].typ
= URINELAKE
;
1323 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1324 levl
[x
][y
].typ
= SHIFTINGSAND
;
1325 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1326 levl
[x
][y
].typ
= STYXRIVER
;
1329 else levl
[x
][y
].typ
= walkableterrain();
1334 panic("Overflow in walkfrom");
1335 mazex
[pos
] = (char) x
;
1336 mazey
[pos
] = (char) y
;
1346 register int q
,a
,dir
;
1349 register int tryct
= 0;
1350 register struct obj
*otmpX
;
1353 int specialcorridor
= 0;
1354 if (!rn2(iswarper
? 50 : 500)) specialcorridor
= rnd(2);
1356 if(!IS_DOOR(levl
[x
][y
].typ
) && !specialcorridor
) {
1357 /* might still be on edge of MAP, so don't overwrite */
1358 #ifndef WALLIFIED_MAZE
1359 levl
[x
][y
].typ
= CORR
;
1361 levl
[x
][y
].typ
= ROOM
;
1363 levl
[x
][y
].flags
= 0;
1365 if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1366 levl
[x
][y
].typ
= THRONE
;
1367 else if (!rn2(ishaxor
? 50000 : 100000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1368 levl
[x
][y
].typ
= PENTAGRAM
;
1369 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1370 levl
[x
][y
].typ
= WELL
;
1371 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1372 levl
[x
][y
].typ
= POISONEDWELL
;
1373 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1374 levl
[x
][y
].typ
= WAGON
;
1375 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1376 levl
[x
][y
].typ
= BURNINGWAGON
;
1377 else if (!rn2(ishaxor
? 20000 : 40000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1378 levl
[x
][y
].typ
= WOODENTABLE
;
1379 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1380 levl
[x
][y
].typ
= CARVEDBED
;
1381 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1382 levl
[x
][y
].typ
= STRAWMATTRESS
;
1383 else if (!rn2(ishaxor
? 2500 : 5000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))) {
1384 levl
[x
][y
].typ
= FOUNTAIN
;
1385 level
.flags
.nfountains
++;
1387 else if (!rn2(ishaxor
? 2500 : 5000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))) {
1388 levl
[x
][y
].typ
= SINK
;
1389 level
.flags
.nsinks
++;
1391 else if (!rn2(ishaxor
? 5000 : 10000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1392 levl
[x
][y
].typ
= TOILET
;
1393 else if (!rn2(ishaxor
? 1000 : 2000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))) {
1394 levl
[x
][y
].typ
= GRAVE
;
1395 str
= random_epitaph();
1397 make_engr_at(x
, y
, str
, 0L, HEADSTONE
);
1399 if (!rn2(3)) (void) mkgold(0L, x
, y
);
1400 for (tryct
= rn2(5); tryct
; tryct
--) {
1401 if (timebasedlowerchance()) {
1402 otmpX
= mkobj(RANDOM_CLASS
, TRUE
, FALSE
);
1407 add_to_buried(otmpX
);
1411 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))) {
1412 levl
[x
][y
].typ
= ALTAR
;
1413 if (rn2(10)) levl
[x
][y
].altarmask
= Align2amask( A_NONE
);
1414 else switch (rnd(3)) {
1415 case 1: levl
[x
][y
].altarmask
= Align2amask( A_LAWFUL
); break;
1416 case 2: levl
[x
][y
].altarmask
= Align2amask( A_NEUTRAL
); break;
1417 case 3: levl
[x
][y
].altarmask
= Align2amask( A_CHAOTIC
); break;
1421 register struct obj
*altarwater
;
1422 altarwater
= mksobj_at(POT_WATER
, x
, y
, FALSE
, FALSE
, FALSE
);
1424 if (Amask2align(levl
[x
][y
].altarmask
) == A_NONE
&& !rn2(5)) curse(altarwater
);
1425 else bless(altarwater
);
1430 else if (!rn2(ishaxor
? 1000 : 2000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1431 levl
[x
][y
].typ
= TREE
;
1432 else if (!rn2(ishaxor
? 1000 : 2000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1433 levl
[x
][y
].typ
= MOAT
;
1434 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1435 levl
[x
][y
].typ
= LAVAPOOL
;
1436 else if (!rn2(ishaxor
? 500 : 1000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1437 levl
[x
][y
].typ
= ICE
;
1438 else if (!rn2(ishaxor
? 500 : 1000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1439 levl
[x
][y
].typ
= CLOUD
;
1440 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1441 levl
[x
][y
].typ
= GRAVEWALL
;
1442 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1443 levl
[x
][y
].typ
= SNOW
;
1444 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1445 levl
[x
][y
].typ
= ASH
;
1446 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1447 levl
[x
][y
].typ
= SAND
;
1448 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1449 levl
[x
][y
].typ
= PAVEDFLOOR
;
1450 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1451 levl
[x
][y
].typ
= HIGHWAY
;
1452 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1453 levl
[x
][y
].typ
= GRASSLAND
;
1454 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1455 levl
[x
][y
].typ
= NETHERMIST
;
1456 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1457 levl
[x
][y
].typ
= STALACTITE
;
1458 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1459 levl
[x
][y
].typ
= CRYPTFLOOR
;
1460 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1461 levl
[x
][y
].typ
= BUBBLES
;
1462 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1463 levl
[x
][y
].typ
= RAINCLOUD
;
1464 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1465 levl
[x
][y
].typ
= TUNNELWALL
;
1466 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1467 levl
[x
][y
].typ
= FARMLAND
;
1468 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1469 levl
[x
][y
].typ
= MOUNTAIN
;
1470 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1471 levl
[x
][y
].typ
= WATERTUNNEL
;
1472 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1473 levl
[x
][y
].typ
= CRYSTALWATER
;
1474 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1475 levl
[x
][y
].typ
= MOORLAND
;
1476 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1477 levl
[x
][y
].typ
= URINELAKE
;
1478 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1479 levl
[x
][y
].typ
= SHIFTINGSAND
;
1480 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1481 levl
[x
][y
].typ
= STYXRIVER
;
1484 if(!IS_DOOR(levl
[x
][y
].typ
) && specialcorridor
) {
1486 levl
[x
][y
].typ
= walkableterrain();
1487 levl
[x
][y
].flags
= 0;
1492 for(a
= 0; a
< 4; a
++)
1493 if(okay(x
,y
,a
)) dirs
[q
++]= a
;
1497 if (!specialcorridor
) {
1498 #ifndef WALLIFIED_MAZE
1499 levl
[x
][y
].typ
= CORR
;
1501 levl
[x
][y
].typ
= ROOM
;
1503 if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1504 levl
[x
][y
].typ
= THRONE
;
1505 else if (!rn2(ishaxor
? 50000 : 100000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1506 levl
[x
][y
].typ
= PENTAGRAM
;
1507 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1508 levl
[x
][y
].typ
= WELL
;
1509 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1510 levl
[x
][y
].typ
= POISONEDWELL
;
1511 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1512 levl
[x
][y
].typ
= WAGON
;
1513 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1514 levl
[x
][y
].typ
= BURNINGWAGON
;
1515 else if (!rn2(ishaxor
? 20000 : 40000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1516 levl
[x
][y
].typ
= WOODENTABLE
;
1517 else if (!rn2(ishaxor
? 25000 : 50000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1518 levl
[x
][y
].typ
= CARVEDBED
;
1519 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1520 levl
[x
][y
].typ
= STRAWMATTRESS
;
1521 else if (!rn2(ishaxor
? 2500 : 5000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))) {
1522 levl
[x
][y
].typ
= FOUNTAIN
;
1523 level
.flags
.nfountains
++;
1525 else if (!rn2(ishaxor
? 2500 : 5000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))) {
1526 levl
[x
][y
].typ
= SINK
;
1527 level
.flags
.nsinks
++;
1529 else if (!rn2(ishaxor
? 5000 : 10000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1530 levl
[x
][y
].typ
= TOILET
;
1531 else if (!rn2(ishaxor
? 1000 : 2000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))) {
1532 levl
[x
][y
].typ
= GRAVE
;
1533 str
= random_epitaph();
1535 make_engr_at(x
, y
, str
, 0L, HEADSTONE
);
1537 if (!rn2(3)) (void) mkgold(0L, x
, y
);
1538 for (tryct
= rn2(5); tryct
; tryct
--) {
1539 if (timebasedlowerchance()) {
1540 otmpX
= mkobj(RANDOM_CLASS
, TRUE
, FALSE
);
1545 add_to_buried(otmpX
);
1549 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
))) {
1550 levl
[x
][y
].typ
= ALTAR
;
1551 if (rn2(10)) levl
[x
][y
].altarmask
= Align2amask( A_NONE
);
1552 else switch (rnd(3)) {
1553 case 1: levl
[x
][y
].altarmask
= Align2amask( A_LAWFUL
); break;
1554 case 2: levl
[x
][y
].altarmask
= Align2amask( A_NEUTRAL
); break;
1555 case 3: levl
[x
][y
].altarmask
= Align2amask( A_CHAOTIC
); break;
1559 register struct obj
*altarwater
;
1560 altarwater
= mksobj_at(POT_WATER
, x
, y
, FALSE
, FALSE
, FALSE
);
1562 if (Amask2align(levl
[x
][y
].altarmask
) == A_NONE
&& !rn2(5)) curse(altarwater
);
1563 else bless(altarwater
);
1568 else if (!rn2(ishaxor
? 1000 : 2000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1569 levl
[x
][y
].typ
= TREE
;
1570 else if (!rn2(ishaxor
? 1000 : 2000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1571 levl
[x
][y
].typ
= MOAT
;
1572 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1573 levl
[x
][y
].typ
= LAVAPOOL
;
1574 else if (!rn2(ishaxor
? 500 : 1000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1575 levl
[x
][y
].typ
= ICE
;
1576 else if (!rn2(ishaxor
? 500 : 1000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1577 levl
[x
][y
].typ
= CLOUD
;
1578 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1579 levl
[x
][y
].typ
= GRAVEWALL
;
1580 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1581 levl
[x
][y
].typ
= SNOW
;
1582 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1583 levl
[x
][y
].typ
= ASH
;
1584 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1585 levl
[x
][y
].typ
= SAND
;
1586 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1587 levl
[x
][y
].typ
= PAVEDFLOOR
;
1588 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1589 levl
[x
][y
].typ
= HIGHWAY
;
1590 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1591 levl
[x
][y
].typ
= GRASSLAND
;
1592 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1593 levl
[x
][y
].typ
= NETHERMIST
;
1594 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1595 levl
[x
][y
].typ
= STALACTITE
;
1596 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1597 levl
[x
][y
].typ
= CRYPTFLOOR
;
1598 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1599 levl
[x
][y
].typ
= BUBBLES
;
1600 else if (!rn2(ishaxor
? 2000 : 4000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1601 levl
[x
][y
].typ
= RAINCLOUD
;
1602 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1603 levl
[x
][y
].typ
= TUNNELWALL
;
1604 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1605 levl
[x
][y
].typ
= FARMLAND
;
1606 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1607 levl
[x
][y
].typ
= MOUNTAIN
;
1608 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1609 levl
[x
][y
].typ
= WATERTUNNEL
;
1610 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1611 levl
[x
][y
].typ
= CRYSTALWATER
;
1612 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1613 levl
[x
][y
].typ
= MOORLAND
;
1614 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1615 levl
[x
][y
].typ
= URINELAKE
;
1616 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1617 levl
[x
][y
].typ
= SHIFTINGSAND
;
1618 else if (!rn2(ishaxor
? 10000 : 20000) && ((levl
[x
][y
].typ
== CORR
) || (levl
[x
][y
].typ
== ROOM
)))
1619 levl
[x
][y
].typ
= STYXRIVER
;
1622 else levl
[x
][y
].typ
= walkableterrain();
1631 register int *x
, *y
;
1635 case 0: --(*y
); break;
1636 case 1: (*x
)++; break;
1637 case 2: (*y
)++; break;
1638 case 3: --(*x
); break;
1639 default: panic("move: bad direction");
1644 mazexy(cc
) /* find random point in generated corridors,
1645 so we don't create items in moats, bunkers, or walls */
1651 cc
->x
= 3 + 2*rn2((x_maze_max
>>1) - 1);
1652 cc
->y
= 3 + 2*rn2((y_maze_max
>>1) - 1);
1654 } while (cpt
< 100 && levl
[cc
->x
][cc
->y
].typ
!=
1655 #ifdef WALLIFIED_MAZE
1664 for (x
= 0; x
< (x_maze_max
>>1) - 1; x
++)
1665 for (y
= 0; y
< (y_maze_max
>>1) - 1; y
++) {
1668 if (levl
[cc
->x
][cc
->y
].typ
==
1669 #ifdef WALLIFIED_MAZE
1677 for (x
= 0; x
< (x_maze_max
>>1) - 1; x
++)
1678 for (y
= 0; y
< (y_maze_max
>>1) - 1; y
++) {
1681 if ((levl
[cc
->x
][cc
->y
].typ
== ROOM
) || (levl
[cc
->x
][cc
->y
].typ
== CORR
) || (levl
[cc
->x
][cc
->y
].typ
== CLOUD
) || (levl
[cc
->x
][cc
->y
].typ
== ICE
) || (levl
[cc
->x
][cc
->y
].typ
== SNOW
) || (levl
[cc
->x
][cc
->y
].typ
== ASH
) || (levl
[cc
->x
][cc
->y
].typ
== SAND
) || (levl
[cc
->x
][cc
->y
].typ
== PAVEDFLOOR
) || (levl
[cc
->x
][cc
->y
].typ
== HIGHWAY
) || (levl
[cc
->x
][cc
->y
].typ
== GRASSLAND
) || (levl
[cc
->x
][cc
->y
].typ
== NETHERMIST
) || (levl
[cc
->x
][cc
->y
].typ
== STALACTITE
) || (levl
[cc
->x
][cc
->y
].typ
== CRYPTFLOOR
) || (levl
[cc
->x
][cc
->y
].typ
== BUBBLES
) || (levl
[cc
->x
][cc
->y
].typ
== RAINCLOUD
)) return;
1684 for (x
= 0; x
< (x_maze_max
) - 1; x
++)
1685 for (y
= 0; y
< (y_maze_max
) - 1; y
++) {
1688 if ((levl
[cc
->x
][cc
->y
].typ
>= ROCKWALL
&& levl
[cc
->x
][cc
->y
].typ
<= URINELAKE
) || (levl
[cc
->x
][cc
->y
].typ
>= SHIFTINGSAND
&& levl
[cc
->x
][cc
->y
].typ
<= ROOM
) || (levl
[cc
->x
][cc
->y
].typ
>= ICE
&& levl
[cc
->x
][cc
->y
].typ
<= CRYPTFLOOR
) || (levl
[cc
->x
][cc
->y
].typ
>= AIR
&& levl
[cc
->x
][cc
->y
].typ
<= RAINCLOUD
) ) return;
1691 panic("mazexy: can't find a place!");
1697 mazexy_all(cc
) /* mazexy() only returns "even-numbered" squares... --Amy */
1703 cc
->x
= 3 + rn2((x_maze_max
) - 1);
1704 cc
->y
= 3 + rn2((y_maze_max
) - 1);
1706 } while (cpt
< 100 && levl
[cc
->x
][cc
->y
].typ
!=
1707 #ifdef WALLIFIED_MAZE
1716 for (x
= 0; x
< (x_maze_max
) - 1; x
++)
1717 for (y
= 0; y
< (y_maze_max
) - 1; y
++) {
1720 if (levl
[cc
->x
][cc
->y
].typ
==
1721 #ifdef WALLIFIED_MAZE
1729 for (x
= 0; x
< (x_maze_max
) - 1; x
++)
1730 for (y
= 0; y
< (y_maze_max
) - 1; y
++) {
1733 if ((levl
[cc
->x
][cc
->y
].typ
== ROOM
) || (levl
[cc
->x
][cc
->y
].typ
== CORR
) || (levl
[cc
->x
][cc
->y
].typ
== CLOUD
) || (levl
[cc
->x
][cc
->y
].typ
== ICE
) || (levl
[cc
->x
][cc
->y
].typ
== SNOW
) || (levl
[cc
->x
][cc
->y
].typ
== ASH
) || (levl
[cc
->x
][cc
->y
].typ
== SAND
) || (levl
[cc
->x
][cc
->y
].typ
== PAVEDFLOOR
) || (levl
[cc
->x
][cc
->y
].typ
== HIGHWAY
) || (levl
[cc
->x
][cc
->y
].typ
== GRASSLAND
) || (levl
[cc
->x
][cc
->y
].typ
== NETHERMIST
) || (levl
[cc
->x
][cc
->y
].typ
== STALACTITE
) || (levl
[cc
->x
][cc
->y
].typ
== CRYPTFLOOR
) || (levl
[cc
->x
][cc
->y
].typ
== BUBBLES
) || (levl
[cc
->x
][cc
->y
].typ
== RAINCLOUD
)) return;
1736 for (x
= 0; x
< (x_maze_max
) - 1; x
++)
1737 for (y
= 0; y
< (y_maze_max
) - 1; y
++) {
1740 if ((levl
[cc
->x
][cc
->y
].typ
>= ROCKWALL
&& levl
[cc
->x
][cc
->y
].typ
<= URINELAKE
) || (levl
[cc
->x
][cc
->y
].typ
>= SHIFTINGSAND
&& levl
[cc
->x
][cc
->y
].typ
<= ROOM
) || (levl
[cc
->x
][cc
->y
].typ
>= ICE
&& levl
[cc
->x
][cc
->y
].typ
<= CRYPTFLOOR
) || (levl
[cc
->x
][cc
->y
].typ
>= AIR
&& levl
[cc
->x
][cc
->y
].typ
<= RAINCLOUD
) ) return;
1743 panic("mazexy_all: can't find a place!");
1750 /* put a non-diggable boundary around the initial portion of a level map.
1751 * assumes that no level will initially put things beyond the isok() range.
1753 * we can't bound unconditionally on the last line with something in it,
1754 * because that something might be a niche which was already reachable,
1755 * so the boundary would be breached
1757 * we can't bound unconditionally on one beyond the last line, because
1758 * that provides a window of abuse for WALLIFIED_MAZE special levels
1762 register int quasarchance
;
1763 register unsigned typ
;
1764 register struct rm
*lev
;
1765 boolean found
, nonwall
;
1766 int xmin
,xmax
,ymin
,ymax
;
1768 quasarchance
= 3 + rn2(5);
1770 for (x
= 0; x
< COLNO
; x
++)
1771 for (y
= 0; y
< ROWNO
; y
++) {
1772 if (!rn2(quasarchance
)) levl
[x
][y
].wall_info
|= W_QUASAROK
;
1773 levl
[x
][y
].nofunwall
= rn2(43);
1776 if(Is_earthlevel(&u
.uz
)) return; /* everything diggable here */
1778 found
= nonwall
= FALSE
;
1779 for(xmin
=0; !found
; xmin
++) {
1780 lev
= &levl
[xmin
][0];
1781 for(y
=0; y
<=ROWNO
-1; y
++, lev
++) {
1785 if(!IS_WALL(typ
)) nonwall
= TRUE
;
1789 xmin
-= (nonwall
|| !level
.flags
.is_maze_lev
) ? 2 : 1;
1790 if (xmin
< 0) xmin
= 0;
1792 found
= nonwall
= FALSE
;
1793 for(xmax
=COLNO
-1; !found
; xmax
--) {
1794 lev
= &levl
[xmax
][0];
1795 for(y
=0; y
<=ROWNO
-1; y
++, lev
++) {
1799 if(!IS_WALL(typ
)) nonwall
= TRUE
;
1803 xmax
+= (nonwall
|| !level
.flags
.is_maze_lev
) ? 2 : 1;
1804 if (xmax
>= COLNO
) xmax
= COLNO
-1;
1806 found
= nonwall
= FALSE
;
1807 for(ymin
=0; !found
; ymin
++) {
1808 lev
= &levl
[xmin
][ymin
];
1809 for(x
=xmin
; x
<=xmax
; x
++, lev
+= ROWNO
) {
1813 if(!IS_WALL(typ
)) nonwall
= TRUE
;
1817 ymin
-= (nonwall
|| !level
.flags
.is_maze_lev
) ? 2 : 1;
1819 found
= nonwall
= FALSE
;
1820 for(ymax
=ROWNO
-1; !found
; ymax
--) {
1821 lev
= &levl
[xmin
][ymax
];
1822 for(x
=xmin
; x
<=xmax
; x
++, lev
+= ROWNO
) {
1826 if(!IS_WALL(typ
)) nonwall
= TRUE
;
1830 ymax
+= (nonwall
|| !level
.flags
.is_maze_lev
) ? 2 : 1;
1832 for (x
= 0; x
< COLNO
; x
++)
1833 for (y
= 0; y
< ROWNO
; y
++)
1834 if (y
<= ymin
|| y
>= ymax
|| x
<= xmin
|| x
>= xmax
) {
1837 lev
->wall_info
|= W_NONDIGGABLE
;
1839 levl
[x
][y
].wall_info
|= W_NONDIGGABLE
;
1845 mkportal(x
, y
, todnum
, todlevel
)
1846 register xchar x
, y
, todnum
, todlevel
;
1848 /* a portal "trap" must be matched by a */
1849 /* portal in the destination dungeon/dlevel */
1850 register struct trap
*ttmp
= maketrap(x
, y
, MAGIC_PORTAL
, 0, FALSE
);
1853 impossible("portal on top of portal??");
1857 pline("mkportal: at (%d,%d), to %s, level %d",
1858 x
, y
, dungeons
[todnum
].dname
, todlevel
);
1860 ttmp
->dst
.dnum
= todnum
;
1861 ttmp
->dst
.dlevel
= todlevel
;
1866 * Special waterlevel stuff in endgame (TH).
1868 * Some of these functions would probably logically belong to some
1869 * other source files, but they are all so nicely encapsulated here.
1872 /* to ease the work of debuggers at this stage */
1880 static struct bubble
*bbubbles
, *ebubbles
;
1882 static struct trap
*wportal
;
1883 static int xmin
, ymin
, xmax
, ymax
; /* level boundaries */
1884 /* bubble movement boundaries */
1885 #define bxmin (xmin + 1)
1886 #define bymin (ymin + 1)
1887 #define bxmax (xmax - 1)
1888 #define bymax (ymax - 1)
1890 STATIC_DCL
void set_wportal(void);
1891 STATIC_DCL
void mk_bubble(int,int,int);
1892 STATIC_DCL
void mv_bubble(struct bubble
*,int,int,BOOLEAN_P
);
1898 register struct bubble
*b
;
1899 register int x
, y
, i
, j
;
1901 static const struct rm water_pos
=
1902 #ifdef DISPLAY_LAYERS
1903 { S_water
, 0, 0, 0, 0, 0,
1905 { cmap_to_glyph(S_water
),
1907 WATER
, 0, 0, 0, 0, 0, 0, 0 };
1909 /* set up the portal the first time bubbles are moved */
1910 if (!wportal
) set_wportal();
1913 /* fix from 3.4.3: keep attached ball&chain separate from bubble objects, otherwise panic! */
1914 if (Punished
) unplacebc();
1917 * Pick up everything inside of a bubble then fill all bubble
1921 for (b
= up
? bbubbles
: ebubbles
; b
; b
= up
? b
->next
: b
->prev
) {
1922 if (b
->cons
) panic("movebubbles: cons != null");
1923 for (i
= 0, x
= b
->x
; i
< (int) b
->bm
[0]; i
++, x
++)
1924 for (j
= 0, y
= b
->y
; j
< (int) b
->bm
[1]; j
++, y
++)
1925 if (b
->bm
[j
+ 2] & (1 << i
)) {
1927 impossible("movebubbles: bad pos (%d,%d)", x
,y
);
1931 /* pick up objects, monsters, hero, and traps */
1933 struct obj
*olist
= (struct obj
*) 0, *otmp
;
1934 struct container
*cons
= (struct container
*)
1935 alloc(sizeof(struct container
));
1937 while ((otmp
= level
.objects
[x
][y
]) != 0) {
1938 remove_object(otmp
);
1939 otmp
->ox
= otmp
->oy
= 0;
1940 otmp
->nexthere
= olist
;
1946 cons
->what
= CONS_OBJ
;
1947 cons
->list
= (void *) olist
;
1948 cons
->next
= b
->cons
;
1952 struct monst
*mon
= m_at(x
,y
);
1953 struct container
*cons
= (struct container
*)
1954 alloc(sizeof(struct container
));
1958 cons
->what
= CONS_MON
;
1959 cons
->list
= (void *) mon
;
1961 cons
->next
= b
->cons
;
1967 remove_monster(x
, y
);
1969 newsym(x
,y
); /* clean up old position */
1970 mon
->mx
= mon
->my
= 0;
1972 if (!u
.uswallow
&& x
== u
.ux
&& y
== u
.uy
) {
1973 struct container
*cons
= (struct container
*)
1974 alloc(sizeof(struct container
));
1978 cons
->what
= CONS_HERO
;
1979 cons
->list
= (void *) 0;
1981 cons
->next
= b
->cons
;
1984 if ((btrap
= t_at(x
,y
)) != 0) {
1985 struct container
*cons
= (struct container
*)
1986 alloc(sizeof(struct container
));
1990 cons
->what
= CONS_TRAP
;
1991 cons
->list
= (void *) btrap
;
1993 cons
->next
= b
->cons
;
1997 levl
[x
][y
] = water_pos
;
2003 * Every second time traverse down. This is because otherwise
2004 * all the junk that changes owners when bubbles overlap
2005 * would eventually end up in the last bubble in the chain.
2009 for (b
= up
? bbubbles
: ebubbles
; b
; b
= up
? b
->next
: b
->prev
) {
2010 register int rx
= rn2(3), ry
= rn2(3);
2012 mv_bubble(b
,b
->dx
+ 1 - (!b
->dx
? rx
: (rx
? 1 : 0)),
2013 b
->dy
+ 1 - (!b
->dy
? ry
: (ry
? 1 : 0)),
2017 /* put attached ball&chain back */
2018 if (Punished
) placebc();
2019 vision_full_recalc
= 1;
2022 /* when moving in water, possibly (1 in 3) alter the intended destination */
2026 register int x
, y
, dx
, dy
;
2027 register boolean eff
= FALSE
;
2029 if (Race_if(PM_SEA_ELF
)) return; /* idea by Elronnd: they are at home in the sea, and therefore unaffected */
2030 if (tech_inuse(T_SILENT_OCEAN
)) return; /* if the ocean is silent, it means there are no currents */
2031 if (uarmh
&& uarmh
->oartifact
== ART_AIR_ON_HOLD
) return;
2033 if (Swimming
&& rn2(StrongSwimming
? 20 : 4))
2034 return; /* natural swimmers have advantage */
2036 if (u
.dx
&& !rn2(!u
.dy
? 3 : 6)) { /* 1/3 chance or half that */
2037 /* cancel delta x and choose an arbitrary delta y value */
2040 dy
= rn2(3) - 1; /* -1, 0, 1 */
2042 } while (dy
&& (!isok(x
,y
) || (!is_waterypool(x
,y
) && !is_watertunnel(x
,y
) ) ));
2046 } else if (u
.dy
&& !rn2(!u
.dx
? 3 : 5)) { /* 1/3 or 1/5*(5/6) */
2047 /* cancel delta y and choose an arbitrary delta x value */
2050 dx
= rn2(3) - 1; /* -1 .. 1 */
2052 } while (dx
&& (!isok(x
,y
) || (!is_waterypool(x
,y
) && !is_watertunnel(x
,y
) ) ));
2057 if (eff
) pline("Water turbulence affects your movements.");
2061 save_waterlevel(fd
, mode
)
2064 register struct bubble
*b
;
2066 if (!Is_waterlevel(&u
.uz
)) return;
2068 if (perform_bwrite(mode
)) {
2070 for (b
= bbubbles
; b
; b
= b
->next
) ++n
;
2071 bwrite(fd
, (void *)&n
, sizeof (int));
2072 bwrite(fd
, (void *)&xmin
, sizeof (int));
2073 bwrite(fd
, (void *)&ymin
, sizeof (int));
2074 bwrite(fd
, (void *)&xmax
, sizeof (int));
2075 bwrite(fd
, (void *)&ymax
, sizeof (int));
2076 for (b
= bbubbles
; b
; b
= b
->next
)
2077 bwrite(fd
, (void *)b
, sizeof (struct bubble
));
2079 if (release_data(mode
))
2080 unsetup_waterlevel();
2084 restore_waterlevel(fd
)
2087 register struct bubble
*b
= (struct bubble
*)0, *btmp
;
2091 if (!Is_waterlevel(&u
.uz
)) return;
2094 mread(fd
,(void *)&n
,sizeof(int));
2095 mread(fd
,(void *)&xmin
,sizeof(int));
2096 mread(fd
,(void *)&ymin
,sizeof(int));
2097 mread(fd
,(void *)&xmax
,sizeof(int));
2098 mread(fd
,(void *)&ymax
,sizeof(int));
2101 for (i
= 0; i
< n
; i
++) {
2103 b
= (struct bubble
*)alloc(sizeof(struct bubble
));
2104 mread(fd
,(void *)b
,sizeof(struct bubble
));
2110 b
->prev
= (struct bubble
*)0;
2112 mv_bubble(b
,0,0,TRUE
);
2115 b
->next
= (struct bubble
*)0;
2117 was_waterlevel
= TRUE
;
2120 const char *waterbody_name(x
, y
)
2123 register struct rm
*lev
;
2127 return "drink"; /* should never happen */
2133 else if (ltyp
== ICE
||
2134 (ltyp
== DRAWBRIDGE_UP
&&
2135 (levl
[x
][y
].drawbridgemask
& DB_UNDER
) == DB_ICE
))
2137 else if (((ltyp
!= POOL
) && (ltyp
!= WATER
) &&
2138 !Is_medusa_level(&u
.uz
) && !Is_waterlevel(&u
.uz
) && !Is_juiblex_level(&u
.uz
)) ||
2139 (ltyp
== DRAWBRIDGE_UP
&& (levl
[x
][y
].drawbridgemask
& DB_UNDER
) == DB_MOAT
))
2141 else if ((ltyp
!= POOL
) && (ltyp
!= WATER
) && Is_juiblex_level(&u
.uz
))
2143 else if (ltyp
== POOL
)
2144 return "pool of water";
2145 else if (ltyp
== MOORLAND
)
2147 else if (ltyp
== URINELAKE
)
2148 return "urine lake";
2149 else if (ltyp
== STYXRIVER
)
2150 return "styx river";
2151 else return "water";
2157 /* there better be only one magic portal on water level... */
2158 for (wportal
= ftrap
; wportal
; wportal
= wportal
->ntrap
)
2159 if (wportal
->ttyp
== MAGIC_PORTAL
) return;
2160 impossible("set_wportal(): no portal!");
2167 register int xskip
, yskip
;
2169 /* ouch, hardcoded... */
2183 /* set hero's memory to water */
2185 for (x
= xmin
; x
<= xmax
; x
++)
2186 for (y
= ymin
; y
<= ymax
; y
++)
2187 clear_memory_glyph(x
, y
, S_water
);
2191 xskip
= 10 + rn2(10);
2193 for (x
= bxmin
; x
<= bxmax
; x
+= xskip
)
2194 for (y
= bymin
; y
<= bymax
; y
+= yskip
)
2195 mk_bubble(x
,y
,rn2(7));
2199 unsetup_waterlevel()
2201 register struct bubble
*b
, *bb
;
2205 for (b
= bbubbles
; b
; b
= bb
) {
2209 bbubbles
= ebubbles
= (struct bubble
*)0;
2214 register int x
, y
, n
;
2217 * These bit masks make visually pleasing bubbles on a normal aspect
2218 * 25x80 terminal, which naturally results in them being mathematically
2219 * anything but symmetric. For this reason they cannot be computed
2220 * in situ, either. The first two elements tell the dimensions of
2221 * the bubble's bounding box.
2225 bm3
[] = {3,2,0x7,0x7},
2226 bm4
[] = {4,3,0x6,0xf,0x6},
2227 bm5
[] = {5,3,0xe,0x1f,0xe},
2228 bm6
[] = {6,4,0x1e,0x3f,0x3f,0x1e},
2229 bm7
[] = {7,4,0x3e,0x7f,0x7f,0x3e},
2230 bm8
[] = {8,4,0x7e,0xff,0xff,0x7e},
2231 *bmask
[] = {bm2
,bm3
,bm4
,bm5
,bm6
,bm7
,bm8
};
2233 register struct bubble
*b
;
2235 if (x
>= bxmax
|| y
>= bymax
) return;
2236 if (n
>= SIZE(bmask
)) {
2237 impossible("n too large (mk_bubble)");
2238 n
= SIZE(bmask
) - 1;
2240 b
= (struct bubble
*)alloc(sizeof(struct bubble
));
2241 if ((x
+ (int) bmask
[n
][0] - 1) > bxmax
) x
= bxmax
- bmask
[n
][0] + 1;
2242 if ((y
+ (int) bmask
[n
][1] - 1) > bymax
) y
= bymax
- bmask
[n
][1] + 1;
2249 if (!bbubbles
) bbubbles
= b
;
2255 b
->prev
= (struct bubble
*)0;
2256 b
->next
= (struct bubble
*)0;
2258 mv_bubble(b
,0,0,TRUE
);
2262 * The player, the portal and all other objects and monsters
2263 * float along with their associated bubbles. Bubbles may overlap
2264 * freely, and the contents may get associated with other bubbles in
2265 * the process. Bubbles are "sticky", meaning that if the player is
2266 * in the immediate neighborhood of one, he/she may get sucked inside.
2267 * This property also makes leaving a bubble slightly difficult.
2270 mv_bubble(b
,dx
,dy
,ini
)
2271 register struct bubble
*b
;
2272 register int dx
, dy
;
2273 register boolean ini
;
2275 register int x
, y
, i
, j
, colli
= 0;
2276 struct container
*cons
, *ctemp
;
2279 if (dx
< -1 || dx
> 1 || dy
< -1 || dy
> 1) {
2280 /* pline("mv_bubble: dx = %d, dy = %d", dx, dy); */
2286 * collision with level borders?
2287 * 1 = horizontal border, 2 = vertical, 3 = corner
2289 if (b
->x
<= bxmin
) colli
|= 2;
2290 if (b
->y
<= bymin
) colli
|= 1;
2291 if ((int) (b
->x
+ b
->bm
[0] - 1) >= bxmax
) colli
|= 2;
2292 if ((int) (b
->y
+ b
->bm
[1] - 1) >= bymax
) colli
|= 1;
2295 pline("bubble xmin: x = %d, xmin = %d", b
->x
, bxmin
);
2299 pline("bubble ymin: y = %d, ymin = %d", b
->y
, bymin
);
2302 if ((int) (b
->x
+ b
->bm
[0] - 1) > bxmax
) {
2303 pline("bubble xmax: x = %d, xmax = %d",
2304 b
->x
+ b
->bm
[0] - 1, bxmax
);
2305 b
->x
= bxmax
- b
->bm
[0] + 1;
2307 if ((int) (b
->y
+ b
->bm
[1] - 1) > bymax
) {
2308 pline("bubble ymax: y = %d, ymax = %d",
2309 b
->y
+ b
->bm
[1] - 1, bymax
);
2310 b
->y
= bymax
- b
->bm
[1] + 1;
2313 /* bounce if we're trying to move off the border */
2314 if (b
->x
== bxmin
&& dx
< 0) dx
= -dx
;
2315 if (b
->x
+ b
->bm
[0] - 1 == bxmax
&& dx
> 0) dx
= -dx
;
2316 if (b
->y
== bymin
&& dy
< 0) dy
= -dy
;
2317 if (b
->y
+ b
->bm
[1] - 1 == bymax
&& dy
> 0) dy
= -dy
;
2322 /* void positions inside bubble */
2324 for (i
= 0, x
= b
->x
; i
< (int) b
->bm
[0]; i
++, x
++)
2325 for (j
= 0, y
= b
->y
; j
< (int) b
->bm
[1]; j
++, y
++)
2326 if (b
->bm
[j
+ 2] & (1 << i
)) {
2327 levl
[x
][y
].typ
= AIR
;
2332 /* replace contents of bubble */
2333 for (cons
= b
->cons
; cons
; cons
= ctemp
) {
2338 switch(cons
->what
) {
2340 struct obj
*olist
, *otmp
;
2342 for (olist
=(struct obj
*)cons
->list
; olist
; olist
=otmp
) {
2343 otmp
= olist
->nexthere
;
2344 place_object(olist
, cons
->x
, cons
->y
);
2350 struct monst
*mon
= (struct monst
*) cons
->list
;
2351 (void) mnearto(mon
, cons
->x
, cons
->y
, TRUE
);
2356 int ux0
= u
.ux
, uy0
= u
.uy
;
2358 /* change u.ux0 and u.uy0? */
2361 newsym(ux0
, uy0
); /* clean up old position */
2363 if (MON_AT(cons
->x
, cons
->y
)) {
2364 mnexto(m_at(cons
->x
,cons
->y
));
2366 /* WAC removed this. The ball and chain is moved
2367 * as a CONS_OBJECT by the bubble
2370 if (Punished
) placebc(); /* do this for now */
2376 struct trap
*btrap
= (struct trap
*) cons
->list
;
2377 btrap
->tx
= cons
->x
;
2378 btrap
->ty
= cons
->y
;
2383 impossible("mv_bubble: unknown bubble contents");
2393 case 1: b
->dy
= -b
->dy
; break;
2394 case 3: b
->dy
= -b
->dy
; /* fall through */
2395 case 2: b
->dx
= -b
->dx
; break;
2397 /* sometimes alter direction for fun anyway
2398 (higher probability for stationary bubbles) */
2399 if (!ini
&& ((b
->dx
|| b
->dy
) ? !rn2(20) : !rn2(5))) {