Crossfire Server, Branches 1.12  R18729
room_gen_onion.c
Go to the documentation of this file.
1 /*
2  * static char *room_gen_onion_c =
3  * "$Id: room_gen_onion.c 11578 2009-02-23 22:02:27Z lalo $";
4  */
5 
6 /*
7  CrossFire, A Multiplayer game for X-windows
8 
9  Copyright (C) 2001 Mark Wedel & Crossfire Development Team
10  Copyright (C) 1992 Frank Tore Johansen
11 
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation; either version 2 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 
26  The authors can be reached via e-mail at crossfire-devel@real-time.com
27 */
28 
58 #include <stdlib.h>
59 #include <global.h>
60 #include <random_map.h>
61 
62 #ifndef MIN
63 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
64 #endif
65 
66 void centered_onion(char **maze, int xsize, int ysize, int option, int layers);
67 void bottom_centered_onion(char **maze, int xsize, int ysize, int option, int layers);
68 void bottom_right_centered_onion(char **maze, int xsize, int ysize, int option, int layers);
69 
70 void draw_onion(char **maze, float *xlocations, float *ylocations, int layers);
71 void make_doors(char **maze, float *xlocations, float *ylocations, int layers, int options);
72 
85 char **map_gen_onion(int xsize, int ysize, int option, int layers) {
86  int i, j;
87 
88  /* allocate that array, set it up */
89  char **maze = (char **)calloc(sizeof(char *), xsize);
90  for (i = 0; i < xsize; i++) {
91  maze[i] = (char *)calloc(sizeof(char), ysize);
92  }
93 
94  /* pick some random options if option = 0 */
95  if (option == 0) {
96  switch (RANDOM()%3) {
97  case 0:
98  option |= OPT_CENTERED;
99  break;
100 
101  case 1:
102  option |= OPT_BOTTOM_C;
103  break;
104 
105  case 2:
106  option |= OPT_BOTTOM_R;
107  break;
108  }
109  if (RANDOM()%2)
110  option |= OPT_LINEAR;
111  if (RANDOM()%2)
112  option |= OPT_IRR_SPACE;
113  }
114 
115  /* write the outer walls, if appropriate. */
116  if (!(option&OPT_WALL_OFF)) {
117  for (i = 0; i < xsize; i++)
118  maze[i][0] = maze[i][ysize-1] = '#';
119  for (j = 0; j < ysize; j++)
120  maze[0][j] = maze[xsize-1][j] = '#';
121  };
122 
123  if (option&OPT_WALLS_ONLY)
124  return maze;
125 
126  /* pick off the mutually exclusive options */
127  if (option&OPT_BOTTOM_R)
128  bottom_right_centered_onion(maze, xsize, ysize, option, layers);
129  else if (option&OPT_BOTTOM_C)
130  bottom_centered_onion(maze, xsize, ysize, option, layers);
131  else if (option&OPT_CENTERED)
132  centered_onion(maze, xsize, ysize, option, layers);
133 
134  return maze;
135 }
136 
149 void centered_onion(char **maze, int xsize, int ysize, int option, int layers) {
150  int i, maxlayers;
151  float *xlocations;
152  float *ylocations;
153 
154  maxlayers = (MIN(xsize, ysize)-2)/5;
155  if (!maxlayers)
156  return; /* map too small to onionize */
157  if (layers > maxlayers)
158  layers = maxlayers;
159  if (layers == 0)
160  layers = (RANDOM()%maxlayers)+1;
161  xlocations = (float *)calloc(sizeof(float), 2*layers);
162  ylocations = (float *)calloc(sizeof(float), 2*layers);
163 
164  /* place all the walls */
165  if (option&OPT_IRR_SPACE) { /* randomly spaced */
166  int x_spaces_available, y_spaces_available;
167  /* the "extra" spaces available for spacing between layers */
168  x_spaces_available = (xsize-2)-6*layers+1;
169  y_spaces_available = (ysize-2)-6*layers+1;
170 
171  /* pick an initial random pitch */
172  for (i = 0; i < 2*layers; i++) {
173  float xpitch = 2, ypitch = 2;
174 
175  if (x_spaces_available > 0)
176  xpitch = 2
177  +(RANDOM()%x_spaces_available
178  +RANDOM()%x_spaces_available
179  +RANDOM()%x_spaces_available)/3;
180 
181  if (y_spaces_available > 0)
182  ypitch = 2
183  +(RANDOM()%y_spaces_available
184  +RANDOM()%y_spaces_available
185  +RANDOM()%y_spaces_available)/3;
186  xlocations[i] = ((i > 0) ? xlocations[i-1] : 0)+xpitch;
187  ylocations[i] = ((i > 0) ? ylocations[i-1] : 0)+ypitch;
188  x_spaces_available -= xpitch-2;
189  y_spaces_available -= ypitch-2;
190  }
191 
192  }
193  if (!(option&OPT_IRR_SPACE)) {
194  /* evenly spaced */
195  float xpitch, ypitch; /* pitch of the onion layers */
196 
197  xpitch = (xsize-2.0)/(2.0*layers+1);
198  ypitch = (ysize-2.0)/(2.0*layers+1);
199  xlocations[0] = xpitch;
200  ylocations[0] = ypitch;
201  for (i = 1; i < 2*layers; i++) {
202  xlocations[i] = xlocations[i-1]+xpitch;
203  ylocations[i] = ylocations[i-1]+ypitch;
204  }
205  }
206 
207  /* draw all the onion boxes. */
208  draw_onion(maze, xlocations, ylocations, layers);
209  make_doors(maze, xlocations, ylocations, layers, option);
210 }
211 
224 void bottom_centered_onion(char **maze, int xsize, int ysize, int option, int layers) {
225  int i, maxlayers;
226  float *xlocations;
227  float *ylocations;
228 
229  maxlayers = (MIN(xsize, ysize)-2)/5;
230  if (!maxlayers)
231  return; /* map too small to onionize */
232  if (layers > maxlayers)
233  layers = maxlayers;
234  if (layers == 0)
235  layers = (RANDOM()%maxlayers)+1;
236  xlocations = (float *)calloc(sizeof(float), 2*layers);
237  ylocations = (float *)calloc(sizeof(float), 2*layers);
238 
239  /* place all the walls */
240  if (option&OPT_IRR_SPACE) { /* randomly spaced */
241  int x_spaces_available, y_spaces_available;
242  /* the "extra" spaces available for spacing between layers */
243  x_spaces_available = (xsize-2)-6*layers+1;
244  y_spaces_available = (ysize-2)-3*layers+1;
245 
246  /* pick an initial random pitch */
247  for (i = 0; i < 2*layers; i++) {
248  float xpitch = 2, ypitch = 2;
249 
250  if (x_spaces_available > 0)
251  xpitch = 2
252  +(RANDOM()%x_spaces_available
253  +RANDOM()%x_spaces_available
254  +RANDOM()%x_spaces_available)/3;
255 
256  if (y_spaces_available > 0)
257  ypitch = 2
258  +(RANDOM()%y_spaces_available
259  +RANDOM()%y_spaces_available
260  +RANDOM()%y_spaces_available)/3;
261  xlocations[i] = ((i > 0) ? xlocations[i-1] : 0)+xpitch;
262  if (i < layers)
263  ylocations[i] = ((i > 0) ? ylocations[i-1] : 0)+ypitch;
264  else
265  ylocations[i] = ysize-1;
266  x_spaces_available -= xpitch-2;
267  y_spaces_available -= ypitch-2;
268  }
269 
270  }
271 
272  if (!(option&OPT_IRR_SPACE)) {
273  /* evenly spaced */
274  float xpitch, ypitch; /* pitch of the onion layers */
275 
276  xpitch = (xsize-2.0)/(2.0*layers+1);
277  ypitch = (ysize-2.0)/(layers+1);
278  xlocations[0] = xpitch;
279  ylocations[0] = ypitch;
280  for (i = 1; i < 2*layers; i++) {
281  xlocations[i] = xlocations[i-1]+xpitch;
282  if (i < layers)
283  ylocations[i] = ylocations[i-1]+ypitch;
284  else
285  ylocations[i] = ysize-1;
286  }
287  }
288 
289  /* draw all the onion boxes. */
290  draw_onion(maze, xlocations, ylocations, layers);
291  make_doors(maze, xlocations, ylocations, layers, option);
292 }
293 
306 void draw_onion(char **maze, float *xlocations, float *ylocations, int layers) {
307  int i, j, l;
308 
309  for (l = 0; l < layers; l++) {
310  int x1, x2, y1, y2;
311 
312  /* horizontal segments */
313  y1 = (int)ylocations[l];
314  y2 = (int)ylocations[2*layers-l-1];
315  for (i = (int)xlocations[l]; i <= (int)xlocations[2*layers-l-1]; i++) {
316  maze[i][y1] = '#';
317  maze[i][y2] = '#';
318  }
319 
320  /* vertical segments */
321  x1 = (int)xlocations[l];
322  x2 = (int)xlocations[2*layers-l-1];
323  for (j = (int)ylocations[l]; j <= (int)ylocations[2*layers-l-1]; j++) {
324  maze[x1][j] = '#';
325  maze[x2][j] = '#';
326  }
327  }
328 }
329 
344 void make_doors(char **maze, float *xlocations, float *ylocations, int layers, int options) {
345  int freedoms; /* number of different walls on which we could place a door */
346  int which_wall; /* left, 1, top, 2, right, 3, bottom 4 */
347  int l, x1 = 0, x2, y1 = 0, y2;
348 
349  freedoms = 4; /* centered */
350  if (options&OPT_BOTTOM_C)
351  freedoms = 3;
352  if (options&OPT_BOTTOM_R)
353  freedoms = 2;
354  if (layers <= 0)
355  return;
356 
357  /* pick which wall will have a door. */
358  which_wall = RANDOM()%freedoms+1;
359  for (l = 0; l < layers; l++) {
360  if (options&OPT_LINEAR) { /* linear door placement. */
361  switch (which_wall) {
362  case 1: { /* left hand wall */
363  x1 = (int)xlocations[l];
364  y1 = (int)((ylocations[l]+ylocations[2*layers-l-1])/2);
365  break;
366  }
367 
368  case 2: { /* top wall placement */
369  x1 = (int)((xlocations[l]+xlocations[2*layers-l-1])/2);
370  y1 = (int)ylocations[l];
371  break;
372  }
373 
374  case 3: { /* right wall placement */
375  x1 = (int)xlocations[2*layers-l-1];
376  y1 = (int)((ylocations[l]+ylocations[2*layers-l-1])/2);
377  break;
378  }
379 
380  case 4: { /* bottom wall placement */
381  x1 = (int)((xlocations[l]+xlocations[2*layers-l-1])/2);
382  y1 = (int)ylocations[2*layers-l-1];
383  break;
384  }
385  }
386  } else { /* random door placement. */
387  which_wall = RANDOM()%freedoms+1;
388  switch (which_wall) {
389  case 1: { /* left hand wall */
390  x1 = (int)xlocations[l];
391  y2 = ylocations[2*layers-l-1]-ylocations[l]-1;
392  if (y2 > 0)
393  y1 = ylocations[l]+RANDOM()%y2+1;
394  else
395  y1 = ylocations[l]+1;
396  break;
397  }
398 
399  case 2: { /* top wall placement */
400  x2 = (int)((-xlocations[l]+xlocations[2*layers-l-1]))-1;
401  if (x2 > 0)
402  x1 = xlocations[l]+RANDOM()%x2+1;
403  else
404  x1 = xlocations[l]+1;
405  y1 = (int)ylocations[l];
406  break;
407  }
408 
409  case 3: { /* right wall placement */
410  x1 = (int)xlocations[2*layers-l-1];
411  y2 = (int)((-ylocations[l]+ylocations[2*layers-l-1]))-1;
412  if (y2 > 0)
413  y1 = ylocations[l]+RANDOM()%y2+1;
414  else
415  y1 = ylocations[l]+1;
416  break;
417  }
418 
419  case 4: { /* bottom wall placement */
420  x2 = (int)((-xlocations[l]+xlocations[2*layers-l-1]))-1;
421  if (x2 > 0)
422  x1 = xlocations[l]+RANDOM()%x2+1;
423  else
424  x1 = xlocations[l]+1;
425  y1 = (int)ylocations[2*layers-l-1];
426  break;
427  }
428  }
429  }
430 
431  if (options&OPT_NO_DOORS)
432  maze[x1][y1] = '#'; /* no door. */
433  else
434  maze[x1][y1] = 'D'; /* write the door */
435  }
436 
437  /* mark the center of the maze with a C */
438  l = layers-1;
439  x1 = (int)(xlocations[l]+xlocations[2*layers-l-1])/2;
440  y1 = (int)(ylocations[l]+ylocations[2*layers-l-1])/2;
441  maze[x1][y1] = 'C';
442 
443  /* not needed anymore */
444  free(xlocations);
445  free(ylocations);
446 }
447 
460 void bottom_right_centered_onion(char **maze, int xsize, int ysize, int option, int layers) {
461  int i, maxlayers;
462  float *xlocations;
463  float *ylocations;
464 
465  maxlayers = (MIN(xsize, ysize)-2)/5;
466  if (!maxlayers)
467  return; /* map too small to onionize */
468  if (layers > maxlayers)
469  layers = maxlayers;
470  if (layers == 0)
471  layers = (RANDOM()%maxlayers)+1;
472  xlocations = (float *)calloc(sizeof(float), 2*layers);
473  ylocations = (float *)calloc(sizeof(float), 2*layers);
474 
475  /* place all the walls */
476  if (option&OPT_IRR_SPACE) { /* randomly spaced */
477  int x_spaces_available, y_spaces_available;
478  /* the "extra" spaces available for spacing between layers */
479  x_spaces_available = (xsize-2)-3*layers+1;
480  y_spaces_available = (ysize-2)-3*layers+1;
481 
482  /* pick an initial random pitch */
483  for (i = 0; i < 2*layers; i++) {
484  float xpitch = 2, ypitch = 2;
485 
486  if (x_spaces_available > 0)
487  xpitch = 2
488  +(RANDOM()%x_spaces_available
489  +RANDOM()%x_spaces_available
490  +RANDOM()%x_spaces_available)/3;
491 
492  if (y_spaces_available > 0)
493  ypitch = 2
494  +(RANDOM()%y_spaces_available
495  +RANDOM()%y_spaces_available
496  +RANDOM()%y_spaces_available)/3;
497  if (i < layers)
498  xlocations[i] = ((i > 0) ? xlocations[i-1] : 0)+xpitch;
499  else
500  xlocations[i] = xsize-1;
501 
502  if (i < layers)
503  ylocations[i] = ((i > 0) ? ylocations[i-1] : 0)+ypitch;
504  else
505  ylocations[i] = ysize-1;
506  x_spaces_available -= xpitch-2;
507  y_spaces_available -= ypitch-2;
508  }
509 
510  }
511 
512  if (!(option&OPT_IRR_SPACE)) { /* evenly spaced */
513  float xpitch, ypitch; /* pitch of the onion layers */
514 
515  xpitch = (xsize-2.0)/(2.0*layers+1);
516  ypitch = (ysize-2.0)/(layers+1);
517  xlocations[0] = xpitch;
518  ylocations[0] = ypitch;
519  for (i = 1; i < 2*layers; i++) {
520  if (i < layers)
521  xlocations[i] = xlocations[i-1]+xpitch;
522  else
523  xlocations[i] = xsize-1;
524  if (i < layers)
525  ylocations[i] = ylocations[i-1]+ypitch;
526  else
527  ylocations[i] = ysize-1;
528  }
529  }
530 
531  /* draw all the onion boxes. */
532  draw_onion(maze, xlocations, ylocations, layers);
533  make_doors(maze, xlocations, ylocations, layers, option);
534 }
static struct Command_Line_Options options[]
Definition: init.c:234
#define MIN(x, y)
#define OPT_IRR_SPACE
Definition: random_map.h:111
#define OPT_CENTERED
Definition: random_map.h:107
#define OPT_WALL_OFF
Definition: random_map.h:112
#define OPT_LINEAR
Definition: random_map.h:108
void make_doors(char **maze, float *xlocations, float *ylocations, int layers, int options)
#define OPT_BOTTOM_R
Definition: random_map.h:110
void centered_onion(char **maze, int xsize, int ysize, int option, int layers)
void draw_onion(char **maze, float *xlocations, float *ylocations, int layers)
#define OPT_BOTTOM_C
Definition: random_map.h:109
#define OPT_WALLS_ONLY
Definition: random_map.h:113
void bottom_centered_onion(char **maze, int xsize, int ysize, int option, int layers)
void bottom_right_centered_onion(char **maze, int xsize, int ysize, int option, int layers)
char ** map_gen_onion(int xsize, int ysize, int option, int layers)
#define OPT_NO_DOORS
Definition: random_map.h:114