1 | #include "system.h" |
2 | |
3 | #include "defs.h" |
4 | #include "struct.h" |
5 | #include "../src/global.h" |
6 | #include "proto.h" |
7 | |
8 | #include "mapgen/mapgen.h" |
9 | |
10 | #define MIN_ROOM_WIDE6 6 |
11 | |
12 | |
13 | static const int Smin = 100; |
14 | |
15 | |
16 | static int dim_x_init; |
17 | static int dim_y_init; |
18 | |
19 | |
20 | #define WORST_ROOM_RATIO2.0 2.0 |
21 | |
22 | enum cut_axis { |
23 | CUT_HORIZONTALLY = 0, |
24 | CUT_VERTICALLY = 1, |
25 | DO_NOT_CUT = 2 |
26 | }; |
27 | |
28 | |
29 | |
30 | static int check_surf(int w_creator, int h_creator, int w_newroom, int h_newroom) |
31 | { |
32 | if ((w_creator * h_creator > Smin) && (h_newroom * w_newroom > Smin)) |
33 | return 1; |
34 | |
35 | return 0; |
36 | } |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | static int trycut(int dim_x, int dim_y, int *r, enum cut_axis vert) |
45 | { |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | float rmin = 1, rmin2 = 1, rmax = 0, rmax2 = 0; |
61 | |
62 | switch (vert) { |
63 | case CUT_HORIZONTALLY: |
64 | rmax = WORST_ROOM_RATIO2.0 * (float)dim_x / dim_y; |
65 | rmin2 = (1.0 / WORST_ROOM_RATIO2.0) * dim_x / dim_y; |
66 | break; |
67 | case CUT_VERTICALLY: |
68 | rmax = WORST_ROOM_RATIO2.0 * (float)dim_y / dim_x; |
69 | rmin2 = (1.0 / WORST_ROOM_RATIO2.0) * dim_y / dim_x; |
70 | break; |
71 | default: |
72 | ; |
73 | } |
74 | |
75 | rmin = 1 - rmax; |
76 | rmax2 = 1 - rmin2; |
77 | |
78 | rmax = rmax > rmax2 ? rmax2 : rmax; |
79 | rmin = rmin < rmin2 ? rmin2 : rmin; |
80 | |
81 | if (rmax < rmin) { |
82 | |
83 | return 0; |
84 | } |
85 | |
86 | *r = 100.0 * (rmin + (rmax - rmin) * ((float)rand() / (float)RAND_MAX2147483647)); |
87 | |
88 | return 1; |
89 | } |
90 | |
91 | |
92 | |
93 | |
94 | |
95 | static enum cut_axis cut(int dim_x, int dim_y, int *r) |
96 | { |
97 | enum cut_axis ret = DO_NOT_CUT; |
98 | |
99 | float chancetocut = (1 / (dim_x_init * dim_y_init)) * dim_x * dim_y - (Smin / (dim_x_init * dim_y_init - Smin)); |
100 | float p = rand() % 10000 + 1; |
101 | |
102 | |
103 | if (p / 10000 < chancetocut) { |
104 | return DO_NOT_CUT; |
105 | } |
106 | |
107 | ret = rand() % 2; |
108 | |
109 | |
110 | if (!trycut(dim_x, dim_y, r, ret)) { |
111 | |
112 | if (!trycut(dim_x, dim_y, r, !ret)) |
113 | return DO_NOT_CUT; |
114 | else |
115 | ret = !ret; |
116 | } |
117 | |
118 | switch (ret) { |
119 | case CUT_HORIZONTALLY: |
120 | if ((*r / 100.0 * dim_y) < MIN_ROOM_WIDE6 || ((100.0 - *r) / 100.0 * dim_y) < MIN_ROOM_WIDE6) |
121 | return DO_NOT_CUT; |
122 | break; |
123 | case CUT_VERTICALLY: |
124 | if ((*r / 100.0 * dim_x) < MIN_ROOM_WIDE6 || ((100.0 - *r) / 100.0 * dim_x) < MIN_ROOM_WIDE6) |
125 | return DO_NOT_CUT; |
126 | break; |
127 | default: |
128 | ; |
129 | } |
130 | |
131 | return ret; |
132 | } |
133 | |
134 | static void deriv_P(int id) |
135 | { |
136 | int p; |
137 | int prop; |
138 | int x = rooms[id].x; |
139 | int y = rooms[id].y; |
140 | int creator = id; |
141 | int dim_x = rooms[creator].w; |
142 | int dim_y = rooms[creator].h; |
143 | int newroom; |
144 | p = cut(dim_x, dim_y, &prop); |
145 | |
146 | int w_creator = dim_x; |
147 | int h_creator = dim_y; |
148 | int w_newroom = dim_x; |
149 | int h_newroom = dim_y; |
150 | int x_newroom = x; |
151 | int y_newroom = y; |
152 | |
153 | |
154 | |
155 | |
156 | |
157 | |
158 | |
159 | |
160 | switch (p) { |
161 | case CUT_HORIZONTALLY: |
162 | h_creator = rooms[creator].h * prop / 100.0; |
163 | |
164 | h_newroom = dim_y - h_creator - 1; |
165 | y_newroom = y + h_creator + 1; |
166 | break; |
167 | case CUT_VERTICALLY: |
168 | w_creator = rooms[creator].w * prop / 100.0; |
169 | |
170 | w_newroom = dim_x - w_creator - 1; |
171 | x_newroom = x + w_creator + 1; |
172 | break; |
173 | default: |
174 | return; |
175 | } |
176 | |
177 | if (!check_surf(w_creator, h_creator, w_newroom, h_newroom)) { |
178 | return; |
179 | } |
180 | |
181 | newroom = mapgen_add_room(x_newroom, y_newroom, w_newroom, h_newroom); |
182 | |
183 | rooms[creator].w = w_creator; |
184 | rooms[creator].h = h_creator; |
185 | |
186 | mapgen_draw_room(newroom); |
187 | mapgen_draw_room(creator); |
188 | deriv_P(id); |
189 | deriv_P(newroom); |
190 | } |
191 | |
192 | static void adj(struct cplist_t *cplist, int *nx, int *ny) |
193 | { |
194 | static const int dx[] = {0, 0, -1, 1}; |
195 | static const int dy[] = {-1, 1, 0, 0}; |
196 | if (cplist->t != UP && cplist->t != DOWN && cplist->t != LEFT && cplist->t != RIGHT) { |
197 | *nx = 0; |
198 | *ny = 0; |
199 | } |
200 | *nx = cplist->x + dx[cplist->t]; |
201 | *ny = cplist->y + dy[cplist->t]; |
202 | } |
203 | |
204 | static int set_internal_door(int room1, int room2) |
205 | { |
206 | int i; |
207 | for (i = 0; i < rooms[room1].num_doors; i++) { |
208 | if (rooms[room1].doors[i].room == room2) { |
209 | rooms[room1].doors[i].internal = 1; |
210 | return 1; |
211 | } |
212 | } |
213 | |
214 | return 0; |
215 | } |
216 | |
217 | |
218 | |
219 | |
220 | void fusion(int id, int cible) |
221 | { |
222 | int new_owner; |
223 | struct cplist_t cplist[100]; |
224 | int correct_directory[100]; |
225 | |
226 | memset(correct_directory, -1, 100 * sizeof(int)); |
227 | memset(cplist, -1, 100 * sizeof(struct cplist_t)); |
228 | |
229 | int nb_max; |
230 | nb_max = find_connection_points(id, cplist, 0); |
231 | int k = 0; |
232 | int l = 0; |
233 | while (k < nb_max) { |
234 | if (cplist[k].r == cible) { |
235 | correct_directory[l] = k; |
236 | l++; |
237 | } |
238 | k++; |
239 | } |
240 | |
241 | |
242 | |
243 | if (l == rooms[id].w || l == rooms[id].h) |
244 | new_owner = id; |
245 | else |
246 | new_owner = cible; |
247 | int x, y; |
248 | for (k = 0; k < l; k++) { |
249 | x = cplist[correct_directory[k]].x; |
250 | y = cplist[correct_directory[k]].y; |
251 | mapgen_put_tile(x, y, TILE_PARTITION, new_owner); |
252 | } |
253 | |
254 | |
255 | if (l && !set_internal_door(id, cible)) |
256 | set_internal_door(cible, id); |
257 | } |
258 | |
259 | static void add_rel(int x, int y, enum connection_type type, int r, int cible) |
260 | { |
261 | MakeConnect(x, y, type); |
262 | if ((((rooms[r].x != rooms[cible].x) || (rooms[r].w != rooms[cible].w)) && (type == UP || type == DOWN)) |
263 | || (((rooms[r].y != rooms[cible].y) || (rooms[r].h != rooms[cible].h)) && (type == RIGHT || type == LEFT))) { |
264 | if (!(rand() % 4)) |
265 | fusion(r, cible); |
266 | } |
267 | } |
268 | |
269 | static void bulldozer(unsigned char *seen, int r) |
270 | { |
271 | struct cplist_t cplist[300]; |
272 | int max_connections = find_connection_points(r, cplist, 3); |
| 1 | 'max_connections' initialized here | |
|
273 | if (!max_connections) |
| 2 | | Assuming 'max_connections' is 0 | |
|
| |
274 | error_message(__FUNCTION__, "Room %d does not have any connection points.", PLEASE_INFORM | IS_FATAL, r); |
275 | |
276 | |
277 | seen[r] = 1; |
278 | |
279 | |
280 | int i = rand() % max_connections; |
| |
281 | int x2 = cplist[i].x; |
282 | int y2 = cplist[i].y; |
283 | adj(&cplist[i], &x2, &y2); |
284 | |
285 | |
286 | if (mapgen_are_connected(r, cplist[i].r)) |
287 | return; |
288 | |
289 | |
290 | add_rel(cplist[i].x, cplist[i].y, cplist[i].t, r, cplist[i].r); |
291 | |
292 | |
293 | bulldozer(seen, mapgen_get_room(x2, y2)); |
294 | } |
295 | |
296 | static void launch_buldo() |
297 | { |
298 | int r, i, recalculate_components; |
299 | unsigned char seen[total_rooms]; |
300 | unsigned char connected_to_room_0[total_rooms]; |
301 | memset(seen, 0, total_rooms); |
302 | |
303 | |
304 | for (r = 0; r < total_rooms; r++) { |
305 | if (!(seen[r])) { |
306 | bulldozer(seen, r); |
307 | } |
308 | } |
309 | |
310 | |
311 | |
312 | |
313 | |
314 | while (!mapgen_is_connected(connected_to_room_0)) { |
315 | recalculate_components = 0; |
316 | |
317 | for (i = 1; i < total_rooms && !recalculate_components; i++) { |
318 | if (!connected_to_room_0[i]) { |
319 | |
320 | int n; |
321 | struct cplist_t neigh[100]; |
322 | int nbconn, prevneigh = -1; |
323 | nbconn = find_connection_points(i, neigh, 3); |
324 | for (n = 0; n < nbconn; n++) { |
325 | if (neigh[n].r == prevneigh) { |
326 | continue; |
327 | } else { |
328 | int next = 0; |
329 | while (n + next < nbconn && neigh[n + next].r == neigh[n].r) |
330 | next++; |
331 | |
332 | int pick = n + rand() % next; |
333 | |
334 | n = pick; |
335 | } |
336 | |
337 | prevneigh = neigh[n].r; |
338 | |
339 | if (connected_to_room_0[neigh[n].r]) { |
340 | add_rel(neigh[n].x, neigh[n].y, neigh[n].t, i, neigh[n].r); |
341 | |
342 | if (!(rand() % 3)) { |
343 | recalculate_components = 1; |
344 | } |
345 | |
346 | break; |
347 | } |
348 | } |
349 | } |
350 | } |
351 | } |
352 | } |
353 | |
354 | int generate_dungeon_gram(int dim_x, int dim_y) |
355 | { |
356 | dim_x_init = dim_x; |
357 | dim_y_init = dim_y; |
358 | total_rooms = 0; |
359 | |
360 | |
361 | mapgen_add_room(1, 1, dim_x - 2, dim_y - 2); |
362 | mapgen_draw_room(0); |
363 | |
364 | |
365 | deriv_P(0); |
366 | |
367 | |
368 | launch_buldo(); |
369 | return 0; |
370 | } |