Source:NetHack 3.0.0/sp lev.c

From NetHackWiki
(Redirected from NetHack 3.0.0/sp lev.c)
Jump to navigation Jump to search

Below is the full text to sp_lev.c from the source code of NetHack 3.0.0. To link to a particular line, write [[NetHack 3.0.0/sp_lev.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: @(#)sp_lev.c	3.0	89/01/11
2.    /*	Copyright (c) 1989 by Jean-Christophe Collet */
3.    /* NetHack may be freely redistributed.  See license for details. */
4.    
5.    /*
6.     * This file contains the various functions that are related to the special
7.     * levels.
8.     * It contains also the special level loader.
9.     *
10.    */
11.   
12.   #include "hack.h"
13.   
14.   #ifdef STRONGHOLD
15.   #include "sp_lev.h"
16.   
17.   #if defined(MSDOS) && !defined(AMIGA)
18.   # define RDMODE "rb"
19.   #else
20.   # define RDMODE "r"
21.   #endif
22.   
23.   #define LEFT	1
24.   #define CENTER	2
25.   #define RIGHT	3
26.   #define TOP	1
27.   #define BOTTOM	3
28.   
29.   static walk walklist[50];
30.   extern int x_maze_max, y_maze_max;
31.   
32.   static char Map[COLNO][ROWNO];
33.   static char robjects[10], rloc_x[10], rloc_y[10], rmonst[10],
34.   	ralign[3] = { A_CHAOS, A_NEUTRAL, A_LAW };
35.   static xchar xstart, ystart, xsize, ysize;
36.   
37.   /*
38.    * Make walls of the area (x1, y1, x2, y2) non diggable
39.    */
40.   
41.   static void
42.   make_walls_nondiggable(x1,y1,x2,y2)
43.   xchar x1, y1, x2, y2;
44.   {
45.   	register xchar x, y;
46.   
47.   	for(y = y1; y <= y2; y++)
48.   	    for(x = x1; x <= x2; x++)
49.   		if(IS_WALL(levl[x][y].typ))
50.   		    levl[x][y].diggable |= W_NONDIGGABLE;
51.   }
52.   
53.   /*
54.    * Choose randomly the state (nodoor, open, closed or locked) for a door
55.    */
56.   
57.   static int
58.   rnddoor()
59.   {
60.   	int i;
61.   	
62.   	i = 1 << rn2(5);
63.   	i >>= 1;
64.   	return i;
65.   }
66.   
67.   /* 
68.    * Select a random trap
69.    */
70.   
71.   static int
72.   rndtrap()
73.   {
74.   	return(rnd(TRAPNUM-1));
75.   }
76.   
77.   /* 
78.    * Coordinates in special level files are handled specially:
79.    *
80.    *	if x or y is -11, we generate a random coordinate.
81.    *	if x or y is between -1 and -10, we read one from the corresponding
82.    *	register (x0, x1, ... x9).
83.    *	if x or y is nonnegative, we convert it from relative to the local map
84.    *	to global coordinates.
85.    */
86.   
87.   static void
88.   get_location(x, y)
89.   schar *x, *y;
90.   {
91.   	int cpt = 0;
92.   
93.   	if (*x >= 0) {			/* normal locations */
94.   		*x += xstart;
95.   		*y += ystart;
96.   	} else if (*x > -11) {		/* special locations */
97.   		*y = ystart + rloc_y[ - *y - 1];
98.   		*x = xstart + rloc_x[ - *x - 1];
99.   	} else {			/* random location */
100.  		do {
101.  		    *x = xstart + rn2((int)xsize);
102.  		    *y = ystart + rn2((int)ysize);
103.  		} while (cpt < 100 &&
104.  			 levl[*x][*y].typ != ROOM &&
105.  			 levl[*x][*y].typ != CORR);
106.  		if(cpt >= 100)
107.  		    panic("get_location: can't find a place!");
108.  	}
109.  
110.  	if (*x < 0 || *x > x_maze_max || *y < 0 || *y > y_maze_max) {
111.  	    impossible("get_location: (%d,%d) out of bounds", *x, *y);
112.  	    *x = x_maze_max; *y = y_maze_max;
113.  	}
114.  }
115.  
116.  /*
117.   * Shuffle the registers for locations, objects or monsters
118.   */
119.  
120.  static void
121.  shuffle(list, n)
122.  char list[];
123.  xchar n;
124.  {
125.  	int i, j;
126.  	char k;
127.  
128.  	for(i = n-1; i; i--) {
129.  		j = rn2(i);
130.  
131.  		k = list[j];
132.  		list[j] = list[i];
133.  		list[i] = k;
134.  	}
135.  }
136.  
137.  /* 
138.   * Shuffle two arrays in the same order (for rloc_x & rloc_y)
139.   */
140.  
141.  static void
142.  shuffle2(list1, list2, n)
143.  char list1[], list2[];
144.  xchar n;
145.  {
146.  	int i, j;
147.  	char k1, k2;
148.  
149.  	for(i = n-1; i; i--) {
150.  		j = rn2(i);
151.  
152.  		k1 = list1[j];
153.  		k2 = list2[j];
154.  
155.  		list1[j] = list1[i];
156.  		list2[j] = list2[i];
157.  
158.  		list1[i] = k1;
159.  		list2[i] = k2;
160.  	}
161.  }
162.  
163.  /* 
164.   * NOT YET IMPLEMENTED!!!
165.   */
166.  
167.  static boolean
168.  load_rooms(fd)
169.  FILE *fd;
170.  {
171.  	return FALSE;
172.  }
173.  
174.  /*
175.   * Select a random coordinate in the maze.
176.   *
177.   * We want a place not 'touched' by the loader.  That is, a place in
178.   * the maze outside every part of the special level.
179.   */
180.  
181.  static void
182.  maze1xy(m)
183.  coord *m;
184.  {
185.  	do {
186.  		m->x = rn1(x_maze_max - 3, 3);
187.  		m->y = rn1(y_maze_max - 3, 3);
188.  	} while (!(m->x % 2) || !(m->y % 2) || Map[m->x][m->y]);
189.  }
190.  
191.  /* 
192.   * The Big Thing: special maze loader
193.   *
194.   * Could be cleaner, but it works.
195.   */
196.  
197.  static boolean
198.  load_maze(fd)
199.  FILE *fd;
200.  {
201.      xchar   x, y, n, typ;
202.      char    c;
203.  
204.      xchar   numpart = 0, nwalk = 0;
205.      uchar   halign, valign;
206.  
207.      int     xi, yi, dir;
208.      coord   mm;
209.      int     mapcount, mapcountmax, mapfact;
210.  
211.      region  tmpregion;
212.      door    tmpdoor;
213.      trap    tmptrap;
214.      monster tmpmons;
215.      object  tmpobj;
216.      drawbridge tmpdb;
217.      walk    tmpwalk;
218.      dig     tmpdig;
219.      lad     tmplad;
220.  #ifdef ALTARS
221.      altar   tmpaltar;
222.  #endif
223.  
224.      /* shuffle alignments */
225.      shuffle(ralign,3);
226.  
227.      /* Initialize map */
228.      xupstair = yupstair = xdnstair = ydnstair = doorindex = 0;
229.      for(x = 2; x <= x_maze_max; x++)
230.  	for(y = 2; y <= y_maze_max; y++) {
231.  #ifndef WALLIFIED_MAZE
232.  	    levl[x][y].typ = STONE;
233.  #else
234.  	    levl[x][y].typ = ((x % 2) && (y % 2)) ? STONE : HWALL;
235.  #endif
236.  	    Map[x][y] = 0;
237.  	}
238.  
239.      /* Start reading the file */
240.      numpart = fgetc(fd); /* Number of parts */
241.      if (!numpart || numpart > 9)
242.  	panic("load_maze error: numpart = %d", (int) numpart);
243.  
244.      while (numpart--) {
245.  	halign = fgetc(fd); /* Horizontal alignment */
246.  	valign = fgetc(fd); /* Vertical alignment */
247.  	xsize  = fgetc(fd); /* size in X */
248.  	ysize  = fgetc(fd); /* size in Y */
249.  
250.  	switch((int) halign) {
251.  	    case LEFT:	    xstart = 3; 				break;
252.  	    case CENTER:    xstart = 2+((x_maze_max-2-xsize)/2);	break;
253.  	    case RIGHT:     xstart = x_maze_max-xsize-1;		break;
254.  	}
255.  	switch((int) valign) {
256.  	    case TOP:	    ystart = 3; 				break;
257.  	    case CENTER:    ystart = 2+((y_maze_max-2-ysize)/2);	break;
258.  	    case BOTTOM:    ystart = y_maze_max-ysize-1;		break;
259.  	}
260.  	if (!(xstart % 2)) xstart++;
261.  	if (!(ystart % 2)) ystart++;
262.  
263.  	/* Load the map */
264.  	for(y = ystart; y < ystart+ysize; y++)
265.  	    for(x = xstart; x < xstart+xsize; x++) {
266.  		levl[x][y].typ = fgetc(fd);
267.  		initsym(x,y);
268.  		/* secret doors default closed */
269.  		if (levl[x][y].typ == SDOOR)
270.  		  levl[x][y].doormask = D_CLOSED;
271.  		Map[x][y] = 1;
272.  	    }
273.  
274.  	n = fgetc(fd); /* Random objects */
275.  	if(n) {
276.  		(void) fread((genericptr_t)robjects, 1, (int) n, fd);
277.  		shuffle(robjects, n);
278.  	}
279.  
280.  	n = fgetc(fd); /* Random locations */
281.  	if(n) {
282.  		(void) fread((genericptr_t)rloc_x, 1, (int) n, fd);
283.  		(void) fread((genericptr_t)rloc_y, 1, (int) n, fd);
284.  		shuffle2(rloc_x, rloc_y, n);
285.  	}
286.  
287.  	n = fgetc(fd); /* Random monsters */
288.  	if(n) {
289.  		(void) fread((genericptr_t)rmonst, 1, (int) n, fd);
290.  		shuffle(rmonst, n);
291.  	}
292.  
293.  	n = fgetc(fd); /* Number of subrooms */
294.  	while(n--) {
295.  		(void) fread((genericptr_t)&tmpregion, sizeof(tmpregion), 1, fd);
296.  		if (nroom >= MAXNROFROOMS) continue;
297.  
298.  		get_location(&tmpregion.x1, &tmpregion.y1);
299.  		get_location(&tmpregion.x2, &tmpregion.y2);
300.  
301.  		rooms[nroom].lx = tmpregion.x1;
302.  		rooms[nroom].ly = tmpregion.y1;
303.  		rooms[nroom].hx = tmpregion.x2;
304.  		rooms[nroom].hy = tmpregion.y2;
305.  		rooms[nroom].rtype = tmpregion.rtype;
306.  		rooms[nroom].rlit = tmpregion.rlit;
307.  		if (tmpregion.rlit == 1)
308.  			for(x = rooms[nroom].lx-1; x <= rooms[nroom].hx+1; x++)
309.  				for(y = rooms[nroom].ly-1; y <= rooms[nroom].hy+1; y++)
310.  					levl[x][y].lit = 1;
311.  
312.  		rooms[nroom].fdoor = rooms[nroom].doorct = 0;
313.  
314.  		++nroom;
315.  		rooms[nroom].hx = -1;
316.  	}
317.  
318.  	n = fgetc(fd); /* Number of doors */
319.  	while(n--) {
320.  		struct mkroom *croom = &rooms[0], *broom;
321.  		int tmp;
322.  
323.  		(void) fread((genericptr_t)&tmpdoor, sizeof(tmpdoor), 1, fd);
324.  
325.  		x = tmpdoor.x;	y = tmpdoor.y;
326.  		typ = tmpdoor.mask == -1 ? rnddoor() : tmpdoor.mask;
327.  
328.  		get_location(&x, &y);
329.  		levl[x][y].doormask = typ;
330.  
331.  		/* Now the complicated part, list it with each subroom */
332.  		/* The dog move and mail daemon routines use this */
333.  		while(croom->hx >= 0 && doorindex < DOORMAX) {
334.  		    if(croom->hx >= x-1 && croom->lx <= x+1 &&
335.  		       croom->hy >= y-1 && croom->ly <= y+1) {
336.  			/* Found it */
337.  			croom->doorct++;
338.  
339.  			/* Append or insert into doors[] */
340.  			broom = croom+1;
341.  			if(broom->hx < 0) tmp = doorindex;
342.  			else
343.  			    for(tmp = doorindex; tmp > broom->fdoor; tmp--)
344.  				doors[tmp] = doors[tmp-1];
345.  
346.  			doors[tmp].x = x;
347.  			doors[tmp].y = y;
348.  			doorindex++;
349.  
350.  			for( ; broom->hx >= 0; broom++) broom->fdoor++;
351.  		    }
352.  		    croom++;
353.  		}
354.  	}
355.  
356.  	n = fgetc(fd); /* Number of traps */
357.  	while(n--) {
358.  		(void) fread((genericptr_t)&tmptrap, sizeof(tmptrap), 1, fd);
359.  
360.  		x = tmptrap.x;	y = tmptrap.y;
361.  		typ = (tmptrap.type == -1 ? rndtrap() : tmptrap.type);
362.  
363.  		get_location(&x, &y);
364.  		(void) maketrap(x, y, typ);
365.  	}
366.  
367.  	n = fgetc(fd);	/* Number of monsters */
368.  	while(n--) {
369.  		(void) fread((genericptr_t)&tmpmons, sizeof(tmpmons), 1, fd);
370.  
371.  		x = tmpmons.x;	y = tmpmons.y;
372.  		get_location(&x, &y);
373.  
374.  		if	(tmpmons.class >= 0)
375.  			c = tmpmons.class;
376.  		else if (tmpmons.class > -11)
377.  			c = rmonst[-tmpmons.class - 1];
378.  		else
379.  			c = 0;
380.  
381.  		if (!c)
382.  			(void) makemon((struct permonst *) 0, x, y);
383.  		else if (tmpmons.id != -1)
384.  			(void) makemon(&mons[tmpmons.id], x, y);
385.  		else
386.  			(void) makemon(mkclass(c), x, y);
387.  	}
388.  
389.  	n = fgetc(fd); /* Number of objects */
390.  	while(n--) {
391.  		(void) fread((genericptr_t) &tmpobj, sizeof(object),1, fd);
392.  
393.  		x = tmpobj.x;  y = tmpobj.y;
394.  		get_location(&x, &y);
395.  
396.  		if	(tmpobj.class >= 0)
397.  			c = tmpobj.class;
398.  		else if (tmpobj.class > -11)
399.  			c = robjects[-tmpobj.class - 1];
400.  		else
401.  			c = 0;
402.  
403.  		if (!c)
404.  			(void) mkobj_at(0, x, y);
405.  		else if (tmpobj.id != -1)
406.  			(void) mksobj_at(tmpobj.id, x, y);
407.  		else
408.  			(void) mkobj_at(c, x, y);
409.  	}
410.  
411.  	n = fgetc(fd); /* Number of drawbridges */
412.  	while(n--) {
413.  		(void) fread((genericptr_t)&tmpdb, sizeof(tmpdb), 1, fd);
414.  
415.  		x = tmpdb.x;  y = tmpdb.y;
416.  		get_location(&x, &y);
417.  
418.  		if (!create_drawbridge(x, y, tmpdb.dir, tmpdb.open))
419.  		    impossible("Cannot create drawbridge.");
420.  	}
421.  
422.  	n = fgetc(fd); /* Number of mazewalks */
423.  	while(n--) {
424.  		(void) fread((genericptr_t)&tmpwalk, sizeof(tmpwalk), 1, fd);
425.  
426.  		get_location(&tmpwalk.x, &tmpwalk.y);
427.  
428.  		walklist[nwalk++] = tmpwalk;
429.  	}
430.  
431.  	n = fgetc(fd); /* Number of non_diggables */
432.  	while(n--) {
433.  		(void) fread((genericptr_t)&tmpdig, sizeof(tmpdig), 1, fd);
434.  
435.  		get_location(&tmpdig.x1, &tmpdig.y1);
436.  		get_location(&tmpdig.x2, &tmpdig.y2);
437.  
438.  		make_walls_nondiggable(tmpdig.x1, tmpdig.y1,
439.  				       tmpdig.x2, tmpdig.y2);
440.  	}
441.  
442.  	n = fgetc(fd); /* Number of ladders */
443.  	while(n--) {
444.  		(void) fread((genericptr_t)&tmplad, sizeof(tmplad), 1, fd);
445.  
446.  		x = tmplad.x;  y = tmplad.y;
447.  		get_location(&x, &y);
448.  
449.  		levl[x][y].typ = LADDER;
450.  		if (tmplad.up == 1) {
451.  			xupladder = x;	yupladder = y;
452.  			levl[x][y].ladder = LA_UP;
453.  		} else {
454.  			xdnladder = x;	ydnladder = y;
455.  			levl[x][y].ladder = LA_DOWN;
456.  		}
457.  	}
458.  
459.  #ifdef ALTARS
460.  	n = fgetc(fd); /* Number of altars */
461.  	while(n--) {
462.  		(void) fread((genericptr_t)&tmpaltar, sizeof(tmpaltar), 1, fd);
463.  
464.  		x = tmpaltar.x;  y = tmpaltar.y;
465.  		get_location(&x, &y);
466.  
467.  		typ = tmpaltar.align == -11 ? rn2(3) :
468.  		      tmpaltar.align < 0    ? ralign[-tmpaltar.align-1] :
469.  					      tmpaltar.align;
470.  		if (tmpaltar.shrine)
471.  		    typ |= A_SHRINE;
472.  
473.  		levl[x][y].typ = ALTAR;
474.  		levl[x][y].altarmask = typ;
475.  	}
476.  #endif /* ALTARS /**/
477.      }
478.  
479.      while(nwalk--) {
480.  	    xi = walklist[nwalk].x;
481.  	    yi = walklist[nwalk].y;
482.  	    dir = walklist[nwalk].dir;
483.  
484.  	    move(&xi, &yi, dir);
485.  	    x = xi;
486.  	    y = yi;
487.  
488.  #ifndef WALLIFIED_MAZE
489.  	    levl[x][y].typ = CORR;
490.  #else
491.  	    levl[x][y].typ = ROOM;
492.  #endif
493.  
494.  	    /*
495.  	     * We must be sure that the parity of the coordinates for
496.  	     * walkfrom() is odd.  But we must also take into account
497.  	     * what direction was chosen.
498.  	     */
499.  	    if(!(x % 2))
500.  		if (dir == W_EAST)
501.  		    x++;
502.  		else
503.  		    x--;
504.  
505.  #ifndef WALLIFIED_MAZE
506.  	    levl[x][y].typ = CORR;
507.  #else
508.  	    levl[x][y].typ = ROOM;
509.  #endif
510.  
511.  	    if (!(y % 2))
512.  		if (dir == W_SOUTH)
513.  		    y++;
514.  		else
515.  		    y--;
516.  
517.  	    walkfrom(x, y);
518.      }
519.      wallification(2, 2, x_maze_max, y_maze_max, TRUE);
520.  
521.      /*
522.       * If there's a significant portion of maze unused by the special level,
523.       * we don't want it empty.
524.       *
525.       * Makes the number of traps, monsters, etc. proportional
526.       * to the size of the maze.
527.       */
528.      mapcountmax = mapcount = (x_maze_max - 2) * (y_maze_max - 2);
529.  
530.      for(x = 2; x < x_maze_max; x++)
531.  	for(y = 2; y < y_maze_max; y++)
532.  	    if(Map[x][y]) mapcount--;
533.  
534.      if (mapcount > (int) (mapcountmax / 10)) {
535.  	    mapfact = (int) ((mapcount * 100L) / mapcountmax);
536.  	    for(x = rnd((int) (20 * mapfact) / 100); x; x--) {
537.  		    maze1xy(&mm);
538.  		    (void) mkobj_at(rn2(2) ? GEM_SYM : 0, mm.x, mm.y);
539.  	    }
540.  	    for(x = rnd((int) (12 * mapfact) / 100); x; x--) {
541.  		    maze1xy(&mm);
542.  		    (void) mksobj_at(BOULDER, mm.x, mm.y);
543.  	    }
544.  	    maze1xy(&mm);
545.  	    (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y);
546.  	    for(x = rnd((int) (12 * mapfact) / 100); x; x--) {
547.  		    maze1xy(&mm);
548.  		    (void) makemon((struct permonst *) 0, mm.x, mm.y);
549.  	    }
550.  	    for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
551.  		    maze1xy(&mm);
552.  		    mkgold(0L,mm.x,mm.y);
553.  	    }
554.  	    for(x = rn2((int) (15 * mapfact) / 100); x; x--) {
555.  		    maze1xy(&mm);
556.  		    (void) maketrap(mm.x, mm.y,rndtrap());
557.  	    }
558.      }
559.      return TRUE;
560.  }
561.  
562.  /*
563.   * General loader
564.   */
565.  
566.  boolean
567.  load_special(name)
568.  char *name;
569.  {
570.  	FILE *fd;
571.  	boolean result;
572.  	schar c;
573.  
574.  	fd = fopen(name, RDMODE);
575.  	if (!fd) return FALSE;
576.  
577.  	if ((c = fgetc(fd)) == EOF) {
578.  		(void)fclose(fd);
579.  		return FALSE;
580.  	}
581.  
582.  	switch (c) {
583.  		case 1: 	/* Alas, this is not yet implemented. */
584.  		    result = load_rooms(fd);
585.  		    break;
586.  		case 2: 	/* But this is implemented :-) */
587.  		    result = load_maze(fd);
588.  		    break;
589.  		default:	/* ??? */
590.  		    result = FALSE;
591.  	}
592.  	(void)fclose(fd);
593.  	return result;
594.  }
595.  #endif /* STRONGHOLD /**/