Source:Mkmaze.c

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