ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.30
Committed: Wed Nov 16 23:42:02 2016 UTC (7 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.29: +1 -1 lines
Log Message:
copyright update 2016

File Contents

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