ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.14
Committed: Mon Apr 14 22:41:17 2008 UTC (16 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.13: +8 -10 lines
Log Message:
refactor random map gen more

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2001,2007 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen
7 *
8 * Deliantra is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 * The authors can be reached via e-mail to <support@deliantra.net>
22 */
23
24 /* The onion room generator:
25 Onion rooms are like this:
26
27 char **map_gen_onion(int xsize, int ysize, int option, int layers);
28
29 like this:
30 regular random
31 centered, linear onion bottom/right centered, nonlinear
32
33 ######################### #########################
34 # # # #
35 # ######## ########## # # #####################
36 # # # # # # #
37 # # ###### ######## # # # # #
38 # # # # # # # # ######## ########
39 # # # #### ###### # # # # # # #
40 # # # # # # # # # # # #
41 # # # ############ # # # # # # ########### ##
42 # # # # # # # # # # #
43 # # ################ # # # # # # #########
44 # # # # # # # # #
45 # #################### # # # # # #
46 # # # # # # # #
47 ######################### #########################
48
49 */
50
51
52 #include <global.h>
53 #include <random_map.h>
54
55 #ifndef MIN
56 # define MIN(x,y) (((x)<(y))? (x):(y))
57 #endif
58 void centered_onion (char **maze, int xsize, int ysize, int option, int layers);
59 void bottom_centered_onion (char **maze, int xsize, int ysize, int option, int layers);
60 void bottom_right_centered_onion (char **maze, int xsize, int ysize, int option, int layers);
61
62 void draw_onion (char **maze, float *xlocations, float *ylocations, int layers);
63 void make_doors (char **maze, float *xlocations, float *ylocations, int layers, int options);
64
65 void
66 map_gen_onion (Maze maze, int option, int layers)
67 {
68 int i, j;
69
70 int xsize = maze->w;
71 int ysize = maze->h;
72
73 maze->clear ();
74
75 /* pick some random options if option = 0 */
76 if (option == 0)
77 {
78 switch (rndm (3))
79 {
80 case 0:
81 option |= RMOPT_CENTERED;
82 break;
83 case 1:
84 option |= RMOPT_BOTTOM_C;
85 break;
86 case 2:
87 option |= RMOPT_BOTTOM_R;
88 break;
89 }
90
91 if (rndm (2)) option |= RMOPT_LINEAR;
92 if (rndm (2)) option |= RMOPT_IRR_SPACE;
93 }
94
95 /* write the outer walls, if appropriate. */
96 if (!(option & RMOPT_WALL_OFF))
97 maze->border ();
98
99 if (option & RMOPT_WALLS_ONLY)
100 return;
101
102 /* pick off the mutually exclusive options */
103 if (option & RMOPT_BOTTOM_R)
104 bottom_right_centered_onion (maze, xsize, ysize, option, layers);
105 else if (option & RMOPT_BOTTOM_C)
106 bottom_centered_onion (maze, xsize, ysize, option, layers);
107 else if (option & RMOPT_CENTERED)
108 centered_onion (maze, xsize, ysize, option, layers);
109 }
110
111 void
112 centered_onion (char **maze, int xsize, int ysize, int option, int layers)
113 {
114 int i, maxlayers;
115
116 maxlayers = (MIN (xsize, ysize) - 2) / 5;
117
118 if (!maxlayers)
119 return; /* map too small to onionize */
120
121 if (layers > maxlayers)
122 layers = maxlayers;
123
124 if (layers == 0)
125 layers = rndm (maxlayers) + 1;
126
127 float *xlocations = salloc0<float> (2 * layers);
128 float *ylocations = salloc0<float> (2 * layers);
129
130 /* place all the walls */
131 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
132 {
133 int x_spaces_available, y_spaces_available;
134
135 /* the "extra" spaces available for spacing between layers */
136 x_spaces_available = (xsize - 2) - 6 * layers + 1;
137 y_spaces_available = (ysize - 2) - 6 * layers + 1;
138
139 /* pick an initial random pitch */
140 for (i = 0; i < 2 * layers; i++)
141 {
142 float xpitch = 2, ypitch = 2;
143
144 if (x_spaces_available > 0)
145 xpitch = 2 + (rndm (x_spaces_available) + rndm (x_spaces_available) + rndm (x_spaces_available)) / 3;
146
147 if (y_spaces_available > 0)
148 ypitch = 2 + (rndm (y_spaces_available) + rndm (y_spaces_available) + rndm (y_spaces_available)) / 3;
149
150 xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
151 ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
152 x_spaces_available -= (int) (xpitch - 2);
153 y_spaces_available -= (int) (ypitch - 2);
154 }
155
156 }
157
158 if (!(option & RMOPT_IRR_SPACE))
159 { /* evenly spaced */
160 float xpitch, ypitch; /* pitch of the onion layers */
161
162 xpitch = (xsize - 2.0) / (2.0 * layers + 1);
163 ypitch = (ysize - 2.0) / (2.0 * layers + 1);
164
165 xlocations[0] = xpitch;
166 ylocations[0] = ypitch;
167
168 for (i = 1; i < 2 * layers; i++)
169 {
170 xlocations[i] = xlocations[i - 1] + xpitch;
171 ylocations[i] = ylocations[i - 1] + ypitch;
172 }
173 }
174
175 /* draw all the onion boxes. */
176 draw_onion (maze, xlocations, ylocations, layers);
177 make_doors (maze, xlocations, ylocations, layers, option);
178
179 sfree (xlocations, 2 * layers);
180 sfree (ylocations, 2 * layers);
181 }
182
183 void
184 bottom_centered_onion (char **maze, int xsize, int ysize, int option, int layers)
185 {
186 int i, maxlayers;
187
188 maxlayers = (MIN (xsize, ysize) - 2) / 5;
189
190 if (!maxlayers)
191 return; /* map too small to onionize */
192
193 if (layers > maxlayers)
194 layers = maxlayers;
195
196 if (layers == 0)
197 layers = rndm (maxlayers) + 1;
198
199 float *xlocations = salloc0<float> (2 * layers);
200 float *ylocations = salloc0<float> (2 * layers);
201
202 /* place all the walls */
203 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
204 {
205 int x_spaces_available, y_spaces_available;
206
207 /* the "extra" spaces available for spacing between layers */
208 x_spaces_available = (xsize - 2) - 6 * layers + 1;
209 y_spaces_available = (ysize - 2) - 3 * layers + 1;
210
211 /* pick an initial random pitch */
212 for (i = 0; i < 2 * layers; i++)
213 {
214 float xpitch = 2, ypitch = 2;
215
216 if (x_spaces_available > 0)
217 xpitch = 2 + (rndm (x_spaces_available) + rndm (x_spaces_available) + rndm (x_spaces_available)) / 3;
218
219 if (y_spaces_available > 0)
220 ypitch = 2 + (rndm (y_spaces_available) + rndm (y_spaces_available) + rndm (y_spaces_available)) / 3;
221
222 xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
223
224 if (i < layers)
225 ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
226 else
227 ylocations[i] = ysize - 1;
228
229 x_spaces_available -= (int) (xpitch - 2);
230 y_spaces_available -= (int) (ypitch - 2);
231 }
232 }
233
234 if (!(option & RMOPT_IRR_SPACE))
235 { /* evenly spaced */
236 float xpitch, ypitch; /* pitch of the onion layers */
237
238 xpitch = (xsize - 2.0) / (2.0 * layers + 1);
239 ypitch = (ysize - 2.0) / (layers + 1);
240
241 xlocations[0] = xpitch;
242 ylocations[0] = ypitch;
243
244 for (i = 1; i < 2 * layers; i++)
245 {
246 xlocations[i] = xlocations[i - 1] + xpitch;
247
248 if (i < layers)
249 ylocations[i] = ylocations[i - 1] + ypitch;
250 else
251 ylocations[i] = ysize - 1;
252 }
253 }
254
255 /* draw all the onion boxes. */
256
257 draw_onion (maze, xlocations, ylocations, layers);
258 make_doors (maze, xlocations, ylocations, layers, option);
259
260 sfree (xlocations, 2 * layers);
261 sfree (ylocations, 2 * layers);
262 }
263
264 /* draw_boxes: draws the lines in the maze defining the onion layers */
265 void
266 draw_onion (char **maze, float *xlocations, float *ylocations, int layers)
267 {
268 int i, j, l;
269
270 for (l = 0; l < layers; l++)
271 {
272 int x1, x2, y1, y2;
273
274 /* horizontal segments */
275 y1 = (int) ylocations[l];
276 y2 = (int) ylocations[2 * layers - l - 1];
277 for (i = (int) xlocations[l]; i <= (int) xlocations[2 * layers - l - 1]; i++)
278 {
279 maze[i][y1] = '#';
280 maze[i][y2] = '#';
281 }
282
283 /* vertical segments */
284 x1 = (int) xlocations[l];
285 x2 = (int) xlocations[2 * layers - l - 1];
286 for (j = (int) ylocations[l]; j <= (int) ylocations[2 * layers - l - 1]; j++)
287 {
288 maze[x1][j] = '#';
289 maze[x2][j] = '#';
290 }
291
292 }
293 }
294
295 void
296 make_doors (char **maze, float *xlocations, float *ylocations, int layers, int options)
297 {
298 int freedoms; /* number of different walls on which we could place a door */
299 int which_wall; /* left, 1, top, 2, right, 3, bottom 4 */
300 int l, x1 = 0, x2, y1 = 0, y2;
301
302 freedoms = 4; /* centered */
303
304 if (options & RMOPT_BOTTOM_C)
305 freedoms = 3;
306
307 if (options & RMOPT_BOTTOM_R)
308 freedoms = 2;
309
310 if (layers <= 0)
311 return;
312
313 /* pick which wall will have a door. */
314 which_wall = rndm (freedoms) + 1;
315 for (l = 0; l < layers; l++)
316 {
317 if (options & RMOPT_LINEAR)
318 { /* linear door placement. */
319 switch (which_wall)
320 {
321 case 1:
322 { /* left hand wall */
323 x1 = (int) xlocations[l];
324 y1 = (int) ((ylocations[l] + ylocations[2 * layers - l - 1]) / 2);
325 break;
326 }
327 case 2:
328 { /* top wall placement */
329 x1 = (int) ((xlocations[l] + xlocations[2 * layers - l - 1]) / 2);
330 y1 = (int) ylocations[l];
331 break;
332 }
333 case 3:
334 { /* right wall placement */
335 x1 = (int) xlocations[2 * layers - l - 1];
336 y1 = (int) ((ylocations[l] + ylocations[2 * layers - l - 1]) / 2);
337 break;
338 }
339 case 4:
340 { /* bottom wall placement */
341 x1 = (int) ((xlocations[l] + xlocations[2 * layers - l - 1]) / 2);
342 y1 = (int) ylocations[2 * layers - l - 1];
343 break;
344 }
345 }
346 }
347 else
348 { /* random door placement. */
349 which_wall = rndm (freedoms) + 1;
350 switch (which_wall)
351 {
352 case 1:
353 { /* left hand wall */
354 x1 = (int) xlocations[l];
355 y2 = (int) (ylocations[2 * layers - l - 1] - ylocations[l] - 1);
356 if (y2 > 0)
357 y1 = (int) (ylocations[l] + rndm (y2) + 1);
358 else
359 y1 = (int) (ylocations[l] + 1);
360 break;
361 }
362 case 2:
363 { /* top wall placement */
364 x2 = (int) ((-xlocations[l] + xlocations[2 * layers - l - 1])) - 1;
365 if (x2 > 0)
366 x1 = (int) (xlocations[l] + rndm (x2) + 1);
367 else
368 x1 = (int) (xlocations[l] + 1);
369 y1 = (int) ylocations[l];
370 break;
371 }
372 case 3:
373 { /* right wall placement */
374 x1 = (int) xlocations[2 * layers - l - 1];
375 y2 = (int) ((-ylocations[l] + ylocations[2 * layers - l - 1])) - 1;
376 if (y2 > 0)
377 y1 = (int) (ylocations[l] + rndm (y2) + 1);
378 else
379 y1 = (int) (ylocations[l] + 1);
380
381 break;
382 }
383 case 4:
384 { /* bottom wall placement */
385 x2 = (int) ((-xlocations[l] + xlocations[2 * layers - l - 1])) - 1;
386 if (x2 > 0)
387 x1 = (int) (xlocations[l] + rndm (x2) + 1);
388 else
389 x1 = (int) (xlocations[l] + 1);
390 y1 = (int) ylocations[2 * layers - l - 1];
391 break;
392 }
393
394 }
395 }
396
397 if (options & RMOPT_NO_DOORS)
398 maze[x1][y1] = '#'; /* no door. */
399 else
400 maze[x1][y1] = 'D'; /* write the door */
401
402 }
403 /* mark the center of the maze with a C */
404 l = layers - 1;
405 x1 = (int) (xlocations[l] + xlocations[2 * layers - l - 1]) / 2;
406 y1 = (int) (ylocations[l] + ylocations[2 * layers - l - 1]) / 2;
407
408 maze[x1][y1] = 'C';
409 }
410
411 void
412 bottom_right_centered_onion (char **maze, int xsize, int ysize, int option, int layers)
413 {
414 int i, maxlayers;
415
416 maxlayers = (MIN (xsize, ysize) - 2) / 5;
417
418 if (!maxlayers)
419 return; /* map too small to onionize */
420
421 if (layers > maxlayers)
422 layers = maxlayers;
423
424 if (layers == 0)
425 layers = rndm (maxlayers) + 1;
426
427 float *xlocations = salloc0<float> (2 * layers);
428 float *ylocations = salloc0<float> (2 * layers);
429
430 /* place all the walls */
431 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
432 {
433 int x_spaces_available, y_spaces_available;
434
435 /* the "extra" spaces available for spacing between layers */
436 x_spaces_available = (xsize - 2) - 3 * layers + 1;
437 y_spaces_available = (ysize - 2) - 3 * layers + 1;
438
439
440 /* pick an initial random pitch */
441 for (i = 0; i < 2 * layers; i++)
442 {
443 float xpitch = 2, ypitch = 2;
444
445 if (x_spaces_available > 0)
446 xpitch = 2 + (rndm (x_spaces_available) + rndm (x_spaces_available) + rndm (x_spaces_available)) / 3;
447
448 if (y_spaces_available > 0)
449 ypitch = 2 + (rndm (y_spaces_available) + rndm (y_spaces_available) + rndm (y_spaces_available)) / 3;
450
451 if (i < layers)
452 xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
453 else
454 xlocations[i] = xsize - 1;
455
456 if (i < layers)
457 ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
458 else
459 ylocations[i] = ysize - 1;
460
461 x_spaces_available -= (int) (xpitch - 2);
462 y_spaces_available -= (int) (ypitch - 2);
463 }
464 }
465
466 if (!(option & RMOPT_IRR_SPACE))
467 { /* evenly spaced */
468 float xpitch, ypitch; /* pitch of the onion layers */
469
470 xpitch = (xsize - 2.0) / (2.0 * layers + 1);
471 ypitch = (ysize - 2.0) / (layers + 1);
472
473 xlocations[0] = xpitch;
474 ylocations[0] = ypitch;
475
476 for (i = 1; i < 2 * layers; i++)
477 {
478 if (i < layers)
479 xlocations[i] = xlocations[i - 1] + xpitch;
480 else
481 xlocations[i] = xsize - 1;
482
483 if (i < layers)
484 ylocations[i] = ylocations[i - 1] + ypitch;
485 else
486 ylocations[i] = ysize - 1;
487 }
488 }
489
490 /* draw all the onion boxes. */
491
492 draw_onion (maze, xlocations, ylocations, layers);
493 make_doors (maze, xlocations, ylocations, layers, option);
494
495 sfree (xlocations, 2 * layers);
496 sfree (ylocations, 2 * layers);
497 }
498