Atrinik Server 2.5
random_maps/style.c
Go to the documentation of this file.
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 }