1 /* SCCS Id: @(#)mkmaze.c 3.3 2000/01/03 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 #include "hack.h"
6 #include "sp_lev.h"
7 #include "lev.h" /* save & restore info */
8
9 /* from sp_lev.c, for fixup_special() */
10 extern char *lev_message;
11 extern lev_region *lregions;
12 extern int num_lregions;
13
14 STATIC_DCL boolean FDECL(iswall,(int,int));
15 STATIC_DCL boolean FDECL(iswall_or_stone,(int,int));
16 STATIC_DCL boolean FDECL(is_solid,(int,int));
17 STATIC_DCL int FDECL(extend_spine, (int [3][3], int, int, int));
18 STATIC_DCL boolean FDECL(okay,(int,int,int));
19 STATIC_DCL void FDECL(maze0xy,(coord *));
20 STATIC_DCL boolean FDECL(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 void NDECL(fixup_special);
23 STATIC_DCL void FDECL(move, (int *,int *,int));
24 STATIC_DCL void NDECL(setup_waterlevel);
25 STATIC_DCL void NDECL(unsetup_waterlevel);
26
27
28 STATIC_OVL boolean
iswall(x,y)29 iswall(x,y)
30 int x,y;
31 {
32 if (!isok(x,y)) return FALSE;
33 return (IS_WALL(levl[x][y].typ) || IS_DOOR(levl[x][y].typ)
34 || levl[x][y].typ == SDOOR);
35 }
36
37 STATIC_OVL boolean
iswall_or_stone(x,y)38 iswall_or_stone(x,y)
39 int x,y;
40 {
41 register int type;
42
43 /* out of bounds = stone */
44 if (!isok(x,y)) return TRUE;
45
46 type = levl[x][y].typ;
47 return (type == STONE || IS_WALL(type) || IS_DOOR(type) || type == SDOOR);
48 }
49
50 /* return TRUE if out of bounds, wall or rock */
51 STATIC_OVL boolean
is_solid(x,y)52 is_solid(x,y)
53 int x, y;
54 {
55 return (!isok(x,y) || IS_STWALL(levl[x][y].typ));
56 }
57
58
59 /*
60 * Return 1 (not TRUE - we're doing bit vectors here) if we want to extend
61 * a wall spine in the (dx,dy) direction. Return 0 otherwise.
62 *
63 * To extend a wall spine in that direction, first there must be a wall there.
64 * Then, extend a spine unless the current position is surrounded by walls
65 * in the direction given by (dx,dy). E.g. if 'x' is our location, 'W'
66 * a wall, '.' a room, 'a' anything (we don't care), and our direction is
67 * (0,1) - South or down - then:
68 *
69 * a a a
70 * W x W This would not extend a spine from x down
71 * W W W (a corridor of walls is formed).
72 *
73 * a a a
74 * W x W This would extend a spine from x down.
75 * . W W
76 */
77 STATIC_OVL int
extend_spine(locale,wall_there,dx,dy)78 extend_spine(locale, wall_there, dx, dy)
79 int locale[3][3];
80 int wall_there, dx, dy;
81 {
82 int spine, nx, ny;
83
84 nx = 1 + dx;
85 ny = 1 + dy;
86
87 if (wall_there) { /* wall in that direction */
88 if (dx) {
89 if (locale[ 1][0] && locale[ 1][2] && /* EW are wall/stone */
90 locale[nx][0] && locale[nx][2]) { /* diag are wall/stone */
91 spine = 0;
92 } else {
93 spine = 1;
94 }
95 } else { /* dy */
96 if (locale[0][ 1] && locale[2][ 1] && /* NS are wall/stone */
97 locale[0][ny] && locale[2][ny]) { /* diag are wall/stone */
98 spine = 0;
99 } else {
100 spine = 1;
101 }
102 }
103 } else {
104 spine = 0;
105 }
106
107 return spine;
108 }
109
110
111 /*
112 * Wall cleanup. This function has two purposes: (1) remove walls that
113 * are totally surrounded by stone - they are redundant. (2) correct
114 * the types so that they extend and connect to each other.
115 */
116 void
wallification(x1,y1,x2,y2)117 wallification(x1, y1, x2, y2)
118 int x1, y1, x2, y2;
119 {
120 uchar type;
121 register int x,y;
122 struct rm *lev;
123 int bits;
124 int locale[3][3]; /* rock or wall status surrounding positions */
125 /*
126 * Value 0 represents a free-standing wall. It could be anything,
127 * so even though this table says VWALL, we actually leave whatever
128 * typ was there alone.
129 */
130 static xchar spine_array[16] = {
131 VWALL, HWALL, HWALL, HWALL,
132 VWALL, TRCORNER, TLCORNER, TDWALL,
133 VWALL, BRCORNER, BLCORNER, TUWALL,
134 VWALL, TLWALL, TRWALL, CROSSWALL
135 };
136
137 /* sanity check on incoming variables */
138 if (x1<0 || x2>=COLNO || x1>x2 || y1<0 || y2>=ROWNO || y1>y2)
139 panic("wallification: bad bounds (%d,%d) to (%d,%d)",x1,y1,x2,y2);
140
141 /* Step 1: change walls surrounded by rock to rock. */
142 for(x = x1; x <= x2; x++)
143 for(y = y1; y <= y2; y++) {
144 lev = &levl[x][y];
145 type = lev->typ;
146 if (IS_WALL(type) && type != DBWALL) {
147 if (is_solid(x-1,y-1) &&
148 is_solid(x-1,y ) &&
149 is_solid(x-1,y+1) &&
150 is_solid(x, y-1) &&
151 is_solid(x, y+1) &&
152 is_solid(x+1,y-1) &&
153 is_solid(x+1,y ) &&
154 is_solid(x+1,y+1))
155 lev->typ = STONE;
156 }
157 }
158
159 /*
160 * Step 2: set the correct wall type. We can't combine steps
161 * 1 and 2 into a single sweep because we depend on knowing if
162 * the surrounding positions are stone.
163 */
164 for(x = x1; x <= x2; x++)
165 for(y = y1; y <= y2; y++) {
166 lev = &levl[x][y];
167 type = lev->typ;
168 if ( !(IS_WALL(type) && type != DBWALL)) continue;
169
170 /* set the locations TRUE if rock or wall or out of bounds */
171 locale[0][0] = iswall_or_stone(x-1,y-1);
172 locale[1][0] = iswall_or_stone( x,y-1);
173 locale[2][0] = iswall_or_stone(x+1,y-1);
174
175 locale[0][1] = iswall_or_stone(x-1, y);
176 locale[2][1] = iswall_or_stone(x+1, y);
177
178 locale[0][2] = iswall_or_stone(x-1,y+1);
179 locale[1][2] = iswall_or_stone( x,y+1);
180 locale[2][2] = iswall_or_stone(x+1,y+1);
181
182 /* determine if wall should extend to each direction NSEW */
183 bits = (extend_spine(locale, iswall(x,y-1), 0, -1) << 3)
184 | (extend_spine(locale, iswall(x,y+1), 0, 1) << 2)
185 | (extend_spine(locale, iswall(x+1,y), 1, 0) << 1)
186 | extend_spine(locale, iswall(x-1,y), -1, 0);
187
188 /* don't change typ if wall is free-standing */
189 if (bits) lev->typ = spine_array[bits];
190 }
191 }
192
193 STATIC_OVL boolean
okay(x,y,dir)194 okay(x,y,dir)
195 int x,y;
196 register int dir;
197 {
198 move(&x,&y,dir);
199 move(&x,&y,dir);
200 if(x<3 || y<3 || x>x_maze_max || y>y_maze_max || levl[x][y].typ != 0)
201 return(FALSE);
202 return(TRUE);
203 }
204
205 STATIC_OVL void
maze0xy(cc)206 maze0xy(cc) /* find random starting point for maze generation */
207 coord *cc;
208 {
209 cc->x = 3 + 2*rn2((x_maze_max>>1) - 1);
210 cc->y = 3 + 2*rn2((y_maze_max>>1) - 1);
211 return;
212 }
213
214 /*
215 * Bad if:
216 * pos is occupied OR
217 * pos is inside restricted region (lx,ly,hx,hy) OR
218 * NOT (pos is corridor and a maze level OR pos is a room OR pos is air)
219 */
220 boolean
bad_location(x,y,lx,ly,hx,hy)221 bad_location(x, y, lx, ly, hx, hy)
222 xchar x, y;
223 xchar lx, ly, hx, hy;
224 {
225 return((boolean)(occupied(x, y) ||
226 within_bounded_area(x,y, lx,ly, hx,hy) ||
227 !((levl[x][y].typ == CORR && level.flags.is_maze_lev) ||
228 levl[x][y].typ == ROOM || levl[x][y].typ == AIR)));
229 }
230
231 /* pick a location in area (lx, ly, hx, hy) but not in (nlx, nly, nhx, nhy) */
232 /* and place something (based on rtype) in that region */
233 void
place_lregion(lx,ly,hx,hy,nlx,nly,nhx,nhy,rtype,lev)234 place_lregion(lx, ly, hx, hy, nlx, nly, nhx, nhy, rtype, lev)
235 xchar lx, ly, hx, hy;
236 xchar nlx, nly, nhx, nhy;
237 xchar rtype;
238 d_level *lev;
239 {
240 int trycnt;
241 boolean oneshot;
242 xchar x, y;
243
244 if(!lx) { /* default to whole level */
245 /*
246 * if there are rooms and this a branch, let place_branch choose
247 * the branch location (to avoid putting branches in corridors).
248 */
249 if(rtype == LR_BRANCH && nroom) {
250 place_branch(Is_branchlev(&u.uz), 0, 0);
251 return;
252 }
253
254 lx = 1; hx = COLNO-1;
255 ly = 1; hy = ROWNO-1;
256 }
257
258 /* first a probabilistic approach */
259
260 oneshot = (lx == hx && ly == hy);
261 for(trycnt = 0; trycnt < 100; trycnt ++) {
262
263 x = rn1((hx - lx) + 1, lx);
264 y = rn1((hy - ly) + 1, ly);
265
266 if (put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev))
267 return;
268 }
269
270 /* then a deterministic one */
271
272 oneshot = TRUE;
273 for (x = lx; x <= hx; x++)
274 for (y = ly; y <= hy; y++)
275 if (put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev))
276 return;
277
278 impossible("Couldn't place lregion type %d!", rtype);
279 }
280
281 STATIC_OVL boolean
put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev)282 put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev)
283 xchar x, y;
284 xchar nlx, nly, nhx, nhy;
285 xchar rtype;
286 boolean oneshot;
287 d_level *lev;
288 {
289 if(oneshot) {
290 /* must make due with the only location possible */
291 /* avoid failure due to a misplaced trap */
292 /* it might still fail if there's a dungeon feature here */
293 struct trap *t = t_at(x,y);
294 if (t) deltrap(t);
295 }
296 if(bad_location(x, y, nlx, nly, nhx, nhy)) return(FALSE);
297 switch (rtype) {
298 case LR_TELE:
299 case LR_UPTELE:
300 case LR_DOWNTELE:
301 /* "something" means the player in this case */
302 if(MON_AT(x, y)) {
303 /* move the monster if no choice, or just try again */
304 if(oneshot) rloc(m_at(x,y));
305 else return(FALSE);
306 }
307 u_on_newpos(x, y);
308 break;
309 case LR_PORTAL:
310 mkportal(x, y, lev->dnum, lev->dlevel);
311 break;
312 case LR_DOWNSTAIR:
313 case LR_UPSTAIR:
314 mkstairs(x, y, (char)rtype, (struct mkroom *)0);
315 break;
316 case LR_BRANCH:
317 place_branch(Is_branchlev(&u.uz), x, y);
318 break;
319 }
320 return(TRUE);
321 }
322
323 static boolean was_waterlevel; /* ugh... this shouldn't be needed */
324
325 /* this is special stuff that the level compiler cannot (yet) handle */
326 STATIC_OVL void
fixup_special()327 fixup_special()
328 {
329 register lev_region *r = lregions;
330 struct d_level lev;
331 register int x, y;
332 struct mkroom *croom;
333 boolean added_branch = FALSE;
334
335 if (was_waterlevel) {
336 was_waterlevel = FALSE;
337 u.uinwater = 0;
338 unsetup_waterlevel();
339 } else if (Is_waterlevel(&u.uz)) {
340 level.flags.hero_memory = 0;
341 was_waterlevel = TRUE;
342 /* water level is an odd beast - it has to be set up
343 before calling place_lregions etc. */
344 setup_waterlevel();
345 }
346 for(x = 0; x < num_lregions; x++, r++) {
347 switch(r->rtype) {
348 case LR_BRANCH:
349 added_branch = TRUE;
350 goto place_it;
351
352 case LR_PORTAL:
353 if(*r->rname.str >= '0' && *r->rname.str <= '9') {
354 /* "chutes and ladders" */
355 lev = u.uz;
356 lev.dlevel = atoi(r->rname.str);
357 } else {
358 s_level *sp = find_level(r->rname.str);
359 lev = sp->dlevel;
360 }
361 /* fall into... */
362
363 case LR_UPSTAIR:
364 case LR_DOWNSTAIR:
365 place_it:
366 place_lregion(r->inarea.x1, r->inarea.y1,
367 r->inarea.x2, r->inarea.y2,
368 r->delarea.x1, r->delarea.y1,
369 r->delarea.x2, r->delarea.y2,
370 r->rtype, &lev);
371 break;
372
373 case LR_TELE:
374 case LR_UPTELE:
375 case LR_DOWNTELE:
376 /* save the region outlines for goto_level() */
377 if(r->rtype == LR_TELE || r->rtype == LR_UPTELE) {
378 updest.lx = r->inarea.x1; updest.ly = r->inarea.y1;
379 updest.hx = r->inarea.x2; updest.hy = r->inarea.y2;
380 updest.nlx = r->delarea.x1; updest.nly = r->delarea.y1;
381 updest.nhx = r->delarea.x2; updest.nhy = r->delarea.y2;
382 }
383 if(r->rtype == LR_TELE || r->rtype == LR_DOWNTELE) {
384 dndest.lx = r->inarea.x1; dndest.ly = r->inarea.y1;
385 dndest.hx = r->inarea.x2; dndest.hy = r->inarea.y2;
386 dndest.nlx = r->delarea.x1; dndest.nly = r->delarea.y1;
387 dndest.nhx = r->delarea.x2; dndest.nhy = r->delarea.y2;
388 }
389 /* place_lregion gets called from goto_level() */
390 break;
391 }
392
393 if (r->rname.str) free((genericptr_t) r->rname.str), r->rname.str = 0;
394 }
395
396 /* place dungeon branch if not placed above */
397 if (!added_branch && Is_branchlev(&u.uz)) {
398 place_lregion(0,0,0,0,0,0,0,0,LR_BRANCH,(d_level *)0);
399 }
400
401 /* KMH -- Sokoban levels */
402 if(In_sokoban(&u.uz))
403 sokoban_detect();
404
405 /* Still need to add some stuff to level file */
406 if (Is_medusa_level(&u.uz)) {
407 struct obj *otmp;
408 int tryct;
409
410 croom = &rooms[0]; /* only one room on the medusa level */
411 for (tryct = rnd(4); tryct; tryct--) {
412 x = somex(croom); y = somey(croom);
413 if (goodpos(x, y, (struct monst *)0)) {
414 otmp = mk_tt_object(STATUE, x, y);
415 while (otmp && (poly_when_stoned(&mons[otmp->corpsenm]) ||
416 pm_resistance(&mons[otmp->corpsenm],MR_STONE))) {
417 otmp->corpsenm = rndmonnum();
418 otmp->owt = weight(otmp);
419 }
420 }
421 }
422
423 if (rn2(2))
424 otmp = mk_tt_object(STATUE, somex(croom), somey(croom));
425 else /* Medusa statues don't contain books */
426 otmp = mkcorpstat(STATUE, (struct monst *)0, (struct permonst *)0,
427 somex(croom), somey(croom), FALSE);
428 if (otmp) {
429 while (pm_resistance(&mons[otmp->corpsenm],MR_STONE)
430 || poly_when_stoned(&mons[otmp->corpsenm])) {
431 otmp->corpsenm = rndmonnum();
432 otmp->owt = weight(otmp);
433 }
434 }
435 } else if(Is_wiz1_level(&u.uz)) {
436 croom = search_special(MORGUE);
437
438 create_secret_door(croom, W_SOUTH|W_EAST|W_WEST);
439 } else if(Is_knox(&u.uz)) {
440 /* using an unfilled morgue for rm id */
441 croom = search_special(MORGUE);
442 /* avoid inappropriate morgue-related messages */
443 level.flags.graveyard = level.flags.has_morgue = 0;
444 croom->rtype = OROOM; /* perhaps it should be set to VAULT? */
445 /* stock the main vault */
446 for(x = croom->lx; x <= croom->hx; x++)
447 for(y = croom->ly; y <= croom->hy; y++) {
448 (void) mkgold((long) rn1(300, 600), x, y);
449 if (!rn2(3) && !is_pool(x,y))
450 (void)maketrap(x, y, rn2(3) ? LANDMINE : SPIKED_PIT);
451 }
452 } else if (Role_if(PM_PRIEST) && In_quest(&u.uz)) {
453 /* less chance for undead corpses (lured from lower morgues) */
454 level.flags.graveyard = 1;
455 } else if (Is_stronghold(&u.uz)) {
456 level.flags.graveyard = 1;
457 } else if(Is_sanctum(&u.uz)) {
458 croom = search_special(TEMPLE);
459
460 create_secret_door(croom, W_ANY);
461 } else if(on_level(&u.uz, &orcus_level)) {
462 register struct monst *mtmp, *mtmp2;
463
464 /* it's a ghost town, get rid of shopkeepers */
465 for(mtmp = fmon; mtmp; mtmp = mtmp2) {
466 mtmp2 = mtmp->nmon;
467 if(mtmp->isshk) mongone(mtmp);
468 }
469 }
470
471 if(lev_message) {
472 char *str, *nl;
473 for(str = lev_message; (nl = index(str, '\n')) != 0; str = nl+1) {
474 *nl = '\0';
475 pline("%s", str);
476 }
477 if(*str)
478 pline("%s", str);
479 free((genericptr_t)lev_message);
480 lev_message = 0;
481 }
482
483 if (lregions)
484 free((genericptr_t) lregions), lregions = 0;
485 num_lregions = 0;
486 }
487
488 void
makemaz(s)489 makemaz(s)
490 register const char *s;
491 {
492 int x,y;
493 char protofile[20];
494 s_level *sp = Is_special(&u.uz);
495 coord mm;
496
497 if(*s) {
498 if(sp && sp->rndlevs) Sprintf(protofile, "%s-%d", s,
499 rnd((int) sp->rndlevs));
500 else Strcpy(protofile, s);
501 } else if(*(dungeons[u.uz.dnum].proto)) {
502 if(dunlevs_in_dungeon(&u.uz) > 1) {
503 if(sp && sp->rndlevs)
504 Sprintf(protofile, "%s%d-%d", dungeons[u.uz.dnum].proto,
505 dunlev(&u.uz),
506 rnd((int) sp->rndlevs));
507 else Sprintf(protofile, "%s%d", dungeons[u.uz.dnum].proto,
508 dunlev(&u.uz));
509 } else if(sp && sp->rndlevs) {
510 Sprintf(protofile, "%s-%d", dungeons[u.uz.dnum].proto,
511 rnd((int) sp->rndlevs));
512 } else Strcpy(protofile, dungeons[u.uz.dnum].proto);
513
514 } else Strcpy(protofile, "");
515
516 if(*protofile) {
517 Strcat(protofile, LEV_EXT);
518 if(load_special(protofile)) {
519 fixup_special();
520 /* some levels can end up with monsters
521 on dead mon list, including light source monsters */
522 dmonsfree();
523 return; /* no mazification right now */
524 }
525 impossible("Couldn't load \"%s\" - making a maze.", protofile);
526 }
527
528 level.flags.is_maze_lev = TRUE;
529
530 #ifndef WALLIFIED_MAZE
531 for(x = 2; x < x_maze_max; x++)
532 for(y = 2; y < y_maze_max; y++)
533 levl[x][y].typ = STONE;
534 #else
535 for(x = 2; x <= x_maze_max; x++)
536 for(y = 2; y <= y_maze_max; y++)
537 levl[x][y].typ = ((x % 2) && (y % 2)) ? STONE : HWALL;
538 #endif
539
540 maze0xy(&mm);
541 walkfrom((int) mm.x, (int) mm.y);
542 /* put a boulder at the maze center */
543 (void) mksobj_at(BOULDER, (int) mm.x, (int) mm.y, TRUE);
544
545 #ifdef WALLIFIED_MAZE
546 wallification(2, 2, x_maze_max, y_maze_max);
547 #endif
548 mazexy(&mm);
549 mkstairs(mm.x, mm.y, 1, (struct mkroom *)0); /* up */
550 if (!Invocation_lev(&u.uz)) {
551 mazexy(&mm);
552 mkstairs(mm.x, mm.y, 0, (struct mkroom *)0); /* down */
553 } else { /* choose "vibrating square" location */
554 #define x_maze_min 2
555 #define y_maze_min 2
556 /*
557 * Pick a position where the stairs down to Moloch's Sanctum
558 * level will ultimately be created. At that time, an area
559 * will be altered: walls removed, moat and traps generated,
560 * boulders destroyed. The position picked here must ensure
561 * that that invocation area won't extend off the map.
562 *
563 * We actually allow up to 2 squares around the usual edge of
564 * the area to get truncated; see mkinvokearea(mklev.c).
565 */
566 #define INVPOS_X_MARGIN (6 - 2)
567 #define INVPOS_Y_MARGIN (5 - 2)
568 #define INVPOS_DISTANCE 11
569 int x_range = x_maze_max - x_maze_min - 2*INVPOS_X_MARGIN - 1,
570 y_range = y_maze_max - y_maze_min - 2*INVPOS_Y_MARGIN - 1;
571
572 #ifdef DEBUG
573 if (x_range <= INVPOS_X_MARGIN || y_range <= INVPOS_Y_MARGIN ||
574 (x_range * y_range) <= (INVPOS_DISTANCE * INVPOS_DISTANCE))
575 panic("inv_pos: maze is too small! (%d x %d)",
576 x_maze_max, y_maze_max);
577 #endif
578 inv_pos.x = inv_pos.y = 0; /*{occupied() => invocation_pos()}*/
579 do {
580 x = rn1(x_range, x_maze_min + INVPOS_X_MARGIN + 1);
581 y = rn1(y_range, y_maze_min + INVPOS_Y_MARGIN + 1);
582 /* we don't want it to be too near the stairs, nor
583 to be on a spot that's already in use (wall|trap) */
584 } while (x == xupstair || y == yupstair || /*(direct line)*/
585 abs(x - xupstair) == abs(y - yupstair) ||
586 distmin(x, y, xupstair, yupstair) <= INVPOS_DISTANCE ||
587 !SPACE_POS(levl[x][y].typ) || occupied(x, y));
588 inv_pos.x = x;
589 inv_pos.y = y;
590 #undef INVPOS_X_MARGIN
591 #undef INVPOS_Y_MARGIN
592 #undef INVPOS_DISTANCE
593 #undef x_maze_min
594 #undef y_maze_min
595 }
596
597 /* place branch stair or portal */
598 place_branch(Is_branchlev(&u.uz), 0, 0);
599
600 for(x = rn1(8,11); x; x--) {
601 mazexy(&mm);
602 (void) mkobj_at(rn2(2) ? GEM_CLASS : 0, mm.x, mm.y, TRUE);
603 }
604 for(x = rn1(10,2); x; x--) {
605 mazexy(&mm);
606 (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE);
607 }
608 for (x = rn2(3); x; x--) {
609 mazexy(&mm);
610 (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y, NO_MM_FLAGS);
611 }
612 for(x = rn1(5,7); x; x--) {
613 mazexy(&mm);
614 (void) makemon((struct permonst *) 0, mm.x, mm.y, NO_MM_FLAGS);
615 }
616 for(x = rn1(6,7); x; x--) {
617 mazexy(&mm);
618 (void) mkgold(0L,mm.x,mm.y);
619 }
620 for(x = rn1(6,7); x; x--)
621 mktrap(0,1,(struct mkroom *) 0, (coord*) 0);
622 }
623
624 #ifdef MICRO
625 /* Make the mazewalk iterative by faking a stack. This is needed to
626 * ensure the mazewalk is successful in the limited stack space of
627 * the program. This iterative version uses the minimum amount of stack
628 * that is totally safe.
629 */
630 void
walkfrom(x,y)631 walkfrom(x,y)
632 int x,y;
633 {
634 #define CELLS (ROWNO * COLNO) / 4 /* a maze cell is 4 squares */
635 char mazex[CELLS + 1], mazey[CELLS + 1]; /* char's are OK */
636 int q, a, dir, pos;
637 int dirs[4];
638
639 pos = 1;
640 mazex[pos] = (char) x;
641 mazey[pos] = (char) y;
642 while (pos) {
643 x = (int) mazex[pos];
644 y = (int) mazey[pos];
645 if(!IS_DOOR(levl[x][y].typ)) {
646 /* might still be on edge of MAP, so don't overwrite */
647 #ifndef WALLIFIED_MAZE
648 levl[x][y].typ = CORR;
649 #else
650 levl[x][y].typ = ROOM;
651 #endif
652 levl[x][y].flags = 0;
653 }
654 q = 0;
655 for (a = 0; a < 4; a++)
656 if(okay(x, y, a)) dirs[q++]= a;
657 if (!q)
658 pos--;
659 else {
660 dir = dirs[rn2(q)];
661 move(&x, &y, dir);
662 #ifndef WALLIFIED_MAZE
663 levl[x][y].typ = CORR;
664 #else
665 levl[x][y].typ = ROOM;
666 #endif
667 move(&x, &y, dir);
668 pos++;
669 if (pos > CELLS)
670 panic("Overflow in walkfrom");
671 mazex[pos] = (char) x;
672 mazey[pos] = (char) y;
673 }
674 }
675 }
676 #else
677
678 void
walkfrom(x,y)679 walkfrom(x,y)
680 int x,y;
681 {
682 register int q,a,dir;
683 int dirs[4];
684
685 if(!IS_DOOR(levl[x][y].typ)) {
686 /* might still be on edge of MAP, so don't overwrite */
687 #ifndef WALLIFIED_MAZE
688 levl[x][y].typ = CORR;
689 #else
690 levl[x][y].typ = ROOM;
691 #endif
692 levl[x][y].flags = 0;
693 }
694
695 while(1) {
696 q = 0;
697 for(a = 0; a < 4; a++)
698 if(okay(x,y,a)) dirs[q++]= a;
699 if(!q) return;
700 dir = dirs[rn2(q)];
701 move(&x,&y,dir);
702 #ifndef WALLIFIED_MAZE
703 levl[x][y].typ = CORR;
704 #else
705 levl[x][y].typ = ROOM;
706 #endif
707 move(&x,&y,dir);
708 walkfrom(x,y);
709 }
710 }
711 #endif /* MICRO */
712
713 STATIC_OVL void
move(x,y,dir)714 move(x,y,dir)
715 register int *x, *y;
716 register int dir;
717 {
718 switch(dir){
719 case 0: --(*y); break;
720 case 1: (*x)++; break;
721 case 2: (*y)++; break;
722 case 3: --(*x); break;
723 default: panic("move: bad direction");
724 }
725 }
726
727 void
mazexy(cc)728 mazexy(cc) /* find random point in generated corridors,
729 so we don't create items in moats, bunkers, or walls */
730 coord *cc;
731 {
732 int cpt=0;
733
734 do {
735 cc->x = 3 + 2*rn2((x_maze_max>>1) - 1);
736 cc->y = 3 + 2*rn2((y_maze_max>>1) - 1);
737 cpt++;
738 } while (cpt < 100 && levl[cc->x][cc->y].typ !=
739 #ifdef WALLIFIED_MAZE
740 ROOM
741 #else
742 CORR
743 #endif
744 );
745 if (cpt >= 100) {
746 register int x, y;
747 /* last try */
748 for (x = 0; x < (x_maze_max>>1) - 1; x++)
749 for (y = 0; y < (y_maze_max>>1) - 1; y++) {
750 cc->x = 3 + 2 * x;
751 cc->y = 3 + 2 * y;
752 if (levl[cc->x][cc->y].typ ==
753 #ifdef WALLIFIED_MAZE
754 ROOM
755 #else
756 CORR
757 #endif
758 ) return;
759 }
760 panic("mazexy: can't find a place!");
761 }
762 return;
763 }
764
765 void
bound_digging()766 bound_digging()
767 /* put a non-diggable boundary around the initial portion of a level map.
768 * assumes that no level will initially put things beyond the isok() range.
769 *
770 * we can't bound unconditionally on the last line with something in it,
771 * because that something might be a niche which was already reachable,
772 * so the boundary would be breached
773 *
774 * we can't bound unconditionally on one beyond the last line, because
775 * that provides a window of abuse for WALLIFIED_MAZE special levels
776 */
777 {
778 register int x,y;
779 register unsigned typ;
780 register struct rm *lev;
781 boolean found, nonwall;
782 int xmin,xmax,ymin,ymax;
783
784 if(Is_earthlevel(&u.uz)) return; /* everything diggable here */
785
786 found = nonwall = FALSE;
787 for(xmin=0; !found; xmin++) {
788 lev = &levl[xmin][0];
789 for(y=0; y<=ROWNO-1; y++, lev++) {
790 typ = lev->typ;
791 if(typ != STONE) {
792 found = TRUE;
793 if(!IS_WALL(typ)) nonwall = TRUE;
794 }
795 }
796 }
797 xmin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
798 if (xmin < 0) xmin = 0;
799
800 found = nonwall = FALSE;
801 for(xmax=COLNO-1; !found; xmax--) {
802 lev = &levl[xmax][0];
803 for(y=0; y<=ROWNO-1; y++, lev++) {
804 typ = lev->typ;
805 if(typ != STONE) {
806 found = TRUE;
807 if(!IS_WALL(typ)) nonwall = TRUE;
808 }
809 }
810 }
811 xmax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
812 if (xmax >= COLNO) xmax = COLNO-1;
813
814 found = nonwall = FALSE;
815 for(ymin=0; !found; ymin++) {
816 lev = &levl[xmin][ymin];
817 for(x=xmin; x<=xmax; x++, lev += ROWNO) {
818 typ = lev->typ;
819 if(typ != STONE) {
820 found = TRUE;
821 if(!IS_WALL(typ)) nonwall = TRUE;
822 }
823 }
824 }
825 ymin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
826
827 found = nonwall = FALSE;
828 for(ymax=ROWNO-1; !found; ymax--) {
829 lev = &levl[xmin][ymax];
830 for(x=xmin; x<=xmax; x++, lev += ROWNO) {
831 typ = lev->typ;
832 if(typ != STONE) {
833 found = TRUE;
834 if(!IS_WALL(typ)) nonwall = TRUE;
835 }
836 }
837 }
838 ymax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1;
839
840 for (x = 0; x < COLNO; x++)
841 for (y = 0; y < ROWNO; y++)
842 if (y <= ymin || y >= ymax || x <= xmin || x >= xmax) {
843 #ifdef DCC30_BUG
844 lev = &levl[x][y];
845 lev->wall_info |= W_NONDIGGABLE;
846 #else
847 levl[x][y].wall_info |= W_NONDIGGABLE;
848 #endif
849 }
850 }
851
852 void
mkportal(x,y,todnum,todlevel)853 mkportal(x, y, todnum, todlevel)
854 register xchar x, y, todnum, todlevel;
855 {
856 /* a portal "trap" must be matched by a */
857 /* portal in the destination dungeon/dlevel */
858 register struct trap *ttmp = maketrap(x, y, MAGIC_PORTAL);
859
860 if (!ttmp) {
861 impossible("portal on top of portal??");
862 return;
863 }
864 #ifdef DEBUG
865 pline("mkportal: at (%d,%d), to %s, level %d",
866 x, y, dungeons[todnum].dname, todlevel);
867 #endif
868 ttmp->dst.dnum = todnum;
869 ttmp->dst.dlevel = todlevel;
870 return;
871 }
872
873 /*
874 * Special waterlevel stuff in endgame (TH).
875 *
876 * Some of these functions would probably logically belong to some
877 * other source files, but they are all so nicely encapsulated here.
878 */
879
880 /* to ease the work of debuggers at this stage */
881 #define register
882
883 struct container {
884 struct container *next;
885 xchar x, y;
886 short what;
887 genericptr_t list;
888 };
889 #define CONS_OBJ 0
890 #define CONS_MON 1
891 #define CONS_HERO 2
892 #define CONS_TRAP 3
893
894 static struct bubble {
895 xchar x, y; /* coordinates of the upper left corner */
896 schar dx, dy; /* the general direction of the bubble's movement */
897 uchar *bm; /* pointer to the bubble bit mask */
898 struct bubble *prev, *next; /* need to traverse the list up and down */
899 struct container *cons;
900 } *bbubbles, *ebubbles;
901
902 static struct trap *wportal;
903 static int xmin, ymin, xmax, ymax; /* level boundaries */
904 /* bubble movement boundaries */
905 #define bxmin (xmin + 1)
906 #define bymin (ymin + 1)
907 #define bxmax (xmax - 1)
908 #define bymax (ymax - 1)
909
910 STATIC_DCL void NDECL(set_wportal);
911 STATIC_DCL void FDECL(mk_bubble, (int,int,int));
912 STATIC_DCL void FDECL(mv_bubble, (struct bubble *,int,int,BOOLEAN_P));
913
914 void
movebubbles()915 movebubbles()
916 {
917 static boolean up;
918 register struct bubble *b;
919 register int x, y, i, j;
920 struct trap *btrap;
921 static const struct rm water_pos =
922 { cmap_to_glyph(S_water), WATER, 0, 0, 0, 0, 0, 0, 0 };
923
924 /* set up the portal the first time bubbles are moved */
925 if (!wportal) set_wportal();
926
927 vision_recalc(2);
928 /* keep attached ball&chain separate from bubble objects */
929 if (Punished) unplacebc();
930
931 /*
932 * Pick up everything inside of a bubble then fill all bubble
933 * locations.
934 */
935
936 for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) {
937 if (b->cons) panic("movebubbles: cons != null");
938 for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++)
939 for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++)
940 if (b->bm[j + 2] & (1 << i)) {
941 if (!isok(x,y)) {
942 impossible("movebubbles: bad pos (%d,%d)", x,y);
943 continue;
944 }
945
946 /* pick up objects, monsters, hero, and traps */
947 if (OBJ_AT(x,y)) {
948 struct obj *olist = (struct obj *) 0, *otmp;
949 struct container *cons = (struct container *)
950 alloc(sizeof(struct container));
951
952 while ((otmp = level.objects[x][y]) != 0) {
953 remove_object(otmp);
954 otmp->ox = otmp->oy = 0;
955 otmp->nexthere = olist;
956 olist = otmp;
957 }
958
959 cons->x = x;
960 cons->y = y;
961 cons->what = CONS_OBJ;
962 cons->list = (genericptr_t) olist;
963 cons->next = b->cons;
964 b->cons = cons;
965 }
966 if (MON_AT(x,y)) {
967 struct monst *mon = m_at(x,y);
968 struct container *cons = (struct container *)
969 alloc(sizeof(struct container));
970
971 cons->x = x;
972 cons->y = y;
973 cons->what = CONS_MON;
974 cons->list = (genericptr_t) mon;
975
976 cons->next = b->cons;
977 b->cons = cons;
978
979 if(mon->wormno)
980 remove_worm(mon);
981 else
982 remove_monster(x, y);
983
984 newsym(x,y); /* clean up old position */
985 mon->mx = mon->my = 0;
986 }
987 if (!u.uswallow && x == u.ux && y == u.uy) {
988 struct container *cons = (struct container *)
989 alloc(sizeof(struct container));
990
991 cons->x = x;
992 cons->y = y;
993 cons->what = CONS_HERO;
994 cons->list = (genericptr_t) 0;
995
996 cons->next = b->cons;
997 b->cons = cons;
998 }
999 if ((btrap = t_at(x,y)) != 0) {
1000 struct container *cons = (struct container *)
1001 alloc(sizeof(struct container));
1002
1003 cons->x = x;
1004 cons->y = y;
1005 cons->what = CONS_TRAP;
1006 cons->list = (genericptr_t) btrap;
1007
1008 cons->next = b->cons;
1009 b->cons = cons;
1010 }
1011
1012 levl[x][y] = water_pos;
1013 block_point(x,y);
1014 }
1015 }
1016
1017 /*
1018 * Every second time traverse down. This is because otherwise
1019 * all the junk that changes owners when bubbles overlap
1020 * would eventually end up in the last bubble in the chain.
1021 */
1022
1023 up = !up;
1024 for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) {
1025 register int rx = rn2(3), ry = rn2(3);
1026
1027 mv_bubble(b,b->dx + 1 - (!b->dx ? rx : (rx ? 1 : 0)),
1028 b->dy + 1 - (!b->dy ? ry : (ry ? 1 : 0)),
1029 FALSE);
1030 }
1031
1032 /* put attached ball&chain back */
1033 if (Punished) placebc();
1034 vision_full_recalc = 1;
1035 }
1036
1037 /* when moving in water, possibly (1 in 3) alter the intended destination */
1038 void
water_friction()1039 water_friction()
1040 {
1041 register int x, y, dx, dy;
1042 register boolean eff = FALSE;
1043
1044 if (Swimming && rn2(4))
1045 return; /* natural swimmers have advantage */
1046
1047 if (u.dx && !rn2(!u.dy ? 3 : 6)) { /* 1/3 chance or half that */
1048 /* cancel delta x and choose an arbitrary delta y value */
1049 x = u.ux;
1050 do {
1051 dy = rn2(3) - 1; /* -1, 0, 1 */
1052 y = u.uy + dy;
1053 } while (dy && (!isok(x,y) || !is_pool(x,y)));
1054 u.dx = 0;
1055 u.dy = dy;
1056 eff = TRUE;
1057 } else if (u.dy && !rn2(!u.dx ? 3 : 5)) { /* 1/3 or 1/5*(5/6) */
1058 /* cancel delta y and choose an arbitrary delta x value */
1059 y = u.uy;
1060 do {
1061 dx = rn2(3) - 1; /* -1 .. 1 */
1062 x = u.ux + dx;
1063 } while (dx && (!isok(x,y) || !is_pool(x,y)));
1064 u.dy = 0;
1065 u.dx = dx;
1066 eff = TRUE;
1067 }
1068 if (eff) pline("Water turbulence affects your movements.");
1069 }
1070
1071 void
save_waterlevel(fd,mode)1072 save_waterlevel(fd, mode)
1073 int fd, mode;
1074 {
1075 register struct bubble *b;
1076
1077 if (!Is_waterlevel(&u.uz)) return;
1078
1079 if (perform_bwrite(mode)) {
1080 int n = 0;
1081 for (b = bbubbles; b; b = b->next) ++n;
1082 bwrite(fd, (genericptr_t)&n, sizeof (int));
1083 bwrite(fd, (genericptr_t)&xmin, sizeof (int));
1084 bwrite(fd, (genericptr_t)&ymin, sizeof (int));
1085 bwrite(fd, (genericptr_t)&xmax, sizeof (int));
1086 bwrite(fd, (genericptr_t)&ymax, sizeof (int));
1087 for (b = bbubbles; b; b = b->next)
1088 bwrite(fd, (genericptr_t)b, sizeof (struct bubble));
1089 }
1090 if (release_data(mode))
1091 unsetup_waterlevel();
1092 }
1093
1094 void
restore_waterlevel(fd)1095 restore_waterlevel(fd)
1096 register int fd;
1097 {
1098 register struct bubble *b = (struct bubble *)0, *btmp;
1099 register int i;
1100 int n;
1101
1102 if (!Is_waterlevel(&u.uz)) return;
1103
1104 set_wportal();
1105 mread(fd,(genericptr_t)&n,sizeof(int));
1106 mread(fd,(genericptr_t)&xmin,sizeof(int));
1107 mread(fd,(genericptr_t)&ymin,sizeof(int));
1108 mread(fd,(genericptr_t)&xmax,sizeof(int));
1109 mread(fd,(genericptr_t)&ymax,sizeof(int));
1110 for (i = 0; i < n; i++) {
1111 btmp = b;
1112 b = (struct bubble *)alloc(sizeof(struct bubble));
1113 mread(fd,(genericptr_t)b,sizeof(struct bubble));
1114 if (bbubbles) {
1115 btmp->next = b;
1116 b->prev = btmp;
1117 } else {
1118 bbubbles = b;
1119 b->prev = (struct bubble *)0;
1120 }
1121 mv_bubble(b,0,0,TRUE);
1122 }
1123 ebubbles = b;
1124 b->next = (struct bubble *)0;
1125 was_waterlevel = TRUE;
1126 }
1127
1128 STATIC_OVL void
set_wportal()1129 set_wportal()
1130 {
1131 /* there better be only one magic portal on water level... */
1132 for (wportal = ftrap; wportal; wportal = wportal->ntrap)
1133 if (wportal->ttyp == MAGIC_PORTAL) return;
1134 impossible("set_wportal(): no portal!");
1135 }
1136
1137 STATIC_OVL void
setup_waterlevel()1138 setup_waterlevel()
1139 {
1140 register int x, y;
1141 register int xskip, yskip;
1142 register int water_glyph = cmap_to_glyph(S_water);
1143
1144 /* ouch, hardcoded... */
1145
1146 xmin = 3;
1147 ymin = 1;
1148 xmax = 78;
1149 ymax = 20;
1150
1151 /* set hero's memory to water */
1152
1153 for (x = xmin; x <= xmax; x++)
1154 for (y = ymin; y <= ymax; y++)
1155 levl[x][y].glyph = water_glyph;
1156
1157 /* make bubbles */
1158
1159 xskip = 10 + rn2(10);
1160 yskip = 4 + rn2(4);
1161 for (x = bxmin; x <= bxmax; x += xskip)
1162 for (y = bymin; y <= bymax; y += yskip)
1163 mk_bubble(x,y,rn2(7));
1164 }
1165
1166 STATIC_OVL void
unsetup_waterlevel()1167 unsetup_waterlevel()
1168 {
1169 register struct bubble *b, *bb;
1170
1171 /* free bubbles */
1172
1173 for (b = bbubbles; b; b = bb) {
1174 bb = b->next;
1175 free((genericptr_t)b);
1176 }
1177 bbubbles = ebubbles = (struct bubble *)0;
1178 }
1179
1180 STATIC_OVL void
mk_bubble(x,y,n)1181 mk_bubble(x,y,n)
1182 register int x, y, n;
1183 {
1184 /*
1185 * These bit masks make visually pleasing bubbles on a normal aspect
1186 * 25x80 terminal, which naturally results in them being mathematically
1187 * anything but symmetric. For this reason they cannot be computed
1188 * in situ, either. The first two elements tell the dimensions of
1189 * the bubble's bounding box.
1190 */
1191 static uchar
1192 bm2[] = {2,1,0x3},
1193 bm3[] = {3,2,0x7,0x7},
1194 bm4[] = {4,3,0x6,0xf,0x6},
1195 bm5[] = {5,3,0xe,0x1f,0xe},
1196 bm6[] = {6,4,0x1e,0x3f,0x3f,0x1e},
1197 bm7[] = {7,4,0x3e,0x7f,0x7f,0x3e},
1198 bm8[] = {8,4,0x7e,0xff,0xff,0x7e},
1199 *bmask[] = {bm2,bm3,bm4,bm5,bm6,bm7,bm8};
1200
1201 register struct bubble *b;
1202
1203 if (x >= bxmax || y >= bymax) return;
1204 if (n >= SIZE(bmask)) {
1205 impossible("n too large (mk_bubble)");
1206 n = SIZE(bmask) - 1;
1207 }
1208 b = (struct bubble *)alloc(sizeof(struct bubble));
1209 if ((x + (int) bmask[n][0] - 1) > bxmax) x = bxmax - bmask[n][0] + 1;
1210 if ((y + (int) bmask[n][1] - 1) > bymax) y = bymax - bmask[n][1] + 1;
1211 b->x = x;
1212 b->y = y;
1213 b->dx = 1 - rn2(3);
1214 b->dy = 1 - rn2(3);
1215 b->bm = bmask[n];
1216 b->cons = 0;
1217 if (!bbubbles) bbubbles = b;
1218 if (ebubbles) {
1219 ebubbles->next = b;
1220 b->prev = ebubbles;
1221 }
1222 else
1223 b->prev = (struct bubble *)0;
1224 b->next = (struct bubble *)0;
1225 ebubbles = b;
1226 mv_bubble(b,0,0,TRUE);
1227 }
1228
1229 /*
1230 * The player, the portal and all other objects and monsters
1231 * float along with their associated bubbles. Bubbles may overlap
1232 * freely, and the contents may get associated with other bubbles in
1233 * the process. Bubbles are "sticky", meaning that if the player is
1234 * in the immediate neighborhood of one, he/she may get sucked inside.
1235 * This property also makes leaving a bubble slightly difficult.
1236 */
1237 STATIC_OVL void
mv_bubble(b,dx,dy,ini)1238 mv_bubble(b,dx,dy,ini)
1239 register struct bubble *b;
1240 register int dx, dy;
1241 register boolean ini;
1242 {
1243 register int x, y, i, j, colli = 0;
1244 struct container *cons, *ctemp;
1245
1246 /* move bubble */
1247 if (dx < -1 || dx > 1 || dy < -1 || dy > 1) {
1248 /* pline("mv_bubble: dx = %d, dy = %d", dx, dy); */
1249 dx = sgn(dx);
1250 dy = sgn(dy);
1251 }
1252
1253 /*
1254 * collision with level borders?
1255 * 1 = horizontal border, 2 = vertical, 3 = corner
1256 */
1257 if (b->x <= bxmin) colli |= 2;
1258 if (b->y <= bymin) colli |= 1;
1259 if ((int) (b->x + b->bm[0] - 1) >= bxmax) colli |= 2;
1260 if ((int) (b->y + b->bm[1] - 1) >= bymax) colli |= 1;
1261
1262 if (b->x < bxmin) {
1263 pline("bubble xmin: x = %d, xmin = %d", b->x, bxmin);
1264 b->x = bxmin;
1265 }
1266 if (b->y < bymin) {
1267 pline("bubble ymin: y = %d, ymin = %d", b->y, bymin);
1268 b->y = bymin;
1269 }
1270 if ((int) (b->x + b->bm[0] - 1) > bxmax) {
1271 pline("bubble xmax: x = %d, xmax = %d",
1272 b->x + b->bm[0] - 1, bxmax);
1273 b->x = bxmax - b->bm[0] + 1;
1274 }
1275 if ((int) (b->y + b->bm[1] - 1) > bymax) {
1276 pline("bubble ymax: y = %d, ymax = %d",
1277 b->y + b->bm[1] - 1, bymax);
1278 b->y = bymax - b->bm[1] + 1;
1279 }
1280
1281 /* bounce if we're trying to move off the border */
1282 if (b->x == bxmin && dx < 0) dx = -dx;
1283 if (b->x + b->bm[0] - 1 == bxmax && dx > 0) dx = -dx;
1284 if (b->y == bymin && dy < 0) dy = -dy;
1285 if (b->y + b->bm[1] - 1 == bymax && dy > 0) dy = -dy;
1286
1287 b->x += dx;
1288 b->y += dy;
1289
1290 /* void positions inside bubble */
1291
1292 for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++)
1293 for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++)
1294 if (b->bm[j + 2] & (1 << i)) {
1295 levl[x][y].typ = AIR;
1296 levl[x][y].lit = 1;
1297 unblock_point(x,y);
1298 }
1299
1300 /* replace contents of bubble */
1301 for (cons = b->cons; cons; cons = ctemp) {
1302 ctemp = cons->next;
1303 cons->x += dx;
1304 cons->y += dy;
1305
1306 switch(cons->what) {
1307 case CONS_OBJ: {
1308 struct obj *olist, *otmp;
1309
1310 for (olist=(struct obj *)cons->list; olist; olist=otmp) {
1311 otmp = olist->nexthere;
1312 place_object(olist, cons->x, cons->y);
1313 }
1314 break;
1315 }
1316
1317 case CONS_MON: {
1318 struct monst *mon = (struct monst *) cons->list;
1319 (void) mnearto(mon, cons->x, cons->y, TRUE);
1320 break;
1321 }
1322
1323 case CONS_HERO: {
1324 int ux0 = u.ux, uy0 = u.uy;
1325
1326 /* change u.ux0 and u.uy0? */
1327 u.ux = cons->x;
1328 u.uy = cons->y;
1329 newsym(ux0, uy0); /* clean up old position */
1330
1331 if (MON_AT(cons->x, cons->y)) {
1332 mnexto(m_at(cons->x,cons->y));
1333 }
1334 break;
1335 }
1336
1337 case CONS_TRAP: {
1338 struct trap *btrap = (struct trap *) cons->list;
1339 btrap->tx = cons->x;
1340 btrap->ty = cons->y;
1341 break;
1342 }
1343
1344 default:
1345 impossible("mv_bubble: unknown bubble contents");
1346 break;
1347 }
1348 free((genericptr_t)cons);
1349 }
1350 b->cons = 0;
1351
1352 /* boing? */
1353
1354 switch (colli) {
1355 case 1: b->dy = -b->dy; break;
1356 case 3: b->dy = -b->dy; /* fall through */
1357 case 2: b->dx = -b->dx; break;
1358 default:
1359 /* sometimes alter direction for fun anyway
1360 (higher probability for stationary bubbles) */
1361 if (!ini && ((b->dx || b->dy) ? !rn2(20) : !rn2(5))) {
1362 b->dx = 1 - rn2(3);
1363 b->dy = 1 - rn2(3);
1364 }
1365 }
1366 }
1367
1368 /*mkmaze.c*/
1369