ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.7
Committed: Sat Jan 6 14:42:30 2007 UTC (17 years, 5 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.6: +1 -0 lines
Log Message:
added some copyrights

File Contents

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