ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.8
Committed: Mon Jan 15 21:06:19 2007 UTC (17 years, 4 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.7: +22 -23 lines
Log Message:
comments

File Contents

# Content
1 /*
2 * CrossFire, A Multiplayer game for X-windows
3 *
4 * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5 * Copyright (C) 2001 Mark Wedel & Crossfire Development Team
6 * Copyright (C) 1992 Frank Tore Johansen
7 *
8 * This program 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 2 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, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * The authors can be reached via e-mail at <crossfire@schmorp.de>
23 */
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 <random_map.h>
56
57 #ifndef MIN
58 # define MIN(x,y) (((x)<(y))? (x):(y))
59 #endif
60 void centered_onion (char **maze, int xsize, int ysize, int option, int layers);
61 void bottom_centered_onion (char **maze, int xsize, int ysize, int option, int layers);
62 void bottom_right_centered_onion (char **maze, int xsize, int ysize, int option, int layers);
63
64
65 void draw_onion (char **maze, float *xlocations, float *ylocations, int layers);
66 void make_doors (char **maze, float *xlocations, float *ylocations, int layers, int options);
67
68 char **
69 map_gen_onion (int xsize, int ysize, int option, int layers)
70 {
71 int i, j;
72
73 /* allocate that array, set it up */
74 char **maze = (char **) calloc (sizeof (char *), xsize);
75
76 for (i = 0; i < xsize; i++)
77 {
78 maze[i] = (char *) calloc (sizeof (char), ysize);
79 }
80
81 /* pick some random options if option = 0 */
82 if (option == 0)
83 {
84 switch (RANDOM () % 3)
85 {
86 case 0:
87 option |= RMOPT_CENTERED;
88 break;
89 case 1:
90 option |= RMOPT_BOTTOM_C;
91 break;
92 case 2:
93 option |= RMOPT_BOTTOM_R;
94 break;
95 }
96 if (RANDOM () % 2)
97 option |= RMOPT_LINEAR;
98 if (RANDOM () % 2)
99 option |= RMOPT_IRR_SPACE;
100 }
101
102 /* write the outer walls, if appropriate. */
103 if (!(option & RMOPT_WALL_OFF))
104 {
105 for (i = 0; i < xsize; i++)
106 maze[i][0] = maze[i][ysize - 1] = '#';
107 for (j = 0; j < ysize; j++)
108 maze[0][j] = maze[xsize - 1][j] = '#';
109 };
110
111 if (option & RMOPT_WALLS_ONLY)
112 return maze;
113
114 /* pick off the mutually exclusive options */
115 if (option & RMOPT_BOTTOM_R)
116 bottom_right_centered_onion (maze, xsize, ysize, option, layers);
117 else if (option & RMOPT_BOTTOM_C)
118 bottom_centered_onion (maze, xsize, ysize, option, layers);
119 else if (option & RMOPT_CENTERED)
120 centered_onion (maze, xsize, ysize, option, layers);
121
122 return maze;
123 }
124
125 void
126 centered_onion (char **maze, int xsize, int ysize, int option, int layers)
127 {
128 int i, maxlayers;
129 float *xlocations;
130 float *ylocations;
131
132 maxlayers = (MIN (xsize, ysize) - 2) / 5;
133 if (!maxlayers)
134 return; /* map too small to onionize */
135 if (layers > maxlayers)
136 layers = maxlayers;
137 if (layers == 0)
138 layers = (RANDOM () % maxlayers) + 1;
139 xlocations = (float *) calloc (sizeof (float), 2 * layers);
140 ylocations = (float *) calloc (sizeof (float), 2 * layers);
141
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 + (RANDOM () % x_spaces_available + RANDOM () % x_spaces_available + RANDOM () % x_spaces_available) / 3;
160
161 if (y_spaces_available > 0)
162 ypitch = 2 + (RANDOM () % y_spaces_available + RANDOM () % y_spaces_available + RANDOM () % y_spaces_available) / 3;
163 xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
164 ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
165 x_spaces_available -= (int) (xpitch - 2);
166 y_spaces_available -= (int) (ypitch - 2);
167 }
168
169 }
170 if (!(option & RMOPT_IRR_SPACE))
171 { /* evenly spaced */
172 float xpitch, ypitch; /* pitch of the onion layers */
173
174 xpitch = (xsize - 2.0) / (2.0 * layers + 1);
175 ypitch = (ysize - 2.0) / (2.0 * layers + 1);
176 xlocations[0] = xpitch;
177 ylocations[0] = ypitch;
178 for (i = 1; i < 2 * layers; i++)
179 {
180 xlocations[i] = xlocations[i - 1] + xpitch;
181 ylocations[i] = ylocations[i - 1] + ypitch;
182 }
183 }
184
185 /* draw all the onion boxes. */
186
187 draw_onion (maze, xlocations, ylocations, layers);
188 make_doors (maze, xlocations, ylocations, layers, option);
189
190 }
191
192 void
193 bottom_centered_onion (char **maze, int xsize, int ysize, int option, int layers)
194 {
195 int i, maxlayers;
196 float *xlocations;
197 float *ylocations;
198
199 maxlayers = (MIN (xsize, ysize) - 2) / 5;
200 if (!maxlayers)
201 return; /* map too small to onionize */
202 if (layers > maxlayers)
203 layers = maxlayers;
204 if (layers == 0)
205 layers = (RANDOM () % maxlayers) + 1;
206 xlocations = (float *) calloc (sizeof (float), 2 * layers);
207 ylocations = (float *) calloc (sizeof (float), 2 * layers);
208
209
210 /* place all the walls */
211 if (option & RMOPT_IRR_SPACE) /* randomly spaced */
212 {
213 int x_spaces_available, y_spaces_available;
214
215 /* the "extra" spaces available for spacing between layers */
216 x_spaces_available = (xsize - 2) - 6 * layers + 1;
217 y_spaces_available = (ysize - 2) - 3 * layers + 1;
218
219
220 /* pick an initial random pitch */
221 for (i = 0; i < 2 * layers; i++)
222 {
223 float xpitch = 2, ypitch = 2;
224
225 if (x_spaces_available > 0)
226 xpitch = 2 + (RANDOM () % x_spaces_available + RANDOM () % x_spaces_available + RANDOM () % x_spaces_available) / 3;
227
228 if (y_spaces_available > 0)
229 ypitch = 2 + (RANDOM () % y_spaces_available + RANDOM () % y_spaces_available + RANDOM () % y_spaces_available) / 3;
230 xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
231 if (i < layers)
232 ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
233 else
234 ylocations[i] = ysize - 1;
235 x_spaces_available -= (int) (xpitch - 2);
236 y_spaces_available -= (int) (ypitch - 2);
237 }
238
239 }
240 if (!(option & RMOPT_IRR_SPACE))
241 { /* evenly spaced */
242 float xpitch, ypitch; /* pitch of the onion layers */
243
244 xpitch = (xsize - 2.0) / (2.0 * layers + 1);
245 ypitch = (ysize - 2.0) / (layers + 1);
246 xlocations[0] = xpitch;
247 ylocations[0] = ypitch;
248 for (i = 1; i < 2 * layers; i++)
249 {
250 xlocations[i] = xlocations[i - 1] + xpitch;
251 if (i < layers)
252 ylocations[i] = ylocations[i - 1] + ypitch;
253 else
254 ylocations[i] = ysize - 1;
255 }
256 }
257
258 /* draw all the onion boxes. */
259
260 draw_onion (maze, xlocations, ylocations, layers);
261 make_doors (maze, xlocations, ylocations, layers, option);
262
263 }
264
265
266 /* draw_boxes: draws the lines in the maze defining the onion layers */
267
268 void
269 draw_onion (char **maze, float *xlocations, float *ylocations, int layers)
270 {
271 int i, j, l;
272
273 for (l = 0; l < layers; l++)
274 {
275 int x1, x2, y1, y2;
276
277 /* horizontal segments */
278 y1 = (int) ylocations[l];
279 y2 = (int) ylocations[2 * layers - l - 1];
280 for (i = (int) xlocations[l]; i <= (int) xlocations[2 * layers - l - 1]; i++)
281 {
282 maze[i][y1] = '#';
283 maze[i][y2] = '#';
284 }
285
286 /* vertical segments */
287 x1 = (int) xlocations[l];
288 x2 = (int) xlocations[2 * layers - l - 1];
289 for (j = (int) ylocations[l]; j <= (int) ylocations[2 * layers - l - 1]; j++)
290 {
291 maze[x1][j] = '#';
292 maze[x2][j] = '#';
293 }
294
295 }
296 }
297
298 void
299 make_doors (char **maze, float *xlocations, float *ylocations, int layers, int options)
300 {
301 int freedoms; /* number of different walls on which we could place a door */
302 int which_wall; /* left, 1, top, 2, right, 3, bottom 4 */
303 int l, x1 = 0, x2, y1 = 0, y2;
304
305 freedoms = 4; /* centered */
306 if (options & RMOPT_BOTTOM_C)
307 freedoms = 3;
308 if (options & RMOPT_BOTTOM_R)
309 freedoms = 2;
310 if (layers <= 0)
311 return;
312 /* pick which wall will have a door. */
313 which_wall = RANDOM () % 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 = RANDOM () % 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] + RANDOM () % 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] + RANDOM () % 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] + RANDOM () % 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] + RANDOM () % 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 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 maze[x1][y1] = 'C';
406
407 /* not needed anymore */
408 free (xlocations);
409 free (ylocations);
410
411 }
412
413 void
414 bottom_right_centered_onion (char **maze, int xsize, int ysize, int option, int layers)
415 {
416 int i, maxlayers;
417 float *xlocations;
418 float *ylocations;
419
420 maxlayers = (MIN (xsize, ysize) - 2) / 5;
421 if (!maxlayers)
422 return; /* map too small to onionize */
423 if (layers > maxlayers)
424 layers = maxlayers;
425 if (layers == 0)
426 layers = (RANDOM () % maxlayers) + 1;
427 xlocations = (float *) calloc (sizeof (float), 2 * layers);
428 ylocations = (float *) calloc (sizeof (float), 2 * layers);
429
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 + (RANDOM () % x_spaces_available + RANDOM () % x_spaces_available + RANDOM () % x_spaces_available) / 3;
448
449 if (y_spaces_available > 0)
450 ypitch = 2 + (RANDOM () % y_spaces_available + RANDOM () % y_spaces_available + RANDOM () % y_spaces_available) / 3;
451 if (i < layers)
452 xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
453 else
454 xlocations[i] = xsize - 1;
455
456 if (i < layers)
457 ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
458 else
459 ylocations[i] = ysize - 1;
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 xlocations[0] = xpitch;
472 ylocations[0] = ypitch;
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 if (i < layers)
480 ylocations[i] = ylocations[i - 1] + ypitch;
481 else
482 ylocations[i] = ysize - 1;
483 }
484 }
485
486 /* draw all the onion boxes. */
487
488 draw_onion (maze, xlocations, ylocations, layers);
489 make_doors (maze, xlocations, ylocations, layers, option);
490
491 }