ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.14
Committed: Mon Apr 14 22:41:17 2008 UTC (16 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.13: +8 -10 lines
Log Message:
refactor random map gen more

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