Crossfire Server, Trunk  1.75.0
map.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
19 #include "global.h"
20 
21 #include <ctype.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <math.h>
28 
29 #ifndef WIN32 /* ---win32 exclude header */
30 #include <unistd.h>
31 #endif /* win32 */
32 
33 #include "sproto.h"
34 #include "loader.h"
35 #include "output_file.h"
36 #include "path.h"
37 #include "stats.h"
38 
39 static void free_all_objects(mapstruct *m);
40 
46 const char *const map_layer_name[MAP_LAYERS] = {
47  "floor", "no_pick", "no_pick", "item", "item",
48  "item", "living", "living", "fly", "fly"
49 };
50 
53  uint8_t high_layer;
54  uint8_t honor_visibility;
55 };
56 
64  { MAP_LAYER_FLOOR, 1 },
66  { MAP_LAYER_ITEM3, 1 }, { MAP_LAYER_ITEM3, 1 }, { MAP_LAYER_ITEM3, 1 },
67  { MAP_LAYER_LIVING2, 1 }, { MAP_LAYER_LIVING2, 1 },
68  { MAP_LAYER_FLY2, 1 }, { MAP_LAYER_FLY2, 1 }
69 };
70 
80  mapstruct *map;
81 
82  if (!name || !*name)
83  return NULL;
84 
85  for (map = first_map; map; map = map->next)
86  if (!strcmp(name, map->path))
87  break;
88  return (map);
89 }
90 
104 char *create_pathname(const char *name, char *buf, size_t size) {
105  /* Why? having extra / doesn't confuse unix anyplace? Dependancies
106  * someplace else in the code? msw 2-17-97
107  */
108  if (*name == '/')
109  snprintf(buf, size, "%s/%s%s", settings.datadir, settings.mapdir, name);
110  else
111  snprintf(buf, size, "%s/%s/%s", settings.datadir, settings.mapdir, name);
112  return buf;
113 }
114 
125 void create_overlay_pathname(const char *name, char *buf, size_t size) {
126  /* Why? having extra / doesn't confuse unix anyplace? Dependancies
127  * someplace else in the code? msw 2-17-97
128  */
129  if (*name == '/')
130  snprintf(buf, size, "%s/%s%s", settings.localdir, settings.mapdir, name);
131  else
132  snprintf(buf, size, "%s/%s/%s", settings.localdir, settings.mapdir, name);
133 }
134 
145 void create_template_pathname(const char *name, char *buf, size_t size) {
146  /* Why? having extra / doesn't confuse unix anyplace? Dependancies
147  * someplace else in the code? msw 2-17-97
148  */
149  if (*name == '/')
150  snprintf(buf, size, "%s/%s%s", settings.localdir, settings.templatedir, name);
151  else
152  snprintf(buf, size, "%s/%s/%s", settings.localdir, settings.templatedir, name);
153 }
154 
166 static void create_items_path(const char *s, char *buf, size_t size) {
167  char *t;
168 
169  if (*s == '/')
170  s++;
171 
172  snprintf(buf, size, "%s/%s/", settings.localdir, settings.uniquedir);
173  t = buf+strlen(buf);
174  snprintf(t, buf+size-t, "%s", s);
175 
176  while (*t != '\0') {
177  if (*t == '/')
178  *t = '@';
179  t++;
180  }
181 }
182 
201 int check_path(const char *name, int prepend_dir) {
202  char buf[MAX_BUF];
203 #ifndef WIN32
204  struct stat statbuf;
205  int mode = 0;
206 #endif
207 
208  if (prepend_dir)
210  else
211  strlcpy(buf, name, sizeof(buf));
212 #ifdef WIN32 /* ***win32: check this sucker in windows style. */
213  return(_access(buf, 0));
214 #else
215 
216  if (stat(buf, &statbuf) != 0)
217  return -1;
218 
219  if (!S_ISREG(statbuf.st_mode))
220  return (-1);
221 
222  if (((statbuf.st_mode&S_IRGRP) && getegid() == statbuf.st_gid)
223  || ((statbuf.st_mode&S_IRUSR) && geteuid() == statbuf.st_uid)
224  || (statbuf.st_mode&S_IROTH))
225  mode |= 4;
226 
227  if ((statbuf.st_mode&S_IWGRP && getegid() == statbuf.st_gid)
228  || (statbuf.st_mode&S_IWUSR && geteuid() == statbuf.st_uid)
229  || (statbuf.st_mode&S_IWOTH))
230  mode |= 2;
231 
232  return (mode);
233 #endif
234 }
235 
245 void dump_map(const mapstruct *m) {
246  LOG(llevError, "Map %s status: %d.\n", m->path, m->in_memory);
247  LOG(llevError, "Size: %dx%d Start: %d,%d\n", MAP_WIDTH(m), MAP_HEIGHT(m), MAP_ENTER_X(m), MAP_ENTER_Y(m));
248 
249  if (m->msg != NULL)
250  LOG(llevError, "Message:\n%s", m->msg);
251 
252  if (m->maplore != NULL)
253  LOG(llevError, "Lore:\n%s", m->maplore);
254 
255  if (m->tmpname != NULL)
256  LOG(llevError, "Tmpname: %s\n", m->tmpname);
257 
258  LOG(llevError, "Difficulty: %d\n", m->difficulty);
259  LOG(llevError, "Darkness: %d\n", m->darkness);
260 }
261 
268 void dump_all_maps(void) {
269  mapstruct *m;
270 
271  for (m = first_map; m != NULL; m = m->next) {
272  dump_map(m);
273  }
274 }
275 
300 int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny) {
301  int retval = 0;
302  mapstruct *mp;
303 
304  /*
305  * Since x and y are copies of the original values, we can directly
306  * mess with them here.
307  */
308  mp = get_map_from_coord(oldmap, &x, &y);
309  if (!mp)
310  return P_OUT_OF_MAP;
311  if (mp != oldmap)
312  retval |= P_NEW_MAP;
313  if (newmap)
314  *newmap = mp;
315  if (nx)
316  *nx = x;
317  if (ny)
318  *ny = y;
319  retval |= mp->spaces[x+mp->width*y].flags;
320  return retval;
321 }
322 
327 bool ob_move_block(object *ob1, object *ob2) {
328  // Special case: if ob1 has no move type, but we're here, then we're being
329  // pushed by something. Assume "walk".
330  return ((ob1->move_type ? ob1->move_type : MOVE_WALK) & ~ob2->move_block) == 0;
331 }
332 
354 int blocked_link(object *ob, mapstruct *m, int16_t sx, int16_t sy) {
355  object *tmp_head;
356  int mflags, blocked;
357 
358  /* Make sure the coordinates are valid - they should be, as caller should
359  * have already checked this.
360  */
361  if (OUT_OF_REAL_MAP(m, sx, sy)) {
362  LOG(llevError, "blocked_link: Passed map, x, y coordinates outside of map\n");
363  return 1;
364  }
365 
366  /* special hack for transports: if it's a transport with a move_type of 0, it can do on the space anyway */
367  if (ob->type == TRANSPORT && ob->move_type == 0)
368  return 0;
369 
370  mflags = m->spaces[sx+m->width*sy].flags;
371 
372  blocked = GET_MAP_MOVE_BLOCK(m, sx, sy);
373 
374  /* If space is currently not blocked by anything, no need to
375  * go further. Not true for players - all sorts of special
376  * things we need to do for players.
377  */
378  if (ob->type != PLAYER && !(mflags&P_IS_ALIVE) && (blocked == 0))
379  return 0;
380 
381  /* if there isn't anytyhing alive on this space, and this space isn't
382  * otherwise blocked, we can return now. Only if there is a living
383  * creature do we need to investigate if it is part of this creature
384  * or another. Likewise, only if something is blocking us do we
385  * need to investigate if there is a special circumstance that would
386  * let the player through (inventory checkers for example)
387  */
388  if (!(mflags&P_IS_ALIVE) && !OB_TYPE_MOVE_BLOCK(ob, blocked))
389  return 0;
390 
391  ob = HEAD(ob);
392 
393  /* We basically go through the stack of objects, and if there is
394  * some other object that has NO_PASS or FLAG_ALIVE set, return
395  * true. If we get through the entire stack, that must mean
396  * ob is blocking it, so return 0.
397  */
398  FOR_MAP_PREPARE(m, sx, sy, tmp) {
399  /* Never block part of self. */
400  tmp_head = HEAD(tmp);
401  if (tmp_head == ob)
402  continue;
403  /* This must be before the checks below. Code for inventory checkers. */
404  if (tmp->type == CHECK_INV && OB_MOVE_BLOCK(ob, tmp)) {
405  /* If last_sp is set, the player/monster needs an object,
406  * so we check for it. If they don't have it, they can't
407  * pass through this space.
408  */
409  if (tmp->last_sp) {
410  if (check_inv_recursive(ob, tmp) == NULL) {
411  if (tmp->msg) {
412  /* Optionally display the reason why one cannot move
413  * there. Note: emitting a message from this function
414  * is not very elegant. Ideally, this should be done
415  * somewhere in server/player.c, but this is difficult
416  * for objects of type CHECK_INV that are not alive.
417  */
420  tmp->msg);
421  }
422  return 1;
423  }
424  } else {
425  /* In this case, the player must not have the object -
426  * if they do, they can't pass through.
427  */
428  if (check_inv_recursive(ob, tmp) != NULL) {
429  if (tmp->msg) {
432  tmp->msg);
433  }
434  return 1;
435  }
436  }
437  } /* if check_inv */
438  else {
439  /* Broke apart a big nasty if into several here to make
440  * this more readable. first check - if the space blocks
441  * movement, can't move here.
442  * second - if a monster, can't move there, unless it is a
443  * hidden dm
444  */
445  if (OB_MOVE_BLOCK(ob, tmp))
446  return 1;
447  if (QUERY_FLAG(tmp, FLAG_ALIVE)
448  && tmp->head != ob
449  && tmp != ob
450  && tmp->type != DOOR
451  && !(QUERY_FLAG(tmp, FLAG_WIZ) && tmp->contr->hidden))
452  return 1;
453  }
454  } FOR_MAP_FINISH();
455  return 0;
456 }
457 
489 int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y) {
490  archetype *tmp;
491  int flag;
492  mapstruct *m1;
493  int16_t sx, sy;
494  const object *part;
495 
496  if (ob == NULL) {
497  flag = get_map_flags(m, &m1, x, y, &sx, &sy);
498  if (flag&P_OUT_OF_MAP)
499  return P_OUT_OF_MAP;
500 
501  /* don't have object, so don't know what types would block */
502  return(GET_MAP_MOVE_BLOCK(m1, sx, sy));
503  }
504 
505  for (tmp = ob->arch, part = ob; tmp != NULL; tmp = tmp->more, part = part->more) {
506  flag = get_map_flags(m, &m1, x+tmp->clone.x, y+tmp->clone.y, &sx, &sy);
507 
508  if (flag&P_OUT_OF_MAP)
509  return P_OUT_OF_MAP;
510  if (flag&P_IS_ALIVE)
511  return P_IS_ALIVE;
512 
513  /* object_find_first_free_spot() calls this function. However, often
514  * ob doesn't have any move type (when used to place exits)
515  * so the AND operation in OB_TYPE_MOVE_BLOCK doesn't work.
516  */
517 
518  if (ob->move_type == 0 && GET_MAP_MOVE_BLOCK(m1, sx, sy) != MOVE_ALL)
519  continue;
520 
521  /* A transport without move_type for a part should go through everything for that part. */
522  if (ob->type == TRANSPORT && part->move_type == 0)
523  continue;
524 
525  /* Note it is intentional that we check ob - the movement type of the
526  * head of the object should correspond for the entire object.
527  */
528  if (OB_TYPE_MOVE_BLOCK(ob, GET_MAP_MOVE_BLOCK(m1, sx, sy)))
529  return AB_NO_PASS;
530  }
531  return 0;
532 }
533 
544 static void fix_container_multipart(object *container) {
545  FOR_INV_PREPARE(container, tmp) {
546  archetype *at;
547  object *op, *last;
548 
549  if (tmp->inv)
551  /* already multipart, or non-multipart arch - don't do anything more */
552  for (at = tmp->arch->more, last = tmp; at != NULL; at = at->more, last = op) {
553  /* FIXME: We can't reuse object_fix_multipart() since that only
554  * works for items directly on maps. Maybe factor out common code?
555  */
556  op = arch_to_object(at);
557  op->head = tmp;
558  op->env = tmp->env;
559  last->more = op;
560  if (tmp->name != op->name) {
561  if (op->name)
562  free_string(op->name);
563  op->name = add_string(tmp->name);
564  }
565  if (tmp->title != op->title) {
566  if (op->title)
567  free_string(op->title);
568  op->title = add_string(tmp->title);
569  }
571  }
572  } FOR_INV_FINISH();
573 }
574 
586  int x, y;
587 
588  for (x = 0; x < MAP_WIDTH(m); x++)
589  for (y = 0; y < MAP_HEIGHT(m); y++)
590  FOR_MAP_PREPARE(m, x, y, tmp) {
591  if (tmp->inv)
593 
594  /* already multipart - don't do anything more */
595  if (tmp->head || tmp->more)
596  continue;
597 
599  } FOR_MAP_FINISH(); /* for objects on this space */
600 }
601 
613 void load_objects(mapstruct *m, FILE *fp, int mapflags) {
614  int i, j, bufstate = LO_NEWFILE;
615  int unique;
616  object *op, *prev = NULL, *last_more = NULL;
617 
618  op = object_new();
619  op->map = m; /* To handle buttons correctly */
620 
621  PROFILE_BEGIN();
622  while ((i = load_object(fp, op, bufstate, mapflags, false))) {
623  /* Since the loading of the map header does not load an object
624  * anymore, we need to pass LO_NEWFILE for the first object loaded,
625  * and then switch to LO_REPEAT for faster loading.
626  */
627  bufstate = LO_REPEAT;
628 
629  /* if the archetype for the object is null, means that we
630  * got an invalid object. Don't do anything with it - the game
631  * or editor will not be able to do anything with it either.
632  */
633  if (op->arch == NULL) {
634  LOG(llevDebug, "Discarding object without arch: %s\n", op->name ? op->name : "(null)");
635  continue;
636  }
637 
638  /*
639  * You can NOT have players on a map being loaded.
640  * Trying to use such a type leads to crashes everywhere as op->contr is NULL.
641  */
642  if (op->type == PLAYER) {
643  LOG(llevError, "Discarding invalid item with type PLAYER in map %s\n", m->path);
644  continue;
645  }
646 
647  /* don't use out_of_map because we don't want to consider tiling properties, we're loading a single map */
648  if (OUT_OF_REAL_MAP(m, op->x, op->y)) {
649  LOG(llevError, " object %s not on valid map position %s:%d:%d\n", op->name ? op->name : "(null)", m->path, op->x, op->y);
650  if (op->x < 0) {
651  op->x = 0;
652  } else if (op->x >= MAP_WIDTH(m)) {
653  op->x = MAP_WIDTH(m) - 1;
654  }
655  if (op->y < 0) {
656  op->y = 0;
657  } else if (op->y >= MAP_HEIGHT(m)) {
658  op->y = MAP_HEIGHT(m) - 1;
659  }
660  }
661 
662  switch (i) {
663  case LL_NORMAL:
664  /* if we are loading an overlay, put the floors on the bottom */
666  && mapflags&MAP_OVERLAY)
668  else
670 
671  if (op->inv)
672  object_sum_weight(op);
673 
674  prev = op,
675  last_more = op;
676  break;
677 
678  case LL_MORE:
679  if (last_more == NULL) {
680  LOG(llevError, "Error loading map %s from file: multi-part object requires an object before 'more' parts can follow\n",
681  m->path);
682  continue;
683  }
685  op->head = prev,
686  last_more->more = op,
687  last_more = op;
688  break;
689  }
690  if (mapflags&MAP_STYLE) {
692  }
693  op = object_new();
694  op->map = m;
695  }
696  PROFILE_END(diff, LOG(llevDebug,
697  "load_objects on %s took %ld us\n", m->path, diff));
698  for (i = 0; i < m->width; i++) {
699  for (j = 0; j < m->height; j++) {
700  unique = 0;
701  /* check for unique items, or unique squares */
702  FOR_MAP_PREPARE(m, i, j, otmp) {
703  if (QUERY_FLAG(otmp, FLAG_UNIQUE))
704  unique = 1;
705  if (!(mapflags&(MAP_OVERLAY|MAP_PLAYER_UNIQUE) || unique))
707  } FOR_MAP_FINISH();
708  }
709  }
712 }
713 
730 int save_objects(mapstruct *m, FILE *fp, FILE *fp2, int flag) {
731  int i, j = 0, unique = 0;
732  unsigned int count = 0;
733 
736 
737  long serialize_time, write_time;
738 
739  PROFILE_BEGIN();
740 
741  for (i = 0; i < MAP_WIDTH(m); i++) {
742  for (j = 0; j < MAP_HEIGHT(m); j++) {
743  unique = 0;
744  FOR_MAP_PREPARE(m, i, j, op) {
746  unique = 1;
747 
748  if (op->type == PLAYER) {
749  LOG(llevDebug, "Player on map that is being saved\n");
750  continue;
751  }
752 
753  if (op->head || object_get_owner(op) != NULL)
754  continue;
755 
756  if (unique || QUERY_FLAG(op, FLAG_UNIQUE)) {
758  count++ ;
759  } else if (flag == 0
760  || (flag == SAVE_FLAG_NO_REMOVE && (!QUERY_FLAG(op, FLAG_OBJ_ORIGINAL) && !QUERY_FLAG(op, FLAG_UNPAID)))) {
762  count++;
763  }
764  } FOR_MAP_FINISH(); /* for this space */
765  } /* for this j */
766  }
767  PROFILE_END(diff, serialize_time = diff);
768 
769  PROFILE_BEGIN();
770  char *cp = stringbuffer_finish(sb);
771  char *cp2 = stringbuffer_finish(sb2);
772  fputs(cp, fp);
773  fputs(cp2, fp2);
774  free(cp);
775  free(cp2);
776  PROFILE_END(diff, write_time = diff);
777 
778  LOG(llevDebug, "saved %d objects on %s (%ld us serializing, %ld us writing)\n", count, m->path, serialize_time, write_time);
779  return 0;
780 }
781 
792  mapstruct *map = static_cast<mapstruct *>(calloc(1, sizeof(mapstruct)));
793  /* mapstruct *mp;*/
794 
795  if (map == NULL)
797 
798  map->next = first_map;
799  first_map = map;
800 
801  map->in_memory = MAP_SWAPPED;
802 
803  MAP_WIDTH(map) = 16;
804  MAP_HEIGHT(map) = 16;
805  MAP_RESET_TIMEOUT(map) = 0;
806  MAP_ENTER_X(map) = 0;
807  MAP_ENTER_Y(map) = 0;
808  /*set part to -1 indicating conversion to weather map not yet done*/
809  MAP_WORLDPARTX(map)=-1;
810  MAP_WORLDPARTY(map)=-1;
811  map->last_reset_time = 0;
812  return map;
813 }
814 
816 uint32_t map_size(mapstruct *m) {
817  return (uint32_t)m->width * (uint32_t)m->height;
818 }
819 
831  m->in_memory = MAP_IN_MEMORY;
832  /* Log this condition and free the storage. We could I suppose
833  * realloc, but if the caller is presuming the data will be intact,
834  * that is their poor assumption.
835  */
836  if (m->spaces) {
837  LOG(llevError, "allocate_map called with already allocated map (%s)\n", m->path);
838  free(m->spaces);
839  }
840 
841  m->spaces = static_cast<MapSpace *>(calloc(map_size(m), sizeof(MapSpace)));
842 
843  if (m->spaces == NULL)
845 }
846 
860 mapstruct *get_empty_map(int sizex, int sizey) {
862  m->width = sizex;
863  m->height = sizey;
864  m->in_memory = MAP_SWAPPED;
865  allocate_map(m);
866  return m;
867 }
868 
882 static shopitems *parse_shop_string(const char *input_string, const mapstruct *map) {
883  char *shop_string, *p, *q, *next_semicolon, *next_colon;
884  shopitems *items = NULL;
885  int i = 0, number_of_entries = 0;
886  const typedata *current_type;
887 
888  shop_string = strdup_local(input_string);
889  p = shop_string;
890  /* first we'll count the entries, we'll need that for allocating the array shortly */
891  while (p) {
892  p = strchr(p, ';');
893  number_of_entries++;
894  if (p)
895  p++;
896  }
897  p = shop_string;
898  strip_endline(p);
899  items = static_cast<shopitems *>(CALLOC(number_of_entries+1, sizeof(shopitems)));
900  /*
901  * The memset would always set at least one byte to zero,
902  * so a failed calloc would have segfaulted the program.
903  * Instead, check for a null and fail more gracefully.
904  */
905  if (!items)
907 
908  for (i = 0; i < number_of_entries; i++) {
909  if (!p) {
910  LOG(llevError, "parse_shop_string: I seem to have run out of string, that shouldn't happen.\n");
911  break;
912  }
913  next_semicolon = strchr(p, ';');
914  next_colon = strchr(p, ':');
915  /* if there is a stregth specified, figure out what it is, we'll need it soon. */
916  if (next_colon && (!next_semicolon || next_colon < next_semicolon))
917  items[i].strength = atoi(strchr(p, ':')+1);
918 
919  if (isdigit(*p) || *p == '*') {
920  items[i].typenum = *p == '*' ? -1 : atoi(p);
921  current_type = get_typedata(items[i].typenum);
922  if (current_type) {
923  items[i].name = current_type->name;
924  items[i].name_pl = current_type->name_pl;
925  }
926  } else { /*we have a named type, let's figure out what it is */
927  q = strpbrk(p, ";:");
928  if (q)
929  *q = '\0';
930 
931  current_type = get_typedata_by_name(p);
932  if (current_type) {
933  items[i].name = current_type->name;
934  items[i].typenum = current_type->number;
935  items[i].name_pl = current_type->name_pl;
936  } else {
937  /* oh uh, something's wrong, let's free up this one, and try
938  * the next entry while we're at it, better print a warning */
939  LOG(llevError, "invalid type %s defined in shopitems for %s in string %s\n", p, map->name, input_string);
940  }
941  }
942  items[i].index = number_of_entries;
943  if (next_semicolon)
944  p = ++next_semicolon;
945  else
946  p = NULL;
947  }
948  free(shop_string);
949  return items;
950 }
951 
963 static void print_shop_string(mapstruct *m, char *output_string, int size) {
964  int i;
965  char tmp[MAX_BUF];
966 
967  output_string[0] = '\0';
968  for (i = 0; i < m->shopitems[0].index; i++) {
969  if (m->shopitems[i].typenum != -1) {
970  if (m->shopitems[i].strength) {
971  snprintf(tmp, sizeof(tmp), "%s:%d;", m->shopitems[i].name, m->shopitems[i].strength);
972  } else
973  snprintf(tmp, sizeof(tmp), "%s;", m->shopitems[i].name);
974  } else {
975  if (m->shopitems[i].strength) {
976  snprintf(tmp, sizeof(tmp), "*:%d;", m->shopitems[i].strength);
977  } else
978  snprintf(tmp, sizeof(tmp), "*;");
979  }
980  snprintf(output_string+strlen(output_string), size-strlen(output_string), "%s", tmp);
981  }
982 
983  /* erase final ; else parsing back will lead to issues */
984  if (strlen(output_string) > 0) {
985  output_string[strlen(output_string) - 1] = '\0';
986  }
987 }
988 
1005 static int load_map_header(FILE *fp, mapstruct *m) {
1006  char buf[HUGE_BUF], *key = NULL, *value;
1007 
1008  m->width = m->height = 0;
1009  while (fgets(buf, sizeof(buf), fp) != NULL) {
1010  char *p;
1011 
1012  p = strchr(buf, '\n');
1013  if (p == NULL) {
1014  LOG(llevError, "Error loading map header - did not find a newline - perhaps file is truncated? Buf=%s\n", buf);
1015  return 1;
1016  }
1017  *p = '\0';
1018 
1019  key = buf;
1020  while (isspace(*key))
1021  key++;
1022  if (*key == 0)
1023  continue; /* empty line */
1024  value = strchr(key, ' ');
1025  if (value) {
1026  *value = 0;
1027  value++;
1028  while (isspace(*value)) {
1029  value++;
1030  if (*value == '\0') {
1031  /* Nothing but spaces. */
1032  value = NULL;
1033  break;
1034  }
1035  }
1036  }
1037 
1038  /* key is the field name, value is what it should be set
1039  * to. We've already done the work to null terminate key,
1040  * and strip off any leading spaces for both of these.
1041  * We have not touched the newline at the end of the line -
1042  * these are needed for some values. the end pointer
1043  * points to the first of the newlines.
1044  * value could be NULL! It would be easy enough to just point
1045  * this to "" to prevent cores, but that would let more errors slide
1046  * through.
1047  *
1048  * First check for entries that do not use the value parameter, then
1049  * validate that value is given and check for the remaining entries
1050  * that use the parameter.
1051  */
1052 
1053  if (!strcmp(key, "msg")) {
1054  char msgbuf[HUGE_BUF];
1055  int msgpos = 0;
1056 
1057  while (fgets(buf, sizeof(buf), fp) != NULL) {
1058  if (!strcmp(buf, "endmsg\n"))
1059  break;
1060  else {
1061  snprintf(msgbuf+msgpos, sizeof(msgbuf)-msgpos, "%s", buf);
1062  msgpos += strlen(buf);
1063  }
1064  }
1065  /* There are lots of maps that have empty messages (eg, msg/endmsg
1066  * with nothing between). There is no reason in those cases to
1067  * keep the empty message. Also, msgbuf contains garbage data
1068  * when msgpos is zero, so copying it results in crashes
1069  */
1070  if (msgpos != 0) {
1071  /* When loading eg an overlay, message is already set, so free() current one. */
1072  free(m->msg);
1073  m->msg = strdup_local(msgbuf);
1074  }
1075  } else if (!strcmp(key, "maplore")) {
1076  char maplorebuf[HUGE_BUF];
1077  size_t maplorepos = 0;
1078 
1079  while (fgets(buf, HUGE_BUF-1, fp) != NULL) {
1080  if (!strcmp(buf, "endmaplore\n"))
1081  break;
1082  else {
1083  if (maplorepos >= sizeof(maplorebuf)) {
1084  LOG(llevError, "Map lore exceeds buffer length\n");
1085  return 1;
1086  }
1087  snprintf(maplorebuf+maplorepos, sizeof(maplorebuf)-maplorepos, "%s", buf);
1088  maplorepos += strlen(buf);
1089  }
1090  }
1091  if (maplorepos != 0)
1092  m->maplore = strdup_local(maplorebuf);
1093  } else if (!strcmp(key, "end")) {
1094  break;
1095  } else if (value == NULL) {
1096  LOG(llevError, "Got '%s' line without parameter in map header\n", key);
1097  } else if (!strcmp(key, "arch")) {
1098  /* This is an oddity, but not something we care about much. */
1099  if (strcmp(value, "map")) {
1100  LOG(llevError, "load_map_header: expected 'arch map': check line endings?\n");
1101  return 1;
1102  }
1103  } else if (!strcmp(key, "name")) {
1104  /* When loading eg an overlay, the name is already set, so free() current one. */
1105  free(m->name);
1106  m->name = strdup_local(value);
1107  /* first strcmp value on these are old names supported
1108  * for compatibility reasons. The new values (second) are
1109  * what really should be used.
1110  */
1111  } else if (!strcmp(key, "enter_x")) {
1112  m->enter_x = atoi(value);
1113  } else if (!strcmp(key, "enter_y")) {
1114  m->enter_y = atoi(value);
1115  } else if (!strcmp(key, "width")) {
1116  m->width = atoi(value);
1117  } else if (!strcmp(key, "height")) {
1118  m->height = atoi(value);
1119  } else if (!strcmp(key, "reset_timeout")) {
1120  m->reset_timeout = atoi(value);
1121  } else if (!strcmp(key, "swap_time")) {
1122  // deprecated and ignored
1123  } else if (!strcmp(key, "difficulty")) {
1124  m->difficulty = atoi(value);
1125  } else if (!strcmp(key, "darkness")) {
1126  m->darkness = atoi(value);
1127  } else if (!strcmp(key, "fixed_resettime")) {
1128  m->fixed_resettime = atoi(value);
1129  } else if (!strcmp(key, "unique")) {
1130  m->unique = atoi(value);
1131  } else if (!strcmp(key, "template")) {
1132  m->is_template = atoi(value);
1133  } else if (!strcmp(key, "region")) {
1134  m->region = get_region_by_name(value);
1135  } else if (!strcmp(key, "shopitems")) {
1136  m->shopitems = parse_shop_string(value, m);
1137  } else if (!strcmp(key, "shopgreed")) {
1138  m->shopgreed = atof(value);
1139  } else if (!strcmp(key, "shopmin")) {
1140  m->shopmin = atol(value);
1141  } else if (!strcmp(key, "shopmax")) {
1142  m->shopmax = atol(value);
1143  } else if (!strcmp(key, "shoprace")) {
1144  m->shoprace = strdup_local(value);
1145  } else if (!strcmp(key, "outdoor")) {
1146  m->outdoor = atoi(value);
1147  } else if (!strcmp(key, "nosmooth")) {
1148  m->nosmooth = atoi(value);
1149  } else if (!strcmp(key, "first_load")) {
1150  m->last_reset_time = atoi(value);
1151  } else if (!strncmp(key, "tile_path_", 10)) {
1152  int tile = atoi(key+10);
1153 
1154  if (tile < 1 || tile > 4) {
1155  LOG(llevError, "load_map_header: tile location %d out of bounds (%s)\n", tile, m->path);
1156  } else {
1157  if (m->tile_path[tile-1]) {
1158  LOG(llevError, "load_map_header: tile location %d duplicated (%s)\n", tile, m->path);
1159  free(m->tile_path[tile-1]);
1160  }
1161  m->tile_path[tile-1] = strdup_local(value);
1162  } /* end if tile direction (in)valid */
1163  } else if (!strcmp(key, "background_music")) {
1164  m->background_music = strdup_local(value);
1165  } else if (!strcmp(key, "reset_group")) {
1166  m->reset_group = add_string(value);
1167  } else {
1168  LOG(llevError, "Got unknown value in map header: %s %s\n", key, value);
1169  }
1170  }
1171  if ((m->width == 0) || (m->height == 0)) {
1172  LOG(llevError, "Map width or height not specified\n");
1173  return 1;
1174  }
1175  if (!key || strcmp(key, "end")) {
1176  LOG(llevError, "Got premature eof on map header!\n");
1177  return 1;
1178  }
1179  return 0;
1180 }
1181 
1182 void map_path(const char *map, int flags, char *pathname, size_t bufsize) {
1183  if (flags&MAP_PLAYER_UNIQUE) {
1184  snprintf(pathname, bufsize, "%s/%s/%s", settings.localdir, settings.playerdir, map+1);
1185  }
1186  else if (flags&MAP_OVERLAY)
1187  create_overlay_pathname(map, pathname, bufsize);
1188  else
1189  create_pathname(map, pathname, bufsize);
1190 }
1191 
1192 mapstruct *mapfile_load_lowlevel(const char *map, const char *pathname, int flags) {
1193  FILE *fp;
1194  if ((fp = fopen(pathname, "r")) == NULL) {
1196  "Can't open %s: %s\n", pathname, strerror(errno));
1197  return NULL;
1198  }
1199 
1200  mapstruct *m = get_linked_map();
1201  safe_strncpy(m->path, map, HUGE_BUF);
1202  if (load_map_header(fp, m)) {
1203  LOG(llevError, "Error loading map header for %s, flags=%d\n", map, flags);
1204  delete_map(m);
1205  fclose(fp);
1206  return NULL;
1207  }
1208 
1209  allocate_map(m);
1210 
1211  m->in_memory = MAP_LOADING;
1212  load_objects(m, fp, flags & MAP_STYLE);
1213  fclose(fp);
1214  m->in_memory = MAP_IN_MEMORY;
1215  return m;
1216 }
1217 
1233 mapstruct *mapfile_load(const char *map, int flags) {
1234  mapstruct *m;
1235  PROFILE_BEGIN();
1236  char pathname[MAX_BUF];
1237  map_path(map, flags, pathname, sizeof(pathname));
1238  m = mapfile_load_lowlevel(map, pathname, flags);
1239  if (!m) {
1240  return NULL;
1241  }
1242  if (!MAP_DIFFICULTY(m) && (!(flags & MAP_NO_DIFFICULTY)))
1245 
1246  /* In case other objects press some buttons down */
1247  update_buttons(m);
1248 
1250 
1251  if (!(flags & MAP_STYLE))
1252  apply_auto_fix(m); /* Chests which open as default */
1253 
1254  PROFILE_END(diff,
1255  LOG(llevDebug, "mapfile_load on %s" " took %ld us\n", map, diff));
1256 
1258  return (m);
1259 }
1260 
1270  FILE *fp;
1271 
1272  if (!m->tmpname) {
1273  LOG(llevError, "No temporary filename for map %s\n", m->path);
1274  return 1;
1275  }
1276 
1277  if ((fp = fopen(m->tmpname, "r")) == NULL) {
1278  LOG(llevError, "Cannot open %s: %s\n", m->tmpname, strerror(errno));
1279  return 2;
1280  }
1281 
1282  if (load_map_header(fp, m)) {
1283  LOG(llevError, "Error loading map header for %s (%s)\n", m->path, m->tmpname);
1284  fclose(fp);
1285  return 3;
1286  }
1287  allocate_map(m);
1288 
1289  m->in_memory = MAP_LOADING;
1290  load_objects(m, fp, 0);
1291  fclose(fp);
1292  m->in_memory = MAP_IN_MEMORY;
1293  return 0;
1294 }
1295 
1305 int load_overlay_map(const char *filename, mapstruct *m) {
1306  FILE *fp;
1307  char pathname[MAX_BUF];
1308 
1309  create_overlay_pathname(filename, pathname, MAX_BUF);
1310 
1311  if ((fp = fopen(pathname, "r")) == NULL) {
1312  /* nothing bad to not having an overlay */
1313  return 0;
1314  }
1315 
1316  if (load_map_header(fp, m)) {
1317  LOG(llevError, "Error loading map header for overlay %s (%s)\n", m->path, pathname);
1318  fclose(fp);
1319  return 1;
1320  }
1321  /*allocate_map(m);*/
1322 
1323  m->in_memory = MAP_LOADING;
1324  load_objects(m, fp, MAP_OVERLAY);
1325  fclose(fp);
1326  m->in_memory = MAP_IN_MEMORY;
1327  return 0;
1328 }
1329 
1330 /******************************************************************************
1331  * This is the start of unique map handling code
1332  *****************************************************************************/
1333 
1341  int i, j, unique = 0;
1342 
1343  for (i = 0; i < MAP_WIDTH(m); i++)
1344  for (j = 0; j < MAP_HEIGHT(m); j++) {
1345  unique = 0;
1346  FOR_MAP_PREPARE(m, i, j, op) {
1348  unique = 1;
1349  if (op->head == NULL && (QUERY_FLAG(op, FLAG_UNIQUE) || unique)) {
1350  clean_object(op);
1351  if (QUERY_FLAG(op, FLAG_IS_LINKED))
1352  remove_button_link(op);
1353  object_remove(op);
1355  }
1356  } FOR_MAP_FINISH();
1357  }
1358 }
1359 
1366  FILE *fp;
1367  int count;
1368  char name[MAX_BUF], firstname[sizeof(name) + 4];
1369 
1370  create_items_path(m->path, name, MAX_BUF);
1371  for (count = 0; count < 10; count++) {
1372  snprintf(firstname, sizeof(firstname), "%s.v%02d", name, count);
1373  if (!access(firstname, R_OK))
1374  break;
1375  }
1376  /* If we get here, we did not find any map */
1377  if (count == 10)
1378  return;
1379 
1380  if ((fp = fopen(firstname, "r")) == NULL) {
1381  /* There is no expectation that every map will have unique items, but this
1382  * is debug output, so leave it in.
1383  */
1384  LOG(llevDebug, "Can't open unique items file for %s\n", name);
1385  return;
1386  }
1387 
1388  m->in_memory = MAP_LOADING;
1389  if (m->tmpname == NULL) /* if we have loaded unique items from */
1390  delete_unique_items(m); /* original map before, don't duplicate them */
1391  load_object(fp, NULL, LO_NOREAD, 0, false);
1392  load_objects(m, fp, 0);
1393  fclose(fp);
1394  m->in_memory = MAP_IN_MEMORY;
1395 }
1396 
1412 int save_map(mapstruct *m, int flag) {
1413  FILE *fp, *fp2;
1414  OutputFile of, of2;
1415  char filename[MAX_BUF], shop[MAX_BUF];
1416  int i, res;
1417 
1418  if (flag && !*m->path) {
1419  LOG(llevError, "Tried to save map without path.\n");
1420  return SAVE_ERROR_NO_PATH;
1421  }
1422 
1423  PROFILE_BEGIN();
1424 
1425  if (flag != SAVE_MODE_NORMAL || (m->unique) || (m->is_template)) {
1426  if (!m->unique && !m->is_template) { /* flag is set */
1427  if (flag == SAVE_MODE_OVERLAY)
1428  create_overlay_pathname(m->path, filename, MAX_BUF);
1429  else
1430  create_pathname(m->path, filename, MAX_BUF);
1431  } else {
1432  if (m->path[0] != '~') {
1433  LOG(llevError,
1434  "Cannot save unique map '%s' outside of LOCALDIR. Check "
1435  "that all exits to '%s' have FLAG_UNIQUE set correctly.\n",
1436  m->path, m->path);
1437  return SAVE_ERROR_UCREATION;
1438  }
1439  snprintf(filename, sizeof(filename), "%s/%s/%s", settings.localdir, settings.playerdir, m->path+1);
1440  }
1441 
1442  make_path_to_file(filename);
1443  } else {
1444  if (!m->tmpname)
1445  m->tmpname = tempnam(settings.tmpdir, NULL);
1446  strlcpy(filename, m->tmpname, sizeof(filename));
1447  }
1448  m->in_memory = MAP_SAVING;
1449 
1450  fp = of_open(&of, filename);
1451  if (fp == NULL)
1452  return SAVE_ERROR_RCREATION;
1453 
1454  /* legacy */
1455  fprintf(fp, "arch map\n");
1456  if (m->name)
1457  fprintf(fp, "name %s\n", m->name);
1458  if (m->reset_timeout)
1459  fprintf(fp, "reset_timeout %u\n", m->reset_timeout);
1460  if (m->fixed_resettime)
1461  fprintf(fp, "fixed_resettime %d\n", m->fixed_resettime);
1462  /* we unfortunately have no idea if this is a value the creator set
1463  * or a difficulty value we generated when the map was first loaded
1464  */
1465  if (m->difficulty)
1466  fprintf(fp, "difficulty %d\n", m->difficulty);
1467  if (m->region)
1468  fprintf(fp, "region %s\n", m->region->name);
1469  if (m->shopitems) {
1470  print_shop_string(m, shop, sizeof(shop));
1471  fprintf(fp, "shopitems %s\n", shop);
1472  }
1473  if (m->shopgreed)
1474  fprintf(fp, "shopgreed %f\n", m->shopgreed);
1475  if (m->shopmin)
1476  fprintf(fp, "shopmin %" FMT64U "\n", m->shopmin);
1477  if (m->shopmax)
1478  fprintf(fp, "shopmax %" FMT64U "\n", m->shopmax);
1479  if (m->shoprace)
1480  fprintf(fp, "shoprace %s\n", m->shoprace);
1481  if (m->darkness)
1482  fprintf(fp, "darkness %d\n", m->darkness);
1483  if (m->width)
1484  fprintf(fp, "width %d\n", m->width);
1485  if (m->height)
1486  fprintf(fp, "height %d\n", m->height);
1487  if (m->enter_x)
1488  fprintf(fp, "enter_x %d\n", m->enter_x);
1489  if (m->enter_y)
1490  fprintf(fp, "enter_y %d\n", m->enter_y);
1491  if (m->msg)
1492  fprintf(fp, "msg\n%sendmsg\n", m->msg);
1493  if (m->maplore)
1494  fprintf(fp, "maplore\n%sendmaplore\n", m->maplore);
1495  if (m->unique)
1496  fprintf(fp, "unique %d\n", m->unique);
1497  if (m->is_template)
1498  fprintf(fp, "template %d\n", m->is_template);
1499  if (m->outdoor)
1500  fprintf(fp, "outdoor %d\n", m->outdoor);
1501  if (m->nosmooth)
1502  fprintf(fp, "nosmooth %d\n", m->nosmooth);
1503  if (m->last_reset_time)
1504  fprintf(fp, "first_load %ld\n", m->last_reset_time);
1505  if (m->background_music)
1506  fprintf(fp, "background_music %s\n", m->background_music);
1507  if (m->reset_group)
1508  fprintf(fp, "reset_group %s\n", m->reset_group);
1509 
1510  /* Save any tiling information, except on overlays */
1511  if (flag != SAVE_MODE_OVERLAY)
1512  for (i = 0; i < 4; i++)
1513  if (m->tile_path[i])
1514  fprintf(fp, "tile_path_%d %s\n", i+1, m->tile_path[i]);
1515 
1516  fprintf(fp, "end\n");
1517 
1518  /* In the game save unique items in the different file, but
1519  * in the editor save them to the normal map file.
1520  * If unique map, save files in the proper destination (set by
1521  * player)
1522  */
1523  if ((flag == SAVE_MODE_NORMAL || flag == SAVE_MODE_OVERLAY) && !m->unique && !m->is_template) {
1524  char name[MAX_BUF], final_unique[sizeof(name) + 4];
1525 
1526  create_items_path(m->path, name, MAX_BUF);
1527  snprintf(final_unique, sizeof(final_unique), "%s.v00", name);
1528  fp2 = of_open(&of2, final_unique);
1529  if (fp2 == NULL) {
1530  of_cancel(&of);
1531  return SAVE_ERROR_UCREATION;
1532  }
1533  if (flag == SAVE_MODE_OVERLAY) {
1534  /* SO_FLAG_NO_REMOVE is non destructive save, so map is still valid. */
1535  res = save_objects(m, fp, fp2, SAVE_FLAG_NO_REMOVE);
1536  if (res < 0) {
1537  LOG(llevError, "Save error during object save: %d\n", res);
1538  of_cancel(&of);
1539  of_cancel(&of2);
1540  return res;
1541  }
1542  m->in_memory = MAP_IN_MEMORY;
1543  } else {
1544  res = save_objects(m, fp, fp2, 0);
1545  if (res < 0) {
1546  LOG(llevError, "Save error during object save: %d\n", res);
1547  of_cancel(&of);
1548  of_cancel(&of2);
1549  return res;
1550  }
1552  }
1553  if (ftell(fp2) == 0) {
1554  of_cancel(&of2);
1555  /* If there are no unique items left on the map, we need to
1556  * unlink the original unique map so that the unique
1557  * items don't show up again.
1558  */
1559  unlink(final_unique);
1560  } else {
1561  if (!of_close(&of2)) {
1562  of_cancel(&of);
1563  return SAVE_ERROR_URENAME;
1564  }
1565 
1566  if (chmod(final_unique, SAVE_MODE) != 0) {
1567  LOG(llevError, "Could not set permissions on '%s'\n",
1568  final_unique);
1569  }
1570  }
1571  } else { /* save same file when not playing, like in editor */
1572  res = save_objects(m, fp, fp, 0);
1573  if (res < 0) {
1574  LOG(llevError, "Save error during object save: %d\n", res);
1575  of_cancel(&of);
1576  return res;
1577  }
1579  }
1580 
1581  if (!of_close(&of))
1582  return SAVE_ERROR_CLOSE;
1583 
1584  if (chmod(filename, SAVE_MODE) != 0) {
1585  LOG(llevError, "Could not set permissions on '%s'\n", filename);
1586  }
1587 
1588  PROFILE_END(diff,
1589  LOG(llevDebug, "save_map on %s" " took %ld us\n", m->path, diff));
1590 
1591  maps_saved_total++;
1592  return SAVE_ERROR_OK;
1593 }
1594 
1604 void clean_object(object *op) {
1605  FOR_INV_PREPARE(op, tmp) {
1606  clean_object(tmp);
1607  if (QUERY_FLAG(tmp, FLAG_IS_LINKED))
1608  remove_button_link(tmp);
1609  object_remove(tmp);
1611  } FOR_INV_FINISH();
1612 }
1613 
1621  int i, j;
1622  object *op;
1623 
1624  for (i = 0; i < MAP_WIDTH(m); i++)
1625  for (j = 0; j < MAP_HEIGHT(m); j++) {
1626  object *previous_obj = NULL;
1627 
1628  while ((op = GET_MAP_OB(m, i, j)) != NULL) {
1629  if (op == previous_obj) {
1630  LOG(llevDebug, "free_all_objects: Link error, bailing out.\n");
1631  break;
1632  }
1633  previous_obj = op;
1634  op = HEAD(op);
1635 
1636  /* If the map isn't in memory, object_free_drop_inventory() will remove and
1637  * free objects in op's inventory. So let it do the job.
1638  */
1639  if (m->in_memory == MAP_IN_MEMORY)
1640  clean_object(op);
1641  object_remove(op);
1643  }
1644  }
1645 #ifdef MANY_CORES
1646  /* I see periodic cores on metalforge where a map has been swapped out, but apparantly
1647  * an item on that map was not saved - look for that condition and die as appropriate -
1648  * this leaves more of the map data intact for better debugging.
1649  */
1650  for (op = objects; op != NULL; op = op->next) {
1651  if (!QUERY_FLAG(op, FLAG_REMOVED) && op->map == m) {
1652  LOG(llevError, "free_all_objects: object %s still on map after it should have been freed\n", op->name);
1653  abort();
1654  }
1655  }
1656 #endif
1657 }
1658 
1668  int i;
1669 
1670  if (!m->in_memory) {
1671  LOG(llevError, "Trying to free freed map.\n");
1672  return;
1673  }
1674 
1676 
1677  if (m->spaces)
1679  if (m->name)
1680  FREE_AND_CLEAR(m->name);
1681  if (m->spaces)
1682  FREE_AND_CLEAR(m->spaces);
1683  if (m->msg)
1684  FREE_AND_CLEAR(m->msg);
1685  if (m->maplore)
1686  FREE_AND_CLEAR(m->maplore);
1687  if (m->shopitems)
1688  FREE_AND_CLEAR(m->shopitems);
1689  if (m->shoprace)
1690  FREE_AND_CLEAR(m->shoprace);
1691  if (m->background_music)
1692  FREE_AND_CLEAR(m->background_music);
1693  if (m->buttons)
1694  free_objectlinkpt(m->buttons);
1695  m->buttons = NULL;
1696  for (i = 0; i < 4; i++) {
1697  if (m->tile_path[i])
1698  FREE_AND_CLEAR(m->tile_path[i]);
1699  m->tile_map[i] = NULL;
1700  }
1701  m->in_memory = MAP_SWAPPED;
1702 }
1703 
1714  mapstruct *tmp, *last;
1715  int i;
1716 
1717  if (!m)
1718  return;
1719  if (m->in_memory == MAP_IN_MEMORY) {
1720  /* change to MAP_SAVING, even though we are not,
1721  * so that object_remove() doesn't do as much work.
1722  */
1723  m->in_memory = MAP_SAVING;
1724  free_map(m);
1725  }
1726  /* move this out of free_map, since tmpname can still be needed if
1727  * the map is swapped out.
1728  */
1729  free(m->tmpname);
1730  m->tmpname = NULL;
1731  FREE_AND_CLEAR_STR_IF(m->reset_group);
1732  last = NULL;
1733  /* We need to look through all the maps and see if any maps
1734  * are pointing at this one for tiling information. Since
1735  * tiling can be assymetric, we just can not look to see which
1736  * maps this map tiles with and clears those.
1737  */
1738  for (tmp = first_map; tmp != NULL; tmp = tmp->next) {
1739  if (tmp->next == m)
1740  last = tmp;
1741 
1742  /* This should hopefully get unrolled on a decent compiler */
1743  for (i = 0; i < 4; i++)
1744  if (tmp->tile_map[i] == m)
1745  tmp->tile_map[i] = NULL;
1746  }
1747 
1748  /* If last is null, then this should be the first map in the list */
1749  if (!last) {
1750  if (m == first_map)
1751  first_map = m->next;
1752  else
1753  /* m->path is a static char, so should hopefully still have
1754  * some useful data in it.
1755  */
1756  LOG(llevError, "delete_map: Unable to find map %s in list\n", m->path);
1757  } else
1758  last->next = m->next;
1759 
1760  free(m);
1761 }
1762 
1768  // Right now this just sets the fixed swap time.
1769  m->timeout = MAP_MINTIMEOUT;
1770 }
1771 
1785 mapstruct *ready_map_name(const char *name, int flags) {
1786  mapstruct *m;
1787 
1788  if (!name)
1789  return (NULL);
1790 
1791  /* Have we been at this level before? */
1792  m = has_been_loaded(name);
1793 
1794  /* Map is good to go, so just return it */
1795  if (m && (m->in_memory == MAP_LOADING || m->in_memory == MAP_IN_MEMORY)) {
1796  map_reset_swap(m);
1797 
1798  return m;
1799  }
1800 
1801  /* Rewrite old paths starting with LOCALDIR/PLAYERDIR to new '~' paths. */
1802  char buf[MAX_BUF], buf2[MAX_BUF];
1803  snprintf(buf, sizeof(buf), "%s/%s", settings.localdir, settings.playerdir);
1804  if (strncmp(name, buf, strlen(buf)) == 0) {
1805  snprintf(buf2, sizeof(buf2), "~%s", name+strlen(buf)+1);
1806  name = buf2;
1807  }
1808 
1809  /* Paths starting with '~' are unique. */
1810  if (name[0] == '~') {
1812  }
1813 
1814  /* unique maps always get loaded from their original location, and never
1815  * a temp location. Likewise, if map_flush is set, or we have never loaded
1816  * this map, load it now. I removed the reset checking from here -
1817  * it seems the probability of a player trying to enter a map that should
1818  * reset but hasn't yet is quite low, and removing that makes this function
1819  * a bit cleaner (and players probably shouldn't rely on exact timing for
1820  * resets in any case - if they really care, they should use the 'maps command.
1821  */
1822  if ((flags&(MAP_FLUSH|MAP_PLAYER_UNIQUE)) || !m) {
1823  /* first visit or time to reset */
1824  if (m) {
1825  clean_tmp_map(m); /* Doesn't make much difference */
1826  delete_map(m);
1827  }
1828 
1830  if (m == NULL) return NULL;
1831 
1832  /* If a player unique map, no extra unique object file to load.
1833  * if from the editor, likewise.
1834  */
1837 
1839  if (load_overlay_map(name, m) != 0) {
1840  delete_map(m);
1841  m = mapfile_load(name, 0);
1842  if (m == NULL) {
1843  /* Really, this map is bad :( */
1844  return NULL;
1845  }
1846  }
1847  }
1848  } else {
1849  /* If in this loop, we found a temporary map, so load it up. */
1850 
1851  if (load_temporary_map(m) != 0) {
1852  /*
1853  * There was a failure loading the temporary map, fall back to original one.
1854  * load_temporary_map() already logged the error.
1855  */
1856  delete_map(m);
1857  m = mapfile_load(name, 0);
1858  if (m == NULL) {
1859  /* Really, this map is bad :( */
1860  return NULL;
1861  }
1862  }
1864 
1865  clean_tmp_map(m);
1866  m->in_memory = MAP_IN_MEMORY;
1867  /* tempnam() on sun systems (probably others) uses malloc
1868  * to allocated space for the string. Free it here.
1869  * In some cases, load_temporary_map above won't find the
1870  * temporary map, and so has reloaded a new map. If that
1871  * is the case, tmpname is now null
1872  */
1873  free(m->tmpname);
1874  m->tmpname = NULL;
1875  /* It's going to be saved anew anyway */
1876  }
1877 
1878  /* Below here is stuff common to both first time loaded maps and
1879  * temp maps.
1880  */
1881 
1882  decay_objects(m); /* start the decay */
1883 
1884  if (m->outdoor) {
1886  }
1887  if (!(flags&(MAP_FLUSH))) {
1888  if (m->last_reset_time == 0) {
1889  m->last_reset_time = seconds();
1890  }
1891  }
1892 
1893  /* Randomize monsters direction and animation state */
1894 
1895  if (!(flags & MAP_STYLE)) {
1896  for (int x = 0; x < MAP_WIDTH(m); x++)
1897  for (int y = 0; y < MAP_HEIGHT(m); y++)
1898  FOR_MAP_PREPARE(m, x, y, op) {
1899  if (!op->head && QUERY_FLAG(op, FLAG_MONSTER) && (op->direction == 0 || op->facing == 0)) {
1900  if (op->animation) {
1901  auto facings = NUM_FACINGS(op);
1902  op->facing = facings > 1 ? 1 + (cf_random() % facings) : 1;
1903  op->direction = op->facing;
1904  const int max_state = NUM_ANIMATIONS(op) / facings;
1905  op->state = max_state > 1 ? cf_random() % max_state : 0;
1906  animate_object(op, op->direction);
1907  }
1908  }
1909  } FOR_MAP_FINISH();
1910 
1911  }
1912 
1913  map_reset_swap(m);
1915 
1916  return m;
1917 }
1918 
1935  archetype *at;
1936  int x, y;
1937  int diff = 0;
1938  int i;
1939  int64_t exp_pr_sq, total_exp = 0;
1940 
1941  if (MAP_DIFFICULTY(m)) {
1942  return MAP_DIFFICULTY(m);
1943  }
1944 
1945  for (x = 0; x < MAP_WIDTH(m); x++)
1946  for (y = 0; y < MAP_HEIGHT(m); y++)
1947  FOR_MAP_PREPARE(m, x, y, op) {
1948  if (QUERY_FLAG(op, FLAG_MONSTER))
1949  total_exp += op->stats.exp;
1950  if (QUERY_FLAG(op, FLAG_GENERATOR)) {
1951  total_exp += op->stats.exp;
1952  // If we have an other_arch on our generator, just use that.
1953  // FIXME: Figure out what to do if we are doing template generation from inventory.
1954  at = op->other_arch ? op->other_arch : NULL;
1955  if (at != NULL) {
1956  // Make sure we can't set off a null pointer dereference in atoi().
1957  const char *val = object_get_value(op, "generator_limit");
1958  int lim = atoi(val ? val : "0");
1959  // We assume, on average, the generator will generate half its contents.
1960  if (!lim || lim >= 16)
1961  total_exp += at->clone.stats.exp*8;
1962  else
1963  total_exp += at->clone.stats.exp*(lim/2);
1964  }
1965  }
1966  } FOR_MAP_FINISH();
1967  // Used to be multiplied by 1000, but this undershot horribly
1968  // once I fixed the calculation for generators.
1969  // I'm trying out some exponentiation, since linear scaling
1970  // seems to overshoot low-level maps and undershoot high-level maps.
1971  // I also feel comfortable, knowing that generators return
1972  // sensible values, to up the max diff this calculates from 20 to 25.
1973  // - Neila Hawkins 2021-03-04
1974  exp_pr_sq = (pow(total_exp, 1.75))/(MAP_WIDTH(m)*MAP_HEIGHT(m)+1);
1975  diff = 25;
1976  for (i = 1; i < 25; i++)
1977  if (exp_pr_sq <= level_exp(i, 1.0)) {
1978  diff = i;
1979  break;
1980  }
1981 
1982  return diff;
1983 }
1984 
1992  if (m->tmpname == NULL)
1993  return;
1994  (void)unlink(m->tmpname);
1995 }
1996 
2000 void free_all_maps(void) {
2001  int real_maps = 0;
2002 
2003  while (first_map) {
2004  /* I think some of the callers above before it gets here set this to be
2005  * saving, but we still want to free this data
2006  */
2007  if (first_map->in_memory == MAP_SAVING)
2010  real_maps++;
2011  }
2012  LOG(llevDebug, "free_all_maps: Freed %d maps\n", real_maps);
2013 }
2014 
2032 int change_map_light(mapstruct *m, int change) {
2033  int new_level = m->darkness+change;
2034 
2035  /* Nothing to do */
2036  if (!change
2037  || (new_level <= 0 && m->darkness == 0)
2038  || (new_level >= MAX_DARKNESS && m->darkness >= MAX_DARKNESS)) {
2039  return 0;
2040  }
2041 
2042  /* inform all players on the map */
2043  if (change > 0)
2044  ext_info_map(NDI_BLACK, m, MSG_TYPE_MISC, MSG_SUBTYPE_NONE, "It becomes darker.");
2045  else
2046  ext_info_map(NDI_BLACK, m, MSG_TYPE_MISC, MSG_SUBTYPE_NONE, "It becomes brighter.");
2047 
2048  /* Do extra checking. since m->darkness is a unsigned value,
2049  * we need to be extra careful about negative values.
2050  * In general, the checks below are only needed if change
2051  * is not +/-1
2052  */
2053  if (new_level < 0)
2054  m->darkness = 0;
2055  else if (new_level >= MAX_DARKNESS)
2056  m->darkness = MAX_DARKNESS;
2057  else
2058  m->darkness = new_level;
2059 
2060  /* All clients need to get re-updated for the change */
2062  return 1;
2063 }
2064 
2087 static inline void add_face_layer(int low_layer, int high_layer, object *ob, object *layers[], int honor_visibility) {
2088  int l, l1;
2089  object *tmp;
2090 
2091  for (l = low_layer; l <= high_layer; l++) {
2092  if (!layers[l]) {
2093  /* found an empty spot. now, we want to make sure
2094  * highest visibility at top, etc.
2095  */
2096  layers[l] = ob;
2097  if (!honor_visibility)
2098  return;
2099 
2100  /* This is basically a mini bubble sort. Only swap
2101  * position if the lower face has greater (not equal)
2102  * visibility - map stacking is secondary consideration here.
2103  */
2104  for (l1 = (l-1); l1 >= low_layer; l1--) {
2105  if (layers[l1]->face->visibility > layers[l1+1]->face->visibility) {
2106  tmp = layers[l1+1];
2107  layers[l1+1] = layers[l1];
2108  layers[l1] = tmp;
2109  }
2110  }
2111  /* Nothing more to do - face inserted */
2112  return;
2113  }
2114  }
2115  /* If we get here, all the layers have an object..
2116  */
2117  if (!honor_visibility) {
2118  /* Basically, in this case, it is pure stacking logic, so
2119  * new object goes on the top.
2120  */
2121  for (l = low_layer; l < high_layer; l++)
2122  layers[l] = layers[l+1];
2123  layers[high_layer] = ob;
2124  /* If this object doesn't have higher visibility than
2125  * the lowest object, no reason to go further.
2126  */
2127  } else if (ob->face->visibility >= layers[low_layer]->face->visibility) {
2128  /*
2129  * Start at the top (highest visibility) layer and work down.
2130  * once this face exceed that of the layer, push down those
2131  * other layers, and then replace the layer with our object.
2132  */
2133  for (l = high_layer; l >= low_layer; l--) {
2134  if (ob->face->visibility >= layers[l]->face->visibility) {
2135  for (l1 = low_layer; l1 < l; l1++)
2136  layers[l1] = layers[l1+1];
2137  layers[l] = ob;
2138  break;
2139  }
2140  }
2141  }
2142 }
2143 
2156 void update_position(mapstruct *m, int x, int y) {
2157  object *player = NULL;
2158  uint8_t flags = 0, oldflags, light = 0;
2159  object *layers[MAP_LAYERS];
2160 
2161  MoveType move_block = 0, move_slow = 0, move_on = 0, move_off = 0, move_allow = 0;
2162 
2163  oldflags = GET_MAP_FLAGS(m, x, y);
2164  if (!(oldflags&P_NEED_UPDATE)) {
2165  LOG(llevDebug, "update_position called with P_NEED_UPDATE not set: %s (%d, %d)\n", m->path, x, y);
2166  return;
2167  }
2168 
2169  memset(layers, 0, MAP_LAYERS*sizeof(object *));
2170 
2171  FOR_MAP_PREPARE(m, x, y, tmp) {
2172  /* DMs just don't do anything when hidden, including no light. */
2173  if (QUERY_FLAG(tmp, FLAG_WIZ) && tmp->contr->hidden)
2174  continue;
2175 
2176  if (tmp->type == PLAYER)
2177  player = tmp;
2178 
2179  /* This could be made additive I guess (two lights better than
2180  * one). But if so, it shouldn't be a simple additive - 2
2181  * light bulbs do not illuminate twice as far as once since
2182  * it is a dissipation factor that is squared (or is it cubed?)
2183  */
2184  if (tmp->glow_radius > light)
2185  light = tmp->glow_radius;
2186 
2187  /* if this object is visible and not a blank face,
2188  * update the objects that show how this space
2189  * looks.
2190  */
2191  if (!tmp->invisible && tmp->face != blank_face) {
2192  if (tmp->map_layer) {
2193  add_face_layer(tmp->map_layer, map_layer_info[tmp->map_layer].high_layer,
2194  tmp, layers, map_layer_info[tmp->map_layer].honor_visibility);
2195  } else if (tmp->move_type&MOVE_FLYING) {
2196  add_face_layer(MAP_LAYER_FLY1, MAP_LAYER_FLY2, tmp, layers, 1);
2197  } else if ((tmp->type == PLAYER || QUERY_FLAG(tmp, FLAG_MONSTER) || QUERY_FLAG(tmp, FLAG_CAN_ROLL))) {
2198  // Put things that are likely to move on the LIVING layers
2200  } else if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
2201  layers[MAP_LAYER_FLOOR] = tmp;
2202  /* floors hide everything else */
2203  memset(layers+1, 0, (MAP_LAYERS-1)*sizeof(object *));
2204  /* Check for FLAG_SEE_ANYWHERE is removed - objects
2205  * with that flag should just have a high visibility
2206  * set - we shouldn't need special code here.
2207  */
2208  } else if (QUERY_FLAG(tmp, FLAG_NO_PICK)) {
2210  } else {
2212  }
2213  }
2214  if (tmp == tmp->above) {
2215  LOG(llevError, "Error in structure of map\n");
2216  exit(-1);
2217  }
2218 
2219  move_slow |= tmp->move_slow;
2220  move_block |= tmp->move_block;
2221  move_on |= tmp->move_on;
2222  move_off |= tmp->move_off;
2223  move_allow |= tmp->move_allow;
2224 
2225  if (QUERY_FLAG(tmp, FLAG_ALIVE))
2226  flags |= P_IS_ALIVE;
2227  if (QUERY_FLAG(tmp, FLAG_NO_MAGIC))
2228  flags |= P_NO_MAGIC;
2230  flags |= P_NO_CLERIC;
2231 
2232  if (QUERY_FLAG(tmp, FLAG_BLOCKSVIEW))
2233  flags |= P_BLOCKSVIEW;
2234  } FOR_MAP_FINISH(); /* for stack of objects */
2235 
2236  if (player)
2237  flags |= P_PLAYER;
2238 
2239  /* we don't want to rely on this function to have accurate flags, but
2240  * since we're already doing the work, we calculate them here.
2241  * if they don't match, logic is broken someplace.
2242  */
2243  if (((oldflags&~(P_NEED_UPDATE|P_NO_ERROR)) != flags)
2244  && (!(oldflags&P_NO_ERROR))) {
2245  LOG(llevDebug, "update_position: updated flags do not match old flags: %s (x=%d,y=%d) %x != %x\n",
2246  m->path, x, y, (oldflags&~P_NEED_UPDATE), flags);
2247  }
2248 
2249  SET_MAP_FLAGS(m, x, y, flags);
2250  SET_MAP_MOVE_BLOCK(m, x, y, move_block&~move_allow);
2251  SET_MAP_MOVE_ON(m, x, y, move_on);
2252  SET_MAP_MOVE_OFF(m, x, y, move_off);
2253  SET_MAP_MOVE_SLOW(m, x, y, move_slow);
2254  SET_MAP_LIGHT(m, x, y, light);
2255 
2256  /* Note that player may be NULL here, which is fine - if no player, need
2257  * to clear any value that may be set.
2258  */
2259  SET_MAP_PLAYER(m, x, y, player);
2260 
2261  /* Note it is intentional we copy everything, including NULL values. */
2262  memcpy(GET_MAP_FACE_OBJS(m, x, y), layers, sizeof(object *)*MAP_LAYERS);
2263 }
2264 
2272  int timeout;
2273 
2274  timeout = MAP_RESET_TIMEOUT(map);
2275  if (timeout <= 0)
2276  timeout = MAP_DEFAULTRESET;
2277  if (timeout >= MAP_MAXRESET)
2278  timeout = MAP_MAXRESET;
2279  MAP_RESET_TIMEOUT(map) = timeout;
2280  MAP_WHEN_RESET(map) = seconds()+timeout;
2281 }
2282 
2297 static mapstruct *load_and_link_tiled_map(mapstruct *orig_map, int tile_num) {
2298  int dest_tile = (tile_num+2)%4;
2299  char path[HUGE_BUF];
2300 
2301  path_combine_and_normalize(orig_map->path, orig_map->tile_path[tile_num], path, sizeof(path));
2302 
2303  orig_map->tile_map[tile_num] = ready_map_name(path, 0);
2304  if (orig_map->tile_map[tile_num] == NULL) {
2305  LOG(llevError, "%s has invalid tiled map %s\n", orig_map->path, path);
2306  free(orig_map->tile_path[tile_num]);
2307  orig_map->tile_path[tile_num] = NULL;
2308  return NULL;
2309  }
2310 
2311  /* need to do a strcmp here as the orig_map->path is not a shared string */
2312  if (orig_map->tile_map[tile_num]->tile_path[dest_tile]
2313  && !strcmp(orig_map->tile_map[tile_num]->tile_path[dest_tile], orig_map->path))
2314  orig_map->tile_map[tile_num]->tile_map[dest_tile] = orig_map;
2315 
2316  return orig_map->tile_map[tile_num];
2317 }
2318 
2332 int out_of_map(mapstruct *m, int x, int y) {
2333  int16_t xp = x, yp = y;
2334  if (get_map_from_coord(m, &xp, &yp) == NULL) {
2335  return 1;
2336  } else {
2337  return 0;
2338  }
2339 }
2340 
2360 mapstruct *get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y) {
2361 
2362  /* Simple case - coordinates are within this local
2363  * map.
2364  */
2365 
2366  if ( !m ) return NULL;
2367  if (m->in_memory == MAP_SWAPPED) {
2368  // callers are calling get_map_from_coord() to access the map, so if
2369  // it's swapped out return early here. While we could finish this
2370  // computation without having to swap the map in, when they try to
2371  // get/set it will abort()
2372  //
2373  // This should never happen (if it did, the swapper is buggy) but it
2374  // does actually happen because of object recycling (e.g. op->enemy
2375  // points to a completely different object on a swapped out map)
2376  return NULL;
2377  }
2378  if (!OUT_OF_REAL_MAP(m, *x, *y))
2379  return m;
2380 
2381  do /* With the first case there, we can assume we are out of the map if we get here */
2382  {
2383  // Figure out what map should be in the direction we are off the map, and then
2384  // load that map and look again.
2385  if (*x < 0) {
2386  if (!m->tile_path[3])
2387  return NULL;
2388  if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY){
2390  /* Make sure we loaded properly. */
2391  if (!m->tile_map[3])
2392  return NULL;
2393  }
2394  *x += MAP_WIDTH(m->tile_map[3]);
2395  m = m->tile_map[3];
2396  }
2397  else if (*x >= MAP_WIDTH(m)) {
2398  if (!m->tile_path[1])
2399  return NULL;
2400  if (!m->tile_map[1] || m->tile_map[1]->in_memory != MAP_IN_MEMORY){
2402  /* Make sure we loaded properly. */
2403  if (!m->tile_map[1])
2404  return NULL;
2405  }
2406  *x -= MAP_WIDTH(m);
2407  m = m->tile_map[1];
2408  }
2409  // It is possible that x and y be considered separate compare groups,
2410  // But using an else-if here retains the old behavior that recursion produced.
2411  else if (*y < 0) {
2412  if (!m->tile_path[0])
2413  return NULL;
2414  if (!m->tile_map[0] || m->tile_map[0]->in_memory != MAP_IN_MEMORY){
2416  /* Make sure we loaded properly. */
2417  if (!m->tile_map[0])
2418  return NULL;
2419  }
2420  *y += MAP_HEIGHT(m->tile_map[0]);
2421  m = m->tile_map[0];
2422  }
2423  else if (*y >= MAP_HEIGHT(m)) {
2424  if (!m->tile_path[2])
2425  return NULL;
2426  if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY){
2428  /* Make sure we loaded properly. */
2429  if (!m->tile_map[2])
2430  return NULL;
2431  }
2432  *y -= MAP_HEIGHT(m);
2433  m = m->tile_map[2];
2434  }
2435  // The check here is if our single tile is in the map.
2436  // That is exactly what the OUT_OF_MAP macro does.
2437  } while (OUT_OF_REAL_MAP(m, *x, *y));
2438  return m; /* We have found our map */
2439 }
2440 
2454 static int adjacent_map(const mapstruct *map1, const mapstruct *map2, int *dx, int *dy) {
2455  if (!map1 || !map2)
2456  return 0;
2457 
2458  if (map1 == map2) {
2459  *dx = 0;
2460  *dy = 0;
2461  } else if (map1->tile_map[0] == map2) { /* up */
2462  *dx = 0;
2463  *dy = -MAP_HEIGHT(map2);
2464  } else if (map1->tile_map[1] == map2) { /* right */
2465  *dx = MAP_WIDTH(map1);
2466  *dy = 0;
2467  } else if (map1->tile_map[2] == map2) { /* down */
2468  *dx = 0;
2469  *dy = MAP_HEIGHT(map1);
2470  } else if (map1->tile_map[3] == map2) { /* left */
2471  *dx = -MAP_WIDTH(map2);
2472  *dy = 0;
2473  } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[1] == map2) { /* up right */
2474  *dx = MAP_WIDTH(map1->tile_map[0]);
2475  *dy = -MAP_HEIGHT(map1->tile_map[0]);
2476  } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[3] == map2) { /* up left */
2477  *dx = -MAP_WIDTH(map2);
2478  *dy = -MAP_HEIGHT(map1->tile_map[0]);
2479  } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[0] == map2) { /* right up */
2480  *dx = MAP_WIDTH(map1);
2481  *dy = -MAP_HEIGHT(map2);
2482  } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[2] == map2) { /* right down */
2483  *dx = MAP_WIDTH(map1);
2484  *dy = MAP_HEIGHT(map1->tile_map[1]);
2485  } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[1] == map2) { /* down right */
2486  *dx = MAP_WIDTH(map1->tile_map[2]);
2487  *dy = MAP_HEIGHT(map1);
2488  } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[3] == map2) { /* down left */
2489  *dx = -MAP_WIDTH(map2);
2490  *dy = MAP_HEIGHT(map1);
2491  } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[0] == map2) { /* left up */
2492  *dx = -MAP_WIDTH(map1->tile_map[3]);
2493  *dy = -MAP_HEIGHT(map2);
2494  } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[2] == map2) { /* left down */
2495  *dx = -MAP_WIDTH(map1->tile_map[3]);
2496  *dy = MAP_HEIGHT(map1->tile_map[3]);
2497  } else { /* not "adjacent" enough */
2498  return 0;
2499  }
2500 
2501  return 1;
2502 }
2503 
2531 int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags) {
2532  if (!adjacent_map(op1->map, op2->map, &retval->distance_x, &retval->distance_y)) {
2533  /* be conservative and fill in _some_ data */
2534  retval->distance = 100000;
2535  retval->distance_x = 32767;
2536  retval->distance_y = 32767;
2537  retval->direction = 0;
2538  retval->part = NULL;
2539  return 0;
2540  } else {
2541  object *best;
2542 
2543  retval->distance_x += op2->x-op1->x;
2544  retval->distance_y += op2->y-op1->y;
2545 
2546  best = op1;
2547  /* If this is multipart, find the closest part now */
2548  if (!(flags&0x1) && op1->more) {
2549  object *tmp;
2550  int best_distance = retval->distance_x*retval->distance_x+
2551  retval->distance_y*retval->distance_y, tmpi;
2552 
2553  /* we just take the offset of the piece to head to figure
2554  * distance instead of doing all that work above again
2555  * since the distance fields we set above are positive in the
2556  * same axis as is used for multipart objects, the simply arithmetic
2557  * below works.
2558  */
2559  for (tmp = op1->more; tmp != NULL; tmp = tmp->more) {
2560  tmpi = (op1->x-tmp->x+retval->distance_x)*(op1->x-tmp->x+retval->distance_x)+
2561  (op1->y-tmp->y+retval->distance_y)*(op1->y-tmp->y+retval->distance_y);
2562  if (tmpi < best_distance) {
2563  best_distance = tmpi;
2564  best = tmp;
2565  }
2566  }
2567  if (best != op1) {
2568  retval->distance_x += op1->x-best->x;
2569  retval->distance_y += op1->y-best->y;
2570  }
2571  }
2572  retval->part = best;
2573  retval->distance = ihypot(retval->distance_x, retval->distance_y);
2574  retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y);
2575  return 1;
2576  }
2577 }
2578 
2599 int get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval) {
2600  if (!adjacent_map(m, op2->map, &retval->distance_x, &retval->distance_y)) {
2601  /* be conservative and fill in _some_ data */
2602  retval->distance = 100000;
2603  retval->distance_x = 32767;
2604  retval->distance_y = 32767;
2605  retval->direction = 0;
2606  retval->part = NULL;
2607  return 0;
2608  } else {
2609  retval->distance_x += op2->x-x;
2610  retval->distance_y += op2->y-y;
2611 
2612  retval->part = NULL;
2613  retval->distance = isqrt(retval->distance_x*retval->distance_x+retval->distance_y*retval->distance_y);
2614  retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y);
2615  return 1;
2616  }
2617 }
2618 
2637 int on_same_map(const object *op1, const object *op2) {
2638  int dx, dy;
2639 
2640  return adjacent_map(op1->map, op2->map, &dx, &dy);
2641 }
2642 
2660 object *map_find_by_flag(mapstruct *map, int x, int y, int flag) {
2661  object *tmp;
2662 
2663  for (tmp = GET_MAP_OB(map, x, y); tmp != NULL; tmp = tmp->above) {
2664  object *head;
2665 
2666  head = HEAD(tmp);
2667  if (QUERY_FLAG(head, flag))
2668  return head;
2669  }
2670  return NULL;
2671 }
2672 
2678  char base[HUGE_BUF], path[sizeof(base) + 4];
2679  int count;
2680 
2681  if (map->unique) {
2682  snprintf(path, sizeof(path), "%s/%s/%s", settings.localdir, settings.playerdir, map->path+1);
2683  if (unlink(path) != 0) {
2684  LOG(llevError, "Could not delete %s: %s\n", path, strerror(errno));
2685  }
2686  return;
2687  }
2688 
2689  create_items_path(map->path, base, sizeof(base));
2690 
2691  for (count = 0; count < 10; count++) {
2692  snprintf(path, sizeof(path), "%s.v%02d", base, count);
2693  unlink(path);
2694  }
2695 }
2696 
2702 const char *map_get_path(const object *item) {
2703  if (item->map != NULL) {
2704  if (strlen(item->map->path) > 0) {
2705  return item->map->path;
2706  }
2707 
2708  return item->map->name ? item->map->name : "(empty path and name)";
2709  }
2710 
2711  if (item->env != NULL)
2712  return map_get_path(item->env);
2713 
2714  return "(no map and no env!)";
2715 }
2716 
2722 bool map_path_unique(const char *path) {
2723  return path != NULL && path[0] == '~';
2724 }
2725 
2726 MapSpace *map_space(const mapstruct *m, int x, int y) {
2727  if (m->spaces == NULL) // guard against map being swapped out
2728  abort();
2729  if (OUT_OF_REAL_MAP(m, x, y)) // array out of bounds check
2730  abort();
2731  return &m->spaces[x + m->width * y];
2732 }
2733 
2738 int map_light_on(mapstruct *m, int x, int y) {
2739  /* Check the spaces with the max light radius to see if any of them
2740  * have lights, and if any of them light the player enough, then return 1.
2741  */
2742  for (int i = x - MAX_LIGHT_RADII; i <= x + MAX_LIGHT_RADII; i++) {
2743  for (int j = y - MAX_LIGHT_RADII; j <= y + MAX_LIGHT_RADII; j++) {
2744  int16_t nx = i;
2745  int16_t ny = j;
2746  auto real = get_map_from_coord(m, &nx, &ny);
2747  if (real == nullptr)
2748  continue;
2749 
2750  int light = GET_MAP_LIGHT(real, nx, ny);
2751  if (light == 0)
2752  continue;
2753 
2754  if (ihypot(i - x, j - y) < light)
2755  return 1;
2756  }
2757  }
2758 
2759  return 0;
2760 }
2761 
2765 bool coords_in_shop(mapstruct *map, int x, int y) {
2766  FOR_MAP_PREPARE(map, x, y, floor)
2767  if (floor->type == SHOP_FLOOR) return true;
2768  FOR_MAP_FINISH();
2769  return false;
2770 }
2771 
2772 bool shop_contains(object *ob) {
2773  if (!ob->map) return 0;
2774  return coords_in_shop(ob->map, ob->x, ob->y);
2775 }
mapstruct::tile_path
char * tile_path[4]
Path to adjoining maps.
Definition: map.h:359
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:563
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:1305
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:860
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:166
get_region_by_name
region * get_region_by_name(const char *region_name)
Gets a region by name.
Definition: region.cpp:45
of_open
FILE * of_open(OutputFile *of, const char *fname)
Opens an output file.
Definition: output_file.cpp:30
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:354
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:1340
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:1785
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:1269
ob_move_block
bool ob_move_block(object *ob1, object *ob2)
Basic macro to see if ob2 blocks ob1 from moving onto this space.
Definition: map.cpp:327
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:963
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:2156
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:2738
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:2087
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:1182
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
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:1604
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:366
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:245
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:381
object::title
sstring title
Of foo, etc.
Definition: object.h:325
mapstruct::path
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:361
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:2000
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:342
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:219
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
rv_vector::distance_y
int distance_y
Y delta.
Definition: map.h:379
map_remove_unique_files
void map_remove_unique_files(const mapstruct *map)
Remove files containing the map's unique items.
Definition: map.cpp:2677
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:730
PROFILE_END
#define PROFILE_END(var, expr)
Definition: global.h:371
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:373
rv_vector::distance_x
int distance_x
X delta.
Definition: map.h:378
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:260
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:816
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:782
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:1365
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:1991
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:2032
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:336
mapfile_load_lowlevel
mapstruct * mapfile_load_lowlevel(const char *map, const char *pathname, int flags)
Definition: map.cpp:1192
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:2332
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:28
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:693
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:1667
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:1620
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:2360
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:2599
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:2660
delete_map
void delete_map(mapstruct *m)
Frees the map, including the mapstruct.
Definition: map.cpp:1713
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:489
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:362
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:585
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:791
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
create_template_pathname
void create_template_pathname(const char *name, char *buf, size_t size)
same as create_pathname(), but for the template maps.
Definition: map.cpp:145
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:222
map_space
MapSpace * map_space(const mapstruct *m, int x, int y)
Definition: map.cpp:2726
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:2271
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:2297
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:1005
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:2454
Face::visibility
uint8_t visibility
How visible is the face compared to other faces, highest wins.
Definition: face.h:16
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_.
Definition: map.cpp:300
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
shop_contains
bool shop_contains(object *ob)
Check if an object is in a shop.
Definition: map.cpp:2772
mapstruct::in_memory
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:340
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:376
update_buttons
void update_buttons(mapstruct *m)
Updates every button on the map (by calling update_button() for them).
Definition: button.cpp:227
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:2702
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:2637
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:2722
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:360
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:350
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:2531
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:830
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
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:544
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
Settings::templatedir
const char * templatedir
Directory for the template map.
Definition: global.h:259
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
make_path_to_file
void make_path_to_file(const char *filename)
Checks if any directories in the given path doesn't exist, and creates if necessary.
Definition: porting.cpp:164
mapstruct::unique
uint32_t unique
If set, this is a per player unique map.
Definition: map.h:333
save_map
int save_map(mapstruct *m, int flag)
Saves a map to file.
Definition: map.cpp:1412
calculate_difficulty
int calculate_difficulty(mapstruct *m)
This routine is supposed to find out the difficulty of the map.
Definition: map.cpp:1934
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:260
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:1233
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:882
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:380
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:377
map_reset_swap
void map_reset_swap(mapstruct *m)
Call this when an in-memory map is used or referenced.
Definition: map.cpp:1767
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:201
S_IRGRP
#define S_IRGRP
Definition: win32.h:53
MAX_LIGHT_RADII
#define MAX_LIGHT_RADII
Max radii for 'light' object, really large values allow objects that can slow down the game.
Definition: define.h:435
dump_all_maps
void dump_all_maps(void)
Prints out debug-information about all maps.
Definition: map.cpp:268
events_execute_global_event
void events_execute_global_event(int eventcode,...)
Execute a global event.
Definition: events.cpp:30
load_objects
void load_objects(mapstruct *m, FILE *fp, int mapflags)
Loads (and parses) the objects into a given map from the specified file pointer.
Definition: map.cpp:613
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:2765
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