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

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 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 xsize = maze.w;
68 int ysize = maze.h;
69
70 maze.clear ();
71
72 /* pick some random options if option = 0 */
73 if (option == 0)
74 {
75 switch (rmg_rndm (3))
76 {
77 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 }
87
88 if (rmg_rndm (2)) option |= RMOPT_LINEAR;
89 if (rmg_rndm (2)) option |= RMOPT_IRR_SPACE;
90 }
91
92 /* write the outer walls, if appropriate. */
93 if (!(option & RMOPT_WALL_OFF))
94 maze.border ();
95
96 if (option & RMOPT_WALLS_ONLY)
97 return;
98
99 /* pick off the mutually exclusive options */
100 if (option & RMOPT_BOTTOM_R)
101 bottom_right_centered_onion (maze, xsize, ysize, option, layers);
102 else if (option & RMOPT_BOTTOM_C)
103 bottom_centered_onion (maze, xsize, ysize, option, layers);
104 else if (option & RMOPT_CENTERED)
105 centered_onion (maze, xsize, ysize, option, layers);
106 }
107
108 static void
109 centered_onion (char **maze, int xsize, int ysize, int option, int layers)
110 {
111 int i, maxlayers;
112
113 maxlayers = (min (xsize, ysize) - 2) / 5;
114
115 if (!maxlayers)
116 return; /* map too small to onionize */
117
118 if (layers > maxlayers)
119 layers = maxlayers;
120
121 if (layers == 0)
122 layers = rmg_rndm (maxlayers) + 1;
123
124 float *xlocations = salloc0<float> (2 * layers);
125 float *ylocations = salloc0<float> (2 * layers);
126
127 /* place all the walls */
128 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
129 {
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 xpitch = 2 + (rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available)) / 3;
143
144 if (y_spaces_available > 0)
145 ypitch = 2 + (rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available)) / 3;
146
147 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
155 if (!(option & RMOPT_IRR_SPACE))
156 { /* 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
162 xlocations[0] = xpitch;
163 ylocations[0] = ypitch;
164
165 for (i = 1; i < 2 * layers; i++)
166 {
167 xlocations[i] = xlocations[i - 1] + xpitch;
168 ylocations[i] = ylocations[i - 1] + ypitch;
169 }
170 }
171
172 /* draw all the onion boxes. */
173 draw_onion (maze, xlocations, ylocations, layers);
174 make_doors (maze, xlocations, ylocations, layers, option);
175
176 sfree (xlocations, 2 * layers);
177 sfree (ylocations, 2 * layers);
178 }
179
180 static void
181 bottom_centered_onion (char **maze, int xsize, int ysize, int option, int layers)
182 {
183 int i, maxlayers;
184
185 maxlayers = (min (xsize, ysize) - 2) / 5;
186
187 if (!maxlayers)
188 return; /* map too small to onionize */
189
190 if (layers > maxlayers)
191 layers = maxlayers;
192
193 if (layers == 0)
194 layers = rmg_rndm (maxlayers) + 1;
195
196 float *xlocations = salloc0<float> (2 * layers);
197 float *ylocations = salloc0<float> (2 * layers);
198
199 /* place all the walls */
200 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
201 {
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 xpitch = 2 + (rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available)) / 3;
215
216 if (y_spaces_available > 0)
217 ypitch = 2 + (rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available)) / 3;
218
219 xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
220
221 if (i < layers)
222 ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
223 else
224 ylocations[i] = ysize - 1;
225
226 x_spaces_available -= (int) (xpitch - 2);
227 y_spaces_available -= (int) (ypitch - 2);
228 }
229 }
230
231 if (!(option & RMOPT_IRR_SPACE))
232 { /* 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
238 xlocations[0] = xpitch;
239 ylocations[0] = ypitch;
240
241 for (i = 1; i < 2 * layers; i++)
242 {
243 xlocations[i] = xlocations[i - 1] + xpitch;
244
245 if (i < layers)
246 ylocations[i] = ylocations[i - 1] + ypitch;
247 else
248 ylocations[i] = ysize - 1;
249 }
250 }
251
252 /* draw all the onion boxes. */
253
254 draw_onion (maze, xlocations, ylocations, layers);
255 make_doors (maze, xlocations, ylocations, layers, option);
256
257 sfree (xlocations, 2 * layers);
258 sfree (ylocations, 2 * layers);
259 }
260
261 /* draw_boxes: draws the lines in the maze defining the onion layers */
262 static void
263 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
289 }
290 }
291
292 static void
293 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
301 if (options & RMOPT_BOTTOM_C)
302 freedoms = 3;
303
304 if (options & RMOPT_BOTTOM_R)
305 freedoms = 2;
306
307 if (layers <= 0)
308 return;
309
310 /* pick which wall will have a door. */
311 which_wall = rmg_rndm (freedoms) + 1;
312 for (l = 0; l < layers; l++)
313 {
314 if (options & RMOPT_LINEAR)
315 { /* linear door placement. */
316 switch (which_wall)
317 {
318 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 }
343 }
344 else
345 { /* random door placement. */
346 which_wall = rmg_rndm (freedoms) + 1;
347 switch (which_wall)
348 {
349 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 y1 = (int) (ylocations[l] + rmg_rndm (y2) + 1);
355 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 x1 = (int) (xlocations[l] + rmg_rndm (x2) + 1);
364 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 y1 = (int) (ylocations[l] + rmg_rndm (y2) + 1);
375 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 x1 = (int) (xlocations[l] + rmg_rndm (x2) + 1);
385 else
386 x1 = (int) (xlocations[l] + 1);
387 y1 = (int) ylocations[2 * layers - l - 1];
388 break;
389 }
390
391 }
392 }
393
394 if (options & RMOPT_NO_DOORS)
395 maze[x1][y1] = '#'; /* no door. */
396 else
397 maze[x1][y1] = 'D'; /* write the door */
398
399 }
400 /* mark the center of the maze with a C */
401 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
405 maze[x1][y1] = 'C';
406 }
407
408 static void
409 bottom_right_centered_onion (char **maze, int xsize, int ysize, int option, int layers)
410 {
411 int i, maxlayers;
412
413 maxlayers = (min (xsize, ysize) - 2) / 5;
414
415 if (!maxlayers)
416 return; /* map too small to onionize */
417
418 if (layers > maxlayers)
419 layers = maxlayers;
420
421 if (layers == 0)
422 layers = rmg_rndm (maxlayers) + 1;
423
424 float *xlocations = salloc0<float> (2 * layers);
425 float *ylocations = salloc0<float> (2 * layers);
426
427 /* place all the walls */
428 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
429 {
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 xpitch = 2 + (rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available) + rmg_rndm (x_spaces_available)) / 3;
444
445 if (y_spaces_available > 0)
446 ypitch = 2 + (rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available) + rmg_rndm (y_spaces_available)) / 3;
447
448 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
458 x_spaces_available -= (int) (xpitch - 2);
459 y_spaces_available -= (int) (ypitch - 2);
460 }
461 }
462
463 if (!(option & RMOPT_IRR_SPACE))
464 { /* 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
470 xlocations[0] = xpitch;
471 ylocations[0] = ypitch;
472
473 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
480 if (i < layers)
481 ylocations[i] = ylocations[i - 1] + ypitch;
482 else
483 ylocations[i] = ysize - 1;
484 }
485 }
486
487 /* draw all the onion boxes. */
488
489 draw_onion (maze, xlocations, ylocations, layers);
490 make_doors (maze, xlocations, ylocations, layers, option);
491
492 sfree (xlocations, 2 * layers);
493 sfree (ylocations, 2 * layers);
494 }
495