Source:NetHack 3.0.0/sp lev.c

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

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