ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.27
Committed: Tue Jan 3 11:25:34 2012 UTC (12 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.26: +1 -1 lines
Log Message:
update copyrights to 2012

File Contents

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