Crossfire Server, Branch 1.12  R12190
room_gen_onion.c
Go to the documentation of this file.
00001 /*
00002  * static char *room_gen_onion_c =
00003  *   "$Id: room_gen_onion.c 11578 2009-02-23 22:02:27Z lalo $";
00004  */
00005 
00006 /*
00007     CrossFire, A Multiplayer game for X-windows
00008 
00009     Copyright (C) 2001 Mark Wedel & Crossfire Development Team
00010     Copyright (C) 1992 Frank Tore Johansen
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00025 
00026     The authors can be reached via e-mail at crossfire-devel@real-time.com
00027 */
00028 
00058 #include <stdlib.h>
00059 #include <global.h>
00060 #include <random_map.h>
00061 
00062 #ifndef MIN
00063 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
00064 #endif
00065 
00066 void centered_onion(char **maze, int xsize, int ysize, int option, int layers);
00067 void bottom_centered_onion(char **maze, int xsize, int ysize, int option, int layers);
00068 void bottom_right_centered_onion(char **maze, int xsize, int ysize, int option, int layers);
00069 
00070 void draw_onion(char **maze, float *xlocations, float *ylocations, int layers);
00071 void make_doors(char **maze, float *xlocations, float *ylocations, int layers, int options);
00072 
00085 char **map_gen_onion(int xsize, int ysize, int option, int layers) {
00086     int i, j;
00087 
00088     /* allocate that array, set it up */
00089     char **maze = (char **)calloc(sizeof(char *), xsize);
00090     for (i = 0; i < xsize; i++) {
00091         maze[i] = (char *)calloc(sizeof(char), ysize);
00092     }
00093 
00094     /* pick some random options if option = 0 */
00095     if (option == 0) {
00096         switch (RANDOM()%3) {
00097         case 0:
00098             option |= OPT_CENTERED;
00099             break;
00100 
00101         case 1:
00102             option |= OPT_BOTTOM_C;
00103             break;
00104 
00105         case 2:
00106             option |= OPT_BOTTOM_R;
00107             break;
00108         }
00109         if (RANDOM()%2)
00110             option |= OPT_LINEAR;
00111         if (RANDOM()%2)
00112             option |= OPT_IRR_SPACE;
00113     }
00114 
00115     /* write the outer walls, if appropriate. */
00116     if (!(option&OPT_WALL_OFF)) {
00117         for (i = 0; i < xsize; i++)
00118             maze[i][0] = maze[i][ysize-1] = '#';
00119         for (j = 0; j < ysize; j++)
00120             maze[0][j] = maze[xsize-1][j] = '#';
00121     };
00122 
00123     if (option&OPT_WALLS_ONLY)
00124         return maze;
00125 
00126     /* pick off the mutually exclusive options */
00127     if (option&OPT_BOTTOM_R)
00128         bottom_right_centered_onion(maze, xsize, ysize, option, layers);
00129     else if (option&OPT_BOTTOM_C)
00130         bottom_centered_onion(maze, xsize, ysize, option, layers);
00131     else if (option&OPT_CENTERED)
00132         centered_onion(maze, xsize, ysize, option, layers);
00133 
00134     return maze;
00135 }
00136 
00149 void centered_onion(char **maze, int xsize, int ysize, int option, int layers) {
00150     int i, maxlayers;
00151     float *xlocations;
00152     float *ylocations;
00153 
00154     maxlayers = (MIN(xsize, ysize)-2)/5;
00155     if (!maxlayers)
00156         return; /* map too small to onionize */
00157     if (layers > maxlayers)
00158         layers = maxlayers;
00159     if (layers == 0)
00160         layers = (RANDOM()%maxlayers)+1;
00161     xlocations = (float *)calloc(sizeof(float), 2*layers);
00162     ylocations = (float *)calloc(sizeof(float), 2*layers);
00163 
00164     /* place all the walls */
00165     if (option&OPT_IRR_SPACE) { /* randomly spaced */
00166         int x_spaces_available, y_spaces_available;
00167         /* the "extra" spaces available for spacing between layers */
00168         x_spaces_available = (xsize-2)-6*layers+1;
00169         y_spaces_available = (ysize-2)-6*layers+1;
00170 
00171         /* pick an initial random pitch */
00172         for (i = 0; i < 2*layers; i++) {
00173             float xpitch = 2, ypitch = 2;
00174 
00175             if (x_spaces_available > 0)
00176                 xpitch = 2
00177                     +(RANDOM()%x_spaces_available
00178                     +RANDOM()%x_spaces_available
00179                     +RANDOM()%x_spaces_available)/3;
00180 
00181             if (y_spaces_available > 0)
00182                 ypitch = 2
00183                     +(RANDOM()%y_spaces_available
00184                     +RANDOM()%y_spaces_available
00185                     +RANDOM()%y_spaces_available)/3;
00186             xlocations[i] = ((i > 0) ? xlocations[i-1] : 0)+xpitch;
00187             ylocations[i] = ((i > 0) ? ylocations[i-1] : 0)+ypitch;
00188             x_spaces_available -= xpitch-2;
00189             y_spaces_available -= ypitch-2;
00190         }
00191 
00192     }
00193     if (!(option&OPT_IRR_SPACE)) {
00194         /* evenly spaced */
00195         float xpitch, ypitch;  /* pitch of the onion layers */
00196 
00197         xpitch = (xsize-2.0)/(2.0*layers+1);
00198         ypitch = (ysize-2.0)/(2.0*layers+1);
00199         xlocations[0] = xpitch;
00200         ylocations[0] = ypitch;
00201         for (i = 1; i < 2*layers; i++) {
00202             xlocations[i] = xlocations[i-1]+xpitch;
00203             ylocations[i] = ylocations[i-1]+ypitch;
00204         }
00205     }
00206 
00207     /* draw all the onion boxes.  */
00208     draw_onion(maze, xlocations, ylocations, layers);
00209     make_doors(maze, xlocations, ylocations, layers, option);
00210 }
00211 
00224 void bottom_centered_onion(char **maze, int xsize, int ysize, int option, int layers) {
00225     int i, maxlayers;
00226     float *xlocations;
00227     float *ylocations;
00228 
00229     maxlayers = (MIN(xsize, ysize)-2)/5;
00230     if (!maxlayers)
00231         return; /* map too small to onionize */
00232     if (layers > maxlayers)
00233         layers = maxlayers;
00234     if (layers == 0)
00235         layers = (RANDOM()%maxlayers)+1;
00236     xlocations = (float *)calloc(sizeof(float), 2*layers);
00237     ylocations = (float *)calloc(sizeof(float), 2*layers);
00238 
00239     /* place all the walls */
00240     if (option&OPT_IRR_SPACE) { /* randomly spaced */
00241         int x_spaces_available, y_spaces_available;
00242         /* the "extra" spaces available for spacing between layers */
00243         x_spaces_available = (xsize-2)-6*layers+1;
00244         y_spaces_available = (ysize-2)-3*layers+1;
00245 
00246         /* pick an initial random pitch */
00247         for (i = 0; i < 2*layers; i++) {
00248             float xpitch = 2, ypitch = 2;
00249 
00250             if (x_spaces_available > 0)
00251                 xpitch = 2
00252                     +(RANDOM()%x_spaces_available
00253                     +RANDOM()%x_spaces_available
00254                     +RANDOM()%x_spaces_available)/3;
00255 
00256             if (y_spaces_available > 0)
00257                 ypitch = 2
00258                     +(RANDOM()%y_spaces_available
00259                     +RANDOM()%y_spaces_available
00260                     +RANDOM()%y_spaces_available)/3;
00261             xlocations[i] = ((i > 0) ? xlocations[i-1] : 0)+xpitch;
00262             if (i < layers)
00263                 ylocations[i] = ((i > 0) ? ylocations[i-1] : 0)+ypitch;
00264             else
00265                 ylocations[i] = ysize-1;
00266             x_spaces_available -= xpitch-2;
00267             y_spaces_available -= ypitch-2;
00268         }
00269 
00270     }
00271 
00272     if (!(option&OPT_IRR_SPACE)) {
00273         /* evenly spaced */
00274         float xpitch, ypitch;  /* pitch of the onion layers */
00275 
00276         xpitch = (xsize-2.0)/(2.0*layers+1);
00277         ypitch = (ysize-2.0)/(layers+1);
00278         xlocations[0] = xpitch;
00279         ylocations[0] = ypitch;
00280         for (i = 1; i < 2*layers; i++) {
00281             xlocations[i] = xlocations[i-1]+xpitch;
00282             if (i < layers)
00283                 ylocations[i] = ylocations[i-1]+ypitch;
00284             else
00285                 ylocations[i] = ysize-1;
00286         }
00287     }
00288 
00289     /* draw all the onion boxes.  */
00290     draw_onion(maze, xlocations, ylocations, layers);
00291     make_doors(maze, xlocations, ylocations, layers, option);
00292 }
00293 
00306 void draw_onion(char **maze, float *xlocations, float *ylocations, int layers) {
00307     int i, j, l;
00308 
00309     for (l = 0; l < layers; l++) {
00310         int x1, x2, y1, y2;
00311 
00312         /* horizontal segments */
00313         y1 = (int)ylocations[l];
00314         y2 = (int)ylocations[2*layers-l-1];
00315         for (i = (int)xlocations[l]; i <= (int)xlocations[2*layers-l-1]; i++) {
00316             maze[i][y1] = '#';
00317             maze[i][y2] = '#';
00318         }
00319 
00320         /* vertical segments */
00321         x1 = (int)xlocations[l];
00322         x2 = (int)xlocations[2*layers-l-1];
00323         for (j = (int)ylocations[l]; j <= (int)ylocations[2*layers-l-1]; j++) {
00324             maze[x1][j] = '#';
00325             maze[x2][j] = '#';
00326         }
00327     }
00328 }
00329 
00344 void make_doors(char **maze, float *xlocations, float *ylocations, int layers, int options) {
00345     int freedoms;  /* number of different walls on which we could place a door */
00346     int which_wall; /* left, 1, top, 2, right, 3, bottom 4 */
00347     int l, x1 = 0, x2, y1 = 0, y2;
00348 
00349     freedoms = 4;  /* centered */
00350     if (options&OPT_BOTTOM_C)
00351         freedoms = 3;
00352     if (options&OPT_BOTTOM_R)
00353         freedoms = 2;
00354     if (layers <= 0)
00355         return;
00356 
00357     /* pick which wall will have a door. */
00358     which_wall = RANDOM()%freedoms+1;
00359     for (l = 0; l < layers; l++) {
00360         if (options&OPT_LINEAR) { /* linear door placement. */
00361             switch (which_wall) {
00362             case 1: { /* left hand wall */
00363                 x1 = (int)xlocations[l];
00364                 y1 = (int)((ylocations[l]+ylocations[2*layers-l-1])/2);
00365                 break;
00366                 }
00367 
00368             case 2: { /* top wall placement */
00369                 x1 = (int)((xlocations[l]+xlocations[2*layers-l-1])/2);
00370                 y1 = (int)ylocations[l];
00371                 break;
00372             }
00373 
00374             case 3: { /* right wall placement */
00375                 x1 = (int)xlocations[2*layers-l-1];
00376                 y1 = (int)((ylocations[l]+ylocations[2*layers-l-1])/2);
00377                 break;
00378             }
00379 
00380             case 4: { /* bottom wall placement */
00381                 x1 = (int)((xlocations[l]+xlocations[2*layers-l-1])/2);
00382                 y1 = (int)ylocations[2*layers-l-1];
00383                 break;
00384             }
00385             }
00386         } else { /* random door placement. */
00387             which_wall = RANDOM()%freedoms+1;
00388             switch (which_wall) {
00389             case 1: {  /* left hand wall */
00390                 x1 = (int)xlocations[l];
00391                 y2 = ylocations[2*layers-l-1]-ylocations[l]-1;
00392                 if (y2 > 0)
00393                     y1 = ylocations[l]+RANDOM()%y2+1;
00394                 else
00395                     y1 = ylocations[l]+1;
00396                 break;
00397             }
00398 
00399             case 2: { /* top wall placement */
00400                 x2 = (int)((-xlocations[l]+xlocations[2*layers-l-1]))-1;
00401                 if (x2 > 0)
00402                     x1 = xlocations[l]+RANDOM()%x2+1;
00403                 else
00404                     x1 = xlocations[l]+1;
00405                 y1 = (int)ylocations[l];
00406                 break;
00407             }
00408 
00409             case 3: { /* right wall placement */
00410                 x1 = (int)xlocations[2*layers-l-1];
00411                 y2 = (int)((-ylocations[l]+ylocations[2*layers-l-1]))-1;
00412                 if (y2 > 0)
00413                     y1 = ylocations[l]+RANDOM()%y2+1;
00414                 else
00415                     y1 = ylocations[l]+1;
00416                 break;
00417             }
00418 
00419             case 4: { /* bottom wall placement */
00420                 x2 = (int)((-xlocations[l]+xlocations[2*layers-l-1]))-1;
00421                 if (x2 > 0)
00422                     x1 = xlocations[l]+RANDOM()%x2+1;
00423                 else
00424                     x1 = xlocations[l]+1;
00425                 y1 = (int)ylocations[2*layers-l-1];
00426                 break;
00427             }
00428             }
00429         }
00430 
00431         if (options&OPT_NO_DOORS)
00432             maze[x1][y1] = '#';  /* no door. */
00433         else
00434             maze[x1][y1] = 'D'; /* write the door */
00435     }
00436 
00437     /* mark the center of the maze with a C */
00438     l = layers-1;
00439     x1 = (int)(xlocations[l]+xlocations[2*layers-l-1])/2;
00440     y1 = (int)(ylocations[l]+ylocations[2*layers-l-1])/2;
00441     maze[x1][y1] = 'C';
00442 
00443     /* not needed anymore */
00444     free(xlocations);
00445     free(ylocations);
00446 }
00447 
00460 void bottom_right_centered_onion(char **maze, int xsize, int ysize, int option, int layers) {
00461     int i, maxlayers;
00462     float *xlocations;
00463     float *ylocations;
00464 
00465     maxlayers = (MIN(xsize, ysize)-2)/5;
00466     if (!maxlayers)
00467         return; /* map too small to onionize */
00468     if (layers > maxlayers)
00469         layers = maxlayers;
00470     if (layers == 0)
00471         layers = (RANDOM()%maxlayers)+1;
00472     xlocations = (float *)calloc(sizeof(float), 2*layers);
00473     ylocations = (float *)calloc(sizeof(float), 2*layers);
00474 
00475     /* place all the walls */
00476     if (option&OPT_IRR_SPACE) { /* randomly spaced */
00477         int x_spaces_available, y_spaces_available;
00478         /* the "extra" spaces available for spacing between layers */
00479         x_spaces_available = (xsize-2)-3*layers+1;
00480         y_spaces_available = (ysize-2)-3*layers+1;
00481 
00482         /* pick an initial random pitch */
00483         for (i = 0; i < 2*layers; i++) {
00484             float xpitch = 2, ypitch = 2;
00485 
00486             if (x_spaces_available > 0)
00487                 xpitch = 2
00488                     +(RANDOM()%x_spaces_available
00489                     +RANDOM()%x_spaces_available
00490                     +RANDOM()%x_spaces_available)/3;
00491 
00492             if (y_spaces_available > 0)
00493                 ypitch = 2
00494                     +(RANDOM()%y_spaces_available
00495                     +RANDOM()%y_spaces_available
00496                     +RANDOM()%y_spaces_available)/3;
00497             if (i < layers)
00498                 xlocations[i] = ((i > 0) ? xlocations[i-1] : 0)+xpitch;
00499             else
00500                 xlocations[i] = xsize-1;
00501 
00502             if (i < layers)
00503                 ylocations[i] = ((i > 0) ? ylocations[i-1] : 0)+ypitch;
00504             else
00505                 ylocations[i] = ysize-1;
00506             x_spaces_available -= xpitch-2;
00507             y_spaces_available -= ypitch-2;
00508         }
00509 
00510     }
00511 
00512     if (!(option&OPT_IRR_SPACE)) { /* evenly spaced */
00513         float xpitch, ypitch;  /* pitch of the onion layers */
00514 
00515         xpitch = (xsize-2.0)/(2.0*layers+1);
00516         ypitch = (ysize-2.0)/(layers+1);
00517         xlocations[0] = xpitch;
00518         ylocations[0] = ypitch;
00519         for (i = 1; i < 2*layers; i++) {
00520             if (i < layers)
00521                 xlocations[i] = xlocations[i-1]+xpitch;
00522             else
00523                 xlocations[i] = xsize-1;
00524             if (i < layers)
00525                 ylocations[i] = ylocations[i-1]+ypitch;
00526             else
00527                 ylocations[i] = ysize-1;
00528         }
00529     }
00530 
00531     /* draw all the onion boxes.  */
00532     draw_onion(maze, xlocations, ylocations, layers);
00533     make_doors(maze, xlocations, ylocations, layers, option);
00534 }