ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.12
Committed: Thu Nov 8 19:43:25 2007 UTC (16 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_4, rel-2_32, rel-2_43, rel-2_42, rel-2_41
Changes since 1.11: +4 -4 lines
Log Message:
update copyrights and other minor stuff to deliantra

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