Source:NetHack 3.3.0/mkmaze.c

Below is the full text to mkmaze.c from the source code of NetHack 3.3.0. To link to a particular line, write [[NetHack 3.3.0/mkmaze.c#line123 ]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

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