Below is the full text to src/mkmap.c from NetHack 3.4.3. To link to a particular line, write [[mkmap.c#line123]], for example.
Top of file[]
1. /* SCCS Id: @(#)mkmap.c 3.4 1996/05/23 */ 2. /* Copyright (c) J. C. Collet, M. Stephenson and D. Cohrs, 1992 */ 3. /* NetHack may be freely redistributed. See license for details. */ 4.
The NetHack General Public License applies to screenshots, source code and other content from NetHack. |
5. #include "hack.h" 6. #include "sp_lev.h" 7. 8. #define HEIGHT (ROWNO - 1) 9. #define WIDTH (COLNO - 2) 10. 11. STATIC_DCL void FDECL(init_map,(SCHAR_P)); 12. STATIC_DCL void FDECL(init_fill,(SCHAR_P,SCHAR_P)); 13. STATIC_DCL schar FDECL(get_map,(int,int,SCHAR_P)); 14. STATIC_DCL void FDECL(pass_one,(SCHAR_P,SCHAR_P)); 15. STATIC_DCL void FDECL(pass_two,(SCHAR_P,SCHAR_P)); 16. STATIC_DCL void FDECL(pass_three,(SCHAR_P,SCHAR_P)); 17. STATIC_DCL void NDECL(wallify_map); 18. STATIC_DCL void FDECL(join_map,(SCHAR_P,SCHAR_P)); 19. STATIC_DCL void FDECL(finish_map,(SCHAR_P,SCHAR_P,XCHAR_P,XCHAR_P)); 20. STATIC_DCL void FDECL(remove_room,(unsigned)); 21. void FDECL(mkmap, (lev_init *)); 22. 23. char *new_locations; 24. int min_rx, max_rx, min_ry, max_ry; /* rectangle bounds for regions */ 25. static int n_loc_filled; 26.
init_map[]
27. STATIC_OVL void 28. init_map(bg_typ) 29. schar bg_typ; 30. { 31. register int i,j; 32. 33. for(i=1; i<COLNO; i++) 34. for(j=0; j<ROWNO; j++) 35. levl[i][j].typ = bg_typ; 36. } 37.
init_fill[]
38. STATIC_OVL void 39. init_fill(bg_typ, fg_typ) 40. schar bg_typ, fg_typ; 41. { 42. register int i,j; 43. long limit, count; 44. 45. limit = (WIDTH * HEIGHT * 2) / 5; 46. count = 0; 47. while(count < limit) { 48. i = rn1(WIDTH-1, 2); 49. j = rnd(HEIGHT-1); 50. if (levl[i][j].typ == bg_typ) { 51. levl[i][j].typ = fg_typ; 52. count++; 53. } 54. } 55. } 56.
get_map[]
57. STATIC_OVL schar 58. get_map(col,row, bg_typ) 59. int col,row; 60. schar bg_typ; 61. { 62. if (col <= 0 || row < 0 || col > WIDTH || row >= HEIGHT) 63. return bg_typ; 64. return levl[col][row].typ; 65. } 66. 67. static int dirs[16] = { 68. -1, -1 /**/, -1, 0 /**/, -1, 1 /**/, 69. 0, -1 /**/, 0, 1 /**/, 70. 1, -1 /**/, 1, 0 /**/, 1, 1}; 71.
pass_one[]
72. STATIC_OVL void 73. pass_one(bg_typ, fg_typ) 74. schar bg_typ, fg_typ; 75. { 76. register int i,j; 77. short count, dr; 78. 79. for(i=2; i<=WIDTH; i++) 80. for(j=1; j<HEIGHT; j++) { 81. for(count=0, dr=0; dr < 8; dr++) 82. if(get_map(i+dirs[dr*2], j+dirs[(dr*2)+1], bg_typ) 83. == fg_typ) 84. count++; 85. 86. switch(count) { 87. case 0 : /* death */ 88. case 1 : 89. case 2: 90. levl[i][j].typ = bg_typ; 91. break; 92. case 5: 93. case 6: 94. case 7: 95. case 8: 96. levl[i][j].typ = fg_typ; 97. break; 98. default: 99. break; 100. } 101. } 102. } 103. 104. #define new_loc(i,j) *(new_locations+ ((j)*(WIDTH+1)) + (i)) 105.
pass_two[]
106. STATIC_OVL void 107. pass_two(bg_typ, fg_typ) 108. schar bg_typ, fg_typ; 109. { 110. register int i,j; 111. short count, dr; 112. 113. for(i=2; i<=WIDTH; i++) 114. for(j=1; j<HEIGHT; j++) { 115. for(count=0, dr=0; dr < 8; dr++) 116. if(get_map(i+dirs[dr*2], j+dirs[(dr*2)+1], bg_typ) 117. == fg_typ) 118. count++; 119. if (count == 5) 120. new_loc(i,j) = bg_typ; 121. else 122. new_loc(i,j) = get_map(i,j, bg_typ); 123. } 124. 125. for(i=2; i<=WIDTH; i++) 126. for(j=1; j<HEIGHT; j++) 127. levl[i][j].typ = new_loc(i,j); 128. } 129.
pass_three[]
130. STATIC_OVL void 131. pass_three(bg_typ, fg_typ) 132. schar bg_typ, fg_typ; 133. { 134. register int i,j; 135. short count, dr; 136. 137. for(i=2; i<=WIDTH; i++) 138. for(j=1; j<HEIGHT; j++) { 139. for(count=0, dr=0; dr < 8; dr++) 140. if(get_map(i+dirs[dr*2], j+dirs[(dr*2)+1], bg_typ) 141. == fg_typ) 142. count++; 143. if (count < 3) 144. new_loc(i,j) = bg_typ; 145. else 146. new_loc(i,j) = get_map(i,j, bg_typ); 147. } 148. 149. for(i=2; i<=WIDTH; i++) 150. for(j=1; j<HEIGHT; j++) 151. levl[i][j].typ = new_loc(i,j); 152. } 153.
flood_fill_rm[]
154. /* 155. * use a flooding algorithm to find all locations that should 156. * have the same rm number as the current location. 157. * if anyroom is TRUE, use IS_ROOM to check room membership instead of 158. * exactly matching levl[sx][sy].typ and walls are included as well. 159. */ 160. void 161. flood_fill_rm(sx, sy, rmno, lit, anyroom) 162. int sx; 163. register int sy; 164. register int rmno; 165. boolean lit; 166. boolean anyroom; 167. { 168. register int i; 169. int nx; 170. schar fg_typ = levl[sx][sy].typ; 171. 172. /* back up to find leftmost uninitialized location */ 173. while (sx > 0 && 174. (anyroom ? IS_ROOM(levl[sx][sy].typ) : levl[sx][sy].typ == fg_typ) && 175. (int) levl[sx][sy].roomno != rmno) 176. sx--; 177. sx++; /* compensate for extra decrement */ 178. 179. /* assume sx,sy is valid */ 180. if(sx < min_rx) min_rx = sx; 181. if(sy < min_ry) min_ry = sy; 182. 183. for(i=sx; i<=WIDTH && levl[i][sy].typ == fg_typ; i++) { 184. levl[i][sy].roomno = rmno; 185. levl[i][sy].lit = lit; 186. if(anyroom) { 187. /* add walls to room as well */ 188. register int ii,jj; 189. for(ii= (i == sx ? i-1 : i); ii <= i+1; ii++) 190. for(jj = sy-1; jj <= sy+1; jj++) 191. if(isok(ii,jj) && 192. (IS_WALL(levl[ii][jj].typ) || 193. IS_DOOR(levl[ii][jj].typ))) { 194. levl[ii][jj].edge = 1; 195. if(lit) levl[ii][jj].lit = lit; 196. if ((int) levl[ii][jj].roomno != rmno) 197. levl[ii][jj].roomno = SHARED; 198. } 199. } 200. n_loc_filled++; 201. } 202. nx = i; 203. 204. if(isok(sx,sy-1)) { 205. for(i=sx; i<nx; i++) 206. if(levl[i][sy-1].typ == fg_typ) { 207. if ((int) levl[i][sy-1].roomno != rmno) 208. flood_fill_rm(i,sy-1,rmno,lit,anyroom); 209. } else { 210. if((i>sx || isok(i-1,sy-1)) && 211. levl[i-1][sy-1].typ == fg_typ) { 212. if ((int) levl[i-1][sy-1].roomno != rmno) 213. flood_fill_rm(i-1,sy-1,rmno,lit,anyroom); 214. } 215. if((i<nx-1 || isok(i+1,sy-1)) && 216. levl[i+1][sy-1].typ == fg_typ) { 217. if ((int) levl[i+1][sy-1].roomno != rmno) 218. flood_fill_rm(i+1,sy-1,rmno,lit,anyroom); 219. } 220. } 221. } 222. if(isok(sx,sy+1)) { 223. for(i=sx; i<nx; i++) 224. if(levl[i][sy+1].typ == fg_typ) { 225. if ((int) levl[i][sy+1].roomno != rmno) 226. flood_fill_rm(i,sy+1,rmno,lit,anyroom); 227. } else { 228. if((i>sx || isok(i-1,sy+1)) && 229. levl[i-1][sy+1].typ == fg_typ) { 230. if ((int) levl[i-1][sy+1].roomno != rmno) 231. flood_fill_rm(i-1,sy+1,rmno,lit,anyroom); 232. } 233. if((i<nx-1 || isok(i+1,sy+1)) && 234. levl[i+1][sy+1].typ == fg_typ) { 235. if ((int) levl[i+1][sy+1].roomno != rmno) 236. flood_fill_rm(i+1,sy+1,rmno,lit,anyroom); 237. } 238. } 239. } 240. 241. if(nx > max_rx) max_rx = nx - 1; /* nx is just past valid region */ 242. if(sy > max_ry) max_ry = sy; 243. } 244.
wallify_map[]
245. /* 246. * If we have drawn a map without walls, this allows us to 247. * auto-magically wallify it. Taken from lev_main.c. 248. */ 249. STATIC_OVL void 250. wallify_map() 251. { 252. 253. int x, y, xx, yy; 254. 255. for(x = 1; x < COLNO; x++) 256. for(y = 0; y < ROWNO; y++) 257. if(levl[x][y].typ == STONE) { 258. for(yy = y - 1; yy <= y+1; yy++) 259. for(xx = x - 1; xx <= x+1; xx++) 260. if(isok(xx,yy) && levl[xx][yy].typ == ROOM) { 261. if(yy != y) levl[x][y].typ = HWALL; 262. else levl[x][y].typ = VWALL; 263. } 264. } 265. } 266.
join_map[]
267. STATIC_OVL void 268. join_map(bg_typ, fg_typ) 269. schar bg_typ, fg_typ; 270. { 271. register struct mkroom *croom, *croom2; 272. 273. register int i, j; 274. int sx, sy; 275. coord sm, em; 276. 277. /* first, use flood filling to find all of the regions that need joining */ 278. for(i=2; i<=WIDTH; i++) 279. for(j=1; j<HEIGHT; j++) { 280. if(levl[i][j].typ == fg_typ && levl[i][j].roomno == NO_ROOM) { 281. min_rx = max_rx = i; 282. min_ry = max_ry = j; 283. n_loc_filled = 0; 284. flood_fill_rm(i,j,nroom+ROOMOFFSET,FALSE,FALSE); 285. if(n_loc_filled > 3) { 286. add_room(min_rx, min_ry, max_rx, max_ry, 287. FALSE, OROOM, TRUE); 288. rooms[nroom-1].irregular = TRUE; 289. if(nroom >= (MAXNROFROOMS*2)) 290. goto joinm; 291. } else { 292. /* 293. * it's a tiny hole; erase it from the map to avoid 294. * having the player end up here with no way out. 295. */ 296. for(sx = min_rx; sx<=max_rx; sx++) 297. for(sy = min_ry; sy<=max_ry; sy++) 298. if ((int) levl[sx][sy].roomno == 299. nroom + ROOMOFFSET) { 300. levl[sx][sy].typ = bg_typ; 301. levl[sx][sy].roomno = NO_ROOM; 302. } 303. } 304. } 305. } 306. 307. joinm: 308. /* 309. * Ok, now we can actually join the regions with fg_typ's. 310. * The rooms are already sorted due to the previous loop, 311. * so don't call sort_rooms(), which can screw up the roomno's 312. * validity in the levl structure. 313. */ 314. for(croom = &rooms[0], croom2 = croom + 1; croom2 < &rooms[nroom]; ) { 315. /* pick random starting and end locations for "corridor" */ 316. if(!somexy(croom, &sm) || !somexy(croom2, &em)) { 317. /* ack! -- the level is going to be busted */ 318. /* arbitrarily pick centers of both rooms and hope for the best */ 319. impossible("No start/end room loc in join_map."); 320. sm.x = croom->lx + ((croom->hx - croom->lx) / 2); 321. sm.y = croom->ly + ((croom->hy - croom->ly) / 2); 322. em.x = croom2->lx + ((croom2->hx - croom2->lx) / 2); 323. em.y = croom2->ly + ((croom2->hy - croom2->ly) / 2); 324. } 325. 326. (void) dig_corridor(&sm, &em, FALSE, fg_typ, bg_typ); 327. 328. /* choose next region to join */ 329. /* only increment croom if croom and croom2 are non-overlapping */ 330. if(croom2->lx > croom->hx || 331. ((croom2->ly > croom->hy || croom2->hy < croom->ly) && rn2(3))) { 332. croom = croom2; 333. } 334. croom2++; /* always increment the next room */ 335. } 336. } 337.
finish_map[]
338. STATIC_OVL void 339. finish_map(fg_typ, bg_typ, lit, walled) 340. schar fg_typ, bg_typ; 341. boolean lit, walled; 342. { 343. int i, j; 344. 345. if(walled) wallify_map(); 346. 347. if(lit) { 348. for(i=1; i<COLNO; i++) 349. for(j=0; j<ROWNO; j++) 350. if((!IS_ROCK(fg_typ) && levl[i][j].typ == fg_typ) || 351. (!IS_ROCK(bg_typ) && levl[i][j].typ == bg_typ) || 352. (bg_typ == TREE && levl[i][j].typ == bg_typ) || 353. (walled && IS_WALL(levl[i][j].typ))) 354. levl[i][j].lit = TRUE; 355. for(i = 0; i < nroom; i++) 356. rooms[i].rlit = 1; 357. } 358. /* light lava even if everything's otherwise unlit */ 359. for(i=1; i<COLNO; i++) 360. for(j=0; j<ROWNO; j++) 361. if (levl[i][j].typ == LAVAPOOL) 362. levl[i][j].lit = TRUE; 363. } 364.
remove_rooms[]
365. /* 366. * When level processed by join_map is overlaid by a MAP, some rooms may no 367. * longer be valid. All rooms in the region lx <= x < hx, ly <= y < hy are 368. * removed. Rooms partially in the region are truncated. This function 369. * must be called before the REGIONs or ROOMs of the map are processed, or 370. * those rooms will be removed as well. Assumes roomno fields in the 371. * region are already cleared, and roomno and irregular fields outside the 372. * region are all set. 373. */ 374. void 375. remove_rooms(lx, ly, hx, hy) 376. int lx, ly, hx, hy; 377. { 378. int i; 379. struct mkroom *croom; 380. 381. for (i = nroom - 1; i >= 0; --i) { 382. croom = &rooms[i]; 383. if (croom->hx < lx || croom->lx >= hx || 384. croom->hy < ly || croom->ly >= hy) continue; /* no overlap */ 385. 386. if (croom->lx < lx || croom->hx >= hx || 387. croom->ly < ly || croom->hy >= hy) { /* partial overlap */ 388. /* TODO: ensure remaining parts of room are still joined */ 389. 390. if (!croom->irregular) impossible("regular room in joined map"); 391. } else { 392. /* total overlap, remove the room */ 393. remove_room((unsigned)i); 394. } 395. } 396. } 397.
remove_room[]
398. /* 399. * Remove roomno from the rooms array, decrementing nroom. Also updates 400. * all level roomno values of affected higher numbered rooms. Assumes 401. * level structure contents corresponding to roomno have already been reset. 402. * Currently handles only the removal of rooms that have no subrooms. 403. */ 404. STATIC_OVL void 405. remove_room(roomno) 406. unsigned roomno; 407. { 408. struct mkroom *croom = &rooms[roomno]; 409. struct mkroom *maxroom = &rooms[--nroom]; 410. int i, j; 411. unsigned oroomno; 412. 413. if (croom != maxroom) { 414. /* since the order in the array only matters for making corridors, 415. * copy the last room over the one being removed on the assumption 416. * that corridors have already been dug. */ 417. (void) memcpy((genericptr_t)croom, (genericptr_t)maxroom, 418. sizeof(struct mkroom)); 419. 420. /* since maxroom moved, update affected level roomno values */ 421. oroomno = nroom + ROOMOFFSET; 422. roomno += ROOMOFFSET; 423. for (i = croom->lx; i <= croom->hx; ++i) 424. for (j = croom->ly; j <= croom->hy; ++j) { 425. if (levl[i][j].roomno == oroomno) 426. levl[i][j].roomno = roomno; 427. } 428. } 429. 430. maxroom->hx = -1; /* just like add_room */ 431. } 432.
mkmap[]
433. #define N_P1_ITER 1 /* tune map generation via this value */ 434. #define N_P2_ITER 1 /* tune map generation via this value */ 435. #define N_P3_ITER 2 /* tune map smoothing via this value */ 436. 437. void 438. mkmap(init_lev) 439. lev_init *init_lev; 440. { 441. schar bg_typ = init_lev->bg, 442. fg_typ = init_lev->fg; 443. boolean smooth = init_lev->smoothed, 444. join = init_lev->joined; 445. xchar lit = init_lev->lit, 446. walled = init_lev->walled; 447. int i; 448. 449. if(lit < 0) 450. lit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) ? 1 : 0; 451. 452. new_locations = (char *)alloc((WIDTH+1) * HEIGHT); 453. 454. init_map(bg_typ); 455. init_fill(bg_typ, fg_typ); 456. 457. for(i = 0; i < N_P1_ITER; i++) 458. pass_one(bg_typ, fg_typ); 459. 460. for(i = 0; i < N_P2_ITER; i++) 461. pass_two(bg_typ, fg_typ); 462. 463. if(smooth) 464. for(i = 0; i < N_P3_ITER; i++) 465. pass_three(bg_typ, fg_typ); 466. 467. if(join) 468. join_map(bg_typ, fg_typ); 469. 470. finish_map(fg_typ, bg_typ, (boolean)lit, (boolean)walled); 471. /* a walled, joined level is cavernous, not mazelike -dlc */ 472. if (walled && join) { 473. level.flags.is_maze_lev = FALSE; 474. level.flags.is_cavernous_lev = TRUE; 475. } 476. free(new_locations); 477. } 478. 479. /*mkmap.c*/