ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.9
Committed: Thu Jan 18 19:42:10 2007 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.8: +3 -3 lines
Log Message:
just experimenting

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     if (layers > maxlayers)
136     layers = maxlayers;
137     if (layers == 0)
138     layers = (RANDOM () % maxlayers) + 1;
139     xlocations = (float *) calloc (sizeof (float), 2 * layers);
140     ylocations = (float *) calloc (sizeof (float), 2 * layers);
141    
142    
143 elmex 1.1 /* place all the walls */
144 root 1.6 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
145 root 1.3 {
146     int x_spaces_available, y_spaces_available;
147    
148     /* the "extra" spaces available for spacing between layers */
149     x_spaces_available = (xsize - 2) - 6 * layers + 1;
150     y_spaces_available = (ysize - 2) - 6 * layers + 1;
151    
152    
153     /* pick an initial random pitch */
154     for (i = 0; i < 2 * layers; i++)
155     {
156     float xpitch = 2, ypitch = 2;
157    
158     if (x_spaces_available > 0)
159     xpitch = 2 + (RANDOM () % x_spaces_available + RANDOM () % x_spaces_available + RANDOM () % x_spaces_available) / 3;
160    
161     if (y_spaces_available > 0)
162     ypitch = 2 + (RANDOM () % y_spaces_available + RANDOM () % y_spaces_available + RANDOM () % y_spaces_available) / 3;
163     xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
164     ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
165     x_spaces_available -= (int) (xpitch - 2);
166     y_spaces_available -= (int) (ypitch - 2);
167     }
168    
169     }
170 root 1.5 if (!(option & RMOPT_IRR_SPACE))
171 root 1.3 { /* evenly spaced */
172     float xpitch, ypitch; /* pitch of the onion layers */
173    
174     xpitch = (xsize - 2.0) / (2.0 * layers + 1);
175     ypitch = (ysize - 2.0) / (2.0 * layers + 1);
176     xlocations[0] = xpitch;
177     ylocations[0] = ypitch;
178     for (i = 1; i < 2 * layers; i++)
179     {
180     xlocations[i] = xlocations[i - 1] + xpitch;
181     ylocations[i] = ylocations[i - 1] + ypitch;
182     }
183 elmex 1.1 }
184 root 1.3
185 elmex 1.1 /* draw all the onion boxes. */
186    
187 root 1.3 draw_onion (maze, xlocations, ylocations, layers);
188     make_doors (maze, xlocations, ylocations, layers, option);
189    
190 elmex 1.1 }
191    
192 root 1.3 void
193     bottom_centered_onion (char **maze, int xsize, int ysize, int option, int layers)
194     {
195     int i, maxlayers;
196 elmex 1.1 float *xlocations;
197     float *ylocations;
198    
199 root 1.3 maxlayers = (MIN (xsize, ysize) - 2) / 5;
200     if (!maxlayers)
201     return; /* map too small to onionize */
202     if (layers > maxlayers)
203     layers = maxlayers;
204     if (layers == 0)
205     layers = (RANDOM () % maxlayers) + 1;
206     xlocations = (float *) calloc (sizeof (float), 2 * layers);
207     ylocations = (float *) calloc (sizeof (float), 2 * layers);
208    
209    
210 elmex 1.1 /* place all the walls */
211 root 1.6 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
212 root 1.3 {
213     int x_spaces_available, y_spaces_available;
214    
215     /* the "extra" spaces available for spacing between layers */
216     x_spaces_available = (xsize - 2) - 6 * layers + 1;
217     y_spaces_available = (ysize - 2) - 3 * layers + 1;
218    
219    
220     /* pick an initial random pitch */
221     for (i = 0; i < 2 * layers; i++)
222     {
223     float xpitch = 2, ypitch = 2;
224    
225     if (x_spaces_available > 0)
226     xpitch = 2 + (RANDOM () % x_spaces_available + RANDOM () % x_spaces_available + RANDOM () % x_spaces_available) / 3;
227    
228     if (y_spaces_available > 0)
229     ypitch = 2 + (RANDOM () % y_spaces_available + RANDOM () % y_spaces_available + RANDOM () % y_spaces_available) / 3;
230     xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
231     if (i < layers)
232     ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
233     else
234     ylocations[i] = ysize - 1;
235     x_spaces_available -= (int) (xpitch - 2);
236     y_spaces_available -= (int) (ypitch - 2);
237     }
238    
239 elmex 1.1 }
240 root 1.5 if (!(option & RMOPT_IRR_SPACE))
241 root 1.3 { /* evenly spaced */
242     float xpitch, ypitch; /* pitch of the onion layers */
243    
244     xpitch = (xsize - 2.0) / (2.0 * layers + 1);
245     ypitch = (ysize - 2.0) / (layers + 1);
246     xlocations[0] = xpitch;
247     ylocations[0] = ypitch;
248     for (i = 1; i < 2 * layers; i++)
249     {
250     xlocations[i] = xlocations[i - 1] + xpitch;
251     if (i < layers)
252     ylocations[i] = ylocations[i - 1] + ypitch;
253     else
254     ylocations[i] = ysize - 1;
255     }
256     }
257    
258 elmex 1.1 /* draw all the onion boxes. */
259    
260 root 1.3 draw_onion (maze, xlocations, ylocations, layers);
261     make_doors (maze, xlocations, ylocations, layers, option);
262    
263 elmex 1.1 }
264    
265    
266     /* draw_boxes: draws the lines in the maze defining the onion layers */
267    
268 root 1.3 void
269     draw_onion (char **maze, float *xlocations, float *ylocations, int layers)
270     {
271     int i, j, l;
272    
273     for (l = 0; l < layers; l++)
274     {
275     int x1, x2, y1, y2;
276    
277     /* horizontal segments */
278     y1 = (int) ylocations[l];
279     y2 = (int) ylocations[2 * layers - l - 1];
280     for (i = (int) xlocations[l]; i <= (int) xlocations[2 * layers - l - 1]; i++)
281     {
282     maze[i][y1] = '#';
283     maze[i][y2] = '#';
284     }
285    
286     /* vertical segments */
287     x1 = (int) xlocations[l];
288     x2 = (int) xlocations[2 * layers - l - 1];
289     for (j = (int) ylocations[l]; j <= (int) ylocations[2 * layers - l - 1]; j++)
290     {
291     maze[x1][j] = '#';
292     maze[x2][j] = '#';
293     }
294 elmex 1.1
295 root 1.3 }
296 elmex 1.1 }
297    
298 root 1.3 void
299     make_doors (char **maze, float *xlocations, float *ylocations, int layers, int options)
300     {
301     int freedoms; /* number of different walls on which we could place a door */
302     int which_wall; /* left, 1, top, 2, right, 3, bottom 4 */
303     int l, x1 = 0, x2, y1 = 0, y2;
304    
305     freedoms = 4; /* centered */
306 root 1.5 if (options & RMOPT_BOTTOM_C)
307 root 1.3 freedoms = 3;
308 root 1.5 if (options & RMOPT_BOTTOM_R)
309 root 1.3 freedoms = 2;
310     if (layers <= 0)
311     return;
312 elmex 1.1 /* pick which wall will have a door. */
313 root 1.3 which_wall = RANDOM () % freedoms + 1;
314     for (l = 0; l < layers; l++)
315     {
316 root 1.5 if (options & RMOPT_LINEAR)
317 root 1.3 { /* linear door placement. */
318     switch (which_wall)
319     {
320 root 1.6 case 1:
321     { /* left hand wall */
322     x1 = (int) xlocations[l];
323     y1 = (int) ((ylocations[l] + ylocations[2 * layers - l - 1]) / 2);
324     break;
325     }
326     case 2:
327     { /* top wall placement */
328     x1 = (int) ((xlocations[l] + xlocations[2 * layers - l - 1]) / 2);
329     y1 = (int) ylocations[l];
330     break;
331     }
332     case 3:
333     { /* right wall placement */
334     x1 = (int) xlocations[2 * layers - l - 1];
335     y1 = (int) ((ylocations[l] + ylocations[2 * layers - l - 1]) / 2);
336     break;
337     }
338     case 4:
339     { /* bottom wall placement */
340     x1 = (int) ((xlocations[l] + xlocations[2 * layers - l - 1]) / 2);
341     y1 = (int) ylocations[2 * layers - l - 1];
342     break;
343     }
344 root 1.3 }
345     }
346     else
347     { /* random door placement. */
348     which_wall = RANDOM () % freedoms + 1;
349     switch (which_wall)
350     {
351 root 1.6 case 1:
352     { /* left hand wall */
353     x1 = (int) xlocations[l];
354     y2 = (int) (ylocations[2 * layers - l - 1] - ylocations[l] - 1);
355     if (y2 > 0)
356     y1 = (int) (ylocations[l] + RANDOM () % y2 + 1);
357     else
358     y1 = (int) (ylocations[l] + 1);
359     break;
360     }
361     case 2:
362     { /* top wall placement */
363     x2 = (int) ((-xlocations[l] + xlocations[2 * layers - l - 1])) - 1;
364     if (x2 > 0)
365     x1 = (int) (xlocations[l] + RANDOM () % x2 + 1);
366     else
367     x1 = (int) (xlocations[l] + 1);
368     y1 = (int) ylocations[l];
369     break;
370     }
371     case 3:
372     { /* right wall placement */
373     x1 = (int) xlocations[2 * layers - l - 1];
374     y2 = (int) ((-ylocations[l] + ylocations[2 * layers - l - 1])) - 1;
375     if (y2 > 0)
376     y1 = (int) (ylocations[l] + RANDOM () % y2 + 1);
377     else
378     y1 = (int) (ylocations[l] + 1);
379    
380     break;
381     }
382     case 4:
383     { /* bottom wall placement */
384     x2 = (int) ((-xlocations[l] + xlocations[2 * layers - l - 1])) - 1;
385     if (x2 > 0)
386     x1 = (int) (xlocations[l] + RANDOM () % x2 + 1);
387     else
388     x1 = (int) (xlocations[l] + 1);
389     y1 = (int) ylocations[2 * layers - l - 1];
390     break;
391     }
392 root 1.3
393     }
394     }
395 root 1.5 if (options & RMOPT_NO_DOORS)
396 root 1.3 maze[x1][y1] = '#'; /* no door. */
397     else
398     maze[x1][y1] = 'D'; /* write the door */
399 elmex 1.1
400 root 1.3 }
401 elmex 1.1 /* mark the center of the maze with a C */
402 root 1.3 l = layers - 1;
403     x1 = (int) (xlocations[l] + xlocations[2 * layers - l - 1]) / 2;
404     y1 = (int) (ylocations[l] + ylocations[2 * layers - l - 1]) / 2;
405 elmex 1.1 maze[x1][y1] = 'C';
406    
407     /* not needed anymore */
408 root 1.3 free (xlocations);
409     free (ylocations);
410    
411 elmex 1.1 }
412    
413 root 1.3 void
414     bottom_right_centered_onion (char **maze, int xsize, int ysize, int option, int layers)
415     {
416     int i, maxlayers;
417 elmex 1.1 float *xlocations;
418     float *ylocations;
419    
420 root 1.3 maxlayers = (MIN (xsize, ysize) - 2) / 5;
421     if (!maxlayers)
422     return; /* map too small to onionize */
423     if (layers > maxlayers)
424     layers = maxlayers;
425     if (layers == 0)
426     layers = (RANDOM () % maxlayers) + 1;
427     xlocations = (float *) calloc (sizeof (float), 2 * layers);
428     ylocations = (float *) calloc (sizeof (float), 2 * layers);
429    
430    
431 elmex 1.1 /* place all the walls */
432 root 1.6 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
433 root 1.3 {
434     int x_spaces_available, y_spaces_available;
435    
436     /* the "extra" spaces available for spacing between layers */
437     x_spaces_available = (xsize - 2) - 3 * layers + 1;
438     y_spaces_available = (ysize - 2) - 3 * layers + 1;
439    
440    
441     /* pick an initial random pitch */
442     for (i = 0; i < 2 * layers; i++)
443     {
444     float xpitch = 2, ypitch = 2;
445    
446     if (x_spaces_available > 0)
447     xpitch = 2 + (RANDOM () % x_spaces_available + RANDOM () % x_spaces_available + RANDOM () % x_spaces_available) / 3;
448    
449     if (y_spaces_available > 0)
450     ypitch = 2 + (RANDOM () % y_spaces_available + RANDOM () % y_spaces_available + RANDOM () % y_spaces_available) / 3;
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     x_spaces_available -= (int) (xpitch - 2);
461     y_spaces_available -= (int) (ypitch - 2);
462     }
463    
464 elmex 1.1 }
465 root 1.5 if (!(option & RMOPT_IRR_SPACE))
466 root 1.3 { /* evenly spaced */
467     float xpitch, ypitch; /* pitch of the onion layers */
468    
469     xpitch = (xsize - 2.0) / (2.0 * layers + 1);
470     ypitch = (ysize - 2.0) / (layers + 1);
471     xlocations[0] = xpitch;
472     ylocations[0] = ypitch;
473     for (i = 1; i < 2 * layers; i++)
474     {
475     if (i < layers)
476     xlocations[i] = xlocations[i - 1] + xpitch;
477     else
478     xlocations[i] = xsize - 1;
479     if (i < layers)
480     ylocations[i] = ylocations[i - 1] + ypitch;
481     else
482     ylocations[i] = ysize - 1;
483     }
484     }
485    
486 elmex 1.1 /* draw all the onion boxes. */
487    
488 root 1.3 draw_onion (maze, xlocations, ylocations, layers);
489     make_doors (maze, xlocations, ylocations, layers, option);
490    
491 elmex 1.1 }