Atrinik Server  4.0
style.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
30 #include <global.h>
31 #include <toolkit/string.h>
32 #include <object.h>
33 
43 static int pointer_strcmp(const void *p1, const void *p2)
44 {
45  const char *s1 = *(const char * const *) p1;
46  const char *s2 = *(const char * const *) p2;
47 
48  return (strcmp(s1, s2));
49 }
50 
71 int load_dir(const char *dir, char ***namelist, int skip_dirs)
72 {
73  DIR *dp;
74  struct dirent *d;
75  int entries = 0, entry_size = 0;
76  char name[NAME_MAX + 1], **rn = NULL;
77  struct stat sb;
78 
79  dp = opendir(dir);
80 
81  if (dp == NULL) {
82  return -1;
83  }
84 
85  while ((d = readdir(dp)) != NULL) {
86  if (skip_dirs) {
87  snprintf(name, sizeof(name), "%s/%s", dir, d->d_name);
88 
89  if (stat(name, &sb) == 0 && S_ISDIR(sb.st_mode)) {
90  continue;
91  }
92  }
93 
94  if (entries == entry_size) {
95  entry_size += 10;
96  rn = erealloc(rn, sizeof(char *) * entry_size);
97  }
98 
99  rn[entries] = estrdup(d->d_name);
100  entries++;
101  }
102 
103  closedir(dp);
104 
105  qsort(rn, entries, sizeof(char *), pointer_strcmp);
106 
107  *namelist = rn;
108 
109  return entries;
110 }
111 
116 
124 mapstruct *load_style_map(char *style_name)
125 {
126  mapstruct *style_map;
127 
128  /* Given a file. See if its in memory */
129  DL_FOREACH(styles, style_map)
130  {
131  if (!strcmp(style_name, style_map->path)) {
132  return style_map;
133  }
134  }
135 
136  style_map = load_original_map(style_name, NULL, MAP_STYLE);
137 
138  /* Remove it from global list, put it on our local list */
139  if (style_map != NULL) {
140  DL_DELETE(first_map, style_map);
141  style_map->global_removed = true;
142  DL_APPEND(styles, style_map);
143  }
144 
145  return style_map;
146 }
147 
169 mapstruct *find_style(const char *dirname, const char *stylename, int difficulty)
170 {
171  char style_file_path[256], style_file_full_path[256];
172  mapstruct *style_map = NULL;
173  struct stat file_stat;
174  int i;
175 
176  /* If stylename exists, set style_file_path to that file.*/
177  if (stylename && strlen(stylename) > 0) {
178  snprintf(style_file_path, sizeof(style_file_path), "%s/%s", dirname, stylename);
179  } else {
180  /* Otherwise, just use the dirname. We'll pick a random stylefile.*/
181  snprintf(style_file_path, sizeof(style_file_path), "%s", dirname);
182  }
183 
184  /* Is what we were given a directory, or a file? */
185  snprintf(style_file_full_path, sizeof(style_file_full_path), "%s/%s", settings.mapspath, style_file_path);
186 
187  stat(style_file_full_path, &file_stat);
188 
189  if (!(S_ISDIR(file_stat.st_mode))) {
190  style_map = load_style_map(style_file_path);
191  }
192 
193  /* Maybe we were given a directory! */
194  if (style_map == NULL) {
195  char **namelist;
196  int n, only_subdirs = 0;
197  char style_dir_full_path[256];
198 
199  /* Get the names of all the files in that directory */
200  snprintf(style_dir_full_path, sizeof(style_dir_full_path), "%s/%s", settings.mapspath, style_file_path);
201 
202  /* First, skip subdirectories. If we don't find anything, then try
203  * again
204  * without skipping subdirs. */
205  n = load_dir(style_dir_full_path, &namelist, 1);
206 
207  if (n <= 0) {
208  n = load_dir(style_dir_full_path, &namelist, 0);
209  only_subdirs = 1;
210  }
211 
212  /* Nothing to load. Bye. */
213  if (n <= 0) {
214  return 0;
215  }
216 
217  /* pick a random style from this dir. */
218  if (difficulty == -1) {
219  if (only_subdirs) {
220  style_map = NULL;
221  } else {
222  strcat(style_file_path, "/");
223  strcat(style_file_path, namelist[RANDOM() % n]);
224 
225  style_map = load_style_map(style_file_path);
226  }
227  } else {
228  int min_dist = 32000, min_index = -1;
229 
230  /* find the map closest in difficulty */
231 
232  for (i = 0; i < n; i++) {
233  int dist;
234  char *mfile_name = strrchr(namelist[i], '_') + 1;
235 
236  /* since there isn't a sequence, pick one at random to recurse
237  * */
238  if ((mfile_name - 1) == NULL) {
239  int q;
240 
241  style_map = find_style(style_file_path, namelist[RANDOM() % n], difficulty);
242 
243  for (q = 0; q < n; q++) {
244  efree(namelist[q]);
245  }
246 
247  efree(namelist);
248 
249  return style_map;
250  } else {
251  dist = abs(difficulty - atoi(mfile_name));
252 
253  if (dist < min_dist) {
254  min_dist = dist;
255  min_index = i;
256  }
257  }
258  }
259 
260  /* presumably now we've found the "best" match for the
261  * difficulty. */
262  strcat(style_file_path, "/");
263  strcat(style_file_path, namelist[min_index]);
264 
265  style_map = load_style_map(style_file_path);
266  }
267 
268  for (i = 0; i < n; i++) {
269  efree(namelist[i]);
270  }
271 
272  efree(namelist);
273  }
274 
275  return style_map;
276 
277 }
278 
287 {
288  int x, y, i;
289  object *new_obj;
290 
291  /* If someone makes a style map that is empty, this will loop forever,
292  * but the callers will crash if we return a NULL object, so either
293  * way is not good. */
294  do {
295  i = RANDOM () % (MAP_WIDTH(style) * MAP_HEIGHT(style));
296 
297  x = i / MAP_HEIGHT(style);
298  y = i % MAP_HEIGHT(style);
299  new_obj = GET_MAP_OB(style, x, y);
300  } while (new_obj == NULL);
301 
302  if (new_obj->head) {
303  return new_obj->head;
304  } else {
305  return new_obj;
306  }
307 }
308 
312 void free_style_maps(void)
313 {
314  mapstruct *map, *tmp;
315 
316  /* delete_map will try to free it from the linked list,
317  * but won't find it, so we need to do it ourselves */
318  DL_FOREACH_SAFE(styles, map, tmp)
319  {
320  DL_DELETE(styles, map);
321  delete_map(map);
322  }
323 }
#define MAP_WIDTH(m)
Definition: map.h:120
shstr * path
Definition: map.h:568
void delete_map(mapstruct *m)
Definition: map.c:1555
static int pointer_strcmp(const void *p1, const void *p2)
Definition: style.c:43
mapstruct * load_original_map(const char *filename, mapstruct *originator, int flags)
Definition: map.c:1055
mapstruct * styles
Definition: style.c:115
mapstruct * find_style(const char *dirname, const char *stylename, int difficulty)
Definition: style.c:169
int load_dir(const char *dir, char ***namelist, int skip_dirs)
Definition: style.c:71
#define MAP_HEIGHT(m)
Definition: map.h:122
object * pick_random_object(mapstruct *style)
Definition: style.c:286
mapstruct * load_style_map(char *style_name)
Definition: style.c:124
char mapspath[MAX_BUF]
Definition: global.h:348
struct settings_struct settings
Definition: init.c:55
bool global_removed
If true, the map was removed from the global list.
Definition: map.h:684
struct obj * head
Definition: object.h:136
#define MAP_STYLE
Definition: map.h:153
Definition: map.h:536
mapstruct * first_map
Definition: main.c:59
void free_style_maps(void)
Definition: style.c:312