Crossfire Server, Branch 1.12
R12190
|
00001 00006 #include <global.h> 00007 #include <random_map.h> 00008 #include <math.h> 00009 00010 typedef struct { 00011 int x; 00012 int y; /* coordinates of room centers */ 00013 00014 int sx; 00015 int sy; /* sizes */ 00016 int ax, ay, zx, zy; /* coordinates of extrema of the rectangle */ 00017 00018 int rtype; /* circle or rectangular */ 00019 } Room; 00020 00021 static int roguelike_place_room(Room *Rooms, int xsize, int ysize, int nrooms); 00022 static void roguelike_make_rooms(Room *Rooms, char **maze, int options); 00023 static void roguelike_link_rooms(Room *Rooms, char **maze, int xsize, int ysize); 00024 00044 int surround_check(char **layout, int i, int j, int Xsize, int Ysize) { 00045 int surround_index = 0; 00046 00047 if ((i > 0) && (layout[i-1][j] != 0 && layout[i-1][j] != '.')) 00048 surround_index += 1; 00049 if ((i < Xsize-1) && (layout[i+1][j] != 0 && layout[i+1][j] != '.')) 00050 surround_index += 2; 00051 if ((j > 0) && (layout[i][j-1] != 0 && layout[i][j-1] != '.')) 00052 surround_index += 4; 00053 if ((j < Ysize-1) && (layout[i][j+1] != 0 && layout[i][j+1] != '.')) 00054 surround_index += 8; 00055 return surround_index; 00056 } 00057 00069 char **roguelike_layout_gen(int xsize, int ysize, int options) { 00070 int i, j; 00071 Room *Rooms = NULL; 00072 Room *walk; 00073 int nrooms = 0; 00074 int tries = 0; 00075 00076 /* allocate that array, write walls everywhere up */ 00077 char **maze = (char **)malloc(sizeof(char *)*xsize); 00078 for (i = 0; i < xsize; i++) { 00079 maze[i] = (char *)malloc(sizeof(char)*ysize); 00080 for (j = 0; j < ysize; j++) 00081 maze[i][j] = '#'; 00082 } 00083 00084 /* minimum room size is basically 5x5: if xsize/ysize is 00085 less than 3x that then hollow things out, stick in 00086 a stairsup and stairs down, and exit */ 00087 00088 if (xsize < 11 || ysize < 11) { 00089 for (i = 1; i < xsize-1; i++) 00090 for (j = 1; j < ysize-1; j++) 00091 maze[i][j] = 0; 00092 maze[(xsize-1)/2][(ysize-1)/2] = '>'; 00093 maze[(xsize-1)/2][(ysize-1)/2+1] = '<'; 00094 return maze; 00095 } 00096 00097 /* decide on the number of rooms */ 00098 nrooms = RANDOM()%10+6; 00099 Rooms = (Room *)calloc(nrooms+1, sizeof(Room)); 00100 00101 /* actually place the rooms */ 00102 i = 0; 00103 while (tries < 450 && i < nrooms) { 00104 /* try to place the room */ 00105 if (!roguelike_place_room(Rooms, xsize, ysize, nrooms)) 00106 tries++; 00107 else 00108 i++; 00109 } 00110 00111 if (i == 0) { /* no can do! */ 00112 for (i = 1; i < xsize-1; i++) 00113 for (j = 1; j < ysize-1; j++) 00114 maze[i][j] = 0; 00115 maze[(xsize-1)/2][(ysize-1)/2] = '>'; 00116 maze[(xsize-1)/2][(ysize-1)/2+1] = '<'; 00117 free(Rooms); 00118 return maze; 00119 } 00120 00121 /* erase the areas occupied by the rooms */ 00122 roguelike_make_rooms(Rooms, maze, options); 00123 00124 roguelike_link_rooms(Rooms, maze, xsize, ysize); 00125 00126 /* put in the stairs */ 00127 00128 maze[Rooms->x][Rooms->y] = '<'; 00129 /* get the last one */ 00130 for (walk = Rooms; walk->x != 0; walk++) 00131 ; 00132 /* back up one */ 00133 walk--; 00134 if (walk == Rooms) { 00135 /* In this case, there is only a single room. We don't want to 00136 * clobber are up exit (above) with a down exit, so put the 00137 * other exit one space up/down, depending which is a space 00138 * and not a wall. 00139 */ 00140 if (maze[walk->x][walk->y+1] == '.') 00141 maze[walk->x][walk->y+1] = '>'; 00142 else 00143 maze[walk->x][walk->y-1] = '>'; 00144 } else 00145 maze[walk->x][walk->y] = '>'; 00146 00147 /* convert all the '.' to 0, we're through with the '.' */ 00148 for (i = 0; i < xsize; i++) 00149 for (j = 0; j < ysize; j++) { 00150 if (maze[i][j] == '.') 00151 maze[i][j] = 0; 00152 if (maze[i][j] == 'D') { /* remove bad door. */ 00153 int si = surround_check(maze, i, j, xsize, ysize); 00154 00155 if (si != 3 && si != 12) { 00156 maze[i][j] = 0; 00157 /* back up and recheck any nearby doors */ 00158 i = 0; 00159 j = 0; 00160 } 00161 } 00162 } 00163 00164 free(Rooms); 00165 return maze; 00166 } 00167 00180 static int roguelike_place_room(Room *Rooms, int xsize, int ysize, int nrooms) { 00181 int tx, ty; /* trial center locations */ 00182 int sx, sy; /* trial sizes */ 00183 int ax, ay; /* min coords of rect */ 00184 int zx, zy; /* max coords of rect */ 00185 int x_basesize; 00186 int y_basesize; 00187 Room *walk; 00188 00189 /* decide on the base x and y sizes */ 00190 00191 x_basesize = xsize/isqrt(nrooms); 00192 y_basesize = ysize/isqrt(nrooms); 00193 00194 00195 tx = RANDOM()%xsize; 00196 ty = RANDOM()%ysize; 00197 00198 /* generate a distribution of sizes centered about basesize */ 00199 sx = (RANDOM()%x_basesize)+(RANDOM()%x_basesize)+(RANDOM()%x_basesize); 00200 sy = (RANDOM()%y_basesize)+(RANDOM()%y_basesize)+(RANDOM()%y_basesize); 00201 sy = (int)(sy*.5); /* renormalize */ 00202 00203 /* find the corners */ 00204 ax = tx-sx/2; 00205 zx = tx+sx/2+sx%2; 00206 00207 ay = ty-sy/2; 00208 zy = ty+sy/2+sy%2; 00209 00210 /* check to see if it's in the map */ 00211 if (zx > xsize-1 || ax < 1) 00212 return 0; 00213 if (zy > ysize-1 || ay < 1) 00214 return 0; 00215 00216 /* no small fish */ 00217 if (sx < 3 || sy < 3) 00218 return 0; 00219 00220 /* check overlap with existing rooms */ 00221 for (walk = Rooms; walk->x != 0; walk++) { 00222 int dx = abs(tx-walk->x); 00223 int dy = abs(ty-walk->y); 00224 00225 if ((dx < (walk->sx+sx)/2+2) && (dy < (walk->sy+sy)/2+2)) 00226 return 0; 00227 } 00228 00229 /* if we've got here, presumably the room is OK. */ 00230 00231 /* get a pointer to the first free room */ 00232 for (walk = Rooms; walk->x != 0; walk++) 00233 ; 00234 walk->x = tx; 00235 walk->y = ty; 00236 walk->sx = sx; 00237 walk->sy = sy; 00238 walk->ax = ax; 00239 walk->ay = ay; 00240 walk->zx = zx; 00241 walk->zy = zy; 00242 return 1; /* success */ 00243 } 00244 00254 static void roguelike_make_rooms(Room *Rooms, char **maze, int options) { 00255 int making_circle = 0; 00256 int i, j; 00257 int R; 00258 Room *walk; 00259 00260 for (walk = Rooms; walk->x != 0; walk++) { 00261 /* first decide what shape to make */ 00262 switch (options) { 00263 case 1: 00264 making_circle = 0; 00265 break; 00266 00267 case 2: 00268 making_circle = 1; 00269 break; 00270 00271 default: 00272 making_circle = ((RANDOM()%3 == 0) ? 1 : 0); 00273 break; 00274 } 00275 00276 if (walk->sx < walk->sy) 00277 R = walk->sx/2; 00278 else 00279 R = walk->sy/2; 00280 00281 /* enscribe a rectangle or a circle */ 00282 for (i = walk->ax; i < walk->zx; i++) 00283 for (j = walk->ay; j < walk->zy; j++) { 00284 if (!making_circle || ((int)(0.5+hypot(walk->x-i, walk->y-j))) <= R) 00285 maze[i][j] = '.'; 00286 } 00287 } 00288 } 00289 00300 static void roguelike_link_rooms(Room *Rooms, char **maze, int xsize, int ysize) { 00301 Room *walk; 00302 int i, j; 00303 00304 /* link each room to the previous room */ 00305 if (Rooms[1].x == 0) 00306 return; /* only 1 room */ 00307 00308 for (walk = Rooms+1; walk->x != 0; walk++) { 00309 int x1 = walk->x; 00310 int y1 = walk->y; 00311 int x2 = (walk-1)->x; 00312 int y2 = (walk-1)->y; 00313 int in_wall = 0; 00314 00315 if (RANDOM()%2) { /* connect in x direction first */ 00316 /* horizontal connect */ 00317 /* swap (x1,y1) (x2,y2) if necessary */ 00318 00319 if (x2 < x1) { 00320 int tx = x2, ty = y2; 00321 x2 = x1; 00322 y2 = y1; 00323 x1 = tx; 00324 y1 = ty; 00325 } 00326 00327 j = y1; 00328 for (i = x1; i < x2; i++) { 00329 if (in_wall == 0 && maze[i][j] == '#') { 00330 in_wall = 1; 00331 maze[i][j] = 'D'; 00332 } else if (in_wall && maze[i][j] == '.') { 00333 in_wall = 0; 00334 maze[i-1][j] = 'D'; 00335 } else if (maze[i][j] != 'D' && maze[i][j] != '.') 00336 maze[i][j] = 0; 00337 } 00338 j = MIN(y1, y2); 00339 if (maze[i][j] == '.') 00340 in_wall = 0; 00341 if (maze[i][j] == 0 || maze[i][j] == '#') 00342 in_wall = 1; 00343 for (/* j set already */; j < MAX(y1, y2); j++) { 00344 if (in_wall == 0 && maze[i][j] == '#') { 00345 in_wall = 1; 00346 maze[i][j] = 'D'; 00347 } else if (in_wall && maze[i][j] == '.') { 00348 in_wall = 0; 00349 maze[i][j-1] = 'D'; 00350 } else if (maze[i][j] != 'D' && maze[i][j] != '.') 00351 maze[i][j] = 0; 00352 } 00353 } else { /* connect in y direction first */ 00354 in_wall = 0; 00355 /* swap if necessary */ 00356 if (y2 < y1) { 00357 int tx = x2, ty = y2; 00358 x2 = x1; 00359 y2 = y1; 00360 x1 = tx; 00361 y1 = ty; 00362 } 00363 i = x1; 00364 /* vertical connect */ 00365 for (j = y1; j < y2; j++) { 00366 if (in_wall == 0 && maze[i][j] == '#') { 00367 in_wall = 1; 00368 maze[i][j] = 'D'; 00369 } else if (in_wall && maze[i][j] == '.') { 00370 in_wall = 0; 00371 maze[i][j-1] = 'D'; 00372 } else if (maze[i][j] != 'D' && maze[i][j] != '.') 00373 maze[i][j] = 0; 00374 } 00375 00376 i = MIN(x1, x2); 00377 if (maze[i][j] == '.') 00378 in_wall = 0; 00379 if (maze[i][j] == 0 || maze[i][j] == '#') 00380 in_wall = 1; 00381 for (/* i set already */; i < MAX(x1, x2); i++) { 00382 if (in_wall == 0 && maze[i][j] == '#') { 00383 in_wall = 1; 00384 maze[i][j] = 'D'; 00385 } else if (in_wall && maze[i][j] == '.') { 00386 in_wall = 0; 00387 maze[i-1][j] = 'D'; 00388 } else 00389 if (maze[i][j] != 'D' && maze[i][j] != '.') 00390 maze[i][j] = 0; 00391 00392 } 00393 } 00394 } 00395 }