1 /* NetHack 3.6 mkmaze.c $NHDT-Date: 1461571093 2016/04/25 07:58:13 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.47 $ */
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 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
!= 0)
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 register 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 register 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;
623 register const char *s
;
627 s_level
*sp
= Is_special(&u
.uz
);
631 if (sp
&& sp
->rndlevs
)
632 Sprintf(protofile
, "%s-%d", s
, rnd((int) sp
->rndlevs
));
634 Strcpy(protofile
, s
);
635 } else if (*(dungeons
[u
.uz
.dnum
].proto
)) {
636 if (dunlevs_in_dungeon(&u
.uz
) > 1) {
637 if (sp
&& sp
->rndlevs
)
638 Sprintf(protofile
, "%s%d-%d", dungeons
[u
.uz
.dnum
].proto
,
639 dunlev(&u
.uz
), rnd((int) sp
->rndlevs
));
641 Sprintf(protofile
, "%s%d", dungeons
[u
.uz
.dnum
].proto
,
643 } else if (sp
&& sp
->rndlevs
) {
644 Sprintf(protofile
, "%s-%d", dungeons
[u
.uz
.dnum
].proto
,
645 rnd((int) sp
->rndlevs
));
647 Strcpy(protofile
, dungeons
[u
.uz
.dnum
].proto
);
650 Strcpy(protofile
, "");
652 /* SPLEVTYPE format is "level-choice,level-choice"... */
653 if (wizard
&& *protofile
&& sp
&& sp
->rndlevs
) {
654 char *ep
= getenv("SPLEVTYPE"); /* not nh_getenv */
656 /* rindex always succeeds due to code in prior block */
657 int len
= (int) ((rindex(protofile
, '-') - protofile
) + 1);
660 if (!strncmp(ep
, protofile
, len
)) {
661 int pick
= atoi(ep
+ len
);
662 /* use choice only if valid */
663 if (pick
> 0 && pick
<= (int) sp
->rndlevs
)
664 Sprintf(protofile
+ len
, "%d", pick
);
676 Strcat(protofile
, LEV_EXT
);
677 if (load_special(protofile
)) {
678 /* some levels can end up with monsters
679 on dead mon list, including light source monsters */
681 return; /* no mazification right now */
683 impossible("Couldn't load \"%s\" - making a maze.", protofile
);
686 level
.flags
.is_maze_lev
= TRUE
;
687 level
.flags
.corrmaze
= !rn2(3);
689 if (level
.flags
.corrmaze
)
690 for (x
= 2; x
< x_maze_max
; x
++)
691 for (y
= 2; y
< y_maze_max
; y
++)
692 levl
[x
][y
].typ
= STONE
;
694 for (x
= 2; x
<= x_maze_max
; x
++)
695 for (y
= 2; y
<= y_maze_max
; y
++)
696 levl
[x
][y
].typ
= ((x
% 2) && (y
% 2)) ? STONE
: HWALL
;
699 walkfrom((int) mm
.x
, (int) mm
.y
, 0);
700 /* put a boulder at the maze center */
701 (void) mksobj_at(BOULDER
, (int) mm
.x
, (int) mm
.y
, TRUE
, FALSE
);
703 if (!level
.flags
.corrmaze
)
704 wallification(2, 2, x_maze_max
, y_maze_max
);
707 mkstairs(mm
.x
, mm
.y
, 1, (struct mkroom
*) 0); /* up */
708 if (!Invocation_lev(&u
.uz
)) {
710 mkstairs(mm
.x
, mm
.y
, 0, (struct mkroom
*) 0); /* down */
711 } else { /* choose "vibrating square" location */
715 * Pick a position where the stairs down to Moloch's Sanctum
716 * level will ultimately be created. At that time, an area
717 * will be altered: walls removed, moat and traps generated,
718 * boulders destroyed. The position picked here must ensure
719 * that that invocation area won't extend off the map.
721 * We actually allow up to 2 squares around the usual edge of
722 * the area to get truncated; see mkinvokearea(mklev.c).
724 #define INVPOS_X_MARGIN (6 - 2)
725 #define INVPOS_Y_MARGIN (5 - 2)
726 #define INVPOS_DISTANCE 11
727 int x_range
= x_maze_max
- x_maze_min
- 2 * INVPOS_X_MARGIN
- 1,
728 y_range
= y_maze_max
- y_maze_min
- 2 * INVPOS_Y_MARGIN
- 1;
730 if (x_range
<= INVPOS_X_MARGIN
|| y_range
<= INVPOS_Y_MARGIN
731 || (x_range
* y_range
) <= (INVPOS_DISTANCE
* INVPOS_DISTANCE
)) {
732 debugpline2("inv_pos: maze is too small! (%d x %d)",
733 x_maze_max
, y_maze_max
);
735 inv_pos
.x
= inv_pos
.y
= 0; /*{occupied() => invocation_pos()}*/
737 x
= rn1(x_range
, x_maze_min
+ INVPOS_X_MARGIN
+ 1);
738 y
= rn1(y_range
, y_maze_min
+ INVPOS_Y_MARGIN
+ 1);
739 /* we don't want it to be too near the stairs, nor
740 to be on a spot that's already in use (wall|trap) */
741 } while (x
== xupstair
|| y
== yupstair
/*(direct line)*/
742 || abs(x
- xupstair
) == abs(y
- yupstair
)
743 || distmin(x
, y
, xupstair
, yupstair
) <= INVPOS_DISTANCE
744 || !SPACE_POS(levl
[x
][y
].typ
) || occupied(x
, y
));
747 maketrap(inv_pos
.x
, inv_pos
.y
, VIBRATING_SQUARE
);
748 #undef INVPOS_X_MARGIN
749 #undef INVPOS_Y_MARGIN
750 #undef INVPOS_DISTANCE
755 /* place branch stair or portal */
756 place_branch(Is_branchlev(&u
.uz
), 0, 0);
758 for (x
= rn1(8, 11); x
; x
--) {
760 (void) mkobj_at(rn2(2) ? GEM_CLASS
: 0, mm
.x
, mm
.y
, TRUE
);
762 for (x
= rn1(10, 2); x
; x
--) {
764 (void) mksobj_at(BOULDER
, mm
.x
, mm
.y
, TRUE
, FALSE
);
766 for (x
= rn2(3); x
; x
--) {
768 (void) makemon(&mons
[PM_MINOTAUR
], mm
.x
, mm
.y
, NO_MM_FLAGS
);
770 for (x
= rn1(5, 7); x
; x
--) {
772 (void) makemon((struct permonst
*) 0, mm
.x
, mm
.y
, NO_MM_FLAGS
);
774 for (x
= rn1(6, 7); x
; x
--) {
776 (void) mkgold(0L, mm
.x
, mm
.y
);
778 for (x
= rn1(6, 7); x
; x
--)
779 mktrap(0, 1, (struct mkroom
*) 0, (coord
*) 0);
783 /* Make the mazewalk iterative by faking a stack. This is needed to
784 * ensure the mazewalk is successful in the limited stack space of
785 * the program. This iterative version uses the minimum amount of stack
786 * that is totally safe.
793 #define CELLS (ROWNO * COLNO) / 4 /* a maze cell is 4 squares */
794 char mazex
[CELLS
+ 1], mazey
[CELLS
+ 1]; /* char's are OK */
799 if (level
.flags
.corrmaze
)
806 mazex
[pos
] = (char) x
;
807 mazey
[pos
] = (char) y
;
809 x
= (int) mazex
[pos
];
810 y
= (int) mazey
[pos
];
811 if (!IS_DOOR(levl
[x
][y
].typ
)) {
812 /* might still be on edge of MAP, so don't overwrite */
813 levl
[x
][y
].typ
= typ
;
814 levl
[x
][y
].flags
= 0;
817 for (a
= 0; a
< 4; a
++)
825 levl
[x
][y
].typ
= typ
;
829 panic("Overflow in walkfrom");
830 mazex
[pos
] = (char) x
;
831 mazey
[pos
] = (char) y
;
842 register int q
, a
, dir
;
846 if (level
.flags
.corrmaze
)
852 if (!IS_DOOR(levl
[x
][y
].typ
)) {
853 /* might still be on edge of MAP, so don't overwrite */
854 levl
[x
][y
].typ
= typ
;
855 levl
[x
][y
].flags
= 0;
860 for (a
= 0; a
< 4; a
++)
867 levl
[x
][y
].typ
= typ
;
874 /* find random point in generated corridors,
875 so we don't create items in moats, bunkers, or walls */
883 cc
->x
= 3 + 2 * rn2((x_maze_max
>> 1) - 1);
884 cc
->y
= 3 + 2 * rn2((y_maze_max
>> 1) - 1);
887 && levl
[cc
->x
][cc
->y
].typ
888 != (level
.flags
.corrmaze
? CORR
: ROOM
));
892 for (x
= 0; x
< (x_maze_max
>> 1) - 1; x
++)
893 for (y
= 0; y
< (y_maze_max
>> 1) - 1; y
++) {
896 if (levl
[cc
->x
][cc
->y
].typ
897 == (level
.flags
.corrmaze
? CORR
: ROOM
))
900 panic("mazexy: can't find a place!");
905 /* put a non-diggable boundary around the initial portion of a level map.
906 * assumes that no level will initially put things beyond the isok() range.
908 * we can't bound unconditionally on the last line with something in it,
909 * because that something might be a niche which was already reachable,
910 * so the boundary would be breached
912 * we can't bound unconditionally on one beyond the last line, because
913 * that provides a window of abuse for wallified special levels
919 register unsigned typ
;
920 register struct rm
*lev
;
921 boolean found
, nonwall
;
922 int xmin
, xmax
, ymin
, ymax
;
924 if (Is_earthlevel(&u
.uz
))
925 return; /* everything diggable here */
927 found
= nonwall
= FALSE
;
928 for (xmin
= 0; !found
&& xmin
<= COLNO
; xmin
++) {
929 lev
= &levl
[xmin
][0];
930 for (y
= 0; y
<= ROWNO
- 1; y
++, lev
++) {
939 xmin
-= (nonwall
|| !level
.flags
.is_maze_lev
) ? 2 : 1;
943 found
= nonwall
= FALSE
;
944 for (xmax
= COLNO
- 1; !found
&& xmax
>= 0; xmax
--) {
945 lev
= &levl
[xmax
][0];
946 for (y
= 0; y
<= ROWNO
- 1; y
++, lev
++) {
955 xmax
+= (nonwall
|| !level
.flags
.is_maze_lev
) ? 2 : 1;
959 found
= nonwall
= FALSE
;
960 for (ymin
= 0; !found
&& ymin
<= ROWNO
; ymin
++) {
961 lev
= &levl
[xmin
][ymin
];
962 for (x
= xmin
; x
<= xmax
; x
++, lev
+= ROWNO
) {
971 ymin
-= (nonwall
|| !level
.flags
.is_maze_lev
) ? 2 : 1;
973 found
= nonwall
= FALSE
;
974 for (ymax
= ROWNO
- 1; !found
&& ymax
>= 0; ymax
--) {
975 lev
= &levl
[xmin
][ymax
];
976 for (x
= xmin
; x
<= xmax
; x
++, lev
+= ROWNO
) {
985 ymax
+= (nonwall
|| !level
.flags
.is_maze_lev
) ? 2 : 1;
987 for (x
= 0; x
< COLNO
; x
++)
988 for (y
= 0; y
< ROWNO
; y
++)
989 if (y
<= ymin
|| y
>= ymax
|| x
<= xmin
|| x
>= xmax
) {
992 lev
->wall_info
|= W_NONDIGGABLE
;
994 levl
[x
][y
].wall_info
|= W_NONDIGGABLE
;
1000 mkportal(x
, y
, todnum
, todlevel
)
1001 xchar x
, y
, todnum
, todlevel
;
1003 /* a portal "trap" must be matched by a
1004 portal in the destination dungeon/dlevel */
1005 struct trap
*ttmp
= maketrap(x
, y
, MAGIC_PORTAL
);
1008 impossible("portal on top of portal??");
1011 debugpline4("mkportal: at <%d,%d>, to %s, level %d", x
, y
,
1012 dungeons
[todnum
].dname
, todlevel
);
1013 ttmp
->dst
.dnum
= todnum
;
1014 ttmp
->dst
.dlevel
= todlevel
;
1022 boolean snd
= FALSE
, loud
= FALSE
;
1024 for (n
= rn2(3) + 2; n
; n
--) {
1025 xchar x
= rn1(COLNO
- 4, 3);
1026 xchar y
= rn1(ROWNO
- 4, 3);
1027 if (levl
[x
][y
].typ
== LAVAPOOL
) {
1028 NhRegion
*r
= create_gas_cloud(x
, y
, 4 + rn2(5), rn1(10, 5));
1029 clear_heros_fault(r
);
1031 if (distu(x
, y
) < 15)
1036 Norep("You hear a %swhoosh!", loud
? "loud " : "");
1040 * Special waterlevel stuff in endgame (TH).
1042 * Some of these functions would probably logically belong to some
1043 * other source files, but they are all so nicely encapsulated here.
1047 /* to ease the work of debuggers at this stage */
1056 static struct bubble
*bbubbles
, *ebubbles
;
1058 static struct trap
*wportal
;
1059 static int xmin
, ymin
, xmax
, ymax
; /* level boundaries */
1060 /* bubble movement boundaries */
1061 #define bxmin (xmin + 1)
1062 #define bymin (ymin + 1)
1063 #define bxmax (xmax - 1)
1064 #define bymax (ymax - 1)
1066 STATIC_DCL
void NDECL(set_wportal
);
1067 STATIC_DCL
void FDECL(mk_bubble
, (int, int, int));
1068 STATIC_DCL
void FDECL(mv_bubble
, (struct bubble
*, int, int, BOOLEAN_P
));
1074 register struct bubble
*b
;
1075 register int x
, y
, i
, j
;
1077 static const struct rm water_pos
= { cmap_to_glyph(S_water
), WATER
, 0, 0,
1079 static const struct rm air_pos
= { cmap_to_glyph(S_cloud
), AIR
, 0, 0, 0,
1082 /* set up the portal the first time bubbles are moved */
1088 if (Is_waterlevel(&u
.uz
)) {
1089 /* keep attached ball&chain separate from bubble objects */
1094 * Pick up everything inside of a bubble then fill all bubble
1097 for (b
= up
? bbubbles
: ebubbles
; b
; b
= up
? b
->next
: b
->prev
) {
1099 panic("movebubbles: cons != null");
1100 for (i
= 0, x
= b
->x
; i
< (int) b
->bm
[0]; i
++, x
++)
1101 for (j
= 0, y
= b
->y
; j
< (int) b
->bm
[1]; j
++, y
++)
1102 if (b
->bm
[j
+ 2] & (1 << i
)) {
1104 impossible("movebubbles: bad pos (%d,%d)", x
, y
);
1108 /* pick up objects, monsters, hero, and traps */
1110 struct obj
*olist
= (struct obj
*) 0, *otmp
;
1111 struct container
*cons
=
1112 (struct container
*) alloc(
1113 sizeof(struct container
));
1115 while ((otmp
= level
.objects
[x
][y
]) != 0) {
1116 remove_object(otmp
);
1117 otmp
->ox
= otmp
->oy
= 0;
1118 otmp
->nexthere
= olist
;
1124 cons
->what
= CONS_OBJ
;
1125 cons
->list
= (genericptr_t
) olist
;
1126 cons
->next
= b
->cons
;
1130 struct monst
*mon
= m_at(x
, y
);
1131 struct container
*cons
=
1132 (struct container
*) alloc(
1133 sizeof(struct container
));
1137 cons
->what
= CONS_MON
;
1138 cons
->list
= (genericptr_t
) mon
;
1140 cons
->next
= b
->cons
;
1146 remove_monster(x
, y
);
1148 newsym(x
, y
); /* clean up old position */
1149 mon
->mx
= mon
->my
= 0;
1151 if (!u
.uswallow
&& x
== u
.ux
&& y
== u
.uy
) {
1152 struct container
*cons
=
1153 (struct container
*) alloc(
1154 sizeof(struct container
));
1158 cons
->what
= CONS_HERO
;
1159 cons
->list
= (genericptr_t
) 0;
1161 cons
->next
= b
->cons
;
1164 if ((btrap
= t_at(x
, y
)) != 0) {
1165 struct container
*cons
=
1166 (struct container
*) alloc(
1167 sizeof(struct container
));
1171 cons
->what
= CONS_TRAP
;
1172 cons
->list
= (genericptr_t
) btrap
;
1174 cons
->next
= b
->cons
;
1178 levl
[x
][y
] = water_pos
;
1182 } else if (Is_airlevel(&u
.uz
)) {
1183 for (x
= 0; x
< COLNO
; x
++)
1184 for (y
= 0; y
< ROWNO
; y
++) {
1185 levl
[x
][y
] = air_pos
;
1186 unblock_point(x
, y
);
1191 * Every second time traverse down. This is because otherwise
1192 * all the junk that changes owners when bubbles overlap
1193 * would eventually end up in the last bubble in the chain.
1196 for (b
= up
? bbubbles
: ebubbles
; b
; b
= up
? b
->next
: b
->prev
) {
1197 register int rx
= rn2(3), ry
= rn2(3);
1199 mv_bubble(b
, b
->dx
+ 1 - (!b
->dx
? rx
: (rx
? 1 : 0)),
1200 b
->dy
+ 1 - (!b
->dy
? ry
: (ry
? 1 : 0)), FALSE
);
1203 /* put attached ball&chain back */
1204 if (Is_waterlevel(&u
.uz
) && Punished
)
1206 vision_full_recalc
= 1;
1209 /* when moving in water, possibly (1 in 3) alter the intended destination */
1213 register int x
, y
, dx
, dy
;
1214 register boolean eff
= FALSE
;
1216 if (Swimming
&& rn2(4))
1217 return; /* natural swimmers have advantage */
1219 if (u
.dx
&& !rn2(!u
.dy
? 3 : 6)) { /* 1/3 chance or half that */
1220 /* cancel delta x and choose an arbitrary delta y value */
1223 dy
= rn2(3) - 1; /* -1, 0, 1 */
1225 } while (dy
&& (!isok(x
, y
) || !is_pool(x
, y
)));
1229 } else if (u
.dy
&& !rn2(!u
.dx
? 3 : 5)) { /* 1/3 or 1/5*(5/6) */
1230 /* cancel delta y and choose an arbitrary delta x value */
1233 dx
= rn2(3) - 1; /* -1 .. 1 */
1235 } while (dx
&& (!isok(x
, y
) || !is_pool(x
, y
)));
1241 pline("Water turbulence affects your movements.");
1245 save_waterlevel(fd
, mode
)
1248 register struct bubble
*b
;
1250 if (!Is_waterlevel(&u
.uz
) && !Is_airlevel(&u
.uz
))
1253 if (perform_bwrite(mode
)) {
1255 for (b
= bbubbles
; b
; b
= b
->next
)
1257 bwrite(fd
, (genericptr_t
) &n
, sizeof(int));
1258 bwrite(fd
, (genericptr_t
) &xmin
, sizeof(int));
1259 bwrite(fd
, (genericptr_t
) &ymin
, sizeof(int));
1260 bwrite(fd
, (genericptr_t
) &xmax
, sizeof(int));
1261 bwrite(fd
, (genericptr_t
) &ymax
, sizeof(int));
1262 for (b
= bbubbles
; b
; b
= b
->next
)
1263 bwrite(fd
, (genericptr_t
) b
, sizeof(struct bubble
));
1265 if (release_data(mode
))
1266 unsetup_waterlevel();
1270 restore_waterlevel(fd
)
1273 register struct bubble
*b
= (struct bubble
*) 0, *btmp
;
1277 if (!Is_waterlevel(&u
.uz
) && !Is_airlevel(&u
.uz
))
1281 mread(fd
, (genericptr_t
) &n
, sizeof(int));
1282 mread(fd
, (genericptr_t
) &xmin
, sizeof(int));
1283 mread(fd
, (genericptr_t
) &ymin
, sizeof(int));
1284 mread(fd
, (genericptr_t
) &xmax
, sizeof(int));
1285 mread(fd
, (genericptr_t
) &ymax
, sizeof(int));
1286 for (i
= 0; i
< n
; i
++) {
1288 b
= (struct bubble
*) alloc(sizeof(struct bubble
));
1289 mread(fd
, (genericptr_t
) b
, sizeof(struct bubble
));
1295 b
->prev
= (struct bubble
*) 0;
1297 mv_bubble(b
, 0, 0, TRUE
);
1300 b
->next
= (struct bubble
*) 0;
1301 was_waterlevel
= TRUE
;
1305 waterbody_name(x
, y
)
1308 register struct rm
*lev
;
1312 return "drink"; /* should never happen */
1315 if (ltyp
== DRAWBRIDGE_UP
)
1316 ltyp
= db_under_typ(lev
->drawbridgemask
);
1318 if (ltyp
== LAVAPOOL
)
1320 else if (ltyp
== ICE
)
1322 else if (ltyp
== POOL
)
1323 return "pool of water";
1324 else if (ltyp
== WATER
|| Is_waterlevel(&u
.uz
))
1325 ; /* fall through to default return value */
1326 else if (Is_juiblex_level(&u
.uz
))
1328 else if (ltyp
== MOAT
&& !Is_medusa_level(&u
.uz
))
1337 /* there better be only one magic portal on water level... */
1338 for (wportal
= ftrap
; wportal
; wportal
= wportal
->ntrap
)
1339 if (wportal
->ttyp
== MAGIC_PORTAL
)
1341 impossible("set_wportal(): no portal!");
1348 register int xskip
, yskip
;
1349 register int water_glyph
= cmap_to_glyph(S_water
);
1350 register int air_glyph
= cmap_to_glyph(S_air
);
1352 /* ouch, hardcoded... */
1359 /* set hero's memory to water */
1361 for (x
= xmin
; x
<= xmax
; x
++)
1362 for (y
= ymin
; y
<= ymax
; y
++)
1363 levl
[x
][y
].glyph
= Is_waterlevel(&u
.uz
) ? water_glyph
: air_glyph
;
1367 if (Is_waterlevel(&u
.uz
)) {
1368 xskip
= 10 + rn2(10);
1375 for (x
= bxmin
; x
<= bxmax
; x
+= xskip
)
1376 for (y
= bymin
; y
<= bymax
; y
+= yskip
)
1377 mk_bubble(x
, y
, rn2(7));
1381 unsetup_waterlevel()
1383 register struct bubble
*b
, *bb
;
1387 for (b
= bbubbles
; b
; b
= bb
) {
1389 free((genericptr_t
) b
);
1391 bbubbles
= ebubbles
= (struct bubble
*) 0;
1396 register int x
, y
, n
;
1399 * These bit masks make visually pleasing bubbles on a normal aspect
1400 * 25x80 terminal, which naturally results in them being mathematically
1401 * anything but symmetric. For this reason they cannot be computed
1402 * in situ, either. The first two elements tell the dimensions of
1403 * the bubble's bounding box.
1405 static uchar bm2
[] = { 2, 1, 0x3 }, bm3
[] = { 3, 2, 0x7, 0x7 },
1406 bm4
[] = { 4, 3, 0x6, 0xf, 0x6 },
1407 bm5
[] = { 5, 3, 0xe, 0x1f, 0xe },
1408 bm6
[] = { 6, 4, 0x1e, 0x3f, 0x3f, 0x1e },
1409 bm7
[] = { 7, 4, 0x3e, 0x7f, 0x7f, 0x3e },
1410 bm8
[] = { 8, 4, 0x7e, 0xff, 0xff, 0x7e },
1411 *bmask
[] = { bm2
, bm3
, bm4
, bm5
, bm6
, bm7
, bm8
};
1412 register struct bubble
*b
;
1414 if (x
>= bxmax
|| y
>= bymax
)
1416 if (n
>= SIZE(bmask
)) {
1417 impossible("n too large (mk_bubble)");
1418 n
= SIZE(bmask
) - 1;
1420 if (bmask
[n
][1] > MAX_BMASK
) {
1421 panic("bmask size is larger than MAX_BMASK");
1423 b
= (struct bubble
*) alloc(sizeof(struct bubble
));
1424 if ((x
+ (int) bmask
[n
][0] - 1) > bxmax
)
1425 x
= bxmax
- bmask
[n
][0] + 1;
1426 if ((y
+ (int) bmask
[n
][1] - 1) > bymax
)
1427 y
= bymax
- bmask
[n
][1] + 1;
1432 /* y dimension is the length of bitmap data - see bmask above */
1433 (void) memcpy((genericptr_t
) b
->bm
, (genericptr_t
) bmask
[n
],
1434 (bmask
[n
][1] + 2) * sizeof(b
->bm
[0]));
1442 b
->prev
= (struct bubble
*) 0;
1443 b
->next
= (struct bubble
*) 0;
1445 mv_bubble(b
, 0, 0, TRUE
);
1449 * The player, the portal and all other objects and monsters
1450 * float along with their associated bubbles. Bubbles may overlap
1451 * freely, and the contents may get associated with other bubbles in
1452 * the process. Bubbles are "sticky", meaning that if the player is
1453 * in the immediate neighborhood of one, he/she may get sucked inside.
1454 * This property also makes leaving a bubble slightly difficult.
1457 mv_bubble(b
, dx
, dy
, ini
)
1458 register struct bubble
*b
;
1459 register int dx
, dy
;
1460 register boolean ini
;
1462 register int x
, y
, i
, j
, colli
= 0;
1463 struct container
*cons
, *ctemp
;
1465 /* clouds move slowly */
1466 if (!Is_airlevel(&u
.uz
) || !rn2(6)) {
1468 if (dx
< -1 || dx
> 1 || dy
< -1 || dy
> 1) {
1469 /* pline("mv_bubble: dx = %d, dy = %d", dx, dy); */
1475 * collision with level borders?
1476 * 1 = horizontal border, 2 = vertical, 3 = corner
1482 if ((int) (b
->x
+ b
->bm
[0] - 1) >= bxmax
)
1484 if ((int) (b
->y
+ b
->bm
[1] - 1) >= bymax
)
1488 pline("bubble xmin: x = %d, xmin = %d", b
->x
, bxmin
);
1492 pline("bubble ymin: y = %d, ymin = %d", b
->y
, bymin
);
1495 if ((int) (b
->x
+ b
->bm
[0] - 1) > bxmax
) {
1496 pline("bubble xmax: x = %d, xmax = %d", b
->x
+ b
->bm
[0] - 1,
1498 b
->x
= bxmax
- b
->bm
[0] + 1;
1500 if ((int) (b
->y
+ b
->bm
[1] - 1) > bymax
) {
1501 pline("bubble ymax: y = %d, ymax = %d", b
->y
+ b
->bm
[1] - 1,
1503 b
->y
= bymax
- b
->bm
[1] + 1;
1506 /* bounce if we're trying to move off the border */
1507 if (b
->x
== bxmin
&& dx
< 0)
1509 if (b
->x
+ b
->bm
[0] - 1 == bxmax
&& dx
> 0)
1511 if (b
->y
== bymin
&& dy
< 0)
1513 if (b
->y
+ b
->bm
[1] - 1 == bymax
&& dy
> 0)
1520 /* draw the bubbles */
1521 for (i
= 0, x
= b
->x
; i
< (int) b
->bm
[0]; i
++, x
++)
1522 for (j
= 0, y
= b
->y
; j
< (int) b
->bm
[1]; j
++, y
++)
1523 if (b
->bm
[j
+ 2] & (1 << i
)) {
1524 if (Is_waterlevel(&u
.uz
)) {
1525 levl
[x
][y
].typ
= AIR
;
1527 unblock_point(x
, y
);
1528 } else if (Is_airlevel(&u
.uz
)) {
1529 levl
[x
][y
].typ
= CLOUD
;
1535 if (Is_waterlevel(&u
.uz
)) {
1536 /* replace contents of bubble */
1537 for (cons
= b
->cons
; cons
; cons
= ctemp
) {
1542 switch (cons
->what
) {
1544 struct obj
*olist
, *otmp
;
1546 for (olist
= (struct obj
*) cons
->list
; olist
; olist
= otmp
) {
1547 otmp
= olist
->nexthere
;
1548 place_object(olist
, cons
->x
, cons
->y
);
1554 struct monst
*mon
= (struct monst
*) cons
->list
;
1555 (void) mnearto(mon
, cons
->x
, cons
->y
, TRUE
);
1560 int ux0
= u
.ux
, uy0
= u
.uy
;
1562 /* change u.ux0 and u.uy0? */
1565 newsym(ux0
, uy0
); /* clean up old position */
1567 if (MON_AT(cons
->x
, cons
->y
)) {
1568 mnexto(m_at(cons
->x
, cons
->y
));
1574 struct trap
*btrap
= (struct trap
*) cons
->list
;
1575 btrap
->tx
= cons
->x
;
1576 btrap
->ty
= cons
->y
;
1581 impossible("mv_bubble: unknown bubble contents");
1584 free((genericptr_t
) cons
);
1595 b
->dy
= -b
->dy
; /* fall through */
1600 /* sometimes alter direction for fun anyway
1601 (higher probability for stationary bubbles) */
1602 if (!ini
&& ((b
->dx
|| b
->dy
) ? !rn2(20) : !rn2(5))) {