Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_style_c = 00003 * "$Id: style.c 11578 2009-02-23 22:02:27Z lalo $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2002 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 00036 #include <global.h> 00037 #include <random_map.h> 00038 #ifndef WIN32 /* ---win32 exclude headers */ 00039 #include <dirent.h> 00040 #include <sys/stat.h> 00041 #include <unistd.h> 00042 #include "../include/autoconf.h" 00043 #endif /* win32 */ 00044 00053 static int pointer_strcmp(const void *p1, const void *p2) { 00054 const char *s1 = *(const char * const *)p1; 00055 const char *s2 = *(const char * const *)p2; 00056 00057 return(strcmp(s1, s2)); 00058 } 00059 00083 int load_dir(const char *dir, char ***namelist, int skip_dirs) { 00084 DIR *dp; 00085 struct dirent *d; 00086 int entries = 0, entry_size = 0; 00087 char name[NAME_MAX+1], **rn = NULL; 00088 struct stat sb; 00089 00090 dp = opendir(dir); 00091 if (dp == NULL) 00092 return -1; 00093 00094 while ((d = readdir(dp)) != NULL) { 00095 if (skip_dirs) { 00096 snprintf(name, sizeof(name), "%s/%s", dir, d->d_name); 00097 stat(name, &sb); 00098 if (S_ISDIR(sb.st_mode)) { 00099 continue; 00100 } 00101 } 00102 00103 if (entries == entry_size) { 00104 entry_size += 10; 00105 rn = realloc(rn, sizeof(char *)*entry_size); 00106 } 00107 rn[entries] = strdup_local(d->d_name); 00108 entries++; 00109 00110 } 00111 (void)closedir(dp); 00112 00113 qsort(rn, entries, sizeof(char *), pointer_strcmp); 00114 00115 *namelist = rn; 00116 return entries; 00117 } 00118 00122 mapstruct *styles = NULL; 00123 00131 mapstruct *load_style_map(char *style_name) { 00132 mapstruct *style_map; 00133 00134 /* Given a file. See if its in memory */ 00135 for (style_map = styles; style_map != NULL; style_map = style_map->next) { 00136 if (!strcmp(style_name, style_map->path)) 00137 return style_map; 00138 } 00139 style_map = load_original_map(style_name, MAP_STYLE); 00140 /* Remove it from global list, put it on our local list */ 00141 if (style_map) { 00142 mapstruct *tmp; 00143 00144 if (style_map == first_map) 00145 first_map = style_map->next; 00146 else { 00147 for (tmp = first_map; tmp && tmp->next != style_map; tmp = tmp->next) 00148 ; 00149 if (tmp) 00150 tmp->next = style_map->next; 00151 } 00152 style_map->next = styles; 00153 styles = style_map; 00154 } 00155 return style_map; 00156 } 00157 00177 mapstruct *find_style(const char *dirname, const char *stylename, int difficulty) { 00178 char style_file_path[256]; 00179 char style_file_full_path[256]; 00180 mapstruct *style_map = NULL; 00181 struct stat file_stat; 00182 int i, only_subdirs = 0; 00183 00184 /* if stylename exists, set style_file_path to that file.*/ 00185 if (stylename && strlen(stylename) > 0) 00186 snprintf(style_file_path, sizeof(style_file_path), "%s/%s", dirname, stylename); 00187 else /* otherwise, just use the dirname. We'll pick a random stylefile.*/ 00188 snprintf(style_file_path, sizeof(style_file_path), "%s", dirname); 00189 00190 /* is what we were given a directory, or a file? */ 00191 snprintf(style_file_full_path, sizeof(style_file_full_path), "%s/maps%s", settings.datadir, style_file_path); 00192 if (stat(style_file_full_path, &file_stat) == 0 00193 && !S_ISDIR(file_stat.st_mode)) { 00194 style_map = load_style_map(style_file_path); 00195 } 00196 if (style_map == NULL) { /* maybe we were given a directory! */ 00197 char **namelist; 00198 int n; 00199 char style_dir_full_path[256]; 00200 00201 /* get the names of all the files in that directory */ 00202 snprintf(style_dir_full_path, sizeof(style_dir_full_path), "%s/maps%s", settings.datadir, style_file_path); 00203 00204 /* First, skip subdirectories. If we don't find anything, then try again 00205 * without skipping subdirs. 00206 */ 00207 n = load_dir(style_dir_full_path, &namelist, 1); 00208 if (n <= 0) { 00209 n = load_dir(style_dir_full_path, &namelist, 0); 00210 only_subdirs = 1; 00211 } 00212 00213 if (n <= 0) 00214 return NULL; /* nothing to load. Bye. */ 00215 00216 /* Picks a random map. Note that if this is all directories, 00217 * we know it won't be able to load, so save a few ticks. 00218 * the door handling checks for this failure and handles 00219 * it properly. 00220 */ 00221 if (difficulty == -1) { /* pick a random style from this dir. */ 00222 if (only_subdirs) 00223 style_map = NULL; 00224 else { 00225 strncat(style_file_path, "/", sizeof(style_file_path)); 00226 strncat(style_file_path, namelist[RANDOM()%n], sizeof(style_file_path)); 00227 style_map = load_style_map(style_file_path); 00228 } 00229 } else { /* find the map closest in difficulty */ 00230 int min_dist = 32000, min_index = -1; 00231 00232 for (i = 0; i < n; i++) { 00233 int dist; 00234 char *mfile_name = strrchr(namelist[i], '_')+1; 00235 00236 if ((mfile_name-1) == NULL) { /* since there isn't a sequence, */ 00237 int q; 00238 00239 /*pick one at random to recurse */ 00240 style_map = find_style(style_file_path, namelist[RANDOM()%n], difficulty); 00241 for (q = 0; q < n; q++) 00242 free(namelist[q]); 00243 free(namelist); 00244 return style_map; 00245 } else { 00246 dist = abs(difficulty-atoi(mfile_name)); 00247 if (dist < min_dist) { 00248 min_dist = dist; 00249 min_index = i; 00250 } 00251 } 00252 } 00253 /* presumably now we've found the "best" match for the 00254 difficulty. */ 00255 strncat(style_file_path, "/", sizeof(style_file_path)); 00256 strncat(style_file_path, namelist[min_index], sizeof(style_file_path)); 00257 style_map = load_style_map(style_file_path); 00258 } 00259 for (i = 0; i < n; i++) 00260 free(namelist[i]); 00261 free(namelist); 00262 } 00263 return style_map; 00264 } 00265 00275 object *pick_random_object(mapstruct *style) { 00276 int x, y, limit = 0; 00277 object *new_obj; 00278 00279 /* while returning a null object will result in a crash, that 00280 * is actually preferable to an infinite loop. That is because 00281 * most servers will automatically restart in case of crash. 00282 * Change the logic on getting the random space - shouldn't make 00283 * any difference, but this seems clearer to me. 00284 */ 00285 do { 00286 limit++; 00287 x = RANDOM()%MAP_WIDTH(style); 00288 y = RANDOM()%MAP_HEIGHT(style); 00289 new_obj = GET_MAP_OB(style, x, y); 00290 } while (new_obj == NULL && limit < 1000); 00291 if (new_obj->head) 00292 return new_obj->head; 00293 else 00294 return new_obj; 00295 } 00296 00300 void free_style_maps(void) { 00301 mapstruct *next; 00302 int style_maps = 0; 00303 00304 /* delete_map will try to free it from the linked list, 00305 * but won't find it, so we need to do it ourselves 00306 */ 00307 while (styles) { 00308 next = styles->next; 00309 delete_map(styles); 00310 styles = next; 00311 style_maps++; 00312 } 00313 LOG(llevDebug, "free_style_maps: Freed %d maps\n", style_maps); 00314 }