ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.17
Committed: Mon Oct 12 14:00:58 2009 UTC (14 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_82, rel-2_81
Changes since 1.16: +7 -6 lines
Log Message:
clarify license

File Contents

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