Source:SLASH'EM 0.0.7E7F2/mkmaze.c

Below is the full text to mkmaze.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/mkmaze.c#line123 ]], for example.

The latest source code for vanilla NetHack is at Source code.

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