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