ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.17
Committed: Mon Oct 12 14:00:58 2009 UTC (14 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_82, rel-2_81
Changes since 1.16: +7 -6 lines
Log Message:
clarify license

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.12 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 pippijn 1.8 *
4 root 1.13 * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 root 1.11 * Copyright (©) 2001,2007 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992,2007 Frank Tore Johansen
7 pippijn 1.8 *
8 root 1.17 * Deliantra is free software: you can redistribute it and/or modify it under
9     * the terms of the Affero GNU General Public License as published by the
10     * Free Software Foundation, either version 3 of the License, or (at your
11     * option) any later version.
12 pippijn 1.8 *
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 root 1.11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 pippijn 1.8 * GNU General Public License for more details.
17     *
18 root 1.17 * You should have received a copy of the Affero GNU General Public License
19     * and the GNU General Public License along with this program. If not, see
20     * <http://www.gnu.org/licenses/>.
21 root 1.11 *
22 root 1.12 * The authors can be reached via e-mail to <support@deliantra.net>
23 pippijn 1.8 */
24 elmex 1.1
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 root 1.3 void draw_onion (char **maze, float *xlocations, float *ylocations, int layers);
64     void make_doors (char **maze, float *xlocations, float *ylocations, int layers, int options);
65    
66 root 1.14 void
67 root 1.15 map_gen_onion (Layout maze, int option, int layers)
68 root 1.3 {
69     int i, j;
70 elmex 1.1
71 root 1.14 int xsize = maze->w;
72     int ysize = maze->h;
73    
74     maze->clear ();
75 elmex 1.1
76     /* pick some random options if option = 0 */
77 root 1.3 if (option == 0)
78     {
79 root 1.16 switch (rmg_rndm (3))
80 root 1.3 {
81 root 1.6 case 0:
82     option |= RMOPT_CENTERED;
83     break;
84     case 1:
85     option |= RMOPT_BOTTOM_C;
86     break;
87     case 2:
88     option |= RMOPT_BOTTOM_R;
89     break;
90 root 1.3 }
91 root 1.13
92 root 1.16 if (rmg_rndm (2)) option |= RMOPT_LINEAR;
93     if (rmg_rndm (2)) option |= RMOPT_IRR_SPACE;
94 root 1.3 }
95    
96 elmex 1.1 /* write the outer walls, if appropriate. */
97 root 1.5 if (!(option & RMOPT_WALL_OFF))
98 root 1.14 maze->border ();
99 elmex 1.1
100 root 1.5 if (option & RMOPT_WALLS_ONLY)
101 root 1.14 return;
102 elmex 1.1
103     /* pick off the mutually exclusive options */
104 root 1.5 if (option & RMOPT_BOTTOM_R)
105 root 1.3 bottom_right_centered_onion (maze, xsize, ysize, option, layers);
106 root 1.5 else if (option & RMOPT_BOTTOM_C)
107 root 1.3 bottom_centered_onion (maze, xsize, ysize, option, layers);
108 root 1.5 else if (option & RMOPT_CENTERED)
109 root 1.3 centered_onion (maze, xsize, ysize, option, layers);
110 elmex 1.1 }
111    
112 root 1.3 void
113     centered_onion (char **maze, int xsize, int ysize, int option, int layers)
114     {
115     int i, maxlayers;
116 elmex 1.1
117 root 1.3 maxlayers = (MIN (xsize, ysize) - 2) / 5;
118 root 1.13
119 root 1.3 if (!maxlayers)
120     return; /* map too small to onionize */
121 root 1.10
122 root 1.3 if (layers > maxlayers)
123     layers = maxlayers;
124 root 1.10
125 root 1.3 if (layers == 0)
126 root 1.16 layers = rmg_rndm (maxlayers) + 1;
127 root 1.10
128 root 1.13 float *xlocations = salloc0<float> (2 * layers);
129     float *ylocations = salloc0<float> (2 * layers);
130 root 1.3
131 elmex 1.1 /* place all the walls */
132 root 1.6 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
133 root 1.3 {
134     int x_spaces_available, y_spaces_available;
135    
136     /* the "extra" spaces available for spacing between layers */
137     x_spaces_available = (xsize - 2) - 6 * layers + 1;
138     y_spaces_available = (ysize - 2) - 6 * layers + 1;
139    
140     /* pick an initial random pitch */
141     for (i = 0; i < 2 * layers; i++)
142     {
143     float xpitch = 2, ypitch = 2;
144    
145     if (x_spaces_available > 0)
146 root 1.16 xpitch = 2 + (rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available)) / 3;
147 root 1.3
148     if (y_spaces_available > 0)
149 root 1.16 ypitch = 2 + (rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available)) / 3;
150 root 1.10
151 root 1.3 xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
152     ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
153     x_spaces_available -= (int) (xpitch - 2);
154     y_spaces_available -= (int) (ypitch - 2);
155     }
156    
157     }
158 root 1.13
159 root 1.5 if (!(option & RMOPT_IRR_SPACE))
160 root 1.3 { /* evenly spaced */
161     float xpitch, ypitch; /* pitch of the onion layers */
162    
163     xpitch = (xsize - 2.0) / (2.0 * layers + 1);
164     ypitch = (ysize - 2.0) / (2.0 * layers + 1);
165 root 1.13
166 root 1.3 xlocations[0] = xpitch;
167     ylocations[0] = ypitch;
168 root 1.13
169 root 1.3 for (i = 1; i < 2 * layers; i++)
170     {
171     xlocations[i] = xlocations[i - 1] + xpitch;
172     ylocations[i] = ylocations[i - 1] + ypitch;
173     }
174 elmex 1.1 }
175 root 1.3
176 elmex 1.1 /* draw all the onion boxes. */
177 root 1.3 draw_onion (maze, xlocations, ylocations, layers);
178     make_doors (maze, xlocations, ylocations, layers, option);
179    
180 root 1.13 sfree (xlocations, 2 * layers);
181     sfree (ylocations, 2 * layers);
182 elmex 1.1 }
183    
184 root 1.3 void
185     bottom_centered_onion (char **maze, int xsize, int ysize, int option, int layers)
186     {
187     int i, maxlayers;
188 elmex 1.1
189 root 1.3 maxlayers = (MIN (xsize, ysize) - 2) / 5;
190 root 1.13
191 root 1.3 if (!maxlayers)
192     return; /* map too small to onionize */
193 root 1.13
194 root 1.3 if (layers > maxlayers)
195     layers = maxlayers;
196 root 1.13
197 root 1.3 if (layers == 0)
198 root 1.16 layers = rmg_rndm (maxlayers) + 1;
199 root 1.3
200 root 1.13 float *xlocations = salloc0<float> (2 * layers);
201     float *ylocations = salloc0<float> (2 * layers);
202 root 1.3
203 elmex 1.1 /* place all the walls */
204 root 1.6 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
205 root 1.3 {
206     int x_spaces_available, y_spaces_available;
207    
208     /* the "extra" spaces available for spacing between layers */
209     x_spaces_available = (xsize - 2) - 6 * layers + 1;
210     y_spaces_available = (ysize - 2) - 3 * layers + 1;
211    
212     /* pick an initial random pitch */
213     for (i = 0; i < 2 * layers; i++)
214     {
215     float xpitch = 2, ypitch = 2;
216    
217     if (x_spaces_available > 0)
218 root 1.16 xpitch = 2 + (rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available)) / 3;
219 root 1.3
220     if (y_spaces_available > 0)
221 root 1.16 ypitch = 2 + (rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available)) / 3;
222 root 1.10
223 root 1.3 xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
224 root 1.13
225 root 1.3 if (i < layers)
226     ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
227     else
228     ylocations[i] = ysize - 1;
229 root 1.10
230 root 1.3 x_spaces_available -= (int) (xpitch - 2);
231     y_spaces_available -= (int) (ypitch - 2);
232     }
233 root 1.13 }
234 root 1.3
235 root 1.5 if (!(option & RMOPT_IRR_SPACE))
236 root 1.3 { /* evenly spaced */
237     float xpitch, ypitch; /* pitch of the onion layers */
238    
239     xpitch = (xsize - 2.0) / (2.0 * layers + 1);
240     ypitch = (ysize - 2.0) / (layers + 1);
241 root 1.13
242 root 1.3 xlocations[0] = xpitch;
243     ylocations[0] = ypitch;
244 root 1.13
245 root 1.3 for (i = 1; i < 2 * layers; i++)
246     {
247     xlocations[i] = xlocations[i - 1] + xpitch;
248 root 1.13
249 root 1.3 if (i < layers)
250     ylocations[i] = ylocations[i - 1] + ypitch;
251     else
252     ylocations[i] = ysize - 1;
253     }
254     }
255    
256 elmex 1.1 /* draw all the onion boxes. */
257    
258 root 1.3 draw_onion (maze, xlocations, ylocations, layers);
259     make_doors (maze, xlocations, ylocations, layers, option);
260    
261 root 1.13 sfree (xlocations, 2 * layers);
262     sfree (ylocations, 2 * layers);
263 elmex 1.1 }
264    
265     /* draw_boxes: draws the lines in the maze defining the onion layers */
266 root 1.3 void
267     draw_onion (char **maze, float *xlocations, float *ylocations, int layers)
268     {
269     int i, j, l;
270    
271     for (l = 0; l < layers; l++)
272     {
273     int x1, x2, y1, y2;
274    
275     /* horizontal segments */
276     y1 = (int) ylocations[l];
277     y2 = (int) ylocations[2 * layers - l - 1];
278     for (i = (int) xlocations[l]; i <= (int) xlocations[2 * layers - l - 1]; i++)
279     {
280     maze[i][y1] = '#';
281     maze[i][y2] = '#';
282     }
283    
284     /* vertical segments */
285     x1 = (int) xlocations[l];
286     x2 = (int) xlocations[2 * layers - l - 1];
287     for (j = (int) ylocations[l]; j <= (int) ylocations[2 * layers - l - 1]; j++)
288     {
289     maze[x1][j] = '#';
290     maze[x2][j] = '#';
291     }
292 elmex 1.1
293 root 1.3 }
294 elmex 1.1 }
295    
296 root 1.3 void
297     make_doors (char **maze, float *xlocations, float *ylocations, int layers, int options)
298     {
299     int freedoms; /* number of different walls on which we could place a door */
300     int which_wall; /* left, 1, top, 2, right, 3, bottom 4 */
301     int l, x1 = 0, x2, y1 = 0, y2;
302    
303     freedoms = 4; /* centered */
304 root 1.13
305 root 1.5 if (options & RMOPT_BOTTOM_C)
306 root 1.3 freedoms = 3;
307 root 1.13
308 root 1.5 if (options & RMOPT_BOTTOM_R)
309 root 1.3 freedoms = 2;
310 root 1.13
311 root 1.3 if (layers <= 0)
312     return;
313 root 1.10
314 elmex 1.1 /* pick which wall will have a door. */
315 root 1.16 which_wall = rmg_rndm (freedoms) + 1;
316 root 1.3 for (l = 0; l < layers; l++)
317     {
318 root 1.5 if (options & RMOPT_LINEAR)
319 root 1.3 { /* linear door placement. */
320     switch (which_wall)
321     {
322 root 1.6 case 1:
323     { /* left hand wall */
324     x1 = (int) xlocations[l];
325     y1 = (int) ((ylocations[l] + ylocations[2 * layers - l - 1]) / 2);
326     break;
327     }
328     case 2:
329     { /* top wall placement */
330     x1 = (int) ((xlocations[l] + xlocations[2 * layers - l - 1]) / 2);
331     y1 = (int) ylocations[l];
332     break;
333     }
334     case 3:
335     { /* right wall placement */
336     x1 = (int) xlocations[2 * layers - l - 1];
337     y1 = (int) ((ylocations[l] + ylocations[2 * layers - l - 1]) / 2);
338     break;
339     }
340     case 4:
341     { /* bottom wall placement */
342     x1 = (int) ((xlocations[l] + xlocations[2 * layers - l - 1]) / 2);
343     y1 = (int) ylocations[2 * layers - l - 1];
344     break;
345     }
346 root 1.3 }
347     }
348     else
349     { /* random door placement. */
350 root 1.16 which_wall = rmg_rndm (freedoms) + 1;
351 root 1.3 switch (which_wall)
352     {
353 root 1.6 case 1:
354     { /* left hand wall */
355     x1 = (int) xlocations[l];
356     y2 = (int) (ylocations[2 * layers - l - 1] - ylocations[l] - 1);
357     if (y2 > 0)
358 root 1.16 y1 = (int) (ylocations[l] + rmg_rndm (y2) + 1);
359 root 1.6 else
360     y1 = (int) (ylocations[l] + 1);
361     break;
362     }
363     case 2:
364     { /* top wall placement */
365     x2 = (int) ((-xlocations[l] + xlocations[2 * layers - l - 1])) - 1;
366     if (x2 > 0)
367 root 1.16 x1 = (int) (xlocations[l] + rmg_rndm (x2) + 1);
368 root 1.6 else
369     x1 = (int) (xlocations[l] + 1);
370     y1 = (int) ylocations[l];
371     break;
372     }
373     case 3:
374     { /* right wall placement */
375     x1 = (int) xlocations[2 * layers - l - 1];
376     y2 = (int) ((-ylocations[l] + ylocations[2 * layers - l - 1])) - 1;
377     if (y2 > 0)
378 root 1.16 y1 = (int) (ylocations[l] + rmg_rndm (y2) + 1);
379 root 1.6 else
380     y1 = (int) (ylocations[l] + 1);
381    
382     break;
383     }
384     case 4:
385     { /* bottom wall placement */
386     x2 = (int) ((-xlocations[l] + xlocations[2 * layers - l - 1])) - 1;
387     if (x2 > 0)
388 root 1.16 x1 = (int) (xlocations[l] + rmg_rndm (x2) + 1);
389 root 1.6 else
390     x1 = (int) (xlocations[l] + 1);
391     y1 = (int) ylocations[2 * layers - l - 1];
392     break;
393     }
394 root 1.3
395     }
396     }
397 root 1.13
398 root 1.5 if (options & RMOPT_NO_DOORS)
399 root 1.3 maze[x1][y1] = '#'; /* no door. */
400     else
401     maze[x1][y1] = 'D'; /* write the door */
402 elmex 1.1
403 root 1.3 }
404 elmex 1.1 /* mark the center of the maze with a C */
405 root 1.3 l = layers - 1;
406     x1 = (int) (xlocations[l] + xlocations[2 * layers - l - 1]) / 2;
407     y1 = (int) (ylocations[l] + ylocations[2 * layers - l - 1]) / 2;
408 root 1.13
409 elmex 1.1 maze[x1][y1] = 'C';
410     }
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
417 root 1.3 maxlayers = (MIN (xsize, ysize) - 2) / 5;
418 root 1.13
419 root 1.3 if (!maxlayers)
420     return; /* map too small to onionize */
421 root 1.13
422 root 1.3 if (layers > maxlayers)
423     layers = maxlayers;
424 root 1.13
425 root 1.3 if (layers == 0)
426 root 1.16 layers = rmg_rndm (maxlayers) + 1;
427 root 1.10
428 root 1.13 float *xlocations = salloc0<float> (2 * layers);
429     float *ylocations = salloc0<float> (2 * layers);
430 root 1.3
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 root 1.16 xpitch = 2 + (rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available)) / 3;
448 root 1.3
449     if (y_spaces_available > 0)
450 root 1.16 ypitch = 2 + (rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available)) / 3;
451 root 1.10
452 root 1.3 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 root 1.13
462 root 1.3 x_spaces_available -= (int) (xpitch - 2);
463     y_spaces_available -= (int) (ypitch - 2);
464     }
465 root 1.13 }
466 root 1.3
467 root 1.5 if (!(option & RMOPT_IRR_SPACE))
468 root 1.3 { /* evenly spaced */
469     float xpitch, ypitch; /* pitch of the onion layers */
470    
471     xpitch = (xsize - 2.0) / (2.0 * layers + 1);
472     ypitch = (ysize - 2.0) / (layers + 1);
473 root 1.13
474 root 1.3 xlocations[0] = xpitch;
475     ylocations[0] = ypitch;
476 root 1.13
477 root 1.3 for (i = 1; i < 2 * layers; i++)
478     {
479     if (i < layers)
480     xlocations[i] = xlocations[i - 1] + xpitch;
481     else
482     xlocations[i] = xsize - 1;
483 root 1.13
484 root 1.3 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 root 1.13 sfree (xlocations, 2 * layers);
497     sfree (ylocations, 2 * layers);
498 elmex 1.1 }
499 root 1.13