|
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 00037 static int pointer_strcmp(const void *p1, const void *p2) 00038 { 00039 const char *s1 = *(const char * const *) p1; 00040 const char *s2 = *(const char * const *) p2; 00041 00042 return (strcmp(s1, s2)); 00043 } 00044 00060 int load_dir(const char *dir, char ***namelist, int skip_dirs) 00061 { 00062 DIR *dp; 00063 struct dirent *d; 00064 int entries = 0, entry_size = 0; 00065 char name[NAME_MAX + 1], **rn = NULL; 00066 struct stat sb; 00067 00068 dp = opendir(dir); 00069 00070 if (dp == NULL) 00071 { 00072 return -1; 00073 } 00074 00075 while ((d = readdir(dp)) != NULL) 00076 { 00077 if (skip_dirs) 00078 { 00079 snprintf(name, sizeof(name), "%s/%s", dir, d->d_name); 00080 stat(name, &sb); 00081 00082 if (S_ISDIR(sb.st_mode)) 00083 { 00084 continue; 00085 } 00086 } 00087 00088 if (entries == entry_size) 00089 { 00090 entry_size += 10; 00091 rn = realloc(rn, sizeof(char *) * entry_size); 00092 } 00093 00094 rn[entries] = strdup_local(d->d_name); 00095 entries++; 00096 } 00097 00098 closedir(dp); 00099 00100 qsort(rn, entries, sizeof(char *), pointer_strcmp); 00101 00102 *namelist = rn; 00103 00104 return entries; 00105 } 00106 00109 mapstruct *styles = NULL; 00110 00115 mapstruct *load_style_map(char *style_name) 00116 { 00117 mapstruct *style_map; 00118 00119 /* Given a file. See if its in memory */ 00120 for (style_map = styles; style_map != NULL; style_map = style_map->next) 00121 { 00122 if (!strcmp(style_name, style_map->path)) 00123 { 00124 return style_map; 00125 } 00126 } 00127 00128 style_map = load_original_map(style_name, MAP_STYLE); 00129 00130 /* Remove it from global list, put it on our local list */ 00131 if (style_map) 00132 { 00133 mapstruct *tmp; 00134 00135 if (style_map == first_map) 00136 { 00137 first_map = style_map->next; 00138 } 00139 else 00140 { 00141 for (tmp = first_map; tmp && tmp->next != style_map; tmp = tmp->next) 00142 { 00143 } 00144 00145 if (tmp) 00146 { 00147 tmp->next = style_map->next; 00148 } 00149 } 00150 00151 style_map->next = styles; 00152 styles = style_map; 00153 } 00154 00155 return style_map; 00156 } 00157 00174 mapstruct *find_style(char *dirname, char *stylename, int difficulty) 00175 { 00176 char style_file_path[256], style_file_full_path[256]; 00177 mapstruct *style_map = NULL; 00178 struct stat file_stat; 00179 int i; 00180 00181 /* If stylename exists, set style_file_path to that file.*/ 00182 if (stylename && strlen(stylename) > 0) 00183 { 00184 snprintf(style_file_path, sizeof(style_file_path), "%s/%s", dirname, stylename); 00185 } 00186 /* Otherwise, just use the dirname. We'll pick a random stylefile.*/ 00187 else 00188 { 00189 snprintf(style_file_path, sizeof(style_file_path), "%s", dirname); 00190 } 00191 00192 /* Is what we were given a directory, or a file? */ 00193 snprintf(style_file_full_path, sizeof(style_file_full_path), "%s/%s", MAPDIR, style_file_path); 00194 00195 stat(style_file_full_path, &file_stat); 00196 00197 if (!(S_ISDIR(file_stat.st_mode))) 00198 { 00199 style_map = load_style_map(style_file_path); 00200 } 00201 00202 /* Maybe we were given a directory! */ 00203 if (style_map == NULL) 00204 { 00205 char **namelist; 00206 int n, only_subdirs = 0; 00207 char style_dir_full_path[256]; 00208 00209 /* Get the names of all the files in that directory */ 00210 snprintf(style_dir_full_path, sizeof(style_dir_full_path), "%s/%s", MAPDIR, style_file_path); 00211 00212 /* First, skip subdirectories. If we don't find anything, then try again 00213 * without skipping subdirs. */ 00214 n = load_dir(style_dir_full_path, &namelist, 1); 00215 00216 if (n <= 0) 00217 { 00218 n = load_dir(style_dir_full_path, &namelist, 0); 00219 only_subdirs = 1; 00220 } 00221 00222 /* Nothing to load. Bye. */ 00223 if (n <= 0) 00224 { 00225 return 0; 00226 } 00227 00228 /* pick a random style from this dir. */ 00229 if (difficulty == -1) 00230 { 00231 if (only_subdirs) 00232 { 00233 style_map = NULL; 00234 } 00235 else 00236 { 00237 strcat(style_file_path, "/"); 00238 strcat(style_file_path, namelist[RANDOM() % n]); 00239 00240 style_map = load_style_map(style_file_path); 00241 } 00242 } 00243 /* find the map closest in difficulty */ 00244 else 00245 { 00246 int min_dist = 32000, min_index = -1; 00247 00248 for (i = 0; i < n; i++) 00249 { 00250 int dist; 00251 char *mfile_name = strrchr(namelist[i], '_') + 1; 00252 00253 /* since there isn't a sequence, pick one at random to recurse */ 00254 if ((mfile_name - 1) == NULL) 00255 { 00256 int q; 00257 00258 style_map = find_style(style_file_path, namelist[RANDOM() % n], difficulty); 00259 00260 for (q = 0; q < n; q++) 00261 { 00262 free(namelist[q]); 00263 } 00264 00265 free(namelist); 00266 00267 return style_map; 00268 } 00269 else 00270 { 00271 dist = abs(difficulty - atoi(mfile_name)); 00272 00273 if (dist < min_dist) 00274 { 00275 min_dist = dist; 00276 min_index = i; 00277 } 00278 } 00279 } 00280 00281 /* presumably now we've found the "best" match for the 00282 * difficulty. */ 00283 strcat(style_file_path, "/"); 00284 strcat(style_file_path, namelist[min_index]); 00285 00286 style_map = load_style_map(style_file_path); 00287 } 00288 00289 for (i = 0; i < n; i++) 00290 { 00291 free(namelist[i]); 00292 } 00293 00294 free(namelist); 00295 } 00296 00297 return style_map; 00298 00299 } 00300 00305 object *pick_random_object(mapstruct *style) 00306 { 00307 int x, y, i; 00308 object *new_obj; 00309 00310 /* If someone makes a style map that is empty, this will loop forever, 00311 * but the callers will crash if we return a NULL object, so either 00312 * way is not good. */ 00313 do 00314 { 00315 i = RANDOM () % (MAP_WIDTH(style) * MAP_HEIGHT(style)); 00316 00317 x = i / MAP_HEIGHT(style); 00318 y = i % MAP_HEIGHT(style); 00319 new_obj = get_map_ob(style, x, y); 00320 } 00321 while (new_obj == NULL); 00322 00323 if (new_obj->head) 00324 { 00325 return new_obj->head; 00326 } 00327 else 00328 { 00329 return new_obj; 00330 } 00331 } 00332 00335 void free_style_maps() 00336 { 00337 mapstruct *next; 00338 int style_maps = 0; 00339 00340 /* delete_map will try to free it from the linked list, 00341 * but won't find it, so we need to do it ourselves */ 00342 while (styles) 00343 { 00344 next = styles->next; 00345 delete_map(styles); 00346 styles = next; 00347 style_maps++; 00348 } 00349 00350 LOG(llevDebug, "free_style_maps: Freed %d maps\n", style_maps); 00351 }
1.7.4