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  // An empty hashed password only matches an empty input password.
116  if (strlen(crypted) == 0) {
117  return strlen(typed) == 0 ? true : false;
118  }
119 
120  const char *typed_hashed = crypt_string(typed, crypted);
121  if (typed_hashed != NULL) {
122  return strcmp(typed_hashed, crypted) == 0;
123  } else {
124  LOG(llevError, "Could not check password with stored hash %s\n", crypted);
125  return false;
126  }
127 }
128 
138 void enter_player_savebed(object *op) {
139  mapstruct *oldmap = op->map;
140  object *tmp;
141 
142  tmp = object_new();
143 
144  EXIT_PATH(tmp) = add_string(op->contr->savebed_map);
145  EXIT_X(tmp) = op->contr->bed_x;
146  EXIT_Y(tmp) = op->contr->bed_y;
147  enter_exit(op, tmp);
148  /* If the player has not changed maps and the name does not match
149  * that of the savebed, his savebed map is gone. Lets go back
150  * to the emergency path. Update what the players savebed is
151  * while we're at it.
152  */
153  if (oldmap == op->map && strcmp(op->contr->savebed_map, oldmap->path)) {
154  LOG(llevDebug, "Player %s savebed location %s is invalid - going to emergency location (%s)\n",
155  settings.emergency_mapname, op->name, op->contr->savebed_map);
156  safe_strncpy(op->contr->savebed_map, settings.emergency_mapname, MAX_BUF);
157  op->contr->bed_x = settings.emergency_x;
158  op->contr->bed_y = settings.emergency_y;
159  free_string(op->contr->savebed_map);
160  EXIT_PATH(tmp) = add_string(op->contr->savebed_map);
161  EXIT_X(tmp) = op->contr->bed_x;
162  EXIT_Y(tmp) = op->contr->bed_y;
163  enter_exit(op, tmp);
164  }
166 }
167 
179 static void enter_map(object *op, mapstruct *newmap, int x, int y) {
180  mapstruct *oldmap = op->map;
181 
182  /* Default hp/sp for exits changed to -1 to use enter_x/enter_y values by default, but if one value
183  * is specified, we want the other to default to zero like before the change.
184  */
185  if (x < 0 && y >= 0) x=0;
186  if (y < 0 && x >= 0) y=0;
187 
188  if (out_of_map(newmap, x, y)) {
189  if (x != -1 || y != -1) {
190  LOG(llevError, "enter_map: supplied coordinates are not within the map! (%s: %d, %d)\n", newmap->path, x, y);
191  }
192  /* If op has invalid (probably -1,-1) coordinates, force them to a correct value, else issues later on. */
193  if (op->x == x)
194  op->x = MAP_ENTER_X(newmap);
195  if (op->y == y)
196  op->y = MAP_ENTER_Y(newmap);
197  x = MAP_ENTER_X(newmap);
198  y = MAP_ENTER_Y(newmap);
199  if (out_of_map(newmap, x, y)) {
200  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));
202  "The exit is closed");
203  return;
204  }
205  }
206  /* try to find a spot for the player */
207  if (ob_blocked(op, newmap, x, y)) { /* First choice blocked */
208  /* We try to find a spot for the player, starting closest in.
209  * We could use object_find_first_free_spot(), but that doesn't randomize it at all,
210  * So for example, if the north space is free, you would always end up there even
211  * if other spaces around are available.
212  * Note that for the second and third calls, we could start at a position other
213  * than one, but then we could end up on the other side of walls and so forth.
214  */
215  int i = object_find_free_spot(op, newmap, x, y, 1, SIZEOFFREE1+1);
216  if (i == -1) {
217  i = object_find_free_spot(op, newmap, x, y, 1, SIZEOFFREE2+1);
218  if (i == -1)
219  i = object_find_free_spot(op, newmap, x, y, 1, SIZEOFFREE);
220  }
221  if (i != -1) {
222  x += freearr_x[i];
223  y += freearr_y[i];
224  } else {
225  /* not much we can do in this case. */
226  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);
227  }
228  } /* end if looking for free spot */
229 
230  /* If it is a player login, he has yet to be inserted anyplace.
231  * otherwise, we need to deal with removing the playe here.
232  */
233  if (!QUERY_FLAG(op, FLAG_REMOVED))
234  object_remove(op);
235  /* object_remove clears these so they must be reset after the object_remove() call */
236  object_insert_in_map_at(op, newmap, NULL, INS_NO_WALK_ON, x, y);
237 
238  object_set_enemy(op, NULL);
239 
240  if (op->contr) {
241  safe_strncpy(op->contr->maplevel, newmap->path,
242  sizeof(op->contr->maplevel));
243  op->contr->count = 0;
244  }
245 
246  /* Update any golems */
247  if (op->type == PLAYER && op->contr->ranges[range_golem] != NULL) {
248  int i = object_find_free_spot(op->contr->ranges[range_golem], newmap, x, y, 1, SIZEOFFREE);
249  object_remove(op->contr->ranges[range_golem]);
250  if (i == -1) {
251  remove_friendly_object(op->contr->ranges[range_golem]);
252  object_free_drop_inventory(op->contr->ranges[range_golem]);
253  op->contr->ranges[range_golem] = NULL;
254  op->contr->golem_count = 0;
255  } else {
256  object_insert_in_map_at(op->contr->ranges[range_golem], newmap, NULL, 0, x+freearr_x[i], y+freearr_y[i]);
257  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);
258  }
259  }
260  op->direction = 0;
261 
262  /* since the players map is already loaded, we don't need to worry
263  * about pending objects.
264  */
266 
267  /* If the player is changing maps, we need to do some special things
268  * Do this after the player is on the new map - otherwise the force swap of the
269  * old map does not work.
270  */
271  if (oldmap != newmap) {
272  player_map_change_common(op, oldmap, newmap);
273  }
274 
275  map_newmap_cmd(op->contr->socket);
276 }
277 
278 void player_map_change_common(object* op, mapstruct* const oldmap,
279  mapstruct* const newmap) {
280  if (oldmap != NULL) {
282 
283  /* can be less than zero due to errors in tracking this */
284  if (oldmap->players <= 0) {
285  set_map_timeout(oldmap);
286  }
287  }
288 
290  newmap->timeout = 0;
292 }
293 
300 void set_map_timeout(mapstruct *oldmap) {
301 #if MAP_MAXTIMEOUT
302  oldmap->timeout = MAP_TIMEOUT(oldmap);
303  /* Do MINTIMEOUT first, so that MAXTIMEOUT is used if that is
304  * lower than the min value.
305  */
306 #if MAP_MINTIMEOUT
307  if (oldmap->timeout < MAP_MINTIMEOUT) {
308  oldmap->timeout = MAP_MINTIMEOUT;
309  }
310 #endif
311  if (oldmap->timeout > MAP_MAXTIMEOUT) {
312  oldmap->timeout = MAP_MAXTIMEOUT;
313  }
314 #else
315  /* save out the map */
316  swap_map(oldmap);
317 #endif /* MAP_MAXTIMEOUT */
318 }
319 
333 static char *clean_path(const char *file, char *newpath, int size) {
334  char *cp;
335 
336  strlcpy(newpath, file, size);
337  for (cp = newpath; *cp != '\0'; cp++) {
338  if (*cp == '/')
339  *cp = '_';
340  }
341  return newpath;
342 }
343 
361 static char *unclean_path(const char *src, char *newpath, int size) {
362  char *cp;
363 
364  cp = const_cast<char *>(strrchr(src, '/'));
365  if (cp)
366  strlcpy(newpath, cp+1, size);
367  else
368  strlcpy(newpath, src, size);
369 
370  for (cp = newpath; *cp != '\0'; cp++) {
371  if (*cp == '_')
372  *cp = '/';
373  }
374  return newpath;
375 }
376 
386 static void enter_random_map(object *pl, object *exit_ob) {
387  mapstruct *new_map;
388  char newmap_name[HUGE_BUF], buf[HUGE_BUF], *cp;
389  static int reference_number = 0;
390  RMParms rp;
391 
392  memset(&rp, 0, sizeof(RMParms));
393  rp.Xsize = -1;
394  rp.Ysize = -1;
395  rp.region = get_region_by_map(exit_ob->map);
396  if (exit_ob->msg)
397  set_random_map_variable(&rp, exit_ob->msg);
398  rp.origin_x = exit_ob->x;
399  rp.origin_y = exit_ob->y;
400  safe_strncpy(rp.origin_map, pl->map->path, sizeof(rp.origin_map));
401 
402  /* If we have a final_map, use it as a base name to give some clue
403  * as where the player is. Otherwise, use the origin map.
404  * Take the last component (after the last slash) to give
405  * shorter names without bogus slashes.
406  */
407  if (rp.final_map[0]) {
408  cp = strrchr(rp.final_map, '/');
409  if (!cp)
410  cp = rp.final_map;
411  } else {
412  cp = strrchr(rp.origin_map, '/');
413  if (!cp)
414  cp = rp.origin_map;
415  /* Need to strip of any trailing digits, if it has them */
416  strlcpy(buf, cp, sizeof(buf));
417  while (isdigit(buf[strlen(buf)-1]))
418  buf[strlen(buf)-1] = 0;
419  cp = buf;
420  }
421 
422  snprintf(newmap_name, sizeof(newmap_name), "/random/%s%04d", cp+1, reference_number++);
423 
424  /* now to generate the actual map. */
425  new_map = generate_random_map(newmap_name, &rp, NULL, exit_ob->map ? exit_ob->map->reset_group : NULL);
426 
427  /* Update the exit_ob so it now points directly at the newly created
428  * random maps. Not that it is likely to happen, but it does mean that a
429  * exit in a unique map leading to a random map will not work properly.
430  * It also means that if the created random map gets reset before
431  * the exit leading to it, that the exit will no longer work.
432  */
433  if (new_map) {
434  int x, y;
435 
436  x = EXIT_X(exit_ob) = MAP_ENTER_X(new_map);
437  y = EXIT_Y(exit_ob) = MAP_ENTER_Y(new_map);
438  EXIT_PATH(exit_ob) = add_string(newmap_name);
439  strlcpy(new_map->path, newmap_name, sizeof(new_map->path));
440  enter_map(pl, new_map, x, y);
441 
442  /* Make the initial map part of the same reset group so it doesn't
443  * reset before the random maps */
444  if (exit_ob->map && exit_ob->map->reset_group == NULL && new_map->reset_group) {
445  exit_ob->map->reset_group = add_string(new_map->reset_group);
446  }
447  }
448 }
449 
459 static void enter_fixed_template_map(object *pl, object *exit_ob) {
460  mapstruct *new_map;
461  char tmpnum[32], exitpath[HUGE_BUF], resultname[HUGE_BUF], tmpstring[HUGE_BUF], *sourcemap;
462  char sourcemap_buf[HUGE_BUF];
463  char new_map_name[MAX_BUF];
464 
465  /* Split the exit path string into two parts, one
466  * for where to store the map, and one for were
467  * to generate the map from.
468  */
469  strlcpy(exitpath, EXIT_PATH(exit_ob)+2, sizeof(exitpath));
470  sourcemap = strchr(exitpath, '!');
471  if (!sourcemap) {
474  "The %s is closed.",
475  exit_ob->name);
476  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);
477  return;
478  }
479  *sourcemap++ = '\0';
480 
481  /* If we are not coming from a template map, we can use relative directories
482  * for the map to generate from.
483  */
484  if (!exit_ob->map->is_template) {
485  /* We can't use exitpath directly, as sourcemap points there. */
486  path_combine_and_normalize(exit_ob->map->path, sourcemap, sourcemap_buf, sizeof(sourcemap_buf));
487  sourcemap = sourcemap_buf;
488  }
489 
490  /* Do replacement of %x, %y, and %n to the x coord of the exit, the y coord
491  * of the exit, and the name of the map the exit is on, respectively.
492  */
493  snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->x);
494  replace(exitpath, "%x", tmpnum, resultname, sizeof(resultname));
495 
496  snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->y);
497  strlcpy(tmpstring, resultname, sizeof(tmpstring));
498  replace(tmpstring, "%y", tmpnum, resultname, sizeof(resultname));
499 
500  strlcpy(tmpstring, resultname, sizeof(tmpstring));
501  replace(tmpstring, "%n", exit_ob->map->name, resultname, sizeof(resultname));
502 
503  /* If we are coming from another template map, use reletive paths unless
504  * indicated otherwise.
505  */
506  if (exit_ob->map->is_template && (resultname[0] != '/')) {
507  path_combine_and_normalize(exit_ob->map->path, resultname, new_map_name, sizeof(new_map_name));
508  } else {
509  create_template_pathname(resultname, new_map_name, sizeof(new_map_name));
510  }
511 
512  /* Attempt to load the map, if unable to, then
513  * create the map from the template.
514  */
515  new_map = ready_map_name(new_map_name, MAP_PLAYER_UNIQUE);
516  if (!new_map) {
517  char path[MAX_BUF];
518  create_pathname(sourcemap, path, MAX_BUF);
519  new_map = mapfile_load(path, MAP_PLAYER_UNIQUE);
520  if (!new_map) {
522  MSG_TYPE_COMMAND_FAILURE, "The %s is closed.",
523  exit_ob->name);
524  LOG(llevError,
525  "Template exit in '%s' (%d, %d) does not reference a valid "
526  "template. Make sure a template exists at '%s'.\n",
527  exit_ob->map->path, exit_ob->x, exit_ob->y, path);
528  return;
529  }
530  }
531 
532  assert(new_map);
533  /* set the path of the map to where it should be
534  * so we don't just save over the source map.
535  */
536  strlcpy(new_map->path, new_map_name, sizeof(new_map->path));
537  new_map->is_template = 1;
538  enter_map(pl, new_map, EXIT_X(exit_ob), EXIT_Y(exit_ob));
539 }
540 
550 static void enter_random_template_map(object *pl, object *exit_ob) {
551  mapstruct *new_map;
552  char tmpnum[32], resultname[HUGE_BUF], tmpstring[HUGE_BUF];
553  char new_map_name[MAX_BUF];
554  RMParms rp;
555 
556  /* Do replacement of %x, %y, and %n to the x coord of the exit, the y coord
557  * of the exit, and the name of the map the exit is on, respectively.
558  */
559  snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->x);
560  replace(EXIT_PATH(exit_ob)+3, "%x", tmpnum, resultname, sizeof(resultname));
561 
562  snprintf(tmpnum, sizeof(tmpnum), "%d", exit_ob->y);
563  strlcpy(tmpstring, resultname, sizeof(tmpstring));
564  replace(tmpstring, "%y", tmpnum, resultname, sizeof(resultname));
565 
566  strlcpy(tmpstring, resultname, sizeof(tmpstring));
567  replace(tmpstring, "%n", exit_ob->map->name, resultname, sizeof(resultname));
568 
569  /* If we are coming from another template map, use reletive paths unless
570  * indicated otherwise.
571  */
572  if (exit_ob->map->is_template && (resultname[0] != '/')) {
573  path_combine_and_normalize(exit_ob->map->path, resultname, new_map_name, sizeof(new_map_name));
574  } else {
575  create_template_pathname(resultname, new_map_name, sizeof(new_map_name));
576  }
577 
578  new_map = ready_map_name(new_map_name, MAP_PLAYER_UNIQUE);
579  if (!new_map) {
580  memset(&rp, 0, sizeof(RMParms));
581  rp.Xsize = -1;
582  rp.Ysize = -1;
583  rp.region = get_region_by_map(exit_ob->map);
584  if (exit_ob->msg)
585  set_random_map_variable(&rp, exit_ob->msg);
586  rp.origin_x = exit_ob->x;
587  rp.origin_y = exit_ob->y;
588  safe_strncpy(rp.origin_map, pl->map->path, sizeof(rp.origin_map));
589 
590  /* now to generate the actual map. */
591  new_map = generate_random_map(new_map_name, &rp, NULL, exit_ob->map ? exit_ob->map->reset_group : NULL);
592  }
593 
594  /* Update the exit_ob so it now points directly at the newly created
595  * random maps. Not that it is likely to happen, but it does mean that a
596  * exit in a unique map leading to a random map will not work properly.
597  * It also means that if the created random map gets reset before
598  * the exit leading to it, that the exit will no longer work.
599  */
600  if (new_map) {
601  int x, y;
602 
603  x = EXIT_X(exit_ob) = MAP_ENTER_X(new_map);
604  y = EXIT_Y(exit_ob) = MAP_ENTER_Y(new_map);
605  new_map->is_template = 1;
606  enter_map(pl, new_map, x, y);
607  }
608 }
609 
618 static void enter_unique_map(object *op, object *exit_ob) {
619  char apartment[HUGE_BUF], path[MAX_BUF];
620  mapstruct *newmap;
621 
622  if (EXIT_PATH(exit_ob)[0] == '/') {
623  snprintf(apartment, sizeof(apartment), "~%s/%s", op->name, clean_path(EXIT_PATH(exit_ob), path, sizeof(path)));
624  newmap = ready_map_name(apartment, MAP_PLAYER_UNIQUE);
625  if (!newmap) {
626  newmap = mapfile_load(EXIT_PATH(exit_ob), 0);
627  }
628  } else { /* relative directory */
629  char reldir[HUGE_BUF], tmpc[HUGE_BUF], *cp;
630 
631  if (exit_ob->map->unique) {
632  // Use player's current map path to construct base of relative path in 'src'
633  char* src = strdup(op->map->path);
634  char* slash = strrchr(src, '/');
635  if (slash == NULL) {
636  abort();
637  }
638  *slash = '\0';
639 
640  unclean_path(exit_ob->map->path, reldir, sizeof(reldir));
641 
642  /* Need to copy this over, as clean_path only has one static return buffer */
643  clean_path(reldir, tmpc, sizeof(tmpc));
644  /* Remove final component, if any */
645  if ((cp = strrchr(tmpc, '_')) != NULL)
646  *cp = 0;
647 
648  snprintf(apartment, sizeof(apartment), "%s/%s_%s", src, tmpc, clean_path(EXIT_PATH(exit_ob), path, sizeof(path)));
649 
650  newmap = ready_map_name(apartment, MAP_PLAYER_UNIQUE);
651  if (!newmap) {
652  newmap = mapfile_load(path_combine_and_normalize(reldir, EXIT_PATH(exit_ob), tmpc, sizeof(tmpc)), 0);
653  }
654  } else {
655  /* The exit is unique, but the map we are coming from is not unique. So
656  * use the basic logic - don't need to demangle the path name
657  */
658  path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), reldir, sizeof(reldir));
659  snprintf(apartment, sizeof(apartment), "~%s/%s", op->name, clean_path(reldir, path, sizeof(path)));
660  newmap = ready_map_name(apartment, MAP_PLAYER_UNIQUE);
661  if (!newmap) {
662  path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), reldir, sizeof(reldir));
663  newmap = ready_map_name(reldir, 0);
664  if (newmap)
665  apply_auto_fix(newmap);
666  }
667  }
668  }
669 
670  if (newmap) {
671  strlcpy(newmap->path, apartment, sizeof(newmap->path));
672  newmap->unique = 1;
673  enter_map(op, newmap, EXIT_X(exit_ob), EXIT_Y(exit_ob));
674  } else {
677  "The %s is closed.",
678  exit_ob->name);
679  /* Perhaps not critical, but I would think that the unique maps
680  * should be new enough this does not happen. This also creates
681  * a strange situation where some players could perhaps have visited
682  * such a map before it was removed, so they have the private
683  * map, but other players can't get it anymore.
684  */
685  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);
686  }
687 }
688 
689 void enter_player_maplevel(object *op) {
690  assert(op != NULL);
691  int flags = 0, x = op->x, y = op->y;
692  mapstruct *newmap;
693 
694  assert(op->type == PLAYER);
695 
696  /* newmap returns the map (if already loaded), or loads it for us. */
697  newmap = ready_map_name(op->contr->maplevel, flags);
698  if (!newmap) {
702  if (!newmap) {
703  LOG(llevError, "Fatal: Could not load emergency map!\n");
704  abort();
705  }
706 
708  "You find yourself somewhere unexpected...");
709  }
710 
711  /* as a special case, if coordinates are (-1, -1), then the item should
712  * be put at the default location. Used for loginmethod 0 (old clients). */
713  if (x == -1 && y == -1) {
714  x = MAP_ENTER_X(newmap);
715  y = MAP_ENTER_Y(newmap);
716  }
717 
718  enter_map(op, newmap, x, y);
719 }
720 
734 void enter_exit(object *op, object *exit_ob) {
735 #define PORTAL_DESTINATION_NAME "Town portal destination" /* this one should really be in a header file */
736  /* It may be nice to support other creatures moving across
737  * exits, but right now a lot of the code looks at op->contr,
738  * so thta is an RFE.
739  */
740  if (op->type != PLAYER)
741  return;
742 
743  assert(exit_ob != NULL);
744  assert(EXIT_PATH(exit_ob) != NULL);
745 
746  /* Don't word-of-recall out of a shop */
747  if ( exit_ob->subtype == SP_WORD_OF_RECALL ) {
748  /* Scan inventory for unpaid objects */
749  object *item = op->inv;
751  if (QUERY_FLAG(item, FLAG_UNPAID)) {
752  char buf[MAX_BUF];
753 
754  ob_describe(item, op, 1, buf, sizeof(buf));
756  "You feel a force fizzling away. You feel a vibration from: %s",buf);
757  return;
758  }
760  }
761 
762  /* Need to remove player from transport */
763  if (op->contr->transport)
764  ob_apply(op->contr->transport, op, AP_UNAPPLY);
765 
766  /* check to see if we make a template map
767  * Template maps have an EXIT_PATH in the form:
768  * /@[!]<MAP_NAME>!<TEMPLATE_PATH>
769  *
770  * <MAP_NAME> is the name of the destination map, which is saved in LOCALDIR/template-maps/.
771  * <TEMPLATE_PATH> is the path to a template map, used when <MAP_NAME> does not exist.
772  */
773  if (EXIT_PATH(exit_ob) && EXIT_PATH(exit_ob)[1] == '@') {
774  if (EXIT_PATH(exit_ob)[2] == '!') {
775  /* generate a template map randomly */
776  enter_random_template_map(op, exit_ob);
777  } else {
778  /* generate a template map from a fixed template */
779  enter_fixed_template_map(op, exit_ob);
780  }
781  }
782  /* check to see if we make a randomly generated map */
783  else if (EXIT_PATH(exit_ob) && EXIT_PATH(exit_ob)[1] == '!') {
784  enter_random_map(op, exit_ob);
785  } else if (QUERY_FLAG(exit_ob, FLAG_UNIQUE)) {
786  enter_unique_map(op, exit_ob);
787  } else {
788  int x = EXIT_X(exit_ob), y = EXIT_Y(exit_ob);
789  /* 'Normal' exits that do not do anything special
790  * Simple enough we don't need another routine for it.
791  */
792  mapstruct *newmap;
793  if (exit_ob->map) {
794  char tmp_path[HUGE_BUF];
795 
796  path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), tmp_path, sizeof(tmp_path));
797  newmap = ready_map_name(tmp_path, 0);
798  /* Random map was previously generated, but is no longer about. Lets generate a new
799  * map.
800  */
801  if (!newmap && !strncmp(EXIT_PATH(exit_ob), "/random/", 8)) {
802  /* Maps that go down have a message set. However, maps that go
803  * up, don't. If the going home has reset, there isn't much
804  * point generating a random map, because it won't match the maps.
805  */
806  if (exit_ob->msg) {
807  enter_random_map(op, exit_ob);
808  } else {
811  "The %s is closed.",
812  exit_ob->name);
813  return;
814  }
815 
816  /* For exits that cause damages (like pits). Don't know if any
817  * random maps use this or not.
818  */
819  if (exit_ob->stats.dam && op->type == PLAYER)
820  hit_player(op, exit_ob->stats.dam, exit_ob, exit_ob->attacktype, 1);
821  return;
822  }
823  } else {
824  /* For word of recall and other force objects
825  * They contain the full pathname of the map to go back to,
826  * so we don't need to normalize it.
827  * But we do need to see if it is unique or not
828  */
829  if (!strncmp(EXIT_PATH(exit_ob), settings.localdir, strlen(settings.localdir)))
830  newmap = ready_map_name(EXIT_PATH(exit_ob), MAP_PLAYER_UNIQUE);
831  else
832  newmap = ready_map_name(EXIT_PATH(exit_ob), 0);
833  }
834  if (!newmap) {
835  if (exit_ob->name)
838  "The %s is closed.",
839  exit_ob->name);
840  /* don't cry to momma if name is not set - as in tmp objects
841  * used by the savebed code and character creation */
842  return;
843  }
844 
845  if (x == -1 && y == -1) {
846  x = MAP_ENTER_X(newmap);
847  y = MAP_ENTER_Y(newmap);
848  }
849 
850  /* mids 02/13/2002 if exit is damned, update players death & WoR home-position and delete town portal */
851  if (QUERY_FLAG(exit_ob, FLAG_DAMNED)) {
852  object *tmp;
853 
854  /* remove an old force with a slaying field == PORTAL_DESTINATION_NAME */
856  if (tmp) {
859  }
860 
861  path_combine_and_normalize(exit_ob->map->path, EXIT_PATH(exit_ob), op->contr->savebed_map, sizeof(op->contr->savebed_map));
862  op->contr->bed_x = EXIT_X(exit_ob), op->contr->bed_y = EXIT_Y(exit_ob);
863  save_player(op, 1);
864  }
865 
866  enter_map(op, newmap, x, y);
867  }
868 
869  LOG(llevDebug, "%s enters %s\n", op->name, EXIT_PATH(exit_ob));
870 
871  /* For exits that cause damages (like pits) */
872  if (exit_ob->stats.dam && op->type == PLAYER)
873  hit_player(op, exit_ob->stats.dam, exit_ob, exit_ob->attacktype, 1);
874 
875  if (op->contr) {
876  object* exit_copy = object_new();
877  object_copy(exit_ob, exit_copy);
878  exit_copy->speed = 0; // Item isn't on map or in inv, but object_copy() may have added it to active list
879  object_update_speed(exit_copy);
880  exit_copy->map = exit_ob->map; // hack to set map without actually inserting
881  if (op->contr->last_exit) {
882  object_free(op->contr->last_exit, FREE_OBJ_NO_DESTROY_CALLBACK);
883  }
884  op->contr->last_exit = exit_copy;
885  }
886 }
887 
893 static int move_towards(object *ob, object *towards, unsigned int mindist) {
894  rv_vector rv;
895  get_rangevector(ob, towards, &rv, 0);
896  if (rv.direction != 0 && rv.distance > mindist && ob->speed_left > 0) {
897  move_player(ob, rv.direction);
898  }
899  return rv.direction;
900 }
901 
906 static bool object_on_exit(object* ob, object* exit) {
907  int x = exit->x;
908  int y = exit->y;
909  int sx, sy, sx2, sy2;
910  object_get_multi_size(exit, &sx, &sy, &sx2, &sy2);
911  return (ob->x >= x+sx2) && (ob->x <= x+sx) && (ob->y >= y+sy2) && (ob->y <= y+sy);
912 }
913 
917 static void do_follow(player *pl) {
918  assert(pl->followed_player != NULL);
919  player *followed = find_player_partial_name(pl->followed_player);
920  if (followed && followed->ob && followed->ob->map) {
921  if (query_flag(pl->ob, FLAG_WIZ)) {
922  rv_vector rv;
923  if (!get_rangevector(pl->ob, followed->ob, &rv, 0) || rv.distance > 4) {
924  int space = object_find_free_spot(pl->ob, followed->ob->map, followed->ob->x, followed->ob->y, 1, 25);
925  if (space == -1) {
927  space = 0;
928  }
929  object_remove(pl->ob);
930  object_insert_in_map_at(pl->ob, followed->ob->map, NULL, 0, followed->ob->x+freearr_x[space], followed->ob->y+freearr_y[space]);
931  map_newmap_cmd(pl->socket);
933  }
934  } else {
935  if (!can_follow(pl->ob, followed)) {
937  "%s stops letting you follow them.", pl->followed_player);
938  FREE_AND_CLEAR_STR(pl->followed_player);
939  return;
940  }
941  if (move_towards(pl->ob, followed->ob, 1)== 0 && followed->ob->contr->last_exit != NULL) {
942  // Move to and apply exit
943  object* exit = followed->ob->contr->last_exit;
944  if (!object_on_exit(pl->ob, exit)) {
945  move_towards(pl->ob, exit, 0);
946  } else {
947  enter_exit(pl->ob, exit);
948  }
949  }
950  }
951  } else {
953  "You stop following %s.", pl->followed_player);
954  FREE_AND_CLEAR_STR(pl->followed_player);
955  }
956 }
957 
963 static void process_players1(void) {
964  int flag;
965  player *pl, *plnext;
966 
967  /* Basically, we keep looping until all the players have done their actions. */
968  for (flag = 1; flag != 0; ) {
969  flag = 0;
970  for (pl = first_player; pl != NULL; pl = plnext) {
971  plnext = pl->next; /* In case a player exits the game in handle_player() */
972 
973  if (pl->ob == NULL)
974  continue;
975 
976  /* Only do this on the first pass - what we are recording
977  * here is the number of ticks the player has been online - not
978  * how many actions/moves the player has done.
979  */
980  if (!flag) pl->ticks_played++;
981 
982  if (pl->followed_player) {
983  do_follow(pl);
984  }
985 
986  if (pl->ob->speed_left > 0) {
987  if (handle_newcs_player(pl->ob))
988  flag = 1;
989  } /* end if player has speed left */
990 
991  /* If the player is not actively playing, don't make a
992  * backup save - nothing to save anyway. Plus, the
993  * map may not longer be valid. This can happen when the
994  * player quits - they exist for purposes of tracking on the map,
995  * but don't actually reside on any actual map.
996  */
997  if (QUERY_FLAG(pl->ob, FLAG_REMOVED))
998  continue;
999 
1000 #ifdef AUTOSAVE
1001  /* check for ST_PLAYING state so that we don't try to save off when
1002  * the player is logging in.
1003  */
1004  if ((pl->last_save_tick+AUTOSAVE) < pticks && pl->state == ST_PLAYING) {
1005  /* Don't save the player on unholy ground. Instead, increase the
1006  * tick time so it will be about 10 seconds before we try and save
1007  * again.
1008  */
1009  if (get_map_flags(pl->ob->map, NULL, pl->ob->x, pl->ob->y, NULL, NULL)&P_NO_CLERIC) {
1010  pl->last_save_tick += 100;
1011  } else {
1012  save_player(pl->ob, 1);
1013  pl->last_save_tick = pticks;
1014  hiscore_check(pl->ob, 1);
1015  }
1016  }
1017 #endif
1018  } /* end of for loop for all the players */
1019  } /* for flag */
1020  for (pl = first_player; pl != NULL; pl = pl->next) {
1021  int has_action = 1;
1022 
1023  pl->ob->weapon_speed_left += pl->ob->weapon_speed;
1024  if (pl->ob->weapon_speed_left > 1.0)
1025  pl->ob->weapon_speed_left = 1.0;
1026 
1027  pl->socket->sounds_this_tick = 0;
1028 
1029  if (settings.casting_time == TRUE) {
1030  if (pl->ob->casting_time > 0) {
1031  pl->ob->casting_time--;
1032  has_action = 0;
1033  }
1034  }
1035  /* If the character is idle (standing around resting) increase
1036  * regen rates.
1037  */
1038  if (has_action && pl->ob->speed_left > 0) {
1039  pl->ob->last_heal -= 2;
1040  pl->ob->last_sp -= 2;
1041  pl->ob->last_grace -= 2;
1042  pl->ob->last_eat += 2; /* Slow down food consumption */
1043  }
1044  do_some_living(pl->ob);
1045  }
1046 }
1047 
1055 static void process_players2(void) {
1056  player *pl;
1057 
1058  /* Then check if any players should use weapon-speed instead of speed */
1059  for (pl = first_player; pl != NULL; pl = pl->next) {
1060  /* The code that did weapon_sp handling here was out of place -
1061  * this isn't called until after the player has finished there
1062  * actions, and is thus out of place. All we do here is bounds
1063  * checking.
1064  */
1065  if (pl->has_hit) {
1066  /* This needs to be here - if the player is running, we need to
1067  * clear this each tick, but new commands are not being received
1068  * so execute_newserver_command() is never called
1069  */
1070  pl->has_hit = 0;
1071  } else if (pl->ob->speed_left > pl->ob->speed)
1072  pl->ob->speed_left = pl->ob->speed;
1073  }
1074 }
1075 
1076 #define SPEED_DEBUG
1077 
1078 static bool object_in_icecube(object *op) {
1079  return op->env != NULL && strcmp(op->env->arch->name, "icecube") == 0;
1080 }
1081 
1085 void process_events(void) {
1086  object *op;
1087  object marker;
1088  tag_t tag;
1089 
1090  process_players1();
1091 
1092  memset(&marker, 0, sizeof(object));
1093  /* Put marker object at beginning of active list */
1094  marker.active_next = active_objects;
1095 
1096  if (marker.active_next)
1097  marker.active_next->active_prev = &marker;
1098  marker.active_prev = NULL;
1099  active_objects = &marker;
1100 
1101  while (marker.active_next) {
1102  op = marker.active_next;
1103  tag = op->count;
1104 
1105  /* Move marker forward - swap op and marker */
1106  op->active_prev = marker.active_prev;
1107 
1108  if (op->active_prev)
1109  op->active_prev->active_next = op;
1110  else
1111  active_objects = op;
1112 
1113  marker.active_next = op->active_next;
1114 
1115  if (marker.active_next)
1116  marker.active_next->active_prev = &marker;
1117  marker.active_prev = op;
1118  op->active_next = &marker;
1119 
1120  /* Now process op */
1121  if (QUERY_FLAG(op, FLAG_FREED)) {
1122  LOG(llevError, "BUG: process_events(): Free object on list\n");
1123  op->speed = 0;
1125  continue;
1126  }
1127 
1128  /* I've seen occasional crashes due to this - the object is removed,
1129  * and thus the map it points to (last map it was on) may be bogus
1130  * The real bug is to try to find out the cause of this - someone
1131  * is probably calling object_remove() without either an insert_ob or
1132  * object_free_drop_inventory() afterwards, leaving an object dangling.
1133  * But I'd rather log this and continue on instead of crashing.
1134  * Don't remove players - when a player quits, the object is in
1135  * sort of a limbo, of removed, but something we want to keep
1136  * around.
1137  */
1138  if (QUERY_FLAG(op, FLAG_REMOVED)
1139  && op->type != PLAYER
1140  && op->map
1141  && op->map->in_memory != MAP_IN_MEMORY) {
1142  StringBuffer *sb;
1143  char *diff;
1144 
1145  LOG(llevError, "BUG: process_events(): Removed object on list\n");
1146  sb = stringbuffer_new();
1147  object_dump(op, sb);
1148  diff = stringbuffer_finish(sb);
1149  LOG(llevError, "%s\n", diff);
1150  free(diff);
1152  continue;
1153  }
1154 
1155  if (!op->speed) {
1156  LOG(llevError, "BUG: process_events(): Object %s has no speed, but is on active list\n", op->arch->name);
1158  continue;
1159  }
1160 
1161  if (op->map == NULL
1162  && op->env == NULL
1163  && op->name
1164  && op->type != MAP) {
1165  LOG(llevError, "BUG: process_events(): Object without map or inventory is on active list: %s (%d)\n", op->name, op->count);
1166  op->speed = 0;
1168  continue;
1169  }
1170 
1171  /* Seen some cases where process_object() is crashing because
1172  * the object is on a swapped out map. But can't be sure if
1173  * something in the chain of events caused the object to
1174  * change maps or was just never removed - this will
1175  * give some clue as to its state before call to
1176  * process_object
1177  */
1178  if (op->map && op->map->in_memory != MAP_IN_MEMORY) {
1179  LOG(llevError, "BUG: process_events(): Processing object on swapped out map: %s (%d), map=%s\n", op->name, op->count, op->map->path);
1180  }
1181 
1182  /* Animate the object. Bug of feature that andim_speed
1183  * is based on ticks, and not the creatures speed?
1184  */
1185  if ((op->anim_speed && op->last_anim >= op->anim_speed)
1186  || (op->temp_animation && op->last_anim >= op->temp_anim_speed)) {
1187  op->state++;
1188  if ((op->type == PLAYER) || (op->type == MONSTER))
1189  animate_object(op, op->facing);
1190  else
1191  animate_object(op, op->direction);
1192  op->last_anim = 1;
1193  } else {
1194  op->last_anim++;
1195  }
1196 
1197  if (op->speed_left > 0) {
1198  // Players are special because their speed_left has already been
1199  // reduced in do_server(). Players effectively process every tick
1200  // so long they have non-zero speed left.
1201  if (op->type != PLAYER) {
1202  // Objects in icecubes decay at a slower rate
1203  if (object_in_icecube(op)) {
1204  op->speed_left -= 10;
1205  } else {
1206  op->speed_left -= 1;
1207  }
1208  }
1209  process_object(op);
1210  if (object_was_destroyed(op, tag))
1211  continue;
1212  } else {
1213  // Custom-made creatures for random maps can still have negative speeds, so catch that with FABS().
1214  op->speed_left += FABS(op->speed);
1215  }
1216  if (settings.casting_time == TRUE && op->casting_time > 0)
1217  op->casting_time--;
1218  }
1219 
1220  /* Remove marker object from active list */
1221  if (marker.active_prev != NULL)
1222  marker.active_prev->active_next = NULL;
1223  else
1224  active_objects = NULL;
1225 
1226  process_players2();
1227 }
1228 
1233 void clean_tmp_files(void) {
1234  mapstruct *m, *next;
1235  for (m = first_map; m != NULL; m = next) {
1236  next = m->next;
1237  if (m->in_memory == MAP_IN_MEMORY) {
1238  // Save all maps currently in memory, because they might contain
1239  // unique tiles that have not been written to disk.
1240  if (settings.recycle_tmp_maps) {
1241  // swap_map() also updates the write log.
1242  swap_map(m);
1243  } else {
1245  // FIXME: Unfortunately, save_map() also unnecessarily saves
1246  // non-unique tiles to a new temporary file, so we have to
1247  // get rid of it here.
1248  clean_tmp_map(m);
1249  }
1250  } else {
1251  // Remove the swap file.
1252  clean_tmp_map(m);
1253  }
1254  }
1255  write_todclock(); /* lets just write the clock here */
1256 }
1257 
1259 void cleanup(void) {
1260  metaserver2_exit();
1261  LOG(llevInfo, "Cleaning up...\n");
1262  clean_tmp_files();
1264  accounts_save();
1265 
1266  close_modules();
1267 
1268 #ifdef MEMORY_DEBUG
1269  free_all_maps();
1270  free_style_maps();
1271 #endif
1272  cleanupPlugins();
1273  commands_clear();
1274 #ifdef MEMORY_DEBUG
1275  free_all_archs();
1277  free_all_images();
1279  free_all_recipes();
1281  free_all_god();
1282  free_all_anim();
1283  i18n_free();
1284  free_loader();
1285  free_globals();
1286  free_server();
1288  free_knowledge();
1289  free_quest();
1291  /* See what the string data that is out there that hasn't been freed. */
1292  /* LOG(llevDebug, "%s", ss_dump_table(0xff));*/
1293 #endif
1294  exit(0);
1295 }
1296 
1305 void leave(player *pl, int draw_exit) {
1306  if (!QUERY_FLAG(pl->ob, FLAG_REMOVED)) {
1307  pets_terminate_all(pl->ob);
1308  object_remove(pl->ob);
1309  }
1310 
1311  pl->socket->status = Ns_Dead;
1312  LOG(llevInfo, "logout: %s from %s\n", pl->ob->name, pl->socket->host);
1313 
1314  strcpy(pl->ob->contr->killer, "left");
1315  hiscore_check(pl->ob, 1);
1316 
1317  /* If this player is the captain of the transport, need to do
1318  * some extra work. By the time we get here, object_remove()
1319  * should have already been called.
1320  */
1321  if (pl->transport && pl->transport->contr == pl) {
1322  /* If inv is a non player, inv->contr will be NULL, but that
1323  * is OK.
1324  */
1325  if (pl->transport->inv)
1326  pl->transport->contr = pl->transport->inv->contr;
1327  else
1328  pl->transport->contr = NULL;
1329 
1330  if (pl->transport->contr) {
1331  char name[MAX_BUF];
1332 
1333  query_name(pl->transport, name, MAX_BUF);
1334  draw_ext_info_format(NDI_UNIQUE, 0, pl->transport->contr->ob,
1336  "%s has left. You are now the captain of %s",
1337  pl->ob->name, name);
1338  }
1339  }
1340 
1341  if (pl->ob->map) {
1342  if (pl->ob->map->in_memory == MAP_IN_MEMORY)
1343  pl->ob->map->timeout = MAP_TIMEOUT(pl->ob->map);
1344  pl->ob->map = NULL;
1345  }
1346  pl->ob->type = DEAD_OBJECT; /* To avoid problems with inventory window */
1347  party_leave(pl->ob);
1348  /* If a hidden dm dropped connection do not create
1349  * inconsistencies by showing that they have left the game
1350  */
1351  if (!(QUERY_FLAG(pl->ob, FLAG_WIZ) && pl->ob->contr->hidden)
1352  && (draw_exit) && (pl->state != ST_GET_NAME && pl->state != ST_GET_PASSWORD && pl->state != ST_CONFIRM_PASSWORD))
1355  "%s left the game.",
1356  pl->ob->name);
1357 }
1358 
1366 int forbid_play(void) {
1367 #if !defined(_IBMR2) && !defined(___IBMR2) && defined(PERM_FILE)
1368  char buf[MAX_BUF], day[MAX_BUF];
1369  FILE *fp;
1370  time_t clock;
1371  struct tm *tm;
1372  int i, start, stop, forbit = 0;
1373 
1374  clock = time(NULL);
1375  tm = (struct tm *)localtime(&clock);
1376 
1377  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, PERM_FILE);
1378  if ((fp = fopen(buf, "r")) == NULL)
1379  return 0;
1380 
1381  while (fgets(buf, sizeof(buf), fp)) {
1382  if (buf[0] == '#')
1383  continue;
1384  if (!strncmp(buf, "msg", 3)) {
1385  if (forbit)
1386  while (fgets(buf, sizeof(buf), fp)) /* print message */
1387  fputs(buf, logfile);
1388  break;
1389  } else if (sscanf(buf, "%s %d%*c%d\n", day, &start, &stop) != 3) {
1390  LOG(llevDebug, "Warning: Incomplete line in permission file ignored.\n");
1391  continue;
1392  }
1393 
1394  for (i = 0; i < 7; i++) {
1395  if (!strncmp(buf, days[i], 3)
1396  && (tm->tm_wday == i)
1397  && (tm->tm_hour >= start)
1398  && (tm->tm_hour < stop))
1399  forbit = 1;
1400  }
1401  }
1402 
1403  fclose(fp);
1404 
1405  return forbit;
1406 #else
1407  return 0;
1408 #endif
1409 }
1410 
1411 static void save_and_kick_all_players(void) {
1412  for (player *pl = first_player; pl != NULL; ) {
1413  player *npl = pl->next;
1414  save_player(pl->ob, 0);
1415  leave(pl, 0);
1417  pl = npl;
1418  }
1419 }
1420 
1421 static void do_shutdown(void) {
1423  MSG_TYPE_ADMIN_DM, "The server has shut down.");
1425 
1426  // Maps are saved out in clean_tmp_files(), called by cleanup().
1427  cleanup();
1428 }
1429 
1433 static bool check_shutdown(void) {
1434  if (shutdown_flag == 1) {
1435  LOG(llevInfo, "Received SIGINT; shutting down...\n");
1436  return true;
1437  }
1438 
1440  return false;
1441  }
1442 
1444  if (count_players() == 0) {
1445  if (shutdown_state.time == 0) {
1446  // Start idle countdown
1447  shutdown_state.time = time(NULL);
1448  return false;
1449  } else {
1450  time_t diff = time(NULL) - shutdown_state.time;
1451  if (diff > 60) {
1452  LOG(llevInfo, "No active players in the last %ld seconds, shutting down...\n", diff);
1453  return true;
1454  } else {
1455  return false;
1456  }
1457  }
1458  } else {
1459  // Reset idle time, since there are players
1460  shutdown_state.time = 0;
1461  }
1462  return false;
1463  }
1464 
1465  assert(shutdown_state.type == SHUTDOWN_TIME);
1466 
1467  /* If a timed shutdown is coming, remind players periodically. */
1468  time_t time_left = shutdown_state.time - time(NULL);
1469 
1470  for (unsigned int i = shutdown_state.next_warn; i < sizeof(shutdown_warn_times) / sizeof(int); i++) {
1471  if (shutdown_warn_times[i] == (int)ceil(time_left / 60.0)) {
1474  "Server shutting down in %d minutes.", shutdown_warn_times[i]);
1475  shutdown_state.next_warn = i + 1;
1476  return false;
1477  }
1478  }
1479 
1480  if (time_left <= 0) {
1481  return true;
1482  }
1483  return false;
1484 }
1485 
1490 void login_check_shutdown(object* const op) {
1492  return;
1493  }
1494 
1498  "This server will shut down when all players leave.");
1499  return;
1500  }
1501 
1502  assert(shutdown_state.type == SHUTDOWN_TIME);
1503 
1504  time_t time_left = shutdown_state.time - time(NULL);
1505  if (time_left <= 60*shutdown_warn_times[0]) {
1508  "This server will shut down in %lu minutes.", time_left / 60);
1509  }
1510 }
1511 
1526 static void do_specials(void) {
1527  if (check_shutdown()) {
1528  do_shutdown();
1529  }
1530 
1531 #ifdef CS_LOGSTATS
1532  if ((time(NULL)-cst_lst.time_start) >= CS_LOGTIME) {
1533  write_cs_stats();
1534  }
1535 #endif
1536 
1537  if (!(pticks%10))
1539 
1540 #ifdef WATCHDOG
1541  if (!(pticks%503))
1542  watchdog();
1543 #endif
1544 
1545  if (!(pticks%PTICKS_PER_CLOCK))
1546  tick_the_clock();
1547 
1548  if (!(pticks%509))
1549  flush_old_maps(); /* Clears the tmp-files of maps which have reset */
1550 
1551  if (!(pticks%2503))
1552  fix_weight(); /* Hack to fix weightproblems caused by bugs */
1553 
1554  if (!(pticks%2521))
1555  metaserver_update(); /* 2500 ticks is about 5 minutes */
1556 
1557  if (!(pticks%2531))
1558  accounts_save();
1559 
1560  if (!(pticks%5003))
1562 
1563  if (!(pticks%5009))
1565 
1566  if (!(pticks%5011))
1568 
1569  if (!(pticks%12503))
1570  fix_luck();
1571 }
1572 
1581 void server_main(int argc, char *argv[]) {
1582  PROFILE_BEGIN();
1583 #ifdef WIN32 /* ---win32 this sets the win32 from 0d0a to 0a handling */
1584  _fmode = _O_BINARY;
1585 #endif
1586 
1587 #ifndef WIN32
1588  /* Here we check that we aren't root or suid */
1589  if (getuid() == 0 || geteuid() == 0) {
1590  fprintf(stderr,
1591  "Running crossfire-server as root is a bad idea; aborting!\n"
1592  "Please run it again as a normal, unprivileged user.\n");
1593  exit(EXIT_FAILURE);
1594  }
1595 #endif
1596 
1597 #ifdef DEBUG_MALLOC_LEVEL
1598  malloc_debug(DEBUG_MALLOC_LEVEL);
1599 #endif
1600 
1601  init(argc, argv);
1602  initPlugins(); /* GROS - Init the Plugins */
1603  // Give feedback that loading is complete. This prevents confusion on when it is done loading.
1604  PROFILE_END(diff, LOG(llevInfo, "Initialization complete (%ld ms). Waiting for connections.\n", diff/1000));
1605 #ifdef WIN32
1606  while (bRunning) {
1607 #else
1608  while (TRUE) {
1609 #endif
1610  nroferrors = 0;
1611 
1612  tick_game_time();
1613  do_server();
1614  process_events(); /* "do" something with objects with speed */
1615  cftimer_process_timers(); /* Process the crossfire Timers */
1617  check_active_maps(); /* Removes unused maps after a certain timeout */
1618  do_specials(); /* Routines called from time to time. */
1619  update_players();
1620  }
1621 
1622  /* This is unreachable. */
1623  abort();
1624 }
write_book_archive
void write_book_archive(void)
Definition: readable.cpp:1989
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Definition: object.h:70
fix_weight
void fix_weight(void)
Definition: player.cpp:3890
check_shutdown
static bool check_shutdown(void)
Definition: server.cpp:1433
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:536
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:1233
settings
struct Settings settings
Definition: init.cpp:139
INS_NO_WALK_ON
#define INS_NO_WALK_ON
Definition: object.h:573
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:138
ST_GET_PASSWORD
#define ST_GET_PASSWORD
Definition: define.h:547
MONSTER
@ MONSTER
Definition: object.h:205
llevError
@ llevError
Definition: logger.h:11
FABS
#define FABS(x)
Definition: define.h:22
MSG_TYPE_ADMIN_PLAYER
#define MSG_TYPE_ADMIN_PLAYER
Definition: newclient.h:485
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
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:1958
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:179
diamondslots.x
x
Definition: diamondslots.py:15
ready_map_name
mapstruct * ready_map_name(const char *name, int flags)
Definition: map.cpp:1759
SIZEOFFREE1
#define SIZEOFFREE1
Definition: define.h:153
CFweardisguise.tag
tag
Definition: CFweardisguise.py:25
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
RMParms::origin_y
int origin_y
Definition: random_map.h:88
flush_old_maps
void flush_old_maps(void)
Definition: swap.cpp:289
ST_GET_NAME
#define ST_GET_NAME
Definition: define.h:546
set_map_timeout
void set_map_timeout(mapstruct *oldmap)
Definition: server.cpp:300
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:334
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
RMParms::region
struct region * region
Definition: random_map.h:96
player::ob
object * ob
Definition: player.h:177
do_server
void do_server(void)
Definition: loop.cpp:564
do_follow
static void do_follow(player *pl)
Definition: server.cpp:917
Settings::recycle_tmp_maps
uint8_t recycle_tmp_maps
Definition: global.h:272
MAP_MAXTIMEOUT
#define MAP_MAXTIMEOUT
Definition: config.h:407
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.c:2579
guildjoin.ob
ob
Definition: guildjoin.py:42
Settings::localdir
const char * localdir
Definition: global.h:249
enter_random_map
static void enter_random_map(object *pl, object *exit_ob)
Definition: server.cpp:386
time
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long time
Definition: arch-handbook.txt:206
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:403
replace
void replace(const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
Definition: utils.cpp:327
flags
static const flag_definition flags[]
Definition: gridarta-types-convert.cpp:101
Ice.tmp
int tmp
Definition: Ice.py:207
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:93
PROFILE_BEGIN
#define PROFILE_BEGIN(expr)
Definition: global.h:372
RMParms::origin_map
char origin_map[RM_SIZE]
Definition: random_map.h:55
free_knowledge
void free_knowledge(void)
Definition: knowledge.cpp:1277
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
RMParms::Ysize
int Ysize
Definition: random_map.h:75
mapstruct::is_template
uint32_t is_template
Definition: map.h:328
range_golem
@ range_golem
Definition: player.h:34
enter_player_maplevel
void enter_player_maplevel(object *op)
Definition: server.cpp:689
mapstruct::path
char path[HUGE_BUF]
Definition: map.h:355
MSG_TYPE_MISC
#define MSG_TYPE_MISC
Definition: newclient.h:402
party_obsolete_parties
void party_obsolete_parties(void)
Definition: party.cpp:215
free_all_maps
void free_all_maps(void)
Definition: map.cpp:1951
pticks
uint32_t pticks
Definition: time.cpp:47
buf
StringBuffer * buf
Definition: readable.cpp:1552
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
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
query_flag
static int query_flag(const object *op, int flag)
Definition: object.h:496
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:393
move_towards
static int move_towards(object *ob, object *towards, unsigned int mindist)
Definition: server.cpp:893
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
Ns_Dead
@ Ns_Dead
Definition: newserver.h:67
MSG_TYPE_ADMIN_DM
#define MSG_TYPE_ADMIN_DM
Definition: newclient.h:486
PROFILE_END
#define PROFILE_END(var, expr)
Definition: global.h:377
object::y
int16_t y
Definition: object.h:335
RMParms::Xsize
int Xsize
Definition: random_map.h:74
m
static event_registration m
Definition: citylife.cpp:425
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Definition: map.h:127
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.cpp:76
apply_auto_fix
void apply_auto_fix(mapstruct *m)
Definition: main.cpp:258
space
Crossfire Protocol most of the time after the actual code was already omit certain important and possibly make life miserable any new developer or curious player should be able to find most of the relevant information here If inconsistencies are found or this documentation proves to be consider the latest server side protocol code in the public source code repository as the authoritative reference Introduction If you were ever curious enough to telnet or netcat to a Crossfire chances are you were sorely disappointed While the protocol may seem to use plain text at it actually uses a mix of ASCII and binary data This handbook attempts to document various aspects of the Crossfire protocol As consult the README file to find out how to get in touch with helpful people via mailing and more History the communications plan was set to be a text based system It was up to the server and client to parse these messages and determine what to do These messages were assumed to be line per message At a reasonably early stage of Eric Anderson wrote a then the data itself you could send many data and after the other end could decode these commands This works fairly but I think the creation of numerous sub packets has some performance hit the eutl was not especially well so writing a client for a different platform became more Eric left to work on other products shortly after writing his which didn t really leave anyone with a full understanding of the socket code I have decided to remove the eutl dependency At least one advantage is that having this network related code directly in the client and server makes error handling a bit easier cleaner Packet Format the outside packet method the byte size for the size information is not included here Eutl originally used bytes for the size to bytes seems it makes a least some sense The actual data is something of the nature of the commands listed below It is a text followed by possible other data The remaining data can be binary it is up to the client and server to decode what it sent The commands as described below is just the data portion of the packet If writing a new remember that you must take into account the size of the packet There is no termination of other than knowing how long it should be For most everything that is sent is text This is more or less how things worked under except it packed the ints into bytes in a known order In some we handle ints as in they are sent as binary information How any command handles it is detailed below in the command description The S and C represent the direction of the we use MSB as well as any ints or shorts that get sent inside the packets All packets are defined to have at least one word of followed by a space
Definition: protocol.txt:85
login_check_shutdown
void login_check_shutdown(object *const op)
Definition: server.cpp:1490
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1555
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:1366
MAP_MINTIMEOUT
#define MAP_MINTIMEOUT
Definition: config.h:409
write_todclock
void write_todclock(void)
Definition: init.cpp:518
final_free_player
void final_free_player(player *pl)
Definition: init.cpp:455
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:333
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.cpp:592
Settings::emergency_x
uint16_t emergency_x
Definition: global.h:300
RMParms
Definition: random_map.h:14
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
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:4735
clean_tmp_map
void clean_tmp_map(mapstruct *m)
Definition: map.cpp:1942
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:1085
FLAG_FREED
#define FLAG_FREED
Definition: define.h:233
server_main
void server_main(int argc, char *argv[])
Definition: server.cpp:1581
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Definition: map.cpp:2286
do_specials
static void do_specials(void)
Definition: server.cpp:1526
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:1344
object_on_exit
static bool object_on_exit(object *ob, object *exit)
Definition: server.cpp:906
enter_exit
void enter_exit(object *op, object *exit_ob)
Definition: server.cpp:734
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
object_free
void object_free(object *ob, int flags)
Definition: object.cpp:1587
init
pluglist shows those as well as a short text describing each the list will simply appear empty The keyword for the Python plugin is Python plugout< keyword > Unloads a given identified by its _keyword_ So if you want to unload the Python you need to do plugout Python plugin< libname > Loads a given whose _filename_ is libname So in the case of you d have to do a plugin cfpython so Note that all filenames are relative to the default plugin it tries to load all available files in the SHARE plugins directory as plugin libraries It first displays the Initializing the plugin has the opportunity to signal itself by a message on the console Then the server displays an informative message containing both the plugin content and its keyword For the Python the standard load process thus GreenGoblin When a plugin has been it can request to be warned whenever a global event and are named freely by the developer If the directory doesn t nothing will happen< event name > can be init
Definition: plugins.txt:54
tag_t
uint32_t tag_t
Definition: object.h:14
mapstruct::reset_group
sstring reset_group
Definition: map.h:326
rproto.h
sproto.h
logfile
FILE * logfile
Definition: init.cpp:114
RMParms::origin_x
int origin_x
Definition: random_map.h:89
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:963
MSG_TYPE_SPELL
#define MSG_TYPE_SPELL
Definition: newclient.h:400
Settings::casting_time
uint8_t casting_time
Definition: global.h:270
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:1078
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:478
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:2095
MAP_WIDTH
#define MAP_WIDTH(m)
Definition: map.h:74
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:144
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:1268
free_all_god
void free_all_god(void)
Definition: holy.cpp:327
path
pluglist shows those as well as a short text describing each the list will simply appear empty The keyword for the Python plugin is Python plugout< keyword > Unloads a given identified by its _keyword_ So if you want to unload the Python you need to do plugout Python plugin< libname > Loads a given whose _filename_ is libname So in the case of you d have to do a plugin cfpython so Note that all filenames are relative to the default plugin path(SHARE/plugins). Console messages. ----------------- When Crossfire starts
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:117
RANDOM
#define RANDOM()
Definition: define.h:644
free_loader
void free_loader(void)
Definition: loader.c:5333
metaserver2_exit
void metaserver2_exit()
Definition: metaserver.cpp:485
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:618
MSG_TYPE_COMMAND_FAILURE
#define MSG_TYPE_COMMAND_FAILURE
Definition: newclient.h:520
can_follow
bool can_follow(object *, player *)
Definition: c_wiz.cpp:2757
player_map_change_common
void player_map_change_common(object *op, mapstruct *const oldmap, mapstruct *const newmap)
Definition: server.cpp:278
ST_PLAYING
#define ST_PLAYING
Definition: define.h:541
find_dir_2
int find_dir_2(int x, int y)
Definition: object.cpp:3668
RMParms::final_map
char final_map[RM_SIZE]
Definition: random_map.h:57
pets_attempt_follow
void pets_attempt_follow(object *for_owner, int force)
Definition: pets.cpp:249
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:4149
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
swap_map
int swap_map(mapstruct *map)
Definition: swap.cpp:135
llevInfo
@ llevInfo
Definition: logger.h:12
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:251
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:622
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:80
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:299
save_and_kick_all_players
static void save_and_kick_all_players(void)
Definition: server.cpp:1411
item
Definition: item.py:1
mapstruct
Definition: map.h:314
create_pathname
char * create_pathname(const char *name, char *buf, size_t size)
Definition: map.cpp:103
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:252
animate_object
void animate_object(object *op, int dir)
Definition: anim.cpp:44
update_players
void update_players(void)
Definition: loop.cpp:707
mapstruct::name
char * name
Definition: map.h:317
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:3550
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:550
object::msg
sstring msg
Definition: object.h:330
rv_vector
Definition: map.h:370
hit_player
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
Definition: attack.cpp:1902
exit
Install Bug reporting Credits but rather whatever guild name you are using *With the current map and server there are three they and GreenGoblin *Whatever name you give the folder should but it will still use GUILD_TEMPLATE *You can change what guild it uses by editing the map files Modify Map or objects if you want to use the optional Python based Guild Storage hall The first three are on the main the next two are in the guild_hq and the final one is in hallofjoining Withe the Storage three objects are found on the main floor and the last two are in the basement It s not that but you will need a map editor You find the object that has the click edit and change the line script options(which currently is "GUILD_TEMPALTE") to the guild you wish to use. And make sure you use the same one for all of them or it won 't work. Here 's a quick HOWTO for using the map editor to make these changes edit the mainfloor map exit(x15, y29 - set to/Edit/This/Exit/Path in the template) back to the world map as well. If you are using the Storage Hall map(storage_hall)
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:439
free_server
void free_server(void)
Definition: init.cpp:1121
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:331
MAP_HEIGHT
#define MAP_HEIGHT(m)
Definition: map.h:76
MAP_ENTER_Y
#define MAP_ENTER_Y(m)
Definition: map.h:83
NDI_DK_ORANGE
#define NDI_DK_ORANGE
Definition: newclient.h:237
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:669
get_rangevector
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
Definition: map.cpp:2519
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
MAP_ENTER_X
#define MAP_ENTER_X(m)
Definition: map.h:81
process_object
void process_object(object *op)
Definition: time.cpp:796
CS_Stats::time_start
time_t time_start
Definition: newclient.h:687
object::active_next
object * active_next
Definition: object.h:287
object_remove
void object_remove(object *op)
Definition: object.cpp:1828
shutdown_state
struct shutdown_s shutdown_state
Definition: c_wiz.cpp:44
cleanup
void cleanup(void)
Definition: server.cpp:1259
leave
void leave(player *pl, int draw_exit)
Definition: server.cpp:1305
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
do_some_living
void do_some_living(object *op)
Definition: player.cpp:3272
P_NO_CLERIC
#define P_NO_CLERIC
Definition: map.h:237
mapstruct::unique
uint32_t unique
Definition: map.h:327
save_map
int save_map(mapstruct *m, int flag)
Definition: map.cpp:1394
shutdown_s::next_warn
int next_warn
Definition: commands.h:51
fix_luck
void fix_luck(void)
Definition: player.cpp:3906
check_active_maps
void check_active_maps(void)
Definition: swap.cpp:199
object::stats
living stats
Definition: object.h:378
commands_clear
void commands_clear()
Definition: commands.cpp:345
count_players
int count_players(void)
Definition: metaserver.cpp:48
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
Settings::crypt_mode
uint8_t crypt_mode
Definition: global.h:330
StringBuffer
Definition: stringbuffer.cpp:25
TRUE
#define TRUE
Definition: compat.h:11
Settings::emergency_y
uint16_t emergency_y
Definition: global.h:300
do_shutdown
static void do_shutdown(void)
Definition: server.cpp:1421
CS_LOGTIME
#define CS_LOGTIME
Definition: config.h:188
cst_lst
CS_Stats cst_lst
Definition: newclient.h:690
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:374
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
MSG_TYPE_ADMIN
#define MSG_TYPE_ADMIN
Definition: newclient.h:391
rv_vector::distance
unsigned int distance
Definition: map.h:371
Settings::confdir
const char * confdir
Definition: global.h:247
FORCE
@ FORCE
Definition: object.h:229
enter_fixed_template_map
static void enter_fixed_template_map(object *pl, object *exit_ob)
Definition: server.cpp:459
knowledge_process_incremental
void knowledge_process_incremental(void)
Definition: knowledge.cpp:1436
object.h
tick_game_time
void tick_game_time()
Definition: time.cpp:181
events_execute_global_event
void events_execute_global_event(int eventcode,...)
Definition: events.cpp:27
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:1055
AUTOSAVE
#define AUTOSAVE
Definition: config.h:594
player_update_bg_music
void player_update_bg_music(object *player)
Definition: sounds.cpp:161
Settings::emergency_mapname
char * emergency_mapname
Definition: global.h:299
unclean_path
static char * unclean_path(const char *src, char *newpath, int size)
Definition: server.cpp:361
crypt_string
static char const * crypt_string(char const *str, char const *salt)
Definition: server.cpp:70