ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.3
Committed: Sun Sep 10 16:06:37 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.2: +382 -302 lines
Log Message:
indent

File Contents

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