1 /* aNetHack 0.0.1 mkmaze.c $ANH-Date: 1469930897 2016/07/31 02:08:17 $ $ANH-Branch: master $:$ANH-Revision: 1.50 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* aNetHack 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 lev_region
*lregions
;
11 extern int num_lregions
;
12 /* for preserving the insect legs when wallifying baalz level */
13 static lev_region bughack
= { {COLNO
, ROWNO
, 0, 0}, {COLNO
, ROWNO
, 0, 0} };
15 STATIC_DCL
int FDECL(iswall
, (int, int));
16 STATIC_DCL
int FDECL(iswall_or_stone
, (int, int));
17 STATIC_DCL boolean
FDECL(is_solid
, (int, int));
18 STATIC_DCL
int FDECL(extend_spine
, (int[3][3], int, int, int));
19 STATIC_DCL boolean
FDECL(okay
, (int, int, int));
20 STATIC_DCL
void FDECL(maze0xy
, (coord
*));
21 STATIC_DCL boolean
FDECL(put_lregion_here
, (XCHAR_P
, XCHAR_P
, XCHAR_P
,
22 XCHAR_P
, XCHAR_P
, XCHAR_P
,
23 XCHAR_P
, BOOLEAN_P
, d_level
*));
24 STATIC_DCL
void NDECL(baalz_fixup
);
25 STATIC_DCL
void NDECL(setup_waterlevel
);
26 STATIC_DCL
void NDECL(unsetup_waterlevel
);
28 /* adjust a coordinate one step in the specified direction */
29 #define mz_move(X, Y, dir) \
32 case 0: --(Y); break; \
33 case 1: (X)++; break; \
34 case 2: (Y)++; break; \
35 case 3: --(X); break; \
36 default: panic("mz_move: bad direction %d", dir); \
48 type
= levl
[x
][y
].typ
;
49 return (IS_WALL(type
) || IS_DOOR(type
)
50 || type
== SDOOR
|| type
== IRONBARS
);
57 /* out of bounds = stone */
61 return (levl
[x
][y
].typ
== STONE
|| iswall(x
, y
));
64 /* return TRUE if out of bounds, wall or rock */
69 return (boolean
) (!isok(x
, y
) || IS_STWALL(levl
[x
][y
].typ
));
73 * Return 1 (not TRUE - we're doing bit vectors here) if we want to extend
74 * a wall spine in the (dx,dy) direction. Return 0 otherwise.
76 * To extend a wall spine in that direction, first there must be a wall there.
77 * Then, extend a spine unless the current position is surrounded by walls
78 * in the direction given by (dx,dy). E.g. if 'x' is our location, 'W'
79 * a wall, '.' a room, 'a' anything (we don't care), and our direction is
80 * (0,1) - South or down - then:
83 * W x W This would not extend a spine from x down
84 * W W W (a corridor of walls is formed).
87 * W x W This would extend a spine from x down.
91 extend_spine(locale
, wall_there
, dx
, dy
)
93 int wall_there
, dx
, dy
;
100 if (wall_there
) { /* wall in that direction */
102 if (locale
[1][0] && locale
[1][2] /* EW are wall/stone */
103 && locale
[nx
][0] && locale
[nx
][2]) { /* diag are wall/stone */
109 if (locale
[0][1] && locale
[2][1] /* NS are wall/stone */
110 && locale
[0][ny
] && locale
[2][ny
]) { /* diag are wall/stone */
123 /* Remove walls totally surrounded by stone */
125 wall_cleanup(x1
, y1
, x2
, y2
)
132 /* sanity check on incoming variables */
133 if (x1
< 0 || x2
>= COLNO
|| x1
> x2
|| y1
< 0 || y2
>= ROWNO
|| y1
> y2
)
134 panic("wall_cleanup: bad bounds (%d,%d) to (%d,%d)", x1
, y1
, x2
, y2
);
136 /* change walls surrounded by rock to rock. */
137 for (x
= x1
; x
<= x2
; x
++)
138 for (y
= y1
; y
<= y2
; y
++) {
139 if (within_bounded_area(x
, y
,
140 bughack
.inarea
.x1
, bughack
.inarea
.y1
,
141 bughack
.inarea
.x2
, bughack
.inarea
.y2
))
145 if (IS_WALL(type
) && type
!= DBWALL
) {
146 if (is_solid(x
- 1, y
- 1) && is_solid(x
- 1, y
)
147 && is_solid(x
- 1, y
+ 1) && is_solid(x
, y
- 1)
148 && is_solid(x
, y
+ 1) && is_solid(x
+ 1, y
- 1)
149 && is_solid(x
+ 1, y
) && is_solid(x
+ 1, y
+ 1))
155 /* Correct wall types so they extend and connect to each other */
157 fix_wall_spines(x1
, y1
, x2
, y2
)
163 int FDECL((*loc_f
), (int, int));
165 int locale
[3][3]; /* rock or wall status surrounding positions */
168 * Value 0 represents a free-standing wall. It could be anything,
169 * so even though this table says VWALL, we actually leave whatever
170 * typ was there alone.
172 static xchar spine_array
[16] = { VWALL
, HWALL
, HWALL
, HWALL
,
173 VWALL
, TRCORNER
, TLCORNER
, TDWALL
,
174 VWALL
, BRCORNER
, BLCORNER
, TUWALL
,
175 VWALL
, TLWALL
, TRWALL
, CROSSWALL
};
177 /* sanity check on incoming variables */
178 if (x1
< 0 || x2
>= COLNO
|| x1
> x2
|| y1
< 0 || y2
>= ROWNO
|| y1
> y2
)
179 panic("wall_extends: bad bounds (%d,%d) to (%d,%d)", x1
, y1
, x2
, y2
);
181 /* set the correct wall type. */
182 for (x
= x1
; x
<= x2
; x
++)
183 for (y
= y1
; y
<= y2
; y
++) {
186 if (!(IS_WALL(type
) && type
!= DBWALL
))
189 /* set the locations TRUE if rock or wall or out of bounds */
190 loc_f
= within_bounded_area(x
, y
, /* for baalz insect */
191 bughack
.inarea
.x1
, bughack
.inarea
.y1
,
192 bughack
.inarea
.x2
, bughack
.inarea
.y2
)
195 locale
[0][0] = (*loc_f
)(x
- 1, y
- 1);
196 locale
[1][0] = (*loc_f
)(x
, y
- 1);
197 locale
[2][0] = (*loc_f
)(x
+ 1, y
- 1);
199 locale
[0][1] = (*loc_f
)(x
- 1, y
);
200 locale
[2][1] = (*loc_f
)(x
+ 1, y
);
202 locale
[0][2] = (*loc_f
)(x
- 1, y
+ 1);
203 locale
[1][2] = (*loc_f
)(x
, y
+ 1);
204 locale
[2][2] = (*loc_f
)(x
+ 1, y
+ 1);
206 /* determine if wall should extend to each direction NSEW */
207 bits
= (extend_spine(locale
, iswall(x
, y
- 1), 0, -1) << 3)
208 | (extend_spine(locale
, iswall(x
, y
+ 1), 0, 1) << 2)
209 | (extend_spine(locale
, iswall(x
+ 1, y
), 1, 0) << 1)
210 | extend_spine(locale
, iswall(x
- 1, y
), -1, 0);
212 /* don't change typ if wall is free-standing */
214 lev
->typ
= spine_array
[bits
];
219 wallification(x1
, y1
, x2
, y2
)
222 wall_cleanup(x1
, y1
, x2
, y2
);
223 fix_wall_spines(x1
, y1
, x2
, y2
);
233 if (x
< 3 || y
< 3 || x
> x_maze_max
|| y
> y_maze_max
234 || levl
[x
][y
].typ
!= STONE
)
239 /* find random starting point for maze generation */
244 cc
->x
= 3 + 2 * rn2((x_maze_max
>> 1) - 1);
245 cc
->y
= 3 + 2 * rn2((y_maze_max
>> 1) - 1);
252 * pos is inside restricted region (lx,ly,hx,hy) OR
253 * NOT (pos is corridor and a maze level OR pos is a room OR pos is air)
256 bad_location(x
, y
, lx
, ly
, hx
, hy
)
258 xchar lx
, ly
, hx
, hy
;
260 return (boolean
) (occupied(x
, y
)
261 || within_bounded_area(x
, y
, lx
, ly
, hx
, hy
)
262 || !((levl
[x
][y
].typ
== CORR
&& level
.flags
.is_maze_lev
)
263 || levl
[x
][y
].typ
== ROOM
264 || levl
[x
][y
].typ
== AIR
));
267 /* pick a location in area (lx, ly, hx, hy) but not in (nlx, nly, nhx, nhy)
268 and place something (based on rtype) in that region */
270 place_lregion(lx
, ly
, hx
, hy
, nlx
, nly
, nhx
, nhy
, rtype
, lev
)
271 xchar lx
, ly
, hx
, hy
;
272 xchar nlx
, nly
, nhx
, nhy
;
280 if (!lx
) { /* default to whole level */
282 * if there are rooms and this a branch, let place_branch choose
283 * the branch location (to avoid putting branches in corridors).
285 if (rtype
== LR_BRANCH
&& nroom
) {
286 place_branch(Is_branchlev(&u
.uz
), 0, 0);
296 /* first a probabilistic approach */
298 oneshot
= (lx
== hx
&& ly
== hy
);
299 for (trycnt
= 0; trycnt
< 200; trycnt
++) {
300 x
= rn1((hx
- lx
) + 1, lx
);
301 y
= rn1((hy
- ly
) + 1, ly
);
302 if (put_lregion_here(x
, y
, nlx
, nly
, nhx
, nhy
, rtype
, oneshot
, lev
))
306 /* then a deterministic one */
309 for (x
= lx
; x
<= hx
; x
++)
310 for (y
= ly
; y
<= hy
; y
++)
311 if (put_lregion_here(x
, y
, nlx
, nly
, nhx
, nhy
, rtype
, oneshot
,
315 impossible("Couldn't place lregion type %d!", rtype
);
319 put_lregion_here(x
, y
, nlx
, nly
, nhx
, nhy
, rtype
, oneshot
, lev
)
321 xchar nlx
, nly
, nhx
, nhy
;
326 if (bad_location(x
, y
, nlx
, nly
, nhx
, nhy
)) {
328 return FALSE
; /* caller should try again */
330 /* Must make do with the only location possible;
331 avoid failure due to a misplaced trap.
332 It might still fail if there's a dungeon feature here. */
333 struct trap
*t
= t_at(x
, y
);
335 if (t
&& t
->ttyp
!= MAGIC_PORTAL
&& t
->ttyp
!= VIBRATING_SQUARE
)
337 if (bad_location(x
, y
, nlx
, nly
, nhx
, nhy
))
345 /* "something" means the player in this case */
347 /* move the monster if no choice, or just try again */
349 (void) rloc(m_at(x
, y
), FALSE
);
356 mkportal(x
, y
, lev
->dnum
, lev
->dlevel
);
360 mkstairs(x
, y
, (char) rtype
, (struct mkroom
*) 0);
363 place_branch(Is_branchlev(&u
.uz
), x
, y
);
369 /* fix up Baalzebub's lair, which depicts a level-sized beetle;
370 its legs are walls within solid rock--regular wallification
371 classifies them as superfluous and gets rid of them */
376 int x
, y
, lastx
, lasty
;
379 * baalz level's nondiggable region surrounds the "insect" and rooms.
380 * The outermost perimeter of that region is subject to wall cleanup
381 * (hence 'x + 1' and 'y + 1' for starting don't-clean column and row,
382 * 'lastx - 1' and 'lasty - 1' for ending don't-clean column and row)
383 * and the interior is protected against that (in wall_cleanup()).
385 * Assumes level.flags.corrmaze is True, otherwise the bug legs will
386 * have already been "cleaned" away by general wallification.
389 /* find low and high x for to-be-wallified portion of level */
391 for (lastx
= x
= 0; x
< COLNO
; ++x
)
392 if ((levl
[x
][y
].wall_info
& W_NONDIGGABLE
) != 0) {
394 bughack
.inarea
.x1
= x
+ 1;
397 bughack
.inarea
.x2
= ((lastx
> bughack
.inarea
.x1
) ? lastx
: x
) - 1;
398 /* find low and high y for to-be-wallified portion of level */
399 x
= bughack
.inarea
.x1
;
400 for (lasty
= y
= 0; y
< ROWNO
; ++y
)
401 if ((levl
[x
][y
].wall_info
& W_NONDIGGABLE
) != 0) {
403 bughack
.inarea
.y1
= y
+ 1;
406 bughack
.inarea
.y2
= ((lasty
> bughack
.inarea
.y1
) ? lasty
: y
) - 1;
407 /* two pools mark where special post-wallify fix-ups are needed */
408 for (x
= bughack
.inarea
.x1
; x
<= bughack
.inarea
.x2
; ++x
)
409 for (y
= bughack
.inarea
.y1
; y
<= bughack
.inarea
.y2
; ++y
)
410 if (levl
[x
][y
].typ
== POOL
) {
411 levl
[x
][y
].typ
= HWALL
;
412 if (bughack
.delarea
.x1
== COLNO
)
413 bughack
.delarea
.x1
= x
, bughack
.delarea
.y1
= y
;
415 bughack
.delarea
.x2
= x
, bughack
.delarea
.y2
= y
;
416 } else if (levl
[x
][y
].typ
== IRONBARS
) {
417 /* novelty effect; allowing digging in front of 'eyes' */
418 levl
[x
- 1][y
].wall_info
&= ~W_NONDIGGABLE
;
420 levl
[x
- 2][y
].wall_info
&= ~W_NONDIGGABLE
;
423 wallification(max(bughack
.inarea
.x1
- 2, 1),
424 max(bughack
.inarea
.y1
- 2, 0),
425 min(bughack
.inarea
.x2
+ 2, COLNO
- 1),
426 min(bughack
.inarea
.y2
+ 2, ROWNO
- 1));
428 /* bughack hack for rear-most legs on baalz level; first joint on
429 both top and bottom gets a bogus extra connection to room area,
430 producing unwanted rectangles; change back to separated legs */
431 x
= bughack
.delarea
.x1
, y
= bughack
.delarea
.y1
;
432 if (isok(x
, y
) && levl
[x
][y
].typ
== TLWALL
433 && isok(x
, y
+ 1) && levl
[x
][y
+ 1].typ
== TUWALL
) {
434 levl
[x
][y
].typ
= BRCORNER
;
435 levl
[x
][y
+ 1].typ
= HWALL
;
436 if ((mtmp
= m_at(x
, y
)) != 0) /* something at temporary pool... */
437 (void) rloc(mtmp
, FALSE
);
439 x
= bughack
.delarea
.x2
, y
= bughack
.delarea
.y2
;
440 if (isok(x
, y
) && levl
[x
][y
].typ
== TLWALL
441 && isok(x
, y
- 1) && levl
[x
][y
- 1].typ
== TDWALL
) {
442 levl
[x
][y
].typ
= TRCORNER
;
443 levl
[x
][y
- 1].typ
= HWALL
;
444 if ((mtmp
= m_at(x
, y
)) != 0) /* something at temporary pool... */
445 (void) rloc(mtmp
, FALSE
);
448 /* reset bughack region; set low end to <COLNO,ROWNO> so that
449 within_bounded_region() in fix_wall_spines() will fail
450 most quickly--on its first test--when loading other levels */
451 bughack
.inarea
.x1
= bughack
.delarea
.x1
= COLNO
;
452 bughack
.inarea
.y1
= bughack
.delarea
.y1
= ROWNO
;
453 bughack
.inarea
.x2
= bughack
.delarea
.x2
= 0;
454 bughack
.inarea
.y2
= bughack
.delarea
.y2
= 0;
457 static boolean was_waterlevel
; /* ugh... this shouldn't be needed */
459 /* this is special stuff that the level compiler cannot (yet) handle */
463 lev_region
*r
= lregions
;
466 struct mkroom
*croom
;
467 boolean added_branch
= FALSE
;
469 if (was_waterlevel
) {
470 was_waterlevel
= FALSE
;
472 unsetup_waterlevel();
474 if (Is_waterlevel(&u
.uz
) || Is_airlevel(&u
.uz
)) {
475 level
.flags
.hero_memory
= 0;
476 was_waterlevel
= TRUE
;
477 /* water level is an odd beast - it has to be set up
478 before calling place_lregions etc. */
481 for (x
= 0; x
< num_lregions
; x
++, r
++) {
488 if (*r
->rname
.str
>= '0' && *r
->rname
.str
<= '9') {
489 /* "chutes and ladders" */
491 lev
.dlevel
= atoi(r
->rname
.str
);
493 s_level
*sp
= find_level(r
->rname
.str
);
501 place_lregion(r
->inarea
.x1
, r
->inarea
.y1
, r
->inarea
.x2
,
502 r
->inarea
.y2
, r
->delarea
.x1
, r
->delarea
.y1
,
503 r
->delarea
.x2
, r
->delarea
.y2
, r
->rtype
, &lev
);
509 /* save the region outlines for goto_level() */
510 if (r
->rtype
== LR_TELE
|| r
->rtype
== LR_UPTELE
) {
511 updest
.lx
= r
->inarea
.x1
;
512 updest
.ly
= r
->inarea
.y1
;
513 updest
.hx
= r
->inarea
.x2
;
514 updest
.hy
= r
->inarea
.y2
;
515 updest
.nlx
= r
->delarea
.x1
;
516 updest
.nly
= r
->delarea
.y1
;
517 updest
.nhx
= r
->delarea
.x2
;
518 updest
.nhy
= r
->delarea
.y2
;
520 if (r
->rtype
== LR_TELE
|| r
->rtype
== LR_DOWNTELE
) {
521 dndest
.lx
= r
->inarea
.x1
;
522 dndest
.ly
= r
->inarea
.y1
;
523 dndest
.hx
= r
->inarea
.x2
;
524 dndest
.hy
= r
->inarea
.y2
;
525 dndest
.nlx
= r
->delarea
.x1
;
526 dndest
.nly
= r
->delarea
.y1
;
527 dndest
.nhx
= r
->delarea
.x2
;
528 dndest
.nhy
= r
->delarea
.y2
;
530 /* place_lregion gets called from goto_level() */
535 free((genericptr_t
) r
->rname
.str
), r
->rname
.str
= 0;
538 /* place dungeon branch if not placed above */
539 if (!added_branch
&& Is_branchlev(&u
.uz
)) {
540 place_lregion(0, 0, 0, 0, 0, 0, 0, 0, LR_BRANCH
, (d_level
*) 0);
543 /* Still need to add some stuff to level file */
544 if (Is_medusa_level(&u
.uz
)) {
548 croom
= &rooms
[0]; /* only one room on the medusa level */
549 for (tryct
= rnd(4); tryct
; tryct
--) {
552 if (goodpos(x
, y
, (struct monst
*) 0, 0)) {
553 otmp
= mk_tt_object(STATUE
, x
, y
);
554 while (otmp
&& (poly_when_stoned(&mons
[otmp
->corpsenm
])
555 || pm_resistance(&mons
[otmp
->corpsenm
],
557 /* set_corpsenm() handles weight too */
558 set_corpsenm(otmp
, rndmonnum());
564 otmp
= mk_tt_object(STATUE
, somex(croom
), somey(croom
));
565 else /* Medusa statues don't contain books */
567 mkcorpstat(STATUE
, (struct monst
*) 0, (struct permonst
*) 0,
568 somex(croom
), somey(croom
), CORPSTAT_NONE
);
570 while (pm_resistance(&mons
[otmp
->corpsenm
], MR_STONE
)
571 || poly_when_stoned(&mons
[otmp
->corpsenm
])) {
572 /* set_corpsenm() handles weight too */
573 set_corpsenm(otmp
, rndmonnum());
576 } else if (Is_wiz1_level(&u
.uz
)) {
577 croom
= search_special(MORGUE
);
579 create_secret_door(croom
, W_SOUTH
| W_EAST
| W_WEST
);
580 } else if (Is_knox(&u
.uz
)) {
581 /* using an unfilled morgue for rm id */
582 croom
= search_special(MORGUE
);
583 /* avoid inappropriate morgue-related messages */
584 level
.flags
.graveyard
= level
.flags
.has_morgue
= 0;
585 croom
->rtype
= OROOM
; /* perhaps it should be set to VAULT? */
586 /* stock the main vault */
587 for (x
= croom
->lx
; x
<= croom
->hx
; x
++)
588 for (y
= croom
->ly
; y
<= croom
->hy
; y
++) {
589 (void) mkgold((long) rn1(300, 600), x
, y
);
590 if (!rn2(3) && !is_pool(x
, y
))
591 (void) maketrap(x
, y
, rn2(3) ? LANDMINE
: SPIKED_PIT
);
593 } else if (Role_if(PM_PRIEST
) && In_quest(&u
.uz
)) {
594 /* less chance for undead corpses (lured from lower morgues) */
595 level
.flags
.graveyard
= 1;
596 } else if (Is_stronghold(&u
.uz
)) {
597 level
.flags
.graveyard
= 1;
598 } else if (Is_sanctum(&u
.uz
)) {
599 croom
= search_special(TEMPLE
);
601 create_secret_door(croom
, W_ANY
);
602 } else if (on_level(&u
.uz
, &orcus_level
)) {
603 struct monst
*mtmp
, *mtmp2
;
605 /* it's a ghost town, get rid of shopkeepers */
606 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp2
) {
611 } else if (on_level(&u
.uz
, &baalzebub_level
)) {
612 /* custom wallify the "beetle" potion of the level */
617 free((genericptr_t
) lregions
), lregions
= 0;
625 return (x
>= 2 && y
>= 2
626 && x
< x_maze_max
&& y
< y_maze_max
&& isok(x
, y
));
630 maze_remove_deadends(typ
)
634 int x
, y
, dir
, idx
, idx2
, dx
, dy
, dx2
, dy2
;
636 dirok
[0] = 0; /* lint suppression */
637 for (x
= 2; x
< x_maze_max
; x
++)
638 for (y
= 2; y
< y_maze_max
; y
++)
639 if (ACCESSIBLE(levl
[x
][y
].typ
) && (x
% 2) && (y
% 2)) {
641 for (dir
= 0; dir
< 4; dir
++) {
642 /* note: mz_move() is a macro which modifies
643 one of its first two parameters */
646 mz_move(dx
, dy
, dir
);
647 if (!maze_inbounds(dx
, dy
)) {
651 mz_move(dx2
, dy2
, dir
);
652 mz_move(dx2
, dy2
, dir
);
653 if (!maze_inbounds(dx2
, dy2
)) {
657 if (!ACCESSIBLE(levl
[dx
][dy
].typ
)
658 && ACCESSIBLE(levl
[dx2
][dy2
].typ
)) {
663 if (idx2
>= 3 && idx
> 0) {
666 dir
= dirok
[rn2(idx
)];
667 mz_move(dx
, dy
, dir
);
668 levl
[dx
][dy
].typ
= typ
;
673 /* Create a maze with specified corridor width and wall thickness
674 * TODO: rewrite walkfrom so it works on temp space, not levl
677 create_maze(corrwid
, wallthick
)
683 int tmp_xmax
= x_maze_max
;
684 int tmp_ymax
= y_maze_max
;
691 else if (wallthick
> 5)
696 else if (corrwid
> 5)
699 scale
= corrwid
+ wallthick
;
700 rdx
= (x_maze_max
/ scale
);
701 rdy
= (y_maze_max
/ scale
);
703 if (level
.flags
.corrmaze
)
704 for (x
= 2; x
< (rdx
* 2); x
++)
705 for (y
= 2; y
< (rdy
* 2); y
++)
706 levl
[x
][y
].typ
= STONE
;
708 for (x
= 2; x
<= (rdx
* 2); x
++)
709 for (y
= 2; y
<= (rdy
* 2); y
++)
710 levl
[x
][y
].typ
= ((x
% 2) && (y
% 2)) ? STONE
: HWALL
;
712 /* set upper bounds for maze0xy and walkfrom */
713 x_maze_max
= (rdx
* 2);
714 y_maze_max
= (rdy
* 2);
718 walkfrom((int) mm
.x
, (int) mm
.y
, 0);
721 maze_remove_deadends((level
.flags
.corrmaze
) ? CORR
: ROOM
);
724 x_maze_max
= tmp_xmax
;
725 y_maze_max
= tmp_ymax
;
727 /* scale maze up if needed */
729 char tmpmap
[COLNO
][ROWNO
];
732 /* back up the existing smaller maze */
733 for (x
= 1; x
< x_maze_max
; x
++)
734 for (y
= 1; y
< y_maze_max
; y
++) {
735 tmpmap
[x
][y
] = levl
[x
][y
].typ
;
740 while (rx
< x_maze_max
) {
741 int mx
= (x
% 2) ? corrwid
742 : ((x
== 2 || x
== (rdx
* 2)) ? 1
745 while (ry
< y_maze_max
) {
747 int my
= (y
% 2) ? corrwid
748 : ((y
== 2 || y
== (rdy
* 2)) ? 1
750 for (dx
= 0; dx
< mx
; dx
++)
751 for (dy
= 0; dy
< my
; dy
++) {
752 if (rx
+dx
>= x_maze_max
753 || ry
+dy
>= y_maze_max
)
755 levl
[rx
+ dx
][ry
+ dy
].typ
= tmpmap
[x
][y
];
774 s_level
*sp
= Is_special(&u
.uz
);
778 if (sp
&& sp
->rndlevs
)
779 Sprintf(protofile
, "%s-%d", s
, rnd((int) sp
->rndlevs
));
781 Strcpy(protofile
, s
);
782 } else if (*(dungeons
[u
.uz
.dnum
].proto
)) {
783 if (dunlevs_in_dungeon(&u
.uz
) > 1) {
784 if (sp
&& sp
->rndlevs
)
785 Sprintf(protofile
, "%s%d-%d", dungeons
[u
.uz
.dnum
].proto
,
786 dunlev(&u
.uz
), rnd((int) sp
->rndlevs
));
788 Sprintf(protofile
, "%s%d", dungeons
[u
.uz
.dnum
].proto
,
790 } else if (sp
&& sp
->rndlevs
) {
791 Sprintf(protofile
, "%s-%d", dungeons
[u
.uz
.dnum
].proto
,
792 rnd((int) sp
->rndlevs
));
794 Strcpy(protofile
, dungeons
[u
.uz
.dnum
].proto
);
797 Strcpy(protofile
, "");
799 /* SPLEVTYPE format is "level-choice,level-choice"... */
800 if (wizard
&& *protofile
&& sp
&& sp
->rndlevs
) {
801 char *ep
= getenv("SPLEVTYPE"); /* not nh_getenv */
803 /* rindex always succeeds due to code in prior block */
804 int len
= (int) ((rindex(protofile
, '-') - protofile
) + 1);
807 if (!strncmp(ep
, protofile
, len
)) {
808 int pick
= atoi(ep
+ len
);
809 /* use choice only if valid */
810 if (pick
> 0 && pick
<= (int) sp
->rndlevs
)
811 Sprintf(protofile
+ len
, "%d", pick
);
823 Strcat(protofile
, LEV_EXT
);
824 if (load_special(protofile
)) {
825 /* some levels can end up with monsters
826 on dead mon list, including light source monsters */
828 return; /* no mazification right now */
830 impossible("Couldn't load \"%s\" - making a maze.", protofile
);
833 level
.flags
.is_maze_lev
= TRUE
;
834 level
.flags
.corrmaze
= !rn2(3);
836 if (!Invocation_lev(&u
.uz
) && rn2(2)) {
837 int corrscale
= rnd(4);
838 create_maze(corrscale
,rnd(4)-corrscale
);
843 if (!level
.flags
.corrmaze
)
844 wallification(2, 2, x_maze_max
, y_maze_max
);
847 mkstairs(mm
.x
, mm
.y
, 1, (struct mkroom
*) 0); /* up */
848 if (!Invocation_lev(&u
.uz
)) {
850 mkstairs(mm
.x
, mm
.y
, 0, (struct mkroom
*) 0); /* down */
851 } else { /* choose "vibrating square" location */
855 * Pick a position where the stairs down to Moloch's Sanctum
856 * level will ultimately be created. At that time, an area
857 * will be altered: walls removed, moat and traps generated,
858 * boulders destroyed. The position picked here must ensure
859 * that that invocation area won't extend off the map.
861 * We actually allow up to 2 squares around the usual edge of
862 * the area to get truncated; see mkinvokearea(mklev.c).
864 #define INVPOS_X_MARGIN (6 - 2)
865 #define INVPOS_Y_MARGIN (5 - 2)
866 #define INVPOS_DISTANCE 11
867 int x_range
= x_maze_max
- x_maze_min
- 2 * INVPOS_X_MARGIN
- 1,
868 y_range
= y_maze_max
- y_maze_min
- 2 * INVPOS_Y_MARGIN
- 1;
870 if (x_range
<= INVPOS_X_MARGIN
|| y_range
<= INVPOS_Y_MARGIN
871 || (x_range
* y_range
) <= (INVPOS_DISTANCE
* INVPOS_DISTANCE
)) {
872 debugpline2("inv_pos: maze is too small! (%d x %d)",
873 x_maze_max
, y_maze_max
);
875 inv_pos
.x
= inv_pos
.y
= 0; /*{occupied() => invocation_pos()}*/
877 x
= rn1(x_range
, x_maze_min
+ INVPOS_X_MARGIN
+ 1);
878 y
= rn1(y_range
, y_maze_min
+ INVPOS_Y_MARGIN
+ 1);
879 /* we don't want it to be too near the stairs, nor
880 to be on a spot that's already in use (wall|trap) */
881 } while (x
== xupstair
|| y
== yupstair
/*(direct line)*/
882 || abs(x
- xupstair
) == abs(y
- yupstair
)
883 || distmin(x
, y
, xupstair
, yupstair
) <= INVPOS_DISTANCE
884 || !SPACE_POS(levl
[x
][y
].typ
) || occupied(x
, y
));
887 maketrap(inv_pos
.x
, inv_pos
.y
, VIBRATING_SQUARE
);
888 #undef INVPOS_X_MARGIN
889 #undef INVPOS_Y_MARGIN
890 #undef INVPOS_DISTANCE
895 /* place branch stair or portal */
896 place_branch(Is_branchlev(&u
.uz
), 0, 0);
898 for (x
= rn1(8, 11); x
; x
--) {
900 (void) mkobj_at(rn2(2) ? GEM_CLASS
: 0, mm
.x
, mm
.y
, TRUE
);
902 for (x
= rn1(10, 2); x
; x
--) {
904 (void) mksobj_at(BOULDER
, mm
.x
, mm
.y
, TRUE
, FALSE
);
906 for (x
= rn2(3); x
; x
--) {
908 (void) makemon(&mons
[PM_MINOTAUR
], mm
.x
, mm
.y
, NO_MM_FLAGS
);
910 for (x
= rn1(5, 7); x
; x
--) {
912 (void) makemon((struct permonst
*) 0, mm
.x
, mm
.y
, NO_MM_FLAGS
);
914 for (x
= rn1(6, 7); x
; x
--) {
916 (void) mkgold(0L, mm
.x
, mm
.y
);
918 for (x
= rn1(6, 7); x
; x
--)
919 mktrap(0, 1, (struct mkroom
*) 0, (coord
*) 0);
923 /* Make the mazewalk iterative by faking a stack. This is needed to
924 * ensure the mazewalk is successful in the limited stack space of
925 * the program. This iterative version uses the minimum amount of stack
926 * that is totally safe.
933 #define CELLS (ROWNO * COLNO) / 4 /* a maze cell is 4 squares */
934 char mazex
[CELLS
+ 1], mazey
[CELLS
+ 1]; /* char's are OK */
939 if (level
.flags
.corrmaze
)
946 mazex
[pos
] = (char) x
;
947 mazey
[pos
] = (char) y
;
949 x
= (int) mazex
[pos
];
950 y
= (int) mazey
[pos
];
951 if (!IS_DOOR(levl
[x
][y
].typ
)) {
952 /* might still be on edge of MAP, so don't overwrite */
953 levl
[x
][y
].typ
= typ
;
954 levl
[x
][y
].flags
= 0;
957 for (a
= 0; a
< 4; a
++)
965 levl
[x
][y
].typ
= typ
;
969 panic("Overflow in walkfrom");
970 mazex
[pos
] = (char) x
;
971 mazey
[pos
] = (char) y
;
986 if (level
.flags
.corrmaze
)
992 if (!IS_DOOR(levl
[x
][y
].typ
)) {
993 /* might still be on edge of MAP, so don't overwrite */
994 levl
[x
][y
].typ
= typ
;
995 levl
[x
][y
].flags
= 0;
1000 for (a
= 0; a
< 4; a
++)
1007 levl
[x
][y
].typ
= typ
;
1009 walkfrom(x
, y
, typ
);
1014 /* find random point in generated corridors,
1015 so we don't create items in moats, bunkers, or walls */
1023 cc
->x
= 1 + rn2(x_maze_max
);
1024 cc
->y
= 1 + rn2(y_maze_max
);
1027 && levl
[cc
->x
][cc
->y
].typ
1028 != (level
.flags
.corrmaze
? CORR
: ROOM
));
1033 for (x
= 1; x
< x_maze_max
; x
++)
1034 for (y
= 1; y
< y_maze_max
; y
++) {
1037 if (levl
[cc
->x
][cc
->y
].typ
1038 == (level
.flags
.corrmaze
? CORR
: ROOM
))
1041 panic("mazexy: can't find a place!");
1046 /* put a non-diggable boundary around the initial portion of a level map.
1047 * assumes that no level will initially put things beyond the isok() range.
1049 * we can't bound unconditionally on the last line with something in it,
1050 * because that something might be a niche which was already reachable,
1051 * so the boundary would be breached
1053 * we can't bound unconditionally on one beyond the last line, because
1054 * that provides a window of abuse for wallified special levels
1062 boolean found
, nonwall
;
1063 int xmin
, xmax
, ymin
, ymax
;
1065 if (Is_earthlevel(&u
.uz
))
1066 return; /* everything diggable here */
1068 found
= nonwall
= FALSE
;
1069 for (xmin
= 0; !found
&& xmin
<= COLNO
; xmin
++) {
1070 lev
= &levl
[xmin
][0];
1071 for (y
= 0; y
<= ROWNO
- 1; y
++, lev
++) {
1080 xmin
-= (nonwall
|| !level
.flags
.is_maze_lev
) ? 2 : 1;
1084 found
= nonwall
= FALSE
;
1085 for (xmax
= COLNO
- 1; !found
&& xmax
>= 0; xmax
--) {
1086 lev
= &levl
[xmax
][0];
1087 for (y
= 0; y
<= ROWNO
- 1; y
++, lev
++) {
1096 xmax
+= (nonwall
|| !level
.flags
.is_maze_lev
) ? 2 : 1;
1100 found
= nonwall
= FALSE
;
1101 for (ymin
= 0; !found
&& ymin
<= ROWNO
; ymin
++) {
1102 lev
= &levl
[xmin
][ymin
];
1103 for (x
= xmin
; x
<= xmax
; x
++, lev
+= ROWNO
) {
1112 ymin
-= (nonwall
|| !level
.flags
.is_maze_lev
) ? 2 : 1;
1114 found
= nonwall
= FALSE
;
1115 for (ymax
= ROWNO
- 1; !found
&& ymax
>= 0; ymax
--) {
1116 lev
= &levl
[xmin
][ymax
];
1117 for (x
= xmin
; x
<= xmax
; x
++, lev
+= ROWNO
) {
1126 ymax
+= (nonwall
|| !level
.flags
.is_maze_lev
) ? 2 : 1;
1128 for (x
= 0; x
< COLNO
; x
++)
1129 for (y
= 0; y
< ROWNO
; y
++)
1130 if (y
<= ymin
|| y
>= ymax
|| x
<= xmin
|| x
>= xmax
) {
1133 lev
->wall_info
|= W_NONDIGGABLE
;
1135 levl
[x
][y
].wall_info
|= W_NONDIGGABLE
;
1141 mkportal(x
, y
, todnum
, todlevel
)
1142 xchar x
, y
, todnum
, todlevel
;
1144 /* a portal "trap" must be matched by a
1145 portal in the destination dungeon/dlevel */
1146 struct trap
*ttmp
= maketrap(x
, y
, MAGIC_PORTAL
);
1149 impossible("portal on top of portal??");
1152 debugpline4("mkportal: at <%d,%d>, to %s, level %d", x
, y
,
1153 dungeons
[todnum
].dname
, todlevel
);
1154 ttmp
->dst
.dnum
= todnum
;
1155 ttmp
->dst
.dlevel
= todlevel
;
1163 boolean snd
= FALSE
, loud
= FALSE
;
1165 for (n
= rn2(3) + 2; n
; n
--) {
1166 xchar x
= rn1(COLNO
- 4, 3);
1167 xchar y
= rn1(ROWNO
- 4, 3);
1169 if (levl
[x
][y
].typ
== LAVAPOOL
) {
1170 NhRegion
*r
= create_gas_cloud(x
, y
, 4 + rn2(5), rn1(10, 5));
1172 clear_heros_fault(r
);
1174 if (distu(x
, y
) < 15)
1179 Norep("You hear a %swhoosh!", loud
? "loud " : "");
1183 * Special waterlevel stuff in endgame (TH).
1185 * Some of these functions would probably logically belong to some
1186 * other source files, but they are all so nicely encapsulated here.
1194 static struct bubble
*bbubbles
, *ebubbles
;
1196 static struct trap
*wportal
;
1197 static int xmin
, ymin
, xmax
, ymax
; /* level boundaries */
1198 /* bubble movement boundaries */
1199 #define bxmin (xmin + 1)
1200 #define bymin (ymin + 1)
1201 #define bxmax (xmax - 1)
1202 #define bymax (ymax - 1)
1204 STATIC_DCL
void NDECL(set_wportal
);
1205 STATIC_DCL
void FDECL(mk_bubble
, (int, int, int));
1206 STATIC_DCL
void FDECL(mv_bubble
, (struct bubble
*, int, int, BOOLEAN_P
));
1215 static const struct rm water_pos
= { cmap_to_glyph(S_water
), WATER
, 0, 0,
1217 static const struct rm air_pos
= { cmap_to_glyph(S_cloud
), AIR
, 0, 0, 0,
1220 /* set up the portal the first time bubbles are moved */
1226 if (Is_waterlevel(&u
.uz
)) {
1227 /* keep attached ball&chain separate from bubble objects */
1232 * Pick up everything inside of a bubble then fill all bubble
1235 for (b
= up
? bbubbles
: ebubbles
; b
; b
= up
? b
->next
: b
->prev
) {
1237 panic("movebubbles: cons != null");
1238 for (i
= 0, x
= b
->x
; i
< (int) b
->bm
[0]; i
++, x
++)
1239 for (j
= 0, y
= b
->y
; j
< (int) b
->bm
[1]; j
++, y
++)
1240 if (b
->bm
[j
+ 2] & (1 << i
)) {
1242 impossible("movebubbles: bad pos (%d,%d)", x
, y
);
1246 /* pick up objects, monsters, hero, and traps */
1248 struct obj
*olist
= (struct obj
*) 0, *otmp
;
1249 struct container
*cons
=
1250 (struct container
*) alloc(
1251 sizeof(struct container
));
1253 while ((otmp
= level
.objects
[x
][y
]) != 0) {
1254 remove_object(otmp
);
1255 otmp
->ox
= otmp
->oy
= 0;
1256 otmp
->nexthere
= olist
;
1262 cons
->what
= CONS_OBJ
;
1263 cons
->list
= (genericptr_t
) olist
;
1264 cons
->next
= b
->cons
;
1268 struct monst
*mon
= m_at(x
, y
);
1269 struct container
*cons
=
1270 (struct container
*) alloc(
1271 sizeof(struct container
));
1275 cons
->what
= CONS_MON
;
1276 cons
->list
= (genericptr_t
) mon
;
1278 cons
->next
= b
->cons
;
1284 remove_monster(x
, y
);
1286 newsym(x
, y
); /* clean up old position */
1287 mon
->mx
= mon
->my
= 0;
1289 if (!u
.uswallow
&& x
== u
.ux
&& y
== u
.uy
) {
1290 struct container
*cons
=
1291 (struct container
*) alloc(
1292 sizeof(struct container
));
1296 cons
->what
= CONS_HERO
;
1297 cons
->list
= (genericptr_t
) 0;
1299 cons
->next
= b
->cons
;
1302 if ((btrap
= t_at(x
, y
)) != 0) {
1303 struct container
*cons
=
1304 (struct container
*) alloc(
1305 sizeof(struct container
));
1309 cons
->what
= CONS_TRAP
;
1310 cons
->list
= (genericptr_t
) btrap
;
1312 cons
->next
= b
->cons
;
1316 levl
[x
][y
] = water_pos
;
1320 } else if (Is_airlevel(&u
.uz
)) {
1321 for (x
= 0; x
< COLNO
; x
++)
1322 for (y
= 0; y
< ROWNO
; y
++) {
1323 levl
[x
][y
] = air_pos
;
1324 unblock_point(x
, y
);
1329 * Every second time traverse down. This is because otherwise
1330 * all the junk that changes owners when bubbles overlap
1331 * would eventually end up in the last bubble in the chain.
1334 for (b
= up
? bbubbles
: ebubbles
; b
; b
= up
? b
->next
: b
->prev
) {
1335 int rx
= rn2(3), ry
= rn2(3);
1337 mv_bubble(b
, b
->dx
+ 1 - (!b
->dx
? rx
: (rx
? 1 : 0)),
1338 b
->dy
+ 1 - (!b
->dy
? ry
: (ry
? 1 : 0)), FALSE
);
1341 /* put attached ball&chain back */
1342 if (Is_waterlevel(&u
.uz
) && Punished
)
1344 vision_full_recalc
= 1;
1347 /* when moving in water, possibly (1 in 3) alter the intended destination */
1352 boolean eff
= FALSE
;
1354 if (Swimming
&& rn2(4))
1355 return; /* natural swimmers have advantage */
1357 if (u
.dx
&& !rn2(!u
.dy
? 3 : 6)) { /* 1/3 chance or half that */
1358 /* cancel delta x and choose an arbitrary delta y value */
1361 dy
= rn2(3) - 1; /* -1, 0, 1 */
1363 } while (dy
&& (!isok(x
, y
) || !is_pool(x
, y
)));
1367 } else if (u
.dy
&& !rn2(!u
.dx
? 3 : 5)) { /* 1/3 or 1/5*(5/6) */
1368 /* cancel delta y and choose an arbitrary delta x value */
1371 dx
= rn2(3) - 1; /* -1 .. 1 */
1373 } while (dx
&& (!isok(x
, y
) || !is_pool(x
, y
)));
1379 pline("Water turbulence affects your movements.");
1383 save_waterlevel(fd
, mode
)
1388 if (!Is_waterlevel(&u
.uz
) && !Is_airlevel(&u
.uz
))
1391 if (perform_bwrite(mode
)) {
1393 for (b
= bbubbles
; b
; b
= b
->next
)
1395 bwrite(fd
, (genericptr_t
) &n
, sizeof(int));
1396 bwrite(fd
, (genericptr_t
) &xmin
, sizeof(int));
1397 bwrite(fd
, (genericptr_t
) &ymin
, sizeof(int));
1398 bwrite(fd
, (genericptr_t
) &xmax
, sizeof(int));
1399 bwrite(fd
, (genericptr_t
) &ymax
, sizeof(int));
1400 for (b
= bbubbles
; b
; b
= b
->next
)
1401 bwrite(fd
, (genericptr_t
) b
, sizeof(struct bubble
));
1403 if (release_data(mode
))
1404 unsetup_waterlevel();
1408 restore_waterlevel(fd
)
1411 struct bubble
*b
= (struct bubble
*) 0, *btmp
;
1414 if (!Is_waterlevel(&u
.uz
) && !Is_airlevel(&u
.uz
))
1418 mread(fd
, (genericptr_t
) &n
, sizeof(int));
1419 mread(fd
, (genericptr_t
) &xmin
, sizeof(int));
1420 mread(fd
, (genericptr_t
) &ymin
, sizeof(int));
1421 mread(fd
, (genericptr_t
) &xmax
, sizeof(int));
1422 mread(fd
, (genericptr_t
) &ymax
, sizeof(int));
1423 for (i
= 0; i
< n
; i
++) {
1425 b
= (struct bubble
*) alloc(sizeof(struct bubble
));
1426 mread(fd
, (genericptr_t
) b
, sizeof(struct bubble
));
1432 b
->prev
= (struct bubble
*) 0;
1434 mv_bubble(b
, 0, 0, TRUE
);
1437 b
->next
= (struct bubble
*) 0;
1438 was_waterlevel
= TRUE
;
1442 waterbody_name(x
, y
)
1449 return "drink"; /* should never happen */
1452 if (ltyp
== DRAWBRIDGE_UP
)
1453 ltyp
= db_under_typ(lev
->drawbridgemask
);
1455 if (ltyp
== LAVAPOOL
)
1456 return hliquid("lava");
1457 else if (ltyp
== ICE
)
1459 else if (ltyp
== POOL
)
1460 return "pool of water";
1461 else if (ltyp
== WATER
|| Is_waterlevel(&u
.uz
))
1462 ; /* fall through to default return value */
1463 else if (Is_juiblex_level(&u
.uz
))
1465 else if (ltyp
== MOAT
&& !Is_medusa_level(&u
.uz
))
1468 return hliquid("water");
1474 /* there better be only one magic portal on water level... */
1475 for (wportal
= ftrap
; wportal
; wportal
= wportal
->ntrap
)
1476 if (wportal
->ttyp
== MAGIC_PORTAL
)
1478 impossible("set_wportal(): no portal!");
1486 int water_glyph
= cmap_to_glyph(S_water
),
1487 air_glyph
= cmap_to_glyph(S_air
);
1489 /* ouch, hardcoded... */
1496 /* set hero's memory to water */
1498 for (x
= xmin
; x
<= xmax
; x
++)
1499 for (y
= ymin
; y
<= ymax
; y
++)
1500 levl
[x
][y
].glyph
= Is_waterlevel(&u
.uz
) ? water_glyph
: air_glyph
;
1504 if (Is_waterlevel(&u
.uz
)) {
1505 xskip
= 10 + rn2(10);
1512 for (x
= bxmin
; x
<= bxmax
; x
+= xskip
)
1513 for (y
= bymin
; y
<= bymax
; y
+= yskip
)
1514 mk_bubble(x
, y
, rn2(7));
1518 unsetup_waterlevel()
1520 struct bubble
*b
, *bb
;
1524 for (b
= bbubbles
; b
; b
= bb
) {
1526 free((genericptr_t
) b
);
1528 bbubbles
= ebubbles
= (struct bubble
*) 0;
1536 * These bit masks make visually pleasing bubbles on a normal aspect
1537 * 25x80 terminal, which naturally results in them being mathematically
1538 * anything but symmetric. For this reason they cannot be computed
1539 * in situ, either. The first two elements tell the dimensions of
1540 * the bubble's bounding box.
1542 static uchar bm2
[] = { 2, 1, 0x3 },
1543 bm3
[] = { 3, 2, 0x7, 0x7 },
1544 bm4
[] = { 4, 3, 0x6, 0xf, 0x6 },
1545 bm5
[] = { 5, 3, 0xe, 0x1f, 0xe },
1546 bm6
[] = { 6, 4, 0x1e, 0x3f, 0x3f, 0x1e },
1547 bm7
[] = { 7, 4, 0x3e, 0x7f, 0x7f, 0x3e },
1548 bm8
[] = { 8, 4, 0x7e, 0xff, 0xff, 0x7e },
1549 *bmask
[] = { bm2
, bm3
, bm4
, bm5
, bm6
, bm7
, bm8
};
1552 if (x
>= bxmax
|| y
>= bymax
)
1554 if (n
>= SIZE(bmask
)) {
1555 impossible("n too large (mk_bubble)");
1556 n
= SIZE(bmask
) - 1;
1558 if (bmask
[n
][1] > MAX_BMASK
) {
1559 panic("bmask size is larger than MAX_BMASK");
1561 b
= (struct bubble
*) alloc(sizeof(struct bubble
));
1562 if ((x
+ (int) bmask
[n
][0] - 1) > bxmax
)
1563 x
= bxmax
- bmask
[n
][0] + 1;
1564 if ((y
+ (int) bmask
[n
][1] - 1) > bymax
)
1565 y
= bymax
- bmask
[n
][1] + 1;
1570 /* y dimension is the length of bitmap data - see bmask above */
1571 (void) memcpy((genericptr_t
) b
->bm
, (genericptr_t
) bmask
[n
],
1572 (bmask
[n
][1] + 2) * sizeof(b
->bm
[0]));
1580 b
->prev
= (struct bubble
*) 0;
1581 b
->next
= (struct bubble
*) 0;
1583 mv_bubble(b
, 0, 0, TRUE
);
1587 * The player, the portal and all other objects and monsters
1588 * float along with their associated bubbles. Bubbles may overlap
1589 * freely, and the contents may get associated with other bubbles in
1590 * the process. Bubbles are "sticky", meaning that if the player is
1591 * in the immediate neighborhood of one, he/she may get sucked inside.
1592 * This property also makes leaving a bubble slightly difficult.
1595 mv_bubble(b
, dx
, dy
, ini
)
1600 int x
, y
, i
, j
, colli
= 0;
1601 struct container
*cons
, *ctemp
;
1603 /* clouds move slowly */
1604 if (!Is_airlevel(&u
.uz
) || !rn2(6)) {
1606 if (dx
< -1 || dx
> 1 || dy
< -1 || dy
> 1) {
1607 /* pline("mv_bubble: dx = %d, dy = %d", dx, dy); */
1613 * collision with level borders?
1614 * 1 = horizontal border, 2 = vertical, 3 = corner
1620 if ((int) (b
->x
+ b
->bm
[0] - 1) >= bxmax
)
1622 if ((int) (b
->y
+ b
->bm
[1] - 1) >= bymax
)
1626 pline("bubble xmin: x = %d, xmin = %d", b
->x
, bxmin
);
1630 pline("bubble ymin: y = %d, ymin = %d", b
->y
, bymin
);
1633 if ((int) (b
->x
+ b
->bm
[0] - 1) > bxmax
) {
1634 pline("bubble xmax: x = %d, xmax = %d", b
->x
+ b
->bm
[0] - 1,
1636 b
->x
= bxmax
- b
->bm
[0] + 1;
1638 if ((int) (b
->y
+ b
->bm
[1] - 1) > bymax
) {
1639 pline("bubble ymax: y = %d, ymax = %d", b
->y
+ b
->bm
[1] - 1,
1641 b
->y
= bymax
- b
->bm
[1] + 1;
1644 /* bounce if we're trying to move off the border */
1645 if (b
->x
== bxmin
&& dx
< 0)
1647 if (b
->x
+ b
->bm
[0] - 1 == bxmax
&& dx
> 0)
1649 if (b
->y
== bymin
&& dy
< 0)
1651 if (b
->y
+ b
->bm
[1] - 1 == bymax
&& dy
> 0)
1658 /* draw the bubbles */
1659 for (i
= 0, x
= b
->x
; i
< (int) b
->bm
[0]; i
++, x
++)
1660 for (j
= 0, y
= b
->y
; j
< (int) b
->bm
[1]; j
++, y
++)
1661 if (b
->bm
[j
+ 2] & (1 << i
)) {
1662 if (Is_waterlevel(&u
.uz
)) {
1663 levl
[x
][y
].typ
= AIR
;
1665 unblock_point(x
, y
);
1666 } else if (Is_airlevel(&u
.uz
)) {
1667 levl
[x
][y
].typ
= CLOUD
;
1673 if (Is_waterlevel(&u
.uz
)) {
1674 /* replace contents of bubble */
1675 for (cons
= b
->cons
; cons
; cons
= ctemp
) {
1680 switch (cons
->what
) {
1682 struct obj
*olist
, *otmp
;
1684 for (olist
= (struct obj
*) cons
->list
; olist
; olist
= otmp
) {
1685 otmp
= olist
->nexthere
;
1686 place_object(olist
, cons
->x
, cons
->y
);
1692 struct monst
*mon
= (struct monst
*) cons
->list
;
1693 (void) mnearto(mon
, cons
->x
, cons
->y
, TRUE
);
1698 int ux0
= u
.ux
, uy0
= u
.uy
;
1700 /* change u.ux0 and u.uy0? */
1703 newsym(ux0
, uy0
); /* clean up old position */
1705 if (MON_AT(cons
->x
, cons
->y
)) {
1706 mnexto(m_at(cons
->x
, cons
->y
));
1712 struct trap
*btrap
= (struct trap
*) cons
->list
;
1713 btrap
->tx
= cons
->x
;
1714 btrap
->ty
= cons
->y
;
1719 impossible("mv_bubble: unknown bubble contents");
1722 free((genericptr_t
) cons
);
1733 b
->dy
= -b
->dy
; /* fall through */
1738 /* sometimes alter direction for fun anyway
1739 (higher probability for stationary bubbles) */
1740 if (!ini
&& ((b
->dx
|| b
->dy
) ? !rn2(20) : !rn2(5))) {