1 /* NetHack 3.6 mkmap.c $NHDT-Date: 1432512767 2015/05/25 00:12:47 $ $NHDT-Branch: master $:$NHDT-Revision: 1.16 $ */
2 /* Copyright (c) J. C. Collet, M. Stephenson and D. Cohrs, 1992 */
3 /* NetHack may be freely redistributed. See license for details. */
8 #define HEIGHT (ROWNO - 1)
9 #define WIDTH (COLNO - 2)
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
,
20 (SCHAR_P
, SCHAR_P
, BOOLEAN_P
, BOOLEAN_P
, BOOLEAN_P
));
21 STATIC_DCL
void FDECL(remove_room
, (unsigned));
22 void FDECL(mkmap
, (lev_init
*));
24 static char *new_locations
;
25 int min_rx
, max_rx
, min_ry
, max_ry
; /* rectangle bounds for regions */
26 static int n_loc_filled
;
34 for (i
= 1; i
< COLNO
; i
++)
35 for (j
= 0; j
< ROWNO
; j
++)
36 levl
[i
][j
].typ
= bg_typ
;
40 init_fill(bg_typ
, fg_typ
)
46 limit
= (WIDTH
* HEIGHT
* 2) / 5;
48 while (count
< limit
) {
49 i
= rn1(WIDTH
- 1, 2);
51 if (levl
[i
][j
].typ
== bg_typ
) {
52 levl
[i
][j
].typ
= fg_typ
;
59 get_map(col
, row
, bg_typ
)
63 if (col
<= 0 || row
< 0 || col
> WIDTH
|| row
>= HEIGHT
)
65 return levl
[col
][row
].typ
;
68 static int dirs
[16] = { -1, -1 /**/, -1, 0 /**/, -1, 1 /**/, 0, -1 /**/,
69 0, 1 /**/, 1, -1 /**/, 1, 0 /**/, 1, 1 };
72 pass_one(bg_typ
, fg_typ
)
78 for (i
= 2; i
<= WIDTH
; i
++)
79 for (j
= 1; j
< HEIGHT
; j
++) {
80 for (count
= 0, dr
= 0; dr
< 8; dr
++)
81 if (get_map(i
+ dirs
[dr
* 2], j
+ dirs
[(dr
* 2) + 1], bg_typ
)
89 levl
[i
][j
].typ
= bg_typ
;
95 levl
[i
][j
].typ
= fg_typ
;
103 #define new_loc(i, j) *(new_locations + ((j) * (WIDTH + 1)) + (i))
106 pass_two(bg_typ
, fg_typ
)
107 schar bg_typ
, fg_typ
;
112 for (i
= 2; i
<= WIDTH
; i
++)
113 for (j
= 1; j
< HEIGHT
; j
++) {
114 for (count
= 0, dr
= 0; dr
< 8; dr
++)
115 if (get_map(i
+ dirs
[dr
* 2], j
+ dirs
[(dr
* 2) + 1], bg_typ
)
119 new_loc(i
, j
) = bg_typ
;
121 new_loc(i
, j
) = get_map(i
, j
, bg_typ
);
124 for (i
= 2; i
<= WIDTH
; i
++)
125 for (j
= 1; j
< HEIGHT
; j
++)
126 levl
[i
][j
].typ
= new_loc(i
, j
);
130 pass_three(bg_typ
, fg_typ
)
131 schar bg_typ
, fg_typ
;
136 for (i
= 2; i
<= WIDTH
; i
++)
137 for (j
= 1; j
< HEIGHT
; j
++) {
138 for (count
= 0, dr
= 0; dr
< 8; dr
++)
139 if (get_map(i
+ dirs
[dr
* 2], j
+ dirs
[(dr
* 2) + 1], bg_typ
)
143 new_loc(i
, j
) = bg_typ
;
145 new_loc(i
, j
) = get_map(i
, j
, bg_typ
);
148 for (i
= 2; i
<= WIDTH
; i
++)
149 for (j
= 1; j
< HEIGHT
; j
++)
150 levl
[i
][j
].typ
= new_loc(i
, j
);
154 * use a flooding algorithm to find all locations that should
155 * have the same rm number as the current location.
156 * if anyroom is TRUE, use IS_ROOM to check room membership instead of
157 * exactly matching levl[sx][sy].typ and walls are included as well.
160 flood_fill_rm(sx
, sy
, rmno
, lit
, anyroom
)
169 schar fg_typ
= levl
[sx
][sy
].typ
;
171 /* back up to find leftmost uninitialized location */
172 while (sx
> 0 && (anyroom
? IS_ROOM(levl
[sx
][sy
].typ
)
173 : levl
[sx
][sy
].typ
== fg_typ
)
174 && (int) levl
[sx
][sy
].roomno
!= rmno
)
176 sx
++; /* compensate for extra decrement */
178 /* assume sx,sy is valid */
184 for (i
= sx
; i
<= WIDTH
&& levl
[i
][sy
].typ
== fg_typ
; i
++) {
185 levl
[i
][sy
].roomno
= rmno
;
186 levl
[i
][sy
].lit
= lit
;
188 /* add walls to room as well */
190 for (ii
= (i
== sx
? i
- 1 : i
); ii
<= i
+ 1; ii
++)
191 for (jj
= sy
- 1; jj
<= sy
+ 1; jj
++)
192 if (isok(ii
, jj
) && (IS_WALL(levl
[ii
][jj
].typ
)
193 || IS_DOOR(levl
[ii
][jj
].typ
)
194 || levl
[ii
][jj
].typ
== SDOOR
)) {
195 levl
[ii
][jj
].edge
= 1;
197 levl
[ii
][jj
].lit
= lit
;
198 if ((int) levl
[ii
][jj
].roomno
!= rmno
)
199 levl
[ii
][jj
].roomno
= SHARED
;
206 if (isok(sx
, sy
- 1)) {
207 for (i
= sx
; i
< nx
; i
++)
208 if (levl
[i
][sy
- 1].typ
== fg_typ
) {
209 if ((int) levl
[i
][sy
- 1].roomno
!= rmno
)
210 flood_fill_rm(i
, sy
- 1, rmno
, lit
, anyroom
);
212 if ((i
> sx
|| isok(i
- 1, sy
- 1))
213 && levl
[i
- 1][sy
- 1].typ
== fg_typ
) {
214 if ((int) levl
[i
- 1][sy
- 1].roomno
!= rmno
)
215 flood_fill_rm(i
- 1, sy
- 1, rmno
, lit
, anyroom
);
217 if ((i
< nx
- 1 || isok(i
+ 1, sy
- 1))
218 && levl
[i
+ 1][sy
- 1].typ
== fg_typ
) {
219 if ((int) levl
[i
+ 1][sy
- 1].roomno
!= rmno
)
220 flood_fill_rm(i
+ 1, sy
- 1, rmno
, lit
, anyroom
);
224 if (isok(sx
, sy
+ 1)) {
225 for (i
= sx
; i
< nx
; i
++)
226 if (levl
[i
][sy
+ 1].typ
== fg_typ
) {
227 if ((int) levl
[i
][sy
+ 1].roomno
!= rmno
)
228 flood_fill_rm(i
, sy
+ 1, rmno
, lit
, anyroom
);
230 if ((i
> sx
|| isok(i
- 1, sy
+ 1))
231 && levl
[i
- 1][sy
+ 1].typ
== fg_typ
) {
232 if ((int) levl
[i
- 1][sy
+ 1].roomno
!= rmno
)
233 flood_fill_rm(i
- 1, sy
+ 1, rmno
, lit
, anyroom
);
235 if ((i
< nx
- 1 || isok(i
+ 1, sy
+ 1))
236 && levl
[i
+ 1][sy
+ 1].typ
== fg_typ
) {
237 if ((int) levl
[i
+ 1][sy
+ 1].roomno
!= rmno
)
238 flood_fill_rm(i
+ 1, sy
+ 1, rmno
, lit
, anyroom
);
244 max_rx
= nx
- 1; /* nx is just past valid region */
250 * If we have drawn a map without walls, this allows us to
251 * auto-magically wallify it. Taken from lev_main.c.
258 for (x
= 1; x
< COLNO
; x
++)
259 for (y
= 0; y
< ROWNO
; y
++)
260 if (levl
[x
][y
].typ
== STONE
) {
261 for (yy
= y
- 1; yy
<= y
+ 1; yy
++)
262 for (xx
= x
- 1; xx
<= x
+ 1; xx
++)
263 if (isok(xx
, yy
) && levl
[xx
][yy
].typ
== ROOM
) {
265 levl
[x
][y
].typ
= HWALL
;
267 levl
[x
][y
].typ
= VWALL
;
273 join_map(bg_typ
, fg_typ
)
274 schar bg_typ
, fg_typ
;
276 register struct mkroom
*croom
, *croom2
;
282 /* first, use flood filling to find all of the regions that need joining
284 for (i
= 2; i
<= WIDTH
; i
++)
285 for (j
= 1; j
< HEIGHT
; j
++) {
286 if (levl
[i
][j
].typ
== fg_typ
&& levl
[i
][j
].roomno
== NO_ROOM
) {
290 flood_fill_rm(i
, j
, nroom
+ ROOMOFFSET
, FALSE
, FALSE
);
291 if (n_loc_filled
> 3) {
292 add_room(min_rx
, min_ry
, max_rx
, max_ry
, FALSE
, OROOM
,
294 rooms
[nroom
- 1].irregular
= TRUE
;
295 if (nroom
>= (MAXNROFROOMS
* 2))
299 * it's a tiny hole; erase it from the map to avoid
300 * having the player end up here with no way out.
302 for (sx
= min_rx
; sx
<= max_rx
; sx
++)
303 for (sy
= min_ry
; sy
<= max_ry
; sy
++)
304 if ((int) levl
[sx
][sy
].roomno
305 == nroom
+ ROOMOFFSET
) {
306 levl
[sx
][sy
].typ
= bg_typ
;
307 levl
[sx
][sy
].roomno
= NO_ROOM
;
315 * Ok, now we can actually join the regions with fg_typ's.
316 * The rooms are already sorted due to the previous loop,
317 * so don't call sort_rooms(), which can screw up the roomno's
318 * validity in the levl structure.
320 for (croom
= &rooms
[0], croom2
= croom
+ 1; croom2
< &rooms
[nroom
];) {
321 /* pick random starting and end locations for "corridor" */
322 if (!somexy(croom
, &sm
) || !somexy(croom2
, &em
)) {
323 /* ack! -- the level is going to be busted */
324 /* arbitrarily pick centers of both rooms and hope for the best */
325 impossible("No start/end room loc in join_map.");
326 sm
.x
= croom
->lx
+ ((croom
->hx
- croom
->lx
) / 2);
327 sm
.y
= croom
->ly
+ ((croom
->hy
- croom
->ly
) / 2);
328 em
.x
= croom2
->lx
+ ((croom2
->hx
- croom2
->lx
) / 2);
329 em
.y
= croom2
->ly
+ ((croom2
->hy
- croom2
->ly
) / 2);
332 (void) dig_corridor(&sm
, &em
, FALSE
, fg_typ
, bg_typ
);
334 /* choose next region to join */
335 /* only increment croom if croom and croom2 are non-overlapping */
336 if (croom2
->lx
> croom
->hx
337 || ((croom2
->ly
> croom
->hy
|| croom2
->hy
< croom
->ly
)
341 croom2
++; /* always increment the next room */
346 finish_map(fg_typ
, bg_typ
, lit
, walled
, icedpools
)
347 schar fg_typ
, bg_typ
;
348 boolean lit
, walled
, icedpools
;
356 for (i
= 1; i
< COLNO
; i
++)
357 for (j
= 0; j
< ROWNO
; j
++)
358 if ((!IS_ROCK(fg_typ
) && levl
[i
][j
].typ
== fg_typ
)
359 || (!IS_ROCK(bg_typ
) && levl
[i
][j
].typ
== bg_typ
)
360 || (bg_typ
== TREE
&& levl
[i
][j
].typ
== bg_typ
)
361 || (walled
&& IS_WALL(levl
[i
][j
].typ
)))
362 levl
[i
][j
].lit
= TRUE
;
363 for (i
= 0; i
< nroom
; i
++)
366 /* light lava even if everything's otherwise unlit;
367 ice might be frozen pool rather than frozen moat */
368 for (i
= 1; i
< COLNO
; i
++)
369 for (j
= 0; j
< ROWNO
; j
++) {
370 if (levl
[i
][j
].typ
== LAVAPOOL
)
371 levl
[i
][j
].lit
= TRUE
;
372 else if (levl
[i
][j
].typ
== ICE
)
373 levl
[i
][j
].icedpool
= icedpools
? ICED_POOL
: ICED_MOAT
;
378 * When level processed by join_map is overlaid by a MAP, some rooms may no
379 * longer be valid. All rooms in the region lx <= x < hx, ly <= y < hy are
380 * removed. Rooms partially in the region are truncated. This function
381 * must be called before the REGIONs or ROOMs of the map are processed, or
382 * those rooms will be removed as well. Assumes roomno fields in the
383 * region are already cleared, and roomno and irregular fields outside the
384 * region are all set.
387 remove_rooms(lx
, ly
, hx
, hy
)
391 struct mkroom
*croom
;
393 for (i
= nroom
- 1; i
>= 0; --i
) {
395 if (croom
->hx
< lx
|| croom
->lx
>= hx
|| croom
->hy
< ly
397 continue; /* no overlap */
399 if (croom
->lx
< lx
|| croom
->hx
>= hx
|| croom
->ly
< ly
400 || croom
->hy
>= hy
) { /* partial overlap */
401 /* TODO: ensure remaining parts of room are still joined */
403 if (!croom
->irregular
)
404 impossible("regular room in joined map");
406 /* total overlap, remove the room */
407 remove_room((unsigned) i
);
413 * Remove roomno from the rooms array, decrementing nroom. Also updates
414 * all level roomno values of affected higher numbered rooms. Assumes
415 * level structure contents corresponding to roomno have already been reset.
416 * Currently handles only the removal of rooms that have no subrooms.
422 struct mkroom
*croom
= &rooms
[roomno
];
423 struct mkroom
*maxroom
= &rooms
[--nroom
];
427 if (croom
!= maxroom
) {
428 /* since the order in the array only matters for making corridors,
429 * copy the last room over the one being removed on the assumption
430 * that corridors have already been dug. */
431 (void) memcpy((genericptr_t
) croom
, (genericptr_t
) maxroom
,
432 sizeof(struct mkroom
));
434 /* since maxroom moved, update affected level roomno values */
435 oroomno
= nroom
+ ROOMOFFSET
;
436 roomno
+= ROOMOFFSET
;
437 for (i
= croom
->lx
; i
<= croom
->hx
; ++i
)
438 for (j
= croom
->ly
; j
<= croom
->hy
; ++j
) {
439 if (levl
[i
][j
].roomno
== oroomno
)
440 levl
[i
][j
].roomno
= roomno
;
444 maxroom
->hx
= -1; /* just like add_room */
447 #define N_P1_ITER 1 /* tune map generation via this value */
448 #define N_P2_ITER 1 /* tune map generation via this value */
449 #define N_P3_ITER 2 /* tune map smoothing via this value */
455 schar bg_typ
= init_lev
->bg
, fg_typ
= init_lev
->fg
;
456 boolean smooth
= init_lev
->smoothed
, join
= init_lev
->joined
;
457 xchar lit
= init_lev
->lit
, walled
= init_lev
->walled
;
461 lit
= (rnd(1 + abs(depth(&u
.uz
))) < 11 && rn2(77)) ? 1 : 0;
463 new_locations
= (char *) alloc((WIDTH
+ 1) * HEIGHT
);
466 init_fill(bg_typ
, fg_typ
);
468 for (i
= 0; i
< N_P1_ITER
; i
++)
469 pass_one(bg_typ
, fg_typ
);
471 for (i
= 0; i
< N_P2_ITER
; i
++)
472 pass_two(bg_typ
, fg_typ
);
475 for (i
= 0; i
< N_P3_ITER
; i
++)
476 pass_three(bg_typ
, fg_typ
);
479 join_map(bg_typ
, fg_typ
);
481 finish_map(fg_typ
, bg_typ
, (boolean
) lit
, (boolean
) walled
,
482 init_lev
->icedpools
);
483 /* a walled, joined level is cavernous, not mazelike -dlc */
484 if (walled
&& join
) {
485 level
.flags
.is_maze_lev
= FALSE
;
486 level
.flags
.is_cavernous_lev
= TRUE
;