ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.4
Committed: Thu Sep 14 22:34:02 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.3: +1 -7 lines
Log Message:
indent

File Contents

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