Crossfire Server, Branch 1.12
R12190
|
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 }