Source:NetHack 3.2.0/mkmaze.c

Below is the full text to mkmaze.c from the source code of NetHack 3.2.0. To link to a particular line, write [[NetHack 3.2.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.2	95/09/06	*/ 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 boolean FDECL(iswall,(int,int)); 15.  static boolean FDECL(iswall_or_stone,(int,int)); 16.  static boolean FDECL(is_solid,(int,int)); 17.  static int FDECL(extend_spine, (int locale[3][3], int, int, int)); 18.  static boolean FDECL(okay,(int,int,int)); 19.  static void FDECL(maze0xy,(coord *)); 20.  static 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 void NDECL(fixup_special); 23.  static void FDECL(move, (int *,int *,int)); 24.  static void NDECL(setup_waterlevel); 25.  static 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 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 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 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 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 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 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 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 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.      /* Still need to add some stuff to level file */ 403.     if (Is_medusa_level(&u.uz)) { 404. 	struct obj *otmp; 405. 	int tryct; 406.  407.  	croom = &rooms[0]; /* only one room on the medusa level */ 408. 	for (tryct = rnd(4); tryct; tryct--) { 409. 	    x = somex(croom); y = somey(croom); 410. 	    if (goodpos(x, y, (struct monst *)0, (struct permonst *)0)) { 411. 		otmp = mk_tt_object(STATUE, x, y); 412. 		while (otmp && (poly_when_stoned(&mons[otmp->corpsenm]) || 413. 				pm_resistance(&mons[otmp->corpsenm],MR_STONE))) { 414. 		    otmp->corpsenm = rndmonnum; 415. 		    otmp->owt = weight(otmp); 416. 		}  417.  	    }  418.  	}  419.   420.  	if (rn2(2)) 421. 	    otmp = mk_tt_object(STATUE, somex(croom), somey(croom)); 422. 	else /* Medusa statues don't contain books */ 423. 	    otmp = mkcorpstat(STATUE, (struct permonst *)0,  424.  			      somex(croom), somey(croom), FALSE); 425. 	if (otmp) { 426. 	    while (pm_resistance(&mons[otmp->corpsenm],MR_STONE)  427.  		   || poly_when_stoned(&mons[otmp->corpsenm])) { 428. 		otmp->corpsenm = rndmonnum; 429. 		otmp->owt = weight(otmp); 430. 	    }  431.  	}  432.      } else if(Is_wiz1_level(&u.uz)) { 433. 	croom = search_special(MORGUE); 434.  435.  	create_secret_door(croom, W_SOUTH|W_EAST|W_WEST); 436.     } else if(Is_knox(&u.uz)) { 437. 	/* using an unfilled morgue for rm id */ 438. 	croom = search_special(MORGUE); 439. 	/* avoid inappropriate morgue-related messages */ 440. 	level.flags.graveyard = level.flags.has_morgue = FALSE; 441. 	croom->rtype = OROOM;	/* perhaps it should be set to VAULT? */ 442.  	/* stock the main vault */ 443. 	for(x = croom->lx; x <= croom->hx; x++) 444. 	    for(y = croom->ly; y <= croom->hy; y++) { 445. 		mkgold((long) rn1(300, 600), x, y); 446. 		if (!rn2(3) && !is_pool(x,y)) 447. 		    (void)maketrap(x, y, rn2(3) ? LANDMINE : SPIKED_PIT); 448. 	    }  449.      } else if (Role_is('P') && In_quest(&u.uz)) { 450. 	/* less chance for undead corpses (lured from lower morgues) */ 451. 	level.flags.graveyard = TRUE; 452.     } else if (Is_stronghold(&u.uz)) { 453. 	level.flags.graveyard = TRUE; 454.     } else if(Is_sanctum(&u.uz)) { 455. 	croom = search_special(TEMPLE); 456.  457.  	create_secret_door(croom, W_ANY); 458.     } else if(on_level(&u.uz, &orcus_level)) { 459. 	   register struct monst *mtmp, *mtmp2; 460.  461.  	   /* it's a ghost town, get rid of shopkeepers */ 462. 	    for(mtmp = fmon; mtmp; mtmp = mtmp2) { 463. 		    mtmp2 = mtmp->nmon; 464. 		    if(mtmp->isshk) mongone(mtmp); 465. 	    }  466.      }  467.   468.      if(lev_message) { 469. 	char *str, *nl; 470. 	for(str = lev_message; (nl = index(str, '\n')) != 0; str = nl+1) { 471. 	    *nl = '\0'; 472. 	    pline("%s", str); 473. 	}  474.  	if(*str) 475. 	    pline("%s", str); 476. 	free((genericptr_t)lev_message); 477. 	lev_message = 0; 478.     }  479.   480.      if (lregions) 481. 	free((genericptr_t) lregions),  lregions = 0; 482.     num_lregions = 0; 483. }  484.   485.  void 486. makemaz(s) 487. register const char *s; 488. {  489.  	int x,y; 490. 	char protofile[20]; 491. 	s_level	*sp = Is_special(&u.uz); 492. 	coord mm; 493.  494.  	if(*s) { 495. 	    if(sp && sp->rndlevs) Sprintf(protofile, "%s-%d", s,  496.  						rnd((int) sp->rndlevs)); 497. 	    else		 Strcpy(protofile, s); 498. 	} else if(*(dungeons[u.uz.dnum].proto)) { 499. 	    if(dunlevs_in_dungeon(&u.uz) > 1) { 500. 		if(sp && sp->rndlevs) 501. 		     Sprintf(protofile, "%s%d-%d", dungeons[u.uz.dnum].proto,  502.  						dunlev(&u.uz),  503.  						rnd((int) sp->rndlevs)); 504. 		else Sprintf(protofile, "%s%d", dungeons[u.uz.dnum].proto,  505.  						dunlev(&u.uz)); 506. 	    } else if(sp && sp->rndlevs) { 507. 		     Sprintf(protofile, "%s-%d", dungeons[u.uz.dnum].proto,  508.  						rnd((int) sp->rndlevs)); 509. 	    } else Strcpy(protofile, dungeons[u.uz.dnum].proto); 510.  511.  	} else Strcpy(protofile, ""); 512.  513.  	if(*protofile) { 514. 	    Strcat(protofile, LEV_EXT); 515. 	    if(load_special(protofile)) { 516. 		fixup_special; 517. 		return;	/* no mazification right now */ 518. 	    }  519.  	    impossible("Couldn't load \"%s\" - making a maze.", protofile); 520. 	}  521.   522.  	level.flags.is_maze_lev = TRUE; 523.  524.  #ifndef WALLIFIED_MAZE 525. 	for(x = 2; x < x_maze_max; x++) 526. 		for(y = 2; y < y_maze_max; y++) 527. 			levl[x][y].typ = STONE; 528. #else 529. 	for(x = 2; x <= x_maze_max; x++) 530. 		for(y = 2; y <= y_maze_max; y++) 531. 			levl[x][y].typ = ((x % 2) && (y % 2)) ? STONE : HWALL; 532. #endif 533.  534.  	maze0xy(&mm); 535. 	walkfrom((int) mm.x, (int) mm.y); 536. 	/* put a boulder at the maze center */ 537. 	(void) mksobj_at(BOULDER, (int) mm.x, (int) mm.y, TRUE); 538.  539.  #ifdef WALLIFIED_MAZE 540. 	wallification(2, 2, x_maze_max, y_maze_max); 541. #endif 542. 	mazexy(&mm); 543. 	mkstairs(mm.x, mm.y, 1, (struct mkroom *)0);		/* up */ 544. 	if (!Invocation_lev(&u.uz)) { 545. 	    mazexy(&mm); 546. 	    mkstairs(mm.x, mm.y, 0, (struct mkroom *)0);	/* down */ 547. 	} else {	/* choose "vibrating square" location */ 548. #define x_maze_min 2 549. #define y_maze_min 2 550. 	    /*  551.  	     * Pick a position where the stairs down to Moloch's Sanctum 552. 	     * level will ultimately be created. At that time, an area 553. 	     * will be altered:  walls removed, moat and traps generated, 554. 	     * boulders destroyed. The position picked here must ensure 555. 	     * that that invocation area won't extend off the map. 556. 	     *  557.  	     * We actually allow up to 2 squares around the usual edge of  558. * the area to get truncated; see mkinvokearea(mklev.c). 559. 	     */  560.  #define INVPOS_X_MARGIN (6 - 2) 561. #define INVPOS_Y_MARGIN (5 - 2) 562. #define INVPOS_DISTANCE 11 563. 	    int x_range = x_maze_max - x_maze_min - 2*INVPOS_X_MARGIN - 1, 564. 		y_range = y_maze_max - y_maze_min - 2*INVPOS_Y_MARGIN - 1; 565.  566.  #ifdef DEBUG 567. 	    if (x_range <= INVPOS_X_MARGIN || y_range <= INVPOS_Y_MARGIN ||  568.  		   (x_range * y_range) <= (INVPOS_DISTANCE * INVPOS_DISTANCE)) 569. 		panic("inv_pos: maze is too small! (%d x %d)",  570.  		      x_maze_max, y_maze_max); 571. #endif 572. 	    inv_pos.x = inv_pos.y = 0; /*{occupied => invocation_pos}*/ 573. 	    do { 574. 		x = rn1(x_range, x_maze_min + INVPOS_X_MARGIN + 1); 575. 		y = rn1(y_range, y_maze_min + INVPOS_Y_MARGIN + 1); 576. 		/* we don't want it to be too near the stairs, nor 577. 		   to be on a spot that's already in use (wall|trap) */ 578. 	    } while (x == xupstair || y == yupstair ||	/*(direct line)*/  579.  		     abs(x - xupstair) == abs(y - yupstair) ||  580.  		     distmin(x, y, xupstair, yupstair) <= INVPOS_DISTANCE ||  581.  		     !SPACE_POS(levl[x][y].typ) || occupied(x, y)); 582. 	    inv_pos.x = x;  583. inv_pos.y = y; 584. #undef INVPOS_X_MARGIN 585. #undef INVPOS_Y_MARGIN 586. #undef INVPOS_DISTANCE 587. #undef x_maze_min 588. #undef y_maze_min 589. 	}  590.   591.  	/* place branch stair or portal */ 592. 	place_branch(Is_branchlev(&u.uz), 0, 0); 593.  594.  	for(x = rn1(8,11); x; x--) { 595. 		mazexy(&mm); 596. 		(void) mkobj_at(rn2(2) ? GEM_CLASS : 0, mm.x, mm.y, TRUE); 597. 	}  598.  	for(x = rn1(10,2); x; x--) { 599. 		mazexy(&mm); 600. 		(void) mksobj_at(BOULDER, mm.x, mm.y, TRUE); 601. 	}  602.  	for (x = rn2(3); x; x--) { 603. 		mazexy(&mm); 604. 		(void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y); 605. 	}  606.  	for(x = rn1(5,7); x; x--) { 607. 		mazexy(&mm); 608. 		(void) makemon((struct permonst *) 0, mm.x, mm.y); 609. 	}  610.  	for(x = rn1(6,7); x; x--) { 611. 		mazexy(&mm); 612. 		mkgold(0L,mm.x,mm.y); 613. 	}  614.  	for(x = rn1(6,7); x; x--) 615. 		mktrap(0,1,(struct mkroom *) 0, (coord*) 0); 616. }  617.   618.  #ifdef MICRO 619. /* Make the mazewalk iterative by faking a stack. This is needed to 620. * ensure the mazewalk is successful in the limited stack space of 621. * the program. This iterative version uses the minimum amount of stack 622.  * that is totally safe. 623.  */  624.  void 625. walkfrom(x,y) 626. int x,y; 627. {  628.  #define CELLS (ROWNO * COLNO) / 4		/* a maze cell is 4 squares */ 629. 	char mazex[CELLS + 1], mazey[CELLS + 1];	/* char's are OK */ 630. 	int q, a, dir, pos; 631. 	int dirs[4]; 632.  633.  	pos = 1; 634. 	mazex[pos] = (char) x;  635. mazey[pos] = (char) y; 636. while (pos) { 637. 		x = (int) mazex[pos]; 638. 		y = (int) mazey[pos]; 639. 		if(!IS_DOOR(levl[x][y].typ)) { 640. 		    /* might still be on edge of MAP, so don't overwrite */ 641. #ifndef WALLIFIED_MAZE 642. 		    levl[x][y].typ = CORR; 643. #else 644. 		    levl[x][y].typ = ROOM; 645. #endif 646. 		    levl[x][y].flags = 0; 647. 		}  648.  		q = 0; 649. 		for (a = 0; a < 4; a++) 650. 			if(okay(x, y, a)) dirs[q++]= a;  651. if (!q) 652. 			pos--; 653. 		else { 654. 			dir = dirs[rn2(q)]; 655. 			move(&x, &y, dir); 656. #ifndef WALLIFIED_MAZE 657. 			levl[x][y].typ = CORR; 658. #else 659. 			levl[x][y].typ = ROOM; 660. #endif 661. 			move(&x, &y, dir); 662. 			pos++; 663. 			if (pos > CELLS) 664. 				panic("Overflow in walkfrom"); 665. 			mazex[pos] = (char) x;  666. mazey[pos] = (char) y; 667. } 668.  	}  669.  }  670.  #else 671.  672.  void 673. walkfrom(x,y) 674. int x,y; 675. {  676.  	register int q,a,dir; 677. 	int dirs[4]; 678.  679.  	if(!IS_DOOR(levl[x][y].typ)) { 680. 	    /* might still be on edge of MAP, so don't overwrite */ 681. #ifndef WALLIFIED_MAZE 682. 	    levl[x][y].typ = CORR; 683. #else 684. 	    levl[x][y].typ = ROOM; 685. #endif 686. 	    levl[x][y].flags = 0; 687. 	}  688.   689.  	while(1) { 690. 		q = 0; 691. 		for(a = 0; a < 4; a++) 692. 			if(okay(x,y,a)) dirs[q++]= a;  693. if(!q) return; 694. 		dir = dirs[rn2(q)]; 695. 		move(&x,&y,dir); 696. #ifndef WALLIFIED_MAZE 697. 		levl[x][y].typ = CORR; 698. #else 699. 		levl[x][y].typ = ROOM; 700. #endif 701. 		move(&x,&y,dir); 702. 		walkfrom(x,y); 703. 	}  704.  }  705.  #endif /* MICRO */ 706.  707.  static void 708. move(x,y,dir) 709. register int *x, *y; 710. register int dir; 711. {  712.  	switch(dir){ 713. 		case 0: --(*y); break; 714. 		case 1: (*x)++; break; 715. 		case 2: (*y)++; break; 716. 		case 3: --(*x); break; 717. 		default: panic("move: bad direction"); 718. 	}  719.  }  720.   721.  void 722. mazexy(cc)	/* find random point in generated corridors, 723. 		   so we don't create items in moats, bunkers, or walls */ 724. 	coord	*cc; 725. {  726.  	int cpt=0; 727.  728.  	do { 729. 	    cc->x = 3 + 2*rn2((x_maze_max>>1) - 1); 730. 	    cc->y = 3 + 2*rn2((y_maze_max>>1) - 1); 731. 	    cpt++; 732. 	} while (cpt < 100 && levl[cc->x][cc->y].typ !=  733.  #ifdef WALLIFIED_MAZE  734.  		 ROOM  735.  #else  736.  		 CORR  737.  #endif  738.  		); 739. 	if (cpt >= 100) { 740. 		register int x, y;  741. /* last try */ 742. 		for (x = 0; x < (x_maze_max>>1) - 1; x++) 743. 		    for (y = 0; y < (y_maze_max>>1) - 1; y++) { 744. 			cc->x = 3 + 2 * x;  745. cc->y = 3 + 2 * y; 746. if (levl[cc->x][cc->y].typ == 747.  #ifdef WALLIFIED_MAZE  748.  			    ROOM  749.  #else  750.  			    CORR  751.  #endif  752.  			   ) return; 753. 		    }  754.  		panic("mazexy: can't find a place!"); 755. 	}  756.  	return; 757. }  758.   759.  void 760. bound_digging 761. /* put a non-diggable boundary around the initial portion of a level map. 762.  * assumes that no level will initially put things beyond the isok range. 763.  *  764.   * we can't bound unconditionally on the last line with something in it, 765.  * because that something might be a niche which was already reachable, 766.  * so the boundary would be breached 767.  *  768.   * we can't bound unconditionally on one beyond the last line, because 769.  * that provides a window of abuse for WALLIFIED_MAZE special levels 770.  */  771.  {  772.  	register int x,y; 773. 	register unsigned typ; 774. 	register struct rm *lev; 775. 	boolean found, nonwall; 776. 	int xmin,xmax,ymin,ymax; 777.  778.  	if(Is_earthlevel(&u.uz)) return; /* everything diggable here */ 779.  780.  	found = nonwall = FALSE; 781. 	for(xmin=0; !found; xmin++) { 782. 		lev = &levl[xmin][0]; 783. 		for(y=0; y<=ROWNO-1; y++, lev++) { 784. 			typ = lev->typ; 785. 			if(typ != STONE) { 786. 				found = TRUE; 787. 				if(!IS_WALL(typ)) nonwall = TRUE; 788. 			}  789.  		}  790.  	}  791.  	xmin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1; 792.  	if (xmin < 0) xmin = 0; 793.  794.  	found = nonwall = FALSE; 795. 	for(xmax=COLNO-1; !found; xmax--) { 796. 		lev = &levl[xmax][0]; 797. 		for(y=0; y<=ROWNO-1; y++, lev++) { 798. 			typ = lev->typ; 799. 			if(typ != STONE) { 800. 				found = TRUE; 801. 				if(!IS_WALL(typ)) nonwall = TRUE; 802. 			}  803.  		}  804.  	}  805.  	xmax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1; 806.  	if (xmax >= COLNO) xmax = COLNO-1; 807.  808.  	found = nonwall = FALSE; 809. 	for(ymin=0; !found; ymin++) { 810. 		lev = &levl[xmin][ymin]; 811. 		for(x=xmin; x<=xmax; x++, lev += ROWNO) { 812. 			typ = lev->typ; 813. 			if(typ != STONE) { 814. 				found = TRUE; 815. 				if(!IS_WALL(typ)) nonwall = TRUE; 816. 			}  817.  		}  818.  	}  819.  	ymin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1; 820.   821.  	found = nonwall = FALSE; 822. 	for(ymax=ROWNO-1; !found; ymax--) { 823. 		lev = &levl[xmin][ymax]; 824. 		for(x=xmin; x<=xmax; x++, lev += ROWNO) { 825. 			typ = lev->typ; 826. 			if(typ != STONE) { 827. 				found = TRUE; 828. 				if(!IS_WALL(typ)) nonwall = TRUE; 829. 			}  830.  		}  831.  	}  832.  	ymax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1; 833.   834.  	for (x = 0; x < COLNO; x++) 835. 	  for (y = 0; y < ROWNO; y++) 836. 	    if (y <= ymin || y >= ymax || x <= xmin || x >= xmax) { 837. #ifdef DCC30_BUG 838. 		lev = &levl[x][y]; 839. 		lev->wall_info |= W_NONDIGGABLE; 840. #else 841. 		levl[x][y].wall_info |= W_NONDIGGABLE; 842. #endif 843. 	    }  844.  }  845.   846.  void 847. mkportal(x, y, todnum, todlevel) 848. register xchar x, y, todnum, todlevel; 849. {  850.  	/* a portal "trap" must be matched by a */ 851. 	/* portal in the destination dungeon/dlevel */ 852. 	register struct trap *ttmp = maketrap(x, y, MAGIC_PORTAL); 853.  854.  	if (!ttmp) { 855. 		impossible("portal on top of portal??"); 856. 		return; 857. 	}  858.  #ifdef DEBUG 859. 	pline("mkportal: at (%d,%d), to %s, level %d",  860.  		x, y, dungeons[todnum].dname, todlevel); 861. #endif 862. 	ttmp->dst.dnum = todnum; 863. 	ttmp->dst.dlevel = todlevel; 864. 	return; 865. }  866.   867.  /*  868.   * Special waterlevel stuff in endgame (TH). 869.  *  870.   * Some of these functions would probably logically belong to some 871.  * other source files, but they are all so nicely encapsulated here. 872.  */  873.   874.  /* to ease the work of debuggers at this stage */ 875. #define register 876.  877.  struct container { 878. 	struct container *next; 879. 	xchar x, y;  880. short what; 881. 	genericptr_t list; 882. };  883.  #define CONS_OBJ   0 884. #define CONS_MON   1 885. #define CONS_HERO  2 886. #define CONS_TRAP  3 887.  888.  static struct bubble { 889. 	xchar x, y;	/* coordinates of the upper left corner */ 890. 	schar dx, dy;	/* the general direction of the bubble's movement */ 891. 	uchar *bm;	/* pointer to the bubble bit mask */ 892. 	struct bubble *prev, *next; /* need to traverse the list up and down */ 893. 	struct container *cons; 894. } *bbubbles, *ebubbles; 895.  896.  static struct trap *wportal; 897. static int xmin, ymin, xmax, ymax;	/* level boundaries */ 898. /* bubble movement boundaries */ 899. #define bxmin (xmin + 1) 900. #define bymin (ymin + 1) 901. #define bxmax (xmax - 1) 902. #define bymax (ymax - 1) 903.  904.  static void NDECL(set_wportal); 905. static void FDECL(mk_bubble, (int,int,int)); 906. static void FDECL(mv_bubble, (struct bubble *,int,int,BOOLEAN_P)); 907.  908.  void 909. movebubbles 910. {  911.  	static boolean up; 912. 	register struct bubble *b; 913. 	register int x, y, i, j;  914. struct trap *btrap; 915. 	static const struct rm water_pos = 916. 		{ cmap_to_glyph(S_water), WATER, 0, 0, 0, 0, 0, 0, 0 }; 917.  918.  	/* set up the portal the first time bubbles are moved */ 919. 	if (!wportal) set_wportal; 920.  921.  	vision_recalc(2); 922.  923.  	/*  924.  	 * Pick up everything inside of a bubble then fill all bubble 925. 	 * locations. 926. 	 */  927.   928.  	for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) { 929. 	    if (b->cons) panic("movebubbles: cons != null"); 930. 	    for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++) 931. 		for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++) 932. 		    if (b->bm[j + 2] & (1 << i)) { 933. 			if (!isok(x,y)) { 934. 			    impossible("movebubbles: bad pos (%d,%d)", x,y); 935. 			    continue; 936. 			}  937.   938.  			/* pick up objects, monsters, hero, and traps */ 939. 			if (OBJ_AT(x,y)) { 940. 			    struct obj *olist = (struct obj *) 0, *otmp; 941. 			    struct container *cons = (struct container *) 942. 				alloc(sizeof(struct container)); 943.  944.  			    while ((otmp = level.objects[x][y]) != 0) { 945. 				remove_object(otmp); 946. 				otmp->ox = otmp->oy = 0; 947. 				otmp->nexthere = olist; 948. 				olist = otmp; 949. 			    }  950.   951.  			    cons->x = x;  952. cons->y = y; 953. cons->what = CONS_OBJ; 954. 			    cons->list = (genericptr_t) olist; 955. 			    cons->next = b->cons; 956. 			    b->cons = cons; 957. 			}  958.  			if (MON_AT(x,y)) { 959. 			    struct monst *mon = m_at(x,y); 960. 			    struct container *cons = (struct container *) 961. 				alloc(sizeof(struct container)); 962.  963.  			    cons->x = x;  964. cons->y = y; 965. cons->what = CONS_MON; 966. 			    cons->list = (genericptr_t) mon; 967.  968.  			    cons->next = b->cons; 969. 			    b->cons = cons; 970.  971.  			    if(mon->wormno) 972. 				remove_worm(mon); 973. 			    else 974. 				remove_monster(x, y); 975.  976.  			    newsym(x,y);	/* clean up old position */ 977. 			    mon->mx = mon->my = 0; 978. 			}  979.  			if (!u.uswallow && x == u.ux && y == u.uy) { 980. 			    struct container *cons = (struct container *) 981. 				alloc(sizeof(struct container)); 982.  983.  			    cons->x = x;  984. cons->y = y; 985. cons->what = CONS_HERO; 986. 			    cons->list = (genericptr_t) 0; 987.  988.  			    cons->next = b->cons; 989. 			    b->cons = cons; 990. 			}  991.  			if ((btrap = t_at(x,y)) != 0) { 992. 			    struct container *cons = (struct container *) 993. 				alloc(sizeof(struct container)); 994.  995.  			    cons->x = x;  996. cons->y = y; 997. cons->what = CONS_TRAP; 998. 			    cons->list = (genericptr_t) btrap; 999.  1000. 			    cons->next = b->cons; 1001. 			   b->cons = cons; 1002. 			} 1003.  1004. 			levl[x][y] = water_pos; 1005. 			block_point(x,y); 1006. 		   }  1007. 	}  1008.  1009. 	/*  1010. 	 * Every second time traverse down. This is because otherwise 1011. 	 * all the junk that changes owners when bubbles overlap 1012. 	 * would eventually end up in the last bubble in the chain. 1013. 	 */ 1014.  1015. 	up = !up; 1016. 	for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) { 1017. 		register int rx = rn2(3), ry = rn2(3); 1018. 1019. 		mv_bubble(b,b->dx + 1 - (!b->dx ? rx : (rx ? 1 : 0)), 1020. 			    b->dy + 1 - (!b->dy ? ry : (ry ? 1 : 0)), 1021. 			    FALSE); 1022. 	} 1023.  1024. 	vision_full_recalc = 1; 1025. } 1026.  1027. /* when moving in water, possibly (1 in 3) alter the intended destination */ 1028. void 1029. water_friction 1030. { 1031. 	register int x, y, dx, dy; 1032. 	register boolean eff = FALSE; 1033. 1034. 	if (is_swimmer(uasmon) && rn2(4)) 1035. 		return;		/* natural swimmers have advantage */ 1036. 1037. 	if (u.dx && !rn2(!u.dy ? 3 : 6)) {	/* 1/3 chance or half that */ 1038. 		/* cancel delta x and choose an arbitrary delta y value */ 1039. 		x = u.ux; 1040. 		do { 1041. 		   dy = rn2(3) - 1;		/* -1, 0, 1 */ 1042. 		   y = u.uy + dy; 1043. 		} while (dy && (!isok(x,y) || !is_pool(x,y))); 1044. 		u.dx = 0; 1045. 		u.dy = dy; 1046. 		eff = TRUE; 1047. 	} else if (u.dy && !rn2(!u.dx ? 3 : 5)) {	/* 1/3 or 1/5*(5/6) */ 1048. 		/* cancel delta y and choose an arbitrary delta x value */ 1049. 		y = u.uy; 1050. 		do { 1051. 		   dx = rn2(3) - 1;		/* -1 .. 1 */ 1052. 		    x = u.ux + dx; 1053. 		} while (dx && (!isok(x,y) || !is_pool(x,y))); 1054. 		u.dy = 0; 1055. 		u.dx = dx; 1056. 		eff = TRUE; 1057. 	} 1058. 	if (eff) pline("Water turbulence affects your movements."); 1059. } 1060.  1061. void 1062. save_waterlevel(fd, mode) 1063. int fd, mode; 1064. { 1065. 	register struct bubble *b; 1066. 1067. 	if (!Is_waterlevel(&u.uz)) return; 1068. 1069. 	if (perform_bwrite(mode)) { 1070. 	   int n = 0; 1071. 	   for (b = bbubbles; b; b = b->next) ++n; 1072. 	   bwrite(fd, (genericptr_t)&n, sizeof (int)); 1073. 	   bwrite(fd, (genericptr_t)&xmin, sizeof (int)); 1074. 	   bwrite(fd, (genericptr_t)&ymin, sizeof (int)); 1075. 	   bwrite(fd, (genericptr_t)&xmax, sizeof (int)); 1076. 	   bwrite(fd, (genericptr_t)&ymax, sizeof (int)); 1077. 	   for (b = bbubbles; b; b = b->next) 1078. 		bwrite(fd, (genericptr_t)b, sizeof (struct bubble)); 1079. 	} 1080. 	if (release_data(mode)) 1081. 	   unsetup_waterlevel; 1082. } 1083.  1084. void 1085. restore_waterlevel(fd) 1086. register int fd; 1087. { 1088. 	register struct bubble *b = (struct bubble *)0, *btmp; 1089. 	register int i; 1090. int n; 1091. 1092. 	if (!Is_waterlevel(&u.uz)) return; 1093. 1094. 	set_wportal; 1095. 	mread(fd,(genericptr_t)&n,sizeof(int)); 1096. 	mread(fd,(genericptr_t)&xmin,sizeof(int)); 1097. 	mread(fd,(genericptr_t)&ymin,sizeof(int)); 1098. 	mread(fd,(genericptr_t)&xmax,sizeof(int)); 1099. 	mread(fd,(genericptr_t)&ymax,sizeof(int)); 1100. 	for (i = 0; i < n; i++) { 1101. 		btmp = b; 1102. b = (struct bubble *)alloc(sizeof(struct bubble)); 1103. 		mread(fd,(genericptr_t)b,sizeof(struct bubble)); 1104. 		if (bbubbles) { 1105. 			btmp->next = b; 1106. b->prev = btmp; 1107. 		} else { 1108. 			bbubbles = b; 1109. b->prev = (struct bubble *)0; 1110. 		} 1111. 		mv_bubble(b,0,0,TRUE); 1112. 	} 1113. 	ebubbles = b;  1114. b->next = (struct bubble *)0; 1115. 	was_waterlevel = TRUE; 1116. } 1117.  1118. static void 1119. set_wportal 1120. { 1121. 	/* there better be only one magic portal on water level... */ 1122. 	for (wportal = ftrap; wportal; wportal = wportal->ntrap) 1123. 		if (wportal->ttyp == MAGIC_PORTAL) return; 1124. 	impossible("set_wportal: no portal!"); 1125. } 1126.  1127. static void 1128. setup_waterlevel 1129. { 1130. 	register int x, y;  1131. register int xskip, yskip; 1132. 	register int water_glyph = cmap_to_glyph(S_water); 1133. 1134. 	/* ouch, hardcoded... */ 1135.  1136. 	xmin = 3; 1137. 	ymin = 1; 1138. 	xmax = 78; 1139. 	ymax = 20; 1140. 1141. 	/* set hero's memory to water */ 1142. 1143. 	for (x = xmin; x <= xmax; x++) 1144. 		for (y = ymin; y <= ymax; y++) 1145. 			levl[x][y].glyph = water_glyph; 1146. 1147. 	/* make bubbles */ 1148. 1149. 	xskip = 10 + rn2(10); 1150. 	yskip = 4 + rn2(4); 1151. 	for (x = bxmin; x <= bxmax; x += xskip) 1152. 		for (y = bymin; y <= bymax; y += yskip) 1153. 			mk_bubble(x,y,rn2(7)); 1154. } 1155.  1156. static void 1157. unsetup_waterlevel 1158. { 1159. 	register struct bubble *b, *bb; 1160. 1161. 	/* free bubbles */ 1162. 1163. 	for (b = bbubbles; b; b = bb) { 1164. 		bb = b->next; 1165. 		free((genericptr_t)b); 1166. 	} 1167. 	bbubbles = ebubbles = (struct bubble *)0; 1168. } 1169.  1170. static void 1171. mk_bubble(x,y,n) 1172. register int x, y, n; 1173. { 1174. 	/*  1175. 	 * These bit masks make visually pleasing bubbles on a normal aspect 1176. 	 * 25x80 terminal, which naturally results in them being mathematically 1177. 	 * anything but symmetric. For this reason they cannot be computed 1178. 	 * in situ, either. The first two elements tell the dimensions of 1179. * the bubble's bounding box. 1180. 	 */ 1181. 	static uchar 1182. 		bm2[] = {2,1,0x3}, 1183. 		bm3[] = {3,2,0x7,0x7}, 1184. 		bm4[] = {4,3,0x6,0xf,0x6}, 1185. 		bm5[] = {5,3,0xe,0x1f,0xe}, 1186. 		bm6[] = {6,4,0x1e,0x3f,0x3f,0x1e}, 1187. 		bm7[] = {7,4,0x3e,0x7f,0x7f,0x3e}, 1188. 		bm8[] = {8,4,0x7e,0xff,0xff,0x7e}, 1189. 		*bmask[] = {bm2,bm3,bm4,bm5,bm6,bm7,bm8}; 1190. 1191. 	register struct bubble *b; 1192. 1193. 	if (x >= bxmax || y >= bymax) return; 1194. 	if (n >= SIZE(bmask)) { 1195. 		impossible("n too large (mk_bubble)"); 1196. 		n = SIZE(bmask) - 1; 1197. 	} 1198. 	b = (struct bubble *)alloc(sizeof(struct bubble)); 1199. 	if ((x + (int) bmask[n][0] - 1) > bxmax) x = bxmax - bmask[n][0] + 1; 1200. 	if ((y + (int) bmask[n][1] - 1) > bymax) y = bymax - bmask[n][1] + 1; 1201. 	b->x = x; 1202. b->y = y; 1203. b->dx = 1 - rn2(3); 1204. 	b->dy = 1 - rn2(3); 1205. 	b->bm = bmask[n]; 1206. 	b->cons = 0; 1207. 	if (!bbubbles) bbubbles = b; 1208. if (ebubbles) { 1209. 		ebubbles->next = b; 1210. b->prev = ebubbles; 1211. 	} 1212. 	else 1213. 		b->prev = (struct bubble *)0; 1214. 	b->next = (struct bubble *)0; 1215. 	ebubbles = b; 1216. mv_bubble(b,0,0,TRUE); 1217. } 1218.  1219. /*  1220.  * The player, the portal and all other objects and monsters 1221. * float along with their associated bubbles. Bubbles may overlap 1222. * freely, and the contents may get associated with other bubbles in  1223. * the process. Bubbles are "sticky", meaning that if the player is 1224. * in the immediate neighborhood of one, he/she may get sucked inside. 1225. * This property also makes leaving a bubble slightly difficult. 1226. */  1227. static void 1228. mv_bubble(b,dx,dy,ini) 1229. register struct bubble *b; 1230. register int dx, dy; 1231. register boolean ini; 1232. { 1233. 	register int x, y, i, j, colli = 0; 1234. 	struct container *cons, *ctemp; 1235. 1236. 	/* move bubble */ 1237. 	if (dx < -1 || dx > 1 || dy < -1 || dy > 1) { 1238. 	   /* pline("mv_bubble: dx = %d, dy = %d", dx, dy); */ 1239. 	   dx = sgn(dx); 1240. 	   dy = sgn(dy); 1241. 	} 1242.  1243. 	/*  1244. 	 * collision with level borders? 1245. 	 *	1 = horizontal border, 2 = vertical, 3 = corner 1246. 	 */ 1247. 	if (b->x <= bxmin) colli |= 2; 1248. 	if (b->y <= bymin) colli |= 1; 1249. 	if ((int) (b->x + b->bm[0] - 1) >= bxmax) colli |= 2; 1250. 	if ((int) (b->y + b->bm[1] - 1) >= bymax) colli |= 1; 1251. 1252. 	if (b->x < bxmin) { 1253. 	   pline("bubble xmin: x = %d, xmin = %d", b->x, bxmin); 1254. 	   b->x = bxmin; 1255. 	} 1256. 	if (b->y < bymin) { 1257. 	   pline("bubble ymin: y = %d, ymin = %d", b->y, bymin); 1258. 	   b->y = bymin; 1259. 	} 1260. 	if ((int) (b->x + b->bm[0] - 1) > bxmax) { 1261. 	   pline("bubble xmax: x = %d, xmax = %d",  1262. 			b->x + b->bm[0] - 1, bxmax); 1263. 	   b->x = bxmax - b->bm[0] + 1; 1264. 	} 1265. 	if ((int) (b->y + b->bm[1] - 1) > bymax) { 1266. 	   pline("bubble ymax: y = %d, ymax = %d",  1267. 			b->y + b->bm[1] - 1, bymax); 1268. 	   b->y = bymax - b->bm[1] + 1; 1269. 	} 1270.  1271. 	/* bounce if we're trying to move off the border */ 1272. 	if (b->x == bxmin && dx < 0) dx = -dx; 1273. 	if (b->x + b->bm[0] - 1 == bxmax && dx > 0) dx = -dx; 1274. 	if (b->y == bymin && dy < 0) dy = -dy; 1275. 	if (b->y + b->bm[1] - 1 == bymax && dy > 0) dy = -dy; 1276. 1277. 	b->x += dx; 1278. 	b->y += dy; 1279. 1280. 	/* void positions inside bubble */ 1281. 1282. 	for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++) 1283. 	   for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++) 1284. 		if (b->bm[j + 2] & (1 << i)) { 1285. 		   levl[x][y].typ = AIR; 1286. 		   levl[x][y].lit = 1; 1287. 		   unblock_point(x,y); 1288. 		} 1289.  1290. 	/* replace contents of bubble */ 1291. 	for (cons = b->cons; cons; cons = ctemp) { 1292. 	   ctemp = cons->next; 1293. 	   cons->x += dx; 1294. 	   cons->y += dy; 1295. 1296. 	    switch(cons->what) { 1297. 		case CONS_OBJ: { 1298. 		   struct obj *olist, *otmp; 1299. 1300. 		    for (olist=(struct obj *)cons->list; olist; olist=otmp) { 1301. 			otmp = olist->nexthere; 1302. 			place_object(olist, cons->x, cons->y); 1303. 		   }  1304. 		    break; 1305. 		} 1306.  1307. 		case CONS_MON: { 1308. 		   struct monst *mon = (struct monst *) cons->list; 1309. 		   (void) mnearto(mon, cons->x, cons->y, TRUE); 1310. 		   break; 1311. 		} 1312.  1313. 		case CONS_HERO: { 1314. 		   int ux0 = u.ux, uy0 = u.uy; 1315. 1316. 		    /* change u.ux0 and u.uy0? */ 1317. 		    u.ux = cons->x; 1318. 		   u.uy = cons->y; 1319. 		   newsym(ux0, uy0);	/* clean up old position */ 1320. 1321. 		    if (MON_AT(cons->x, cons->y)) { 1322. 				mnexto(m_at(cons->x,cons->y)); 1323. 			} 1324. 		    if (Punished) placebc;	/* do this for now */ 1325. 		   break; 1326. 		} 1327.  1328. 		case CONS_TRAP: { 1329. 		   struct trap *btrap = (struct trap *) cons->list; 1330. 		   btrap->tx = cons->x; 1331. 		   btrap->ty = cons->y; 1332. 		   break; 1333. 		} 1334.  1335. 		default: 1336. 		   impossible("mv_bubble: unknown bubble contents"); 1337. 		   break; 1338. 	   }  1339. 	    free((genericptr_t)cons); 1340. 	} 1341. 	b->cons = 0; 1342. 1343. 	/* boing? */ 1344.  1345. 	switch (colli) { 1346. 	   case 1: b->dy = -b->dy;	break; 1347. 	   case 3: b->dy = -b->dy;	/* fall through */ 1348. 	   case 2: b->dx = -b->dx;	break; 1349. 	   default: 1350. 		/* sometimes alter direction for fun anyway 1351. 		  (higher probability for stationary bubbles) */ 1352. 		if (!ini && ((b->dx || b->dy) ? !rn2(20) : !rn2(5))) { 1353. 			b->dx = 1 - rn2(3); 1354. 			b->dy = 1 - rn2(3); 1355. 		} 1356. 	}  1357. }  1358.  1359. /*mkmaze.c*/