FANDOM


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.


The NetHack General Public License applies to screenshots, source code and other content from NetHack.
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*/

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.