ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.10
Committed: Sat Jan 27 02:19:37 2007 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_0, rel-2_1
Changes since 1.9: +24 -17 lines
Log Message:
- experimentall.y determine minimum random map size (12)
- harden random map generator by stresstesting
- reduced codesize while increasing readability (RANDOM => rndm)
- fixed a likely unimportant bug in random_roll64
- possibly broke lots of code

File Contents

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