ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.11
Committed: Sun Jul 1 05:00:19 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_2, rel-2_3
Changes since 1.10: +10 -12 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

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