Crossfire Server, Trunk
style.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
21 #include "global.h"
22 
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #ifndef WIN32 /* ---win32 exclude headers */
27 #include <dirent.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include "../include/autoconf.h"
31 #endif /* win32 */
32 
33 #include "random_map.h"
34 
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 
74 int load_dir(const char *dir, char ***namelist, int skip_dirs)
75 {
76  DIR *dp;
77  struct dirent *d;
78  int entries = 0, entry_size = 0;
79  char name[NAME_MAX+1], **rn = NULL;
80  struct stat sb;
81 
82  dp = opendir(dir);
83  if (dp == NULL) {
84  return -1;
85  }
86 
87  while ((d = readdir(dp)) != NULL) {
88  if (skip_dirs) {
89  snprintf(name, sizeof(name), "%s/%s", dir, d->d_name);
90  stat(name, &sb);
91  if (S_ISDIR(sb.st_mode)) {
92  continue;
93  }
94  }
95 
96  if (entries == entry_size) {
97  entry_size += 10;
98  rn = static_cast<char **>(realloc(rn, sizeof(char *)*entry_size));
99  }
100  rn[entries] = strdup_local(d->d_name);
101  entries++;
102  }
103  (void)closedir(dp);
104 
105  /* We don't return -1 for this case here as directory isn't invalid as such.
106  * Most likely directory was empty. In theory it could also be due to
107  * realloc failing to allocate.
108  */
109  if (rn == NULL) {
110  return 0;
111  }
112 
113  qsort(rn, entries, sizeof(char *), pointer_strcmp);
114 
115  *namelist = rn;
116  return entries;
117 }
118 
123 
131 mapstruct *load_style_map(char *style_name)
132 {
133  mapstruct *style_map;
134 
135  /* Given a file. See if its in memory */
136  for (style_map = styles; style_map != NULL; style_map = style_map->next) {
137  if (!strcmp(style_name, style_map->path)) {
138  return style_map;
139  }
140  }
141  style_map = mapfile_load(style_name, MAP_STYLE);
142  /* Remove it from global list, put it on our local list */
143  if (style_map) {
144  mapstruct *tmp;
145 
146  if (style_map == first_map) {
147  first_map = style_map->next;
148  } else {
149  for (tmp = first_map; tmp && tmp->next != style_map; tmp = tmp->next)
150  ;
151  if (tmp) {
152  tmp->next = style_map->next;
153  }
154  }
155  style_map->next = styles;
156  styles = style_map;
157  }
158  return style_map;
159 }
160 
180 mapstruct *find_style(const char *dirname, const char *stylename, int difficulty)
181 {
182  char style_file_path[256];
183  char style_file_full_path[256];
184  mapstruct *style_map = NULL;
185  struct stat file_stat;
186  int i, only_subdirs = 0;
187 
188  /* Don't allow escaping from the styles directory. */
189  if (strstr(dirname, "..") != NULL || (stylename != NULL && strstr(stylename, "..") != NULL))
190  return NULL;
191 
192  /* if stylename exists, set style_file_path to that file.*/
193  if (stylename && strlen(stylename) > 0) {
194  snprintf(style_file_path, sizeof(style_file_path), "%s/%s", dirname, stylename);
195  } else { /* otherwise, just use the dirname. We'll pick a random stylefile.*/
196  strlcpy(style_file_path, dirname, sizeof(style_file_path));
197  }
198 
199  /* is what we were given a directory, or a file? */
200  snprintf(style_file_full_path, sizeof(style_file_full_path), "%s/maps%s", settings.datadir, style_file_path);
201  if (stat(style_file_full_path, &file_stat) == 0
202  && !S_ISDIR(file_stat.st_mode)) {
203  style_map = load_style_map(style_file_path);
204  }
205  if (style_map == NULL) { /* maybe we were given a directory! */
206  char **namelist;
207  int n;
208  char style_dir_full_path[256];
209 
210  /* get the names of all the files in that directory */
211  snprintf(style_dir_full_path, sizeof(style_dir_full_path), "%s/maps%s", settings.datadir, style_file_path);
212 
213  /* First, skip subdirectories. If we don't find anything, then try again
214  * without skipping subdirs.
215  */
216  n = load_dir(style_dir_full_path, &namelist, 1);
217  if (n <= 0) {
218  n = load_dir(style_dir_full_path, &namelist, 0);
219  only_subdirs = 1;
220  }
221 
222  if (n <= 0) {
223  return NULL; /* nothing to load. Bye. */
224  }
225 
226  /* Picks a random map. Note that if this is all directories,
227  * we know it won't be able to load, so save a few ticks.
228  * the door handling checks for this failure and handles
229  * it properly.
230  */
231  if (difficulty == -1) { /* pick a random style from this dir. */
232  if (only_subdirs) {
233  style_map = NULL;
234  } else {
235  char *p;
236 
237  p = strchr(style_file_path, '\0');
238  snprintf(p, style_file_path+sizeof(style_file_path)-p, "/%s", namelist[RANDOM()%n]);
239  style_map = load_style_map(style_file_path);
240  }
241  } else { /* find the map closest in difficulty */
242  int min_dist = 32000, min_index = -1;
243  char *p;
244 
245  for (i = 0; i < n; i++) {
246  int dist;
247  char *mfile_name = strrchr(namelist[i], '_');
248  if (mfile_name == NULL) { /* since there isn't a sequence, */
249  int q;
250 
251  /*pick one at random to recurse */
252  style_map = find_style(style_file_path, namelist[RANDOM()%n], difficulty);
253  for (q = 0; q < n; q++) {
254  free(namelist[q]);
255  }
256  free(namelist);
257  return style_map;
258  } else {
259  dist = abs(difficulty - atoi(mfile_name + 1));
260  if (dist < min_dist) {
261  min_dist = dist;
262  min_index = i;
263  }
264  }
265  }
266  /* presumably now we've found the "best" match for the
267  difficulty. */
268  p = strchr(style_file_path, '\0');
269  snprintf(p, style_file_path+sizeof(style_file_path)-p, "/%s", namelist[min_index]);
270  style_map = load_style_map(style_file_path);
271  }
272  for (i = 0; i < n; i++) {
273  free(namelist[i]);
274  }
275  free(namelist);
276  }
277  return style_map;
278 }
279 
290 {
291  int x, y, limit = 0;
292  object *new_obj;
293 
294  /* while returning a null object will result in a crash, that
295  * is actually preferable to an infinite loop. That is because
296  * most servers will automatically restart in case of crash.
297  * Change the logic on getting the random space - shouldn't make
298  * any difference, but this seems clearer to me.
299  */
300  do {
301  limit++;
302  x = RANDOM()%MAP_WIDTH(style);
303  y = RANDOM()%MAP_HEIGHT(style);
304  new_obj = GET_MAP_OB(style, x, y);
305  } while (new_obj == NULL && limit < 1000);
306  return HEAD(new_obj);
307 }
308 
312 void free_style_maps(void)
313 {
314  mapstruct *next;
315  int style_maps = 0;
316 
317  /* delete_map will try to free it from the linked list,
318  * but won't find it, so we need to do it ourselves
319  */
320  while (styles) {
321  next = styles->next;
323  styles = next;
324  style_maps++;
325  }
326  LOG(llevDebug, "free_style_maps: Freed %d maps\n", style_maps);
327 }
give.next
def next
Definition: give.py:44
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:171
global.h
settings
struct Settings settings
Definition: init.cpp:139
random_map.h
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
strdup_local
#define strdup_local
Definition: compat.h:29
diamondslots.x
x
Definition: diamondslots.py:15
n
based on the size of the this randomly makes land number of spaces randomly lower or higher The default is Note that this is run also based on the the altitude amount will likely be less So if you do something like l and n
Definition: land.6.txt:25
load_dir
int load_dir(const char *dir, char ***namelist, int skip_dirs)
Definition: style.cpp:74
Ice.tmp
int tmp
Definition: Ice.py:207
NAME_MAX
#define NAME_MAX
Definition: define.h:30
mapstruct::path
char path[HUGE_BUF]
Definition: map.h:355
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
MAP_STYLE
#define MAP_STYLE
Definition: map.h:95
item.q
q
Definition: item.py:32
opendir
DIR * opendir(const char *)
pick_random_object
object * pick_random_object(mapstruct *style)
Definition: style.cpp:289
pointer_strcmp
static int pointer_strcmp(const void *p1, const void *p2)
Definition: style.cpp:43
CFInsulter.style
style
Definition: CFInsulter.py:69
first_map
mapstruct * first_map
Definition: init.cpp:107
HEAD
#define HEAD(op)
Definition: object.h:598
readdir
struct dirent * readdir(DIR *)
delete_map
void delete_map(mapstruct *m)
Definition: map.cpp:1696
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
d
How to Install a Crossfire Server on you must install a python script engine on your computer Python is the default script engine of Crossfire You can find the python engine you have only to install them The VisualC Crossfire settings are for d
Definition: INSTALL_WIN32.txt:13
MAP_WIDTH
#define MAP_WIDTH(m)
Definition: map.h:74
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.cpp:222
RANDOM
#define RANDOM()
Definition: define.h:644
styles
mapstruct * styles
Definition: style.cpp:122
mapstruct
Definition: map.h:314
free_style_maps
void free_style_maps(void)
Definition: style.cpp:312
diamondslots.y
y
Definition: diamondslots.py:16
MAP_HEIGHT
#define MAP_HEIGHT(m)
Definition: map.h:76
find_style
mapstruct * find_style(const char *dirname, const char *stylename, int difficulty)
Definition: style.cpp:180
Settings::datadir
const char * datadir
Definition: global.h:248
mapstruct::next
mapstruct * next
Definition: map.h:315
closedir
int closedir(DIR *)
mapfile_load
mapstruct * mapfile_load(const char *map, int flags)
Definition: map.cpp:1216
load_style_map
mapstruct * load_style_map(char *style_name)
Definition: style.cpp:131
llevDebug
@ llevDebug
Definition: logger.h:13