ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.27
Committed: Tue Jan 3 11:25:34 2012 UTC (12 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.26: +1 -1 lines
Log Message:
update copyrights to 2012

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.27 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 root 1.21 * Copyright (©) 2001 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992 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 root 1.25 #include <rmg.h>
55 root 1.20 #include <rproto.h>
56 elmex 1.1
57 root 1.18 static void centered_onion (char **maze, int xsize, int ysize, int option, int layers);
58     static void bottom_centered_onion (char **maze, int xsize, int ysize, int option, int layers);
59     static void bottom_right_centered_onion (char **maze, int xsize, int ysize, int option, int layers);
60    
61     static void draw_onion (char **maze, float *xlocations, float *ylocations, int layers);
62     static void make_doors (char **maze, float *xlocations, float *ylocations, int layers, int options);
63 root 1.3
64 root 1.14 void
65 root 1.24 map_gen_onion (layout &maze, int option, int layers)
66 root 1.3 {
67     int i, j;
68 elmex 1.1
69 root 1.23 int xsize = maze.w;
70     int ysize = maze.h;
71 root 1.14
72 root 1.23 maze.clear ();
73 elmex 1.1
74     /* pick some random options if option = 0 */
75 root 1.3 if (option == 0)
76     {
77 root 1.16 switch (rmg_rndm (3))
78 root 1.3 {
79 root 1.6 case 0:
80     option |= RMOPT_CENTERED;
81     break;
82     case 1:
83     option |= RMOPT_BOTTOM_C;
84     break;
85     case 2:
86     option |= RMOPT_BOTTOM_R;
87     break;
88 root 1.3 }
89 root 1.13
90 root 1.16 if (rmg_rndm (2)) option |= RMOPT_LINEAR;
91     if (rmg_rndm (2)) option |= RMOPT_IRR_SPACE;
92 root 1.3 }
93    
94 elmex 1.1 /* write the outer walls, if appropriate. */
95 root 1.5 if (!(option & RMOPT_WALL_OFF))
96 root 1.23 maze.border ();
97 elmex 1.1
98 root 1.5 if (option & RMOPT_WALLS_ONLY)
99 root 1.14 return;
100 elmex 1.1
101     /* pick off the mutually exclusive options */
102 root 1.5 if (option & RMOPT_BOTTOM_R)
103 root 1.3 bottom_right_centered_onion (maze, xsize, ysize, option, layers);
104 root 1.5 else if (option & RMOPT_BOTTOM_C)
105 root 1.3 bottom_centered_onion (maze, xsize, ysize, option, layers);
106 root 1.5 else if (option & RMOPT_CENTERED)
107 root 1.3 centered_onion (maze, xsize, ysize, option, layers);
108 elmex 1.1 }
109    
110 root 1.18 static void
111 root 1.3 centered_onion (char **maze, int xsize, int ysize, int option, int layers)
112     {
113     int i, maxlayers;
114 elmex 1.1
115 root 1.20 maxlayers = (min (xsize, ysize) - 2) / 5;
116 root 1.13
117 root 1.3 if (!maxlayers)
118     return; /* map too small to onionize */
119 root 1.10
120 root 1.3 if (layers > maxlayers)
121     layers = maxlayers;
122 root 1.10
123 root 1.3 if (layers == 0)
124 root 1.16 layers = rmg_rndm (maxlayers) + 1;
125 root 1.10
126 root 1.13 float *xlocations = salloc0<float> (2 * layers);
127     float *ylocations = salloc0<float> (2 * layers);
128 root 1.3
129 elmex 1.1 /* place all the walls */
130 root 1.6 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
131 root 1.3 {
132     int x_spaces_available, y_spaces_available;
133    
134     /* the "extra" spaces available for spacing between layers */
135     x_spaces_available = (xsize - 2) - 6 * layers + 1;
136     y_spaces_available = (ysize - 2) - 6 * layers + 1;
137    
138     /* pick an initial random pitch */
139     for (i = 0; i < 2 * layers; i++)
140     {
141     float xpitch = 2, ypitch = 2;
142    
143     if (x_spaces_available > 0)
144 root 1.16 xpitch = 2 + (rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available)) / 3;
145 root 1.3
146     if (y_spaces_available > 0)
147 root 1.16 ypitch = 2 + (rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available)) / 3;
148 root 1.10
149 root 1.3 xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
150     ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
151     x_spaces_available -= (int) (xpitch - 2);
152     y_spaces_available -= (int) (ypitch - 2);
153     }
154    
155     }
156 root 1.13
157 root 1.5 if (!(option & RMOPT_IRR_SPACE))
158 root 1.3 { /* evenly spaced */
159     float xpitch, ypitch; /* pitch of the onion layers */
160    
161     xpitch = (xsize - 2.0) / (2.0 * layers + 1);
162     ypitch = (ysize - 2.0) / (2.0 * layers + 1);
163 root 1.13
164 root 1.3 xlocations[0] = xpitch;
165     ylocations[0] = ypitch;
166 root 1.13
167 root 1.3 for (i = 1; i < 2 * layers; i++)
168     {
169     xlocations[i] = xlocations[i - 1] + xpitch;
170     ylocations[i] = ylocations[i - 1] + ypitch;
171     }
172 elmex 1.1 }
173 root 1.3
174 elmex 1.1 /* draw all the onion boxes. */
175 root 1.3 draw_onion (maze, xlocations, ylocations, layers);
176     make_doors (maze, xlocations, ylocations, layers, option);
177    
178 root 1.13 sfree (xlocations, 2 * layers);
179     sfree (ylocations, 2 * layers);
180 elmex 1.1 }
181    
182 root 1.18 static void
183 root 1.3 bottom_centered_onion (char **maze, int xsize, int ysize, int option, int layers)
184     {
185     int i, maxlayers;
186 elmex 1.1
187 root 1.20 maxlayers = (min (xsize, ysize) - 2) / 5;
188 root 1.13
189 root 1.3 if (!maxlayers)
190     return; /* map too small to onionize */
191 root 1.13
192 root 1.3 if (layers > maxlayers)
193     layers = maxlayers;
194 root 1.13
195 root 1.3 if (layers == 0)
196 root 1.16 layers = rmg_rndm (maxlayers) + 1;
197 root 1.3
198 root 1.13 float *xlocations = salloc0<float> (2 * layers);
199     float *ylocations = salloc0<float> (2 * layers);
200 root 1.3
201 elmex 1.1 /* place all the walls */
202 root 1.6 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
203 root 1.3 {
204     int x_spaces_available, y_spaces_available;
205    
206     /* the "extra" spaces available for spacing between layers */
207     x_spaces_available = (xsize - 2) - 6 * layers + 1;
208     y_spaces_available = (ysize - 2) - 3 * layers + 1;
209    
210     /* pick an initial random pitch */
211     for (i = 0; i < 2 * layers; i++)
212     {
213     float xpitch = 2, ypitch = 2;
214    
215     if (x_spaces_available > 0)
216 root 1.16 xpitch = 2 + (rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available)) / 3;
217 root 1.3
218     if (y_spaces_available > 0)
219 root 1.16 ypitch = 2 + (rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available)) / 3;
220 root 1.10
221 root 1.3 xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
222 root 1.13
223 root 1.3 if (i < layers)
224     ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
225     else
226     ylocations[i] = ysize - 1;
227 root 1.10
228 root 1.3 x_spaces_available -= (int) (xpitch - 2);
229     y_spaces_available -= (int) (ypitch - 2);
230     }
231 root 1.13 }
232 root 1.3
233 root 1.5 if (!(option & RMOPT_IRR_SPACE))
234 root 1.3 { /* evenly spaced */
235     float xpitch, ypitch; /* pitch of the onion layers */
236    
237     xpitch = (xsize - 2.0) / (2.0 * layers + 1);
238     ypitch = (ysize - 2.0) / (layers + 1);
239 root 1.13
240 root 1.3 xlocations[0] = xpitch;
241     ylocations[0] = ypitch;
242 root 1.13
243 root 1.3 for (i = 1; i < 2 * layers; i++)
244     {
245     xlocations[i] = xlocations[i - 1] + xpitch;
246 root 1.13
247 root 1.3 if (i < layers)
248     ylocations[i] = ylocations[i - 1] + ypitch;
249     else
250     ylocations[i] = ysize - 1;
251     }
252     }
253    
254 elmex 1.1 /* draw all the onion boxes. */
255    
256 root 1.3 draw_onion (maze, xlocations, ylocations, layers);
257     make_doors (maze, xlocations, ylocations, layers, option);
258    
259 root 1.13 sfree (xlocations, 2 * layers);
260     sfree (ylocations, 2 * layers);
261 elmex 1.1 }
262    
263 root 1.18 /* draw_boxes: draws the lines in the maze defining the onion layers */
264     static void
265 root 1.3 draw_onion (char **maze, float *xlocations, float *ylocations, int layers)
266     {
267     int i, j, l;
268    
269     for (l = 0; l < layers; l++)
270     {
271     int x1, x2, y1, y2;
272    
273     /* horizontal segments */
274     y1 = (int) ylocations[l];
275     y2 = (int) ylocations[2 * layers - l - 1];
276     for (i = (int) xlocations[l]; i <= (int) xlocations[2 * layers - l - 1]; i++)
277     {
278     maze[i][y1] = '#';
279     maze[i][y2] = '#';
280     }
281    
282     /* vertical segments */
283     x1 = (int) xlocations[l];
284     x2 = (int) xlocations[2 * layers - l - 1];
285     for (j = (int) ylocations[l]; j <= (int) ylocations[2 * layers - l - 1]; j++)
286     {
287     maze[x1][j] = '#';
288     maze[x2][j] = '#';
289     }
290 elmex 1.1
291 root 1.3 }
292 elmex 1.1 }
293    
294 root 1.19 static void
295 root 1.3 make_doors (char **maze, float *xlocations, float *ylocations, int layers, int options)
296     {
297     int freedoms; /* number of different walls on which we could place a door */
298     int which_wall; /* left, 1, top, 2, right, 3, bottom 4 */
299     int l, x1 = 0, x2, y1 = 0, y2;
300    
301     freedoms = 4; /* centered */
302 root 1.13
303 root 1.5 if (options & RMOPT_BOTTOM_C)
304 root 1.3 freedoms = 3;
305 root 1.13
306 root 1.5 if (options & RMOPT_BOTTOM_R)
307 root 1.3 freedoms = 2;
308 root 1.13
309 root 1.3 if (layers <= 0)
310     return;
311 root 1.10
312 elmex 1.1 /* pick which wall will have a door. */
313 root 1.16 which_wall = rmg_rndm (freedoms) + 1;
314 root 1.3 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 root 1.16 which_wall = rmg_rndm (freedoms) + 1;
349 root 1.3 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 root 1.16 y1 = (int) (ylocations[l] + rmg_rndm (y2) + 1);
357 root 1.6 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 root 1.16 x1 = (int) (xlocations[l] + rmg_rndm (x2) + 1);
366 root 1.6 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 root 1.16 y1 = (int) (ylocations[l] + rmg_rndm (y2) + 1);
377 root 1.6 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 root 1.16 x1 = (int) (xlocations[l] + rmg_rndm (x2) + 1);
387 root 1.6 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.13
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 root 1.13
407 elmex 1.1 maze[x1][y1] = 'C';
408     }
409    
410 root 1.18 static void
411 root 1.3 bottom_right_centered_onion (char **maze, int xsize, int ysize, int option, int layers)
412     {
413     int i, maxlayers;
414 elmex 1.1
415 root 1.20 maxlayers = (min (xsize, ysize) - 2) / 5;
416 root 1.13
417 root 1.3 if (!maxlayers)
418     return; /* map too small to onionize */
419 root 1.13
420 root 1.3 if (layers > maxlayers)
421     layers = maxlayers;
422 root 1.13
423 root 1.3 if (layers == 0)
424 root 1.16 layers = rmg_rndm (maxlayers) + 1;
425 root 1.10
426 root 1.13 float *xlocations = salloc0<float> (2 * layers);
427     float *ylocations = salloc0<float> (2 * layers);
428 root 1.3
429 elmex 1.1 /* place all the walls */
430 root 1.6 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
431 root 1.3 {
432     int x_spaces_available, y_spaces_available;
433    
434     /* the "extra" spaces available for spacing between layers */
435     x_spaces_available = (xsize - 2) - 3 * layers + 1;
436     y_spaces_available = (ysize - 2) - 3 * layers + 1;
437    
438    
439     /* pick an initial random pitch */
440     for (i = 0; i < 2 * layers; i++)
441     {
442     float xpitch = 2, ypitch = 2;
443    
444     if (x_spaces_available > 0)
445 root 1.16 xpitch = 2 + (rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available)) / 3;
446 root 1.3
447     if (y_spaces_available > 0)
448 root 1.16 ypitch = 2 + (rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available)) / 3;
449 root 1.10
450 root 1.3 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 root 1.13
460 root 1.3 x_spaces_available -= (int) (xpitch - 2);
461     y_spaces_available -= (int) (ypitch - 2);
462     }
463 root 1.13 }
464 root 1.3
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 root 1.13
472 root 1.3 xlocations[0] = xpitch;
473     ylocations[0] = ypitch;
474 root 1.13
475 root 1.3 for (i = 1; i < 2 * layers; i++)
476     {
477     if (i < layers)
478     xlocations[i] = xlocations[i - 1] + xpitch;
479     else
480     xlocations[i] = xsize - 1;
481 root 1.13
482 root 1.3 if (i < layers)
483     ylocations[i] = ylocations[i - 1] + ypitch;
484     else
485     ylocations[i] = ysize - 1;
486     }
487     }
488    
489 elmex 1.1 /* draw all the onion boxes. */
490    
491 root 1.3 draw_onion (maze, xlocations, ylocations, layers);
492     make_doors (maze, xlocations, ylocations, layers, option);
493    
494 root 1.13 sfree (xlocations, 2 * layers);
495     sfree (ylocations, 2 * layers);
496 elmex 1.1 }
497 root 1.13