Crossfire Server, Trunk
server.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 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 
19 #include "global.h"
20 
21 #include <assert.h>
22 #include <ctype.h>
23 #include <fcntl.h>
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 
29 #ifndef WIN32
30 #include <unistd.h>
31 #endif
32 
33 /* FIXME: This is required on certain systems to get crypt(3) to work. */
34 #ifdef HAVE_CRYPT_H
35 #include <crypt.h>
36 #endif
37 
38 #include "object.h"
39 #include "path.h"
40 #include "random_maps/random_map.h"
41 #include "random_maps/rproto.h"
42 #include "sproto.h"
43 #include "tod.h"
44 #include "version.h"
45 #include "server.h"
46 
48 static const int shutdown_warn_times[] = {120, 90, 60, 45, 30, 15, 10, 5, 4, 3, 2, 1};
49 
51 static const char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
52 
53 volatile sig_atomic_t shutdown_flag;
54 
70 static char const* crypt_string(char const str[static 1], char const* salt) {
71 #if defined(WIN32)
72  // Windows will never attempt to crypt()
73  return str;
74 #else
75 #if (defined(__FreeBSD__))
76  // If legacy mode is enabled, do not crypt() on FreeBSD
77  if (settings.crypt_mode == 0) {
78  return str;
79  }
80 #endif
81  char s[3];
82 
83  if (salt == NULL) {
84  /* Generate a two-character salt for the DES cipher.
85  * We want the salt to be in this character set.
86  */
87  static const char *const c =
88  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
89  s[0] = c[RANDOM()%(int)strlen(c)],
90  s[1] = c[RANDOM()%(int)strlen(c)];
91  } else {
92  s[0] = salt[0],
93  s[1] = salt[1];
94  }
95  s[2] = '\0';
96 
97  return crypt(str, s);
98 #endif
99 }
100 
101 char const* newhash(char const password[static 1]) {
102  return crypt_string(password, NULL);
103 }
104 
114 bool check_password(const char *typed, const char *crypted) {
115  // An empty hashed password only matches an empty input password.
116  if (strlen(crypted) == 0) {
117  return strlen(typed) == 0 ? true : false;
118  }
119 
120  const char *typed_hashed = crypt_string(typed, crypted);
121  if (typed_hashed != NULL) {
122  return strcmp(typed_hashed, crypted) == 0;
123  } else {
124  LOG(llevError, "Could not check password with stored hash %s\n", crypted);
125  return false;
126  }
127 }
128 
138 void enter_player_savebed(object *op) {
139  mapstruct *oldmap = op->map;
140  object *tmp;
141 
142  tmp = object_new();
143 
144  EXIT_PATH(tmp) = add_string(op->contr->savebed_map);
145  EXIT_X(tmp) = op->contr->bed_x;
146  EXIT_Y(tmp) = op->contr->bed_y;
147  enter_exit(op, tmp);
148  /* If the player has not changed maps and the name does not match
149  * that of the savebed, his savebed map is gone. Lets go back
150  * to the emergency path. Update what the players savebed is
151  * while we're at it.
152  */
153  if (oldmap == op->map && strcmp(op->contr->savebed_map, oldmap->path)) {
154  LOG(llevDebug, "Player %s savebed location %s is invalid - going to emergency location (%s)\n",
155  settings.emergency_mapname, op->name, op->contr->savebed_map);
156  safe_strncpy(op->contr->savebed_map, settings.emergency_mapname, MAX_BUF);
157  op->contr->bed_x = settings.emergency_x;
158  op->contr->bed_y = settings.emergency_y;
159  free_string(op->contr->savebed_map);
160  EXIT_PATH(tmp) = add_string(op->contr->savebed_map);
161  EXIT_X(tmp) = op->contr->bed_x;
162  EXIT_Y(tmp) = op->contr->bed_y;
163  enter_exit(op, tmp);
164  }
165  object_free(tmp, FREE_OBJ_NO_DESTROY_CALLBACK);
166 }
167 
179 static void enter_map(object *op, mapstruct *newmap, int x, int y) {
180  mapstruct *oldmap = op->map;
181 
182  if (out_of_map(newmap, x, y)) {
183  LOG(llevError, "enter_map: supplied coordinates are not within the map! (%s: %d, %d)\n", newmap->path, x, y);
184  /* If op has invalid (probably -1,-1) coordinates, force them to a correct value, else issues later on. */
185  if (op->x == x)
186  op->x = MAP_ENTER_X(newmap);
187  if (op->y == y)
188  op->y = MAP_ENTER_Y(newmap);
189  x = MAP_ENTER_X(newmap);
190  y = MAP_ENTER_Y(newmap);
191  if (out_of_map(newmap, x, y)) {
192  LOG(llevError, "enter_map: map %s provides invalid default enter location (%d, %d) > (%d, %d)\n", newmap->path, x, y, MAP_WIDTH(newmap), MAP_HEIGHT(newmap));
194  "The exit is closed");
195  return;
196  }
197  }
198  /* try to find a spot for the player */
199  if (ob_blocked(op, newmap, x, y)) { /* First choice blocked */
200  /* We try to find a spot for the player, starting closest in.
201  * We could use object_find_first_free_spot(), but that doesn't randomize it at all,
202  * So for example, if the north space is free, you would always end up there even
203  * if other spaces around are available.
204  * Note that for the second and third calls, we could start at a position other
205  * than one, but then we could end up on the other side of walls and so forth.
206  */
207  int i = object_find_free_spot(op, newmap, x, y, 1, SIZEOFFREE1+1);
208  if (i == -1) {
209  i = object_find_free_spot(op, newmap, x, y, 1, SIZEOFFREE2+1);
210  if (i == -1)
211  i = object_find_free_spot(op, newmap, x, y, 1, SIZEOFFREE);
212  }
213  if (i != -1) {
214  x += freearr_x[i];
215  y += freearr_y[i];
216  } else {
217  /* not much we can do in this case. */
218  LOG(llevInfo, "enter_map: Could not find free spot for player - will dump on top of object (%s: %d, %d)\n", newmap->path, x, y);
219  }
220  } /* end if looking for free spot */
221 
222  /* If it is a player login, he has yet to be inserted anyplace.
223  * otherwise, we need to deal with removing the playe here.
224  */
225  if (!QUERY_FLAG(op, FLAG_REMOVED))
226  object_remove(op);
227  /* object_remove clears these so they must be reset after the object_remove() call */
228  object_insert_in_map_at(op, newmap, NULL, INS_NO_WALK_ON, x, y);
229 
230  object_set_enemy(op, NULL);
231 
232  if (op->contr) {
233  safe_strncpy(op->contr->maplevel, newmap->path,
234  sizeof(op->contr->maplevel));
235  op->contr->count = 0;
236  }
237 
238  /* Update any golems */
239  if (op->type == PLAYER && op->contr->ranges[range_golem] != NULL) {
240  int i = object_find_free_spot(op->contr->ranges[range_golem], newmap, x, y, 1, SIZEOFFREE);
241  object_remove(op->contr->ranges[range_golem]);
242  if (i == -1) {
243  remove_friendly_object(op->contr->ranges[range_golem]);
244  object_free_drop_inventory(op->contr->ranges[range_golem]);
245  op->contr->ranges[range_golem] = NULL;
246  op->contr->golem_count = 0;
247  } else {
248  object_insert_in_map_at(op->contr->ranges[range_golem], newmap, NULL, 0, x+freearr_x[i], y+freearr_y[i]);
249  op->contr->ranges[range_golem]->direction = find_dir_2(op->x-op->contr->ranges[range_golem]->x, op->y-op->contr->ranges[range_golem]->y);
250  }
251  }
252  op->direction = 0;
253 
254  /* since the players map is already loaded, we don't need to worry
255  * about pending objects.
256  */
257  pets_remove_all();
258 
259  /* If the player is changing maps, we need to do some special things
260  * Do this after the player is on the new map - otherwise the force swap of the
261  * old map does not work.
262  */
263  if (oldmap != newmap) {
264  player_map_change_common(op, oldmap, newmap);
265  }
266 
267  map_newmap_cmd(&op->contr->socket);
268 }
269 
270 void player_map_change_common(object* op, mapstruct* const oldmap,
271  mapstruct* const newmap) {
272  if (oldmap != NULL) {
274 
275  /* can be less than zero due to errors in tracking this */
276  if (oldmap->players <= 0) {
277  set_map_timeout(oldmap);
278  }
279  }
280 
282  newmap->timeout = 0;
284 }
285 
292 void set_map_timeout(mapstruct *oldmap) {
293 #if MAP_MAXTIMEOUT
294  oldmap->timeout = MAP_TIMEOUT(oldmap);
295  /* Do MINTIMEOUT first, so that MAXTIMEOUT is used if that is
296  * lower than the min value.
297  */
298 #if MAP_MINTIMEOUT
299  if (oldmap->timeout < MAP_MINTIMEOUT) {
300  oldmap->timeout = MAP_MINTIMEOUT;
301  }
302 #endif
303  if (oldmap->timeout > MAP_MAXTIMEOUT) {
304  oldmap->timeout = MAP_MAXTIMEOUT;
305  }
306 #else
307  /* save out the map */
308  swap_map(oldmap);
309 #endif /* MAP_MAXTIMEOUT */
310 }
311 
325 static char *clean_path(const char *file, char *newpath, int size) {
326  char *cp;
327 
328  strlcpy(newpath, file, size);
329  for (cp = newpath; *cp != '\0'; cp++) {
330  if (*cp == '/')
331  *cp = '_';
332  }
333  return newpath;
334 }
335 
353 static char *unclean_path(const char *src, char *newpath, int size) {
354  char *cp;
355 
356  cp = strrchr(src, '/');
357  if (cp)
358  strlcpy(newpath, cp+1, size);
359  else
360  strlcpy(newpath, src, size);
361 
362  for (cp = newpath; *cp != '\0'; cp++) {
363  if (*cp == '_')
364  *cp = '/';
365  }
366  return newpath;
367 }
368 
369 
379 static void enter_random_map(object *pl, object *exit_ob) {
380  mapstruct *new_map;
381  char newmap_name[HUGE_BUF], buf[HUGE_BUF], *cp;
382  static int reference_number = 0;
383  RMParms rp;
384 
385  memset(&rp, 0, sizeof(RMParms));
386  rp.Xsize = -1;
387  rp.Ysize = -1;
388  rp.region = get_region_by_map(exit_ob->map);
389  if (exit_ob->msg)
390  set_random_map_variable(&rp, exit_ob->msg);
391  rp.origin_x = exit_ob->x;
392  rp.origin_y = exit_ob->y;
393  safe_strncpy(rp.origin_map, pl->map->path, sizeof(rp.origin_map));
394 
395  /* If we have a final_map, use it as a base name to give some clue
396  * as where the player is. Otherwise, use the origin map.
397  * Take the last component (after the last slash) to give
398  * shorter names without bogus slashes.
399  */
400  if (rp.final_map[0]) {
401  cp = strrchr(rp.final_map, '/');
402  if (!cp)
403  cp = rp.final_map;
404  } else {
405  cp = strrchr(rp.origin_map, '/');
406  if (!cp)
407  cp = rp.origin_map;
408  /* Need to strip of any trailing digits, if it has them */
409  strlcpy(buf, cp, sizeof(buf));
410  while (isdigit(buf[strlen(buf)-1]))
411  buf[strlen(buf)-1] = 0;
412  cp = buf;
413  }
414 
415  snprintf(newmap_name, sizeof(newmap_name), "/random/%s%04d", cp+1, reference_number++);
416 
417  /* now to generate the actual map. */
418  new_map = generate_random_map(newmap_name, &rp, NULL);
419 
420  /* Update the exit_ob so it now points directly at the newly created
421  * random maps. Not that it is likely to happen, but it does mean that a
422  * exit in a unique map leading to a random map will not work properly.
423  * It also means that if the created random map gets reset before
424  * the exit leading to it, that the exit will no longer work.
425  */
426  if (new_map) {
427  int x, y;
428 
429  x = EXIT_X(exit_ob) = MAP_ENTER_X(new_map);
430  y = EXIT_Y(exit_ob) = MAP_ENTER_Y(new_map);
431  EXIT_PATH(exit_ob) = add_string(newmap_name);
432  strlcpy(new_map->path, newmap_name, sizeof(new_map->path));
433  enter_map(pl, new_map, x, y);
434  }
435 }
436 
446 static void enter_fixed_template_map(object *pl, object *exit_ob) {
447  mapstruct *new_map;
448  char tmpnum[32], exitpath[HUGE_BUF], resultname[HUGE_BUF], tmpstring[HUGE_BUF], *sourcemap;
449  char sourcemap_buf[HUGE_BUF];
450  char new_map_name[MAX_BUF];
451 
452  /* Split the exit path string into two parts, one
453  * for where to store the map, and one for were
454  * to generate the map from.
455  */
456  strlcpy(exitpath, EXIT_PATH(exit_ob)+2, sizeof(exitpath));
457  sourcemap = strchr(exitpath, '!');
458  if (!sourcemap) {
461  "The %s is closed.",
462  exit_ob->name);
463  LOG(llevError, "enter_fixed_template_map: Exit %s (%d,%d) on map %s has no source template.\n", exit_ob->name, exit_ob->x, exit_ob->y, exit_ob->map->path);
464  return;
465  }
466  *sourcemap++ = '\0';
467 
468  /* If we are not coming from a template map, we can use relative directories
469  * for the map to generate from.
470  */
471  if (!exit_ob->map->is_template) {
472  /* We can't use exitpath directly, as sourcemap points there. */
473  path_combine_and_normalize(exit_ob->map->path, sourcemap, sourcemap_buf, sizeof(sourcemap_buf));
474  sourcemap = sourcemap_buf;
475  }
476 
477  /* Do replacement of %x, %y, and %n to the x coord of the exit, the y coord
478  * of the exit, and the name of the map the exit is on, respectively.
479  */
480  snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->x);
481  replace(exitpath, "%x", tmpnum, resultname, sizeof(resultname));
482 
483  snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->y);
484  strlcpy(tmpstring, resultname, sizeof(tmpstring));
485  replace(tmpstring, "%y", tmpnum, resultname, sizeof(resultname));
486 
487  strlcpy(tmpstring, resultname, sizeof(tmpstring));
488  replace(tmpstring, "%n", exit_ob->map->name, resultname, sizeof(resultname));
489 
490  /* If we are coming from another template map, use reletive paths unless
491  * indicated otherwise.
492  */
493  if (exit_ob->map->is_template && (resultname[0] != '/')) {
494  path_combine_and_normalize(exit_ob->map->path, resultname, new_map_name, sizeof(new_map_name));
495  } else {
496  create_template_pathname(resultname, new_map_name, sizeof(new_map_name));
497  }
498 
499  /* Attempt to load the map, if unable to, then
500  * create the map from the template.
501  */
502  new_map = ready_map_name(new_map_name, MAP_PLAYER_UNIQUE);
503  if (!new_map) {
504  char path[MAX_BUF];
505  create_pathname(sourcemap, path, MAX_BUF);
506  new_map = mapfile_load(path, MAP_PLAYER_UNIQUE);
507  if (!new_map) {
509  MSG_TYPE_COMMAND_FAILURE, "The %s is closed.",
510  exit_ob->name);
511  LOG(llevError,
512  "Template exit in '%s' (%d, %d) does not reference a valid "
513  "template. Make sure a template exists at '%s'.\n",
514  exit_ob->map->path, exit_ob->x, exit_ob->y, path);
515  return;
516  }
517  }
518 
519  assert(new_map);
520  /* set the path of the map to where it should be
521  * so we don't just save over the source map.
522  */
523  strlcpy(new_map->path, new_map_name, sizeof(new_map->path));
524  new_map->is_template = 1;
525  enter_map(pl, new_map, EXIT_X(exit_ob), EXIT_Y(exit_ob));
526 }
527 
537 static void enter_random_template_map(object *pl, object *exit_ob) {
538  mapstruct *new_map;
539  char tmpnum[32], resultname[HUGE_BUF], tmpstring[HUGE_BUF];
540  char new_map_name[MAX_BUF];
541  RMParms rp;
542 
543  /* Do replacement of %x, %y, and %n to the x coord of the exit, the y coord
544  * of the exit, and the name of the map the exit is on, respectively.
545  */
546  snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->x);
547  replace(EXIT_PATH(exit_ob)+3, "%x", tmpnum, resultname, sizeof(resultname));
548 
549  snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->y);
550  strlcpy(tmpstring, resultname, sizeof(tmpstring));
551  replace(tmpstring, "%y", tmpnum, resultname, sizeof(resultname));
552 
553  strlcpy(tmpstring, resultname, sizeof(tmpstring));
554  replace(tmpstring, "%n", exit_ob->map->name, resultname, sizeof(resultname));
555 
556  /* If we are coming from another template map, use reletive paths unless
557  * indicated otherwise.
558  */
559  if (exit_ob->map->is_template && (resultname[0] != '/')) {
560  path_combine_and_normalize(exit_ob->map->path, resultname, new_map_name, sizeof(new_map_name));
561  } else {
562  create_template_pathname(resultname, new_map_name, sizeof(new_map_name));
563  }
564 
565  new_map = ready_map_name(new_map_name, MAP_PLAYER_UNIQUE);
566  if (!new_map) {
567  memset(&rp, 0, sizeof(RMParms));
568  rp.Xsize = -1;
569  rp.Ysize = -1;
570  rp.region = get_region_by_map(exit_ob->map);
571  if (exit_ob->msg)
572  set_random_map_variable(&rp, exit_ob->msg);
573  rp.origin_x = exit_ob->x;
574  rp.origin_y = exit_ob->y;
575  safe_strncpy(rp.origin_map, pl->map->path, sizeof(rp.origin_map));
576 
577  /* now to generate the actual map. */
578  new_map = generate_random_map(new_map_name, &rp, NULL);
579  }
580 
581  /* Update the exit_ob so it now points directly at the newly created
582  * random maps. Not that it is likely to happen, but it does mean that a
583  * exit in a unique map leading to a random map will not work properly.
584  * It also means that if the created random map gets reset before
585  * the exit leading to it, that the exit will no longer work.
586  */
587  if (new_map) {
588  int x, y;
589 
590  x = EXIT_X(exit_ob) = MAP_ENTER_X(new_map);
591  y = EXIT_Y(exit_ob) = MAP_ENTER_Y(new_map);
592  new_map->is_template = 1;
593  enter_map(pl, new_map, x, y);
594  }
595 }
596 
605 static void enter_unique_map(object *op, object *exit_ob) {
606  char apartment[HUGE_BUF], path[MAX_BUF];
607  mapstruct *newmap;
608 
609  if (EXIT_PATH(exit_ob)[0] == '/') {
610  snprintf(apartment, sizeof(apartment), "~%s/%s", op->name, clean_path(EXIT_PATH(exit_ob), path, sizeof(path)));
611  newmap = ready_map_name(apartment, MAP_PLAYER_UNIQUE);
612  if (!newmap) {
613  newmap = mapfile_load(EXIT_PATH(exit_ob), 0);
614  }
615  } else { /* relative directory */
616  char reldir[HUGE_BUF], tmpc[HUGE_BUF], *cp;
617 
618  if (exit_ob->map->unique) {
619  // Use player's current map path to construct base of relative path in 'src'
620  char* src = strdup(op->map->path);
621  char* slash = strrchr(src, '/');
622  if (slash == NULL) {
623  abort();
624  }
625  *slash = '\0';
626 
627  unclean_path(exit_ob->map->path, reldir, sizeof(reldir));
628 
629  /* Need to copy this over, as clean_path only has one static return buffer */
630  clean_path(reldir, tmpc, sizeof(tmpc));
631  /* Remove final component, if any */
632  if ((cp = strrchr(tmpc, '_')) != NULL)
633  *cp = 0;
634 
635  snprintf(apartment, sizeof(apartment), "%s/%s_%s", src, tmpc, clean_path(EXIT_PATH(exit_ob), path, sizeof(path)));
636 
637  newmap = ready_map_name(apartment, MAP_PLAYER_UNIQUE);
638  if (!newmap) {
639  newmap = mapfile_load(path_combine_and_normalize(reldir, EXIT_PATH(exit_ob), tmpc, sizeof(tmpc)), 0);
640  }
641  } else {
642  /* The exit is unique, but the map we are coming from is not unique. So
643  * use the basic logic - don't need to demangle the path name
644  */
645  path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), reldir, sizeof(reldir));
646  snprintf(apartment, sizeof(apartment), "~%s/%s", op->name, clean_path(reldir, path, sizeof(path)));
647  newmap = ready_map_name(apartment, MAP_PLAYER_UNIQUE);
648  if (!newmap) {
649  path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), reldir, sizeof(reldir));
650  newmap = ready_map_name(reldir, 0);
651  if (newmap)
652  apply_auto_fix(newmap);
653  }
654  }
655  }
656 
657  if (newmap) {
658  strlcpy(newmap->path, apartment, sizeof(newmap->path));
659  newmap->unique = 1;
660  enter_map(op, newmap, EXIT_X(exit_ob), EXIT_Y(exit_ob));
661  } else {
664  "The %s is closed.",
665  exit_ob->name);
666  /* Perhaps not critical, but I would think that the unique maps
667  * should be new enough this does not happen. This also creates
668  * a strange situation where some players could perhaps have visited
669  * such a map before it was removed, so they have the private
670  * map, but other players can't get it anymore.
671  */
672  LOG(llevDebug, "enter_unique_map: Exit %s (%d,%d) on map %s is leads no where.\n", exit_ob->name, exit_ob->x, exit_ob->y, exit_ob->map->path);
673  }
674 }
675 
676 void enter_player_maplevel(object *op) {
677  assert(op != NULL);
678  int flags = 0, x = op->x, y = op->y;
679  mapstruct *newmap;
680 
681  assert(op->type == PLAYER);
682 
683  /* newmap returns the map (if already loaded), or loads it for us. */
684  newmap = ready_map_name(op->contr->maplevel, flags);
685  if (!newmap) {
689  if (!newmap) {
690  LOG(llevError, "Fatal: Could not load emergency map!\n");
691  abort();
692  }
693 
695  "You find yourself somewhere unexpected...");
696  }
697 
698  /* as a special case, if coordinates are (-1, -1), then the item should
699  * be put at the default location. Used for loginmethod 0 (old clients). */
700  if (x == -1 && y == -1) {
701  x = MAP_ENTER_X(newmap);
702  y = MAP_ENTER_Y(newmap);
703  }
704 
705  enter_map(op, newmap, x, y);
706 }
707 
721 void enter_exit(object *op, object *exit_ob) {
722 #define PORTAL_DESTINATION_NAME "Town portal destination" /* this one should really be in a header file */
723  /* It may be nice to support other creatures moving across
724  * exits, but right now a lot of the code looks at op->contr,
725  * so thta is an RFE.
726  */
727  if (op->type != PLAYER)
728  return;
729 
730  /* Need to remove player from transport */
731  if (op->contr->transport)
732  ob_apply(op->contr->transport, op, AP_UNAPPLY);
733 
734  assert(exit_ob != NULL);
735  assert(EXIT_PATH(exit_ob) != NULL);
736 
737  /* check to see if we make a template map
738  * Template maps have an EXIT_PATH in the form:
739  * /@[!]<MAP_NAME>!<TEMPLATE_PATH>
740  *
741  * <MAP_NAME> is the name of the destination map, which is saved in LOCALDIR/template-maps/.
742  * <TEMPLATE_PATH> is the path to a template map, used when <MAP_NAME> does not exist.
743  */
744  if (EXIT_PATH(exit_ob) && EXIT_PATH(exit_ob)[1] == '@') {
745  if (EXIT_PATH(exit_ob)[2] == '!') {
746  /* generate a template map randomly */
747  enter_random_template_map(op, exit_ob);
748  } else {
749  /* generate a template map from a fixed template */
750  enter_fixed_template_map(op, exit_ob);
751  }
752  }
753  /* check to see if we make a randomly generated map */
754  else if (EXIT_PATH(exit_ob) && EXIT_PATH(exit_ob)[1] == '!') {
755  enter_random_map(op, exit_ob);
756  } else if (QUERY_FLAG(exit_ob, FLAG_UNIQUE)) {
757  enter_unique_map(op, exit_ob);
758  } else {
759  int x = EXIT_X(exit_ob), y = EXIT_Y(exit_ob);
760  /* 'Normal' exits that do not do anything special
761  * Simple enough we don't need another routine for it.
762  */
763  mapstruct *newmap;
764  if (exit_ob->map) {
765  char tmp_path[HUGE_BUF];
766 
767  path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), tmp_path, sizeof(tmp_path));
768  newmap = ready_map_name(tmp_path, 0);
769  /* Random map was previously generated, but is no longer about. Lets generate a new
770  * map.
771  */
772  if (!newmap && !strncmp(EXIT_PATH(exit_ob), "/random/", 8)) {
773  /* Maps that go down have a message set. However, maps that go
774  * up, don't. If the going home has reset, there isn't much
775  * point generating a random map, because it won't match the maps.
776  */
777  if (exit_ob->msg) {
778  enter_random_map(op, exit_ob);
779  } else {
782  "The %s is closed.",
783  exit_ob->name);
784  return;
785  }
786 
787  /* For exits that cause damages (like pits). Don't know if any
788  * random maps use this or not.
789  */
790  if (exit_ob->stats.dam && op->type == PLAYER)
791  hit_player(op, exit_ob->stats.dam, exit_ob, exit_ob->attacktype, 1);
792  return;
793  }
794  } else {
795  /* For word of recall and other force objects
796  * They contain the full pathname of the map to go back to,
797  * so we don't need to normalize it.
798  * But we do need to see if it is unique or not
799  */
800  if (!strncmp(EXIT_PATH(exit_ob), settings.localdir, strlen(settings.localdir)))
801  newmap = ready_map_name(EXIT_PATH(exit_ob), MAP_PLAYER_UNIQUE);
802  else
803  newmap = ready_map_name(EXIT_PATH(exit_ob), 0);
804  }
805  if (!newmap) {
806  if (exit_ob->name)
809  "The %s is closed.",
810  exit_ob->name);
811  /* don't cry to momma if name is not set - as in tmp objects
812  * used by the savebed code and character creation */
813  return;
814  }
815 
816  if (x == -1 && y == -1) {
817  x = MAP_ENTER_X(newmap);
818  y = MAP_ENTER_Y(newmap);
819  }
820 
821  /* mids 02/13/2002 if exit is damned, update players death & WoR home-position and delete town portal */
822  if (QUERY_FLAG(exit_ob, FLAG_DAMNED)) {
823  object *tmp;
824 
825  /* remove an old force with a slaying field == PORTAL_DESTINATION_NAME */
827  if (tmp) {
829  object_free(tmp, FREE_OBJ_NO_DESTROY_CALLBACK);
830  }
831 
832  path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), op->contr->savebed_map, sizeof(op->contr->savebed_map));
833  op->contr->bed_x = EXIT_X(exit_ob), op->contr->bed_y = EXIT_Y(exit_ob);
834  save_player(op, 1);
835  }
836 
837  enter_map(op, newmap, x, y);
838  }
839 
840  LOG(llevDebug, "%s enters %s\n", op->name, EXIT_PATH(exit_ob));
841 
842  /* For exits that cause damages (like pits) */
843  if (exit_ob->stats.dam && op->type == PLAYER)
844  hit_player(op, exit_ob->stats.dam, exit_ob, exit_ob->attacktype, 1);
845 
846  if (op->contr) {
847  object* exit_copy = object_new();
848  object_copy(exit_ob, exit_copy);
849  exit_copy->speed = 0; // Item isn't on map or in inv, but object_copy() may have added it to active list
850  object_update_speed(exit_copy);
851  exit_copy->map = exit_ob->map; // hack to set map without actually inserting
852  if (op->contr->last_exit) {
853  object_free(op->contr->last_exit, FREE_OBJ_NO_DESTROY_CALLBACK);
854  }
855  op->contr->last_exit = exit_copy;
856  }
857 }
858 
864 static int move_towards(object *ob, object *towards, unsigned int mindist) {
865  rv_vector rv;
866  get_rangevector(ob, towards, &rv, 0);
867  if (rv.direction != 0 && rv.distance > mindist && ob->speed_left > 0) {
868  move_player(ob, rv.direction);
869  }
870  return rv.direction;
871 }
872 
877 static bool object_on_exit(object* ob, object* exit) {
878  int x = exit->x;
879  int y = exit->y;
880  int sx, sy, sx2, sy2;
881  object_get_multi_size(exit, &sx, &sy, &sx2, &sy2);
882  return (ob->x >= x+sx2) && (ob->x <= x+sx) && (ob->y >= y+sy2) && (ob->y <= y+sy);
883 }
884 
888 static void do_follow(player *pl) {
889  assert(pl->followed_player != NULL);
891  if (followed && followed->ob && followed->ob->map) {
892  if (query_flag(pl->ob, FLAG_WIZ)) {
893  rv_vector rv;
894  if (!get_rangevector(pl->ob, followed->ob, &rv, 0) || rv.distance > 4) {
895  int space = object_find_free_spot(pl->ob, followed->ob->map, followed->ob->x, followed->ob->y, 1, 25);
896  if (space == -1) {
898  space = 0;
899  }
900  object_remove(pl->ob);
901  object_insert_in_map_at(pl->ob, followed->ob->map, NULL, 0, followed->ob->x+freearr_x[space], followed->ob->y+freearr_y[space]);
904  }
905  } else {
906  if (!can_follow(pl->ob, followed)) {
908  "%s stops letting you follow them.", pl->followed_player);
910  return;
911  }
912  if (move_towards(pl->ob, followed->ob, 1)== 0 && followed->ob->contr->last_exit != NULL) {
913  // Move to and apply exit
914  object* exit = followed->ob->contr->last_exit;
915  if (!object_on_exit(pl->ob, exit)) {
916  move_towards(pl->ob, exit, 0);
917  } else {
918  enter_exit(pl->ob, exit);
919  }
920  }
921  }
922  } else {
924  "You stop following %s.", pl->followed_player);
926  }
927 }
928 
934 static void process_players1(void) {
935  int flag;
936  player *pl, *plnext;
937 
938  /* Basically, we keep looping until all the players have done their actions. */
939  for (flag = 1; flag != 0; ) {
940  flag = 0;
941  for (pl = first_player; pl != NULL; pl = plnext) {
942  plnext = pl->next; /* In case a player exits the game in handle_player() */
943 
944  if (pl->ob == NULL)
945  continue;
946 
947  /* Only do this on the first pass - what we are recording
948  * here is the number of ticks the player has been online - not
949  * how many actions/moves the player has done.
950  */
951  if (!flag) pl->ticks_played++;
952 
953  if (pl->followed_player) {
954  do_follow(pl);
955  }
956 
957  if (pl->ob->speed_left > 0) {
958  if (handle_newcs_player(pl->ob))
959  flag = 1;
960  } /* end if player has speed left */
961 
962  /* If the player is not actively playing, don't make a
963  * backup save - nothing to save anyway. Plus, the
964  * map may not longer be valid. This can happen when the
965  * player quits - they exist for purposes of tracking on the map,
966  * but don't actually reside on any actual map.
967  */
968  if (QUERY_FLAG(pl->ob, FLAG_REMOVED))
969  continue;
970 
971 #ifdef AUTOSAVE
972  /* check for ST_PLAYING state so that we don't try to save off when
973  * the player is logging in.
974  */
975  if ((pl->last_save_tick+AUTOSAVE) < pticks && pl->state == ST_PLAYING) {
976  /* Don't save the player on unholy ground. Instead, increase the
977  * tick time so it will be about 10 seconds before we try and save
978  * again.
979  */
980  if (get_map_flags(pl->ob->map, NULL, pl->ob->x, pl->ob->y, NULL, NULL)&P_NO_CLERIC) {
981  pl->last_save_tick += 100;
982  } else {
983  save_player(pl->ob, 1);
984  pl->last_save_tick = pticks;
985  hiscore_check(pl->ob, 1);
986  }
987  }
988 #endif
989  } /* end of for loop for all the players */
990  } /* for flag */
991  for (pl = first_player; pl != NULL; pl = pl->next) {
992  int has_action = 1;
993 
994  pl->ob->weapon_speed_left += pl->ob->weapon_speed;
995  if (pl->ob->weapon_speed_left > 1.0)
996  pl->ob->weapon_speed_left = 1.0;
997 
999 
1000  if (settings.casting_time == TRUE) {
1001  if (pl->ob->casting_time > 0) {
1002  pl->ob->casting_time--;
1003  has_action = 0;
1004  }
1005  }
1006  /* If the character is idle (standing around resting) increase
1007  * regen rates.
1008  */
1009  if (has_action && pl->ob->speed_left > 0) {
1010  pl->ob->last_heal -= 2;
1011  pl->ob->last_sp -= 2;
1012  pl->ob->last_grace -= 2;
1013  pl->ob->last_eat += 2; /* Slow down food consumption */
1014  }
1015  do_some_living(pl->ob);
1016  }
1017 }
1018 
1026 static void process_players2(void) {
1027  player *pl;
1028 
1029  /* Then check if any players should use weapon-speed instead of speed */
1030  for (pl = first_player; pl != NULL; pl = pl->next) {
1031  /* The code that did weapon_sp handling here was out of place -
1032  * this isn't called until after the player has finished there
1033  * actions, and is thus out of place. All we do here is bounds
1034  * checking.
1035  */
1036  if (pl->has_hit) {
1037  /* This needs to be here - if the player is running, we need to
1038  * clear this each tick, but new commands are not being received
1039  * so execute_newserver_command() is never called
1040  */
1041  pl->has_hit = 0;
1042  } else if (pl->ob->speed_left > pl->ob->speed)
1043  pl->ob->speed_left = pl->ob->speed;
1044  }
1045 }
1046 
1047 #define SPEED_DEBUG
1048 
1049 static bool object_in_icecube(object *op) {
1050  return op->env != NULL && strcmp(op->env->arch->name, "icecube") == 0;
1051 }
1052 
1056 void process_events(void) {
1057  object *op;
1058  object marker;
1059  tag_t tag;
1060 
1061  process_players1();
1062 
1063  memset(&marker, 0, sizeof(object));
1064  /* Put marker object at beginning of active list */
1065  marker.active_next = active_objects;
1066 
1067  if (marker.active_next)
1068  marker.active_next->active_prev = &marker;
1069  marker.active_prev = NULL;
1070  active_objects = &marker;
1071 
1072  while (marker.active_next) {
1073  op = marker.active_next;
1074  tag = op->count;
1075 
1076  /* Move marker forward - swap op and marker */
1077  op->active_prev = marker.active_prev;
1078 
1079  if (op->active_prev)
1080  op->active_prev->active_next = op;
1081  else
1082  active_objects = op;
1083 
1084  marker.active_next = op->active_next;
1085 
1086  if (marker.active_next)
1087  marker.active_next->active_prev = &marker;
1088  marker.active_prev = op;
1089  op->active_next = &marker;
1090 
1091  /* Now process op */
1092  if (QUERY_FLAG(op, FLAG_FREED)) {
1093  LOG(llevError, "BUG: process_events(): Free object on list\n");
1094  op->speed = 0;
1096  continue;
1097  }
1098 
1099  /* I've seen occasional crashes due to this - the object is removed,
1100  * and thus the map it points to (last map it was on) may be bogus
1101  * The real bug is to try to find out the cause of this - someone
1102  * is probably calling object_remove() without either an insert_ob or
1103  * object_free_drop_inventory() afterwards, leaving an object dangling.
1104  * But I'd rather log this and continue on instead of crashing.
1105  * Don't remove players - when a player quits, the object is in
1106  * sort of a limbo, of removed, but something we want to keep
1107  * around.
1108  */
1109  if (QUERY_FLAG(op, FLAG_REMOVED)
1110  && op->type != PLAYER
1111  && op->map
1112  && op->map->in_memory != MAP_IN_MEMORY) {
1113  StringBuffer *sb;
1114  char *diff;
1115 
1116  LOG(llevError, "BUG: process_events(): Removed object on list\n");
1117  sb = stringbuffer_new();
1118  object_dump(op, sb);
1119  diff = stringbuffer_finish(sb);
1120  LOG(llevError, "%s\n", diff);
1121  free(diff);
1122  object_free(op, FREE_OBJ_NO_DESTROY_CALLBACK);
1123  continue;
1124  }
1125 
1126  if (!op->speed) {
1127  LOG(llevError, "BUG: process_events(): Object %s has no speed, but is on active list\n", op->arch->name);
1129  continue;
1130  }
1131 
1132  if (op->map == NULL
1133  && op->env == NULL
1134  && op->name
1135  && op->type != MAP) {
1136  LOG(llevError, "BUG: process_events(): Object without map or inventory is on active list: %s (%d)\n", op->name, op->count);
1137  op->speed = 0;
1139  continue;
1140  }
1141 
1142  /* Seen some cases where process_object() is crashing because
1143  * the object is on a swapped out map. But can't be sure if
1144  * something in the chain of events caused the object to
1145  * change maps or was just never removed - this will
1146  * give some clue as to its state before call to
1147  * process_object
1148  */
1149  if (op->map && op->map->in_memory != MAP_IN_MEMORY) {
1150  LOG(llevError, "BUG: process_events(): Processing object on swapped out map: %s (%d), map=%s\n", op->name, op->count, op->map->path);
1151  }
1152 
1153  /* Animate the object. Bug of feature that andim_speed
1154  * is based on ticks, and not the creatures speed?
1155  */
1156  if ((op->anim_speed && op->last_anim >= op->anim_speed)
1157  || (op->temp_animation && op->last_anim >= op->temp_anim_speed)) {
1158  op->state++;
1159  if ((op->type == PLAYER) || (op->type == MONSTER))
1160  animate_object(op, op->facing);
1161  else
1162  animate_object(op, op->direction);
1163  op->last_anim = 1;
1164  } else {
1165  op->last_anim++;
1166  }
1167 
1168  if (op->speed_left > 0) {
1169  // Players are special because their speed_left has already been
1170  // reduced in do_server(). Players effectively process every tick
1171  // so long they have non-zero speed left.
1172  if (op->type != PLAYER) {
1173  // Objects in icecubes decay at a slower rate
1174  if (object_in_icecube(op)) {
1175  op->speed_left -= 10;
1176  } else {
1177  op->speed_left -= 1;
1178  }
1179  }
1180  process_object(op);
1181  if (object_was_destroyed(op, tag))
1182  continue;
1183  } else {
1184  // Custom-made creatures for random maps can still have negative speeds, so catch that with FABS().
1185  op->speed_left += FABS(op->speed);
1186  }
1187  if (settings.casting_time == TRUE && op->casting_time > 0)
1188  op->casting_time--;
1189  }
1190 
1191  /* Remove marker object from active list */
1192  if (marker.active_prev != NULL)
1193  marker.active_prev->active_next = NULL;
1194  else
1195  active_objects = NULL;
1196 
1197  process_players2();
1198 }
1199 
1204 void clean_tmp_files(void) {
1205  mapstruct *m, *next;
1206  for (m = first_map; m != NULL; m = next) {
1207  next = m->next;
1208  if (m->in_memory == MAP_IN_MEMORY) {
1209  // Save all maps currently in memory, because they might contain
1210  // unique tiles that have not been written to disk.
1211  if (settings.recycle_tmp_maps) {
1212  // swap_map() also updates the write log.
1213  swap_map(m);
1214  } else {
1216  // FIXME: Unfortunately, save_map() also unnecessarily saves
1217  // non-unique tiles to a new temporary file, so we have to
1218  // get rid of it here.
1219  clean_tmp_map(m);
1220  }
1221  } else {
1222  // Remove the swap file.
1223  clean_tmp_map(m);
1224  }
1225  }
1226  write_todclock(); /* lets just write the clock here */
1227 }
1228 
1230 void cleanup(void) {
1231  LOG(llevInfo, "Cleaning up...\n");
1232  clean_tmp_files();
1234  accounts_save();
1235 
1236  close_modules();
1237 
1238 #ifdef MEMORY_DEBUG
1239  free_all_maps();
1240  free_style_maps();
1241 #endif
1242  cleanupPlugins();
1243  commands_clear();
1244 #ifdef MEMORY_DEBUG
1245  free_all_archs();
1247  free_all_images();
1249  free_all_recipes();
1251  free_all_god();
1252  free_all_anim();
1253  i18n_free();
1254  free_loader();
1255  free_globals();
1256  free_server();
1258  free_knowledge();
1259  free_quest();
1261  /* See what the string data that is out there that hasn't been freed. */
1262  /* LOG(llevDebug, "%s", ss_dump_table(0xff));*/
1263 #endif
1264  exit(0);
1265 }
1266 
1275 void leave(player *pl, int draw_exit) {
1276  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED)) {
1278  object_remove(pl->ob);
1279  }
1280 
1281  pl->socket.status = Ns_Dead;
1282  LOG(llevInfo, "logout: %s from %s\n", pl->ob->name, pl->socket.host);
1283 
1284  strcpy(pl->ob->contr->killer, "left");
1285  hiscore_check(pl->ob, 1);
1286 
1287  /* If this player is the captain of the transport, need to do
1288  * some extra work. By the time we get here, object_remove()
1289  * should have already been called.
1290  */
1291  if (pl->transport && pl->transport->contr == pl) {
1292  /* If inv is a non player, inv->contr will be NULL, but that
1293  * is OK.
1294  */
1295  if (pl->transport->inv)
1296  pl->transport->contr = pl->transport->inv->contr;
1297  else
1298  pl->transport->contr = NULL;
1299 
1300  if (pl->transport->contr) {
1301  char name[MAX_BUF];
1302 
1304  draw_ext_info_format(NDI_UNIQUE, 0, pl->transport->contr->ob,
1306  "%s has left. You are now the captain of %s",
1307  pl->ob->name, name);
1308  }
1309  }
1310 
1311  if (pl->ob->map) {
1312  if (pl->ob->map->in_memory == MAP_IN_MEMORY)
1313  pl->ob->map->timeout = MAP_TIMEOUT(pl->ob->map);
1314  pl->ob->map = NULL;
1315  }
1316  pl->ob->type = DEAD_OBJECT; /* To avoid problems with inventory window */
1317  party_leave(pl->ob);
1318  /* If a hidden dm dropped connection do not create
1319  * inconsistencies by showing that they have left the game
1320  */
1321  if (!(QUERY_FLAG(pl->ob, FLAG_WIZ) && pl->ob->contr->hidden)
1322  && (draw_exit) && (pl->state != ST_GET_NAME && pl->state != ST_GET_PASSWORD && pl->state != ST_CONFIRM_PASSWORD))
1325  "%s left the game.",
1326  pl->ob->name);
1327 }
1328 
1336 int forbid_play(void) {
1337 #if !defined(_IBMR2) && !defined(___IBMR2) && defined(PERM_FILE)
1338  char buf[MAX_BUF], day[MAX_BUF];
1339  FILE *fp;
1340  time_t clock;
1341  struct tm *tm;
1342  int i, start, stop, forbit = 0;
1343 
1344  clock = time(NULL);
1345  tm = (struct tm *)localtime(&clock);
1346 
1347  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, PERM_FILE);
1348  if ((fp = fopen(buf, "r")) == NULL)
1349  return 0;
1350 
1351  while (fgets(buf, sizeof(buf), fp)) {
1352  if (buf[0] == '#')
1353  continue;
1354  if (!strncmp(buf, "msg", 3)) {
1355  if (forbit)
1356  while (fgets(buf, sizeof(buf), fp)) /* print message */
1357  fputs(buf, logfile);
1358  break;
1359  } else if (sscanf(buf, "%s %d%*c%d\n", day, &start, &stop) != 3) {
1360  LOG(llevDebug, "Warning: Incomplete line in permission file ignored.\n");
1361  continue;
1362  }
1363 
1364  for (i = 0; i < 7; i++) {
1365  if (!strncmp(buf, days[i], 3)
1366  && (tm->tm_wday == i)
1367  && (tm->tm_hour >= start)
1368  && (tm->tm_hour < stop))
1369  forbit = 1;
1370  }
1371  }
1372 
1373  fclose(fp);
1374 
1375  return forbit;
1376 #else
1377  return 0;
1378 #endif
1379 }
1380 
1381 static void do_shutdown(void) {
1383  MSG_TYPE_ADMIN_DM, "The server has shut down.");
1384 
1385  /* TODO: Kick everyone out and save player files? */
1386  cleanup();
1387 }
1388 
1392 static bool check_shutdown(void) {
1393  if (shutdown_flag == 1) {
1394  LOG(llevInfo, "Received SIGINT; shutting down...\n");
1395  return true;
1396  }
1397 
1398  /* Zero means that no timed shutdown is pending. */
1399  if (cmd_shutdown_time == 0) {
1400  return false;
1401  }
1402 
1403  /* If a timed shutdown is coming, remind players periodically. */
1404  static int next_warn = 0; // FIXME: next_warn not reset if shutdown cancelled
1405  time_t time_left = cmd_shutdown_time - time(NULL);
1406 
1407  for (unsigned int i = next_warn; i < sizeof(shutdown_warn_times) / sizeof(int); i++) {
1408  if (shutdown_warn_times[i] == (int)ceil(time_left / 60.0)) {
1411  "Server shutting down in %d minutes.", shutdown_warn_times[i]);
1412  next_warn = i + 1;
1413  return false;
1414  }
1415  }
1416 
1417  if (time_left <= 0) {
1418  return true;
1419  }
1420  return false;
1421 }
1422 
1427 void login_check_shutdown(object* const op) {
1428  if (cmd_shutdown_time == 0) {
1429  return;
1430  }
1431 
1432  time_t time_left = cmd_shutdown_time - time(NULL);
1433  if (time_left <= 60*shutdown_warn_times[0]) {
1436  "Server shutting down in %d minutes.", time_left / 60);
1437  }
1438 }
1439 
1440 extern unsigned long todtick;
1441 
1456 static void do_specials(void) {
1457  if (check_shutdown()) {
1458  do_shutdown();
1459  }
1460 
1461 #ifdef CS_LOGSTATS
1462  if ((time(NULL)-cst_lst.time_start) >= CS_LOGTIME)
1463  write_cs_stats();
1464 #endif
1465 
1466  if (!(pticks%10))
1468 
1469 #ifdef WATCHDOG
1470  if (!(pticks%503))
1471  watchdog();
1472 #endif
1473 
1474  if (!(pticks%PTICKS_PER_CLOCK))
1475  tick_the_clock();
1476 
1477  if (!(pticks%509))
1478  flush_old_maps(); /* Clears the tmp-files of maps which have reset */
1479 
1480  if (!(pticks%2503))
1481  fix_weight(); /* Hack to fix weightproblems caused by bugs */
1482 
1483  if (!(pticks%2521))
1484  metaserver_update(); /* 2500 ticks is about 5 minutes */
1485 
1486  if (!(pticks%2531))
1487  accounts_save();
1488 
1489  if (!(pticks%5003))
1491 
1492  if (!(pticks%5009))
1494 
1495  if (!(pticks%5011))
1497 
1498  if (!(pticks%12503))
1499  fix_luck();
1500 }
1501 
1510 void server_main(int argc, char *argv[]) {
1511 #ifdef WIN32 /* ---win32 this sets the win32 from 0d0a to 0a handling */
1512  _fmode = _O_BINARY;
1513 #endif
1514 
1515 #ifndef WIN32
1516  /* Here we check that we aren't root or suid */
1517  if (getuid() == 0 || geteuid() == 0) {
1518  fprintf(stderr,
1519  "Running crossfire-server as root is a bad idea; aborting!\n"
1520  "Please run it again as a normal, unprivileged user.\n");
1521  exit(EXIT_FAILURE);
1522  }
1523 #endif
1524 
1525 #ifdef DEBUG_MALLOC_LEVEL
1526  malloc_debug(DEBUG_MALLOC_LEVEL);
1527 #endif
1528 
1529  init(argc, argv);
1530  initPlugins(); /* GROS - Init the Plugins */
1531  // Give feedback that loading is complete. This prevents confusion on when it is done loading.
1532  LOG(llevInfo, "Initialization complete. Waiting for connections.\n");
1533 #ifdef WIN32
1534  while (bRunning) {
1535 #else
1536  while (TRUE) {
1537 #endif
1538  nroferrors = 0;
1539 
1540  tick_game_time();
1541  do_server();
1542  process_events(); /* "do" something with objects with speed */
1543  cftimer_process_timers(); /* Process the crossfire Timers */
1545  check_active_maps(); /* Removes unused maps after a certain timeout */
1546  do_specials(); /* Routines called from time to time. */
1547  update_players();
1548  }
1549 
1550  /* This is unreachable. */
1551  abort();
1552 }
Settings::casting_time
uint8_t casting_time
Definition: global.h:265
fix_weight
void fix_weight(void)
Definition: player.c:3843
give.next
def next
Definition: give.py:44
ready_map_name
mapstruct * ready_map_name(const char *name, int flags)
Definition: map.c:1778
handle_newcs_player
int handle_newcs_player(object *op)
Definition: player.c:3050
path.h
global.h
object_free
void object_free(object *ob, int flags)
Definition: object.c:1573
add_string
sstring add_string(const char *str)
Definition: shstr.c:124
random_map.h
tick_the_clock
void tick_the_clock(void)
Definition: weather.c:96
object_remove
void object_remove(object *op)
Definition: object.c:1814
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.c:57
pets_terminate_all
void pets_terminate_all(object *owner)
Definition: pets.c:225
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Definition: object.c:902
pl::transport
object * transport
Definition: player.h:199
ST_GET_PASSWORD
#define ST_GET_PASSWORD
Definition: define.h:547
Settings::recycle_tmp_maps
uint8_t recycle_tmp_maps
Definition: global.h:267
login_check_shutdown
void login_check_shutdown(object *const op)
Definition: server.c:1427
Settings::emergency_y
uint16_t emergency_y
Definition: global.h:295
llevError
@ llevError
Definition: logger.h:11
RMParms::origin_map
char origin_map[RM_SIZE]
Definition: random_map.h:55
FABS
#define FABS(x)
Definition: define.h:22
MSG_TYPE_ADMIN_PLAYER
#define MSG_TYPE_ADMIN_PLAYER
Definition: newclient.h:496
PTICKS_PER_CLOCK
#define PTICKS_PER_CLOCK
Definition: tod.h:11
PORTAL_DESTINATION_NAME
#define PORTAL_DESTINATION_NAME
days
static const char * days[]
Definition: server.c:51
diamondslots.x
x
Definition: diamondslots.py:15
clean_tmp_map
void clean_tmp_map(mapstruct *m)
Definition: map.c:1958
SIZEOFFREE1
#define SIZEOFFREE1
Definition: define.h:153
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
server_main
void server_main(int argc, char *argv[])
Definition: server.c:1510
tick_game_time
void tick_game_time()
Definition: time.c:180
flush_old_maps
void flush_old_maps(void)
Definition: swap.c:247
ST_GET_NAME
#define ST_GET_NAME
Definition: define.h:546
process_events
void process_events(void)
Definition: server.c:1056
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2302
object_new
object * object_new(void)
Definition: object.c:1236
Settings::crypt_mode
uint8_t crypt_mode
Definition: global.h:325
c
static event_registration c
Definition: citylife.cpp:410
free_all_artifacts
void free_all_artifacts(void)
Definition: artifact.c:125
pl::socket
socket_struct socket
Definition: player.h:94
clean_friendly_list
void clean_friendly_list(void)
Definition: friend.c:111
FLAG_UNIQUE
#define FLAG_UNIQUE
Definition: define.h:287
pl
Definition: player.h:92
accounts_save
void accounts_save(void)
Definition: account.c:260
EXIT_PATH
#define EXIT_PATH(xyz)
Definition: define.h:439
do_server
void do_server(void)
Definition: loop.c:558
RMParms::Ysize
int Ysize
Definition: random_map.h:75
MAP_MAXTIMEOUT
#define MAP_MAXTIMEOUT
Definition: config.h:399
set_random_map_variable
int set_random_map_variable(RMParms *rp, const char *buf)
Definition: reader.c:2579
guildjoin.ob
ob
Definition: guildjoin.py:42
python_event.path
path
Definition: python_event.py:11
unclean_path
static char * unclean_path(const char *src, char *newpath, int size)
Definition: server.c:353
leave
void leave(player *pl, int draw_exit)
Definition: server.c:1275
do_follow
static void do_follow(player *pl)
Definition: server.c:888
mad_mage_user.file
file
Definition: mad_mage_user.py:15
move_player
int move_player(object *op, int dir)
Definition: player.c:2912
pl::ob
object * ob
Definition: player.h:162
create_pathname
char * create_pathname(const char *name, char *buf, size_t size)
Definition: map.c:113
free_all_newserver
void free_all_newserver(void)
Definition: init.c:395
MAP_PLAYER_UNIQUE
#define MAP_PLAYER_UNIQUE
Definition: map.h:97
path_combine_and_normalize
char * path_combine_and_normalize(const char *src, const char *dst, char *path, size_t size)
Definition: path.c:172
enter_map
static void enter_map(object *op, mapstruct *newmap, int x, int y)
Definition: server.c:179
ob_blocked
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Definition: map.c:498
enter_player_savebed
void enter_player_savebed(object *op)
Definition: server.c:138
free_all_recipes
void free_all_recipes(void)
Definition: recipe.c:679
RMParms::origin_y
int origin_y
Definition: random_map.h:88
Ice.tmp
int tmp
Definition: Ice.py:207
free_knowledge
void free_knowledge(void)
Definition: knowledge.c:1274
remove_friendly_object
void remove_friendly_object(object *op)
Definition: friend.c:56
Settings::emergency_x
uint16_t emergency_x
Definition: global.h:295
flags
static const flag_definition flags[]
Definition: gridarta-types-convert.c:101
cleanupPlugins
void cleanupPlugins(void)
Definition: plugins.c:4569
do_shutdown
static void do_shutdown(void)
Definition: server.c:1381
get_rangevector
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
Definition: map.c:2535
object_free_all_data
void object_free_all_data(void)
Definition: object.c:754
range_golem
@ range_golem
Definition: player.h:21
first_map
EXTERN mapstruct * first_map
Definition: global.h:116
todtick
unsigned long todtick
Definition: init.c:397
MSG_TYPE_MISC
#define MSG_TYPE_MISC
Definition: newclient.h:413
party_obsolete_parties
void party_obsolete_parties(void)
Definition: party.c:215
initPlugins
void initPlugins(void)
Definition: plugins.c:4519
hiscore_check
void hiscore_check(object *op, int quiet)
Definition: hiscore.c:348
version.h
RMParms
Definition: random_map.h:14
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:404
active_objects
object * active_objects
Definition: object.c:285
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.c:288
freearr_y
short freearr_y[SIZEOFFREE]
Definition: object.c:294
ob_apply
method_ret ob_apply(object *op, object *applier, int aflags)
Definition: ob_methods.c:44
check_shutdown
static bool check_shutdown(void)
Definition: server.c:1392
settings
struct Settings settings
Definition: init.c:39
animate_object
void animate_object(object *op, int dir)
Definition: anim.c:43
Ns_Dead
@ Ns_Dead
Definition: newserver.h:67
MSG_TYPE_ADMIN_DM
#define MSG_TYPE_ADMIN_DM
Definition: newclient.h:497
free_string
void free_string(sstring str)
Definition: shstr.c:280
CS_Stats::time_start
time_t time_start
Definition: newclient.h:698
RMParms::origin_x
int origin_x
Definition: random_map.h:89
m
static event_registration m
Definition: citylife.cpp:410
clean_tmp_files
void clean_tmp_files(void)
Definition: server.c:1204
mapdef::players
int16_t players
Definition: map.h:343
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Definition: map.h:131
apply_auto_fix
void apply_auto_fix(mapstruct *m)
Definition: main.c:259
pl::next
struct pl * next
Definition: player.h:93
MAP_MINTIMEOUT
#define MAP_MINTIMEOUT
Definition: config.h:401
object_find_by_type_and_slaying
object * object_find_by_type_and_slaying(const object *who, int type, const char *slaying)
Definition: object.c:4174
set_map_timeout
void set_map_timeout(mapstruct *oldmap)
Definition: server.c:292
object_on_exit
static bool object_on_exit(object *ob, object *exit)
Definition: server.c:877
EVENT_CLOCK
#define EVENT_CLOCK
Definition: events.h:39
pl::state
uint8_t state
Definition: player.h:118
object_copy
void object_copy(const object *src_ob, object *dest_ob)
Definition: object.c:1047
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:584
object_dump
void object_dump(const object *op, StringBuffer *sb)
Definition: object.c:638
RMParms::final_map
char final_map[RM_SIZE]
Definition: random_map.h:57
party_leave
void party_leave(object *op)
Definition: party.c:123
EVENT_MAPENTER
#define EVENT_MAPENTER
Definition: events.h:45
object_in_icecube
static bool object_in_icecube(object *op)
Definition: server.c:1049
free_quest
void free_quest(void)
Definition: quest.c:1280
make_face_from_files.str
str
Definition: make_face_from_files.py:24
crypt_string
static char const * crypt_string(char const str[static 1], char const *salt)
Definition: server.c:70
FLAG_FREED
#define FLAG_FREED
Definition: define.h:233
socket_struct::host
char * host
Definition: newserver.h:100
first_player
EXTERN player * first_player
Definition: global.h:115
FLAG_DAMNED
#define FLAG_DAMNED
Definition: define.h:317
move_towards
static int move_towards(object *ob, object *towards, unsigned int mindist)
Definition: server.c:864
CFweardisguise.tag
tag
Definition: CFweardisguise.py:25
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.c:76
player_map_change_common
void player_map_change_common(object *op, mapstruct *const oldmap, mapstruct *const newmap)
Definition: server.c:270
pl::has_hit
uint32_t has_hit
Definition: player.h:131
mapdef::timeout
int32_t timeout
Definition: map.h:340
pl::followed_player
sstring followed_player
Definition: player.h:203
rproto.h
RMParms::region
struct regiondef * region
Definition: random_map.h:96
Settings::confdir
const char * confdir
Definition: global.h:242
sproto.h
nroferrors
EXTERN long nroferrors
Definition: global.h:128
mapdef
Definition: map.h:324
do_specials
static void do_specials(void)
Definition: server.c:1456
cftimer_process_timers
void cftimer_process_timers(void)
Definition: timers.c:44
logfile
EXTERN FILE * logfile
Definition: global.h:136
newhash
char const * newhash(char const password[static 1])
Definition: server.c:101
clean_path
static char * clean_path(const char *file, char *newpath, int size)
Definition: server.c:325
MAP_WIDTH
#define MAP_WIDTH(m)
Definition: map.h:78
mapdef::is_template
uint32_t is_template
Definition: map.h:337
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.c:220
SIZEOFFREE
#define SIZEOFFREE
Definition: define.h:155
EXIT_X
#define EXIT_X(xyz)
Definition: define.h:441
MAX_BUF
#define MAX_BUF
Definition: define.h:35
object_get_multi_size
void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy)
Definition: object.c:4739
PERM_FILE
#define PERM_FILE
Definition: config.h:446
SAVE_MODE_NORMAL
#define SAVE_MODE_NORMAL
Definition: map.h:121
RANDOM
#define RANDOM()
Definition: define.h:642
check_password
bool check_password(const char *typed, const char *crypted)
Definition: server.c:114
free_loader
void free_loader(void)
Definition: loader.c:5296
StringBuffer
Definition: stringbuffer.c:25
FREE_AND_CLEAR_STR
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:196
free_quest_definitions
void free_quest_definitions(void)
Definition: quest.c:1298
enter_player_maplevel
void enter_player_maplevel(object *op)
Definition: server.c:676
bRunning
int bRunning
save_map
int save_map(mapstruct *m, int flag)
Definition: map.c:1416
cleanup
void cleanup(void)
Definition: server.c:1230
MSG_TYPE_COMMAND_FAILURE
#define MSG_TYPE_COMMAND_FAILURE
Definition: newclient.h:531
can_follow
bool can_follow(object *, player *)
Definition: c_wiz.c:2731
socket_struct::sounds_this_tick
int8_t sounds_this_tick
Definition: newserver.h:121
ST_PLAYING
#define ST_PLAYING
Definition: define.h:541
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
swap_map
int swap_map(mapstruct *map)
Definition: swap.c:135
write_book_archive
void write_book_archive(void)
Definition: readable.c:2042
Settings::emergency_mapname
char * emergency_mapname
Definition: global.h:294
enter_unique_map
static void enter_unique_map(object *op, object *exit_ob)
Definition: server.c:605
llevInfo
@ llevInfo
Definition: logger.h:12
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
pticks
uint32_t pticks
Definition: time.c:45
get_region_by_map
region * get_region_by_map(mapstruct *m)
Definition: region.c:74
roll-o-matic.stop
def stop()
Definition: roll-o-matic.py:49
SIZEOFFREE2
#define SIZEOFFREE2
Definition: define.h:154
free_all_maps
void free_all_maps(void)
Definition: map.c:1967
free_style_maps
void free_style_maps(void)
Definition: style.c:312
ST_CONFIRM_PASSWORD
#define ST_CONFIRM_PASSWORD
Definition: define.h:548
generate_random_map
mapstruct * generate_random_map(const char *OutFileName, RMParms *RP, char **use_layout)
Definition: random_map.c:74
metaserver_update
void metaserver_update(void)
Definition: metaserver.c:52
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
write_cs_stats
void write_cs_stats(void)
give.op
op
Definition: give.py:33
object_find_free_spot
int object_find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop)
Definition: object.c:3517
NDI_ALL
#define NDI_ALL
Definition: newclient.h:263
socket_struct::status
enum Sock_Status status
Definition: newserver.h:90
update_players
void update_players(void)
Definition: loop.c:700
enter_exit
void enter_exit(object *op, object *exit_ob)
Definition: server.c:721
EVENT_MAPLEAVE
#define EVENT_MAPLEAVE
Definition: events.h:46
process_players2
static void process_players2(void)
Definition: server.c:1026
rv_vector
Definition: map.h:379
init
void init(int argc, char **argv)
Definition: init.c:1108
hit_player
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
Definition: attack.c:1853
EXIT_Y
#define EXIT_Y(xyz)
Definition: define.h:442
diamondslots.y
y
Definition: diamondslots.py:16
free_server
void free_server(void)
Definition: init.c:1148
buf
StringBuffer * buf
Definition: readable.c:1606
MAP_HEIGHT
#define MAP_HEIGHT(m)
Definition: map.h:80
MAP_ENTER_Y
#define MAP_ENTER_Y(m)
Definition: map.h:87
NDI_DK_ORANGE
#define NDI_DK_ORANGE
Definition: newclient.h:248
find_player_partial_name
player * find_player_partial_name(const char *plname)
Definition: player.c:111
object_update_speed
void object_update_speed(object *op)
Definition: object.c:1311
watchdog
void watchdog(void)
map_newmap_cmd
void map_newmap_cmd(socket_struct *ns)
Definition: request.c:620
process_players1
static void process_players1(void)
Definition: server.c:934
enter_fixed_template_map
static void enter_fixed_template_map(object *pl, object *exit_ob)
Definition: server.c:446
pets_remove_all
void pets_remove_all(void)
Definition: pets.c:248
make_face_from_files.int
int
Definition: make_face_from_files.py:26
find_dir_2
int find_dir_2(int x, int y)
Definition: object.c:3693
forbid_play
int forbid_play(void)
Definition: server.c:1336
replace
void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
Definition: utils.c:354
save_player
int save_player(object *op, int flag)
Definition: login.c:230
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:2075
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:309
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.c:1541
pl::ticks_played
uint32_t ticks_played
Definition: player.h:207
MAP_ENTER_X
#define MAP_ENTER_X(m)
Definition: map.h:85
shutdown_warn_times
static const int shutdown_warn_times[]
Definition: server.c:48
do_some_living
void do_some_living(object *op)
Definition: player.c:3236
P_NO_CLERIC
#define P_NO_CLERIC
Definition: map.h:239
fix_luck
void fix_luck(void)
Definition: player.c:3859
check_active_maps
void check_active_maps(void)
Definition: swap.c:196
commands_clear
void commands_clear()
Definition: commands.cpp:333
AP_UNAPPLY
#define AP_UNAPPLY
Definition: define.h:575
server.h
close_modules
void close_modules()
Definition: init.c:80
tod.h
mapdef::path
char path[HUGE_BUF]
Definition: map.h:364
MAP_TIMEOUT
#define MAP_TIMEOUT(m)
Definition: map.h:66
TRUE
#define TRUE
Definition: compat.h:11
shutdown_flag
volatile sig_atomic_t shutdown_flag
Definition: server.c:53
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.c:311
CS_LOGTIME
#define CS_LOGTIME
Definition: config.h:188
cst_lst
CS_Stats cst_lst
Definition: newclient.h:701
enter_random_map
static void enter_random_map(object *pl, object *exit_ob)
Definition: server.c:379
free_all_god
void free_all_god(void)
Definition: holy.c:336
rv_vector::direction
int direction
Definition: map.h:383
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
free_globals
void free_globals(void)
Definition: init.c:313
MSG_TYPE_ADMIN
#define MSG_TYPE_ADMIN
Definition: newclient.h:402
write_todclock
void write_todclock(void)
Definition: init.c:403
rv_vector::distance
unsigned int distance
Definition: map.h:380
RMParms::Xsize
int Xsize
Definition: random_map.h:74
free_all_readable
void free_all_readable(void)
Definition: readable.c:2006
process_object
int process_object(object *op)
Definition: time.c:796
mapdef::unique
uint32_t unique
Definition: map.h:336
cmd_shutdown_time
int cmd_shutdown_time
Definition: c_wiz.c:43
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:319
i18n_free
void i18n_free(void)
Definition: languages.c:239
knowledge_process_incremental
void knowledge_process_incremental(void)
Definition: knowledge.c:1433
object.h
events_execute_global_event
void events_execute_global_event(int eventcode,...)
Definition: events.cpp:27
llevDebug
@ llevDebug
Definition: logger.h:13
mapfile_load
mapstruct * mapfile_load(const char *map, int flags)
Definition: map.c:1210
AUTOSAVE
#define AUTOSAVE
Definition: config.h:586
give.name
name
Definition: give.py:27
player_update_bg_music
void player_update_bg_music(object *player)
create_template_pathname
void create_template_pathname(const char *name, char *buf, size_t size)
Definition: map.c:154
enter_random_template_map
static void enter_random_template_map(object *pl, object *exit_ob)
Definition: server.c:537
Settings::localdir
const char * localdir
Definition: global.h:244