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 
146 static void create_items_path(const char *s, char *buf, size_t size) {
147  char *t;
148 
149  if (*s == '/')
150  s++;
151 
152  snprintf(buf, size, "%s/%s/", settings.localdir, settings.uniquedir);
153  t = buf+strlen(buf);
154  snprintf(t, buf+size-t, "%s", s);
155 
156  while (*t != '\0') {
157  if (*t == '/')
158  *t = '@';
159  t++;
160  }
161 }
162 
181 int check_path(const char *name, int prepend_dir) {
182  char buf[MAX_BUF];
183 #ifndef WIN32
184  struct stat statbuf;
185  int mode = 0;
186 #endif
187 
188  if (prepend_dir)
190  else
191  strlcpy(buf, name, sizeof(buf));
192 #ifdef WIN32 /* ***win32: check this sucker in windows style. */
193  return(_access(buf, 0));
194 #else
195 
196  if (stat(buf, &statbuf) != 0)
197  return -1;
198 
199  if (!S_ISREG(statbuf.st_mode))
200  return (-1);
201 
202  if (((statbuf.st_mode&S_IRGRP) && getegid() == statbuf.st_gid)
203  || ((statbuf.st_mode&S_IRUSR) && geteuid() == statbuf.st_uid)
204  || (statbuf.st_mode&S_IROTH))
205  mode |= 4;
206 
207  if ((statbuf.st_mode&S_IWGRP && getegid() == statbuf.st_gid)
208  || (statbuf.st_mode&S_IWUSR && geteuid() == statbuf.st_uid)
209  || (statbuf.st_mode&S_IWOTH))
210  mode |= 2;
211 
212  return (mode);
213 #endif
214 }
215 
225 void dump_map(const mapstruct *m) {
226  LOG(llevError, "Map %s status: %d.\n", m->path, m->in_memory);
227  LOG(llevError, "Size: %dx%d Start: %d,%d\n", MAP_WIDTH(m), MAP_HEIGHT(m), MAP_ENTER_X(m), MAP_ENTER_Y(m));
228 
229  if (m->msg != NULL)
230  LOG(llevError, "Message:\n%s", m->msg);
231 
232  if (m->maplore != NULL)
233  LOG(llevError, "Lore:\n%s", m->maplore);
234 
235  if (m->tmpname != NULL)
236  LOG(llevError, "Tmpname: %s\n", m->tmpname);
237 
238  LOG(llevError, "Difficulty: %d\n", m->difficulty);
239  LOG(llevError, "Darkness: %d\n", m->darkness);
240 }
241 
248 void dump_all_maps(void) {
249  mapstruct *m;
250 
251  for (m = first_map; m != NULL; m = m->next) {
252  dump_map(m);
253  }
254 }
255 
280 int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny) {
281  int retval = 0;
282  mapstruct *mp;
283 
284  /*
285  * Since x and y are copies of the original values, we can directly
286  * mess with them here.
287  */
288  mp = get_map_from_coord(oldmap, &x, &y);
289  if (!mp)
290  return P_OUT_OF_MAP;
291  if (mp != oldmap)
292  retval |= P_NEW_MAP;
293  if (newmap)
294  *newmap = mp;
295  if (nx)
296  *nx = x;
297  if (ny)
298  *ny = y;
299  retval |= mp->spaces[x+mp->width*y].flags;
300  return retval;
301 }
302 
307 bool ob_move_block(object *ob1, object *ob2) {
308  // Special case: if ob1 has no move type, but we're here, then we're being
309  // pushed by something. Assume "walk".
310  return ((ob1->move_type ? ob1->move_type : MOVE_WALK) & ~ob2->move_block) == 0;
311 }
312 
334 int blocked_link(object *ob, mapstruct *m, int16_t sx, int16_t sy) {
335  object *tmp_head;
336  int mflags, blocked;
337 
338  /* Make sure the coordinates are valid - they should be, as caller should
339  * have already checked this.
340  */
341  if (OUT_OF_REAL_MAP(m, sx, sy)) {
342  LOG(llevError, "blocked_link: Passed map, x, y coordinates outside of map\n");
343  return 1;
344  }
345 
346  /* special hack for transports: if it's a transport with a move_type of 0, it can do on the space anyway */
347  if (ob->type == TRANSPORT && ob->move_type == 0)
348  return 0;
349 
350  mflags = m->spaces[sx+m->width*sy].flags;
351 
352  blocked = GET_MAP_MOVE_BLOCK(m, sx, sy);
353 
354  /* If space is currently not blocked by anything, no need to
355  * go further. Not true for players - all sorts of special
356  * things we need to do for players.
357  */
358  if (ob->type != PLAYER && !(mflags&P_IS_ALIVE) && (blocked == 0))
359  return 0;
360 
361  /* if there isn't anytyhing alive on this space, and this space isn't
362  * otherwise blocked, we can return now. Only if there is a living
363  * creature do we need to investigate if it is part of this creature
364  * or another. Likewise, only if something is blocking us do we
365  * need to investigate if there is a special circumstance that would
366  * let the player through (inventory checkers for example)
367  */
368  if (!(mflags&P_IS_ALIVE) && !OB_TYPE_MOVE_BLOCK(ob, blocked))
369  return 0;
370 
371  ob = HEAD(ob);
372 
373  /* We basically go through the stack of objects, and if there is
374  * some other object that has NO_PASS or FLAG_ALIVE set, return
375  * true. If we get through the entire stack, that must mean
376  * ob is blocking it, so return 0.
377  */
378  FOR_MAP_PREPARE(m, sx, sy, tmp) {
379  /* Never block part of self. */
380  tmp_head = HEAD(tmp);
381  if (tmp_head == ob)
382  continue;
383  /* This must be before the checks below. Code for inventory checkers. */
384  if (tmp->type == CHECK_INV && OB_MOVE_BLOCK(ob, tmp)) {
385  /* If last_sp is set, the player/monster needs an object,
386  * so we check for it. If they don't have it, they can't
387  * pass through this space.
388  */
389  if (tmp->last_sp) {
390  if (check_inv_recursive(ob, tmp) == NULL) {
391  if (tmp->msg) {
392  /* Optionally display the reason why one cannot move
393  * there. Note: emitting a message from this function
394  * is not very elegant. Ideally, this should be done
395  * somewhere in server/player.c, but this is difficult
396  * for objects of type CHECK_INV that are not alive.
397  */
400  tmp->msg);
401  }
402  return 1;
403  }
404  } else {
405  /* In this case, the player must not have the object -
406  * if they do, they can't pass through.
407  */
408  if (check_inv_recursive(ob, tmp) != NULL) {
409  if (tmp->msg) {
412  tmp->msg);
413  }
414  return 1;
415  }
416  }
417  } /* if check_inv */
418  else {
419  /* Broke apart a big nasty if into several here to make
420  * this more readable. first check - if the space blocks
421  * movement, can't move here.
422  * second - if a monster, can't move there, unless it is a
423  * hidden dm
424  */
425  if (OB_MOVE_BLOCK(ob, tmp))
426  return 1;
427  if (QUERY_FLAG(tmp, FLAG_ALIVE)
428  && tmp->head != ob
429  && tmp != ob
430  && tmp->type != DOOR
431  && !(QUERY_FLAG(tmp, FLAG_WIZ) && tmp->contr->hidden))
432  return 1;
433  }
434  } FOR_MAP_FINISH();
435  return 0;
436 }
437 
469 int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y) {
470  archetype *tmp;
471  int flag;
472  mapstruct *m1;
473  int16_t sx, sy;
474  const object *part;
475 
476  if (ob == NULL) {
477  flag = get_map_flags(m, &m1, x, y, &sx, &sy);
478  if (flag&P_OUT_OF_MAP)
479  return P_OUT_OF_MAP;
480 
481  /* don't have object, so don't know what types would block */
482  return(GET_MAP_MOVE_BLOCK(m1, sx, sy));
483  }
484 
485  for (tmp = ob->arch, part = ob; tmp != NULL; tmp = tmp->more, part = part->more) {
486  flag = get_map_flags(m, &m1, x+tmp->clone.x, y+tmp->clone.y, &sx, &sy);
487 
488  if (flag&P_OUT_OF_MAP)
489  return P_OUT_OF_MAP;
490  if (flag&P_IS_ALIVE)
491  return P_IS_ALIVE;
492 
493  /* object_find_first_free_spot() calls this function. However, often
494  * ob doesn't have any move type (when used to place exits)
495  * so the AND operation in OB_TYPE_MOVE_BLOCK doesn't work.
496  */
497 
498  if (ob->move_type == 0 && GET_MAP_MOVE_BLOCK(m1, sx, sy) != MOVE_ALL)
499  continue;
500 
501  /* A transport without move_type for a part should go through everything for that part. */
502  if (ob->type == TRANSPORT && part->move_type == 0)
503  continue;
504 
505  /* Note it is intentional that we check ob - the movement type of the
506  * head of the object should correspond for the entire object.
507  */
508  if (OB_TYPE_MOVE_BLOCK(ob, GET_MAP_MOVE_BLOCK(m1, sx, sy)))
509  return AB_NO_PASS;
510  }
511  return 0;
512 }
513 
524 static void fix_container_multipart(object *container) {
525  FOR_INV_PREPARE(container, tmp) {
526  archetype *at;
527  object *op, *last;
528 
529  if (tmp->inv)
531  /* already multipart, or non-multipart arch - don't do anything more */
532  for (at = tmp->arch->more, last = tmp; at != NULL; at = at->more, last = op) {
533  /* FIXME: We can't reuse object_fix_multipart() since that only
534  * works for items directly on maps. Maybe factor out common code?
535  */
536  op = arch_to_object(at);
537  op->head = tmp;
538  op->env = tmp->env;
539  last->more = op;
540  if (tmp->name != op->name) {
541  if (op->name)
542  free_string(op->name);
543  op->name = add_string(tmp->name);
544  }
545  if (tmp->title != op->title) {
546  if (op->title)
547  free_string(op->title);
548  op->title = add_string(tmp->title);
549  }
551  }
552  } FOR_INV_FINISH();
553 }
554 
566  int x, y;
567 
568  for (x = 0; x < MAP_WIDTH(m); x++)
569  for (y = 0; y < MAP_HEIGHT(m); y++)
570  FOR_MAP_PREPARE(m, x, y, tmp) {
571  if (tmp->inv)
573 
574  /* already multipart - don't do anything more */
575  if (tmp->head || tmp->more)
576  continue;
577 
579  } FOR_MAP_FINISH(); /* for objects on this space */
580 }
581 
593 void load_objects(mapstruct *m, FILE *fp, int mapflags) {
594  int i, j, bufstate = LO_NEWFILE;
595  int unique;
596  object *op, *prev = NULL, *last_more = NULL;
597 
598  op = object_new();
599  op->map = m; /* To handle buttons correctly */
600 
601  PROFILE_BEGIN();
602  while ((i = load_object(fp, op, bufstate, mapflags, false))) {
603  /* Since the loading of the map header does not load an object
604  * anymore, we need to pass LO_NEWFILE for the first object loaded,
605  * and then switch to LO_REPEAT for faster loading.
606  */
607  bufstate = LO_REPEAT;
608 
609  /* if the archetype for the object is null, means that we
610  * got an invalid object. Don't do anything with it - the game
611  * or editor will not be able to do anything with it either.
612  */
613  if (op->arch == NULL) {
614  LOG(llevDebug, "Discarding object without arch: %s\n", op->name ? op->name : "(null)");
615  continue;
616  }
617 
618  /*
619  * You can NOT have players on a map being loaded.
620  * Trying to use such a type leads to crashes everywhere as op->contr is NULL.
621  */
622  if (op->type == PLAYER) {
623  LOG(llevError, "Discarding invalid item with type PLAYER in map %s\n", m->path);
624  continue;
625  }
626 
627  /* don't use out_of_map because we don't want to consider tiling properties, we're loading a single map */
628  if (OUT_OF_REAL_MAP(m, op->x, op->y)) {
629  LOG(llevError, " object %s not on valid map position %s:%d:%d\n", op->name ? op->name : "(null)", m->path, op->x, op->y);
630  if (op->x < 0) {
631  op->x = 0;
632  } else if (op->x >= MAP_WIDTH(m)) {
633  op->x = MAP_WIDTH(m) - 1;
634  }
635  if (op->y < 0) {
636  op->y = 0;
637  } else if (op->y >= MAP_HEIGHT(m)) {
638  op->y = MAP_HEIGHT(m) - 1;
639  }
640  }
641 
642  switch (i) {
643  case LL_NORMAL:
644  /* if we are loading an overlay, put the floors on the bottom */
646  && mapflags&MAP_OVERLAY)
648  else
650 
651  if (op->inv)
652  object_sum_weight(op);
653 
654  prev = op,
655  last_more = op;
656  break;
657 
658  case LL_MORE:
659  if (last_more == NULL) {
660  LOG(llevError, "Error loading map %s from file: multi-part object requires an object before 'more' parts can follow\n",
661  m->path);
662  continue;
663  }
665  op->head = prev,
666  last_more->more = op,
667  last_more = op;
668  break;
669  }
670  if (mapflags&MAP_STYLE) {
672  }
673  op = object_new();
674  op->map = m;
675  }
676  PROFILE_END(diff, LOG(llevDebug,
677  "load_objects on %s took %ld us\n", m->path, diff));
678  for (i = 0; i < m->width; i++) {
679  for (j = 0; j < m->height; j++) {
680  unique = 0;
681  /* check for unique items, or unique squares */
682  FOR_MAP_PREPARE(m, i, j, otmp) {
683  if (QUERY_FLAG(otmp, FLAG_UNIQUE))
684  unique = 1;
685  if (!(mapflags&(MAP_OVERLAY|MAP_PLAYER_UNIQUE) || unique))
687  } FOR_MAP_FINISH();
688  }
689  }
692 }
693 
710 int save_objects(mapstruct *m, FILE *fp, FILE *fp2, int flag) {
711  unsigned int count = 0;
712  long serialize_time;
713  PROFILE_BEGIN();
714  for (int i = 0; i < MAP_WIDTH(m); i++) {
715  for (int j = 0; j < MAP_HEIGHT(m); j++) {
716  int unique = 0; //< 1 if this tile should be saved
717  FOR_MAP_PREPARE(m, i, j, op) {
719  unique = 1;
720 
721  if (op->type == PLAYER) {
722  LOG(llevDebug, "Player on map that is being saved\n");
723  continue;
724  }
725 
726  if (op->head || object_get_owner(op) != NULL)
727  continue;
728 
729  FILE *dst = NULL; // fp, fp2, or NULL depending on if object is unique
730  if (unique || QUERY_FLAG(op, FLAG_UNIQUE)) {
731  dst = fp2;
732  } else if (flag == 0 || (flag == SAVE_FLAG_NO_REMOVE && (!QUERY_FLAG(op, FLAG_OBJ_ORIGINAL) && !QUERY_FLAG(op, FLAG_UNPAID)))) {
733  dst = fp;
734  } else {
735  // Don't save
736  continue;
737  }
738 
741  count++;
742  char *cp = stringbuffer_finish(sb);
743  fputs(cp, dst);
744  free(cp);
745  } FOR_MAP_FINISH(); /* for this space */
746  } /* for this j */
747  }
748  PROFILE_END(diff, serialize_time = diff);
749 
750  LOG(llevDebug, "saved %d objects on %s (%ld us)\n", count, m->path, serialize_time);
751  return 0;
752 }
753 
764  mapstruct *map = static_cast<mapstruct *>(calloc(1, sizeof(mapstruct)));
765  /* mapstruct *mp;*/
766 
767  if (map == NULL)
769 
770  map->next = first_map;
771  first_map = map;
772 
773  map->in_memory = MAP_SWAPPED;
774 
775  MAP_WIDTH(map) = 16;
776  MAP_HEIGHT(map) = 16;
777  MAP_RESET_TIMEOUT(map) = 0;
778  MAP_ENTER_X(map) = 0;
779  MAP_ENTER_Y(map) = 0;
780  /*set part to -1 indicating conversion to weather map not yet done*/
781  MAP_WORLDPARTX(map)=-1;
782  MAP_WORLDPARTY(map)=-1;
783  map->last_reset_time = 0;
784  return map;
785 }
786 
788 uint32_t map_size(mapstruct *m) {
789  return (uint32_t)m->width * (uint32_t)m->height;
790 }
791 
803  m->in_memory = MAP_IN_MEMORY;
804  /* Log this condition and free the storage. We could I suppose
805  * realloc, but if the caller is presuming the data will be intact,
806  * that is their poor assumption.
807  */
808  if (m->spaces) {
809  LOG(llevError, "allocate_map called with already allocated map (%s)\n", m->path);
810  free(m->spaces);
811  }
812 
813  m->spaces = static_cast<MapSpace *>(calloc(map_size(m), sizeof(MapSpace)));
814 
815  if (m->spaces == NULL)
817 }
818 
832 mapstruct *get_empty_map(int sizex, int sizey) {
834  m->width = sizex;
835  m->height = sizey;
836  m->in_memory = MAP_SWAPPED;
837  allocate_map(m);
838  return m;
839 }
840 
854 static shopitems *parse_shop_string(const char *input_string, const mapstruct *map) {
855  char *shop_string, *p, *q, *next_semicolon, *next_colon;
856  shopitems *items = NULL;
857  int i = 0, number_of_entries = 0;
858  const typedata *current_type;
859 
860  shop_string = strdup_local(input_string);
861  p = shop_string;
862  /* first we'll count the entries, we'll need that for allocating the array shortly */
863  while (p) {
864  p = strchr(p, ';');
865  number_of_entries++;
866  if (p)
867  p++;
868  }
869  p = shop_string;
870  strip_endline(p);
871  items = static_cast<shopitems *>(CALLOC(number_of_entries+1, sizeof(shopitems)));
872  /*
873  * The memset would always set at least one byte to zero,
874  * so a failed calloc would have segfaulted the program.
875  * Instead, check for a null and fail more gracefully.
876  */
877  if (!items)
879 
880  for (i = 0; i < number_of_entries; i++) {
881  if (!p) {
882  LOG(llevError, "parse_shop_string: I seem to have run out of string, that shouldn't happen.\n");
883  break;
884  }
885  next_semicolon = strchr(p, ';');
886  next_colon = strchr(p, ':');
887  /* if there is a stregth specified, figure out what it is, we'll need it soon. */
888  if (next_colon && (!next_semicolon || next_colon < next_semicolon))
889  items[i].strength = atoi(strchr(p, ':')+1);
890 
891  if (isdigit(*p) || *p == '*') {
892  items[i].typenum = *p == '*' ? -1 : atoi(p);
893  current_type = get_typedata(items[i].typenum);
894  if (current_type) {
895  items[i].name = current_type->name;
896  items[i].name_pl = current_type->name_pl;
897  }
898  } else { /*we have a named type, let's figure out what it is */
899  q = strpbrk(p, ";:");
900  if (q)
901  *q = '\0';
902 
903  current_type = get_typedata_by_name(p);
904  if (current_type) {
905  items[i].name = current_type->name;
906  items[i].typenum = current_type->number;
907  items[i].name_pl = current_type->name_pl;
908  } else {
909  /* oh uh, something's wrong, let's free up this one, and try
910  * the next entry while we're at it, better print a warning */
911  LOG(llevError, "invalid type %s defined in shopitems for %s in string %s\n", p, map->name, input_string);
912  }
913  }
914  items[i].index = number_of_entries;
915  if (next_semicolon)
916  p = ++next_semicolon;
917  else
918  p = NULL;
919  }
920  free(shop_string);
921  return items;
922 }
923 
935 static void print_shop_string(mapstruct *m, char *output_string, int size) {
936  int i;
937  char tmp[MAX_BUF];
938 
939  output_string[0] = '\0';
940  for (i = 0; i < m->shopitems[0].index; i++) {
941  if (m->shopitems[i].typenum != -1) {
942  if (m->shopitems[i].strength) {
943  snprintf(tmp, sizeof(tmp), "%s:%d;", m->shopitems[i].name, m->shopitems[i].strength);
944  } else
945  snprintf(tmp, sizeof(tmp), "%s;", m->shopitems[i].name);
946  } else {
947  if (m->shopitems[i].strength) {
948  snprintf(tmp, sizeof(tmp), "*:%d;", m->shopitems[i].strength);
949  } else
950  snprintf(tmp, sizeof(tmp), "*;");
951  }
952  snprintf(output_string+strlen(output_string), size-strlen(output_string), "%s", tmp);
953  }
954 
955  /* erase final ; else parsing back will lead to issues */
956  if (strlen(output_string) > 0) {
957  output_string[strlen(output_string) - 1] = '\0';
958  }
959 }
960 
977 static int load_map_header(FILE *fp, mapstruct *m) {
978  char buf[HUGE_BUF], *key = NULL, *value;
979 
980  m->width = m->height = 0;
981  while (fgets(buf, sizeof(buf), fp) != NULL) {
982  char *p;
983 
984  p = strchr(buf, '\n');
985  if (p == NULL) {
986  LOG(llevError, "Error loading map header - did not find a newline - perhaps file is truncated? Buf=%s\n", buf);
987  return 1;
988  }
989  *p = '\0';
990 
991  key = buf;
992  while (isspace(*key))
993  key++;
994  if (*key == 0)
995  continue; /* empty line */
996  value = strchr(key, ' ');
997  if (value) {
998  *value = 0;
999  value++;
1000  while (isspace(*value)) {
1001  value++;
1002  if (*value == '\0') {
1003  /* Nothing but spaces. */
1004  value = NULL;
1005  break;
1006  }
1007  }
1008  }
1009 
1010  /* key is the field name, value is what it should be set
1011  * to. We've already done the work to null terminate key,
1012  * and strip off any leading spaces for both of these.
1013  * We have not touched the newline at the end of the line -
1014  * these are needed for some values. the end pointer
1015  * points to the first of the newlines.
1016  * value could be NULL! It would be easy enough to just point
1017  * this to "" to prevent cores, but that would let more errors slide
1018  * through.
1019  *
1020  * First check for entries that do not use the value parameter, then
1021  * validate that value is given and check for the remaining entries
1022  * that use the parameter.
1023  */
1024 
1025  if (!strcmp(key, "msg")) {
1026  char msgbuf[HUGE_BUF];
1027  int msgpos = 0;
1028 
1029  while (fgets(buf, sizeof(buf), fp) != NULL) {
1030  if (!strcmp(buf, "endmsg\n"))
1031  break;
1032  else {
1033  snprintf(msgbuf+msgpos, sizeof(msgbuf)-msgpos, "%s", buf);
1034  msgpos += strlen(buf);
1035  }
1036  }
1037  /* There are lots of maps that have empty messages (eg, msg/endmsg
1038  * with nothing between). There is no reason in those cases to
1039  * keep the empty message. Also, msgbuf contains garbage data
1040  * when msgpos is zero, so copying it results in crashes
1041  */
1042  if (msgpos != 0) {
1043  /* When loading eg an overlay, message is already set, so free() current one. */
1044  free(m->msg);
1045  m->msg = strdup_local(msgbuf);
1046  }
1047  } else if (!strcmp(key, "maplore")) {
1048  char maplorebuf[HUGE_BUF];
1049  size_t maplorepos = 0;
1050 
1051  while (fgets(buf, HUGE_BUF-1, fp) != NULL) {
1052  if (!strcmp(buf, "endmaplore\n"))
1053  break;
1054  else {
1055  if (maplorepos >= sizeof(maplorebuf)) {
1056  LOG(llevError, "Map lore exceeds buffer length\n");
1057  return 1;
1058  }
1059  snprintf(maplorebuf+maplorepos, sizeof(maplorebuf)-maplorepos, "%s", buf);
1060  maplorepos += strlen(buf);
1061  }
1062  }
1063  if (maplorepos != 0)
1064  m->maplore = strdup_local(maplorebuf);
1065  } else if (!strcmp(key, "end")) {
1066  break;
1067  } else if (value == NULL) {
1068  LOG(llevError, "Got '%s' line without parameter in map header\n", key);
1069  } else if (!strcmp(key, "arch")) {
1070  /* This is an oddity, but not something we care about much. */
1071  if (strcmp(value, "map")) {
1072  LOG(llevError, "load_map_header: expected 'arch map': check line endings?\n");
1073  return 1;
1074  }
1075  } else if (!strcmp(key, "name")) {
1076  /* When loading eg an overlay, the name is already set, so free() current one. */
1077  free(m->name);
1078  m->name = strdup_local(value);
1079  /* first strcmp value on these are old names supported
1080  * for compatibility reasons. The new values (second) are
1081  * what really should be used.
1082  */
1083  } else if (!strcmp(key, "enter_x")) {
1084  m->enter_x = atoi(value);
1085  } else if (!strcmp(key, "enter_y")) {
1086  m->enter_y = atoi(value);
1087  } else if (!strcmp(key, "width")) {
1088  m->width = atoi(value);
1089  } else if (!strcmp(key, "height")) {
1090  m->height = atoi(value);
1091  } else if (!strcmp(key, "reset_timeout")) {
1092  m->reset_timeout = atoi(value);
1093  } else if (!strcmp(key, "swap_time")) {
1094  // deprecated and ignored
1095  } else if (!strcmp(key, "difficulty")) {
1096  m->difficulty = atoi(value);
1097  } else if (!strcmp(key, "darkness")) {
1098  m->darkness = atoi(value);
1099  } else if (!strcmp(key, "fixed_resettime")) {
1100  m->fixed_resettime = atoi(value);
1101  } else if (!strcmp(key, "unique")) {
1102  m->unique = atoi(value);
1103  } else if (!strcmp(key, "template")) {
1104  LOG(llevWarn, "template maps are no longer supported");
1105  } else if (!strcmp(key, "region")) {
1106  m->region = get_region_by_name(value);
1107  } else if (!strcmp(key, "shopitems")) {
1108  m->shopitems = parse_shop_string(value, m);
1109  } else if (!strcmp(key, "shopgreed")) {
1110  m->shopgreed = atof(value);
1111  } else if (!strcmp(key, "shopmin")) {
1112  m->shopmin = atol(value);
1113  } else if (!strcmp(key, "shopmax")) {
1114  m->shopmax = atol(value);
1115  } else if (!strcmp(key, "shoprace")) {
1116  m->shoprace = strdup_local(value);
1117  } else if (!strcmp(key, "outdoor")) {
1118  m->outdoor = atoi(value);
1119  } else if (!strcmp(key, "nosmooth")) {
1120  m->nosmooth = atoi(value);
1121  } else if (!strcmp(key, "first_load")) {
1122  m->last_reset_time = atoi(value);
1123  } else if (!strncmp(key, "tile_path_", 10)) {
1124  int tile = atoi(key+10);
1125 
1126  if (tile < 1 || tile > 4) {
1127  LOG(llevError, "load_map_header: tile location %d out of bounds (%s)\n", tile, m->path);
1128  } else {
1129  if (m->tile_path[tile-1]) {
1130  LOG(llevError, "load_map_header: tile location %d duplicated (%s)\n", tile, m->path);
1131  free(m->tile_path[tile-1]);
1132  }
1133  m->tile_path[tile-1] = strdup_local(value);
1134  } /* end if tile direction (in)valid */
1135  } else if (!strcmp(key, "background_music")) {
1136  m->background_music = strdup_local(value);
1137  } else if (!strcmp(key, "reset_group")) {
1138  m->reset_group = add_string(value);
1139  } else {
1140  LOG(llevError, "Got unknown value in map header: %s %s\n", key, value);
1141  }
1142  }
1143  if ((m->width == 0) || (m->height == 0)) {
1144  LOG(llevError, "Map width or height not specified\n");
1145  return 1;
1146  }
1147  if (!key || strcmp(key, "end")) {
1148  LOG(llevError, "Got premature eof on map header!\n");
1149  return 1;
1150  }
1151  return 0;
1152 }
1153 
1154 void map_path(const char *map, int flags, char *pathname, size_t bufsize) {
1155  if (flags&MAP_PLAYER_UNIQUE) {
1156  snprintf(pathname, bufsize, "%s/%s/%s", settings.localdir, settings.playerdir, map+1);
1157  }
1158  else if (flags&MAP_OVERLAY)
1159  create_overlay_pathname(map, pathname, bufsize);
1160  else
1161  create_pathname(map, pathname, bufsize);
1162 }
1163 
1164 mapstruct *mapfile_load_lowlevel(const char *map, const char *pathname, int flags) {
1165  FILE *fp;
1166  if ((fp = fopen(pathname, "r")) == NULL) {
1168  "Can't open %s: %s\n", pathname, strerror(errno));
1169  return NULL;
1170  }
1171 
1172  mapstruct *m = get_linked_map();
1173  safe_strncpy(m->path, map, HUGE_BUF);
1174  if (load_map_header(fp, m)) {
1175  LOG(llevError, "Error loading map header for %s, flags=%d\n", map, flags);
1176  delete_map(m);
1177  fclose(fp);
1178  return NULL;
1179  }
1180 
1181  allocate_map(m);
1182 
1183  m->in_memory = MAP_LOADING;
1184  load_objects(m, fp, flags & MAP_STYLE);
1185  fclose(fp);
1186  m->in_memory = MAP_IN_MEMORY;
1187  return m;
1188 }
1189 
1205 mapstruct *mapfile_load(const char *map, int flags) {
1206  mapstruct *m;
1207  PROFILE_BEGIN();
1208  char pathname[MAX_BUF];
1209  map_path(map, flags, pathname, sizeof(pathname));
1210  m = mapfile_load_lowlevel(map, pathname, flags);
1211  if (!m) {
1212  return NULL;
1213  }
1214  if (!MAP_DIFFICULTY(m) && (!(flags & MAP_NO_DIFFICULTY)))
1217 
1218  /* In case other objects press some buttons down */
1219  update_buttons(m);
1220 
1222 
1223  if (!(flags & MAP_STYLE))
1224  apply_auto_fix(m); /* Chests which open as default */
1225 
1226  PROFILE_END(diff,
1227  LOG(llevDebug, "mapfile_load on %s" " took %ld us\n", map, diff));
1228 
1230  return (m);
1231 }
1232 
1242  FILE *fp;
1243 
1244  if (!m->tmpname) {
1245  LOG(llevError, "No temporary filename for map %s\n", m->path);
1246  return 1;
1247  }
1248 
1249  if ((fp = fopen(m->tmpname, "r")) == NULL) {
1250  LOG(llevError, "Cannot open %s: %s\n", m->tmpname, strerror(errno));
1251  return 2;
1252  }
1253 
1254  if (load_map_header(fp, m)) {
1255  LOG(llevError, "Error loading map header for %s (%s)\n", m->path, m->tmpname);
1256  fclose(fp);
1257  return 3;
1258  }
1259  allocate_map(m);
1260 
1261  m->in_memory = MAP_LOADING;
1262  load_objects(m, fp, 0);
1263  fclose(fp);
1264  m->in_memory = MAP_IN_MEMORY;
1265  return 0;
1266 }
1267 
1277 int load_overlay_map(const char *filename, mapstruct *m) {
1278  FILE *fp;
1279  char pathname[MAX_BUF];
1280 
1281  create_overlay_pathname(filename, pathname, MAX_BUF);
1282 
1283  if ((fp = fopen(pathname, "r")) == NULL) {
1284  /* nothing bad to not having an overlay */
1285  return 0;
1286  }
1287 
1288  if (load_map_header(fp, m)) {
1289  LOG(llevError, "Error loading map header for overlay %s (%s)\n", m->path, pathname);
1290  fclose(fp);
1291  return 1;
1292  }
1293  /*allocate_map(m);*/
1294 
1295  m->in_memory = MAP_LOADING;
1296  load_objects(m, fp, MAP_OVERLAY);
1297  fclose(fp);
1298  m->in_memory = MAP_IN_MEMORY;
1299  return 0;
1300 }
1301 
1302 /******************************************************************************
1303  * This is the start of unique map handling code
1304  *****************************************************************************/
1305 
1313  int i, j, unique = 0;
1314 
1315  for (i = 0; i < MAP_WIDTH(m); i++)
1316  for (j = 0; j < MAP_HEIGHT(m); j++) {
1317  unique = 0;
1318  FOR_MAP_PREPARE(m, i, j, op) {
1320  unique = 1;
1321  if (op->head == NULL && (QUERY_FLAG(op, FLAG_UNIQUE) || unique)) {
1322  clean_object(op);
1323  if (QUERY_FLAG(op, FLAG_IS_LINKED))
1324  remove_button_link(op);
1325  object_remove(op);
1327  }
1328  } FOR_MAP_FINISH();
1329  }
1330 }
1331 
1338  FILE *fp;
1339  int count;
1340  char name[MAX_BUF], firstname[sizeof(name) + 4];
1341 
1342  create_items_path(m->path, name, MAX_BUF);
1343  for (count = 0; count < 10; count++) {
1344  snprintf(firstname, sizeof(firstname), "%s.v%02d", name, count);
1345  if (!access(firstname, R_OK))
1346  break;
1347  }
1348  /* If we get here, we did not find any map */
1349  if (count == 10)
1350  return;
1351 
1352  if ((fp = fopen(firstname, "r")) == NULL) {
1353  /* There is no expectation that every map will have unique items, but this
1354  * is debug output, so leave it in.
1355  */
1356  LOG(llevDebug, "Can't open unique items file for %s\n", name);
1357  return;
1358  }
1359 
1360  m->in_memory = MAP_LOADING;
1361  if (m->tmpname == NULL) /* if we have loaded unique items from */
1362  delete_unique_items(m); /* original map before, don't duplicate them */
1363  load_object(fp, NULL, LO_NOREAD, 0, false);
1364  load_objects(m, fp, 0);
1365  fclose(fp);
1366  m->in_memory = MAP_IN_MEMORY;
1367 }
1368 
1376 int save_map_to_stream(mapstruct *m, int flag, FILE *fp, FILE *fp2) {
1377  m->in_memory = MAP_SAVING;
1378 
1379  // map header
1380  fprintf(fp, "arch map\n");
1381  if (m->name)
1382  fprintf(fp, "name %s\n", m->name);
1383  if (m->reset_timeout)
1384  fprintf(fp, "reset_timeout %u\n", m->reset_timeout);
1385  if (m->fixed_resettime)
1386  fprintf(fp, "fixed_resettime %d\n", m->fixed_resettime);
1387  /* we unfortunately have no idea if this is a value the creator set
1388  * or a difficulty value we generated when the map was first loaded
1389  */
1390  if (m->difficulty)
1391  fprintf(fp, "difficulty %d\n", m->difficulty);
1392  if (m->region)
1393  fprintf(fp, "region %s\n", m->region->name);
1394  if (m->shopitems) {
1395  char shop[MAX_BUF];
1396  print_shop_string(m, shop, sizeof(shop));
1397  fprintf(fp, "shopitems %s\n", shop);
1398  }
1399  if (m->shopgreed)
1400  fprintf(fp, "shopgreed %f\n", m->shopgreed);
1401  if (m->shopmin)
1402  fprintf(fp, "shopmin %" FMT64U "\n", m->shopmin);
1403  if (m->shopmax)
1404  fprintf(fp, "shopmax %" FMT64U "\n", m->shopmax);
1405  if (m->shoprace)
1406  fprintf(fp, "shoprace %s\n", m->shoprace);
1407  if (m->darkness)
1408  fprintf(fp, "darkness %d\n", m->darkness);
1409  if (m->width)
1410  fprintf(fp, "width %d\n", m->width);
1411  if (m->height)
1412  fprintf(fp, "height %d\n", m->height);
1413  if (m->enter_x)
1414  fprintf(fp, "enter_x %d\n", m->enter_x);
1415  if (m->enter_y)
1416  fprintf(fp, "enter_y %d\n", m->enter_y);
1417  if (m->msg)
1418  fprintf(fp, "msg\n%sendmsg\n", m->msg);
1419  if (m->maplore)
1420  fprintf(fp, "maplore\n%sendmaplore\n", m->maplore);
1421  if (m->unique)
1422  fprintf(fp, "unique %d\n", m->unique);
1423  if (m->outdoor)
1424  fprintf(fp, "outdoor %d\n", m->outdoor);
1425 
1426  /* Save any tiling information, except on overlays */
1427  if (flag != SAVE_MODE_OVERLAY)
1428  for (int i = 0; i < 4; i++)
1429  if (m->tile_path[i])
1430  fprintf(fp, "tile_path_%d %s\n", i+1, m->tile_path[i]);
1431 
1432  if (m->nosmooth)
1433  fprintf(fp, "nosmooth %d\n", m->nosmooth);
1434  if (m->background_music)
1435  fprintf(fp, "background_music %s\n", m->background_music);
1436  if (m->last_reset_time)
1437  fprintf(fp, "first_load %ld\n", m->last_reset_time);
1438  if (m->reset_group)
1439  fprintf(fp, "reset_group %s\n", m->reset_group);
1440 
1441  fprintf(fp, "end\n");
1442 
1443  int res;
1444  if (flag == SAVE_MODE_OVERLAY) {
1445  /* SO_FLAG_NO_REMOVE is non destructive save, so map is still valid. */
1446  res = save_objects(m, fp, fp2, SAVE_FLAG_NO_REMOVE);
1447  m->in_memory = MAP_IN_MEMORY;
1448  } else {
1449  res = save_objects(m, fp, fp2, 0);
1451  }
1452  return res;
1453 }
1454 
1470 int save_map(mapstruct *m, int flag) {
1471  FILE *fp;
1472  OutputFile of;
1473  char filename[MAX_BUF];
1474 
1475  if (flag && !*m->path) {
1476  LOG(llevError, "Tried to save map without path.\n");
1477  return SAVE_ERROR_NO_PATH;
1478  }
1479 
1480  PROFILE_BEGIN();
1481 
1482  if (flag != SAVE_MODE_NORMAL || (m->unique)) {
1483  if (!m->unique) { /* flag is set */
1484  if (flag == SAVE_MODE_OVERLAY)
1485  create_overlay_pathname(m->path, filename, MAX_BUF);
1486  else
1487  create_pathname(m->path, filename, MAX_BUF);
1488  } else {
1489  if (m->path[0] != '~') {
1490  LOG(llevError,
1491  "Cannot save unique map '%s' outside of LOCALDIR. Check "
1492  "that all exits to '%s' have FLAG_UNIQUE set correctly.\n",
1493  m->path, m->path);
1494  return SAVE_ERROR_UCREATION;
1495  }
1496  snprintf(filename, sizeof(filename), "%s/%s/%s", settings.localdir, settings.playerdir, m->path+1);
1497  }
1498 
1499  make_path_to_file(filename);
1500  } else {
1501  if (!m->tmpname)
1502  m->tmpname = tempnam(settings.tmpdir, NULL);
1503  strlcpy(filename, m->tmpname, sizeof(filename));
1504  }
1505 
1506  fp = of_open(&of, filename);
1507  if (fp == NULL)
1508  return SAVE_ERROR_RCREATION;
1509 
1510  /* In the game save unique items in the different file, but
1511  * in the editor save them to the normal map file.
1512  * If unique map, save files in the proper destination (set by
1513  * player)
1514  */
1515  int res;
1516  if ((flag == SAVE_MODE_NORMAL || flag == SAVE_MODE_OVERLAY) && !m->unique) {
1517  FILE *fp2;
1518  OutputFile of2;
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 
1529  res = save_map_to_stream(m, flag, fp, fp2);
1530  if (res < 0) {
1531  LOG(llevError, "Save error during object save: %d\n", res);
1532  of_cancel(&of);
1533  of_cancel(&of2);
1534  return res;
1535  }
1536 
1537  if (ftell(fp2) == 0) {
1538  of_cancel(&of2);
1539  /* If there are no unique items left on the map, we need to
1540  * unlink the original unique map so that the unique
1541  * items don't show up again.
1542  */
1543  unlink(final_unique);
1544  } else {
1545  if (!of_close(&of2)) {
1546  of_cancel(&of);
1547  return SAVE_ERROR_URENAME;
1548  }
1549 
1550  if (chmod(final_unique, SAVE_MODE) != 0) {
1551  LOG(llevError, "Could not set permissions on '%s'\n", final_unique);
1552  }
1553  }
1554  } else {
1555  res = save_map_to_stream(m, flag, fp, fp);
1556  }
1557 
1558  if (res < 0) {
1559  LOG(llevError, "Save error during object save: %d\n", res);
1560  of_cancel(&of);
1561  return res;
1562  }
1563 
1564  if (!of_close(&of))
1565  return SAVE_ERROR_CLOSE;
1566 
1567  if (chmod(filename, SAVE_MODE) != 0) {
1568  LOG(llevError, "Could not set permissions on '%s'\n", filename);
1569  }
1570 
1571  PROFILE_END(diff,
1572  LOG(llevDebug, "save_map on %s" " took %ld us\n", m->path, diff));
1573 
1574  maps_saved_total++;
1575  return SAVE_ERROR_OK;
1576 }
1577 
1587 void clean_object(object *op) {
1588  FOR_INV_PREPARE(op, tmp) {
1589  clean_object(tmp);
1590  if (QUERY_FLAG(tmp, FLAG_IS_LINKED))
1591  remove_button_link(tmp);
1592  object_remove(tmp);
1594  } FOR_INV_FINISH();
1595 }
1596 
1604  int i, j;
1605  object *op;
1606 
1607  for (i = 0; i < MAP_WIDTH(m); i++)
1608  for (j = 0; j < MAP_HEIGHT(m); j++) {
1609  object *previous_obj = NULL;
1610 
1611  while ((op = GET_MAP_OB(m, i, j)) != NULL) {
1612  if (op == previous_obj) {
1613  LOG(llevDebug, "free_all_objects: Link error, bailing out.\n");
1614  break;
1615  }
1616  previous_obj = op;
1617  op = HEAD(op);
1618 
1619  /* If the map isn't in memory, object_free_drop_inventory() will remove and
1620  * free objects in op's inventory. So let it do the job.
1621  */
1622  if (m->in_memory == MAP_IN_MEMORY)
1623  clean_object(op);
1624  object_remove(op);
1626  }
1627  }
1628 #ifdef MANY_CORES
1629  /* I see periodic cores on metalforge where a map has been swapped out, but apparantly
1630  * an item on that map was not saved - look for that condition and die as appropriate -
1631  * this leaves more of the map data intact for better debugging.
1632  */
1633  for (op = objects; op != NULL; op = op->next) {
1634  if (!QUERY_FLAG(op, FLAG_REMOVED) && op->map == m) {
1635  LOG(llevError, "free_all_objects: object %s still on map after it should have been freed\n", op->name);
1636  abort();
1637  }
1638  }
1639 #endif
1640 }
1641 
1651  int i;
1652 
1653  if (!m->in_memory) {
1654  LOG(llevError, "Trying to free freed map.\n");
1655  return;
1656  }
1657 
1659 
1660  if (m->spaces)
1662  if (m->name)
1663  FREE_AND_CLEAR(m->name);
1664  if (m->spaces)
1665  FREE_AND_CLEAR(m->spaces);
1666  if (m->msg)
1667  FREE_AND_CLEAR(m->msg);
1668  if (m->maplore)
1669  FREE_AND_CLEAR(m->maplore);
1670  if (m->shopitems)
1671  FREE_AND_CLEAR(m->shopitems);
1672  if (m->shoprace)
1673  FREE_AND_CLEAR(m->shoprace);
1674  if (m->background_music)
1675  FREE_AND_CLEAR(m->background_music);
1676  if (m->buttons)
1677  free_objectlinkpt(m->buttons);
1678  m->buttons = NULL;
1679  for (i = 0; i < 4; i++) {
1680  if (m->tile_path[i])
1681  FREE_AND_CLEAR(m->tile_path[i]);
1682  m->tile_map[i] = NULL;
1683  }
1684  m->in_memory = MAP_SWAPPED;
1685 }
1686 
1697  mapstruct *tmp, *last;
1698  int i;
1699 
1700  if (!m)
1701  return;
1702  if (m->in_memory == MAP_IN_MEMORY) {
1703  /* change to MAP_SAVING, even though we are not,
1704  * so that object_remove() doesn't do as much work.
1705  */
1706  m->in_memory = MAP_SAVING;
1707  free_map(m);
1708  }
1709  /* move this out of free_map, since tmpname can still be needed if
1710  * the map is swapped out.
1711  */
1712  free(m->tmpname);
1713  m->tmpname = NULL;
1714  FREE_AND_CLEAR_STR_IF(m->reset_group);
1715  last = NULL;
1716  /* We need to look through all the maps and see if any maps
1717  * are pointing at this one for tiling information. Since
1718  * tiling can be assymetric, we just can not look to see which
1719  * maps this map tiles with and clears those.
1720  */
1721  for (tmp = first_map; tmp != NULL; tmp = tmp->next) {
1722  if (tmp->next == m)
1723  last = tmp;
1724 
1725  /* This should hopefully get unrolled on a decent compiler */
1726  for (i = 0; i < 4; i++)
1727  if (tmp->tile_map[i] == m)
1728  tmp->tile_map[i] = NULL;
1729  }
1730 
1731  /* If last is null, then this should be the first map in the list */
1732  if (!last) {
1733  if (m == first_map)
1734  first_map = m->next;
1735  else
1736  /* m->path is a static char, so should hopefully still have
1737  * some useful data in it.
1738  */
1739  LOG(llevError, "delete_map: Unable to find map %s in list\n", m->path);
1740  } else
1741  last->next = m->next;
1742 
1743  free(m);
1744 }
1745 
1751  // Right now this just sets the fixed swap time.
1752  m->timeout = MAP_MINTIMEOUT;
1753 }
1754 
1768 mapstruct *ready_map_name(const char *name, int flags) {
1769  mapstruct *m;
1770 
1771  if (!name)
1772  return (NULL);
1773 
1774  /* Have we been at this level before? */
1775  m = has_been_loaded(name);
1776 
1777  /* Map is good to go, so just return it */
1778  if (m && (m->in_memory == MAP_LOADING || m->in_memory == MAP_IN_MEMORY)) {
1779  map_reset_swap(m);
1780 
1781  return m;
1782  }
1783 
1784  /* Rewrite old paths starting with LOCALDIR/PLAYERDIR to new '~' paths. */
1785  char buf[MAX_BUF], buf2[MAX_BUF];
1786  snprintf(buf, sizeof(buf), "%s/%s", settings.localdir, settings.playerdir);
1787  if (strncmp(name, buf, strlen(buf)) == 0) {
1788  snprintf(buf2, sizeof(buf2), "~%s", name+strlen(buf)+1);
1789  name = buf2;
1790  }
1791 
1792  /* Paths starting with '~' are unique. */
1793  if (name[0] == '~') {
1795  }
1796 
1797  /* unique maps always get loaded from their original location, and never
1798  * a temp location. Likewise, if map_flush is set, or we have never loaded
1799  * this map, load it now. I removed the reset checking from here -
1800  * it seems the probability of a player trying to enter a map that should
1801  * reset but hasn't yet is quite low, and removing that makes this function
1802  * a bit cleaner (and players probably shouldn't rely on exact timing for
1803  * resets in any case - if they really care, they should use the 'maps command.
1804  */
1805  if ((flags&(MAP_FLUSH|MAP_PLAYER_UNIQUE)) || !m) {
1806  /* first visit or time to reset */
1807  if (m) {
1808  clean_tmp_map(m); /* Doesn't make much difference */
1809  delete_map(m);
1810  }
1811 
1813  if (m == NULL) return NULL;
1814 
1815  /* If a player unique map, no extra unique object file to load.
1816  * if from the editor, likewise.
1817  */
1820 
1822  if (load_overlay_map(name, m) != 0) {
1823  delete_map(m);
1824  m = mapfile_load(name, 0);
1825  if (m == NULL) {
1826  /* Really, this map is bad :( */
1827  return NULL;
1828  }
1829  }
1830  }
1831  } else {
1832  /* If in this loop, we found a temporary map, so load it up. */
1833 
1834  if (load_temporary_map(m) != 0) {
1835  /*
1836  * There was a failure loading the temporary map, fall back to original one.
1837  * load_temporary_map() already logged the error.
1838  */
1839  delete_map(m);
1840  m = mapfile_load(name, 0);
1841  if (m == NULL) {
1842  /* Really, this map is bad :( */
1843  return NULL;
1844  }
1845  }
1847 
1848  clean_tmp_map(m);
1849  m->in_memory = MAP_IN_MEMORY;
1850  /* tempnam() on sun systems (probably others) uses malloc
1851  * to allocated space for the string. Free it here.
1852  * In some cases, load_temporary_map above won't find the
1853  * temporary map, and so has reloaded a new map. If that
1854  * is the case, tmpname is now null
1855  */
1856  free(m->tmpname);
1857  m->tmpname = NULL;
1858  /* It's going to be saved anew anyway */
1859  }
1860 
1861  /* Below here is stuff common to both first time loaded maps and
1862  * temp maps.
1863  */
1864 
1865  decay_objects(m); /* start the decay */
1866 
1867  if (m->outdoor) {
1869  }
1870  if (!(flags&(MAP_FLUSH))) {
1871  if (m->last_reset_time == 0) {
1872  m->last_reset_time = seconds();
1873  }
1874  }
1875 
1876  /* Randomize monsters direction and animation state */
1877 
1878  if (!(flags & MAP_STYLE)) {
1879  for (int x = 0; x < MAP_WIDTH(m); x++)
1880  for (int y = 0; y < MAP_HEIGHT(m); y++)
1881  FOR_MAP_PREPARE(m, x, y, op) {
1882  if (!op->head && QUERY_FLAG(op, FLAG_MONSTER) && (op->direction == 0 || op->facing == 0)) {
1883  if (op->animation) {
1884  auto facings = NUM_FACINGS(op);
1885  op->facing = facings > 1 ? 1 + (cf_random() % facings) : 1;
1886  op->direction = op->facing;
1887  const int max_state = NUM_ANIMATIONS(op) / facings;
1888  op->state = max_state > 1 ? cf_random() % max_state : 0;
1889  animate_object(op, op->direction);
1890  }
1891  }
1892  } FOR_MAP_FINISH();
1893 
1894  }
1895 
1896  map_reset_swap(m);
1898 
1899  return m;
1900 }
1901 
1918  archetype *at;
1919  int x, y;
1920  int diff = 0;
1921  int i;
1922  int64_t exp_pr_sq, total_exp = 0;
1923 
1924  if (MAP_DIFFICULTY(m)) {
1925  return MAP_DIFFICULTY(m);
1926  }
1927 
1928  for (x = 0; x < MAP_WIDTH(m); x++)
1929  for (y = 0; y < MAP_HEIGHT(m); y++)
1930  FOR_MAP_PREPARE(m, x, y, op) {
1931  if (QUERY_FLAG(op, FLAG_MONSTER))
1932  total_exp += op->stats.exp;
1933  if (QUERY_FLAG(op, FLAG_GENERATOR)) {
1934  total_exp += op->stats.exp;
1935  // If we have an other_arch on our generator, just use that.
1936  // FIXME: Figure out what to do if we are doing template generation from inventory.
1937  at = op->other_arch ? op->other_arch : NULL;
1938  if (at != NULL) {
1939  // Make sure we can't set off a null pointer dereference in atoi().
1940  const char *val = object_get_value(op, "generator_limit");
1941  int lim = atoi(val ? val : "0");
1942  // We assume, on average, the generator will generate half its contents.
1943  if (!lim || lim >= 16)
1944  total_exp += at->clone.stats.exp*8;
1945  else
1946  total_exp += at->clone.stats.exp*(lim/2);
1947  }
1948  }
1949  } FOR_MAP_FINISH();
1950  // Used to be multiplied by 1000, but this undershot horribly
1951  // once I fixed the calculation for generators.
1952  // I'm trying out some exponentiation, since linear scaling
1953  // seems to overshoot low-level maps and undershoot high-level maps.
1954  // I also feel comfortable, knowing that generators return
1955  // sensible values, to up the max diff this calculates from 20 to 25.
1956  // - Neila Hawkins 2021-03-04
1957  exp_pr_sq = (pow(total_exp, 1.75))/(MAP_WIDTH(m)*MAP_HEIGHT(m)+1);
1958  diff = 25;
1959  for (i = 1; i < 25; i++)
1960  if (exp_pr_sq <= level_exp(i, 1.0)) {
1961  diff = i;
1962  break;
1963  }
1964 
1965  return diff;
1966 }
1967 
1975  if (m->tmpname == NULL)
1976  return;
1977  (void)unlink(m->tmpname);
1978 }
1979 
1983 void free_all_maps(void) {
1984  int real_maps = 0;
1985 
1986  while (first_map) {
1987  /* I think some of the callers above before it gets here set this to be
1988  * saving, but we still want to free this data
1989  */
1990  if (first_map->in_memory == MAP_SAVING)
1993  real_maps++;
1994  }
1995  LOG(llevDebug, "free_all_maps: Freed %d maps\n", real_maps);
1996 }
1997 
2015 int change_map_light(mapstruct *m, int change) {
2016  int new_level = m->darkness+change;
2017 
2018  /* Nothing to do */
2019  if (!change
2020  || (new_level <= 0 && m->darkness == 0)
2021  || (new_level >= MAX_DARKNESS && m->darkness >= MAX_DARKNESS)) {
2022  return 0;
2023  }
2024 
2025  /* inform all players on the map */
2026  if (change > 0)
2027  ext_info_map(NDI_BLACK, m, MSG_TYPE_MISC, MSG_SUBTYPE_NONE, "It becomes darker.");
2028  else
2029  ext_info_map(NDI_BLACK, m, MSG_TYPE_MISC, MSG_SUBTYPE_NONE, "It becomes brighter.");
2030 
2031  /* Do extra checking. since m->darkness is a unsigned value,
2032  * we need to be extra careful about negative values.
2033  * In general, the checks below are only needed if change
2034  * is not +/-1
2035  */
2036  if (new_level < 0)
2037  m->darkness = 0;
2038  else if (new_level >= MAX_DARKNESS)
2039  m->darkness = MAX_DARKNESS;
2040  else
2041  m->darkness = new_level;
2042 
2043  /* All clients need to get re-updated for the change */
2045  return 1;
2046 }
2047 
2070 static inline void add_face_layer(int low_layer, int high_layer, object *ob, object *layers[], int honor_visibility) {
2071  int l, l1;
2072  object *tmp;
2073 
2074  for (l = low_layer; l <= high_layer; l++) {
2075  if (!layers[l]) {
2076  /* found an empty spot. now, we want to make sure
2077  * highest visibility at top, etc.
2078  */
2079  layers[l] = ob;
2080  if (!honor_visibility)
2081  return;
2082 
2083  /* This is basically a mini bubble sort. Only swap
2084  * position if the lower face has greater (not equal)
2085  * visibility - map stacking is secondary consideration here.
2086  */
2087  for (l1 = (l-1); l1 >= low_layer; l1--) {
2088  if (layers[l1]->face->visibility > layers[l1+1]->face->visibility) {
2089  tmp = layers[l1+1];
2090  layers[l1+1] = layers[l1];
2091  layers[l1] = tmp;
2092  }
2093  }
2094  /* Nothing more to do - face inserted */
2095  return;
2096  }
2097  }
2098  /* If we get here, all the layers have an object..
2099  */
2100  if (!honor_visibility) {
2101  /* Basically, in this case, it is pure stacking logic, so
2102  * new object goes on the top.
2103  */
2104  for (l = low_layer; l < high_layer; l++)
2105  layers[l] = layers[l+1];
2106  layers[high_layer] = ob;
2107  /* If this object doesn't have higher visibility than
2108  * the lowest object, no reason to go further.
2109  */
2110  } else if (ob->face->visibility >= layers[low_layer]->face->visibility) {
2111  /*
2112  * Start at the top (highest visibility) layer and work down.
2113  * once this face exceed that of the layer, push down those
2114  * other layers, and then replace the layer with our object.
2115  */
2116  for (l = high_layer; l >= low_layer; l--) {
2117  if (ob->face->visibility >= layers[l]->face->visibility) {
2118  for (l1 = low_layer; l1 < l; l1++)
2119  layers[l1] = layers[l1+1];
2120  layers[l] = ob;
2121  break;
2122  }
2123  }
2124  }
2125 }
2126 
2139 void update_position(mapstruct *m, int x, int y) {
2140  object *player = NULL;
2141  uint8_t flags = 0, oldflags, light = 0;
2142  object *layers[MAP_LAYERS];
2143 
2144  MoveType move_block = 0, move_slow = 0, move_on = 0, move_off = 0, move_allow = 0;
2145 
2146  oldflags = GET_MAP_FLAGS(m, x, y);
2147  if (!(oldflags&P_NEED_UPDATE)) {
2148  LOG(llevDebug, "update_position called with P_NEED_UPDATE not set: %s (%d, %d)\n", m->path, x, y);
2149  return;
2150  }
2151 
2152  memset(layers, 0, MAP_LAYERS*sizeof(object *));
2153 
2154  FOR_MAP_PREPARE(m, x, y, tmp) {
2155  /* DMs just don't do anything when hidden, including no light. */
2156  if (QUERY_FLAG(tmp, FLAG_WIZ) && tmp->contr->hidden)
2157  continue;
2158 
2159  if (tmp->type == PLAYER)
2160  player = tmp;
2161 
2162  /* This could be made additive I guess (two lights better than
2163  * one). But if so, it shouldn't be a simple additive - 2
2164  * light bulbs do not illuminate twice as far as once since
2165  * it is a dissipation factor that is squared (or is it cubed?)
2166  */
2167  if (tmp->glow_radius > light)
2168  light = tmp->glow_radius;
2169 
2170  /* if this object is visible and not a blank face,
2171  * update the objects that show how this space
2172  * looks.
2173  */
2174  if (!tmp->invisible && tmp->face != blank_face) {
2175  if (tmp->map_layer) {
2176  add_face_layer(tmp->map_layer, map_layer_info[tmp->map_layer].high_layer,
2177  tmp, layers, map_layer_info[tmp->map_layer].honor_visibility);
2178  } else if (tmp->move_type&MOVE_FLYING) {
2179  add_face_layer(MAP_LAYER_FLY1, MAP_LAYER_FLY2, tmp, layers, 1);
2180  } else if ((tmp->type == PLAYER || QUERY_FLAG(tmp, FLAG_MONSTER) || QUERY_FLAG(tmp, FLAG_CAN_ROLL))) {
2181  // Put things that are likely to move on the LIVING layers
2183  } else if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
2184  layers[MAP_LAYER_FLOOR] = tmp;
2185  /* floors hide everything else */
2186  memset(layers+1, 0, (MAP_LAYERS-1)*sizeof(object *));
2187  /* Check for FLAG_SEE_ANYWHERE is removed - objects
2188  * with that flag should just have a high visibility
2189  * set - we shouldn't need special code here.
2190  */
2191  } else if (QUERY_FLAG(tmp, FLAG_NO_PICK)) {
2193  } else {
2195  }
2196  }
2197  if (tmp == tmp->above) {
2198  LOG(llevError, "Error in structure of map\n");
2199  exit(-1);
2200  }
2201 
2202  move_slow |= tmp->move_slow;
2203  move_block |= tmp->move_block;
2204  move_on |= tmp->move_on;
2205  move_off |= tmp->move_off;
2206  move_allow |= tmp->move_allow;
2207 
2208  if (QUERY_FLAG(tmp, FLAG_ALIVE))
2209  flags |= P_IS_ALIVE;
2210  if (QUERY_FLAG(tmp, FLAG_NO_MAGIC))
2211  flags |= P_NO_MAGIC;
2213  flags |= P_NO_CLERIC;
2214 
2215  if (QUERY_FLAG(tmp, FLAG_BLOCKSVIEW))
2216  flags |= P_BLOCKSVIEW;
2217  } FOR_MAP_FINISH(); /* for stack of objects */
2218 
2219  if (player)
2220  flags |= P_PLAYER;
2221 
2222  /* we don't want to rely on this function to have accurate flags, but
2223  * since we're already doing the work, we calculate them here.
2224  * if they don't match, logic is broken someplace.
2225  */
2226  if (((oldflags&~(P_NEED_UPDATE|P_NO_ERROR)) != flags)
2227  && (!(oldflags&P_NO_ERROR))) {
2228  LOG(llevDebug, "update_position: updated flags do not match old flags: %s (x=%d,y=%d) %x != %x\n",
2229  m->path, x, y, (oldflags&~P_NEED_UPDATE), flags);
2230  }
2231 
2232  SET_MAP_FLAGS(m, x, y, flags);
2233  SET_MAP_MOVE_BLOCK(m, x, y, move_block&~move_allow);
2234  SET_MAP_MOVE_ON(m, x, y, move_on);
2235  SET_MAP_MOVE_OFF(m, x, y, move_off);
2236  SET_MAP_MOVE_SLOW(m, x, y, move_slow);
2237  SET_MAP_LIGHT(m, x, y, light);
2238 
2239  /* Note that player may be NULL here, which is fine - if no player, need
2240  * to clear any value that may be set.
2241  */
2242  SET_MAP_PLAYER(m, x, y, player);
2243 
2244  /* Note it is intentional we copy everything, including NULL values. */
2245  memcpy(GET_MAP_FACE_OBJS(m, x, y), layers, sizeof(object *)*MAP_LAYERS);
2246 }
2247 
2255  int timeout;
2256 
2257  timeout = MAP_RESET_TIMEOUT(map);
2258  if (timeout <= 0)
2259  timeout = MAP_DEFAULTRESET;
2260  if (timeout >= MAP_MAXRESET)
2261  timeout = MAP_MAXRESET;
2262  MAP_RESET_TIMEOUT(map) = timeout;
2263  MAP_WHEN_RESET(map) = seconds()+timeout;
2264 }
2265 
2280 static mapstruct *load_and_link_tiled_map(mapstruct *orig_map, int tile_num) {
2281  int dest_tile = (tile_num+2)%4;
2282  char path[HUGE_BUF];
2283 
2284  path_combine_and_normalize(orig_map->path, orig_map->tile_path[tile_num], path, sizeof(path));
2285 
2286  orig_map->tile_map[tile_num] = ready_map_name(path, 0);
2287  if (orig_map->tile_map[tile_num] == NULL) {
2288  LOG(llevError, "%s has invalid tiled map %s\n", orig_map->path, path);
2289  free(orig_map->tile_path[tile_num]);
2290  orig_map->tile_path[tile_num] = NULL;
2291  return NULL;
2292  }
2293 
2294  /* need to do a strcmp here as the orig_map->path is not a shared string */
2295  if (orig_map->tile_map[tile_num]->tile_path[dest_tile]
2296  && !strcmp(orig_map->tile_map[tile_num]->tile_path[dest_tile], orig_map->path))
2297  orig_map->tile_map[tile_num]->tile_map[dest_tile] = orig_map;
2298 
2299  return orig_map->tile_map[tile_num];
2300 }
2301 
2315 int out_of_map(mapstruct *m, int x, int y) {
2316  int16_t xp = x, yp = y;
2317  if (get_map_from_coord(m, &xp, &yp) == NULL) {
2318  return 1;
2319  } else {
2320  return 0;
2321  }
2322 }
2323 
2343 mapstruct *get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y) {
2344 
2345  /* Simple case - coordinates are within this local
2346  * map.
2347  */
2348 
2349  if ( !m ) return NULL;
2350  if (m->in_memory == MAP_SWAPPED) {
2351  // callers are calling get_map_from_coord() to access the map, so if
2352  // it's swapped out return early here. While we could finish this
2353  // computation without having to swap the map in, when they try to
2354  // get/set it will abort()
2355  //
2356  // This should never happen (if it did, the swapper is buggy) but it
2357  // does actually happen because of object recycling (e.g. op->enemy
2358  // points to a completely different object on a swapped out map)
2359  return NULL;
2360  }
2361  if (!OUT_OF_REAL_MAP(m, *x, *y))
2362  return m;
2363 
2364  do /* With the first case there, we can assume we are out of the map if we get here */
2365  {
2366  // Figure out what map should be in the direction we are off the map, and then
2367  // load that map and look again.
2368  if (*x < 0) {
2369  if (!m->tile_path[3])
2370  return NULL;
2371  if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY){
2373  /* Make sure we loaded properly. */
2374  if (!m->tile_map[3])
2375  return NULL;
2376  }
2377  *x += MAP_WIDTH(m->tile_map[3]);
2378  m = m->tile_map[3];
2379  }
2380  else if (*x >= MAP_WIDTH(m)) {
2381  if (!m->tile_path[1])
2382  return NULL;
2383  if (!m->tile_map[1] || m->tile_map[1]->in_memory != MAP_IN_MEMORY){
2385  /* Make sure we loaded properly. */
2386  if (!m->tile_map[1])
2387  return NULL;
2388  }
2389  *x -= MAP_WIDTH(m);
2390  m = m->tile_map[1];
2391  }
2392  // It is possible that x and y be considered separate compare groups,
2393  // But using an else-if here retains the old behavior that recursion produced.
2394  else if (*y < 0) {
2395  if (!m->tile_path[0])
2396  return NULL;
2397  if (!m->tile_map[0] || m->tile_map[0]->in_memory != MAP_IN_MEMORY){
2399  /* Make sure we loaded properly. */
2400  if (!m->tile_map[0])
2401  return NULL;
2402  }
2403  *y += MAP_HEIGHT(m->tile_map[0]);
2404  m = m->tile_map[0];
2405  }
2406  else if (*y >= MAP_HEIGHT(m)) {
2407  if (!m->tile_path[2])
2408  return NULL;
2409  if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY){
2411  /* Make sure we loaded properly. */
2412  if (!m->tile_map[2])
2413  return NULL;
2414  }
2415  *y -= MAP_HEIGHT(m);
2416  m = m->tile_map[2];
2417  }
2418  // The check here is if our single tile is in the map.
2419  // That is exactly what the OUT_OF_MAP macro does.
2420  } while (OUT_OF_REAL_MAP(m, *x, *y));
2421  return m; /* We have found our map */
2422 }
2423 
2437 static int adjacent_map(const mapstruct *map1, const mapstruct *map2, int *dx, int *dy) {
2438  if (!map1 || !map2)
2439  return 0;
2440 
2441  if (map1 == map2) {
2442  *dx = 0;
2443  *dy = 0;
2444  } else if (map1->tile_map[0] == map2) { /* up */
2445  *dx = 0;
2446  *dy = -MAP_HEIGHT(map2);
2447  } else if (map1->tile_map[1] == map2) { /* right */
2448  *dx = MAP_WIDTH(map1);
2449  *dy = 0;
2450  } else if (map1->tile_map[2] == map2) { /* down */
2451  *dx = 0;
2452  *dy = MAP_HEIGHT(map1);
2453  } else if (map1->tile_map[3] == map2) { /* left */
2454  *dx = -MAP_WIDTH(map2);
2455  *dy = 0;
2456  } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[1] == map2) { /* up right */
2457  *dx = MAP_WIDTH(map1->tile_map[0]);
2458  *dy = -MAP_HEIGHT(map1->tile_map[0]);
2459  } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[3] == map2) { /* up left */
2460  *dx = -MAP_WIDTH(map2);
2461  *dy = -MAP_HEIGHT(map1->tile_map[0]);
2462  } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[0] == map2) { /* right up */
2463  *dx = MAP_WIDTH(map1);
2464  *dy = -MAP_HEIGHT(map2);
2465  } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[2] == map2) { /* right down */
2466  *dx = MAP_WIDTH(map1);
2467  *dy = MAP_HEIGHT(map1->tile_map[1]);
2468  } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[1] == map2) { /* down right */
2469  *dx = MAP_WIDTH(map1->tile_map[2]);
2470  *dy = MAP_HEIGHT(map1);
2471  } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[3] == map2) { /* down left */
2472  *dx = -MAP_WIDTH(map2);
2473  *dy = MAP_HEIGHT(map1);
2474  } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[0] == map2) { /* left up */
2475  *dx = -MAP_WIDTH(map1->tile_map[3]);
2476  *dy = -MAP_HEIGHT(map2);
2477  } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[2] == map2) { /* left down */
2478  *dx = -MAP_WIDTH(map1->tile_map[3]);
2479  *dy = MAP_HEIGHT(map1->tile_map[3]);
2480  } else { /* not "adjacent" enough */
2481  return 0;
2482  }
2483 
2484  return 1;
2485 }
2486 
2514 int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags) {
2515  if (!adjacent_map(op1->map, op2->map, &retval->distance_x, &retval->distance_y)) {
2516  /* be conservative and fill in _some_ data */
2517  retval->distance = 100000;
2518  retval->distance_x = 32767;
2519  retval->distance_y = 32767;
2520  retval->direction = 0;
2521  retval->part = NULL;
2522  return 0;
2523  } else {
2524  object *best;
2525 
2526  retval->distance_x += op2->x-op1->x;
2527  retval->distance_y += op2->y-op1->y;
2528 
2529  best = op1;
2530  /* If this is multipart, find the closest part now */
2531  if (!(flags&0x1) && op1->more) {
2532  object *tmp;
2533  int best_distance = retval->distance_x*retval->distance_x+
2534  retval->distance_y*retval->distance_y, tmpi;
2535 
2536  /* we just take the offset of the piece to head to figure
2537  * distance instead of doing all that work above again
2538  * since the distance fields we set above are positive in the
2539  * same axis as is used for multipart objects, the simply arithmetic
2540  * below works.
2541  */
2542  for (tmp = op1->more; tmp != NULL; tmp = tmp->more) {
2543  tmpi = (op1->x-tmp->x+retval->distance_x)*(op1->x-tmp->x+retval->distance_x)+
2544  (op1->y-tmp->y+retval->distance_y)*(op1->y-tmp->y+retval->distance_y);
2545  if (tmpi < best_distance) {
2546  best_distance = tmpi;
2547  best = tmp;
2548  }
2549  }
2550  if (best != op1) {
2551  retval->distance_x += op1->x-best->x;
2552  retval->distance_y += op1->y-best->y;
2553  }
2554  }
2555  retval->part = best;
2556  retval->distance = ihypot(retval->distance_x, retval->distance_y);
2557  retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y);
2558  return 1;
2559  }
2560 }
2561 
2582 int get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval) {
2583  if (!adjacent_map(m, op2->map, &retval->distance_x, &retval->distance_y)) {
2584  /* be conservative and fill in _some_ data */
2585  retval->distance = 100000;
2586  retval->distance_x = 32767;
2587  retval->distance_y = 32767;
2588  retval->direction = 0;
2589  retval->part = NULL;
2590  return 0;
2591  } else {
2592  retval->distance_x += op2->x-x;
2593  retval->distance_y += op2->y-y;
2594 
2595  retval->part = NULL;
2596  retval->distance = isqrt(retval->distance_x*retval->distance_x+retval->distance_y*retval->distance_y);
2597  retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y);
2598  return 1;
2599  }
2600 }
2601 
2620 int on_same_map(const object *op1, const object *op2) {
2621  int dx, dy;
2622 
2623  return adjacent_map(op1->map, op2->map, &dx, &dy);
2624 }
2625 
2643 object *map_find_by_flag(mapstruct *map, int x, int y, int flag) {
2644  object *tmp;
2645 
2646  for (tmp = GET_MAP_OB(map, x, y); tmp != NULL; tmp = tmp->above) {
2647  object *head;
2648 
2649  head = HEAD(tmp);
2650  if (QUERY_FLAG(head, flag))
2651  return head;
2652  }
2653  return NULL;
2654 }
2655 
2661  char base[HUGE_BUF], path[sizeof(base) + 4];
2662  int count;
2663 
2664  if (map->unique) {
2665  snprintf(path, sizeof(path), "%s/%s/%s", settings.localdir, settings.playerdir, map->path+1);
2666  if (unlink(path) != 0) {
2667  LOG(llevError, "Could not delete %s: %s\n", path, strerror(errno));
2668  }
2669  return;
2670  }
2671 
2672  create_items_path(map->path, base, sizeof(base));
2673 
2674  for (count = 0; count < 10; count++) {
2675  snprintf(path, sizeof(path), "%s.v%02d", base, count);
2676  unlink(path);
2677  }
2678 }
2679 
2685 const char *map_get_path(const object *item) {
2686  if (item->map != NULL) {
2687  if (strlen(item->map->path) > 0) {
2688  return item->map->path;
2689  }
2690 
2691  return item->map->name ? item->map->name : "(empty path and name)";
2692  }
2693 
2694  if (item->env != NULL)
2695  return map_get_path(item->env);
2696 
2697  return "(no map and no env!)";
2698 }
2699 
2705 bool map_path_unique(const char *path) {
2706  return path != NULL && path[0] == '~';
2707 }
2708 
2709 MapSpace *map_space(const mapstruct *m, int x, int y) {
2710  if (m->spaces == NULL) // guard against map being swapped out
2711  abort();
2712  if (OUT_OF_REAL_MAP(m, x, y)) // array out of bounds check
2713  abort();
2714  return &m->spaces[x + m->width * y];
2715 }
2716 
2721 int map_light_on(mapstruct *m, int x, int y) {
2722  /* Check the spaces with the max light radius to see if any of them
2723  * have lights, and if any of them light the player enough, then return 1.
2724  */
2725  for (int i = x - MAX_LIGHT_RADII; i <= x + MAX_LIGHT_RADII; i++) {
2726  for (int j = y - MAX_LIGHT_RADII; j <= y + MAX_LIGHT_RADII; j++) {
2727  int16_t nx = i;
2728  int16_t ny = j;
2729  auto real = get_map_from_coord(m, &nx, &ny);
2730  if (real == nullptr)
2731  continue;
2732 
2733  int light = GET_MAP_LIGHT(real, nx, ny);
2734  if (light == 0)
2735  continue;
2736 
2737  if (ihypot(i - x, j - y) < light)
2738  return 1;
2739  }
2740  }
2741 
2742  return 0;
2743 }
2744 
2748 bool coords_in_shop(mapstruct *map, int x, int y) {
2749  FOR_MAP_PREPARE(map, x, y, floor)
2750  if (floor->type == SHOP_FLOOR) return true;
2751  FOR_MAP_FINISH();
2752  return false;
2753 }
2754 
2755 bool shop_contains(object *ob) {
2756  if (!ob->map) return 0;
2757  return coords_in_shop(ob->map, ob->x, ob->y);
2758 }
mapstruct::tile_path
char * tile_path[4]
Path to adjoining maps.
Definition: map.h:358
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Gets the bottom object on a map.
Definition: map.h:175
MAP_FLUSH
#define MAP_FLUSH
Always load map from the map directory, and don't do unique items or the like.
Definition: map.h:96
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:304
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:789
Settings::mapdir
const char * mapdir
Where the map files are.
Definition: global.h:256
output_file.h
path.h
FREE_AND_CLEAR_STR_IF
#define FREE_AND_CLEAR_STR_IF(xyz)
Definition: global.h:206
global.h
settings
struct Settings settings
Global settings.
Definition: init.cpp:139
MOVE_WALK
#define MOVE_WALK
Object walks.
Definition: define.h:383
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:714
SAVE_MODE
#define SAVE_MODE
If you have defined SAVE_PLAYER, you might want to change this, too.
Definition: config.h:562
save_map_to_stream
int save_map_to_stream(mapstruct *m, int flag, FILE *fp, FILE *fp2)
Save map to stream.
Definition: map.cpp:1376
load_overlay_map
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:1277
llevError
@ llevError
Problems requiring server admin to fix.
Definition: logger.h:11
P_BLOCKSVIEW
#define P_BLOCKSVIEW
This spot blocks the player's view.
Definition: map.h:231
MOVE_FLYING
#define MOVE_FLYING
Combo of fly_low and fly_high.
Definition: define.h:386
EVENT_MAPUNLOAD
#define EVENT_MAPUNLOAD
A map is freed (includes swapping out)
Definition: events.h:64
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:82
get_empty_map
mapstruct * get_empty_map(int sizex, int sizey)
Creates and returns a map of the specific size.
Definition: map.cpp:832
INS_MAP_LOAD
#define INS_MAP_LOAD
Disable lots of checkings.
Definition: object.h:585
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:369
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:146
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
player
One player.
Definition: player.h:107
MAP_RESET_TIMEOUT
#define MAP_RESET_TIMEOUT(m)
Definition: map.h:67
FLAG_IS_LINKED
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:302
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:334
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
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:1312
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:1768
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:371
MAP_STYLE
#define MAP_STYLE
Active objects shouldn't be put on active list.
Definition: map.h:99
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:1241
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:307
MAP_LAYER_FLY1
#define MAP_LAYER_FLY1
Flying objects - creatures, spells.
Definition: map.h:48
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:935
MAP_LAYER_LIVING1
#define MAP_LAYER_LIVING1
Living creatures.
Definition: map.h:46
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:2139
MAP_LOADING
#define MAP_LOADING
This map is being loaded.
Definition: map.h:133
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:2721
Settings::datadir
const char * datadir
Read only data files.
Definition: global.h:253
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:2070
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
P_NO_CLERIC
#define P_NO_CLERIC
No clerical spells cast here.
Definition: map.h:243
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.cpp:57
SHOP_FLOOR
@ SHOP_FLOOR
Definition: object.h:188
if
if(!(yy_init))
Definition: loader.cpp:36440
object::x
int16_t x
Definition: object.h:335
maps_saved_total
int maps_saved_total
Definition: logger.cpp:57
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:131
MAP_LAYER_ITEM3
#define MAP_LAYER_ITEM3
Definition: map.h:45
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:409
shopitems::index
int index
Being the size of the shopitems array.
Definition: map.h:306
SET_MAP_MOVE_ON
#define SET_MAP_MOVE_ON(M, X, Y, C)
Sets the move_on state of a square.
Definition: map.h:209
CHECK_INV
@ CHECK_INV
b.t.
Definition: object.h:174
CALLOC
#define CALLOC(x, y)
Definition: compat.h:31
FLAG_WIZ
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:218
map_path
void map_path(const char *map, int flags, char *pathname, size_t bufsize)
Definition: map.cpp:1154
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
This correspondes to the map layers in the map2 protocol.
Definition: map.h:32
MAP_LAYER_NO_PICK2
#define MAP_LAYER_NO_PICK2
Non pickable ground objects.
Definition: map.h:42
MAP_WORLDPARTY
#define MAP_WORLDPARTY(m)
Definition: map.h:88
flags
static const flag_definition flags[]
Flag mapping.
Definition: gridarta-types-convert.cpp:101
llevWarn
@ llevWarn
Warnings or major code issues.
Definition: logger.h:12
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:1587
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:38957
PROFILE_BEGIN
#define PROFILE_BEGIN(expr)
Definition: global.h:365
MAP_LAYER_FLOOR
#define MAP_LAYER_FLOOR
Definition: map.h:40
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:225
NDI_NAVY
#define NDI_NAVY
Definition: newclient.h:248
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
TRANSPORT
@ TRANSPORT
see doc/Developers/objects
Definition: object.h:113
LO_NEWFILE
#define LO_NEWFILE
Definition: loader.h:17
MAP_LAYER_NO_PICK1
#define MAP_LAYER_NO_PICK1
Non pickable ground objects.
Definition: map.h:41
rv_vector::part
object * part
Part we found.
Definition: map.h:380
object::title
sstring title
Of foo, etc.
Definition: object.h:325
mapstruct::path
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:360
FLAG_CAN_ROLL
#define FLAG_CAN_ROLL
Object can be rolled.
Definition: define.h:241
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:192
MSG_TYPE_MISC
#define MSG_TYPE_MISC
Messages that don't go elsewhere.
Definition: newclient.h:417
free_all_maps
void free_all_maps(void)
Frees all allocated maps.
Definition: map.cpp:1983
buf
StringBuffer * buf
Definition: readable.cpp:1564
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
ihypot
int ihypot(int a, int b)
Rough estimate of hypot(a, b).
Definition: utils.cpp:575
Map_Layer_Info::honor_visibility
uint8_t honor_visibility
If 0 then don't reorder items, else allow.
Definition: map.cpp:54
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
mapstruct::width
uint16_t width
Definition: map.h:341
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:219
rv_vector::distance_y
int distance_y
Y delta.
Definition: map.h:378
map_remove_unique_files
void map_remove_unique_files(const mapstruct *map)
Remove files containing the map's unique items.
Definition: map.cpp:2660
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:710
PROFILE_END
#define PROFILE_END(var, expr)
Definition: global.h:370
FLAG_ALIVE
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:217
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
m
static event_registration m
Definition: citylife.cpp:424
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:379
rv_vector::distance_x
int distance_x
X delta.
Definition: map.h:377
MOVE_ALL
#define MOVE_ALL
Mask of all movement types.
Definition: define.h:389
NUM_FACINGS
#define NUM_FACINGS(ob)
Definition: global.h:178
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:266
MAP_DIFFICULTY
#define MAP_DIFFICULTY(m)
Definition: map.h:68
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:1545
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:788
SAVE_FLAG_NO_REMOVE
#define SAVE_FLAG_NO_REMOVE
If set, objects are not removed while saving.
Definition: map.h:112
MAP_LAYER_FLY2
#define MAP_LAYER_FLY2
Arrows, etc.
Definition: map.h:49
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:4375
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:328
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:223
P_NO_MAGIC
#define P_NO_MAGIC
Spells (some) can't pass this object.
Definition: map.h:232
MSG_TYPE_ATTACK_NOKEY
#define MSG_TYPE_ATTACK_NOKEY
Keys are like attacks, so...
Definition: newclient.h:621
FREE_OBJ_NO_DESTROY_CALLBACK
#define FREE_OBJ_NO_DESTROY_CALLBACK
Do not run the destroy callback.
Definition: object.h:545
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:784
SAVE_FLAG_SAVE_UNPAID
#define SAVE_FLAG_SAVE_UNPAID
If set, unpaid items will be saved.
Definition: map.h:111
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:1337
FLAG_NO_MAGIC
#define FLAG_NO_MAGIC
Spells (some) can't pass this object.
Definition: define.h:263
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
SAVE_ERROR_RCREATION
#define SAVE_ERROR_RCREATION
Couldn't create the regular save file.
Definition: map.h:145
add_string
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
FLAG_MONSTER
#define FLAG_MONSTER
Will attack players.
Definition: define.h:232
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:1974
MAP_OVERLAY
#define MAP_OVERLAY
Map to load is an overlay.
Definition: map.h:100
MAP_WHEN_RESET
#define MAP_WHEN_RESET(m)
This is when the map will reset.
Definition: map.h:65
change_map_light
int change_map_light(mapstruct *m, int change)
Used to change map light level (darkness) up or down.
Definition: map.cpp:2015
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:342
mapfile_load_lowlevel
mapstruct * mapfile_load_lowlevel(const char *map, const char *pathname, int flags)
Definition: map.cpp:1164
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:2315
MAX_DARKNESS
#define MAX_DARKNESS
Maximum map darkness, there is no practical reason to exceed this.
Definition: define.h:439
MSG_TYPE_ATTACK
#define MSG_TYPE_ATTACK
Attack related messages.
Definition: newclient.h:413
isqrt
int isqrt(int n)
Compute the square root.
Definition: utils.cpp:567
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
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:27
SET_MAP_FLAGS
#define SET_MAP_FLAGS(M, X, Y, C)
Sets map flags.
Definition: map.h:164
remove_button_link
void remove_button_link(object *op)
Remove the object from the linked lists of buttons in the map.
Definition: button.cpp:695
SAVE_MODE_OVERLAY
#define SAVE_MODE_OVERLAY
Map is persisted as an overlay.
Definition: map.h:123
FLAG_BLOCKSVIEW
#define FLAG_BLOCKSVIEW
Object blocks view.
Definition: define.h:256
SAVE_ERROR_UCREATION
#define SAVE_ERROR_UCREATION
Couldn't create the file for unique objects.
Definition: map.h:146
shopitems::name_pl
const char * name_pl
Plural name.
Definition: map.h:302
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:1577
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:197
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:661
FLAG_NO_PICK
#define FLAG_NO_PICK
Object can't be picked up.
Definition: define.h:226
P_PLAYER
#define P_PLAYER
There is a player on this space.
Definition: map.h:241
MAP_DEFAULTRESET
#define MAP_DEFAULTRESET
Default time to reset.
Definition: config.h:427
INS_ON_TOP
#define INS_ON_TOP
Always put object on top.
Definition: object.h:583
P_NEED_UPDATE
#define P_NEED_UPDATE
This space is out of date.
Definition: map.h:244
free_map
void free_map(mapstruct *m)
Frees everything allocated by the given mapstructure.
Definition: map.cpp:1650
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:1603
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_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:254
sproto.h
GET_MAP_LIGHT
#define GET_MAP_LIGHT(M, X, Y)
Gets map light.
Definition: map.h:167
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:2343
MapSpace
This structure contains all information related to one map square.
Definition: map.h:261
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Can't see what's underneath this object.
Definition: define.h:289
cf_random
uint32_t cf_random(void)
Definition: cf_random.cpp:5
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:2582
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:2643
delete_map
void delete_map(mapstruct *m)
Frees the map, including the mapstruct.
Definition: map.cpp:1696
FLAG_OVERLAY_FLOOR
#define FLAG_OVERLAY_FLOOR
Object is an overlay floor.
Definition: define.h:242
MSG_SUBTYPE_NONE
#define MSG_SUBTYPE_NONE
Definition: newclient.h:424
INS_NO_WALK_ON
#define INS_NO_WALK_ON
Don't call check_walk_on against the originator.
Definition: object.h:582
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:469
NDI_BLACK
#define NDI_BLACK
Definition: newclient.h:246
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:2085
SAVE_MODE_NORMAL
#define SAVE_MODE_NORMAL
No special handling.
Definition: map.h:121
mapstruct::last_reset_time
long last_reset_time
A timestamp of the last original map loading.
Definition: map.h:361
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:565
get_typedata_by_name
const typedata * get_typedata_by_name(const char *name)
Definition: item.cpp:348
fatal
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:595
MAP_NO_DIFFICULTY
#define MAP_NO_DIFFICULTY
If set then don't compute a map difficulty if it is 0.
Definition: map.h:98
get_linked_map
mapstruct * get_linked_map(void)
Allocates, initialises, and returns a pointer to a mapstruct, linked through first_map.
Definition: map.cpp:763
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:76
maps_loaded_total
int maps_loaded_total
Definition: logger.cpp:56
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
EVENT_MAPREADY
#define EVENT_MAPREADY
A map is ready, either first load or after reload.
Definition: events.h:62
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Portable implementation of strlcpy(3).
Definition: porting.cpp:225
map_space
MapSpace * map_space(const mapstruct *m, int x, int y)
Definition: map.cpp:2709
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:1258
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:410
shopitems::typenum
int typenum
Itemtype number we need to match, -1 if it is the default price.
Definition: map.h:303
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:2254
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:294
Settings::playerdir
const char * playerdir
Where the player files are.
Definition: global.h:255
StringBuffer
A buffer that will be expanded as content is added to it.
Definition: stringbuffer.cpp:25
FLAG_DAMNED
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:304
SET_MAP_MOVE_SLOW
#define SET_MAP_MOVE_SLOW(M, X, Y, C)
Sets the slowing state of a square.
Definition: map.h:204
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:707
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Checks if a square is out of the map.
Definition: map.h:222
SAVE_ERROR_URENAME
#define SAVE_ERROR_URENAME
Couldn't rename unique temporary file.
Definition: map.h:149
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:3662
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:2280
P_IS_ALIVE
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:242
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:266
FLAG_GENERATOR
#define FLAG_GENERATOR
Will generate type ob->stats.food.
Definition: define.h:235
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:977
INS_ABOVE_FLOOR_ONLY
#define INS_ABOVE_FLOOR_ONLY
Put object immediatly above the floor.
Definition: object.h:581
FREE_AND_CLEAR
#define FREE_AND_CLEAR(xyz)
Free the pointer and then set it to NULL.
Definition: global.h:199
shopitems::name
const char * name
Name of the item in question, null if it is the default item.
Definition: map.h:301
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:2437
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:280
mapstruct
This is a game-map.
Definition: map.h:320
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
floor
Magical Runes Runes are magical inscriptions on the dungeon floor
Definition: runes-guide.txt:3
msgbuf
static char msgbuf[HUGE_BUF]
Definition: loader.cpp:35880
P_NO_ERROR
#define P_NO_ERROR
Purely temporary - if set, update_position does not complain if the flags are different.
Definition: map.h:245
MAP_LAYER_ITEM1
#define MAP_LAYER_ITEM1
Items that can be picked up.
Definition: map.h:43
MapSpace::flags
uint8_t flags
Flags about this space (see the P_ values above).
Definition: map.h:265
animate_object
void animate_object(object *op, int dir)
Updates the face-variable of an object.
Definition: anim.cpp:44
mapstruct::name
char * name
Name of map as given by its creator.
Definition: map.h:323
AB_NO_PASS
#define AB_NO_PASS
Definition: map.h:240
make_path_to_file
bool 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:165
shop_contains
bool shop_contains(object *ob)
Check if an object is in a shop.
Definition: map.cpp:2755
mapstruct::in_memory
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:339
MAP_SWAPPED
#define MAP_SWAPPED
Map spaces have been saved to disk.
Definition: map.h:132
rv_vector
This is used by get_rangevector to determine where the other creature is.
Definition: map.h:375
update_buttons
void update_buttons(mapstruct *m)
Updates every button on the map (by calling update_button() for them).
Definition: button.cpp:228
objects
object * objects
Pointer to the list of used objects.
Definition: object.cpp:294
shopitems
Shop-related information for a map.
Definition: map.h:300
object_get_value
sstring object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4331
map_get_path
const char * map_get_path(const object *item)
Return the map path on which the specified item is.
Definition: map.cpp:2685
SET_MAP_MOVE_BLOCK
#define SET_MAP_MOVE_BLOCK(M, X, Y, C)
Sets the blocking state of a square.
Definition: map.h:199
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:2620
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:370
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:2705
MAP_HEIGHT
#define MAP_HEIGHT(m)
Map height.
Definition: map.h:78
MAP_WORLDPARTX
#define MAP_WORLDPARTX(m)
Definition: map.h:87
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:5299
NUM_ANIMATIONS
#define NUM_ANIMATIONS(ob)
Definition: global.h:177
MAP_ENTER_Y
#define MAP_ENTER_Y(m)
Default Y coordinate for map enter.
Definition: map.h:85
strip_endline
void strip_endline(char *buf)
Removes endline from buffer (modified in place).
Definition: utils.cpp:319
mapstruct::tile_map
mapstruct * tile_map[4]
Adjoining maps.
Definition: map.h:359
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:1377
INS_NO_MERGE
#define INS_NO_MERGE
Don't try to merge with other items.
Definition: object.h:580
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:349
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:2514
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:802
MAP_PLAYER_UNIQUE
#define MAP_PLAYER_UNIQUE
This map is player-specific.
Definition: map.h:97
FMT64U
#define FMT64U
Definition: compat.h:17
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:4670
S_IWOTH
#define S_IWOTH
Definition: win32.h:41
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.cpp:316
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:524
FLAG_OBJ_ORIGINAL
#define FLAG_OBJ_ORIGINAL
NEVER SET THIS.
Definition: define.h:344
MAP_ENTER_X
#define MAP_ENTER_X(m)
Default X coordinate for map enter.
Definition: map.h:83
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:1818
GET_MAP_FLAGS
#define GET_MAP_FLAGS(M, X, Y)
Gets map flags.
Definition: map.h:162
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:553
EVENT_MAPLOAD
#define EVENT_MAPLOAD
A map is loaded (pristine state)
Definition: events.h:61
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:418
SAVE_ERROR_CLOSE
#define SAVE_ERROR_CLOSE
Close error for regular file.
Definition: map.h:150
S_IWGRP
#define S_IWGRP
Definition: win32.h:44
mapstruct::unique
uint32_t unique
If set, this is a per player unique map.
Definition: map.h:333
save_map
int save_map(mapstruct *m, int flag)
Saves a map to file.
Definition: map.cpp:1470
calculate_difficulty
int calculate_difficulty(mapstruct *m)
This routine is supposed to find out the difficulty of the map.
Definition: map.cpp:1917
mapstruct::next
mapstruct * next
Next map, linked list.
Definition: map.h:321
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
P_NEW_MAP
#define P_NEW_MAP
Coordinates passed result in a new tiled map.
Definition: map.h:255
SET_MAP_PLAYER
#define SET_MAP_PLAYER(M, X, Y, C)
Definition: map.h:172
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:259
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:1205
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:854
FLAG_UNIQUE
#define FLAG_UNIQUE
Item is really unique (UNIQUE_ITEMS)
Definition: define.h:274
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
SAVE_ERROR_OK
#define SAVE_ERROR_OK
No error.
Definition: map.h:144
MAP_MAXRESET
#define MAP_MAXRESET
MAP_MAXRESET is the maximum time a map can have before being reset.
Definition: config.h:425
rv_vector::direction
int direction
General direction to the targer.
Definition: map.h:379
SET_MAP_LIGHT
#define SET_MAP_LIGHT(M, X, Y, L)
Sets map light.
Definition: map.h:169
SAVE_ERROR_NO_PATH
#define SAVE_ERROR_NO_PATH
Map had no path set.
Definition: map.h:148
rv_vector::distance
unsigned int distance
Distance, in squares.
Definition: map.h:376
map_reset_swap
void map_reset_swap(mapstruct *m)
Call this when an in-memory map is used or referenced.
Definition: map.cpp:1750
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
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
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:654
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:181
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:435
dump_all_maps
void dump_all_maps(void)
Prints out debug-information about all maps.
Definition: map.cpp:248
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:593
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:15
MAP_LAYER_LIVING2
#define MAP_LAYER_LIVING2
Definition: map.h:47
coords_in_shop
bool coords_in_shop(mapstruct *map, int x, int y)
Check if the given map coordinates are in a shop.
Definition: map.cpp:2748
MAP_SAVING
#define MAP_SAVING
Map being saved.
Definition: map.h:134
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:258
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:214
Settings::localdir
const char * localdir
Read/write data files.
Definition: global.h:254