Source:NetHack 3.1.0/mkmaze.c

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