Atrinik Server 2.5
random_maps/room_gen_onion.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00052 #include <global.h>
00053 
00054 void centered_onion(char **maze, int xsize, int ysize, int option, int layers);
00055 void bottom_centered_onion(char **maze, int xsize, int ysize, int option, int layers);
00056 void bottom_right_centered_onion(char **maze, int xsize, int ysize, int option, int layers);
00057 void draw_onion(char **maze, float *xlocations, float *ylocations, int layers);
00058 void make_doors(char **maze, float *xlocations, float *ylocations, int layers, int options);
00059 
00067 char **map_gen_onion(int xsize, int ysize, int option, int layers)
00068 {
00069     int i, j;
00070 
00071     /* Allocate that array, set it up */
00072     char **maze = (char **) calloc(sizeof(char *), xsize);
00073 
00074     for (i = 0; i < xsize; i++)
00075     {
00076         maze[i] = (char *) calloc(sizeof(char), ysize);
00077     }
00078 
00079     /* Pick some random options if option = 0 */
00080     if (option == 0)
00081     {
00082         switch (RANDOM() % 3)
00083         {
00084             case 0:
00085                 option |= OPT_CENTERED;
00086                 break;
00087 
00088             case 1:
00089                 option |= OPT_BOTTOM_C;
00090                 break;
00091 
00092             case 2:
00093                 option |= OPT_BOTTOM_R;
00094                 break;
00095         }
00096 
00097         if (RANDOM() % 2)
00098         {
00099             option |= OPT_LINEAR;
00100         }
00101 
00102         if (RANDOM() % 2)
00103         {
00104             option |=OPT_IRR_SPACE;
00105         }
00106     }
00107 
00108     /* Write the outer walls, if appropriate. */
00109     if (!(option & OPT_WALL_OFF))
00110     {
00111         for (i = 0; i < xsize; i++)
00112         {
00113             maze[i][0] = maze[i][ysize - 1] = '#';
00114         }
00115 
00116         for (j = 0; j < ysize; j++)
00117         {
00118             maze[0][j] = maze[xsize - 1][j] = '#';
00119         }
00120     }
00121 
00122     if (option & OPT_WALLS_ONLY)
00123     {
00124         return maze;
00125     }
00126 
00127     /* pick off the mutually exclusive options */
00128     if (option & OPT_BOTTOM_R)
00129     {
00130         bottom_right_centered_onion(maze, xsize, ysize, option, layers);
00131     }
00132     else if (option & OPT_BOTTOM_C)
00133     {
00134         bottom_centered_onion(maze, xsize, ysize, option, layers);
00135     }
00136     else if (option & OPT_CENTERED)
00137     {
00138         centered_onion(maze, xsize, ysize, option, layers);
00139     }
00140 
00141     return maze;
00142 }
00143 
00151 void centered_onion(char **maze, int xsize, int ysize, int option, int layers)
00152 {
00153     int i, maxlayers;
00154     float *xlocations, *ylocations;
00155 
00156     maxlayers = (MIN(xsize, ysize) - 2) / 5;
00157 
00158     /* map too small to onionize */
00159     if (!maxlayers)
00160     {
00161         return;
00162     }
00163 
00164     if (layers > maxlayers)
00165     {
00166         layers = maxlayers;
00167     }
00168 
00169     if (layers == 0)
00170     {
00171         layers = (RANDOM() % maxlayers) + 1;
00172     }
00173 
00174     xlocations = (float *) calloc(sizeof(float), 2 * layers);
00175     ylocations = (float *) calloc(sizeof(float), 2 * layers);
00176 
00177     /* Place all the walls */
00178 
00179     /* Randomly spaced */
00180     if (option & OPT_IRR_SPACE)
00181     {
00182         int x_spaces_available, y_spaces_available;
00183 
00184         /* the "extra" spaces available for spacing between layers */
00185         x_spaces_available = (xsize - 2) - 6 * layers + 1;
00186         y_spaces_available = (ysize - 2) - 6 * layers + 1;
00187 
00188         /* Pick an initial random pitch */
00189         for (i = 0; i < 2 * layers; i++)
00190         {
00191             float xpitch = 2, ypitch = 2;
00192 
00193             if (x_spaces_available > 0)
00194             {
00195                 xpitch = 2.0f + (float) (RANDOM() % x_spaces_available + RANDOM() % x_spaces_available + RANDOM() % x_spaces_available) / 3.0f;
00196             }
00197 
00198             if (y_spaces_available>0)
00199             {
00200                 ypitch = 2.0f + (float) (RANDOM() % y_spaces_available + RANDOM() % y_spaces_available + RANDOM() % y_spaces_available) / 3.0f;
00201             }
00202 
00203             xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
00204             ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
00205 
00206             x_spaces_available -= (int) xpitch - 2;
00207             y_spaces_available -= (int) ypitch - 2;
00208         }
00209     }
00210 
00211     /* evenly spaced */
00212     if (!(option & OPT_IRR_SPACE))
00213     {
00214         /* pitch of the onion layers */
00215         float xpitch, ypitch;
00216 
00217         xpitch = (float) (xsize - 2) / (2.0f * (float) (layers + 1));
00218         ypitch = (float) (ysize - 2) / (2.0f * (float) (layers + 1));
00219 
00220         xlocations[0] = xpitch;
00221         ylocations[0] = ypitch;
00222 
00223         for (i = 1; i < 2 * layers; i++)
00224         {
00225             xlocations[i] = xlocations[i - 1] + xpitch;
00226             ylocations[i] = ylocations[i - 1] + ypitch;
00227         }
00228     }
00229 
00230     /* draw all the onion boxes.  */
00231     draw_onion(maze, xlocations, ylocations, layers);
00232     make_doors(maze, xlocations, ylocations, layers, option);
00233 }
00234 
00242 void bottom_centered_onion(char **maze, int xsize, int ysize, int option, int layers)
00243 {
00244     int i, maxlayers;
00245     float *xlocations, *ylocations;
00246 
00247     maxlayers = (MIN(xsize, ysize) - 2) / 5;
00248 
00249     /* map too small to onionize */
00250     if (!maxlayers)
00251     {
00252         return;
00253     }
00254 
00255     if (layers > maxlayers)
00256     {
00257         layers = maxlayers;
00258     }
00259 
00260     if (layers == 0)
00261     {
00262         layers = (RANDOM() % maxlayers) + 1;
00263     }
00264 
00265     xlocations = (float *) calloc(sizeof(float), 2 * layers);
00266     ylocations = (float *) calloc(sizeof(float), 2 * layers);
00267 
00268     /* place all the walls */
00269 
00270     /* randomly spaced */
00271     if (option & OPT_IRR_SPACE)
00272     {
00273         int x_spaces_available, y_spaces_available;
00274 
00275         /* the "extra" spaces available for spacing between layers */
00276         x_spaces_available = (xsize - 2) - 6 * layers + 1;
00277         y_spaces_available = (ysize - 2) - 3 * layers + 1;
00278 
00279         /* Pick an initial random pitch */
00280         for (i = 0; i < 2 * layers; i++)
00281         {
00282             float xpitch = 2, ypitch = 2;
00283 
00284             if (x_spaces_available > 0)
00285             {
00286                 xpitch = 2.0f + (float) (RANDOM() % x_spaces_available + RANDOM() % x_spaces_available + RANDOM() % x_spaces_available) / 3.0f;
00287             }
00288 
00289             if (y_spaces_available > 0)
00290             {
00291                 ypitch = 2.0f + (float) (RANDOM() % y_spaces_available + RANDOM() % y_spaces_available + RANDOM() % y_spaces_available) / 3.0f;
00292             }
00293 
00294             xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
00295 
00296             if (i < layers)
00297             {
00298                 ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
00299             }
00300             else
00301             {
00302                 ylocations[i] = (float) (ysize - 1);
00303             }
00304 
00305             x_spaces_available -= (int) xpitch - 2;
00306             y_spaces_available -= (int) ypitch - 2;
00307         }
00308     }
00309 
00310     /* evenly spaced */
00311     if (!(option & OPT_IRR_SPACE))
00312     {
00313         /* pitch of the onion layers */
00314         float xpitch, ypitch;
00315 
00316         xpitch = (float) (xsize - 2) / (2.0f * (float) (layers + 1));
00317         ypitch = (float) (ysize - 2) / (float) (layers + 1);
00318 
00319         xlocations[0] = xpitch;
00320         ylocations[0] = ypitch;
00321 
00322         for (i = 1; i < 2 * layers; i++)
00323         {
00324             xlocations[i] = xlocations[i - 1] + xpitch;
00325 
00326             if (i < layers)
00327             {
00328                 ylocations[i] = ylocations[i - 1] + ypitch;
00329             }
00330             else
00331             {
00332                 ylocations[i] = (float) (ysize - 1);
00333             }
00334         }
00335     }
00336 
00337     /* draw all the onion boxes.  */
00338     draw_onion(maze, xlocations, ylocations, layers);
00339     make_doors(maze, xlocations, ylocations, layers, option);
00340 }
00341 
00348 void draw_onion(char **maze, float *xlocations, float *ylocations, int layers)
00349 {
00350     int i, j, l;
00351 
00352     for (l = 0; l < layers; l++)
00353     {
00354         int x1, x2, y1, y2;
00355 
00356         /* horizontal segments */
00357         y1 = (int) ylocations[l];
00358         y2 = (int) ylocations[2 * layers - l - 1];
00359 
00360         for (i = (int) xlocations[l]; i <= (int) xlocations[2 * layers - l - 1]; i++)
00361         {
00362             maze[i][y1] = '#';
00363             maze[i][y2] = '#';
00364         }
00365 
00366         /* vertical segments */
00367         x1 = (int) xlocations[l];
00368         x2 = (int) xlocations[2 * layers - l - 1];
00369 
00370         for (j = (int) ylocations[l]; j <= (int) ylocations[2 * layers - l - 1]; j++)
00371         {
00372             maze[x1][j] = '#';
00373             maze[x2][j] = '#';
00374         }
00375     }
00376 }
00377 
00385 void make_doors(char **maze, float *xlocations, float *ylocations, int layers, int options)
00386 {
00387     /* number of different walls on which we could place a door */
00388     int freedoms;
00389     /* left, 1, top, 2, right, 3, bottom 4 */
00390     int which_wall;
00391     int l, x1 = 0, x2, y1 = 0, y2;
00392 
00393     /* centered */
00394     freedoms = 4;
00395 
00396     if (options & OPT_BOTTOM_C)
00397     {
00398         freedoms = 3;
00399     }
00400 
00401     if (options & OPT_BOTTOM_R)
00402     {
00403         freedoms = 2;
00404     }
00405 
00406     if (layers <= 0)
00407     {
00408         return;
00409     }
00410 
00411     /* Pick which wall will have a door. */
00412     which_wall = RANDOM() % freedoms + 1;
00413 
00414     for (l = 0; l < layers; l++)
00415     {
00416         /* linear door placement. */
00417         if (options & OPT_LINEAR)
00418         {
00419             switch (which_wall)
00420             {
00421                 /* Left hand wall */
00422                 case 1:
00423                     x1 = (int) xlocations[l];
00424                     y1 = (int) ((ylocations[l] + ylocations[2 * layers - l - 1]) / 2);
00425 
00426                     break;
00427 
00428                 /* Top wall placement */
00429                 case 2:
00430                     x1 = (int) ((xlocations[l] + xlocations[2 * layers - l - 1]) / 2);
00431                     y1 = (int) ylocations[l];
00432 
00433                     break;
00434 
00435                 /* Right wall placement */
00436                 case 3:
00437                     x1 = (int) xlocations[2 * layers - l - 1];
00438                     y1 = (int) ((ylocations[l] + ylocations[2 * layers - l - 1]) / 2);
00439 
00440                     break;
00441 
00442                 /* Bottom wall placement */
00443                 case 4:
00444                     x1 = (int) ((xlocations[l] + xlocations[2 * layers - l - 1]) / 2);
00445                     y1 = (int) ylocations[2 * layers - l - 1];
00446 
00447                     break;
00448             }
00449         }
00450         /* random door placement. */
00451         else
00452         {
00453             which_wall = RANDOM() % freedoms + 1;
00454 
00455             switch (which_wall)
00456             {
00457                 /* Left hand wall */
00458                 case 1:
00459                     x1 = (int) xlocations[l];
00460                     y2 = (int) (ylocations[2 * layers - l - 1] - ylocations[l] - 1.0f);
00461 
00462                     if (y2 > 0)
00463                     {
00464                         y1 = (int) ylocations[l] + RANDOM() % y2 + 1;
00465                     }
00466                     else
00467                     {
00468                         y1 = (int) ylocations[l] + 1;
00469                     }
00470 
00471                     break;
00472 
00473                 /* Top wall placement */
00474                 case 2:
00475                     x2 = (int) ((-xlocations[l] + xlocations[2 * layers - l - 1])) - 1;
00476 
00477                     if (x2 > 0)
00478                     {
00479                         x1 = (int) xlocations[l] + RANDOM() % x2 + 1;
00480                     }
00481                     else
00482                     {
00483                         x1 = (int) xlocations[l] + 1;
00484                     }
00485 
00486                     y1 = (int) ylocations[l];
00487 
00488                     break;
00489 
00490                 /* Right wall placement */
00491                 case 3:
00492                     x1 = (int) xlocations[2 * layers - l - 1];
00493                     y2 = (int) ((-ylocations[l] + ylocations[2 * layers - l - 1])) - 1;
00494 
00495                     if (y2 > 0)
00496                     {
00497                         y1 = (int) ylocations[l] + RANDOM() % y2 + 1;
00498                     }
00499                     else
00500                     {
00501                         y1 = (int) ylocations[l] + 1;
00502                     }
00503 
00504                     break;
00505 
00506                 /* Bottom wall placement */
00507                 case 4:
00508                     x2 = (int) ((-xlocations[l] + xlocations[2 * layers - l - 1])) - 1;
00509 
00510                     if (x2 > 0)
00511                     {
00512                         x1 = (int) xlocations[l] + RANDOM() % x2 + 1;
00513                     }
00514                     else
00515                     {
00516                         x1 = (int) xlocations[l] + 1;
00517                     }
00518 
00519                     y1 = (int) ylocations[2 * layers - l - 1];
00520 
00521                     break;
00522             }
00523         }
00524 
00525         if (options & OPT_NO_DOORS)
00526         {
00527             /* no door. */
00528             maze[x1][y1] = '#';
00529         }
00530         else
00531         {
00532             /* write the door */
00533             maze[x1][y1] = 'D';
00534         }
00535     }
00536 
00537     /* mark the center of the maze with a C */
00538     l = layers - 1;
00539     x1 = (int) (xlocations[l] + xlocations[2 * layers - l - 1]) / 2;
00540     y1 = (int) (ylocations[l] + ylocations[2 * layers - l - 1]) / 2;
00541 
00542     maze[x1][y1] = 'C';
00543 
00544     /* Not needed anymore */
00545     free(xlocations);
00546     free(ylocations);
00547 }
00548 
00556 void bottom_right_centered_onion(char **maze, int xsize, int ysize, int option, int layers)
00557 {
00558     int i, maxlayers;
00559     float *xlocations, *ylocations;
00560 
00561     maxlayers = (MIN(xsize, ysize) - 2) / 5;
00562 
00563     /* map too small to onionize */
00564     if (!maxlayers)
00565     {
00566         return;
00567     }
00568 
00569     if (layers > maxlayers)
00570     {
00571         layers = maxlayers;
00572     }
00573 
00574     if (layers == 0)
00575     {
00576         layers = (RANDOM() % maxlayers)+1;
00577     }
00578 
00579     xlocations = (float *) calloc(sizeof(float), 2 * layers);
00580     ylocations = (float *) calloc(sizeof(float), 2 * layers);
00581 
00582     /* place all the walls */
00583 
00584     /* randomly spaced */
00585     if (option & OPT_IRR_SPACE)
00586     {
00587         int x_spaces_available, y_spaces_available;
00588 
00589         /* the "extra" spaces available for spacing between layers */
00590         x_spaces_available = (xsize - 2) - 3 * layers + 1;
00591         y_spaces_available = (ysize - 2) - 3 * layers + 1;
00592 
00593         /* Pick an initial random pitch */
00594         for (i = 0; i < 2 * layers; i++)
00595         {
00596             float xpitch = 2, ypitch = 2;
00597 
00598             if (x_spaces_available>0)
00599             {
00600                 xpitch = 2.0f + (float) (RANDOM() % x_spaces_available + RANDOM() % x_spaces_available + RANDOM() % x_spaces_available) / 3.0f;
00601             }
00602 
00603             if (y_spaces_available > 0)
00604             {
00605                 ypitch = 2.0f + (float) (RANDOM() % y_spaces_available + RANDOM() % y_spaces_available + RANDOM() % y_spaces_available) / 3.0f;
00606             }
00607 
00608             if (i < layers)
00609             {
00610                 xlocations[i] = ((i > 0) ? xlocations[i - 1] : 0) + xpitch;
00611             }
00612             else
00613             {
00614                 xlocations[i] = (float) (xsize - 1);
00615             }
00616 
00617             if (i < layers)
00618             {
00619                 ylocations[i] = ((i > 0) ? ylocations[i - 1] : 0) + ypitch;
00620             }
00621             else
00622             {
00623                 ylocations[i] = (float) (ysize - 1);
00624             }
00625 
00626             x_spaces_available -= (int) xpitch - 2;
00627             y_spaces_available -= (int) ypitch - 2;
00628         }
00629 
00630     }
00631 
00632     /* evenly spaced */
00633     if (!(option & OPT_IRR_SPACE))
00634     {
00635         /* pitch of the onion layers */
00636         float xpitch, ypitch;
00637 
00638         xpitch = (float) (xsize - 2) / (float) (2 * layers + 1);
00639         ypitch = (float) (ysize - 2) / (float) (layers + 1);
00640 
00641         xlocations[0] = xpitch;
00642         ylocations[0] = ypitch;
00643 
00644         for (i = 1; i < 2 * layers; i++)
00645         {
00646             if (i < layers)
00647             {
00648                 xlocations[i] = xlocations[i - 1] + xpitch;
00649             }
00650             else
00651             {
00652                 xlocations[i] = (float) (xsize - 1);
00653             }
00654 
00655             if (i < layers)
00656             {
00657                 ylocations[i] = ylocations[i - 1] + ypitch;
00658             }
00659             else
00660             {
00661                 ylocations[i] = (float) (ysize - 1);
00662             }
00663         }
00664     }
00665 
00666     /* draw all the onion boxes.  */
00667     draw_onion(maze, xlocations, ylocations, layers);
00668     make_doors(maze, xlocations, ylocations, layers, option);
00669 }