ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/room_gen_onion.C
Revision: 1.7
Committed: Sat Jan 6 14:42:30 2007 UTC (17 years, 4 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.6: +1 -0 lines
Log Message:
added some copyrights

File Contents

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