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