Atrinik Server  4.0
room_gen_onion.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
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 author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
52 #include <global.h>
53 
67 char **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 = ecalloc(sizeof(char *), xsize);
73 
74  for (i = 0; i < xsize; i++) {
75  maze[i] = ecalloc(sizeof(char), ysize);
76  }
77 
78  /* Pick some random options if option = 0 */
79  if (option == 0) {
80  switch (rndm(0, 2)) {
81  case 0:
82  option |= OPT_CENTERED;
83  break;
84 
85  case 1:
86  option |= OPT_BOTTOM_C;
87  break;
88 
89  case 2:
90  option |= OPT_BOTTOM_R;
91  break;
92  }
93 
94  if (rndm_chance(2)) {
95  option |= OPT_LINEAR;
96  }
97 
98  if (rndm_chance(2)) {
99  option |= OPT_IRR_SPACE;
100  }
101  }
102 
103  /* Write the outer walls, if appropriate. */
104  if (!(option & OPT_WALL_OFF)) {
105  for (i = 0; i < xsize; i++) {
106  maze[i][0] = maze[i][ysize - 1] = '#';
107  }
108 
109  for (j = 0; j < ysize; j++) {
110  maze[0][j] = maze[xsize - 1][j] = '#';
111  }
112  }
113 
114  if (option & OPT_WALLS_ONLY) {
115  return maze;
116  }
117 
118  /* pick off the mutually exclusive options */
119  if (option & OPT_BOTTOM_R) {
120  bottom_right_centered_onion(maze, xsize, ysize, option, layers);
121  } else if (option & OPT_BOTTOM_C) {
122  bottom_centered_onion(maze, xsize, ysize, option, layers);
123  } else if (option & OPT_CENTERED) {
124  centered_onion(maze, xsize, ysize, option, layers);
125  }
126 
127  return maze;
128 }
129 
143 void centered_onion(char **maze, int xsize, int ysize, int option, int layers)
144 {
145  int i, maxlayers;
146  float *xlocations, *ylocations;
147 
148  maxlayers = (MIN(xsize, ysize) - 2) / 5;
149 
150  /* map too small to onionize */
151  if (!maxlayers) {
152  return;
153  }
154 
155  if (layers > maxlayers) {
156  layers = maxlayers;
157  }
158 
159  if (layers == 0) {
160  layers = (RANDOM() % maxlayers) + 1;
161  }
162 
163  xlocations = ecalloc(sizeof(float), 2 * layers);
164  ylocations = ecalloc(sizeof(float), 2 * layers);
165 
166  /* Place all the walls */
167 
168  /* Randomly spaced */
169  if (option & OPT_IRR_SPACE) {
170  int x_spaces_available, y_spaces_available;
171 
172  /* the "extra" spaces available for spacing between layers */
173  x_spaces_available = (xsize - 2) - 6 * layers + 1;
174  y_spaces_available = (ysize - 2) - 6 * layers + 1;
175 
176  /* Pick an initial random pitch */
177  for (i = 0; i < 2 * layers; i++) {
178  float xpitch = 2, ypitch = 2;
179 
180  if (x_spaces_available > 0) {
181  xpitch = 2.0f + (float) (RANDOM() % x_spaces_available + RANDOM() % x_spaces_available + RANDOM() % x_spaces_available) / 3.0f;
182  }
183 
184  if (y_spaces_available > 0) {
185  ypitch = 2.0f + (float) (RANDOM() % y_spaces_available + RANDOM() % y_spaces_available + RANDOM() % y_spaces_available) / 3.0f;
186  }
187 
188  xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
189  ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
190 
191  x_spaces_available -= (int) xpitch - 2;
192  y_spaces_available -= (int) ypitch - 2;
193  }
194  }
195 
196  /* evenly spaced */
197  if (!(option & OPT_IRR_SPACE)) {
198  /* pitch of the onion layers */
199  float xpitch, ypitch;
200 
201  xpitch = (float) (xsize - 2) / (2.0f * (float) (layers + 1));
202  ypitch = (float) (ysize - 2) / (2.0f * (float) (layers + 1));
203 
204  xlocations[0] = xpitch;
205  ylocations[0] = ypitch;
206 
207  for (i = 1; i < 2 * layers; i++) {
208  xlocations[i] = xlocations[i - 1] + xpitch;
209  ylocations[i] = ylocations[i - 1] + ypitch;
210  }
211  }
212 
213  /* draw all the onion boxes. */
214  draw_onion(maze, xlocations, ylocations, layers);
215  make_doors(maze, xlocations, ylocations, layers, option);
216 }
217 
231 void bottom_centered_onion(char **maze, int xsize, int ysize, int option, int layers)
232 {
233  int i, maxlayers;
234  float *xlocations, *ylocations;
235 
236  maxlayers = (MIN(xsize, ysize) - 2) / 5;
237 
238  /* map too small to onionize */
239  if (!maxlayers) {
240  return;
241  }
242 
243  if (layers > maxlayers) {
244  layers = maxlayers;
245  }
246 
247  if (layers == 0) {
248  layers = (RANDOM() % maxlayers) + 1;
249  }
250 
251  xlocations = ecalloc(sizeof(float), 2 * layers);
252  ylocations = ecalloc(sizeof(float), 2 * layers);
253 
254  /* place all the walls */
255 
256  /* randomly spaced */
257  if (option & OPT_IRR_SPACE) {
258  int x_spaces_available, y_spaces_available;
259 
260  /* the "extra" spaces available for spacing between layers */
261  x_spaces_available = (xsize - 2) - 6 * layers + 1;
262  y_spaces_available = (ysize - 2) - 3 * layers + 1;
263 
264  /* Pick an initial random pitch */
265  for (i = 0; i < 2 * layers; i++) {
266  float xpitch = 2, ypitch = 2;
267 
268  if (x_spaces_available > 0) {
269  xpitch = 2.0f + (float) (RANDOM() % x_spaces_available + RANDOM() % x_spaces_available + RANDOM() % x_spaces_available) / 3.0f;
270  }
271 
272  if (y_spaces_available > 0) {
273  ypitch = 2.0f + (float) (RANDOM() % y_spaces_available + RANDOM() % y_spaces_available + RANDOM() % y_spaces_available) / 3.0f;
274  }
275 
276  xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
277 
278  if (i < layers) {
279  ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
280  } else {
281  ylocations[i] = (float) (ysize - 1);
282  }
283 
284  x_spaces_available -= (int) xpitch - 2;
285  y_spaces_available -= (int) ypitch - 2;
286  }
287  }
288 
289  /* evenly spaced */
290  if (!(option & OPT_IRR_SPACE)) {
291  /* pitch of the onion layers */
292  float xpitch, ypitch;
293 
294  xpitch = (float) (xsize - 2) / (2.0f * (float) (layers + 1));
295  ypitch = (float) (ysize - 2) / (float) (layers + 1);
296 
297  xlocations[0] = xpitch;
298  ylocations[0] = ypitch;
299 
300  for (i = 1; i < 2 * layers; i++) {
301  xlocations[i] = xlocations[i - 1] + xpitch;
302 
303  if (i < layers) {
304  ylocations[i] = ylocations[i - 1] + ypitch;
305  } else {
306  ylocations[i] = (float) (ysize - 1);
307  }
308  }
309  }
310 
311  /* draw all the onion boxes. */
312  draw_onion(maze, xlocations, ylocations, layers);
313  make_doors(maze, xlocations, ylocations, layers, option);
314 }
315 
327 void draw_onion(char **maze, float *xlocations, float *ylocations, int layers)
328 {
329  int i, j, l;
330 
331  for (l = 0; l < layers; l++) {
332  int x, x2, y, y2;
333 
334  /* horizontal segments */
335  y = (int) ylocations[l];
336  y2 = (int) ylocations[2 * layers - l - 1];
337 
338  for (i = (int) xlocations[l]; i <= (int) xlocations[2 * layers - l - 1]; i++) {
339  maze[i][y] = '#';
340  maze[i][y2] = '#';
341  }
342 
343  /* vertical segments */
344  x = (int) xlocations[l];
345  x2 = (int) xlocations[2 * layers - l - 1];
346 
347  for (j = (int) ylocations[l]; j <= (int) ylocations[2 * layers - l - 1]; j++) {
348  maze[x][j] = '#';
349  maze[x2][j] = '#';
350  }
351  }
352 }
353 
367 void make_doors(char **maze, float *xlocations, float *ylocations, int layers, int options)
368 {
369  /* number of different walls on which we could place a door */
370  int freedoms;
371  /* left, 1, top, 2, right, 3, bottom 4 */
372  int which_wall;
373  int l, x = 0, x2, y = 0, y2;
374 
375  /* centered */
376  freedoms = 4;
377 
378  if (options & OPT_BOTTOM_C) {
379  freedoms = 3;
380  }
381 
382  if (options & OPT_BOTTOM_R) {
383  freedoms = 2;
384  }
385 
386  if (layers <= 0) {
387  return;
388  }
389 
390  /* Pick which wall will have a door. */
391  which_wall = RANDOM() % freedoms + 1;
392 
393  for (l = 0; l < layers; l++) {
394  /* linear door placement. */
395  if (options & OPT_LINEAR) {
396  switch (which_wall) {
397  /* Left hand wall */
398  case 1:
399  x = (int) xlocations[l];
400  y = (int) ((ylocations[l] + ylocations[2 * layers - l - 1]) / 2);
401 
402  break;
403 
404  /* Top wall placement */
405  case 2:
406  x = (int) ((xlocations[l] + xlocations[2 * layers - l - 1]) / 2);
407  y = (int) ylocations[l];
408 
409  break;
410 
411  /* Right wall placement */
412  case 3:
413  x = (int) xlocations[2 * layers - l - 1];
414  y = (int) ((ylocations[l] + ylocations[2 * layers - l - 1]) / 2);
415 
416  break;
417 
418  /* Bottom wall placement */
419  case 4:
420  x = (int) ((xlocations[l] + xlocations[2 * layers - l - 1]) / 2);
421  y = (int) ylocations[2 * layers - l - 1];
422 
423  break;
424  }
425  } else {
426  /* random door placement. */
427 
428  which_wall = RANDOM() % freedoms + 1;
429 
430  switch (which_wall) {
431  /* Left hand wall */
432  case 1:
433  x = (int) xlocations[l];
434  y2 = (int) (ylocations[2 * layers - l - 1] - ylocations[l] - 1.0f);
435 
436  if (y2 > 0) {
437  y = (int) ylocations[l] + RANDOM() % y2 + 1;
438  } else {
439  y = (int) ylocations[l] + 1;
440  }
441 
442  break;
443 
444  /* Top wall placement */
445  case 2:
446  x2 = (int) ((-xlocations[l] + xlocations[2 * layers - l - 1])) - 1;
447 
448  if (x2 > 0) {
449  x = (int) xlocations[l] + RANDOM() % x2 + 1;
450  } else {
451  x = (int) xlocations[l] + 1;
452  }
453 
454  y = (int) ylocations[l];
455 
456  break;
457 
458  /* Right wall placement */
459  case 3:
460  x = (int) xlocations[2 * layers - l - 1];
461  y2 = (int) ((-ylocations[l] + ylocations[2 * layers - l - 1])) - 1;
462 
463  if (y2 > 0) {
464  y = (int) ylocations[l] + RANDOM() % y2 + 1;
465  } else {
466  y = (int) ylocations[l] + 1;
467  }
468 
469  break;
470 
471  /* Bottom wall placement */
472  case 4:
473  x2 = (int) ((-xlocations[l] + xlocations[2 * layers - l - 1])) - 1;
474 
475  if (x2 > 0) {
476  x = (int) xlocations[l] + RANDOM() % x2 + 1;
477  } else {
478  x = (int) xlocations[l] + 1;
479  }
480 
481  y = (int) ylocations[2 * layers - l - 1];
482 
483  break;
484  }
485  }
486 
487  if (options & OPT_NO_DOORS) {
488  /* no door. */
489  maze[x][y] = '#';
490  } else {
491  /* write the door */
492  maze[x][y] = 'D';
493  }
494  }
495 
496  /* mark the center of the maze with a C */
497  l = layers - 1;
498  x = (int) (xlocations[l] + xlocations[2 * layers - l - 1]) / 2;
499  y = (int) (ylocations[l] + ylocations[2 * layers - l - 1]) / 2;
500 
501  maze[x][y] = 'C';
502 
503  /* Not needed anymore */
504  efree(xlocations);
505  efree(ylocations);
506 }
507 
521 void bottom_right_centered_onion(char **maze, int xsize, int ysize, int option, int layers)
522 {
523  int i, maxlayers;
524  float *xlocations, *ylocations;
525 
526  maxlayers = (MIN(xsize, ysize) - 2) / 5;
527 
528  /* map too small to onionize */
529  if (!maxlayers) {
530  return;
531  }
532 
533  if (layers > maxlayers) {
534  layers = maxlayers;
535  }
536 
537  if (layers == 0) {
538  layers = (RANDOM() % maxlayers) + 1;
539  }
540 
541  xlocations = ecalloc(sizeof(float), 2 * layers);
542  ylocations = ecalloc(sizeof(float), 2 * layers);
543 
544  /* place all the walls */
545 
546  /* randomly spaced */
547  if (option & OPT_IRR_SPACE) {
548  int x_spaces_available, y_spaces_available;
549 
550  /* the "extra" spaces available for spacing between layers */
551  x_spaces_available = (xsize - 2) - 3 * layers + 1;
552  y_spaces_available = (ysize - 2) - 3 * layers + 1;
553 
554  /* Pick an initial random pitch */
555  for (i = 0; i < 2 * layers; i++) {
556  float xpitch = 2, ypitch = 2;
557 
558  if (x_spaces_available > 0) {
559  xpitch = 2.0f + (float) (RANDOM() % x_spaces_available + RANDOM() % x_spaces_available + RANDOM() % x_spaces_available) / 3.0f;
560  }
561 
562  if (y_spaces_available > 0) {
563  ypitch = 2.0f + (float) (RANDOM() % y_spaces_available + RANDOM() % y_spaces_available + RANDOM() % y_spaces_available) / 3.0f;
564  }
565 
566  if (i < layers) {
567  xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
568  } else {
569  xlocations[i] = (float) (xsize - 1);
570  }
571 
572  if (i < layers) {
573  ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
574  } else {
575  ylocations[i] = (float) (ysize - 1);
576  }
577 
578  x_spaces_available -= (int) xpitch - 2;
579  y_spaces_available -= (int) ypitch - 2;
580  }
581 
582  }
583 
584  /* evenly spaced */
585  if (!(option & OPT_IRR_SPACE)) {
586  /* pitch of the onion layers */
587  float xpitch, ypitch;
588 
589  xpitch = (float) (xsize - 2) / (float) (2 * layers + 1);
590  ypitch = (float) (ysize - 2) / (float) (layers + 1);
591 
592  xlocations[0] = xpitch;
593  ylocations[0] = ypitch;
594 
595  for (i = 1; i < 2 * layers; i++) {
596  if (i < layers) {
597  xlocations[i] = xlocations[i - 1] + xpitch;
598  } else {
599  xlocations[i] = (float) (xsize - 1);
600  }
601 
602  if (i < layers) {
603  ylocations[i] = ylocations[i - 1] + ypitch;
604  } else {
605  ylocations[i] = (float) (ysize - 1);
606  }
607  }
608  }
609 
610  /* draw all the onion boxes. */
611  draw_onion(maze, xlocations, ylocations, layers);
612  make_doors(maze, xlocations, ylocations, layers, option);
613 }
#define OPT_IRR_SPACE
Definition: random_map.h:163
#define OPT_CENTERED
Definition: random_map.h:155
#define OPT_WALL_OFF
Definition: random_map.h:165
#define OPT_LINEAR
Definition: random_map.h:157
void make_doors(char **maze, float *xlocations, float *ylocations, int layers, int options)
#define OPT_BOTTOM_R
Definition: random_map.h:161
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:159
#define OPT_WALLS_ONLY
Definition: random_map.h:167
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)