Crossfire Server, Trunk  R22010
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) || (defined(__FreeBSD__))
72  // Legacy configuration: use crypt everywhere but on Windows and FreeBSD
73  if (settings.crypt_mode == 0) {
74  return str;
75  }
76 #endif
77  char s[3];
78 
79  if (salt == NULL) {
80  /* Generate a two-character salt for the DES cipher.
81  * We want the salt to be in this character set.
82  */
83  static const char *const c =
84  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
85  s[0] = c[RANDOM()%(int)strlen(c)],
86  s[1] = c[RANDOM()%(int)strlen(c)];
87  } else {
88  s[0] = salt[0],
89  s[1] = salt[1];
90  }
91  s[2] = '\0';
92 
93  return crypt(str, s);
94 }
95 
96 char const* newhash(char const password[static 1]) {
97  return crypt_string(password, NULL);
98 }
99 
109 bool check_password(const char *typed, const char *crypted) {
110  // An empty hashed password only matches an empty input password.
111  if (strlen(crypted) == 0) {
112  return strlen(typed) == 0 ? true : false;
113  }
114 
115  const char *typed_hashed = crypt_string(typed, crypted);
116  if (typed_hashed != NULL) {
117  return strcmp(typed_hashed, crypted) == 0;
118  } else {
119  LOG(llevError, "Could not check password with stored hash %s\n", crypted);
120  return false;
121  }
122 }
123 
133 void enter_player_savebed(object *op) {
134  mapstruct *oldmap = op->map;
135  object *tmp;
136 
137  tmp = object_new();
138 
139  EXIT_PATH(tmp) = add_string(op->contr->savebed_map);
140  EXIT_X(tmp) = op->contr->bed_x;
141  EXIT_Y(tmp) = op->contr->bed_y;
142  enter_exit(op, tmp);
143  /* If the player has not changed maps and the name does not match
144  * that of the savebed, his savebed map is gone. Lets go back
145  * to the emergency path. Update what the players savebed is
146  * while we're at it.
147  */
148  if (oldmap == op->map && strcmp(op->contr->savebed_map, oldmap->path)) {
149  LOG(llevDebug, "Player %s savebed location %s is invalid - going to emergency location (%s)\n",
150  settings.emergency_mapname, op->name, op->contr->savebed_map);
151  safe_strncpy(op->contr->savebed_map, settings.emergency_mapname, MAX_BUF);
152  op->contr->bed_x = settings.emergency_x;
153  op->contr->bed_y = settings.emergency_y;
154  free_string(op->contr->savebed_map);
155  EXIT_PATH(tmp) = add_string(op->contr->savebed_map);
156  EXIT_X(tmp) = op->contr->bed_x;
157  EXIT_Y(tmp) = op->contr->bed_y;
158  enter_exit(op, tmp);
159  }
160  object_free(tmp, FREE_OBJ_NO_DESTROY_CALLBACK);
161 }
162 
174 static void enter_map(object *op, mapstruct *newmap, int x, int y) {
175  mapstruct *oldmap = op->map;
176 
177  if (out_of_map(newmap, x, y)) {
178  LOG(llevError, "enter_map: supplied coordinates are not within the map! (%s: %d, %d)\n", newmap->path, x, y);
179  /* If op has invalid (probably -1,-1) coordinates, force them to a correct value, else issues later on. */
180  if (op->x == x)
181  op->x = MAP_ENTER_X(newmap);
182  if (op->y == y)
183  op->y = MAP_ENTER_Y(newmap);
184  x = MAP_ENTER_X(newmap);
185  y = MAP_ENTER_Y(newmap);
186  if (out_of_map(newmap, x, y)) {
187  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));
189  "The exit is closed");
190  return;
191  }
192  }
193  /* try to find a spot for the player */
194  if (ob_blocked(op, newmap, x, y)) { /* First choice blocked */
195  /* We try to find a spot for the player, starting closest in.
196  * We could use object_find_first_free_spot(), but that doesn't randomize it at all,
197  * So for example, if the north space is free, you would always end up there even
198  * if other spaces around are available.
199  * Note that for the second and third calls, we could start at a position other
200  * than one, but then we could end up on the other side of walls and so forth.
201  */
202  int i = object_find_free_spot(op, newmap, x, y, 1, SIZEOFFREE1+1);
203  if (i == -1) {
204  i = object_find_free_spot(op, newmap, x, y, 1, SIZEOFFREE2+1);
205  if (i == -1)
206  i = object_find_free_spot(op, newmap, x, y, 1, SIZEOFFREE);
207  }
208  if (i != -1) {
209  x += freearr_x[i];
210  y += freearr_y[i];
211  } else {
212  /* not much we can do in this case. */
213  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);
214  }
215  } /* end if looking for free spot */
216 
217  /* If it is a player login, he has yet to be inserted anyplace.
218  * otherwise, we need to deal with removing the playe here.
219  */
220  if (!QUERY_FLAG(op, FLAG_REMOVED))
221  object_remove(op);
222  /* object_remove clears these so they must be reset after the object_remove() call */
223  object_insert_in_map_at(op, newmap, NULL, INS_NO_WALK_ON, x, y);
224 
225  object_set_enemy(op, NULL);
226 
227  if (op->contr) {
228  safe_strncpy(op->contr->maplevel, newmap->path,
229  sizeof(op->contr->maplevel));
230  op->contr->count = 0;
231  }
232 
233  /* Update any golems */
234  if (op->type == PLAYER && op->contr->ranges[range_golem] != NULL) {
235  int i = object_find_free_spot(op->contr->ranges[range_golem], newmap, x, y, 1, SIZEOFFREE);
236  object_remove(op->contr->ranges[range_golem]);
237  if (i == -1) {
238  remove_friendly_object(op->contr->ranges[range_golem]);
239  object_free_drop_inventory(op->contr->ranges[range_golem]);
240  op->contr->ranges[range_golem] = NULL;
241  op->contr->golem_count = 0;
242  } else {
243  object_insert_in_map_at(op->contr->ranges[range_golem], newmap, NULL, 0, x+freearr_x[i], y+freearr_y[i]);
244  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);
245  }
246  }
247  op->direction = 0;
248 
249  /* since the players map is already loaded, we don't need to worry
250  * about pending objects.
251  */
252  pets_remove_all();
253 
254  /* If the player is changing maps, we need to do some special things
255  * Do this after the player is on the new map - otherwise the force swap of the
256  * old map does not work.
257  */
258  if (oldmap != newmap) {
259  player_map_change_common(op, oldmap, newmap);
260  }
261 
262  map_newmap_cmd(&op->contr->socket);
263 }
264 
265 void player_map_change_common(object* op, mapstruct* const oldmap,
266  mapstruct* const newmap) {
267  if (oldmap != NULL) {
269 
270  /* can be less than zero due to errors in tracking this */
271  if (oldmap->players <= 0) {
272  set_map_timeout(oldmap);
273  }
274  }
275 
277  newmap->timeout = 0;
279 }
280 
287 void set_map_timeout(mapstruct *oldmap) {
288 #if MAP_MAXTIMEOUT
289  oldmap->timeout = MAP_TIMEOUT(oldmap);
290  /* Do MINTIMEOUT first, so that MAXTIMEOUT is used if that is
291  * lower than the min value.
292  */
293 #if MAP_MINTIMEOUT
294  if (oldmap->timeout < MAP_MINTIMEOUT) {
295  oldmap->timeout = MAP_MINTIMEOUT;
296  }
297 #endif
298  if (oldmap->timeout > MAP_MAXTIMEOUT) {
299  oldmap->timeout = MAP_MAXTIMEOUT;
300  }
301 #else
302  /* save out the map */
303  swap_map(oldmap);
304 #endif /* MAP_MAXTIMEOUT */
305 }
306 
320 static char *clean_path(const char *file, char *newpath, int size) {
321  char *cp;
322 
323  strlcpy(newpath, file, size);
324  for (cp = newpath; *cp != '\0'; cp++) {
325  if (*cp == '/')
326  *cp = '_';
327  }
328  return newpath;
329 }
330 
348 static char *unclean_path(const char *src, char *newpath, int size) {
349  char *cp;
350 
351  cp = strrchr(src, '/');
352  if (cp)
353  strlcpy(newpath, cp+1, size);
354  else
355  strlcpy(newpath, src, size);
356 
357  for (cp = newpath; *cp != '\0'; cp++) {
358  if (*cp == '_')
359  *cp = '/';
360  }
361  return newpath;
362 }
363 
364 
374 static void enter_random_map(object *pl, object *exit_ob) {
375  mapstruct *new_map;
376  char newmap_name[HUGE_BUF], buf[HUGE_BUF], *cp;
377  static int reference_number = 0;
378  RMParms rp;
379 
380  memset(&rp, 0, sizeof(RMParms));
381  rp.Xsize = -1;
382  rp.Ysize = -1;
383  rp.region = get_region_by_map(exit_ob->map);
384  if (exit_ob->msg)
385  set_random_map_variable(&rp, exit_ob->msg);
386  rp.origin_x = exit_ob->x;
387  rp.origin_y = exit_ob->y;
388  safe_strncpy(rp.origin_map, pl->map->path, sizeof(rp.origin_map));
389 
390  /* If we have a final_map, use it as a base name to give some clue
391  * as where the player is. Otherwise, use the origin map.
392  * Take the last component (after the last slash) to give
393  * shorter names without bogus slashes.
394  */
395  if (rp.final_map[0]) {
396  cp = strrchr(rp.final_map, '/');
397  if (!cp)
398  cp = rp.final_map;
399  } else {
400  cp = strrchr(rp.origin_map, '/');
401  if (!cp)
402  cp = rp.origin_map;
403  /* Need to strip of any trailing digits, if it has them */
404  strlcpy(buf, cp, sizeof(buf));
405  while (isdigit(buf[strlen(buf)-1]))
406  buf[strlen(buf)-1] = 0;
407  cp = buf;
408  }
409 
410  snprintf(newmap_name, sizeof(newmap_name), "/random/%s%04d", cp+1, reference_number++);
411 
412  /* now to generate the actual map. */
413  new_map = generate_random_map(newmap_name, &rp, NULL);
414 
415  /* Update the exit_ob so it now points directly at the newly created
416  * random maps. Not that it is likely to happen, but it does mean that a
417  * exit in a unique map leading to a random map will not work properly.
418  * It also means that if the created random map gets reset before
419  * the exit leading to it, that the exit will no longer work.
420  */
421  if (new_map) {
422  int x, y;
423 
424  x = EXIT_X(exit_ob) = MAP_ENTER_X(new_map);
425  y = EXIT_Y(exit_ob) = MAP_ENTER_Y(new_map);
426  EXIT_PATH(exit_ob) = add_string(newmap_name);
427  strlcpy(new_map->path, newmap_name, sizeof(new_map->path));
428  enter_map(pl, new_map, x, y);
429  }
430 }
431 
441 static void enter_fixed_template_map(object *pl, object *exit_ob) {
442  mapstruct *new_map;
443  char tmpnum[32], exitpath[HUGE_BUF], resultname[HUGE_BUF], tmpstring[HUGE_BUF], *sourcemap;
444  char sourcemap_buf[HUGE_BUF];
445  char new_map_name[MAX_BUF];
446 
447  /* Split the exit path string into two parts, one
448  * for where to store the map, and one for were
449  * to generate the map from.
450  */
451  strlcpy(exitpath, EXIT_PATH(exit_ob)+2, sizeof(exitpath));
452  sourcemap = strchr(exitpath, '!');
453  if (!sourcemap) {
456  "The %s is closed.",
457  exit_ob->name);
458  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);
459  return;
460  }
461  *sourcemap++ = '\0';
462 
463  /* If we are not coming from a template map, we can use relative directories
464  * for the map to generate from.
465  */
466  if (!exit_ob->map->is_template) {
467  /* We can't use exitpath directly, as sourcemap points there. */
468  path_combine_and_normalize(exit_ob->map->path, sourcemap, sourcemap_buf, sizeof(sourcemap_buf));
469  sourcemap = sourcemap_buf;
470  }
471 
472  /* Do replacement of %x, %y, and %n to the x coord of the exit, the y coord
473  * of the exit, and the name of the map the exit is on, respectively.
474  */
475  snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->x);
476  replace(exitpath, "%x", tmpnum, resultname, sizeof(resultname));
477 
478  snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->y);
479  strlcpy(tmpstring, resultname, sizeof(tmpstring));
480  replace(tmpstring, "%y", tmpnum, resultname, sizeof(resultname));
481 
482  strlcpy(tmpstring, resultname, sizeof(tmpstring));
483  replace(tmpstring, "%n", exit_ob->map->name, resultname, sizeof(resultname));
484 
485  /* If we are coming from another template map, use reletive paths unless
486  * indicated otherwise.
487  */
488  if (exit_ob->map->is_template && (resultname[0] != '/')) {
489  path_combine_and_normalize(exit_ob->map->path, resultname, new_map_name, sizeof(new_map_name));
490  } else {
491  create_template_pathname(resultname, new_map_name, sizeof(new_map_name));
492  }
493 
494  /* Attempt to load the map, if unable to, then
495  * create the map from the template.
496  */
497  new_map = ready_map_name(new_map_name, MAP_PLAYER_UNIQUE);
498  if (!new_map) {
499  char path[MAX_BUF];
500  create_pathname(sourcemap, path, MAX_BUF);
501  new_map = mapfile_load(path, MAP_PLAYER_UNIQUE);
502  if (!new_map) {
504  MSG_TYPE_COMMAND_FAILURE, "The %s is closed.",
505  exit_ob->name);
506  LOG(llevError,
507  "Template exit in '%s' (%d, %d) does not reference a valid "
508  "template. Make sure a template exists at '%s'.\n",
509  exit_ob->map->path, exit_ob->x, exit_ob->y, path);
510  return;
511  }
512  }
513 
514  assert(new_map);
515  /* set the path of the map to where it should be
516  * so we don't just save over the source map.
517  */
518  strlcpy(new_map->path, new_map_name, sizeof(new_map->path));
519  new_map->is_template = 1;
520  enter_map(pl, new_map, EXIT_X(exit_ob), EXIT_Y(exit_ob));
521 }
522 
532 static void enter_random_template_map(object *pl, object *exit_ob) {
533  mapstruct *new_map;
534  char tmpnum[32], resultname[HUGE_BUF], tmpstring[HUGE_BUF];
535  char new_map_name[MAX_BUF];
536  RMParms rp;
537 
538  /* Do replacement of %x, %y, and %n to the x coord of the exit, the y coord
539  * of the exit, and the name of the map the exit is on, respectively.
540  */
541  snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->x);
542  replace(EXIT_PATH(exit_ob)+3, "%x", tmpnum, resultname, sizeof(resultname));
543 
544  snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->y);
545  strlcpy(tmpstring, resultname, sizeof(tmpstring));
546  replace(tmpstring, "%y", tmpnum, resultname, sizeof(resultname));
547 
548  strlcpy(tmpstring, resultname, sizeof(tmpstring));
549  replace(tmpstring, "%n", exit_ob->map->name, resultname, sizeof(resultname));
550 
551  /* If we are coming from another template map, use reletive paths unless
552  * indicated otherwise.
553  */
554  if (exit_ob->map->is_template && (resultname[0] != '/')) {
555  path_combine_and_normalize(exit_ob->map->path, resultname, new_map_name, sizeof(new_map_name));
556  } else {
557  create_template_pathname(resultname, new_map_name, sizeof(new_map_name));
558  }
559 
560  new_map = ready_map_name(new_map_name, MAP_PLAYER_UNIQUE);
561  if (!new_map) {
562  memset(&rp, 0, sizeof(RMParms));
563  rp.Xsize = -1;
564  rp.Ysize = -1;
565  rp.region = get_region_by_map(exit_ob->map);
566  if (exit_ob->msg)
567  set_random_map_variable(&rp, exit_ob->msg);
568  rp.origin_x = exit_ob->x;
569  rp.origin_y = exit_ob->y;
570  safe_strncpy(rp.origin_map, pl->map->path, sizeof(rp.origin_map));
571 
572  /* now to generate the actual map. */
573  new_map = generate_random_map(new_map_name, &rp, NULL);
574  }
575 
576  /* Update the exit_ob so it now points directly at the newly created
577  * random maps. Not that it is likely to happen, but it does mean that a
578  * exit in a unique map leading to a random map will not work properly.
579  * It also means that if the created random map gets reset before
580  * the exit leading to it, that the exit will no longer work.
581  */
582  if (new_map) {
583  int x, y;
584 
585  x = EXIT_X(exit_ob) = MAP_ENTER_X(new_map);
586  y = EXIT_Y(exit_ob) = MAP_ENTER_Y(new_map);
587  new_map->is_template = 1;
588  enter_map(pl, new_map, x, y);
589  }
590 }
591 
600 static void enter_unique_map(object *op, object *exit_ob) {
601  char apartment[HUGE_BUF], path[MAX_BUF];
602  mapstruct *newmap;
603 
604  if (EXIT_PATH(exit_ob)[0] == '/') {
605  snprintf(apartment, sizeof(apartment), "~%s/%s", op->name, clean_path(EXIT_PATH(exit_ob), path, sizeof(path)));
606  newmap = ready_map_name(apartment, MAP_PLAYER_UNIQUE);
607  if (!newmap) {
608  newmap = mapfile_load(EXIT_PATH(exit_ob), 0);
609  }
610  } else { /* relative directory */
611  char reldir[HUGE_BUF], tmpc[HUGE_BUF], *cp;
612 
613  if (exit_ob->map->unique) {
614  unclean_path(exit_ob->map->path, reldir, sizeof(reldir));
615 
616  /* Need to copy this over, as clean_path only has one static return buffer */
617  clean_path(reldir, tmpc, sizeof(tmpc));
618  /* Remove final component, if any */
619  if ((cp = strrchr(tmpc, '_')) != NULL)
620  *cp = 0;
621 
622  snprintf(apartment, sizeof(apartment), "~%s/%s_%s", op->name, tmpc, clean_path(EXIT_PATH(exit_ob), path, sizeof(path)));
623 
624  newmap = ready_map_name(apartment, MAP_PLAYER_UNIQUE);
625  if (!newmap) {
626  newmap = mapfile_load(path_combine_and_normalize(reldir, EXIT_PATH(exit_ob), tmpc, sizeof(tmpc)), 0);
627  }
628  } else {
629  /* The exit is unique, but the map we are coming from is not unique. So
630  * use the basic logic - don't need to demangle the path name
631  */
632  path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), reldir, sizeof(reldir));
633  snprintf(apartment, sizeof(apartment), "~%s/%s", op->name, clean_path(reldir, path, sizeof(path)));
634  newmap = ready_map_name(apartment, MAP_PLAYER_UNIQUE);
635  if (!newmap) {
636  path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), reldir, sizeof(reldir));
637  newmap = ready_map_name(reldir, 0);
638  if (newmap)
639  apply_auto_fix(newmap);
640  }
641  }
642  }
643 
644  if (newmap) {
645  strlcpy(newmap->path, apartment, sizeof(newmap->path));
646  newmap->unique = 1;
647  enter_map(op, newmap, EXIT_X(exit_ob), EXIT_Y(exit_ob));
648  } else {
651  "The %s is closed.",
652  exit_ob->name);
653  /* Perhaps not critical, but I would think that the unique maps
654  * should be new enough this does not happen. This also creates
655  * a strange situation where some players could perhaps have visited
656  * such a map before it was removed, so they have the private
657  * map, but other players can't get it anymore.
658  */
659  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);
660  }
661 }
662 
663 void enter_player_maplevel(object *op) {
664  int flags = 0, x = op->x, y = op->y;
665  mapstruct *newmap;
666 
667  assert(op != NULL);
668  assert(op->type == PLAYER);
669 
670  /* newmap returns the map (if already loaded), or loads it for us. */
671  newmap = ready_map_name(op->contr->maplevel, flags);
672  if (!newmap) {
674  x = settings.emergency_x;
675  y = settings.emergency_y;
676  if (!newmap) {
677  LOG(llevError, "Fatal: Could not load emergency map!\n");
678  abort();
679  }
680 
682  "You find yourself somewhere unexpected...");
683  }
684 
685  /* as a special case, if coordinates are (-1, -1), then the item should
686  * be put at the default location. Used for loginmethod 0 (old clients). */
687  if (x == -1 && y == -1) {
688  x = MAP_ENTER_X(newmap);
689  y = MAP_ENTER_Y(newmap);
690  }
691 
692  enter_map(op, newmap, x, y);
693 }
694 
708 void enter_exit(object *op, object *exit_ob) {
709 #define PORTAL_DESTINATION_NAME "Town portal destination" /* this one should really be in a header file */
710  /* It may be nice to support other creatures moving across
711  * exits, but right now a lot of the code looks at op->contr,
712  * so thta is an RFE.
713  */
714  if (op->type != PLAYER)
715  return;
716 
717  /* Need to remove player from transport */
718  if (op->contr->transport)
719  ob_apply(op->contr->transport, op, AP_UNAPPLY);
720 
721  assert(exit_ob != NULL);
722  assert(EXIT_PATH(exit_ob) != NULL);
723 
724  /* check to see if we make a template map
725  * Template maps have an EXIT_PATH in the form:
726  * /@[!]<MAP_NAME>!<TEMPLATE_PATH>
727  *
728  * <MAP_NAME> is the name of the destination map, which is saved in LOCALDIR/template-maps/.
729  * <TEMPLATE_PATH> is the path to a template map, used when <MAP_NAME> does not exist.
730  */
731  if (EXIT_PATH(exit_ob) && EXIT_PATH(exit_ob)[1] == '@') {
732  if (EXIT_PATH(exit_ob)[2] == '!') {
733  /* generate a template map randomly */
734  enter_random_template_map(op, exit_ob);
735  } else {
736  /* generate a template map from a fixed template */
737  enter_fixed_template_map(op, exit_ob);
738  }
739  }
740  /* check to see if we make a randomly generated map */
741  else if (EXIT_PATH(exit_ob) && EXIT_PATH(exit_ob)[1] == '!') {
742  enter_random_map(op, exit_ob);
743  } else if (QUERY_FLAG(exit_ob, FLAG_UNIQUE)) {
744  enter_unique_map(op, exit_ob);
745  } else {
746  int x = EXIT_X(exit_ob), y = EXIT_Y(exit_ob);
747  /* 'Normal' exits that do not do anything special
748  * Simple enough we don't need another routine for it.
749  */
750  mapstruct *newmap;
751  if (exit_ob->map) {
752  char tmp_path[HUGE_BUF];
753 
754  path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), tmp_path, sizeof(tmp_path));
755  newmap = ready_map_name(tmp_path, 0);
756  /* Random map was previously generated, but is no longer about. Lets generate a new
757  * map.
758  */
759  if (!newmap && !strncmp(EXIT_PATH(exit_ob), "/random/", 8)) {
760  /* Maps that go down have a message set. However, maps that go
761  * up, don't. If the going home has reset, there isn't much
762  * point generating a random map, because it won't match the maps.
763  */
764  if (exit_ob->msg) {
765  enter_random_map(op, exit_ob);
766  } else {
769  "The %s is closed.",
770  exit_ob->name);
771  return;
772  }
773 
774  /* For exits that cause damages (like pits). Don't know if any
775  * random maps use this or not.
776  */
777  if (exit_ob->stats.dam && op->type == PLAYER)
778  hit_player(op, exit_ob->stats.dam, exit_ob, exit_ob->attacktype, 1);
779  return;
780  }
781  } else {
782  /* For word of recall and other force objects
783  * They contain the full pathname of the map to go back to,
784  * so we don't need to normalize it.
785  * But we do need to see if it is unique or not
786  */
787  if (!strncmp(EXIT_PATH(exit_ob), settings.localdir, strlen(settings.localdir)))
788  newmap = ready_map_name(EXIT_PATH(exit_ob), MAP_PLAYER_UNIQUE);
789  else
790  newmap = ready_map_name(EXIT_PATH(exit_ob), 0);
791  }
792  if (!newmap) {
793  if (exit_ob->name)
796  "The %s is closed.",
797  exit_ob->name);
798  /* don't cry to momma if name is not set - as in tmp objects
799  * used by the savebed code and character creation */
800  return;
801  }
802 
803  if (x == -1 && y == -1) {
804  x = MAP_ENTER_X(newmap);
805  y = MAP_ENTER_Y(newmap);
806  }
807 
808  /* mids 02/13/2002 if exit is damned, update players death & WoR home-position and delete town portal */
809  if (QUERY_FLAG(exit_ob, FLAG_DAMNED)) {
810  object *tmp;
811 
812  /* remove an old force with a slaying field == PORTAL_DESTINATION_NAME */
814  if (tmp) {
815  object_remove(tmp);
816  object_free(tmp, FREE_OBJ_NO_DESTROY_CALLBACK);
817  }
818 
819  path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), op->contr->savebed_map, sizeof(op->contr->savebed_map));
820  op->contr->bed_x = EXIT_X(exit_ob), op->contr->bed_y = EXIT_Y(exit_ob);
821  save_player(op, 1);
822  }
823 
824  enter_map(op, newmap, x, y);
825  }
826 
827  LOG(llevDebug, "%s enters %s\n", op->name, EXIT_PATH(exit_ob));
828 
829  /* For exits that cause damages (like pits) */
830  if (exit_ob->stats.dam && op->type == PLAYER)
831  hit_player(op, exit_ob->stats.dam, exit_ob, exit_ob->attacktype, 1);
832 }
833 
839 static void process_players1(void) {
840  int flag;
841  player *pl, *plnext;
842 
843  /* Basically, we keep looping until all the players have done their actions. */
844  for (flag = 1; flag != 0; ) {
845  flag = 0;
846  for (pl = first_player; pl != NULL; pl = plnext) {
847  plnext = pl->next; /* In case a player exits the game in handle_player() */
848 
849  if (pl->ob == NULL)
850  continue;
851 
852  /* Only do this on the first pass - what we are recording
853  * here is the number of ticks the player has been online - not
854  * how many actions/moves the player has done.
855  */
856  if (!flag) pl->ticks_played++;
857 
859  if (pl->followed_player) {
861  if (followed && followed->ob && followed->ob->map) {
862  rv_vector rv;
863 
864  if (!get_rangevector(pl->ob, followed->ob, &rv, 0) || rv.distance > 4) {
865  int space = object_find_free_spot(pl->ob, followed->ob->map, followed->ob->x, followed->ob->y, 1, 25);
866  if (space == -1)
868  space = 0;
869  object_remove(pl->ob);
870  object_insert_in_map_at(pl->ob, followed->ob->map, NULL, 0, followed->ob->x+freearr_x[space], followed->ob->y+freearr_y[space]);
871  map_newmap_cmd(&pl->socket);
873  }
874  } else {
875  draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_ADMIN, MSG_TYPE_ADMIN_DM, "Player %s left or ambiguous name.", pl->followed_player);
877  }
878  }
880  if (pl->ob->speed_left > 0) {
881  if (handle_newcs_player(pl->ob))
882  flag = 1;
883  } /* end if player has speed left */
884 
885  /* If the player is not actively playing, don't make a
886  * backup save - nothing to save anyway. Plus, the
887  * map may not longer be valid. This can happen when the
888  * player quits - they exist for purposes of tracking on the map,
889  * but don't actually reside on any actual map.
890  */
891  if (QUERY_FLAG(pl->ob, FLAG_REMOVED))
892  continue;
893 
894 #ifdef AUTOSAVE
895  /* check for ST_PLAYING state so that we don't try to save off when
896  * the player is logging in.
897  */
898  if ((pl->last_save_tick+AUTOSAVE) < pticks && pl->state == ST_PLAYING) {
899  /* Don't save the player on unholy ground. Instead, increase the
900  * tick time so it will be about 10 seconds before we try and save
901  * again.
902  */
903  if (get_map_flags(pl->ob->map, NULL, pl->ob->x, pl->ob->y, NULL, NULL)&P_NO_CLERIC) {
904  pl->last_save_tick += 100;
905  } else {
906  save_player(pl->ob, 1);
907  pl->last_save_tick = pticks;
908  hiscore_check(pl->ob, 1);
909  }
910  }
911 #endif
912  } /* end of for loop for all the players */
913  } /* for flag */
914  for (pl = first_player; pl != NULL; pl = pl->next) {
915  int has_action = 1;
916 
917  pl->ob->weapon_speed_left += pl->ob->weapon_speed;
918  if (pl->ob->weapon_speed_left > 1.0)
919  pl->ob->weapon_speed_left = 1.0;
920 
921  pl->socket.sounds_this_tick = 0;
922 
923  if (settings.casting_time == TRUE) {
924  if (pl->ob->casting_time > 0) {
925  pl->ob->casting_time--;
926  has_action = 0;
927  }
928  }
929  /* If the character is idle (standing around resting) increase
930  * regen rates.
931  */
932  if (has_action && pl->ob->speed_left > 0) {
933  pl->ob->last_heal -= 2;
934  pl->ob->last_sp -= 2;
935  pl->ob->last_grace -= 2;
936  pl->ob->last_eat += 2; /* Slow down food consumption */
937  }
938  do_some_living(pl->ob);
939  }
940 }
941 
949 static void process_players2(void) {
950  player *pl;
951 
952  /* Then check if any players should use weapon-speed instead of speed */
953  for (pl = first_player; pl != NULL; pl = pl->next) {
954  /* The code that did weapon_sp handling here was out of place -
955  * this isn't called until after the player has finished there
956  * actions, and is thus out of place. All we do here is bounds
957  * checking.
958  */
959  if (pl->has_hit) {
960  /* This needs to be here - if the player is running, we need to
961  * clear this each tick, but new commands are not being received
962  * so execute_newserver_command() is never called
963  */
964  pl->has_hit = 0;
965  } else if (pl->ob->speed_left > pl->ob->speed)
966  pl->ob->speed_left = pl->ob->speed;
967  }
968 }
969 
970 #define SPEED_DEBUG
971 
972 static bool object_in_icecube(object *op) {
973  return op->env != NULL && strcmp(op->env->arch->name, "icecube") == 0;
974 }
975 
979 void process_events(void) {
980  object *op;
981  object marker;
982  tag_t tag;
983 
985 
986  memset(&marker, 0, sizeof(object));
987  /* Put marker object at beginning of active list */
988  marker.active_next = active_objects;
989 
990  if (marker.active_next)
991  marker.active_next->active_prev = &marker;
992  marker.active_prev = NULL;
993  active_objects = &marker;
994 
995  while (marker.active_next) {
996  op = marker.active_next;
997  tag = op->count;
998 
999  /* Move marker forward - swap op and marker */
1000  op->active_prev = marker.active_prev;
1001 
1002  if (op->active_prev)
1003  op->active_prev->active_next = op;
1004  else
1005  active_objects = op;
1006 
1007  marker.active_next = op->active_next;
1008 
1009  if (marker.active_next)
1010  marker.active_next->active_prev = &marker;
1011  marker.active_prev = op;
1012  op->active_next = &marker;
1013 
1014  /* Now process op */
1015  if (QUERY_FLAG(op, FLAG_FREED)) {
1016  LOG(llevError, "BUG: process_events(): Free object on list\n");
1017  op->speed = 0;
1018  object_update_speed(op);
1019  continue;
1020  }
1021 
1022  /* I've seen occasional crashes due to this - the object is removed,
1023  * and thus the map it points to (last map it was on) may be bogus
1024  * The real bug is to try to find out the cause of this - someone
1025  * is probably calling object_remove() without either an insert_ob or
1026  * object_free_drop_inventory() afterwards, leaving an object dangling.
1027  * But I'd rather log this and continue on instead of crashing.
1028  * Don't remove players - when a player quits, the object is in
1029  * sort of a limbo, of removed, but something we want to keep
1030  * around.
1031  */
1032  if (QUERY_FLAG(op, FLAG_REMOVED)
1033  && op->type != PLAYER
1034  && op->map
1035  && op->map->in_memory != MAP_IN_MEMORY) {
1036  StringBuffer *sb;
1037  char *diff;
1038 
1039  LOG(llevError, "BUG: process_events(): Removed object on list\n");
1040  sb = stringbuffer_new();
1041  object_dump(op, sb);
1042  diff = stringbuffer_finish(sb);
1043  LOG(llevError, "%s\n", diff);
1044  free(diff);
1045  object_free(op, FREE_OBJ_NO_DESTROY_CALLBACK);
1046  continue;
1047  }
1048 
1049  if (!op->speed) {
1050  LOG(llevError, "BUG: process_events(): Object %s has no speed, but is on active list\n", op->arch->name);
1051  object_update_speed(op);
1052  continue;
1053  }
1054 
1055  if (op->map == NULL
1056  && op->env == NULL
1057  && op->name
1058  && op->type != MAP) {
1059  LOG(llevError, "BUG: process_events(): Object without map or inventory is on active list: %s (%d)\n", op->name, op->count);
1060  op->speed = 0;
1061  object_update_speed(op);
1062  continue;
1063  }
1064 
1065  /* Seen some cases where process_object() is crashing because
1066  * the object is on a swapped out map. But can't be sure if
1067  * something in the chain of events caused the object to
1068  * change maps or was just never removed - this will
1069  * give some clue as to its state before call to
1070  * process_object
1071  */
1072  if (op->map && op->map->in_memory != MAP_IN_MEMORY) {
1073  LOG(llevError, "BUG: process_events(): Processing object on swapped out map: %s (%d), map=%s\n", op->name, op->count, op->map->path);
1074  }
1075 
1076  /* Animate the object. Bug of feature that andim_speed
1077  * is based on ticks, and not the creatures speed?
1078  */
1079  if ((op->anim_speed && op->last_anim >= op->anim_speed)
1080  || (op->temp_animation && op->last_anim >= op->temp_anim_speed)) {
1081  op->state++;
1082  if ((op->type == PLAYER) || (op->type == MONSTER))
1083  animate_object(op, op->facing);
1084  else
1085  animate_object(op, op->direction);
1086  op->last_anim = 1;
1087  } else {
1088  op->last_anim++;
1089  }
1090 
1091  if (op->speed_left > 0) {
1092  // Players are special because their speed_left has already been
1093  // reduced in do_server(). Players effectively process every tick
1094  // so long they have non-zero speed left.
1095  if (op->type != PLAYER) {
1096  // Objects in icecubes decay at a slower rate
1097  if (object_in_icecube(op)) {
1098  op->speed_left -= 10;
1099  } else {
1100  op->speed_left -= 1;
1101  }
1102  }
1103  process_object(op);
1104  if (object_was_destroyed(op, tag))
1105  continue;
1106  } else {
1107  // Custom-made creatures for random maps can still have negative speeds, so catch that with FABS().
1108  op->speed_left += FABS(op->speed);
1109  }
1110  if (settings.casting_time == TRUE && op->casting_time > 0)
1111  op->casting_time--;
1112  }
1113 
1114  /* Remove marker object from active list */
1115  if (marker.active_prev != NULL)
1116  marker.active_prev->active_next = NULL;
1117  else
1118  active_objects = NULL;
1119 
1120  process_players2();
1121 }
1122 
1127 void clean_tmp_files(void) {
1128  mapstruct *m, *next;
1129  for (m = first_map; m != NULL; m = next) {
1130  next = m->next;
1131  if (m->in_memory == MAP_IN_MEMORY) {
1132  // Save all maps currently in memory, because they might contain
1133  // unique tiles that have not been written to disk.
1134  if (settings.recycle_tmp_maps) {
1135  // swap_map() also updates the write log.
1136  swap_map(m);
1137  } else {
1139  // FIXME: Unfortunately, save_map() also unnecessarily saves
1140  // non-unique tiles to a new temporary file, so we have to
1141  // get rid of it here.
1142  clean_tmp_map(m);
1143  }
1144  } else {
1145  // Remove the swap file.
1146  clean_tmp_map(m);
1147  }
1148  }
1149  write_todclock(); /* lets just write the clock here */
1150 }
1151 
1153 void cleanup(void) {
1154  LOG(llevInfo, "Cleaning up...\n");
1155  clean_tmp_files();
1157  accounts_save();
1158 
1159 #ifdef MEMORY_DEBUG
1160  free_all_maps();
1161  free_style_maps();
1162 #endif
1163  cleanupPlugins();
1164 #ifdef MEMORY_DEBUG
1165  free_all_archs();
1167  free_all_images();
1169  free_all_recipes();
1171  free_all_god();
1172  free_all_anim();
1173  i18n_free();
1174  free_loader();
1175  free_globals();
1176  free_server();
1178  free_knowledge();
1179  free_quest();
1181  /* See what the string data that is out there that hasn't been freed. */
1182  /* LOG(llevDebug, "%s", ss_dump_table(0xff));*/
1183 #endif
1184  exit(0);
1185 }
1186 
1195 void leave(player *pl, int draw_exit) {
1196  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED)) {
1197  pets_terminate_all(pl->ob);
1198  object_remove(pl->ob);
1199  }
1200 
1201  pl->socket.status = Ns_Dead;
1202  LOG(llevInfo, "logout: %s from %s\n", pl->ob->name, pl->socket.host);
1203 
1204  strcpy(pl->ob->contr->killer, "left");
1205  hiscore_check(pl->ob, 1);
1206 
1207  /* If this player is the captain of the transport, need to do
1208  * some extra work. By the time we get here, object_remove()
1209  * should have already been called.
1210  */
1211  if (pl->transport && pl->transport->contr == pl) {
1212  /* If inv is a non player, inv->contr will be NULL, but that
1213  * is OK.
1214  */
1215  if (pl->transport->inv)
1216  pl->transport->contr = pl->transport->inv->contr;
1217  else
1218  pl->transport->contr = NULL;
1219 
1220  if (pl->transport->contr) {
1221  char name[MAX_BUF];
1222 
1223  query_name(pl->transport, name, MAX_BUF);
1224  draw_ext_info_format(NDI_UNIQUE, 0, pl->transport->contr->ob,
1226  "%s has left. You are now the captain of %s",
1227  pl->ob->name, name);
1228  }
1229  }
1230 
1231  if (pl->ob->map) {
1232  if (pl->ob->map->in_memory == MAP_IN_MEMORY)
1233  pl->ob->map->timeout = MAP_TIMEOUT(pl->ob->map);
1234  pl->ob->map = NULL;
1235  }
1236  pl->ob->type = DEAD_OBJECT; /* To avoid problems with inventory window */
1237  party_leave(pl->ob);
1238  /* If a hidden dm dropped connection do not create
1239  * inconsistencies by showing that they have left the game
1240  */
1241  if (!(QUERY_FLAG(pl->ob, FLAG_WIZ) && pl->ob->contr->hidden)
1242  && (pl != NULL && draw_exit) && (pl->state != ST_GET_NAME && pl->state != ST_GET_PASSWORD && pl->state != ST_CONFIRM_PASSWORD))
1245  "%s left the game.",
1246  pl->ob->name);
1247 }
1248 
1256 int forbid_play(void) {
1257 #if !defined(_IBMR2) && !defined(___IBMR2) && defined(PERM_FILE)
1258  char buf[MAX_BUF], day[MAX_BUF];
1259  FILE *fp;
1260  time_t clock;
1261  struct tm *tm;
1262  int i, start, stop, forbit = 0;
1263 
1264  clock = time(NULL);
1265  tm = (struct tm *)localtime(&clock);
1266 
1267  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, PERM_FILE);
1268  if ((fp = fopen(buf, "r")) == NULL)
1269  return 0;
1270 
1271  while (fgets(buf, sizeof(buf), fp)) {
1272  if (buf[0] == '#')
1273  continue;
1274  if (!strncmp(buf, "msg", 3)) {
1275  if (forbit)
1276  while (fgets(buf, sizeof(buf), fp)) /* print message */
1277  fputs(buf, logfile);
1278  break;
1279  } else if (sscanf(buf, "%s %d%*c%d\n", day, &start, &stop) != 3) {
1280  LOG(llevDebug, "Warning: Incomplete line in permission file ignored.\n");
1281  continue;
1282  }
1283 
1284  for (i = 0; i < 7; i++) {
1285  if (!strncmp(buf, days[i], 3)
1286  && (tm->tm_wday == i)
1287  && (tm->tm_hour >= start)
1288  && (tm->tm_hour < stop))
1289  forbit = 1;
1290  }
1291  }
1292 
1293  fclose(fp);
1294 
1295  return forbit;
1296 #else
1297  return 0;
1298 #endif
1299 }
1300 
1301 static void do_shutdown(void) {
1303  MSG_TYPE_ADMIN_DM, "The server has shut down.");
1304 
1305  /* TODO: Kick everyone out and save player files? */
1306  cleanup();
1307 }
1308 
1312 static bool check_shutdown(void) {
1313  if (shutdown_flag == 1) {
1314  LOG(llevInfo, "Received SIGINT; shutting down...\n");
1315  return true;
1316  }
1317 
1318  /* Zero means that no timed shutdown is pending. */
1319  if (cmd_shutdown_time == 0) {
1320  return false;
1321  }
1322 
1323  /* If a timed shutdown is coming, remind players periodically. */
1324  static int next_warn = 0; // FIXME: next_warn not reset if shutdown cancelled
1325  time_t time_left = cmd_shutdown_time - time(NULL);
1326 
1327  for (unsigned int i = next_warn; i < sizeof(shutdown_warn_times) / sizeof(int); i++) {
1328  if (shutdown_warn_times[i] == (int)ceil(time_left / 60.0)) {
1331  "Server shutting down in %d minutes.", shutdown_warn_times[i]);
1332  next_warn = i + 1;
1333  return false;
1334  }
1335  }
1336 
1337  if (time_left <= 0) {
1338  return true;
1339  }
1340  return false;
1341 }
1342 
1347 void login_check_shutdown(object* const op) {
1348  if (cmd_shutdown_time == 0) {
1349  return;
1350  }
1351 
1352  time_t time_left = cmd_shutdown_time - time(NULL);
1353  if (time_left <= 60*shutdown_warn_times[0]) {
1356  i18n(op, "Server shutting down in %d minutes."), time_left / 60);
1357  }
1358 }
1359 
1360 extern unsigned long todtick;
1361 
1376 static void do_specials(void) {
1377  if (check_shutdown()) {
1378  do_shutdown();
1379  }
1380 
1381 #ifdef CS_LOGSTATS
1382  if ((time(NULL)-cst_lst.time_start) >= CS_LOGTIME)
1383  write_cs_stats();
1384 #endif
1385 
1386  if (!(pticks%10))
1388 
1389 #ifdef WATCHDOG
1390  if (!(pticks%503))
1391  watchdog();
1392 #endif
1393 
1394  if (!(pticks%PTICKS_PER_CLOCK))
1395  tick_the_clock();
1396 
1397  if (!(pticks%509))
1398  flush_old_maps(); /* Clears the tmp-files of maps which have reset */
1399 
1400  if (!(pticks%2503))
1401  fix_weight(); /* Hack to fix weightproblems caused by bugs */
1402 
1403  if (!(pticks%2521))
1404  metaserver_update(); /* 2500 ticks is about 5 minutes */
1405 
1406  if (!(pticks%2531))
1407  accounts_save();
1408 
1409  if (!(pticks%5003))
1411 
1412  if (!(pticks%5009))
1414 
1415  if (!(pticks%5011))
1417 
1418  if (!(pticks%12503))
1419  fix_luck();
1420 }
1421 
1430 void server_main(int argc, char *argv[]) {
1431 #ifdef WIN32 /* ---win32 this sets the win32 from 0d0a to 0a handling */
1432  _fmode = _O_BINARY;
1433  bRunning = 1;
1434 #endif
1435 
1436 #ifndef WIN32
1437  /* Here we check that we aren't root or suid */
1438  if (getuid() == 0 || geteuid() == 0) {
1439  fprintf(stderr,
1440  "Running crossfire-server as root is a bad idea; aborting!\n"
1441  "Please run it again as a normal, unprivileged user.\n");
1442  exit(EXIT_FAILURE);
1443  }
1444 #endif
1445 
1446 #ifdef DEBUG_MALLOC_LEVEL
1447  malloc_debug(DEBUG_MALLOC_LEVEL);
1448 #endif
1449 
1450  init(argc, argv);
1451  initPlugins(); /* GROS - Init the Plugins */
1452  // Give feedback that loading is complete. This prevents confusion on when it is done loading.
1453  LOG(llevInfo, "Initialization complete. Waiting for connections.\n");
1454 #ifdef WIN32
1455  while (bRunning) {
1456 #else
1457  while (TRUE) {
1458 #endif
1459  nroferrors = 0;
1460 
1461  tick_game_time();
1462  do_server();
1463  process_events(); /* "do" something with objects with speed */
1464  cftimer_process_timers(); /* Process the crossfire Timers */
1466  check_active_maps(); /* Removes unused maps after a certain timeout */
1467  do_specials(); /* Routines called from time to time. */
1468  update_players();
1469  }
1470 
1471  /* This is unreachable. */
1472  abort();
1473 }
void enter_exit(object *op, object *exit_ob)
Definition: server.c:708
EXTERN FILE * logfile
Definition: global.h:137
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:313
#define AP_UNAPPLY
Definition: define.h:612
char path[HUGE_BUF]
Definition: map.h:365
int find_dir_2(int x, int y)
Definition: object.c:3467
void free_all_maps(void)
Definition: map.c:1969
char const * newhash(char const password[static 1])
Definition: server.c:96
void leave(player *pl, int draw_exit)
Definition: server.c:1195
#define MSG_TYPE_MISC
Definition: newclient.h:389
Definition: player.h:92
#define FLAG_DAMNED
Definition: define.h:318
mapstruct * mapfile_load(const char *map, int flags)
Definition: map.c:1212
mapstruct * generate_random_map(const char *OutFileName, RMParms *RP, char **use_layout)
Definition: random_map.c:74
void do_server(void)
Definition: loop.c:536
void object_free(object *ob, int flags)
Definition: object.c:1348
void player_map_change_common(object *op, mapstruct *const oldmap, mapstruct *const newmap)
Definition: server.c:265
static bool check_shutdown(void)
Definition: server.c:1312
Definition: map.h:380
void enter_player_savebed(object *op)
Definition: server.c:133
void free_quest_definitions(void)
Definition: quest.c:1321
void cleanup(void)
Definition: server.c:1153
static void enter_random_map(object *pl, object *exit_ob)
Definition: server.c:374
static void do_specials(void)
Definition: server.c:1376
#define NDI_ALL
Definition: newclient.h:246
#define FABS(x)
Definition: define.h:22
StringBuffer * buf
Definition: readable.c:1591
void object_free_all_data(void)
Definition: object.c:531
#define MSG_TYPE_COMMAND_FAILURE
Definition: newclient.h:511
void do_some_living(object *op)
Definition: player.c:3237
void metaserver_update(void)
Definition: metaserver.c:52
int16_t players
Definition: map.h:344
char final_map[RM_SIZE]
Definition: random_map.h:57
char * create_pathname(const char *name, char *buf, size_t size)
Definition: map.c:112
int save_player(object *op, int flag)
Definition: login.c:212
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.c:57
uint32_t in_memory
Definition: map.h:345
mapstruct * ready_map_name(const char *name, int flags)
Definition: map.c:1796
#define MAP_ENTER_X(m)
Definition: map.h:85
void free_string(sstring str)
Definition: shstr.c:280
#define HUGE_BUF
Definition: define.h:37
uint32_t is_template
Definition: map.h:338
uint32_t pticks
Definition: time.c:45
#define MAP_HEIGHT(m)
Definition: map.h:80
socket_struct socket
Definition: player.h:94
short freearr_x[SIZEOFFREE]
Definition: object.c:65
#define ST_CONFIRM_PASSWORD
Definition: define.h:585
region * get_region_by_map(mapstruct *m)
Definition: region.c:74
void update_players(void)
Definition: loop.c:677
#define AUTOSAVE
Definition: config.h:597
int8_t sounds_this_tick
Definition: newserver.h:121
object * object_find_by_type_and_slaying(const object *who, int type, const char *slaying)
Definition: object.c:3948
enum Sock_Status status
Definition: newserver.h:90
#define TRUE
Definition: compat.h:10
void party_leave(object *op)
Definition: party.c:123
#define PERM_FILE
Definition: config.h:453
#define SAVE_MODE_NORMAL
Definition: map.h:120
void remove_friendly_object(object *op)
Definition: friend.c:56
static bool object_in_icecube(object *op)
Definition: server.c:972
method_ret ob_apply(object *op, object *applier, int aflags)
Definition: ob_methods.c:44
void fix_weight(void)
Definition: player.c:3844
void enter_player_maplevel(object *op)
Definition: server.c:663
void i18n_free(void)
Definition: languages.c:238
void clean_friendly_list(void)
Definition: friend.c:111
#define safe_strncpy
Definition: compat.h:23
void free_quest(void)
Definition: quest.c:1303
void pets_terminate_all(object *owner)
Definition: pets.c:225
static void enter_unique_map(object *op, object *exit_ob)
Definition: server.c:600
int swap_map(mapstruct *map)
Definition: swap.c:135
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:308
#define ST_PLAYING
Definition: define.h:578
static const int shutdown_warn_times[]
Definition: server.c:48
#define NDI_DK_ORANGE
Definition: newclient.h:227
char * host
Definition: newserver.h:100
uint8_t casting_time
Definition: global.h:269
uint8_t recycle_tmp_maps
Definition: global.h:271
uint16_t emergency_y
Definition: global.h:300
#define EVENT_MAPLEAVE
Definition: events.h:46
void login_check_shutdown(object *const op)
Definition: server.c:1347
#define FLAG_REMOVED
Definition: define.h:232
void check_active_maps(void)
Definition: swap.c:193
void events_execute_global_event(int eventcode,...)
Definition: events.cpp:27
short freearr_y[SIZEOFFREE]
Definition: object.c:71
int cmd_shutdown_time
Definition: c_wiz.c:43
object * active_objects
Definition: object.c:62
void free_all_newserver(void)
Definition: init.c:393
uint32_t ticks_played
Definition: player.h:203
#define MSG_TYPE_ADMIN_DM
Definition: newclient.h:475
void map_newmap_cmd(socket_struct *ns)
Definition: request.c:618
int forbid_play(void)
Definition: server.c:1256
#define MAP_IN_MEMORY
Definition: map.h:130
void object_free_drop_inventory(object *ob)
Definition: object.c:1316
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:1849
void flush_old_maps(void)
Definition: swap.c:244
void free_loader(void)
#define MSG_TYPE_COMMAND
Definition: newclient.h:379
void object_dump(const object *op, StringBuffer *sb)
Definition: object.c:415
void write_todclock(void)
Definition: init.c:423
object * object_new(void)
Definition: object.c:1011
static char * clean_path(const char *file, char *newpath, int size)
Definition: server.c:320
void accounts_save(void)
Definition: account.c:267
#define EVENT_CLOCK
Definition: events.h:39
CS_Stats cst_lst
static void enter_fixed_template_map(object *pl, object *exit_ob)
Definition: server.c:441
uint32_t unique
Definition: map.h:337
#define MSG_TYPE_ADMIN_PLAYER
Definition: newclient.h:474
unsigned long todtick
Definition: init.c:417
static void enter_random_template_map(object *pl, object *exit_ob)
Definition: server.c:532
#define snprintf
Definition: win32.h:46
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Definition: map.c:497
void server_main(int argc, char *argv[])
Definition: server.c:1430
object * transport
Definition: player.h:195
void tick_game_time()
Definition: time.c:180
#define MAP_TIMEOUT(m)
Definition: map.h:66
char * path_combine_and_normalize(const char *src, const char *dst, char *path, size_t size)
Definition: path.c:172
struct quest_definition * next
Definition: quest.c:93
#define EXIT_PATH(xyz)
Definition: define.h:454
uint8_t state
Definition: player.h:118
static void process_players1(void)
Definition: server.c:839
static void do_shutdown(void)
Definition: server.c:1301
#define MAP_MAXTIMEOUT
Definition: config.h:406
void pets_remove_all(void)
Definition: pets.c:248
#define MAP_ENTER_Y(m)
Definition: map.h:87
static char * unclean_path(const char *src, char *newpath, int size)
Definition: server.c:348
void hiscore_check(object *op, int quiet)
Definition: hiscore.c:344
EXTERN long nroferrors
Definition: global.h:129
#define SIZEOFFREE
Definition: define.h:154
int bRunning
Definition: win32.c:159
uint16_t emergency_x
Definition: global.h:300
#define EXIT_X(xyz)
Definition: define.h:456
volatile sig_atomic_t shutdown_flag
Definition: server.c:53
uint32_t has_hit
Definition: player.h:129
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:198
void free_globals(void)
Definition: init.c:324
void process_events(void)
Definition: server.c:979
void tick_the_clock(void)
Definition: weather.c:96
int process_object(object *op)
Definition: time.c:796
void init(int argc, char **argv)
Definition: init.c:1035
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
void cleanupPlugins(void)
Definition: plugins.c:4558
void fix_luck(void)
Definition: player.c:3860
#define FLAG_WIZ
Definition: define.h:231
void clean_tmp_files(void)
Definition: server.c:1127
#define MAP_MINTIMEOUT
Definition: config.h:408
void knowledge_process_incremental(void)
Definition: knowledge.c:1460
#define EXIT_Y(xyz)
Definition: define.h:457
#define EVENT_MAPENTER
Definition: events.h:45
#define MAX_BUF
Definition: define.h:35
#define MSG_TYPE_ADMIN
Definition: newclient.h:377
#define CS_LOGTIME
Definition: config.h:188
int Ysize
Definition: random_map.h:75
int handle_newcs_player(object *op)
Definition: player.c:3051
void free_all_artifacts(void)
Definition: artifact.c:140
const char * confdir
Definition: global.h:244
static const flag_definition flags[]
int Xsize
Definition: random_map.h:74
void animate_object(object *op, int dir)
Definition: anim.c:43
int save_map(mapstruct *m, int flag)
Definition: map.c:1418
void free_all_recipes(void)
Definition: recipe.c:641
object * ob
Definition: player.h:158
int32_t timeout
Definition: map.h:341
char origin_map[RM_SIZE]
Definition: random_map.h:55
static char const * crypt_string(char const str[static 1], char const *salt)
Definition: server.c:70
void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
Definition: utils.c:354
int set_random_map_variable(RMParms *rp, const char *buf)
#define RANDOM()
Definition: define.h:681
#define PORTAL_DESTINATION_NAME
#define MAP_PLAYER_UNIQUE
Definition: map.h:97
const char * localdir
Definition: global.h:246
void party_obsolete_parties(void)
Definition: party.c:215
int origin_y
Definition: random_map.h:88
void write_cs_stats(void)
#define MAP_WIDTH(m)
Definition: map.h:78
unsigned int distance
Definition: map.h:381
struct Settings settings
Definition: init.c:39
static void enter_map(object *op, mapstruct *newmap, int x, int y)
Definition: server.c:174
struct regiondef * region
Definition: random_map.h:96
void object_set_enemy(object *op, object *enemy)
Definition: object.c:679
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2304
void free_all_readable(void)
Definition: readable.c:1992
#define SIZEOFFREE2
Definition: define.h:153
void apply_auto_fix(mapstruct *m)
Definition: main.c:259
void cftimer_process_timers(void)
Definition: timers.c:44
void write_book_archive(void)
Definition: readable.c:2029
uint8_t crypt_mode
Definition: global.h:330
sstring add_string(const char *str)
Definition: shstr.c:124
EXTERN player * first_player
Definition: global.h:115
time_t time_start
Definition: newclient.h:697
struct pl * next
Definition: player.h:93
static const char * days[]
Definition: server.c:51
void initPlugins(void)
Definition: plugins.c:4508
void free_style_maps(void)
Definition: style.c:312
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.c:310
#define NDI_UNIQUE
Definition: newclient.h:245
#define SIZEOFFREE1
Definition: define.h:152
void watchdog(void)
void player_update_bg_music(object *player)
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
void free_all_god(void)
Definition: holy.c:338
void free_knowledge(void)
Definition: knowledge.c:1301
struct mapdef * next
Definition: map.h:326
int object_find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop)
Definition: object.c:3291
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:583
char * emergency_mapname
Definition: global.h:299
Definition: map.h:325
void set_map_timeout(mapstruct *oldmap)
Definition: server.c:287
#define ST_GET_NAME
Definition: define.h:583
void free_server(void)
Definition: init.c:1075
#define FLAG_UNIQUE
Definition: define.h:288
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
Definition: attack.c:1847
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
Definition: map.c:2537
int origin_x
Definition: random_map.h:89
void create_template_pathname(const char *name, char *buf, size_t size)
Definition: map.c:153
const char * i18n(const object *who, const char *code)
Definition: languages.c:55
void clean_tmp_map(mapstruct *m)
Definition: map.c:1960
player * find_player_partial_name(const char *plname)
Definition: player.c:110
EXTERN mapstruct * first_map
Definition: global.h:116
#define PTICKS_PER_CLOCK
Definition: tod.h:11
void object_update_speed(object *op)
Definition: object.c:1086
sstring followed_player
Definition: player.h:199
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.c:76
#define P_NO_CLERIC
Definition: map.h:238
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.c:370
void object_remove(object *op)
Definition: object.c:1588
bool check_password(const char *typed, const char *crypted)
Definition: server.c:109
#define ST_GET_PASSWORD
Definition: define.h:584
static void process_players2(void)
Definition: server.c:949
#define FLAG_FREED
Definition: define.h:233