|
Atrinik Server 2.5
|
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 00030 #include <global.h> 00031 #include <math.h> 00032 00033 typedef struct 00034 { 00035 /* coordinates of room centers */ 00036 int x; 00037 int y; 00038 00039 /* sizes */ 00040 int sx; 00041 int sy; 00042 00043 /* coordinates of extrema of the rectangle */ 00044 int ax,ay,zx,zy; 00045 00046 /* Circle or rectangular */ 00047 int rtype; 00048 } Room; 00049 00050 static int roguelike_place_room(Room *Rooms, int xsize, int ysize, int nrooms); 00051 static void roguelike_make_rooms(Room *Rooms, char **maze, int options); 00052 static void roguelike_link_rooms(Room *Rooms, char **maze); 00053 00066 int surround_check(char **layout, int i, int j, int Xsize, int Ysize) 00067 { 00068 int surround_index = 0; 00069 00070 if ((i > 0) && (layout[i - 1][j] != 0 && layout[i - 1][j] != '.')) 00071 { 00072 surround_index += 1; 00073 } 00074 00075 if ((i < Xsize - 1) && (layout[i + 1][j] != 0 && layout[i + 1][j] != '.')) 00076 { 00077 surround_index += 2; 00078 } 00079 00080 if ((j > 0) && (layout[i][j - 1] != 0 && layout[i][j - 1] != '.')) 00081 { 00082 surround_index += 4; 00083 } 00084 00085 if ((j < Ysize - 1) && (layout[i][j + 1] != 0 && layout[i][j + 1] != '.')) 00086 { 00087 surround_index += 8; 00088 } 00089 00090 return surround_index; 00091 } 00092 00102 char **roguelike_layout_gen(int xsize, int ysize, int options) 00103 { 00104 int i, j = 0; 00105 Room *Rooms = NULL, *walk; 00106 int nrooms = 0; 00107 int tries = 0; 00108 00109 /* Allocate that array, write walls everywhere up */ 00110 char **maze = (char **) malloc(sizeof(char *) * xsize); 00111 00112 for (i = 0; i < xsize; i++) 00113 { 00114 maze[i] = (char *) malloc(sizeof(char) * ysize); 00115 00116 for (j = 0; j < ysize; j++) 00117 { 00118 maze[i][j] = '#'; 00119 } 00120 } 00121 00122 /* minimum room size is basically 5x5: if xsize/ysize is 00123 less than 3x that then hollow things out, stick in 00124 a stairsup and stairs down, and exit */ 00125 if (xsize < 11 || ysize < 11) 00126 { 00127 for (i = 1; i < xsize - 1; i++) 00128 { 00129 for (j = 1; j < ysize - 1; j++) 00130 { 00131 maze[i][j] = 0; 00132 } 00133 } 00134 00135 maze[i / 2][j / 2]= '>'; 00136 maze[i / 2][j / 2 + 1] = '<'; 00137 00138 return maze; 00139 } 00140 00141 /* decide on the number of rooms */ 00142 nrooms = RANDOM() % 10 + 6; 00143 Rooms = (Room *) calloc(nrooms + 1 , sizeof(Room)); 00144 00145 /* Actually place the rooms */ 00146 i = 0; 00147 00148 while (tries < 450 && i < nrooms) 00149 { 00150 /* Try to place the room */ 00151 if (!roguelike_place_room(Rooms, xsize, ysize, nrooms)) 00152 { 00153 tries++; 00154 } 00155 else 00156 { 00157 i++; 00158 } 00159 } 00160 00161 /* no can do! */ 00162 if (i == 0) 00163 { 00164 for (i = 1; i < xsize - 1; i++) 00165 { 00166 for (j = 1; j < ysize - 1; j++) 00167 { 00168 maze[i][j] = 0; 00169 } 00170 } 00171 00172 maze[i / 2][j / 2] = '>'; 00173 maze[i / 2][j / 2 + 1] = '<'; 00174 free(Rooms); 00175 00176 return maze; 00177 } 00178 00179 /* Erase the areas occupied by the rooms */ 00180 roguelike_make_rooms(Rooms, maze, options); 00181 00182 roguelike_link_rooms(Rooms, maze); 00183 00184 /* Put in the stairs */ 00185 maze[Rooms->x][Rooms->y] = '<'; 00186 00187 /* Get the last one */ 00188 for (walk = Rooms; walk->x != 0; walk++) 00189 { 00190 } 00191 00192 /* Back up one */ 00193 walk--; 00194 00195 maze[walk->x][walk->y] = '>'; 00196 00197 /* convert all the '.' to 0, we're through with the '.' */ 00198 for (i = 0; i < xsize; i++) 00199 { 00200 for (j = 0; j < ysize; j++) 00201 { 00202 if (maze[i][j] == '.') 00203 { 00204 maze[i][j] = 0; 00205 } 00206 00207 /* Remove bad door. */ 00208 if (maze[i][j] == 'D') 00209 { 00210 int si = surround_check(maze, i, j, xsize, ysize); 00211 00212 if (si != 3 && si != 12) 00213 { 00214 maze[i][j] = 0; 00215 00216 /* back up and recheck any nearby doors */ 00217 i = 0; 00218 j = 0; 00219 } 00220 } 00221 } 00222 } 00223 00224 free(Rooms); 00225 00226 return maze; 00227 } 00228 00236 static int roguelike_place_room(Room *Rooms, int xsize, int ysize, int nrooms) 00237 { 00238 /* trial center locations */ 00239 int tx, ty; 00240 /* trial sizes */ 00241 int sx, sy; 00242 /* min coords of rect */ 00243 int ax, ay; 00244 /* max coords of rect */ 00245 int zx, zy; 00246 int x_basesize, y_basesize; 00247 Room *walk; 00248 00249 /* Decide on the base x and y sizes */ 00250 x_basesize = (int) (xsize / sqrt(nrooms)); 00251 y_basesize = (int) (ysize / sqrt(nrooms)); 00252 00253 tx = RANDOM() % xsize; 00254 ty = RANDOM() % ysize; 00255 00256 /* Generate a distribution of sizes centered about basesize */ 00257 sx = (RANDOM() % x_basesize) + (RANDOM() % x_basesize)+ (RANDOM() % x_basesize); 00258 sy = (RANDOM() % y_basesize) + (RANDOM() % y_basesize)+ (RANDOM() % y_basesize); 00259 00260 /* Renormalize */ 00261 sy = (int) (sy * 0.5); 00262 00263 /* Find the corners */ 00264 ax = tx - sx / 2; 00265 zx = tx + sx / 2 + sx % 2; 00266 00267 ay = ty - sy / 2; 00268 zy = ty + sy / 2 + sy % 2; 00269 00270 /* Check to see if it's in the map */ 00271 if (zx > xsize - 1 || ax < 1) 00272 { 00273 return 0; 00274 } 00275 00276 if (zy > ysize - 1 || ay < 1) 00277 { 00278 return 0; 00279 } 00280 00281 /* No small fish */ 00282 if (sx < 3 || sy < 3) 00283 { 00284 return 0; 00285 } 00286 00287 /* Check overlap with existing rooms */ 00288 for (walk = Rooms; walk->x != 0; walk++) 00289 { 00290 int dx = abs(tx - walk->x), dy = abs(ty - walk->y); 00291 00292 if ((dx < (walk->sx + sx) / 2 + 2) && (dy < (walk->sy + sy) / 2 + 2)) 00293 { 00294 return 0; 00295 } 00296 } 00297 00298 /* If we've got here, presumably the room is OK. */ 00299 00300 /* Get a pointer to the first free room */ 00301 for (walk = Rooms; walk->x != 0; walk++) 00302 { 00303 } 00304 00305 walk->x = tx; 00306 walk->y = ty; 00307 walk->sx = sx; 00308 walk->sy = sy; 00309 walk->ax = ax; 00310 walk->ay = ay; 00311 walk->zx = zx; 00312 walk->zy = zy; 00313 00314 /* success */ 00315 return 1; 00316 } 00317 00324 static void roguelike_make_rooms(Room *Rooms, char **maze, int options) 00325 { 00326 int making_circle = 0, i, j, R = 0; 00327 Room *walk; 00328 00329 for (walk = Rooms; walk->x != 0; walk++) 00330 { 00331 /* First decide what shape to make */ 00332 switch (options) 00333 { 00334 case 1: 00335 making_circle = 0; 00336 break; 00337 00338 case 2: 00339 making_circle = 1; 00340 break; 00341 00342 default: 00343 making_circle = ((RANDOM() % 3 == 0) ? 1 : 0); 00344 00345 if (walk->sx < walk->sy) 00346 { 00347 R = walk->sx / 2; 00348 } 00349 else 00350 { 00351 R = walk->sy / 2; 00352 } 00353 } 00354 00355 /* Enscribe a rectangle */ 00356 for (i = walk->ax; i < walk->zx; i++) 00357 { 00358 for (j = walk->ay; j < walk->zy; j++) 00359 { 00360 if (!making_circle || ((int) (0.5 + hypot(walk->x - i, walk->y - j))) <= R) 00361 { 00362 maze[i][j] = '.'; 00363 } 00364 } 00365 } 00366 } 00367 } 00368 00375 static void roguelike_link_rooms(Room *Rooms, char **maze) 00376 { 00377 Room *walk; 00378 int i, j; 00379 00380 /* Link each room to the previous room */ 00381 if (Rooms[1].x == 0) 00382 { 00383 /* only 1 room */ 00384 return; 00385 } 00386 00387 for (walk = Rooms + 1; walk->x != 0; walk++) 00388 { 00389 int x = walk->x, y = walk->y, x2 = (walk - 1)->x, y2 = (walk - 1)->y, in_wall = 0; 00390 00391 /* Connect in x direction first */ 00392 if (RANDOM() % 2) 00393 { 00394 /* horizontal connect */ 00395 /* swap (x1, y1) (x2, y2) if necessary */ 00396 if (x2 < x) 00397 { 00398 int tx = x2, ty = y2; 00399 00400 x2 = x; 00401 y2 = y; 00402 x = tx; 00403 y = ty; 00404 } 00405 00406 j = y; 00407 00408 for (i = x; i < x2; i++) 00409 { 00410 if (in_wall == 0 && maze[i][j] == '#') 00411 { 00412 in_wall = 1; 00413 maze[i][j] = 'D'; 00414 } 00415 else if (in_wall && maze[i][j] == '.') 00416 { 00417 in_wall = 0; 00418 maze[i - 1][j] = 'D'; 00419 } 00420 else if (maze[i][j] != 'D' && maze[i][j] != '.') 00421 { 00422 maze[i][j] = 0; 00423 } 00424 } 00425 00426 j = MIN(y, y2); 00427 00428 if (maze[i][j] == '.') 00429 { 00430 in_wall = 0; 00431 } 00432 00433 if (maze[i][j] == 0 || maze[i][j] == '#') 00434 { 00435 in_wall = 1; 00436 } 00437 00438 for ( ; j < MAX(y, y2); j++) 00439 { 00440 if (in_wall == 0 && maze[i][j] == '#') 00441 { 00442 in_wall = 1; 00443 maze[i][j] = 'D'; 00444 } 00445 else if (in_wall && maze[i][j] == '.') 00446 { 00447 in_wall = 0; 00448 maze[i][j - 1] = 'D'; 00449 } 00450 else if (maze[i][j] != 'D' && maze[i][j] != '.') 00451 { 00452 maze[i][j] = 0; 00453 } 00454 } 00455 } 00456 /* Connect in y direction first */ 00457 else 00458 { 00459 in_wall = 0; 00460 00461 /* Swap if necessary */ 00462 if (y2 < y) 00463 { 00464 int tx = x2, ty = y2; 00465 00466 x2 = x; 00467 y2 = y; 00468 x = tx; 00469 y = ty; 00470 } 00471 00472 i = x; 00473 00474 /* vertical connect */ 00475 for (j = y; j < y2; j++) 00476 { 00477 if (in_wall == 0 && maze[i][j] == '#') 00478 { 00479 in_wall = 1; 00480 maze[i][j] = 'D'; 00481 } 00482 else if (in_wall && maze[i][j] == '.') 00483 { 00484 in_wall = 0; 00485 maze[i][j - 1] = 'D'; 00486 } 00487 else if (maze[i][j] != 'D' && maze[i][j] != '.') 00488 { 00489 maze[i][j] = 0; 00490 } 00491 } 00492 00493 i = MIN(x, x2); 00494 00495 if (maze[i][j] == '.') 00496 { 00497 in_wall = 0; 00498 } 00499 00500 if (maze[i][j] == 0 || maze[i][j] == '#') 00501 { 00502 in_wall = 1; 00503 } 00504 00505 for ( ; i < MAX(x, x2); i++) 00506 { 00507 if (in_wall == 0 && maze[i][j] == '#') 00508 { 00509 in_wall = 1; 00510 maze[i][j] = 'D'; 00511 } 00512 else if (in_wall && maze[i][j] == '.') 00513 { 00514 in_wall = 0; 00515 maze[i - 1][j] = 'D'; 00516 } 00517 else if (maze[i][j] != 'D' && maze[i][j] != '.') 00518 { 00519 maze[i][j] = 0; 00520 } 00521 } 00522 } 00523 } 00524 }
1.7.4