Source:NetHack 3.4.0/mkmaze.c

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