Source:NetHack 3.1.0/mkmaze.c

From NetHackWiki
Jump to navigation Jump to search

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

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

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*/