Source:NetHack 3.0.0/sp lev.c
Revision as of 05:30, 4 March 2008 by Kernigh bot (talk | contribs) (NetHack 3.0.0/sp lev.c moved to Source:NetHack 3.0.0/sp lev.c: Robot: moved page)
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 /**/