Crossfire Server, Trunk  1.75.0
map.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 <ctype.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <math.h>
28 
29 #ifndef WIN32 /* ---win32 exclude header */
30 #include <unistd.h>
31 #endif /* win32 */
32 
33 #include "sproto.h"
34 #include "loader.h"
35 #include "output_file.h"
36 #include "path.h"
37 #include "stats.h"
38 
39 static void free_all_objects(mapstruct *m);
40 
46 const char *const map_layer_name[MAP_LAYERS] = {
47  "floor", "no_pick", "no_pick", "item", "item",
48  "item", "living", "living", "fly", "fly"
49 };
50 
53  uint8_t high_layer;
54  uint8_t honor_visibility;
55 };
56 
64  { MAP_LAYER_FLOOR, 1 },
66  { MAP_LAYER_ITEM3, 1 }, { MAP_LAYER_ITEM3, 1 }, { MAP_LAYER_ITEM3, 1 },
67  { MAP_LAYER_LIVING2, 1 }, { MAP_LAYER_LIVING2, 1 },
68  { MAP_LAYER_FLY2, 1 }, { MAP_LAYER_FLY2, 1 }
69 };
70 
80  mapstruct *map;
81 
82  if (!name || !*name)
83  return NULL;
84 
85  for (map = first_map; map; map = map->next)
86  if (!strcmp(name, map->path))
87  break;
88  return (map);
89 }
90 
104 char *create_pathname(const char *name, char *buf, size_t size) {
105  /* Why? having extra / doesn't confuse unix anyplace? Dependancies
106  * someplace else in the code? msw 2-17-97
107  */
108  if (*name == '/')
109  snprintf(buf, size, "%s/%s%s", settings.datadir, settings.mapdir, name);
110  else
111  snprintf(buf, size, "%s/%s/%s", settings.datadir, settings.mapdir, name);
112  return buf;
113 }
114 
125 void create_overlay_pathname(const char *name, char *buf, size_t size) {
126  /* Why? having extra / doesn't confuse unix anyplace? Dependancies
127  * someplace else in the code? msw 2-17-97
128  */
129  if (*name == '/')
130  snprintf(buf, size, "%s/%s%s", settings.localdir, settings.mapdir, name);
131  else
132  snprintf(buf, size, "%s/%s/%s", settings.localdir, settings.mapdir, name);
133 }
134 
145 void create_template_pathname(const char *name, char *buf, size_t size) {
146  /* Why? having extra / doesn't confuse unix anyplace? Dependancies
147  * someplace else in the code? msw 2-17-97
148  */
149  if (*name == '/')
150  snprintf(buf, size, "%s/%s%s", settings.localdir, settings.templatedir, name);
151  else
152  snprintf(buf, size, "%s/%s/%s", settings.localdir, settings.templatedir, name);
153 }
154 
166 static void create_items_path(const char *s, char *buf, size_t size) {
167  char *t;
168 
169  if (*s == '/')
170  s++;
171 
172  snprintf(buf, size, "%s/%s/", settings.localdir, settings.uniquedir);
173  t = buf+strlen(buf);
174  snprintf(t, buf+size-t, "%s", s);
175 
176  while (*t != '\0') {
177  if (*t == '/')
178  *t = '@';
179  t++;
180  }
181 }
182 
201 int check_path(const char *name, int prepend_dir) {
202  char buf[MAX_BUF];
203 #ifndef WIN32
204  struct stat statbuf;
205  int mode = 0;
206 #endif
207 
208  if (prepend_dir)
210  else
211  strlcpy(buf, name, sizeof(buf));
212 #ifdef WIN32 /* ***win32: check this sucker in windows style. */
213  return(_access(buf, 0));
214 #else
215 
216  if (stat(buf, &statbuf) != 0)
217  return -1;
218 
219  if (!S_ISREG(statbuf.st_mode))
220  return (-1);
221 
222  if (((statbuf.st_mode&S_IRGRP) && getegid() == statbuf.st_gid)
223  || ((statbuf.st_mode&S_IRUSR) && geteuid() == statbuf.st_uid)
224  || (statbuf.st_mode&S_IROTH))
225  mode |= 4;
226 
227  if ((statbuf.st_mode&S_IWGRP && getegid() == statbuf.st_gid)
228  || (statbuf.st_mode&S_IWUSR && geteuid() == statbuf.st_uid)
229  || (statbuf.st_mode&S_IWOTH))
230  mode |= 2;
231 
232  return (mode);
233 #endif
234 }
235 
245 void dump_map(const mapstruct *m) {
246  LOG(llevError, "Map %s status: %d.\n", m->path, m->in_memory);
247  LOG(llevError, "Size: %dx%d Start: %d,%d\n", MAP_WIDTH(m), MAP_HEIGHT(m), MAP_ENTER_X(m), MAP_ENTER_Y(m));
248 
249  if (m->msg != NULL)
250  LOG(llevError, "Message:\n%s", m->msg);
251 
252  if (m->maplore != NULL)
253  LOG(llevError, "Lore:\n%s", m->maplore);
254 
255  if (m->tmpname != NULL)
256  LOG(llevError, "Tmpname: %s\n", m->tmpname);
257 
258  LOG(llevError, "Difficulty: %d\n", m->difficulty);
259  LOG(llevError, "Darkness: %d\n", m->darkness);
260 }
261 
268 void dump_all_maps(void) {
269  mapstruct *m;
270 
271  for (m = first_map; m != NULL; m = m->next) {
272  dump_map(m);
273  }
274 }
275 
300 int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny) {
301  int retval = 0;
302  mapstruct *mp;
303 
304  /*
305  * Since x and y are copies of the original values, we can directly
306  * mess with them here.
307  */
308  mp = get_map_from_coord(oldmap, &x, &y);
309  if (!mp)
310  return P_OUT_OF_MAP;
311  if (mp != oldmap)
312  retval |= P_NEW_MAP;
313  if (newmap)
314  *newmap = mp;
315  if (nx)
316  *nx = x;
317  if (ny)
318  *ny = y;
319  retval |= mp->spaces[x+mp->width*y].flags;
320  return retval;
321 }
322 
327 bool ob_move_block(object *ob1, object *ob2) {
328  if (ob1->move_type == 0) {
329  // ob1 doesn't move, so it is never blocked *by* ob2.
330  return false;
331  }
332  return (ob1->move_type&ob2->move_block) == ob1->move_type;
333 }
334 
356 int blocked_link(object *ob, mapstruct *m, int16_t sx, int16_t sy) {
357  object *tmp_head;
358  int mflags, blocked;
359 
360  /* Make sure the coordinates are valid - they should be, as caller should
361  * have already checked this.
362  */
363  if (OUT_OF_REAL_MAP(m, sx, sy)) {
364  LOG(llevError, "blocked_link: Passed map, x, y coordinates outside of map\n");
365  return 1;
366  }
367 
368  /* special hack for transports: if it's a transport with a move_type of 0, it can do on the space anyway */
369  if (ob->type == TRANSPORT && ob->move_type == 0)
370  return 0;
371 
372  mflags = m->spaces[sx+m->width*sy].flags;
373 
374  blocked = GET_MAP_MOVE_BLOCK(m, sx, sy);
375 
376  /* If space is currently not blocked by anything, no need to
377  * go further. Not true for players - all sorts of special
378  * things we need to do for players.
379  */
380  if (ob->type != PLAYER && !(mflags&P_IS_ALIVE) && (blocked == 0))
381  return 0;
382 
383  /* if there isn't anytyhing alive on this space, and this space isn't
384  * otherwise blocked, we can return now. Only if there is a living
385  * creature do we need to investigate if it is part of this creature
386  * or another. Likewise, only if something is blocking us do we
387  * need to investigate if there is a special circumstance that would
388  * let the player through (inventory checkers for example)
389  */
390  if (!(mflags&P_IS_ALIVE) && !OB_TYPE_MOVE_BLOCK(ob, blocked))
391  return 0;
392 
393  ob = HEAD(ob);
394 
395  /* We basically go through the stack of objects, and if there is
396  * some other object that has NO_PASS or FLAG_ALIVE set, return
397  * true. If we get through the entire stack, that must mean
398  * ob is blocking it, so return 0.
399  */
400  FOR_MAP_PREPARE(m, sx, sy, tmp) {
401  /* Never block part of self. */
402  tmp_head = HEAD(tmp);
403  if (tmp_head == ob)
404  continue;
405  /* This must be before the checks below. Code for inventory checkers. */
406  if (tmp->type == CHECK_INV && OB_MOVE_BLOCK(ob, tmp)) {
407  /* If last_sp is set, the player/monster needs an object,
408  * so we check for it. If they don't have it, they can't
409  * pass through this space.
410  */
411  if (tmp->last_sp) {
412  if (check_inv_recursive(ob, tmp) == NULL) {
413  if (tmp->msg) {
414  /* Optionally display the reason why one cannot move
415  * there. Note: emitting a message from this function
416  * is not very elegant. Ideally, this should be done
417  * somewhere in server/player.c, but this is difficult
418  * for objects of type CHECK_INV that are not alive.
419  */
422  tmp->msg);
423  }
424  return 1;
425  }
426  } else {
427  /* In this case, the player must not have the object -
428  * if they do, they can't pass through.
429  */
430  if (check_inv_recursive(ob, tmp) != NULL) {
431  if (tmp->msg) {
434  tmp->msg);
435  }
436  return 1;
437  }
438  }
439  } /* if check_inv */
440  else {
441  /* Broke apart a big nasty if into several here to make
442  * this more readable. first check - if the space blocks
443  * movement, can't move here.
444  * second - if a monster, can't move there, unless it is a
445  * hidden dm
446  */
447  if (OB_MOVE_BLOCK(ob, tmp))
448  return 1;
449  if (QUERY_FLAG(tmp, FLAG_ALIVE)
450  && tmp->head != ob
451  && tmp != ob
452  && tmp->type != DOOR
453  && !(QUERY_FLAG(tmp, FLAG_WIZ) && tmp->contr->hidden))
454  return 1;
455  }
456  } FOR_MAP_FINISH();
457  return 0;
458 }
459 
491 int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y) {
492  archetype *tmp;
493  int flag;
494  mapstruct *m1;
495  int16_t sx, sy;
496  const object *part;
497 
498  if (ob == NULL) {
499  flag = get_map_flags(m, &m1, x, y, &sx, &sy);
500  if (flag&P_OUT_OF_MAP)
501  return P_OUT_OF_MAP;
502 
503  /* don't have object, so don't know what types would block */
504  return(GET_MAP_MOVE_BLOCK(m1, sx, sy));
505  }
506 
507  for (tmp = ob->arch, part = ob; tmp != NULL; tmp = tmp->more, part = part->more) {
508  flag = get_map_flags(m, &m1, x+tmp->clone.x, y+tmp->clone.y, &sx, &sy);
509 
510  if (flag&P_OUT_OF_MAP)
511  return P_OUT_OF_MAP;
512  if (flag&P_IS_ALIVE)
513  return P_IS_ALIVE;
514 
515  /* object_find_first_free_spot() calls this function. However, often
516  * ob doesn't have any move type (when used to place exits)
517  * so the AND operation in OB_TYPE_MOVE_BLOCK doesn't work.
518  */
519 
520  if (ob->move_type == 0 && GET_MAP_MOVE_BLOCK(m1, sx, sy) != MOVE_ALL)
521  continue;
522 
523  /* A transport without move_type for a part should go through everything for that part. */
524  if (ob->type == TRANSPORT && part->move_type == 0)
525  continue;
526 
527  /* Note it is intentional that we check ob - the movement type of the
528  * head of the object should correspond for the entire object.
529  */
530  if (OB_TYPE_MOVE_BLOCK(ob, GET_MAP_MOVE_BLOCK(m1, sx, sy)))
531  return AB_NO_PASS;
532  }
533  return 0;
534 }
535 
546 static void fix_container_multipart(object *container) {
547  FOR_INV_PREPARE(container, tmp) {
548  archetype *at;
549  object *op, *last;
550 
551  if (tmp->inv)
553  /* already multipart, or non-multipart arch - don't do anything more */
554  for (at = tmp->arch->more, last = tmp; at != NULL; at = at->more, last = op) {
555  /* FIXME: We can't reuse object_fix_multipart() since that only
556  * works for items directly on maps. Maybe factor out common code?
557  */
558  op = arch_to_object(at);
559  op->head = tmp;
560  op->env = tmp->env;
561  last->more = op;
562  if (tmp->name != op->name) {
563  if (op->name)
564  free_string(op->name);
565  op->name = add_string(tmp->name);
566  }
567  if (tmp->title != op->title) {
568  if (op->title)
569  free_string(op->title);
570  op->title = add_string(tmp->title);
571  }
573  }
574  } FOR_INV_FINISH();
575 }
576 
588  int x, y;
589 
590  for (x = 0; x < MAP_WIDTH(m); x++)
591  for (y = 0; y < MAP_HEIGHT(m); y++)
592  FOR_MAP_PREPARE(m, x, y, tmp) {
593  if (tmp->inv)
595 
596  /* already multipart - don't do anything more */
597  if (tmp->head || tmp->more)
598  continue;
599 
601  } FOR_MAP_FINISH(); /* for objects on this space */
602 }
603 
615 void load_objects(mapstruct *m, FILE *fp, int mapflags) {
616  int i, j, bufstate = LO_NEWFILE;
617  int unique;
618  object *op, *prev = NULL, *last_more = NULL;
619 
620  op = object_new();
621  op->map = m; /* To handle buttons correctly */
622 
623  PROFILE_BEGIN();
624  while ((i = load_object(fp, op, bufstate, mapflags, false))) {
625  /* Since the loading of the map header does not load an object
626  * anymore, we need to pass LO_NEWFILE for the first object loaded,
627  * and then switch to LO_REPEAT for faster loading.
628  */
629  bufstate = LO_REPEAT;
630 
631  /* if the archetype for the object is null, means that we
632  * got an invalid object. Don't do anything with it - the game
633  * or editor will not be able to do anything with it either.
634  */
635  if (op->arch == NULL) {
636  LOG(llevDebug, "Discarding object without arch: %s\n", op->name ? op->name : "(null)");
637  continue;
638  }
639 
640  /*
641  * You can NOT have players on a map being loaded.
642  * Trying to use such a type leads to crashes everywhere as op->contr is NULL.
643  */
644  if (op->type == PLAYER) {
645  LOG(llevError, "Discarding invalid item with type PLAYER in map %s\n", m->path);
646  continue;
647  }
648 
649  /* don't use out_of_map because we don't want to consider tiling properties, we're loading a single map */
650  if (OUT_OF_REAL_MAP(m, op->x, op->y)) {
651  LOG(llevError, " object %s not on valid map position %s:%d:%d\n", op->name ? op->name : "(null)", m->path, op->x, op->y);
652  if (op->x < 0) {
653  op->x = 0;
654  } else if (op->x >= MAP_WIDTH(m)) {
655  op->x = MAP_WIDTH(m) - 1;
656  }
657  if (op->y < 0) {
658  op->y = 0;
659  } else if (op->y >= MAP_HEIGHT(m)) {
660  op->y = MAP_HEIGHT(m) - 1;
661  }
662  }
663 
664  switch (i) {
665  case LL_NORMAL:
666  /* if we are loading an overlay, put the floors on the bottom */
668  && mapflags&MAP_OVERLAY)
670  else
672 
673  if (op->inv)
674  object_sum_weight(op);
675 
676  prev = op,
677  last_more = op;
678  break;
679 
680  case LL_MORE:
682  op->head = prev,
683  last_more->more = op,
684  last_more = op;
685  break;
686  }
687  if (mapflags&MAP_STYLE) {
689  }
690  op = object_new();
691  op->map = m;
692  }
693  PROFILE_END(diff, LOG(llevDebug,
694  "load_objects on %s took %ld us\n", m->path, diff));
695  for (i = 0; i < m->width; i++) {
696  for (j = 0; j < m->height; j++) {
697  unique = 0;
698  /* check for unique items, or unique squares */
699  FOR_MAP_PREPARE(m, i, j, otmp) {
700  if (QUERY_FLAG(otmp, FLAG_UNIQUE))
701  unique = 1;
702  if (!(mapflags&(MAP_OVERLAY|MAP_PLAYER_UNIQUE) || unique))
704  } FOR_MAP_FINISH();
705  }
706  }
709 }
710 
727 int save_objects(mapstruct *m, FILE *fp, FILE *fp2, int flag) {
728  int i, j = 0, unique = 0;
729  unsigned int count = 0;
730 
733 
734  long serialize_time, write_time;
735 
736  PROFILE_BEGIN();
737 
738  for (i = 0; i < MAP_WIDTH(m); i++) {
739  for (j = 0; j < MAP_HEIGHT(m); j++) {
740  unique = 0;
741  FOR_MAP_PREPARE(m, i, j, op) {
743  unique = 1;
744 
745  if (op->type == PLAYER) {
746  LOG(llevDebug, "Player on map that is being saved\n");
747  continue;
748  }
749 
750  if (op->head || object_get_owner(op) != NULL)
751  continue;
752 
753  if (unique || QUERY_FLAG(op, FLAG_UNIQUE)) {
755  count++ ;
756  } else if (flag == 0
757  || (flag == SAVE_FLAG_NO_REMOVE && (!QUERY_FLAG(op, FLAG_OBJ_ORIGINAL) && !QUERY_FLAG(op, FLAG_UNPAID)))) {
759  count++;
760  }
761  } FOR_MAP_FINISH(); /* for this space */
762  } /* for this j */
763  }
764  PROFILE_END(diff, serialize_time = diff);
765 
766  PROFILE_BEGIN();
767  char *cp = stringbuffer_finish(sb);
768  char *cp2 = stringbuffer_finish(sb2);
769  fputs(cp, fp);
770  fputs(cp2, fp2);
771  free(cp);
772  free(cp2);
773  PROFILE_END(diff, write_time = diff);
774 
775  LOG(llevDebug, "saved %d objects on %s (%ld us serializing, %ld us writing)\n", count, m->path, serialize_time, write_time);
776  return 0;
777 }
778 
789  mapstruct *map = static_cast<mapstruct *>(calloc(1, sizeof(mapstruct)));
790  /* mapstruct *mp;*/
791 
792  if (map == NULL)
794 
795  map->next = first_map;
796  first_map = map;
797 
798  map->in_memory = MAP_SWAPPED;
799 
800  MAP_WIDTH(map) = 16;
801  MAP_HEIGHT(map) = 16;
802  MAP_RESET_TIMEOUT(map) = 0;
803  MAP_ENTER_X(map) = 0;
804  MAP_ENTER_Y(map) = 0;
805  map->last_reset_time = 0;
806  return map;
807 }
808 
810 uint32_t map_size(mapstruct *m) {
811  return (uint32_t)m->width * (uint32_t)m->height;
812 }
813 
825  m->in_memory = MAP_IN_MEMORY;
826  /* Log this condition and free the storage. We could I suppose
827  * realloc, but if the caller is presuming the data will be intact,
828  * that is their poor assumption.
829  */
830  if (m->spaces) {
831  LOG(llevError, "allocate_map called with already allocated map (%s)\n", m->path);
832  free(m->spaces);
833  }
834 
835  m->spaces = static_cast<MapSpace *>(calloc(map_size(m), sizeof(MapSpace)));
836 
837  if (m->spaces == NULL)
839 }
840 
854 mapstruct *get_empty_map(int sizex, int sizey) {
856  m->width = sizex;
857  m->height = sizey;
858  m->in_memory = MAP_SWAPPED;
859  allocate_map(m);
860  return m;
861 }
862 
876 static shopitems *parse_shop_string(const char *input_string, const mapstruct *map) {
877  char *shop_string, *p, *q, *next_semicolon, *next_colon;
878  shopitems *items = NULL;
879  int i = 0, number_of_entries = 0;
880  const typedata *current_type;
881 
882  shop_string = strdup_local(input_string);
883  p = shop_string;
884  LOG(llevDebug, "parsing %s\n", input_string);
885  /* first we'll count the entries, we'll need that for allocating the array shortly */
886  while (p) {
887  p = strchr(p, ';');
888  number_of_entries++;
889  if (p)
890  p++;
891  }
892  p = shop_string;
893  strip_endline(p);
894  items = static_cast<shopitems *>(CALLOC(number_of_entries+1, sizeof(shopitems)));
895  /*
896  * The memset would always set at least one byte to zero,
897  * so a failed calloc would have segfaulted the program.
898  * Instead, check for a null and fail more gracefully.
899  */
900  if (!items)
902 
903  for (i = 0; i < number_of_entries; i++) {
904  if (!p) {
905  LOG(llevError, "parse_shop_string: I seem to have run out of string, that shouldn't happen.\n");
906  break;
907  }
908  next_semicolon = strchr(p, ';');
909  next_colon = strchr(p, ':');
910  /* if there is a stregth specified, figure out what it is, we'll need it soon. */
911  if (next_colon && (!next_semicolon || next_colon < next_semicolon))
912  items[i].strength = atoi(strchr(p, ':')+1);
913 
914  if (isdigit(*p) || *p == '*') {
915  items[i].typenum = *p == '*' ? -1 : atoi(p);
916  current_type = get_typedata(items[i].typenum);
917  if (current_type) {
918  items[i].name = current_type->name;
919  items[i].name_pl = current_type->name_pl;
920  }
921  } else { /*we have a named type, let's figure out what it is */
922  q = strpbrk(p, ";:");
923  if (q)
924  *q = '\0';
925 
926  current_type = get_typedata_by_name(p);
927  if (current_type) {
928  items[i].name = current_type->name;
929  items[i].typenum = current_type->number;
930  items[i].name_pl = current_type->name_pl;
931  } else {
932  /* oh uh, something's wrong, let's free up this one, and try
933  * the next entry while we're at it, better print a warning */
934  LOG(llevError, "invalid type %s defined in shopitems for %s in string %s\n", p, map->name, input_string);
935  }
936  }
937  items[i].index = number_of_entries;
938  if (next_semicolon)
939  p = ++next_semicolon;
940  else
941  p = NULL;
942  }
943  free(shop_string);
944  return items;
945 }
946 
958 static void print_shop_string(mapstruct *m, char *output_string, int size) {
959  int i;
960  char tmp[MAX_BUF];
961 
962  output_string[0] = '\0';
963  for (i = 0; i < m->shopitems[0].index; i++) {
964  if (m->shopitems[i].typenum != -1) {
965  if (m->shopitems[i].strength) {
966  snprintf(tmp, sizeof(tmp), "%s:%d;", m->shopitems[i].name, m->shopitems[i].strength);
967  } else
968  snprintf(tmp, sizeof(tmp), "%s;", m->shopitems[i].name);
969  } else {
970  if (m->shopitems[i].strength) {
971  snprintf(tmp, sizeof(tmp), "*:%d;", m->shopitems[i].strength);
972  } else
973  snprintf(tmp, sizeof(tmp), "*;");
974  }
975  snprintf(output_string+strlen(output_string), size-strlen(output_string), "%s", tmp);
976  }
977 
978  /* erase final ; else parsing back will lead to issues */
979  if (strlen(output_string) > 0) {
980  output_string[strlen(output_string) - 1] = '\0';
981  }
982 }
983 
1000 static int load_map_header(FILE *fp, mapstruct *m) {
1001  char buf[HUGE_BUF], *key = NULL, *value;
1002 
1003  m->width = m->height = 0;
1004  while (fgets(buf, sizeof(buf), fp) != NULL) {
1005  char *p;
1006 
1007  p = strchr(buf, '\n');
1008  if (p == NULL) {
1009  LOG(llevError, "Error loading map header - did not find a newline - perhaps file is truncated? Buf=%s\n", buf);
1010  return 1;
1011  }
1012  *p = '\0';
1013 
1014  key = buf;
1015  while (isspace(*key))
1016  key++;
1017  if (*key == 0)
1018  continue; /* empty line */
1019  value = strchr(key, ' ');
1020  if (value) {
1021  *value = 0;
1022  value++;
1023  while (isspace(*value)) {
1024  value++;
1025  if (*value == '\0') {
1026  /* Nothing but spaces. */
1027  value = NULL;
1028  break;
1029  }
1030  }
1031  }
1032 
1033  /* key is the field name, value is what it should be set
1034  * to. We've already done the work to null terminate key,
1035  * and strip off any leading spaces for both of these.
1036  * We have not touched the newline at the end of the line -
1037  * these are needed for some values. the end pointer
1038  * points to the first of the newlines.
1039  * value could be NULL! It would be easy enough to just point
1040  * this to "" to prevent cores, but that would let more errors slide
1041  * through.
1042  *
1043  * First check for entries that do not use the value parameter, then
1044  * validate that value is given and check for the remaining entries
1045  * that use the parameter.
1046  */
1047 
1048  if (!strcmp(key, "msg")) {
1049  char msgbuf[HUGE_BUF];
1050  int msgpos = 0;
1051 
1052  while (fgets(buf, sizeof(buf), fp) != NULL) {
1053  if (!strcmp(buf, "endmsg\n"))
1054  break;
1055  else {
1056  snprintf(msgbuf+msgpos, sizeof(msgbuf)-msgpos, "%s", buf);
1057  msgpos += strlen(buf);
1058  }
1059  }
1060  /* There are lots of maps that have empty messages (eg, msg/endmsg
1061  * with nothing between). There is no reason in those cases to
1062  * keep the empty message. Also, msgbuf contains garbage data
1063  * when msgpos is zero, so copying it results in crashes
1064  */
1065  if (msgpos != 0) {
1066  /* When loading eg an overlay, message is already set, so free() current one. */
1067  free(m->msg);
1068  m->msg = strdup_local(msgbuf);
1069  }
1070  } else if (!strcmp(key, "maplore")) {
1071  char maplorebuf[HUGE_BUF];
1072  size_t maplorepos = 0;
1073 
1074  while (fgets(buf, HUGE_BUF-1, fp) != NULL) {
1075  if (!strcmp(buf, "endmaplore\n"))
1076  break;
1077  else {
1078  if (maplorepos >= sizeof(maplorebuf)) {
1079  LOG(llevError, "Map lore exceeds buffer length\n");
1080  return 1;
1081  }
1082  snprintf(maplorebuf+maplorepos, sizeof(maplorebuf)-maplorepos, "%s", buf);
1083  maplorepos += strlen(buf);
1084  }
1085  }
1086  if (maplorepos != 0)
1087  m->maplore = strdup_local(maplorebuf);
1088  } else if (!strcmp(key, "end")) {
1089  break;
1090  } else if (value == NULL) {
1091  LOG(llevError, "Got '%s' line without parameter in map header\n", key);
1092  } else if (!strcmp(key, "arch")) {
1093  /* This is an oddity, but not something we care about much. */
1094  if (strcmp(value, "map")) {
1095  LOG(llevError, "load_map_header: expected 'arch map': check line endings?\n");
1096  return 1;
1097  }
1098  } else if (!strcmp(key, "name")) {
1099  /* When loading eg an overlay, the name is already set, so free() current one. */
1100  free(m->name);
1101  m->name = strdup_local(value);
1102  /* first strcmp value on these are old names supported
1103  * for compatibility reasons. The new values (second) are
1104  * what really should be used.
1105  */
1106  } else if (!strcmp(key, "enter_x")) {
1107  m->enter_x = atoi(value);
1108  } else if (!strcmp(key, "enter_y")) {
1109  m->enter_y = atoi(value);
1110  } else if (!strcmp(key, "width")) {
1111  m->width = atoi(value);
1112  } else if (!strcmp(key, "height")) {
1113  m->height = atoi(value);
1114  } else if (!strcmp(key, "reset_timeout")) {
1115  m->reset_timeout = atoi(value);
1116  } else if (!strcmp(key, "swap_time")) {
1117  // deprecated and ignored
1118  } else if (!strcmp(key, "difficulty")) {
1119  m->difficulty = atoi(value);
1120  } else if (!strcmp(key, "darkness")) {
1121  m->darkness = atoi(value);
1122  } else if (!strcmp(key, "fixed_resettime")) {
1123  m->fixed_resettime = atoi(value);
1124  } else if (!strcmp(key, "unique")) {
1125  m->unique = atoi(value);
1126  } else if (!strcmp(key, "template")) {
1127  m->is_template = atoi(value);
1128  } else if (!strcmp(key, "region")) {
1129  m->region = get_region_by_name(value);
1130  } else if (!strcmp(key, "shopitems")) {
1131  m->shopitems = parse_shop_string(value, m);
1132  } else if (!strcmp(key, "shopgreed")) {
1133  m->shopgreed = atof(value);
1134  } else if (!strcmp(key, "shopmin")) {
1135  m->shopmin = atol(value);
1136  } else if (!strcmp(key, "shopmax")) {
1137  m->shopmax = atol(value);
1138  } else if (!strcmp(key, "shoprace")) {
1139  m->shoprace = strdup_local(value);
1140  } else if (!strcmp(key, "outdoor")) {
1141  m->outdoor = atoi(value);
1142  } else if (!strcmp(key, "nosmooth")) {
1143  m->nosmooth = atoi(value);
1144  } else if (!strcmp(key, "first_load")) {
1145  m->last_reset_time = atoi(value);
1146  } else if (!strncmp(key, "tile_path_", 10)) {
1147  int tile = atoi(key+10);
1148 
1149  if (tile < 1 || tile > 4) {
1150  LOG(llevError, "load_map_header: tile location %d out of bounds (%s)\n", tile, m->path);
1151  } else {
1152  if (m->tile_path[tile-1]) {
1153  LOG(llevError, "load_map_header: tile location %d duplicated (%s)\n", tile, m->path);
1154  free(m->tile_path[tile-1]);
1155  }
1156  m->tile_path[tile-1] = strdup_local(value);
1157  } /* end if tile direction (in)valid */
1158  } else if (!strcmp(key, "background_music")) {
1159  m->background_music = strdup_local(value);
1160  } else if (!strcmp(key, "reset_group")) {
1161  m->reset_group = add_string(value);
1162  } else {
1163  LOG(llevError, "Got unknown value in map header: %s %s\n", key, value);
1164  }
1165  }
1166  if ((m->width == 0) || (m->height == 0)) {
1167  LOG(llevError, "Map width or height not specified\n");
1168  return 1;
1169  }
1170  if (!key || strcmp(key, "end")) {
1171  LOG(llevError, "Got premature eof on map header!\n");
1172  return 1;
1173  }
1174  return 0;
1175 }
1176 
1177 void map_path(const char *map, int flags, char *pathname, size_t bufsize) {
1178  if (flags&MAP_PLAYER_UNIQUE) {
1179  snprintf(pathname, bufsize, "%s/%s/%s", settings.localdir, settings.playerdir, map+1);
1180  }
1181  else if (flags&MAP_OVERLAY)
1182  create_overlay_pathname(map, pathname, bufsize);
1183  else
1184  create_pathname(map, pathname, bufsize);
1185 }
1186 
1187 mapstruct *mapfile_load_lowlevel(const char *map, const char *pathname, int flags) {
1188  FILE *fp;
1189  if ((fp = fopen(pathname, "r")) == NULL) {
1191  "Can't open %s: %s\n", pathname, strerror(errno));
1192  return NULL;
1193  }
1194 
1195  mapstruct *m = get_linked_map();
1196  safe_strncpy(m->path, map, HUGE_BUF);
1197  if (load_map_header(fp, m)) {
1198  LOG(llevError, "Error loading map header for %s, flags=%d\n", map, flags);
1199  delete_map(m);
1200  fclose(fp);
1201  return NULL;
1202  }
1203 
1204  allocate_map(m);
1205 
1206  m->in_memory = MAP_LOADING;
1207  load_objects(m, fp, flags & MAP_STYLE);
1208  fclose(fp);
1209  m->in_memory = MAP_IN_MEMORY;
1210  return m;
1211 }
1212 
1228 mapstruct *mapfile_load(const char *map, int flags) {
1229  mapstruct *m;
1230  PROFILE_BEGIN();
1231  char pathname[MAX_BUF];
1232  map_path(map, flags, pathname, sizeof(pathname));
1233  m = mapfile_load_lowlevel(map, pathname, flags);
1234  if (!m) {
1235  return NULL;
1236  }
1237  if (!MAP_DIFFICULTY(m) && (!(flags & MAP_NO_DIFFICULTY)))
1240 
1241  /* In case other objects press some buttons down */
1242  update_buttons(m);
1243 
1245 
1246  if (!(flags & MAP_STYLE))
1247  apply_auto_fix(m); /* Chests which open as default */
1248 
1249  PROFILE_END(diff,
1250  LOG(llevDebug, "mapfile_load on %s" " took %ld us\n", map, diff));
1251 
1253  return (m);
1254 }
1255 
1265  FILE *fp;
1266 
1267  if (!m->tmpname) {
1268  LOG(llevError, "No temporary filename for map %s\n", m->path);
1269  return 1;
1270  }
1271 
1272  if ((fp = fopen(m->tmpname, "r")) == NULL) {
1273  LOG(llevError, "Cannot open %s: %s\n", m->tmpname, strerror(errno));
1274  return 2;
1275  }
1276 
1277  if (load_map_header(fp, m)) {
1278  LOG(llevError, "Error loading map header for %s (%s)\n", m->path, m->tmpname);
1279  fclose(fp);
1280  return 3;
1281  }
1282  allocate_map(m);
1283 
1284  m->in_memory = MAP_LOADING;
1285  load_objects(m, fp, 0);
1286  fclose(fp);
1287  m->in_memory = MAP_IN_MEMORY;
1288  return 0;
1289 }
1290 
1300 static int load_overlay_map(const char *filename, mapstruct *m) {
1301  FILE *fp;
1302  char pathname[MAX_BUF];
1303 
1304  create_overlay_pathname(filename, pathname, MAX_BUF);
1305 
1306  if ((fp = fopen(pathname, "r")) == NULL) {
1307  /* nothing bad to not having an overlay */
1308  return 0;
1309  }
1310 
1311  if (load_map_header(fp, m)) {
1312  LOG(llevError, "Error loading map header for overlay %s (%s)\n", m->path, pathname);
1313  fclose(fp);
1314  return 1;
1315  }
1316  /*allocate_map(m);*/
1317 
1318  m->in_memory = MAP_LOADING;
1319  load_objects(m, fp, MAP_OVERLAY);
1320  fclose(fp);
1321  m->in_memory = MAP_IN_MEMORY;
1322  return 0;
1323 }
1324 
1325 /******************************************************************************
1326  * This is the start of unique map handling code
1327  *****************************************************************************/
1328 
1336  int i, j, unique = 0;
1337 
1338  for (i = 0; i < MAP_WIDTH(m); i++)
1339  for (j = 0; j < MAP_HEIGHT(m); j++) {
1340  unique = 0;
1341  FOR_MAP_PREPARE(m, i, j, op) {
1343  unique = 1;
1344  if (op->head == NULL && (QUERY_FLAG(op, FLAG_UNIQUE) || unique)) {
1345  clean_object(op);
1346  if (QUERY_FLAG(op, FLAG_IS_LINKED))
1347  remove_button_link(op);
1348  object_remove(op);
1350  }
1351  } FOR_MAP_FINISH();
1352  }
1353 }
1354 
1361  FILE *fp;
1362  int count;
1363  char name[MAX_BUF], firstname[sizeof(name) + 4];
1364 
1365  create_items_path(m->path, name, MAX_BUF);
1366  for (count = 0; count < 10; count++) {
1367  snprintf(firstname, sizeof(firstname), "%s.v%02d", name, count);
1368  if (!access(firstname, R_OK))
1369  break;
1370  }
1371  /* If we get here, we did not find any map */
1372  if (count == 10)
1373  return;
1374 
1375  if ((fp = fopen(firstname, "r")) == NULL) {
1376  /* There is no expectation that every map will have unique items, but this
1377  * is debug output, so leave it in.
1378  */
1379  LOG(llevDebug, "Can't open unique items file for %s\n", name);
1380  return;
1381  }
1382 
1383  m->in_memory = MAP_LOADING;
1384  if (m->tmpname == NULL) /* if we have loaded unique items from */
1385  delete_unique_items(m); /* original map before, don't duplicate them */
1386  load_object(fp, NULL, LO_NOREAD, 0, false);
1387  load_objects(m, fp, 0);
1388  fclose(fp);
1389  m->in_memory = MAP_IN_MEMORY;
1390 }
1391 
1407 int save_map(mapstruct *m, int flag) {
1408  FILE *fp, *fp2;
1409  OutputFile of, of2;
1410  char filename[MAX_BUF], shop[MAX_BUF];
1411  int i, res;
1412 
1413  if (flag && !*m->path) {
1414  LOG(llevError, "Tried to save map without path.\n");
1415  return SAVE_ERROR_NO_PATH;
1416  }
1417 
1418  PROFILE_BEGIN();
1419 
1420  if (flag != SAVE_MODE_NORMAL || (m->unique) || (m->is_template)) {
1421  if (!m->unique && !m->is_template) { /* flag is set */
1422  if (flag == SAVE_MODE_OVERLAY)
1423  create_overlay_pathname(m->path, filename, MAX_BUF);
1424  else
1425  create_pathname(m->path, filename, MAX_BUF);
1426  } else {
1427  if (m->path[0] != '~') {
1428  LOG(llevError,
1429  "Cannot save unique map '%s' outside of LOCALDIR. Check "
1430  "that all exits to '%s' have FLAG_UNIQUE set correctly.\n",
1431  m->path, m->path);
1432  return SAVE_ERROR_UCREATION;
1433  }
1434  snprintf(filename, sizeof(filename), "%s/%s/%s", settings.localdir, settings.playerdir, m->path+1);
1435  }
1436 
1437  make_path_to_file(filename);
1438  } else {
1439  if (!m->tmpname)
1440  m->tmpname = tempnam(settings.tmpdir, NULL);
1441  strlcpy(filename, m->tmpname, sizeof(filename));
1442  }
1443  m->in_memory = MAP_SAVING;
1444 
1445  fp = of_open(&of, filename);
1446  if (fp == NULL)
1447  return SAVE_ERROR_RCREATION;
1448 
1449  /* legacy */
1450  fprintf(fp, "arch map\n");
1451  if (m->name)
1452  fprintf(fp, "name %s\n", m->name);
1453  if (m->reset_timeout)
1454  fprintf(fp, "reset_timeout %u\n", m->reset_timeout);
1455  if (m->fixed_resettime)
1456  fprintf(fp, "fixed_resettime %d\n", m->fixed_resettime);
1457  /* we unfortunately have no idea if this is a value the creator set
1458  * or a difficulty value we generated when the map was first loaded
1459  */
1460  if (m->difficulty)
1461  fprintf(fp, "difficulty %d\n", m->difficulty);
1462  if (m->region)
1463  fprintf(fp, "region %s\n", m->region->name);
1464  if (m->shopitems) {
1465  print_shop_string(m, shop, sizeof(shop));
1466  fprintf(fp, "shopitems %s\n", shop);
1467  }
1468  if (m->shopgreed)
1469  fprintf(fp, "shopgreed %f\n", m->shopgreed);
1470  if (m->shopmin)
1471  fprintf(fp, "shopmin %" FMT64U "\n", m->shopmin);
1472  if (m->shopmax)
1473  fprintf(fp, "shopmax %" FMT64U "\n", m->shopmax);
1474  if (m->shoprace)
1475  fprintf(fp, "shoprace %s\n", m->shoprace);
1476  if (m->darkness)
1477  fprintf(fp, "darkness %d\n", m->darkness);
1478  if (m->width)
1479  fprintf(fp, "width %d\n", m->width);
1480  if (m->height)
1481  fprintf(fp, "height %d\n", m->height);
1482  if (m->enter_x)
1483  fprintf(fp, "enter_x %d\n", m->enter_x);
1484  if (m->enter_y)
1485  fprintf(fp, "enter_y %d\n", m->enter_y);
1486  if (m->msg)
1487  fprintf(fp, "msg\n%sendmsg\n", m->msg);
1488  if (m->maplore)
1489  fprintf(fp, "maplore\n%sendmaplore\n", m->maplore);
1490  if (m->unique)
1491  fprintf(fp, "unique %d\n", m->unique);
1492  if (m->is_template)
1493  fprintf(fp, "template %d\n", m->is_template);
1494  if (m->outdoor)
1495  fprintf(fp, "outdoor %d\n", m->outdoor);
1496  if (m->nosmooth)
1497  fprintf(fp, "nosmooth %d\n", m->nosmooth);
1498  if (m->last_reset_time)
1499  fprintf(fp, "first_load %ld\n", m->last_reset_time);
1500  if (m->background_music)
1501  fprintf(fp, "background_music %s\n", m->background_music);
1502  if (m->reset_group)
1503  fprintf(fp, "reset_group %s\n", m->reset_group);
1504 
1505  /* Save any tiling information, except on overlays */
1506  if (flag != SAVE_MODE_OVERLAY)
1507  for (i = 0; i < 4; i++)
1508  if (m->tile_path[i])
1509  fprintf(fp, "tile_path_%d %s\n", i+1, m->tile_path[i]);
1510 
1511  fprintf(fp, "end\n");
1512 
1513  /* In the game save unique items in the different file, but
1514  * in the editor save them to the normal map file.
1515  * If unique map, save files in the proper destination (set by
1516  * player)
1517  */
1518  if ((flag == SAVE_MODE_NORMAL || flag == SAVE_MODE_OVERLAY) && !m->unique && !m->is_template) {
1519  char name[MAX_BUF], final_unique[sizeof(name) + 4];
1520 
1521  create_items_path(m->path, name, MAX_BUF);
1522  snprintf(final_unique, sizeof(final_unique), "%s.v00", name);
1523  fp2 = of_open(&of2, final_unique);
1524  if (fp2 == NULL) {
1525  of_cancel(&of);
1526  return SAVE_ERROR_UCREATION;
1527  }
1528  if (flag == SAVE_MODE_OVERLAY) {
1529  /* SO_FLAG_NO_REMOVE is non destructive save, so map is still valid. */
1530  res = save_objects(m, fp, fp2, SAVE_FLAG_NO_REMOVE);
1531  if (res < 0) {
1532  LOG(llevError, "Save error during object save: %d\n", res);
1533  of_cancel(&of);
1534  of_cancel(&of2);
1535  return res;
1536  }
1537  m->in_memory = MAP_IN_MEMORY;
1538  } else {
1539  res = save_objects(m, fp, fp2, 0);
1540  if (res < 0) {
1541  LOG(llevError, "Save error during object save: %d\n", res);
1542  of_cancel(&of);
1543  of_cancel(&of2);
1544  return res;
1545  }
1547  }
1548  if (ftell(fp2) == 0) {
1549  of_cancel(&of2);
1550  /* If there are no unique items left on the map, we need to
1551  * unlink the original unique map so that the unique
1552  * items don't show up again.
1553  */
1554  unlink(final_unique);
1555  } else {
1556  if (!of_close(&of2)) {
1557  of_cancel(&of);
1558  return SAVE_ERROR_URENAME;
1559  }
1560 
1561  if (chmod(final_unique, SAVE_MODE) != 0) {
1562  LOG(llevError, "Could not set permissions on '%s'\n",
1563  final_unique);
1564  }
1565  }
1566  } else { /* save same file when not playing, like in editor */
1567  res = save_objects(m, fp, fp, 0);
1568  if (res < 0) {
1569  LOG(llevError, "Save error during object save: %d\n", res);
1570  of_cancel(&of);
1571  return res;
1572  }
1574  }
1575 
1576  if (!of_close(&of))
1577  return SAVE_ERROR_CLOSE;
1578 
1579  if (chmod(filename, SAVE_MODE) != 0) {
1580  LOG(llevError, "Could not set permissions on '%s'\n", filename);
1581  }
1582 
1583  PROFILE_END(diff,
1584  LOG(llevDebug, "save_map on %s" " took %ld us\n", m->path, diff));
1585 
1586  maps_saved_total++;
1587  return SAVE_ERROR_OK;
1588 }
1589 
1599 void clean_object(object *op) {
1600  FOR_INV_PREPARE(op, tmp) {
1601  clean_object(tmp);
1602  if (QUERY_FLAG(tmp, FLAG_IS_LINKED))
1603  remove_button_link(tmp);
1604  object_remove(tmp);
1606  } FOR_INV_FINISH();
1607 }
1608 
1616  int i, j;
1617  object *op;
1618 
1619  for (i = 0; i < MAP_WIDTH(m); i++)
1620  for (j = 0; j < MAP_HEIGHT(m); j++) {
1621  object *previous_obj = NULL;
1622 
1623  while ((op = GET_MAP_OB(m, i, j)) != NULL) {
1624  if (op == previous_obj) {
1625  LOG(llevDebug, "free_all_objects: Link error, bailing out.\n");
1626  break;
1627  }
1628  previous_obj = op;
1629  op = HEAD(op);
1630 
1631  /* If the map isn't in memory, object_free_drop_inventory() will remove and
1632  * free objects in op's inventory. So let it do the job.
1633  */
1634  if (m->in_memory == MAP_IN_MEMORY)
1635  clean_object(op);
1636  object_remove(op);
1638  }
1639  }
1640 #ifdef MANY_CORES
1641  /* I see periodic cores on metalforge where a map has been swapped out, but apparantly
1642  * an item on that map was not saved - look for that condition and die as appropriate -
1643  * this leaves more of the map data intact for better debugging.
1644  */
1645  for (op = objects; op != NULL; op = op->next) {
1646  if (!QUERY_FLAG(op, FLAG_REMOVED) && op->map == m) {
1647  LOG(llevError, "free_all_objects: object %s still on map after it should have been freed\n", op->name);
1648  abort();
1649  }
1650  }
1651 #endif
1652 }
1653 
1663  int i;
1664 
1665  if (!m->in_memory) {
1666  LOG(llevError, "Trying to free freed map.\n");
1667  return;
1668  }
1669 
1671 
1672  if (m->spaces)
1674  if (m->name)
1675  FREE_AND_CLEAR(m->name);
1676  if (m->spaces)
1677  FREE_AND_CLEAR(m->spaces);
1678  if (m->msg)
1679  FREE_AND_CLEAR(m->msg);
1680  if (m->maplore)
1681  FREE_AND_CLEAR(m->maplore);
1682  if (m->shopitems)
1683  FREE_AND_CLEAR(m->shopitems);
1684  if (m->shoprace)
1685  FREE_AND_CLEAR(m->shoprace);
1686  if (m->background_music)
1687  FREE_AND_CLEAR(m->background_music);
1688  if (m->buttons)
1689  free_objectlinkpt(m->buttons);
1690  m->buttons = NULL;
1691  for (i = 0; i < 4; i++) {
1692  if (m->tile_path[i])
1693  FREE_AND_CLEAR(m->tile_path[i]);
1694  m->tile_map[i] = NULL;
1695  }
1696  m->in_memory = MAP_SWAPPED;
1697 }
1698 
1709  mapstruct *tmp, *last;
1710  int i;
1711 
1712  if (!m)
1713  return;
1714  if (m->in_memory == MAP_IN_MEMORY) {
1715  /* change to MAP_SAVING, even though we are not,
1716  * so that object_remove() doesn't do as much work.
1717  */
1718  m->in_memory = MAP_SAVING;
1719  free_map(m);
1720  }
1721  /* move this out of free_map, since tmpname can still be needed if
1722  * the map is swapped out.
1723  */
1724  free(m->tmpname);
1725  m->tmpname = NULL;
1726  FREE_AND_CLEAR_STR_IF(m->reset_group);
1727  last = NULL;
1728  /* We need to look through all the maps and see if any maps
1729  * are pointing at this one for tiling information. Since
1730  * tiling can be assymetric, we just can not look to see which
1731  * maps this map tiles with and clears those.
1732  */
1733  for (tmp = first_map; tmp != NULL; tmp = tmp->next) {
1734  if (tmp->next == m)
1735  last = tmp;
1736 
1737  /* This should hopefully get unrolled on a decent compiler */
1738  for (i = 0; i < 4; i++)
1739  if (tmp->tile_map[i] == m)
1740  tmp->tile_map[i] = NULL;
1741  }
1742 
1743  /* If last is null, then this should be the first map in the list */
1744  if (!last) {
1745  if (m == first_map)
1746  first_map = m->next;
1747  else
1748  /* m->path is a static char, so should hopefully still have
1749  * some useful data in it.
1750  */
1751  LOG(llevError, "delete_map: Unable to find map %s in list\n", m->path);
1752  } else
1753  last->next = m->next;
1754 
1755  free(m);
1756 }
1757 
1763  // Right now this just sets the fixed swap time.
1764  m->timeout = MAP_MINTIMEOUT;
1765 }
1766 
1780 mapstruct *ready_map_name(const char *name, int flags) {
1781  mapstruct *m;
1782 
1783  if (!name)
1784  return (NULL);
1785 
1786  /* Have we been at this level before? */
1787  m = has_been_loaded(name);
1788 
1789  /* Map is good to go, so just return it */
1790  if (m && (m->in_memory == MAP_LOADING || m->in_memory == MAP_IN_MEMORY)) {
1791  map_reset_swap(m);
1792  return m;
1793  }
1794 
1795  /* Rewrite old paths starting with LOCALDIR/PLAYERDIR to new '~' paths. */
1796  char buf[MAX_BUF], buf2[MAX_BUF];
1797  snprintf(buf, sizeof(buf), "%s/%s", settings.localdir, settings.playerdir);
1798  if (strncmp(name, buf, strlen(buf)) == 0) {
1799  snprintf(buf2, sizeof(buf2), "~%s", name+strlen(buf)+1);
1800  name = buf2;
1801  }
1802 
1803  /* Paths starting with '~' are unique. */
1804  if (name[0] == '~') {
1806  }
1807 
1808  /* unique maps always get loaded from their original location, and never
1809  * a temp location. Likewise, if map_flush is set, or we have never loaded
1810  * this map, load it now. I removed the reset checking from here -
1811  * it seems the probability of a player trying to enter a map that should
1812  * reset but hasn't yet is quite low, and removing that makes this function
1813  * a bit cleaner (and players probably shouldn't rely on exact timing for
1814  * resets in any case - if they really care, they should use the 'maps command.
1815  */
1816  if ((flags&(MAP_FLUSH|MAP_PLAYER_UNIQUE)) || !m) {
1817  /* first visit or time to reset */
1818  if (m) {
1819  clean_tmp_map(m); /* Doesn't make much difference */
1820  delete_map(m);
1821  }
1822 
1824  if (m == NULL) return NULL;
1825 
1826  /* If a player unique map, no extra unique object file to load.
1827  * if from the editor, likewise.
1828  */
1831 
1833  if (load_overlay_map(name, m) != 0) {
1834  delete_map(m);
1835  m = mapfile_load(name, 0);
1836  if (m == NULL) {
1837  /* Really, this map is bad :( */
1838  return NULL;
1839  }
1840  }
1841  }
1842  } else {
1843  /* If in this loop, we found a temporary map, so load it up. */
1844 
1845  if (load_temporary_map(m) != 0) {
1846  /*
1847  * There was a failure loading the temporary map, fall back to original one.
1848  * load_temporary_map() already logged the error.
1849  */
1850  delete_map(m);
1851  m = mapfile_load(name, 0);
1852  if (m == NULL) {
1853  /* Really, this map is bad :( */
1854  return NULL;
1855  }
1856  }
1858 
1859  clean_tmp_map(m);
1860  m->in_memory = MAP_IN_MEMORY;
1861  /* tempnam() on sun systems (probably others) uses malloc
1862  * to allocated space for the string. Free it here.
1863  * In some cases, load_temporary_map above won't find the
1864  * temporary map, and so has reloaded a new map. If that
1865  * is the case, tmpname is now null
1866  */
1867  free(m->tmpname);
1868  m->tmpname = NULL;
1869  /* It's going to be saved anew anyway */
1870  }
1871 
1872  /* Below here is stuff common to both first time loaded maps and
1873  * temp maps.
1874  */
1875 
1876  decay_objects(m); /* start the decay */
1877 
1878  if (m->outdoor)
1880 
1881  if (!(flags&(MAP_FLUSH))) {
1882  if (m->last_reset_time == 0) {
1883  m->last_reset_time = seconds();
1884  }
1885  }
1886 
1887  map_reset_swap(m);
1889 
1890  return m;
1891 }
1892 
1909  archetype *at;
1910  int x, y;
1911  int diff = 0;
1912  int i;
1913  int64_t exp_pr_sq, total_exp = 0;
1914 
1915  if (MAP_DIFFICULTY(m)) {
1916  return MAP_DIFFICULTY(m);
1917  }
1918 
1919  for (x = 0; x < MAP_WIDTH(m); x++)
1920  for (y = 0; y < MAP_HEIGHT(m); y++)
1921  FOR_MAP_PREPARE(m, x, y, op) {
1922  if (QUERY_FLAG(op, FLAG_MONSTER))
1923  total_exp += op->stats.exp;
1924  if (QUERY_FLAG(op, FLAG_GENERATOR)) {
1925  total_exp += op->stats.exp;
1926  // If we have an other_arch on our generator, just use that.
1927  // FIXME: Figure out what to do if we are doing template generation from inventory.
1928  at = op->other_arch ? op->other_arch : NULL;
1929  if (at != NULL) {
1930  // Make sure we can't set off a null pointer dereference in atoi().
1931  const char *val = object_get_value(op, "generator_limit");
1932  int lim = atoi(val ? val : "0");
1933  // We assume, on average, the generator will generate half its contents.
1934  if (!lim || lim >= 16)
1935  total_exp += at->clone.stats.exp*8;
1936  else
1937  total_exp += at->clone.stats.exp*(lim/2);
1938  }
1939  }
1940  } FOR_MAP_FINISH();
1941  // Used to be multiplied by 1000, but this undershot horribly
1942  // once I fixed the calculation for generators.
1943  // I'm trying out some exponentiation, since linear scaling
1944  // seems to overshoot low-level maps and undershoot high-level maps.
1945  // I also feel comfortable, knowing that generators return
1946  // sensible values, to up the max diff this calculates from 20 to 25.
1947  // - Neila Hawkins 2021-03-04
1948  exp_pr_sq = (pow(total_exp, 1.75))/(MAP_WIDTH(m)*MAP_HEIGHT(m)+1);
1949  diff = 25;
1950  for (i = 1; i < 25; i++)
1951  if (exp_pr_sq <= level_exp(i, 1.0)) {
1952  diff = i;
1953  break;
1954  }
1955 
1956  return diff;
1957 }
1958 
1966  if (m->tmpname == NULL)
1967  return;
1968  (void)unlink(m->tmpname);
1969 }
1970 
1974 void free_all_maps(void) {
1975  int real_maps = 0;
1976 
1977  while (first_map) {
1978  /* I think some of the callers above before it gets here set this to be
1979  * saving, but we still want to free this data
1980  */
1981  if (first_map->in_memory == MAP_SAVING)
1984  real_maps++;
1985  }
1986  LOG(llevDebug, "free_all_maps: Freed %d maps\n", real_maps);
1987 }
1988 
2006 int change_map_light(mapstruct *m, int change) {
2007  int new_level = m->darkness+change;
2008 
2009  /* Nothing to do */
2010  if (!change
2011  || (new_level <= 0 && m->darkness == 0)
2012  || (new_level >= MAX_DARKNESS && m->darkness >= MAX_DARKNESS)) {
2013  return 0;
2014  }
2015 
2016  /* inform all players on the map */
2017  if (change > 0)
2018  ext_info_map(NDI_BLACK, m, MSG_TYPE_MISC, MSG_SUBTYPE_NONE, "It becomes darker.");
2019  else
2020  ext_info_map(NDI_BLACK, m, MSG_TYPE_MISC, MSG_SUBTYPE_NONE, "It becomes brighter.");
2021 
2022  /* Do extra checking. since m->darkness is a unsigned value,
2023  * we need to be extra careful about negative values.
2024  * In general, the checks below are only needed if change
2025  * is not +/-1
2026  */
2027  if (new_level < 0)
2028  m->darkness = 0;
2029  else if (new_level >= MAX_DARKNESS)
2030  m->darkness = MAX_DARKNESS;
2031  else
2032  m->darkness = new_level;
2033 
2034  /* All clients need to get re-updated for the change */
2036  return 1;
2037 }
2038 
2061 static inline void add_face_layer(int low_layer, int high_layer, object *ob, object *layers[], int honor_visibility) {
2062  int l, l1;
2063  object *tmp;
2064 
2065  for (l = low_layer; l <= high_layer; l++) {
2066  if (!layers[l]) {
2067  /* found an empty spot. now, we want to make sure
2068  * highest visibility at top, etc.
2069  */
2070  layers[l] = ob;
2071  if (!honor_visibility)
2072  return;
2073 
2074  /* This is basically a mini bubble sort. Only swap
2075  * position if the lower face has greater (not equal)
2076  * visibility - map stacking is secondary consideration here.
2077  */
2078  for (l1 = (l-1); l1 >= low_layer; l1--) {
2079  if (layers[l1]->face->visibility > layers[l1+1]->face->visibility) {
2080  tmp = layers[l1+1];
2081  layers[l1+1] = layers[l1];
2082  layers[l1] = tmp;
2083  }
2084  }
2085  /* Nothing more to do - face inserted */
2086  return;
2087  }
2088  }
2089  /* If we get here, all the layers have an object..
2090  */
2091  if (!honor_visibility) {
2092  /* Basically, in this case, it is pure stacking logic, so
2093  * new object goes on the top.
2094  */
2095  for (l = low_layer; l < high_layer; l++)
2096  layers[l] = layers[l+1];
2097  layers[high_layer] = ob;
2098  /* If this object doesn't have higher visibility than
2099  * the lowest object, no reason to go further.
2100  */
2101  } else if (ob->face->visibility >= layers[low_layer]->face->visibility) {
2102  /*
2103  * Start at the top (highest visibility) layer and work down.
2104  * once this face exceed that of the layer, push down those
2105  * other layers, and then replace the layer with our object.
2106  */
2107  for (l = high_layer; l >= low_layer; l--) {
2108  if (ob->face->visibility >= layers[l]->face->visibility) {
2109  for (l1 = low_layer; l1 < l; l1++)
2110  layers[l1] = layers[l1+1];
2111  layers[l] = ob;
2112  break;
2113  }
2114  }
2115  }
2116 }
2117 
2130 void update_position(mapstruct *m, int x, int y) {
2131  object *player = NULL;
2132  uint8_t flags = 0, oldflags, light = 0;
2133  object *layers[MAP_LAYERS];
2134 
2135  MoveType move_block = 0, move_slow = 0, move_on = 0, move_off = 0, move_allow = 0;
2136 
2137  oldflags = GET_MAP_FLAGS(m, x, y);
2138  if (!(oldflags&P_NEED_UPDATE)) {
2139  LOG(llevDebug, "update_position called with P_NEED_UPDATE not set: %s (%d, %d)\n", m->path, x, y);
2140  return;
2141  }
2142 
2143  memset(layers, 0, MAP_LAYERS*sizeof(object *));
2144 
2145  FOR_MAP_PREPARE(m, x, y, tmp) {
2146  /* DMs just don't do anything when hidden, including no light. */
2147  if (QUERY_FLAG(tmp, FLAG_WIZ) && tmp->contr->hidden)
2148  continue;
2149 
2150  if (tmp->type == PLAYER)
2151  player = tmp;
2152 
2153  /* This could be made additive I guess (two lights better than
2154  * one). But if so, it shouldn't be a simple additive - 2
2155  * light bulbs do not illuminate twice as far as once since
2156  * it is a dissipation factor that is squared (or is it cubed?)
2157  */
2158  if (tmp->glow_radius > light)
2159  light = tmp->glow_radius;
2160 
2161  /* if this object is visible and not a blank face,
2162  * update the objects that show how this space
2163  * looks.
2164  */
2165  if (!tmp->invisible && tmp->face != blank_face) {
2166  if (tmp->map_layer) {
2167  add_face_layer(tmp->map_layer, map_layer_info[tmp->map_layer].high_layer,
2168  tmp, layers, map_layer_info[tmp->map_layer].honor_visibility);
2169  } else if (tmp->move_type&MOVE_FLYING) {
2170  add_face_layer(MAP_LAYER_FLY1, MAP_LAYER_FLY2, tmp, layers, 1);
2171  } else if ((tmp->type == PLAYER || QUERY_FLAG(tmp, FLAG_MONSTER) || QUERY_FLAG(tmp, FLAG_CAN_ROLL))) {
2172  // Put things that are likely to move on the LIVING layers
2174  } else if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
2175  layers[MAP_LAYER_FLOOR] = tmp;
2176  /* floors hide everything else */
2177  memset(layers+1, 0, (MAP_LAYERS-1)*sizeof(object *));
2178  /* Check for FLAG_SEE_ANYWHERE is removed - objects
2179  * with that flag should just have a high visibility
2180  * set - we shouldn't need special code here.
2181  */
2182  } else if (QUERY_FLAG(tmp, FLAG_NO_PICK)) {
2184  } else {
2186  }
2187  }
2188  if (tmp == tmp->above) {
2189  LOG(llevError, "Error in structure of map\n");
2190  exit(-1);
2191  }
2192 
2193  move_slow |= tmp->move_slow;
2194  move_block |= tmp->move_block;
2195  move_on |= tmp->move_on;
2196  move_off |= tmp->move_off;
2197  move_allow |= tmp->move_allow;
2198 
2199  if (QUERY_FLAG(tmp, FLAG_ALIVE))
2200  flags |= P_IS_ALIVE;
2201  if (QUERY_FLAG(tmp, FLAG_NO_MAGIC))
2202  flags |= P_NO_MAGIC;
2204  flags |= P_NO_CLERIC;
2205 
2206  if (QUERY_FLAG(tmp, FLAG_BLOCKSVIEW))
2207  flags |= P_BLOCKSVIEW;
2208  } FOR_MAP_FINISH(); /* for stack of objects */
2209 
2210  if (player)
2211  flags |= P_PLAYER;
2212 
2213  /* we don't want to rely on this function to have accurate flags, but
2214  * since we're already doing the work, we calculate them here.
2215  * if they don't match, logic is broken someplace.
2216  */
2217  if (((oldflags&~(P_NEED_UPDATE|P_NO_ERROR)) != flags)
2218  && (!(oldflags&P_NO_ERROR))) {
2219  LOG(llevDebug, "update_position: updated flags do not match old flags: %s (x=%d,y=%d) %x != %x\n",
2220  m->path, x, y, (oldflags&~P_NEED_UPDATE), flags);
2221  }
2222 
2223  SET_MAP_FLAGS(m, x, y, flags);
2224  SET_MAP_MOVE_BLOCK(m, x, y, move_block&~move_allow);
2225  SET_MAP_MOVE_ON(m, x, y, move_on);
2226  SET_MAP_MOVE_OFF(m, x, y, move_off);
2227  SET_MAP_MOVE_SLOW(m, x, y, move_slow);
2228  SET_MAP_LIGHT(m, x, y, light);
2229 
2230  /* Note that player may be NULL here, which is fine - if no player, need
2231  * to clear any value that may be set.
2232  */
2233  SET_MAP_PLAYER(m, x, y, player);
2234 
2235  /* Note it is intentional we copy everything, including NULL values. */
2236  memcpy(GET_MAP_FACE_OBJS(m, x, y), layers, sizeof(object *)*MAP_LAYERS);
2237 }
2238 
2246  int timeout;
2247 
2248  timeout = MAP_RESET_TIMEOUT(map);
2249  if (timeout <= 0)
2250  timeout = MAP_DEFAULTRESET;
2251  if (timeout >= MAP_MAXRESET)
2252  timeout = MAP_MAXRESET;
2253  MAP_RESET_TIMEOUT(map) = timeout;
2254  MAP_WHEN_RESET(map) = seconds()+timeout;
2255 }
2256 
2271 static mapstruct *load_and_link_tiled_map(mapstruct *orig_map, int tile_num) {
2272  int dest_tile = (tile_num+2)%4;
2273  char path[HUGE_BUF];
2274 
2275  path_combine_and_normalize(orig_map->path, orig_map->tile_path[tile_num], path, sizeof(path));
2276 
2277  orig_map->tile_map[tile_num] = ready_map_name(path, 0);
2278  if (orig_map->tile_map[tile_num] == NULL) {
2279  LOG(llevError, "%s has invalid tiled map %s\n", orig_map->path, path);
2280  free(orig_map->tile_path[tile_num]);
2281  orig_map->tile_path[tile_num] = NULL;
2282  return NULL;
2283  }
2284 
2285  /* need to do a strcmp here as the orig_map->path is not a shared string */
2286  if (orig_map->tile_map[tile_num]->tile_path[dest_tile]
2287  && !strcmp(orig_map->tile_map[tile_num]->tile_path[dest_tile], orig_map->path))
2288  orig_map->tile_map[tile_num]->tile_map[dest_tile] = orig_map;
2289 
2290  return orig_map->tile_map[tile_num];
2291 }
2292 
2306 int out_of_map(mapstruct *m, int x, int y) {
2307  int16_t xp = x, yp = y;
2308  if (get_map_from_coord(m, &xp, &yp) == NULL) {
2309  return 1;
2310  } else {
2311  return 0;
2312  }
2313 }
2314 
2334 mapstruct *get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y) {
2335 
2336  /* Simple case - coordinates are within this local
2337  * map.
2338  */
2339 
2340  if ( !m ) return NULL;
2341  if (m->in_memory == MAP_SWAPPED) {
2342  // callers are calling get_map_from_coord() to access the map, so if
2343  // it's swapped out return early here. While we could finish this
2344  // computation without having to swap the map in, when they try to
2345  // get/set it will abort()
2346  //
2347  // This should never happen (if it did, the swapper is buggy) but it
2348  // does actually happen because of object recycling (e.g. op->enemy
2349  // points to a completely different object on a swapped out map)
2350  return NULL;
2351  }
2352  if (!OUT_OF_REAL_MAP(m, *x, *y))
2353  return m;
2354 
2355  do /* With the first case there, we can assume we are out of the map if we get here */
2356  {
2357  // Figure out what map should be in the direction we are off the map, and then
2358  // load that map and look again.
2359  if (*x < 0) {
2360  if (!m->tile_path[3])
2361  return NULL;
2362  if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY){
2364  /* Make sure we loaded properly. */
2365  if (!m->tile_map[3])
2366  return NULL;
2367  }
2368  *x += MAP_WIDTH(m->tile_map[3]);
2369  m = m->tile_map[3];
2370  }
2371  else if (*x >= MAP_WIDTH(m)) {
2372  if (!m->tile_path[1])
2373  return NULL;
2374  if (!m->tile_map[1] || m->tile_map[1]->in_memory != MAP_IN_MEMORY){
2376  /* Make sure we loaded properly. */
2377  if (!m->tile_map[1])
2378  return NULL;
2379  }
2380  *x -= MAP_WIDTH(m);
2381  m = m->tile_map[1];
2382  }
2383  // It is possible that x and y be considered separate compare groups,
2384  // But using an else-if here retains the old behavior that recursion produced.
2385  else if (*y < 0) {
2386  if (!m->tile_path[0])
2387  return NULL;
2388  if (!m->tile_map[0] || m->tile_map[0]->in_memory != MAP_IN_MEMORY){
2390  /* Make sure we loaded properly. */
2391  if (!m->tile_map[0])
2392  return NULL;
2393  }
2394  *y += MAP_HEIGHT(m->tile_map[0]);
2395  m = m->tile_map[0];
2396  }
2397  else if (*y >= MAP_HEIGHT(m)) {
2398  if (!m->tile_path[2])
2399  return NULL;
2400  if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY){
2402  /* Make sure we loaded properly. */
2403  if (!m->tile_map[2])
2404  return NULL;
2405  }
2406  *y -= MAP_HEIGHT(m);
2407  m = m->tile_map[2];
2408  }
2409  // The check here is if our single tile is in the map.
2410  // That is exactly what the OUT_OF_MAP macro does.
2411  } while (OUT_OF_REAL_MAP(m, *x, *y));
2412  return m; /* We have found our map */
2413 }
2414 
2428 static int adjacent_map(const mapstruct *map1, const mapstruct *map2, int *dx, int *dy) {
2429  if (!map1 || !map2)
2430  return 0;
2431 
2432  if (map1 == map2) {
2433  *dx = 0;
2434  *dy = 0;
2435  } else if (map1->tile_map[0] == map2) { /* up */
2436  *dx = 0;
2437  *dy = -MAP_HEIGHT(map2);
2438  } else if (map1->tile_map[1] == map2) { /* right */
2439  *dx = MAP_WIDTH(map1);
2440  *dy = 0;
2441  } else if (map1->tile_map[2] == map2) { /* down */
2442  *dx = 0;
2443  *dy = MAP_HEIGHT(map1);
2444  } else if (map1->tile_map[3] == map2) { /* left */
2445  *dx = -MAP_WIDTH(map2);
2446  *dy = 0;
2447  } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[1] == map2) { /* up right */
2448  *dx = MAP_WIDTH(map1->tile_map[0]);
2449  *dy = -MAP_HEIGHT(map1->tile_map[0]);
2450  } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[3] == map2) { /* up left */
2451  *dx = -MAP_WIDTH(map2);
2452  *dy = -MAP_HEIGHT(map1->tile_map[0]);
2453  } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[0] == map2) { /* right up */
2454  *dx = MAP_WIDTH(map1);
2455  *dy = -MAP_HEIGHT(map2);
2456  } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[2] == map2) { /* right down */
2457  *dx = MAP_WIDTH(map1);
2458  *dy = MAP_HEIGHT(map1->tile_map[1]);
2459  } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[1] == map2) { /* down right */
2460  *dx = MAP_WIDTH(map1->tile_map[2]);
2461  *dy = MAP_HEIGHT(map1);
2462  } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[3] == map2) { /* down left */
2463  *dx = -MAP_WIDTH(map2);
2464  *dy = MAP_HEIGHT(map1);
2465  } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[0] == map2) { /* left up */
2466  *dx = -MAP_WIDTH(map1->tile_map[3]);
2467  *dy = -MAP_HEIGHT(map2);
2468  } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[2] == map2) { /* left down */
2469  *dx = -MAP_WIDTH(map1->tile_map[3]);
2470  *dy = MAP_HEIGHT(map1->tile_map[3]);
2471  } else { /* not "adjacent" enough */
2472  return 0;
2473  }
2474 
2475  return 1;
2476 }
2477 
2505 int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags) {
2506  if (!adjacent_map(op1->map, op2->map, &retval->distance_x, &retval->distance_y)) {
2507  /* be conservative and fill in _some_ data */
2508  retval->distance = 100000;
2509  retval->distance_x = 32767;
2510  retval->distance_y = 32767;
2511  retval->direction = 0;
2512  retval->part = NULL;
2513  return 0;
2514  } else {
2515  object *best;
2516 
2517  retval->distance_x += op2->x-op1->x;
2518  retval->distance_y += op2->y-op1->y;
2519 
2520  best = op1;
2521  /* If this is multipart, find the closest part now */
2522  if (!(flags&0x1) && op1->more) {
2523  object *tmp;
2524  int best_distance = retval->distance_x*retval->distance_x+
2525  retval->distance_y*retval->distance_y, tmpi;
2526 
2527  /* we just take the offset of the piece to head to figure
2528  * distance instead of doing all that work above again
2529  * since the distance fields we set above are positive in the
2530  * same axis as is used for multipart objects, the simply arithmetic
2531  * below works.
2532  */
2533  for (tmp = op1->more; tmp != NULL; tmp = tmp->more) {
2534  tmpi = (op1->x-tmp->x+retval->distance_x)*(op1->x-tmp->x+retval->distance_x)+
2535  (op1->y-tmp->y+retval->distance_y)*(op1->y-tmp->y+retval->distance_y);
2536  if (tmpi < best_distance) {
2537  best_distance = tmpi;
2538  best = tmp;
2539  }
2540  }
2541  if (best != op1) {
2542  retval->distance_x += op1->x-best->x;
2543  retval->distance_y += op1->y-best->y;
2544  }
2545  }
2546  retval->part = best;
2547  retval->distance = ihypot(retval->distance_x, retval->distance_y);
2548  retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y);
2549  return 1;
2550  }
2551 }
2552 
2573 int get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval) {
2574  if (!adjacent_map(m, op2->map, &retval->distance_x, &retval->distance_y)) {
2575  /* be conservative and fill in _some_ data */
2576  retval->distance = 100000;
2577  retval->distance_x = 32767;
2578  retval->distance_y = 32767;
2579  retval->direction = 0;
2580  retval->part = NULL;
2581  return 0;
2582  } else {
2583  retval->distance_x += op2->x-x;
2584  retval->distance_y += op2->y-y;
2585 
2586  retval->part = NULL;
2587  retval->distance = isqrt(retval->distance_x*retval->distance_x+retval->distance_y*retval->distance_y);
2588  retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y);
2589  return 1;
2590  }
2591 }
2592 
2611 int on_same_map(const object *op1, const object *op2) {
2612  int dx, dy;
2613 
2614  return adjacent_map(op1->map, op2->map, &dx, &dy);
2615 }
2616 
2634 object *map_find_by_flag(mapstruct *map, int x, int y, int flag) {
2635  object *tmp;
2636 
2637  for (tmp = GET_MAP_OB(map, x, y); tmp != NULL; tmp = tmp->above) {
2638  object *head;
2639 
2640  head = HEAD(tmp);
2641  if (QUERY_FLAG(head, flag))
2642  return head;
2643  }
2644  return NULL;
2645 }
2646 
2652  char base[HUGE_BUF], path[sizeof(base) + 4];
2653  int count;
2654 
2655  if (map->unique) {
2656  snprintf(path, sizeof(path), "%s/%s/%s", settings.localdir, settings.playerdir, map->path+1);
2657  if (unlink(path) != 0) {
2658  LOG(llevError, "Could not delete %s: %s\n", path, strerror(errno));
2659  }
2660  return;
2661  }
2662 
2663  create_items_path(map->path, base, sizeof(base));
2664 
2665  for (count = 0; count < 10; count++) {
2666  snprintf(path, sizeof(path), "%s.v%02d", base, count);
2667  unlink(path);
2668  }
2669 }
2670 
2676 const char *map_get_path(const object *item) {
2677  if (item->map != NULL) {
2678  if (strlen(item->map->path) > 0) {
2679  return item->map->path;
2680  }
2681 
2682  return item->map->name ? item->map->name : "(empty path and name)";
2683  }
2684 
2685  if (item->env != NULL)
2686  return map_get_path(item->env);
2687 
2688  return "(no map and no env!)";
2689 }
2690 
2696 bool map_path_unique(const char *path) {
2697  return path != NULL && path[0] == '~';
2698 }
2699 
2700 MapSpace *map_space(const mapstruct *m, int x, int y) {
2701  if (m->spaces == NULL) // guard against map being swapped out
2702  abort();
2703  if (OUT_OF_REAL_MAP(m, x, y)) // array out of bounds check
2704  abort();
2705  return &m->spaces[x + m->width * y];
2706 }
2707 
2712 int map_light_on(mapstruct *m, int x, int y) {
2713  /* Check the spaces with the max light radius to see if any of them
2714  * have lights, and if any of them light the player enough, then return 1.
2715  */
2716  for (int i = x - MAX_LIGHT_RADII; i <= x + MAX_LIGHT_RADII; i++) {
2717  for (int j = y - MAX_LIGHT_RADII; j <= y + MAX_LIGHT_RADII; j++) {
2718  int16_t nx = i;
2719  int16_t ny = j;
2720  auto real = get_map_from_coord(m, &nx, &ny);
2721  if (real == nullptr)
2722  continue;
2723 
2724  int light = GET_MAP_LIGHT(real, nx, ny);
2725  if (light == 0)
2726  continue;
2727 
2728  if (ihypot(i - x, j - y) < light)
2729  return 1;
2730  }
2731  }
2732 
2733  return 0;
2734 }
mapstruct::tile_path
char * tile_path[4]
Path to adjoining maps.
Definition: map.h:353
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Gets the bottom object on a map.
Definition: map.h:170
living::exp
int64_t exp
Experience.
Definition: living.h:47
S_IWUSR
#define S_IWUSR
Definition: win32.h:47
shopitems::strength
int8_t strength
The degree of specialisation the shop has in this item, as a percentage from -100 to 100.
Definition: map.h:299
PLAYER
@ PLAYER
Definition: object.h:112
object_get_owner
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.cpp:804
Settings::mapdir
const char * mapdir
Where the map files are.
Definition: global.h:253
output_file.h
path.h
FREE_AND_CLEAR_STR_IF
#define FREE_AND_CLEAR_STR_IF(xyz)
Definition: global.h:202
global.h
FREE_OBJ_NO_DESTROY_CALLBACK
#define FREE_OBJ_NO_DESTROY_CALLBACK
Do not run the destroy callback.
Definition: object.h:545
settings
struct Settings settings
Server settings.
Definition: init.cpp:139
INS_NO_WALK_ON
#define INS_NO_WALK_ON
Don't call check_walk_on against the originator.
Definition: object.h:582
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:724
SAVE_MODE
#define SAVE_MODE
If you have defined SAVE_PLAYER, you might want to change this, too.
Definition: config.h:563
MAP_SAVING
#define MAP_SAVING
Map being saved.
Definition: map.h:129
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
MAP_NO_DIFFICULTY
#define MAP_NO_DIFFICULTY
If set then don't compute a map difficulty if it is 0.
Definition: map.h:93
MAP_LAYER_ITEM3
#define MAP_LAYER_ITEM3
Definition: map.h:45
MOVE_ALL
#define MOVE_ALL
Mask of all movement types.
Definition: define.h:398
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
get_empty_map
mapstruct * get_empty_map(int sizex, int sizey)
Creates and returns a map of the specific size.
Definition: map.cpp:854
FLAG_OVERLAY_FLOOR
#define FLAG_OVERLAY_FLOOR
Object is an overlay floor.
Definition: define.h:255
of_close
int of_close(OutputFile *of)
Closes an output file.
Definition: output_file.cpp:61
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
archetype::more
archetype * more
Next part of a linked object.
Definition: object.h:486
create_items_path
static void create_items_path(const char *s, char *buf, size_t size)
This makes absolute path to the itemfile where unique objects will be saved.
Definition: map.cpp:166
get_region_by_name
region * get_region_by_name(const char *region_name)
Gets a region by name.
Definition: region.cpp:45
of_open
FILE * of_open(OutputFile *of, const char *fname)
Opens an output file.
Definition: output_file.cpp:30
FLAG_GENERATOR
#define FLAG_GENERATOR
Will generate type ob->stats.food.
Definition: define.h:248
player
One player.
Definition: player.h:105
MAP_RESET_TIMEOUT
#define MAP_RESET_TIMEOUT(m)
Definition: map.h:64
blocked_link
int blocked_link(object *ob, mapstruct *m, int16_t sx, int16_t sy)
Returns true if the given coordinate is blocked except by the object passed is not blocking.
Definition: map.cpp:356
strdup_local
#define strdup_local
Definition: compat.h:29
object::inv
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
SAVE_FLAG_NO_REMOVE
#define SAVE_FLAG_NO_REMOVE
If set, objects are not removed while saving.
Definition: map.h:107
delete_unique_items
static void delete_unique_items(mapstruct *m)
This goes through map 'm' and removes any unique items on the map.
Definition: map.cpp:1335
ready_map_name
mapstruct * ready_map_name(const char *name, int flags)
Makes sure the given map is loaded and swapped in.
Definition: map.cpp:1780
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
S_IROTH
#define S_IROTH
Definition: win32.h:50
load_temporary_map
static int load_temporary_map(mapstruct *m)
Loads a map, which has been loaded earlier, from file.
Definition: map.cpp:1264
ob_move_block
bool ob_move_block(object *ob1, object *ob2)
Basic macro to see if ob2 blocks ob1 from moving onto this space.
Definition: map.cpp:327
has_been_loaded
mapstruct * has_been_loaded(const char *name)
Checks whether map has been loaded.
Definition: map.cpp:79
print_shop_string
static void print_shop_string(mapstruct *m, char *output_string, int size)
Opposite of parse string(), this puts the string that was originally fed in to the map (or something ...
Definition: map.cpp:958
update_position
void update_position(mapstruct *m, int x, int y)
This function updates various attributes about a specific space on the map (what it looks like,...
Definition: map.cpp:2130
MAP_LAYER_FLOOR
#define MAP_LAYER_FLOOR
Definition: map.h:40
map_light_on
int map_light_on(mapstruct *m, int x, int y)
Return the light level at position (X, Y) on map M.
Definition: map.cpp:2712
Settings::datadir
const char * datadir
Read only data files.
Definition: global.h:250
add_face_layer
static void add_face_layer(int low_layer, int high_layer, object *ob, object *layers[], int honor_visibility)
This function is used for things that can have multiple layers - NO_PICK, ITEM, LIVING,...
Definition: map.cpp:2061
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.cpp:57
if
if(!(yy_init))
Definition: loader.cpp:36428
FLAG_UNIQUE
#define FLAG_UNIQUE
Item is really unique (UNIQUE_ITEMS)
Definition: define.h:287
FLAG_OBJ_ORIGINAL
#define FLAG_OBJ_ORIGINAL
NEVER SET THIS.
Definition: define.h:357
object::x
int16_t x
Definition: object.h:335
maps_saved_total
int maps_saved_total
Definition: logger.cpp:40
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
MoveType
unsigned char MoveType
Typdef here to define type large enough to hold bitmask of all movement types.
Definition: define.h:417
shopitems::index
int index
Being the size of the shopitems array.
Definition: map.h:301
SET_MAP_MOVE_ON
#define SET_MAP_MOVE_ON(M, X, Y, C)
Sets the move_on state of a square.
Definition: map.h:204
CHECK_INV
@ CHECK_INV
b.t.
Definition: object.h:174
CALLOC
#define CALLOC(x, y)
Definition: compat.h:31
map_path
void map_path(const char *map, int flags, char *pathname, size_t bufsize)
Definition: map.cpp:1177
map_layer_info
static const Map_Layer_Info map_layer_info[MAP_LAYERS]
the ob->map_layer holds the low layer.
Definition: map.cpp:63
MAP_LAYERS
#define MAP_LAYERS
Definition: map.h:32
EVENT_MAPLOAD
#define EVENT_MAPLOAD
A map is loaded (pristine state)
Definition: events.h:48
flags
static const flag_definition flags[]
Flag mapping.
Definition: gridarta-types-convert.cpp:101
typedata::name
const char * name
Object name.
Definition: define.h:91
clean_object
void clean_object(object *op)
Remove and free all objects in the inventory of the given object.
Definition: map.cpp:1599
MAP_PLAYER_UNIQUE
#define MAP_PLAYER_UNIQUE
This map is player-specific.
Definition: map.h:92
load_object
int load_object(FILE *fp, object *op, int bufstate, int map_flags, bool artifact_init)
Loads an object from the given file-pointer.
Definition: loader.cpp:38944
PROFILE_BEGIN
#define PROFILE_BEGIN(expr)
Definition: global.h:371
MAP_OVERLAY
#define MAP_OVERLAY
Map to load is an overlay.
Definition: map.h:95
typedata::name_pl
const char * name_pl
Plural name.
Definition: define.h:92
dump_map
void dump_map(const mapstruct *m)
Prints out debug-information about a map.
Definition: map.cpp:245
NDI_NAVY
#define NDI_NAVY
Definition: newclient.h:247
FLAG_NO_MAGIC
#define FLAG_NO_MAGIC
Spells (some) can't pass this object.
Definition: define.h:276
blank_face
const Face * blank_face
Following can just as easily be pointers, but it is easier to keep them like this.
Definition: image.cpp:36
P_NO_MAGIC
#define P_NO_MAGIC
Spells (some) can't pass this object.
Definition: map.h:227
TRANSPORT
@ TRANSPORT
see doc/Developers/objects
Definition: object.h:113
LO_NEWFILE
#define LO_NEWFILE
Definition: loader.h:17
FLAG_BLOCKSVIEW
#define FLAG_BLOCKSVIEW
Object blocks view.
Definition: define.h:269
rv_vector::part
object * part
Part we found.
Definition: map.h:375
object::title
sstring title
Of foo, etc.
Definition: object.h:325
mapstruct::path
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:355
object_get_value
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4346
GET_MAP_FACE_OBJS
#define GET_MAP_FACE_OBJS(M, X, Y)
Returns the layers array so update_position can just copy the entire array over.
Definition: map.h:187
P_IS_ALIVE
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:237
MSG_TYPE_MISC
#define MSG_TYPE_MISC
Messages that don't go elsewhere.
Definition: newclient.h:416
free_all_maps
void free_all_maps(void)
Frees all allocated maps.
Definition: map.cpp:1974
buf
StringBuffer * buf
Definition: readable.cpp:1565
object::above
object * above
Pointer to the object stacked above this one.
Definition: object.h:296
HUGE_BUF
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
AB_NO_PASS
#define AB_NO_PASS
Definition: map.h:235
ihypot
int ihypot(int a, int b)
Rough estimate of hypot(a, b).
Definition: utils.cpp:570
MAP_LAYER_ITEM1
#define MAP_LAYER_ITEM1
Items that can be picked up.
Definition: map.h:43
Map_Layer_Info::honor_visibility
uint8_t honor_visibility
If 0 then don't reorder items, else allow.
Definition: map.cpp:54
FLAG_NO_PICK
#define FLAG_NO_PICK
Object can't be picked up.
Definition: define.h:239
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
mapstruct::width
uint16_t width
Definition: map.h:337
MAP_STYLE
#define MAP_STYLE
Active objects shouldn't be put on active list.
Definition: map.h:94
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Can't see what's underneath this object.
Definition: define.h:302
SAVE_MODE_OVERLAY
#define SAVE_MODE_OVERLAY
Map is persisted as an overlay.
Definition: map.h:118
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
FLAG_ALIVE
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
INS_ABOVE_FLOOR_ONLY
#define INS_ABOVE_FLOOR_ONLY
Put object immediatly above the floor.
Definition: object.h:581
rv_vector::distance_y
int distance_y
Y delta.
Definition: map.h:373
map_remove_unique_files
void map_remove_unique_files(const mapstruct *map)
Remove files containing the map's unique items.
Definition: map.cpp:2651
LO_NOREAD
#define LO_NOREAD
Definition: loader.h:18
typedata
Link an object type with skill needed to identify, and general name.
Definition: define.h:89
save_objects
int save_objects(mapstruct *m, FILE *fp, FILE *fp2, int flag)
This saves all the objects on the map in a non destructive fashion.
Definition: map.cpp:727
PROFILE_END
#define PROFILE_END(var, expr)
Definition: global.h:376
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
m
static event_registration m
Definition: citylife.cpp:422
set_darkness_map
void set_darkness_map(mapstruct *m)
Set the darkness level for a map, based on the time of the day.
Definition: main.cpp:371
rv_vector::distance_x
int distance_x
X delta.
Definition: map.h:372
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:126
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
Definition: stringbuffer.cpp:76
apply_auto_fix
void apply_auto_fix(mapstruct *m)
Go through the entire map (only the first time when an original map is loaded) and performs special a...
Definition: main.cpp:258
MAP_LAYER_NO_PICK2
#define MAP_LAYER_NO_PICK2
Non pickable ground objects.
Definition: map.h:42
MAP_DIFFICULTY
#define MAP_DIFFICULTY(m)
Definition: map.h:65
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1560
MAP_MINTIMEOUT
#define MAP_MINTIMEOUT
At least that many ticks before swapout.
Definition: config.h:409
map_size
uint32_t map_size(mapstruct *m)
Calculate map size without intermediate sign extension.
Definition: map.cpp:810
P_NEW_MAP
#define P_NEW_MAP
Coordinates passed result in a new tiled map.
Definition: map.h:250
SAVE_ERROR_CLOSE
#define SAVE_ERROR_CLOSE
Close error for regular file.
Definition: map.h:145
object_value_set_shared
bool object_value_set_shared(const object *op, sstring key)
Determine if an extra value is set to a non empty or 0 value.
Definition: object.cpp:4390
of_cancel
void of_cancel(OutputFile *of)
Cancels a save process.
Definition: output_file.cpp:89
get_typedata
const typedata * get_typedata(int itemtype)
Definition: item.cpp:323
P_NO_ERROR
#define P_NO_ERROR
Purely temporary - if set, update_position does not complain if the flags are different.
Definition: map.h:240
MSG_TYPE_ATTACK_NOKEY
#define MSG_TYPE_ATTACK_NOKEY
Keys are like attacks, so...
Definition: newclient.h:620
stats.h
check_inv_recursive
object * check_inv_recursive(object *op, const object *trig)
Checks object and its inventory for specific item.
Definition: button.cpp:782
path_combine_and_normalize
char * path_combine_and_normalize(const char *src, const char *dst, char *path, size_t size)
Combines the 2 paths.
Definition: path.cpp:172
load_unique_objects
static void load_unique_objects(mapstruct *m)
Loads unique objects from file(s) into the map which is in memory.
Definition: map.cpp:1360
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
add_string
sstring add_string(const char *str)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
first_map
mapstruct * first_map
First map.
Definition: init.cpp:107
HEAD
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:607
clean_tmp_map
void clean_tmp_map(mapstruct *m)
Removse the temporary file used by the map.
Definition: map.cpp:1965
SAVE_ERROR_RCREATION
#define SAVE_ERROR_RCREATION
Couldn't create the regular save file.
Definition: map.h:140
MAP_WHEN_RESET
#define MAP_WHEN_RESET(m)
This is when the map will reset.
Definition: map.h:62
change_map_light
int change_map_light(mapstruct *m, int change)
Used to change map light level (darkness) up or down.
Definition: map.cpp:2006
object::move_type
MoveType move_type
Type of movement this object uses.
Definition: object.h:436
ext_info_map
void void ext_info_map(int color, const mapstruct *map, uint8_t type, uint8_t subtype, const char *str1)
Writes to everyone on the specified map.
Definition: main.cpp:334
mapfile_load_lowlevel
mapstruct * mapfile_load_lowlevel(const char *map, const char *pathname, int flags)
Definition: map.cpp:1187
object::face
const Face * face
Face with colors.
Definition: object.h:341
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Return 1 if coordinates X and Y are out of the map M, taking into account tiling.
Definition: map.cpp:2306
MAX_DARKNESS
#define MAX_DARKNESS
Maximum map darkness, there is no practical reason to exceed this.
Definition: define.h:448
MSG_TYPE_ATTACK
#define MSG_TYPE_ATTACK
Attack related messages.
Definition: newclient.h:412
isqrt
int isqrt(int n)
Compute the square root.
Definition: utils.cpp:562
MOVE_FLYING
#define MOVE_FLYING
Combo of fly_low and fly_high.
Definition: define.h:395
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
EVENT_MAPUNLOAD
#define EVENT_MAPUNLOAD
A map is freed (includes swapping out)
Definition: events.h:51
INS_NO_MERGE
#define INS_NO_MERGE
Don't try to merge with other items.
Definition: object.h:580
FLAG_DAMNED
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:317
t
in that case they will be relative to whatever the PWD of the crossfire server process is You probably shouldn t
Definition: server-directories.txt:28
SET_MAP_FLAGS
#define SET_MAP_FLAGS(M, X, Y, C)
Sets map flags.
Definition: map.h:159
remove_button_link
void remove_button_link(object *op)
Remove the object from the linked lists of buttons in the map.
Definition: button.cpp:693
MAP_LAYER_LIVING1
#define MAP_LAYER_LIVING1
Living creatures.
Definition: map.h:46
shopitems::name_pl
const char * name_pl
Plural name.
Definition: map.h:297
MAP_LAYER_FLY1
#define MAP_LAYER_FLY1
Flying objects - creatures, spells.
Definition: map.h:48
object_free
void object_free(object *ob, int flags)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1592
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:192
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:671
MAP_DEFAULTRESET
#define MAP_DEFAULTRESET
Default time to reset.
Definition: config.h:427
FLAG_CAN_ROLL
#define FLAG_CAN_ROLL
Object can be rolled.
Definition: define.h:254
free_map
void free_map(mapstruct *m)
Frees everything allocated by the given mapstructure.
Definition: map.cpp:1662
level_exp
int64_t level_exp(int level, double expmul)
Returns how much experience is needed for a player to become the given level.
Definition: living.cpp:1885
free_all_objects
static void free_all_objects(mapstruct *m)
Remove and free all objects in the given map.
Definition: map.cpp:1615
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
P_PLAYER
#define P_PLAYER
There is a player on this space.
Definition: map.h:236
sproto.h
GET_MAP_LIGHT
#define GET_MAP_LIGHT(M, X, Y)
Gets map light.
Definition: map.h:162
get_map_from_coord
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
This is basically the same as out_of_map above(), but instead we return NULL if no map is valid (coor...
Definition: map.cpp:2334
MapSpace
This structure contains all information related to one map square.
Definition: map.h:256
get_rangevector_from_mapcoord
int get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval)
This is basically the same as get_rangevector() above, but instead of the first parameter being an ob...
Definition: map.cpp:2573
map_find_by_flag
object * map_find_by_flag(mapstruct *map, int x, int y, int flag)
Finds an object in a map tile by flag number.
Definition: map.cpp:2634
delete_map
void delete_map(mapstruct *m)
Frees the map, including the mapstruct.
Definition: map.cpp:1708
MSG_SUBTYPE_NONE
#define MSG_SUBTYPE_NONE
Definition: newclient.h:423
ob_blocked
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Returns true if the given object can't fit in the given spot.
Definition: map.cpp:491
NDI_BLACK
#define NDI_BLACK
Definition: newclient.h:245
SAVE_ERROR_NO_PATH
#define SAVE_ERROR_NO_PATH
Map had no path set.
Definition: map.h:143
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.cpp:2100
mapstruct::last_reset_time
long last_reset_time
A timestamp of the last original map loading.
Definition: map.h:356
link_multipart_objects
static void link_multipart_objects(mapstruct *m)
Go through all the objects on the map looking for objects whose arch says they are multipart yet acco...
Definition: map.cpp:587
FLAG_MONSTER
#define FLAG_MONSTER
Will attack players.
Definition: define.h:245
get_typedata_by_name
const typedata * get_typedata_by_name(const char *name)
Definition: item.cpp:343
fatal
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
get_linked_map
mapstruct * get_linked_map(void)
Allocates, initialises, and returns a pointer to a mapstruct, linked through first_map.
Definition: map.cpp:788
seconds
long seconds(void)
Return wall clock time in seconds.
Definition: time.cpp:348
MAP_WIDTH
#define MAP_WIDTH(m)
Map width.
Definition: map.h:73
maps_loaded_total
int maps_loaded_total
Definition: logger.cpp:39
create_template_pathname
void create_template_pathname(const char *name, char *buf, size_t size)
same as create_pathname(), but for the template maps.
Definition: map.cpp:145
P_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:249
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
INS_ON_TOP
#define INS_ON_TOP
Always put object on top.
Definition: object.h:583
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Portable implementation of strlcpy(3).
Definition: porting.cpp:222
map_space
MapSpace * map_space(const mapstruct *m, int x, int y)
Definition: map.cpp:2700
object_new
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it.
Definition: object.cpp:1273
create_overlay_pathname
void create_overlay_pathname(const char *name, char *buf, size_t size)
Same as create_pathname(), but for the overlay maps.
Definition: map.cpp:125
OB_MOVE_BLOCK
#define OB_MOVE_BLOCK(ob1, ob2)
Definition: define.h:418
shopitems::typenum
int typenum
Itemtype number we need to match, -1 if it is the default price.
Definition: map.h:298
object::head
object * head
Points to the main object of a large body.
Definition: object.h:304
set_map_reset_time
void set_map_reset_time(mapstruct *map)
Updates the map's timeout.
Definition: map.cpp:2245
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
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:280
SAVE_MODE_NORMAL
#define SAVE_MODE_NORMAL
No special handling.
Definition: map.h:116
Settings::playerdir
const char * playerdir
Where the player files are.
Definition: global.h:252
SAVE_ERROR_UCREATION
#define SAVE_ERROR_UCREATION
Couldn't create the file for unique objects.
Definition: map.h:141
StringBuffer
A buffer that will be expanded as content is added to it.
Definition: stringbuffer.cpp:25
SET_MAP_MOVE_SLOW
#define SET_MAP_MOVE_SLOW(M, X, Y, C)
Sets the slowing state of a square.
Definition: map.h:199
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:717
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Checks if a square is out of the map.
Definition: map.h:217
find_dir_2
int find_dir_2(int x, int y)
Computes a direction which you should travel to move of x and y.
Definition: object.cpp:3677
load_and_link_tiled_map
static mapstruct * load_and_link_tiled_map(mapstruct *orig_map, int tile_num)
This updates the orig_map->tile_map[tile_num] value after loading the map.
Definition: map.cpp:2271
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:232
MAP_LAYER_NO_PICK1
#define MAP_LAYER_NO_PICK1
Non pickable ground objects.
Definition: map.h:41
INS_MAP_LOAD
#define INS_MAP_LOAD
Disable lots of checkings.
Definition: object.h:585
FLAG_WIZ
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:231
decay_objects
void decay_objects(mapstruct *m)
Decay and destroy persihable items in a map.
Definition: utils.cpp:175
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:265
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
Map_Layer_Info
Information about a layer.
Definition: map.cpp:52
load_map_header
static int load_map_header(FILE *fp, mapstruct *m)
This loads the header information of the map.
Definition: map.cpp:1000
FREE_AND_CLEAR
#define FREE_AND_CLEAR(xyz)
Free the pointer and then set it to NULL.
Definition: global.h:195
shopitems::name
const char * name
Name of the item in question, null if it is the default item.
Definition: map.h:296
Map_Layer_Info::high_layer
uint8_t high_layer
Highest layer for this group.
Definition: map.cpp:53
adjacent_map
static int adjacent_map(const mapstruct *map1, const mapstruct *map2, int *dx, int *dy)
Return whether map2 is adjacent to map1.
Definition: map.cpp:2428
Face::visibility
uint8_t visibility
How visible is the face compared to other faces, highest wins.
Definition: face.h:16
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_.
Definition: map.cpp:300
P_NEED_UPDATE
#define P_NEED_UPDATE
This space is out of date.
Definition: map.h:239
mapstruct
This is a game-map.
Definition: map.h:315
object::env
object * env
Pointer to the object which is the environment.
Definition: object.h:301
create_pathname
char * create_pathname(const char *name, char *buf, size_t size)
Get the full path to a map file.
Definition: map.cpp:104
msgbuf
static char msgbuf[HUGE_BUF]
Definition: loader.cpp:35880
MapSpace::flags
uint8_t flags
Flags about this space (see the P_ values above).
Definition: map.h:260
mapstruct::name
char * name
Name of map as given by its creator.
Definition: map.h:318
mapstruct::in_memory
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:335
rv_vector
This is used by get_rangevector to determine where the other creature is.
Definition: map.h:370
update_buttons
void update_buttons(mapstruct *m)
Updates every button on the map (by calling update_button() for them).
Definition: button.cpp:227
MAP_SWAPPED
#define MAP_SWAPPED
Map spaces have been saved to disk.
Definition: map.h:127
objects
object * objects
Pointer to the list of used objects.
Definition: object.cpp:294
shopitems
Shop-related information for a map.
Definition: map.h:295
map_get_path
const char * map_get_path(const object *item)
Return the map path on which the specified item is.
Definition: map.cpp:2676
SET_MAP_MOVE_BLOCK
#define SET_MAP_MOVE_BLOCK(M, X, Y, C)
Sets the blocking state of a square.
Definition: map.h:194
on_same_map
int on_same_map(const object *op1, const object *op2)
Checks whether 2 objects are on the same map or not.
Definition: map.cpp:2611
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
map_path_unique
bool map_path_unique(const char *path)
Return true if the given map path leads to a unique map.
Definition: map.cpp:2696
MAP_HEIGHT
#define MAP_HEIGHT(m)
Map height.
Definition: map.h:75
save_object_in_sb
void save_object_in_sb(StringBuffer *sb, object *op, const int flag)
Store a string representation of op in sb.
Definition: object.cpp:5311
MAP_ENTER_Y
#define MAP_ENTER_Y(m)
Default Y coordinate for map enter.
Definition: map.h:82
SAVE_ERROR_URENAME
#define SAVE_ERROR_URENAME
Couldn't rename unique temporary file.
Definition: map.h:144
strip_endline
void strip_endline(char *buf)
Removes endline from buffer (modified in place).
Definition: utils.cpp:314
mapstruct::tile_map
mapstruct * tile_map[4]
Adjoining maps.
Definition: map.h:354
typedata::number
int number
Type.
Definition: define.h:90
object_remove_from_active_list
void object_remove_from_active_list(object *op)
This function removes object 'op' from the list of active objects.
Definition: object.cpp:1392
arch_to_object
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
mapstruct::spaces
MapSpace * spaces
Array of spaces on this map.
Definition: map.h:345
S_IRUSR
#define S_IRUSR
Definition: win32.h:56
get_rangevector
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
From map.c This is used by get_player to determine where the other creature is.
Definition: map.cpp:2505
update_all_map_los
void update_all_map_los(mapstruct *map)
update all_map_los is like update_all_los() below, but updates everyone on the map,...
Definition: los.cpp:567
allocate_map
void allocate_map(mapstruct *m)
This basically allocates the dynamic array of spaces for the map.
Definition: map.cpp:824
MAP_LAYER_FLY2
#define MAP_LAYER_FLY2
Arrows, etc.
Definition: map.h:49
FMT64U
#define FMT64U
Definition: compat.h:17
SAVE_ERROR_OK
#define SAVE_ERROR_OK
No error.
Definition: map.h:139
loader.h
object_fix_multipart
void object_fix_multipart(object *tmp)
Ensures specified object has its more parts correctly inserted in map.
Definition: object.cpp:4685
S_IWOTH
#define S_IWOTH
Definition: win32.h:41
fix_container_multipart
static void fix_container_multipart(object *container)
Go through all the objects in a container (recursively) looking for objects whose arch says they are ...
Definition: map.cpp:546
MAP_ENTER_X
#define MAP_ENTER_X(m)
Default X coordinate for map enter.
Definition: map.h:80
Settings::templatedir
const char * templatedir
Directory for the template map.
Definition: global.h:256
object_remove
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to.
Definition: object.cpp:1833
EVENT_MAPREADY
#define EVENT_MAPREADY
A map is ready, either first load or after reload.
Definition: events.h:49
MAP_FLUSH
#define MAP_FLUSH
Always load map from the map directory, and don't do unique items or the like.
Definition: map.h:91
GET_MAP_FLAGS
#define GET_MAP_FLAGS(M, X, Y)
Gets map flags.
Definition: map.h:157
DOOR
@ DOOR
Definition: object.h:131
object_sum_weight
signed long object_sum_weight(object *op)
object_sum_weight() is a recursive function which calculates the weight an object is carrying.
Definition: object.cpp:568
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:236
MAP_LAYER_LIVING2
#define MAP_LAYER_LIVING2
Definition: map.h:47
LL_NORMAL
#define LL_NORMAL
Definition: loader.h:12
OB_TYPE_MOVE_BLOCK
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Basic macro to see if if ob1 can not move onto a space based on the 'type' move_block parameter Add c...
Definition: define.h:426
S_IWGRP
#define S_IWGRP
Definition: win32.h:44
P_NO_CLERIC
#define P_NO_CLERIC
No clerical spells cast here.
Definition: map.h:238
make_path_to_file
void make_path_to_file(const char *filename)
Checks if any directories in the given path doesn't exist, and creates if necessary.
Definition: porting.cpp:164
mapstruct::unique
uint32_t unique
If set, this is a per player unique map.
Definition: map.h:328
save_map
int save_map(mapstruct *m, int flag)
Saves a map to file.
Definition: map.cpp:1407
calculate_difficulty
int calculate_difficulty(mapstruct *m)
This routine is supposed to find out the difficulty of the map.
Definition: map.cpp:1908
FLAG_IS_LINKED
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:315
mapstruct::next
mapstruct * next
Next map, linked list.
Definition: map.h:316
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
object::more
object * more
Pointer to the rest of a large body of objects.
Definition: object.h:303
SET_MAP_PLAYER
#define SET_MAP_PLAYER(M, X, Y, C)
Definition: map.h:167
blocks_prayer
sstring blocks_prayer
For update_position() mostly.
Definition: init.cpp:126
Settings::tmpdir
const char * tmpdir
Directory to use for temporary files.
Definition: global.h:257
mapfile_load
mapstruct * mapfile_load(const char *map, int flags)
Opens the file "filename" and reads information about the map from the given file,...
Definition: map.cpp:1228
LO_REPEAT
#define LO_REPEAT
Definition: loader.h:15
parse_shop_string
static shopitems * parse_shop_string(const char *input_string, const mapstruct *map)
Takes a string from a map definition and outputs a pointer to the array of shopitems corresponding to...
Definition: map.cpp:876
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
MAP_MAXRESET
#define MAP_MAXRESET
MAP_MAXRESET is the maximum time a map can have before being reset.
Definition: config.h:425
SAVE_FLAG_SAVE_UNPAID
#define SAVE_FLAG_SAVE_UNPAID
If set, unpaid items will be saved.
Definition: map.h:106
rv_vector::direction
int direction
General direction to the targer.
Definition: map.h:374
SET_MAP_LIGHT
#define SET_MAP_LIGHT(M, X, Y, L)
Sets map light.
Definition: map.h:164
rv_vector::distance
unsigned int distance
Distance, in squares.
Definition: map.h:371
map_reset_swap
void map_reset_swap(mapstruct *m)
Call this when an in-memory map is used or referenced.
Definition: map.cpp:1762
map_layer_name
const char *const map_layer_name[MAP_LAYERS]
These correspond to the layer names in map.h - since some of the types can be on multiple layers,...
Definition: map.cpp:46
MAP_LOADING
#define MAP_LOADING
This map is being loaded.
Definition: map.h:128
object::move_block
MoveType move_block
What movement types this blocks.
Definition: object.h:437
object::next
object * next
Pointer to the next object in the free/used list.
Definition: object.h:285
load_overlay_map
static int load_overlay_map(const char *filename, mapstruct *m)
Loads an overlay for a map, which has been loaded earlier, from file.
Definition: map.cpp:1300
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:664
check_path
int check_path(const char *name, int prepend_dir)
This function checks if a file with the given path exists.
Definition: map.cpp:201
S_IRGRP
#define S_IRGRP
Definition: win32.h:53
MAX_LIGHT_RADII
#define MAX_LIGHT_RADII
Max radii for 'light' object, really large values allow objects that can slow down the game.
Definition: define.h:444
dump_all_maps
void dump_all_maps(void)
Prints out debug-information about all maps.
Definition: map.cpp:268
events_execute_global_event
void events_execute_global_event(int eventcode,...)
Execute a global event.
Definition: events.cpp:30
load_objects
void load_objects(mapstruct *m, FILE *fp, int mapflags)
Loads (and parses) the objects into a given map from the specified file pointer.
Definition: map.cpp:615
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
P_BLOCKSVIEW
#define P_BLOCKSVIEW
This spot blocks the player's view.
Definition: map.h:226
face
in that case they will be relative to whatever the PWD of the crossfire server process is You probably shouldn though Notes on Specific and settings file datadir Usually usr share crossfire Contains data that the server does not need to modify while such as the etc A default install will pack the and treasurelist definitions into a single or trs file and the graphics into a face(metadata) and .tar(bitmaps) file
LL_MORE
#define LL_MORE
Definition: loader.h:11
Settings::uniquedir
const char * uniquedir
Directory for the unique items.
Definition: global.h:255
OutputFile
Definition: output_file.h:41
SET_MAP_MOVE_OFF
#define SET_MAP_MOVE_OFF(M, X, Y, C)
Sets the move_off state of a square.
Definition: map.h:209
Settings::localdir
const char * localdir
Read/write data files.
Definition: global.h:251