ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.31
Committed: Sat Nov 17 23:40:02 2018 UTC (5 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.30: +1 -0 lines
Log Message:
copyright update 2018

File Contents

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