ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.13
Committed: Fri Apr 11 21:09:53 2008 UTC (16 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.12: +46 -42 lines
Log Message:
*** empty log message ***

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.13 Maze
66 root 1.3 map_gen_onion (int xsize, int ysize, int option, int layers)
67     {
68     int i, j;
69 elmex 1.1
70 root 1.13 Maze maze (xsize, ysize);
71 elmex 1.1
72     /* pick some random options if option = 0 */
73 root 1.3 if (option == 0)
74     {
75 root 1.9 switch (rndm (3))
76 root 1.3 {
77 root 1.6 case 0:
78     option |= RMOPT_CENTERED;
79     break;
80     case 1:
81     option |= RMOPT_BOTTOM_C;
82     break;
83     case 2:
84     option |= RMOPT_BOTTOM_R;
85     break;
86 root 1.3 }
87 root 1.13
88     if (rndm (2)) option |= RMOPT_LINEAR;
89     if (rndm (2)) option |= RMOPT_IRR_SPACE;
90 root 1.3 }
91    
92 elmex 1.1 /* write the outer walls, if appropriate. */
93 root 1.5 if (!(option & RMOPT_WALL_OFF))
94 root 1.3 {
95 root 1.13 for (i = 0; i < xsize; i++) maze[i][0] = maze[i][ysize - 1] = '#';
96     for (j = 0; j < ysize; j++) maze[0][j] = maze[xsize - 1][j] = '#';
97 root 1.3 };
98 elmex 1.1
99 root 1.5 if (option & RMOPT_WALLS_ONLY)
100 root 1.3 return maze;
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    
110 elmex 1.1 return maze;
111     }
112    
113 root 1.3 void
114     centered_onion (char **maze, int xsize, int ysize, int option, int layers)
115     {
116     int i, maxlayers;
117 elmex 1.1
118 root 1.3 maxlayers = (MIN (xsize, ysize) - 2) / 5;
119 root 1.13
120 root 1.3 if (!maxlayers)
121     return; /* map too small to onionize */
122 root 1.10
123 root 1.3 if (layers > maxlayers)
124     layers = maxlayers;
125 root 1.10
126 root 1.3 if (layers == 0)
127 root 1.10 layers = rndm (maxlayers) + 1;
128    
129 root 1.13 float *xlocations = salloc0<float> (2 * layers);
130     float *ylocations = salloc0<float> (2 * layers);
131 root 1.3
132 elmex 1.1 /* place all the walls */
133 root 1.6 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
134 root 1.3 {
135     int x_spaces_available, y_spaces_available;
136    
137     /* the "extra" spaces available for spacing between layers */
138     x_spaces_available = (xsize - 2) - 6 * layers + 1;
139     y_spaces_available = (ysize - 2) - 6 * layers + 1;
140    
141     /* pick an initial random pitch */
142     for (i = 0; i < 2 * layers; i++)
143     {
144     float xpitch = 2, ypitch = 2;
145    
146     if (x_spaces_available > 0)
147 root 1.10 xpitch = 2 + (rndm (x_spaces_available) + rndm (x_spaces_available) + rndm (x_spaces_available)) / 3;
148 root 1.3
149     if (y_spaces_available > 0)
150 root 1.10 ypitch = 2 + (rndm (y_spaces_available) + rndm (y_spaces_available) + rndm (y_spaces_available)) / 3;
151    
152 root 1.3 xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
153     ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
154     x_spaces_available -= (int) (xpitch - 2);
155     y_spaces_available -= (int) (ypitch - 2);
156     }
157    
158     }
159 root 1.13
160 root 1.5 if (!(option & RMOPT_IRR_SPACE))
161 root 1.3 { /* evenly spaced */
162     float xpitch, ypitch; /* pitch of the onion layers */
163    
164     xpitch = (xsize - 2.0) / (2.0 * layers + 1);
165     ypitch = (ysize - 2.0) / (2.0 * layers + 1);
166 root 1.13
167 root 1.3 xlocations[0] = xpitch;
168     ylocations[0] = ypitch;
169 root 1.13
170 root 1.3 for (i = 1; i < 2 * layers; i++)
171     {
172     xlocations[i] = xlocations[i - 1] + xpitch;
173     ylocations[i] = ylocations[i - 1] + ypitch;
174     }
175 elmex 1.1 }
176 root 1.3
177 elmex 1.1 /* draw all the onion boxes. */
178 root 1.3 draw_onion (maze, xlocations, ylocations, layers);
179     make_doors (maze, xlocations, ylocations, layers, option);
180    
181 root 1.13 sfree (xlocations, 2 * layers);
182     sfree (ylocations, 2 * layers);
183 elmex 1.1 }
184    
185 root 1.3 void
186     bottom_centered_onion (char **maze, int xsize, int ysize, int option, int layers)
187     {
188     int i, maxlayers;
189 elmex 1.1
190 root 1.3 maxlayers = (MIN (xsize, ysize) - 2) / 5;
191 root 1.13
192 root 1.3 if (!maxlayers)
193     return; /* map too small to onionize */
194 root 1.13
195 root 1.3 if (layers > maxlayers)
196     layers = maxlayers;
197 root 1.13
198 root 1.3 if (layers == 0)
199 root 1.10 layers = rndm (maxlayers) + 1;
200 root 1.3
201 root 1.13 float *xlocations = salloc0<float> (2 * layers);
202     float *ylocations = salloc0<float> (2 * layers);
203 root 1.3
204 elmex 1.1 /* place all the walls */
205 root 1.6 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
206 root 1.3 {
207     int x_spaces_available, y_spaces_available;
208    
209     /* the "extra" spaces available for spacing between layers */
210     x_spaces_available = (xsize - 2) - 6 * layers + 1;
211     y_spaces_available = (ysize - 2) - 3 * layers + 1;
212    
213     /* pick an initial random pitch */
214     for (i = 0; i < 2 * layers; i++)
215     {
216     float xpitch = 2, ypitch = 2;
217    
218     if (x_spaces_available > 0)
219 root 1.10 xpitch = 2 + (rndm (x_spaces_available) + rndm (x_spaces_available) + rndm (x_spaces_available)) / 3;
220 root 1.3
221     if (y_spaces_available > 0)
222 root 1.10 ypitch = 2 + (rndm (y_spaces_available) + rndm (y_spaces_available) + rndm (y_spaces_available)) / 3;
223    
224 root 1.3 xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
225 root 1.13
226 root 1.3 if (i < layers)
227     ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
228     else
229     ylocations[i] = ysize - 1;
230 root 1.10
231 root 1.3 x_spaces_available -= (int) (xpitch - 2);
232     y_spaces_available -= (int) (ypitch - 2);
233     }
234 root 1.13 }
235 root 1.3
236 root 1.5 if (!(option & RMOPT_IRR_SPACE))
237 root 1.3 { /* evenly spaced */
238     float xpitch, ypitch; /* pitch of the onion layers */
239    
240     xpitch = (xsize - 2.0) / (2.0 * layers + 1);
241     ypitch = (ysize - 2.0) / (layers + 1);
242 root 1.13
243 root 1.3 xlocations[0] = xpitch;
244     ylocations[0] = ypitch;
245 root 1.13
246 root 1.3 for (i = 1; i < 2 * layers; i++)
247     {
248     xlocations[i] = xlocations[i - 1] + xpitch;
249 root 1.13
250 root 1.3 if (i < layers)
251     ylocations[i] = ylocations[i - 1] + ypitch;
252     else
253     ylocations[i] = ysize - 1;
254     }
255     }
256    
257 elmex 1.1 /* draw all the onion boxes. */
258    
259 root 1.3 draw_onion (maze, xlocations, ylocations, layers);
260     make_doors (maze, xlocations, ylocations, layers, option);
261    
262 root 1.13 sfree (xlocations, 2 * layers);
263     sfree (ylocations, 2 * layers);
264 elmex 1.1 }
265    
266     /* draw_boxes: draws the lines in the maze defining the onion layers */
267 root 1.3 void
268     draw_onion (char **maze, float *xlocations, float *ylocations, int layers)
269     {
270     int i, j, l;
271    
272     for (l = 0; l < layers; l++)
273     {
274     int x1, x2, y1, y2;
275    
276     /* horizontal segments */
277     y1 = (int) ylocations[l];
278     y2 = (int) ylocations[2 * layers - l - 1];
279     for (i = (int) xlocations[l]; i <= (int) xlocations[2 * layers - l - 1]; i++)
280     {
281     maze[i][y1] = '#';
282     maze[i][y2] = '#';
283     }
284    
285     /* vertical segments */
286     x1 = (int) xlocations[l];
287     x2 = (int) xlocations[2 * layers - l - 1];
288     for (j = (int) ylocations[l]; j <= (int) ylocations[2 * layers - l - 1]; j++)
289     {
290     maze[x1][j] = '#';
291     maze[x2][j] = '#';
292     }
293 elmex 1.1
294 root 1.3 }
295 elmex 1.1 }
296    
297 root 1.3 void
298     make_doors (char **maze, float *xlocations, float *ylocations, int layers, int options)
299     {
300     int freedoms; /* number of different walls on which we could place a door */
301     int which_wall; /* left, 1, top, 2, right, 3, bottom 4 */
302     int l, x1 = 0, x2, y1 = 0, y2;
303    
304     freedoms = 4; /* centered */
305 root 1.13
306 root 1.5 if (options & RMOPT_BOTTOM_C)
307 root 1.3 freedoms = 3;
308 root 1.13
309 root 1.5 if (options & RMOPT_BOTTOM_R)
310 root 1.3 freedoms = 2;
311 root 1.13
312 root 1.3 if (layers <= 0)
313     return;
314 root 1.10
315 elmex 1.1 /* pick which wall will have a door. */
316 root 1.10 which_wall = rndm (freedoms) + 1;
317 root 1.3 for (l = 0; l < layers; l++)
318     {
319 root 1.5 if (options & RMOPT_LINEAR)
320 root 1.3 { /* linear door placement. */
321     switch (which_wall)
322     {
323 root 1.6 case 1:
324     { /* left hand wall */
325     x1 = (int) xlocations[l];
326     y1 = (int) ((ylocations[l] + ylocations[2 * layers - l - 1]) / 2);
327     break;
328     }
329     case 2:
330     { /* top wall placement */
331     x1 = (int) ((xlocations[l] + xlocations[2 * layers - l - 1]) / 2);
332     y1 = (int) ylocations[l];
333     break;
334     }
335     case 3:
336     { /* right wall placement */
337     x1 = (int) xlocations[2 * layers - l - 1];
338     y1 = (int) ((ylocations[l] + ylocations[2 * layers - l - 1]) / 2);
339     break;
340     }
341     case 4:
342     { /* bottom wall placement */
343     x1 = (int) ((xlocations[l] + xlocations[2 * layers - l - 1]) / 2);
344     y1 = (int) ylocations[2 * layers - l - 1];
345     break;
346     }
347 root 1.3 }
348     }
349     else
350     { /* random door placement. */
351 root 1.10 which_wall = rndm (freedoms) + 1;
352 root 1.3 switch (which_wall)
353     {
354 root 1.6 case 1:
355     { /* left hand wall */
356     x1 = (int) xlocations[l];
357     y2 = (int) (ylocations[2 * layers - l - 1] - ylocations[l] - 1);
358     if (y2 > 0)
359 root 1.10 y1 = (int) (ylocations[l] + rndm (y2) + 1);
360 root 1.6 else
361     y1 = (int) (ylocations[l] + 1);
362     break;
363     }
364     case 2:
365     { /* top wall placement */
366     x2 = (int) ((-xlocations[l] + xlocations[2 * layers - l - 1])) - 1;
367     if (x2 > 0)
368 root 1.10 x1 = (int) (xlocations[l] + rndm (x2) + 1);
369 root 1.6 else
370     x1 = (int) (xlocations[l] + 1);
371     y1 = (int) ylocations[l];
372     break;
373     }
374     case 3:
375     { /* right wall placement */
376     x1 = (int) xlocations[2 * layers - l - 1];
377     y2 = (int) ((-ylocations[l] + ylocations[2 * layers - l - 1])) - 1;
378     if (y2 > 0)
379 root 1.10 y1 = (int) (ylocations[l] + rndm (y2) + 1);
380 root 1.6 else
381     y1 = (int) (ylocations[l] + 1);
382    
383     break;
384     }
385     case 4:
386     { /* bottom wall placement */
387     x2 = (int) ((-xlocations[l] + xlocations[2 * layers - l - 1])) - 1;
388     if (x2 > 0)
389 root 1.10 x1 = (int) (xlocations[l] + rndm (x2) + 1);
390 root 1.6 else
391     x1 = (int) (xlocations[l] + 1);
392     y1 = (int) ylocations[2 * layers - l - 1];
393     break;
394     }
395 root 1.3
396     }
397     }
398 root 1.13
399 root 1.5 if (options & RMOPT_NO_DOORS)
400 root 1.3 maze[x1][y1] = '#'; /* no door. */
401     else
402     maze[x1][y1] = 'D'; /* write the door */
403 elmex 1.1
404 root 1.3 }
405 elmex 1.1 /* mark the center of the maze with a C */
406 root 1.3 l = layers - 1;
407     x1 = (int) (xlocations[l] + xlocations[2 * layers - l - 1]) / 2;
408     y1 = (int) (ylocations[l] + ylocations[2 * layers - l - 1]) / 2;
409 root 1.13
410 elmex 1.1 maze[x1][y1] = 'C';
411     }
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
418 root 1.3 maxlayers = (MIN (xsize, ysize) - 2) / 5;
419 root 1.13
420 root 1.3 if (!maxlayers)
421     return; /* map too small to onionize */
422 root 1.13
423 root 1.3 if (layers > maxlayers)
424     layers = maxlayers;
425 root 1.13
426 root 1.3 if (layers == 0)
427 root 1.10 layers = rndm (maxlayers) + 1;
428    
429 root 1.13 float *xlocations = salloc0<float> (2 * layers);
430     float *ylocations = salloc0<float> (2 * layers);
431 root 1.3
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 root 1.10 xpitch = 2 + (rndm (x_spaces_available) + rndm (x_spaces_available) + rndm (x_spaces_available)) / 3;
449 root 1.3
450     if (y_spaces_available > 0)
451 root 1.10 ypitch = 2 + (rndm (y_spaces_available) + rndm (y_spaces_available) + rndm (y_spaces_available)) / 3;
452    
453 root 1.3 if (i < layers)
454     xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
455     else
456     xlocations[i] = xsize - 1;
457    
458     if (i < layers)
459     ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
460     else
461     ylocations[i] = ysize - 1;
462 root 1.13
463 root 1.3 x_spaces_available -= (int) (xpitch - 2);
464     y_spaces_available -= (int) (ypitch - 2);
465     }
466 root 1.13 }
467 root 1.3
468 root 1.5 if (!(option & RMOPT_IRR_SPACE))
469 root 1.3 { /* evenly spaced */
470     float xpitch, ypitch; /* pitch of the onion layers */
471    
472     xpitch = (xsize - 2.0) / (2.0 * layers + 1);
473     ypitch = (ysize - 2.0) / (layers + 1);
474 root 1.13
475 root 1.3 xlocations[0] = xpitch;
476     ylocations[0] = ypitch;
477 root 1.13
478 root 1.3 for (i = 1; i < 2 * layers; i++)
479     {
480     if (i < layers)
481     xlocations[i] = xlocations[i - 1] + xpitch;
482     else
483     xlocations[i] = xsize - 1;
484 root 1.13
485 root 1.3 if (i < layers)
486     ylocations[i] = ylocations[i - 1] + ypitch;
487     else
488     ylocations[i] = ysize - 1;
489     }
490     }
491    
492 elmex 1.1 /* draw all the onion boxes. */
493    
494 root 1.3 draw_onion (maze, xlocations, ylocations, layers);
495     make_doors (maze, xlocations, ylocations, layers, option);
496    
497 root 1.13 sfree (xlocations, 2 * layers);
498     sfree (ylocations, 2 * layers);
499 elmex 1.1 }
500 root 1.13