Crossfire Server, Trunk
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 
38 static void free_all_objects(mapstruct *m);
39 
45 const char *const map_layer_name[MAP_LAYERS] = {
46  "floor", "no_pick", "no_pick", "item", "item",
47  "item", "living", "living", "fly", "fly"
48 };
49 
52  uint8_t high_layer;
53  uint8_t honor_visibility;
54 };
55 
63  { MAP_LAYER_FLOOR, 1 },
65  { MAP_LAYER_ITEM3, 1 }, { MAP_LAYER_ITEM3, 1 }, { MAP_LAYER_ITEM3, 1 },
66  { MAP_LAYER_LIVING2, 1 }, { MAP_LAYER_LIVING2, 1 },
67  { MAP_LAYER_FLY2, 1 }, { MAP_LAYER_FLY2, 1 }
68 };
69 
79  mapstruct *map;
80 
81  if (!name || !*name)
82  return NULL;
83 
84  for (map = first_map; map; map = map->next)
85  if (!strcmp(name, map->path))
86  break;
87  return (map);
88 }
89 
103 char *create_pathname(const char *name, char *buf, size_t size) {
104  /* Why? having extra / doesn't confuse unix anyplace? Dependancies
105  * someplace else in the code? msw 2-17-97
106  */
107  if (*name == '/')
108  snprintf(buf, size, "%s/%s%s", settings.datadir, settings.mapdir, name);
109  else
110  snprintf(buf, size, "%s/%s/%s", settings.datadir, settings.mapdir, name);
111  return buf;
112 }
113 
124 void create_overlay_pathname(const char *name, char *buf, size_t size) {
125  /* Why? having extra / doesn't confuse unix anyplace? Dependancies
126  * someplace else in the code? msw 2-17-97
127  */
128  if (*name == '/')
129  snprintf(buf, size, "%s/%s%s", settings.localdir, settings.mapdir, name);
130  else
131  snprintf(buf, size, "%s/%s/%s", settings.localdir, settings.mapdir, name);
132 }
133 
144 void create_template_pathname(const char *name, char *buf, size_t size) {
145  /* Why? having extra / doesn't confuse unix anyplace? Dependancies
146  * someplace else in the code? msw 2-17-97
147  */
148  if (*name == '/')
149  snprintf(buf, size, "%s/%s%s", settings.localdir, settings.templatedir, name);
150  else
151  snprintf(buf, size, "%s/%s/%s", settings.localdir, settings.templatedir, name);
152 }
153 
165 static void create_items_path(const char *s, char *buf, size_t size) {
166  char *t;
167 
168  if (*s == '/')
169  s++;
170 
171  snprintf(buf, size, "%s/%s/", settings.localdir, settings.uniquedir);
172  t = buf+strlen(buf);
173  snprintf(t, buf+size-t, "%s", s);
174 
175  while (*t != '\0') {
176  if (*t == '/')
177  *t = '@';
178  t++;
179  }
180 }
181 
200 int check_path(const char *name, int prepend_dir) {
201  char buf[MAX_BUF];
202 #ifndef WIN32
203  struct stat statbuf;
204  int mode = 0;
205 #endif
206 
207  if (prepend_dir)
209  else
210  strlcpy(buf, name, sizeof(buf));
211 #ifdef WIN32 /* ***win32: check this sucker in windows style. */
212  return(_access(buf, 0));
213 #else
214 
215  if (stat(buf, &statbuf) != 0)
216  return -1;
217 
218  if (!S_ISREG(statbuf.st_mode))
219  return (-1);
220 
221  if (((statbuf.st_mode&S_IRGRP) && getegid() == statbuf.st_gid)
222  || ((statbuf.st_mode&S_IRUSR) && geteuid() == statbuf.st_uid)
223  || (statbuf.st_mode&S_IROTH))
224  mode |= 4;
225 
226  if ((statbuf.st_mode&S_IWGRP && getegid() == statbuf.st_gid)
227  || (statbuf.st_mode&S_IWUSR && geteuid() == statbuf.st_uid)
228  || (statbuf.st_mode&S_IWOTH))
229  mode |= 2;
230 
231  return (mode);
232 #endif
233 }
234 
244 void dump_map(const mapstruct *m) {
245  LOG(llevError, "Map %s status: %d.\n", m->path, m->in_memory);
246  LOG(llevError, "Size: %dx%d Start: %d,%d\n", MAP_WIDTH(m), MAP_HEIGHT(m), MAP_ENTER_X(m), MAP_ENTER_Y(m));
247 
248  if (m->msg != NULL)
249  LOG(llevError, "Message:\n%s", m->msg);
250 
251  if (m->maplore != NULL)
252  LOG(llevError, "Lore:\n%s", m->maplore);
253 
254  if (m->tmpname != NULL)
255  LOG(llevError, "Tmpname: %s\n", m->tmpname);
256 
257  LOG(llevError, "Difficulty: %d\n", m->difficulty);
258  LOG(llevError, "Darkness: %d\n", m->darkness);
259 }
260 
267 void dump_all_maps(void) {
268  mapstruct *m;
269 
270  for (m = first_map; m != NULL; m = m->next) {
271  dump_map(m);
272  }
273 }
274 
299 int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny) {
300  int retval = 0;
301  mapstruct *mp;
302 
303  /*
304  * Since x and y are copies of the original values, we can directly
305  * mess with them here.
306  */
307  mp = get_map_from_coord(oldmap, &x, &y);
308  if (!mp)
309  return P_OUT_OF_MAP;
310  if (mp != oldmap)
311  retval |= P_NEW_MAP;
312  if (newmap)
313  *newmap = mp;
314  if (nx)
315  *nx = x;
316  if (ny)
317  *ny = y;
318  retval |= mp->spaces[x+mp->width*y].flags;
319  return retval;
320 }
321 
343 int blocked_link(object *ob, mapstruct *m, int16_t sx, int16_t sy) {
344  object *tmp_head;
345  int mflags, blocked;
346 
347  /* Make sure the coordinates are valid - they should be, as caller should
348  * have already checked this.
349  */
350  if (OUT_OF_REAL_MAP(m, sx, sy)) {
351  LOG(llevError, "blocked_link: Passed map, x, y coordinates outside of map\n");
352  return 1;
353  }
354 
355  /* special hack for transports: if it's a transport with a move_type of 0, it can do on the space anyway */
356  if (ob->type == TRANSPORT && ob->move_type == 0)
357  return 0;
358 
359  mflags = m->spaces[sx+m->width*sy].flags;
360 
361  blocked = GET_MAP_MOVE_BLOCK(m, sx, sy);
362 
363  /* If space is currently not blocked by anything, no need to
364  * go further. Not true for players - all sorts of special
365  * things we need to do for players.
366  */
367  if (ob->type != PLAYER && !(mflags&P_IS_ALIVE) && (blocked == 0))
368  return 0;
369 
370  /* if there isn't anytyhing alive on this space, and this space isn't
371  * otherwise blocked, we can return now. Only if there is a living
372  * creature do we need to investigate if it is part of this creature
373  * or another. Likewise, only if something is blocking us do we
374  * need to investigate if there is a special circumstance that would
375  * let the player through (inventory checkers for example)
376  */
377  if (!(mflags&P_IS_ALIVE) && !OB_TYPE_MOVE_BLOCK(ob, blocked))
378  return 0;
379 
380  ob = HEAD(ob);
381 
382  /* We basically go through the stack of objects, and if there is
383  * some other object that has NO_PASS or FLAG_ALIVE set, return
384  * true. If we get through the entire stack, that must mean
385  * ob is blocking it, so return 0.
386  */
387  FOR_MAP_PREPARE(m, sx, sy, tmp) {
388  /* Never block part of self. */
389  tmp_head = HEAD(tmp);
390  if (tmp_head == ob)
391  continue;
392  /* This must be before the checks below. Code for inventory checkers. */
393  if (tmp->type == CHECK_INV && OB_MOVE_BLOCK(ob, tmp)) {
394  /* If last_sp is set, the player/monster needs an object,
395  * so we check for it. If they don't have it, they can't
396  * pass through this space.
397  */
398  if (tmp->last_sp) {
399  if (check_inv_recursive(ob, tmp) == NULL) {
400  if (tmp->msg) {
401  /* Optionally display the reason why one cannot move
402  * there. Note: emitting a message from this function
403  * is not very elegant. Ideally, this should be done
404  * somewhere in server/player.c, but this is difficult
405  * for objects of type CHECK_INV that are not alive.
406  */
409  tmp->msg);
410  }
411  return 1;
412  }
413  } else {
414  /* In this case, the player must not have the object -
415  * if they do, they can't pass through.
416  */
417  if (check_inv_recursive(ob, tmp) != NULL) {
418  if (tmp->msg) {
421  tmp->msg);
422  }
423  return 1;
424  }
425  }
426  } /* if check_inv */
427  else {
428  /* Broke apart a big nasty if into several here to make
429  * this more readable. first check - if the space blocks
430  * movement, can't move here.
431  * second - if a monster, can't move there, unless it is a
432  * hidden dm
433  */
434  if (OB_MOVE_BLOCK(ob, tmp))
435  return 1;
437  && tmp->head != ob
438  && tmp != ob
439  && tmp->type != DOOR
440  && !(QUERY_FLAG(tmp, FLAG_WIZ) && tmp->contr->hidden))
441  return 1;
442  }
443  } FOR_MAP_FINISH();
444  return 0;
445 }
446 
478 int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y) {
479  archetype *tmp;
480  int flag;
481  mapstruct *m1;
482  int16_t sx, sy;
483  const object *part;
484 
485  if (ob == NULL) {
486  flag = get_map_flags(m, &m1, x, y, &sx, &sy);
487  if (flag&P_OUT_OF_MAP)
488  return P_OUT_OF_MAP;
489 
490  /* don't have object, so don't know what types would block */
491  return(GET_MAP_MOVE_BLOCK(m1, sx, sy));
492  }
493 
494  for (tmp = ob->arch, part = ob; tmp != NULL; tmp = tmp->more, part = part->more) {
495  flag = get_map_flags(m, &m1, x+tmp->clone.x, y+tmp->clone.y, &sx, &sy);
496 
497  if (flag&P_OUT_OF_MAP)
498  return P_OUT_OF_MAP;
499  if (flag&P_IS_ALIVE)
500  return P_IS_ALIVE;
501 
502  /* object_find_first_free_spot() calls this function. However, often
503  * ob doesn't have any move type (when used to place exits)
504  * so the AND operation in OB_TYPE_MOVE_BLOCK doesn't work.
505  */
506 
507  if (ob->move_type == 0 && GET_MAP_MOVE_BLOCK(m1, sx, sy) != MOVE_ALL)
508  continue;
509 
510  /* A transport without move_type for a part should go through everything for that part. */
511  if (ob->type == TRANSPORT && part->move_type == 0)
512  continue;
513 
514  /* Note it is intentional that we check ob - the movement type of the
515  * head of the object should correspond for the entire object.
516  */
517  if (OB_TYPE_MOVE_BLOCK(ob, GET_MAP_MOVE_BLOCK(m1, sx, sy)))
518  return AB_NO_PASS;
519  }
520  return 0;
521 }
522 
533 static void fix_container_multipart(object *container) {
534  FOR_INV_PREPARE(container, tmp) {
535  archetype *at;
536  object *op, *last;
537 
538  if (tmp->inv)
540  /* already multipart, or non-multipart arch - don't do anything more */
541  for (at = tmp->arch->more, last = tmp; at != NULL; at = at->more, last = op) {
542  /* FIXME: We can't reuse object_fix_multipart() since that only
543  * works for items directly on maps. Maybe factor out common code?
544  */
545  op = arch_to_object(at);
546  op->head = tmp;
547  op->env = tmp->env;
548  last->more = op;
549  if (tmp->name != op->name) {
550  if (op->name)
551  free_string(op->name);
552  op->name = add_string(tmp->name);
553  }
554  if (tmp->title != op->title) {
555  if (op->title)
556  free_string(op->title);
557  op->title = add_string(tmp->title);
558  }
560  }
561  } FOR_INV_FINISH();
562 }
563 
575  int x, y;
576 
577  for (x = 0; x < MAP_WIDTH(m); x++)
578  for (y = 0; y < MAP_HEIGHT(m); y++)
579  FOR_MAP_PREPARE(m, x, y, tmp) {
580  if (tmp->inv)
582 
583  /* already multipart - don't do anything more */
584  if (tmp->head || tmp->more)
585  continue;
586 
588  } FOR_MAP_FINISH(); /* for objects on this space */
589 }
590 
602 void load_objects(mapstruct *m, FILE *fp, int mapflags) {
603  int i, j, bufstate = LO_NEWFILE;
604  int unique;
605  object *op, *prev = NULL, *last_more = NULL;
606 
607  op = object_new();
608  op->map = m; /* To handle buttons correctly */
609 
610  PROFILE_BEGIN();
611  while ((i = load_object(fp, op, bufstate, mapflags, false))) {
612  /* Since the loading of the map header does not load an object
613  * anymore, we need to pass LO_NEWFILE for the first object loaded,
614  * and then switch to LO_REPEAT for faster loading.
615  */
616  bufstate = LO_REPEAT;
617 
618  /* if the archetype for the object is null, means that we
619  * got an invalid object. Don't do anything with it - the game
620  * or editor will not be able to do anything with it either.
621  */
622  if (op->arch == NULL) {
623  LOG(llevDebug, "Discarding object without arch: %s\n", op->name ? op->name : "(null)");
624  continue;
625  }
626 
627  /*
628  * You can NOT have players on a map being loaded.
629  * Trying to use such a type leads to crashes everywhere as op->contr is NULL.
630  */
631  if (op->type == PLAYER) {
632  LOG(llevError, "Discarding invalid item with type PLAYER in map %s\n", m->path);
633  continue;
634  }
635 
636  /* don't use out_of_map because we don't want to consider tiling properties, we're loading a single map */
637  if (op->x < 0 || op->y < 0 || op->x >= MAP_WIDTH(m) || op->y >= MAP_HEIGHT(m)) {
638  LOG(llevError, " object %s not on valid map position %s:%d:%d\n", op->name ? op->name : "(null)", m->path, op->x, op->y);
639  if (op->x < 0) {
640  op->x = 0;
641  } else if (op->x >= MAP_WIDTH(m)) {
642  op->x = MAP_WIDTH(m) - 1;
643  }
644  if (op->y < 0) {
645  op->y = 0;
646  } else if (op->y >= MAP_HEIGHT(m)) {
647  op->y = MAP_HEIGHT(m) - 1;
648  }
649  }
650 
651  switch (i) {
652  case LL_NORMAL:
653  /* if we are loading an overlay, put the floors on the bottom */
655  && mapflags&MAP_OVERLAY)
657  else
659 
660  if (op->inv)
662 
663  prev = op,
664  last_more = op;
665  break;
666 
667  case LL_MORE:
669  op->head = prev,
670  last_more->more = op,
671  last_more = op;
672  break;
673  }
674  if (mapflags&MAP_STYLE) {
676  }
677  op = object_new();
678  op->map = m;
679  }
680  PROFILE_END(diff, LOG(llevDebug,
681  "load_objects on %s took %ld us\n", m->path, diff));
682  for (i = 0; i < m->width; i++) {
683  for (j = 0; j < m->height; j++) {
684  unique = 0;
685  /* check for unique items, or unique squares */
686  FOR_MAP_PREPARE(m, i, j, otmp) {
687  if (QUERY_FLAG(otmp, FLAG_UNIQUE))
688  unique = 1;
689  if (!(mapflags&(MAP_OVERLAY|MAP_PLAYER_UNIQUE) || unique))
691  } FOR_MAP_FINISH();
692  }
693  }
696 }
697 
714 int save_objects(mapstruct *m, FILE *fp, FILE *fp2, int flag) {
715  int i, j = 0, unique = 0;
716  unsigned int count = 0;
717 
720 
721  long serialize_time, write_time;
722 
723  PROFILE_BEGIN();
724 
725  for (i = 0; i < MAP_WIDTH(m); i++) {
726  for (j = 0; j < MAP_HEIGHT(m); j++) {
727  unique = 0;
728  FOR_MAP_PREPARE(m, i, j, op) {
730  unique = 1;
731 
732  if (op->type == PLAYER) {
733  LOG(llevDebug, "Player on map that is being saved\n");
734  continue;
735  }
736 
737  if (op->head || object_get_owner(op) != NULL)
738  continue;
739 
740  if (unique || QUERY_FLAG(op, FLAG_UNIQUE)) {
742  count++ ;
743  } else if (flag == 0
746  count++;
747  }
748  } FOR_MAP_FINISH(); /* for this space */
749  } /* for this j */
750  }
751  PROFILE_END(diff, serialize_time = diff);
752 
753  PROFILE_BEGIN();
754  char *cp = stringbuffer_finish(sb);
755  char *cp2 = stringbuffer_finish(sb2);
756  fputs(cp, fp);
757  fputs(cp2, fp2);
758  free(cp);
759  free(cp2);
760  PROFILE_END(diff, write_time = diff);
761 
762  LOG(llevDebug, "saved %d objects on %s (%ld us serializing, %ld us writing)\n", count, m->path, serialize_time, write_time);
763  return 0;
764 }
765 
776  mapstruct *map = static_cast<mapstruct *>(calloc(1, sizeof(mapstruct)));
777  /* mapstruct *mp;*/
778 
779  if (map == NULL)
781 
782  map->next = first_map;
783  first_map = map;
784 
785  map->in_memory = MAP_SWAPPED;
786 
787  MAP_WIDTH(map) = 16;
788  MAP_HEIGHT(map) = 16;
789  MAP_RESET_TIMEOUT(map) = 0;
790  MAP_TIMEOUT(map) = 300;
791  MAP_ENTER_X(map) = 0;
792  MAP_ENTER_Y(map) = 0;
793  map->last_reset_time = 0;
794  return map;
795 }
796 
798 uint32_t map_size(mapstruct *m) {
799  return (uint32_t)m->width * (uint32_t)m->height;
800 }
801 
813  m->in_memory = MAP_IN_MEMORY;
814  /* Log this condition and free the storage. We could I suppose
815  * realloc, but if the caller is presuming the data will be intact,
816  * that is their poor assumption.
817  */
818  if (m->spaces) {
819  LOG(llevError, "allocate_map called with already allocated map (%s)\n", m->path);
820  free(m->spaces);
821  }
822 
823  m->spaces = static_cast<MapSpace *>(calloc(map_size(m), sizeof(MapSpace)));
824 
825  if (m->spaces == NULL)
827 }
828 
842 mapstruct *get_empty_map(int sizex, int sizey) {
844  m->width = sizex;
845  m->height = sizey;
846  m->in_memory = MAP_SWAPPED;
847  allocate_map(m);
848  return m;
849 }
850 
864 static shopitems *parse_shop_string(const char *input_string, const mapstruct *map) {
865  char *shop_string, *p, *q, *next_semicolon, *next_colon;
866  shopitems *items = NULL;
867  int i = 0, number_of_entries = 0;
868  const typedata *current_type;
869 
870  shop_string = strdup_local(input_string);
871  p = shop_string;
872  LOG(llevDebug, "parsing %s\n", input_string);
873  /* first we'll count the entries, we'll need that for allocating the array shortly */
874  while (p) {
875  p = strchr(p, ';');
876  number_of_entries++;
877  if (p)
878  p++;
879  }
880  p = shop_string;
881  strip_endline(p);
882  items = static_cast<shopitems *>(CALLOC(number_of_entries+1, sizeof(shopitems)));
883  /*
884  * The memset would always set at least one byte to zero,
885  * so a failed calloc would have segfaulted the program.
886  * Instead, check for a null and fail more gracefully.
887  */
888  if (!items)
890 
891  for (i = 0; i < number_of_entries; i++) {
892  if (!p) {
893  LOG(llevError, "parse_shop_string: I seem to have run out of string, that shouldn't happen.\n");
894  break;
895  }
896  next_semicolon = strchr(p, ';');
897  next_colon = strchr(p, ':');
898  /* if there is a stregth specified, figure out what it is, we'll need it soon. */
899  if (next_colon && (!next_semicolon || next_colon < next_semicolon))
900  items[i].strength = atoi(strchr(p, ':')+1);
901 
902  if (isdigit(*p) || *p == '*') {
903  items[i].typenum = *p == '*' ? -1 : atoi(p);
904  current_type = get_typedata(items[i].typenum);
905  if (current_type) {
906  items[i].name = current_type->name;
907  items[i].name_pl = current_type->name_pl;
908  }
909  } else { /*we have a named type, let's figure out what it is */
910  q = strpbrk(p, ";:");
911  if (q)
912  *q = '\0';
913 
914  current_type = get_typedata_by_name(p);
915  if (current_type) {
916  items[i].name = current_type->name;
917  items[i].typenum = current_type->number;
918  items[i].name_pl = current_type->name_pl;
919  } else {
920  /* oh uh, something's wrong, let's free up this one, and try
921  * the next entry while we're at it, better print a warning */
922  LOG(llevError, "invalid type %s defined in shopitems for %s in string %s\n", p, map->name, input_string);
923  }
924  }
925  items[i].index = number_of_entries;
926  if (next_semicolon)
927  p = ++next_semicolon;
928  else
929  p = NULL;
930  }
931  free(shop_string);
932  return items;
933 }
934 
946 static void print_shop_string(mapstruct *m, char *output_string, int size) {
947  int i;
948  char tmp[MAX_BUF];
949 
950  output_string[0] = '\0';
951  for (i = 0; i < m->shopitems[0].index; i++) {
952  if (m->shopitems[i].typenum != -1) {
953  if (m->shopitems[i].strength) {
954  snprintf(tmp, sizeof(tmp), "%s:%d;", m->shopitems[i].name, m->shopitems[i].strength);
955  } else
956  snprintf(tmp, sizeof(tmp), "%s;", m->shopitems[i].name);
957  } else {
958  if (m->shopitems[i].strength) {
959  snprintf(tmp, sizeof(tmp), "*:%d;", m->shopitems[i].strength);
960  } else
961  snprintf(tmp, sizeof(tmp), "*;");
962  }
963  snprintf(output_string+strlen(output_string), size-strlen(output_string), "%s", tmp);
964  }
965 
966  /* erase final ; else parsing back will lead to issues */
967  if (strlen(output_string) > 0) {
968  output_string[strlen(output_string) - 1] = '\0';
969  }
970 }
971 
988 static int load_map_header(FILE *fp, mapstruct *m) {
989  char buf[HUGE_BUF], *key = NULL, *value;
990 
991  m->width = m->height = 0;
992  while (fgets(buf, sizeof(buf), fp) != NULL) {
993  char *p;
994 
995  p = strchr(buf, '\n');
996  if (p == NULL) {
997  LOG(llevError, "Error loading map header - did not find a newline - perhaps file is truncated? Buf=%s\n", buf);
998  return 1;
999  }
1000  *p = '\0';
1001 
1002  key = buf;
1003  while (isspace(*key))
1004  key++;
1005  if (*key == 0)
1006  continue; /* empty line */
1007  value = strchr(key, ' ');
1008  if (value) {
1009  *value = 0;
1010  value++;
1011  while (isspace(*value)) {
1012  value++;
1013  if (*value == '\0') {
1014  /* Nothing but spaces. */
1015  value = NULL;
1016  break;
1017  }
1018  }
1019  }
1020 
1021  /* key is the field name, value is what it should be set
1022  * to. We've already done the work to null terminate key,
1023  * and strip off any leading spaces for both of these.
1024  * We have not touched the newline at the end of the line -
1025  * these are needed for some values. the end pointer
1026  * points to the first of the newlines.
1027  * value could be NULL! It would be easy enough to just point
1028  * this to "" to prevent cores, but that would let more errors slide
1029  * through.
1030  *
1031  * First check for entries that do not use the value parameter, then
1032  * validate that value is given and check for the remaining entries
1033  * that use the parameter.
1034  */
1035 
1036  if (!strcmp(key, "msg")) {
1037  char msgbuf[HUGE_BUF];
1038  int msgpos = 0;
1039 
1040  while (fgets(buf, sizeof(buf), fp) != NULL) {
1041  if (!strcmp(buf, "endmsg\n"))
1042  break;
1043  else {
1044  snprintf(msgbuf+msgpos, sizeof(msgbuf)-msgpos, "%s", buf);
1045  msgpos += strlen(buf);
1046  }
1047  }
1048  /* There are lots of maps that have empty messages (eg, msg/endmsg
1049  * with nothing between). There is no reason in those cases to
1050  * keep the empty message. Also, msgbuf contains garbage data
1051  * when msgpos is zero, so copying it results in crashes
1052  */
1053  if (msgpos != 0) {
1054  /* When loading eg an overlay, message is already set, so free() current one. */
1055  free(m->msg);
1056  m->msg = strdup_local(msgbuf);
1057  }
1058  } else if (!strcmp(key, "maplore")) {
1059  char maplorebuf[HUGE_BUF];
1060  size_t maplorepos = 0;
1061 
1062  while (fgets(buf, HUGE_BUF-1, fp) != NULL) {
1063  if (!strcmp(buf, "endmaplore\n"))
1064  break;
1065  else {
1066  if (maplorepos >= sizeof(maplorebuf)) {
1067  LOG(llevError, "Map lore exceeds buffer length\n");
1068  return 1;
1069  }
1070  snprintf(maplorebuf+maplorepos, sizeof(maplorebuf)-maplorepos, "%s", buf);
1071  maplorepos += strlen(buf);
1072  }
1073  }
1074  if (maplorepos != 0)
1075  m->maplore = strdup_local(maplorebuf);
1076  } else if (!strcmp(key, "end")) {
1077  break;
1078  } else if (value == NULL) {
1079  LOG(llevError, "Got '%s' line without parameter in map header\n", key);
1080  } else if (!strcmp(key, "arch")) {
1081  /* This is an oddity, but not something we care about much. */
1082  if (strcmp(value, "map")) {
1083  LOG(llevError, "load_map_header: expected 'arch map': check line endings?\n");
1084  return 1;
1085  }
1086  } else if (!strcmp(key, "name")) {
1087  /* When loading eg an overlay, the name is already set, so free() current one. */
1088  free(m->name);
1089  m->name = strdup_local(value);
1090  /* first strcmp value on these are old names supported
1091  * for compatibility reasons. The new values (second) are
1092  * what really should be used.
1093  */
1094  } else if (!strcmp(key, "enter_x")) {
1095  m->enter_x = atoi(value);
1096  } else if (!strcmp(key, "enter_y")) {
1097  m->enter_y = atoi(value);
1098  } else if (!strcmp(key, "width")) {
1099  m->width = atoi(value);
1100  } else if (!strcmp(key, "height")) {
1101  m->height = atoi(value);
1102  } else if (!strcmp(key, "reset_timeout")) {
1103  m->reset_timeout = atoi(value);
1104  } else if (!strcmp(key, "swap_time")) {
1105  m->timeout = atoi(value);
1106  } else if (!strcmp(key, "difficulty")) {
1107  m->difficulty = atoi(value);
1108  } else if (!strcmp(key, "darkness")) {
1109  m->darkness = atoi(value);
1110  } else if (!strcmp(key, "fixed_resettime")) {
1111  m->fixed_resettime = atoi(value);
1112  } else if (!strcmp(key, "unique")) {
1113  m->unique = atoi(value);
1114  } else if (!strcmp(key, "template")) {
1115  m->is_template = atoi(value);
1116  } else if (!strcmp(key, "region")) {
1117  m->region = get_region_by_name(value);
1118  } else if (!strcmp(key, "shopitems")) {
1119  m->shopitems = parse_shop_string(value, m);
1120  } else if (!strcmp(key, "shopgreed")) {
1121  m->shopgreed = atof(value);
1122  } else if (!strcmp(key, "shopmin")) {
1123  m->shopmin = atol(value);
1124  } else if (!strcmp(key, "shopmax")) {
1125  m->shopmax = atol(value);
1126  } else if (!strcmp(key, "shoprace")) {
1127  m->shoprace = strdup_local(value);
1128  } else if (!strcmp(key, "outdoor")) {
1129  m->outdoor = atoi(value);
1130  } else if (!strcmp(key, "nosmooth")) {
1131  m->nosmooth = atoi(value);
1132  } else if (!strcmp(key, "first_load")) {
1133  m->last_reset_time = atoi(value);
1134  } else if (!strncmp(key, "tile_path_", 10)) {
1135  int tile = atoi(key+10);
1136 
1137  if (tile < 1 || tile > 4) {
1138  LOG(llevError, "load_map_header: tile location %d out of bounds (%s)\n", tile, m->path);
1139  } else {
1140  if (m->tile_path[tile-1]) {
1141  LOG(llevError, "load_map_header: tile location %d duplicated (%s)\n", tile, m->path);
1142  free(m->tile_path[tile-1]);
1143  }
1144  m->tile_path[tile-1] = strdup_local(value);
1145  } /* end if tile direction (in)valid */
1146  } else if (!strcmp(key, "background_music")) {
1147  m->background_music = strdup_local(value);
1148  } else if (!strcmp(key, "reset_group")) {
1149  m->reset_group = add_string(value);
1150  } else {
1151  LOG(llevError, "Got unknown value in map header: %s %s\n", key, value);
1152  }
1153  }
1154  if ((m->width == 0) || (m->height == 0)) {
1155  LOG(llevError, "Map width or height not specified\n");
1156  return 1;
1157  }
1158  if (!key || strcmp(key, "end")) {
1159  LOG(llevError, "Got premature eof on map header!\n");
1160  return 1;
1161  }
1162  return 0;
1163 }
1164 
1165 void map_path(const char *map, int flags, char *pathname, size_t bufsize) {
1166  if (flags&MAP_PLAYER_UNIQUE) {
1167  snprintf(pathname, bufsize, "%s/%s/%s", settings.localdir, settings.playerdir, map+1);
1168  }
1169  else if (flags&MAP_OVERLAY)
1170  create_overlay_pathname(map, pathname, bufsize);
1171  else
1172  create_pathname(map, pathname, bufsize);
1173 }
1174 
1175 mapstruct *mapfile_load_lowlevel(const char *map, const char *pathname, int flags) {
1176  FILE *fp;
1177  if ((fp = fopen(pathname, "r")) == NULL) {
1179  "Can't open %s: %s\n", pathname, strerror(errno));
1180  return NULL;
1181  }
1182 
1183  mapstruct *m = get_linked_map();
1184  safe_strncpy(m->path, map, HUGE_BUF);
1185  if (load_map_header(fp, m)) {
1186  LOG(llevError, "Error loading map header for %s, flags=%d\n", map, flags);
1187  delete_map(m);
1188  fclose(fp);
1189  return NULL;
1190  }
1191 
1192  allocate_map(m);
1193 
1194  m->in_memory = MAP_LOADING;
1195  load_objects(m, fp, flags & MAP_STYLE);
1196  fclose(fp);
1197  m->in_memory = MAP_IN_MEMORY;
1198  return m;
1199 }
1200 
1216 mapstruct *mapfile_load(const char *map, int flags) {
1217  mapstruct *m;
1218  PROFILE_BEGIN();
1219  char pathname[MAX_BUF];
1220  map_path(map, flags, pathname, sizeof(pathname));
1221  m = mapfile_load_lowlevel(map, pathname, flags);
1222  if (!m) {
1223  return NULL;
1224  }
1225  if (!MAP_DIFFICULTY(m) && (!(flags & MAP_NO_DIFFICULTY)))
1228 
1229  /* In case other objects press some buttons down */
1230  update_buttons(m);
1231 
1233 
1234  if (!(flags & MAP_STYLE))
1235  apply_auto_fix(m); /* Chests which open as default */
1236 
1237  PROFILE_END(diff,
1238  LOG(llevDebug, "mapfile_load on %s" " took %ld us\n", map, diff));
1239 
1240  return (m);
1241 }
1242 
1252  FILE *fp;
1253 
1254  if (!m->tmpname) {
1255  LOG(llevError, "No temporary filename for map %s\n", m->path);
1256  return 1;
1257  }
1258 
1259  if ((fp = fopen(m->tmpname, "r")) == NULL) {
1260  LOG(llevError, "Cannot open %s: %s\n", m->tmpname, strerror(errno));
1261  return 2;
1262  }
1263 
1264  if (load_map_header(fp, m)) {
1265  LOG(llevError, "Error loading map header for %s (%s)\n", m->path, m->tmpname);
1266  fclose(fp);
1267  return 3;
1268  }
1269  allocate_map(m);
1270 
1271  m->in_memory = MAP_LOADING;
1272  load_objects(m, fp, 0);
1273  fclose(fp);
1274  m->in_memory = MAP_IN_MEMORY;
1275  return 0;
1276 }
1277 
1287 static int load_overlay_map(const char *filename, mapstruct *m) {
1288  FILE *fp;
1289  char pathname[MAX_BUF];
1290 
1292 
1293  if ((fp = fopen(pathname, "r")) == NULL) {
1294  /* nothing bad to not having an overlay */
1295  return 0;
1296  }
1297 
1298  if (load_map_header(fp, m)) {
1299  LOG(llevError, "Error loading map header for overlay %s (%s)\n", m->path, pathname);
1300  fclose(fp);
1301  return 1;
1302  }
1303  /*allocate_map(m);*/
1304 
1305  m->in_memory = MAP_LOADING;
1306  load_objects(m, fp, MAP_OVERLAY);
1307  fclose(fp);
1308  m->in_memory = MAP_IN_MEMORY;
1309  return 0;
1310 }
1311 
1312 /******************************************************************************
1313  * This is the start of unique map handling code
1314  *****************************************************************************/
1315 
1323  int i, j, unique = 0;
1324 
1325  for (i = 0; i < MAP_WIDTH(m); i++)
1326  for (j = 0; j < MAP_HEIGHT(m); j++) {
1327  unique = 0;
1328  FOR_MAP_PREPARE(m, i, j, op) {
1330  unique = 1;
1331  if (op->head == NULL && (QUERY_FLAG(op, FLAG_UNIQUE) || unique)) {
1332  clean_object(op);
1335  object_remove(op);
1337  }
1338  } FOR_MAP_FINISH();
1339  }
1340 }
1341 
1348  FILE *fp;
1349  int count;
1350  char firstname[MAX_BUF], name[MAX_BUF];
1351 
1352  create_items_path(m->path, name, MAX_BUF);
1353  for (count = 0; count < 10; count++) {
1354  snprintf(firstname, sizeof(firstname), "%s.v%02d", name, count);
1355  if (!access(firstname, R_OK))
1356  break;
1357  }
1358  /* If we get here, we did not find any map */
1359  if (count == 10)
1360  return;
1361 
1362  if ((fp = fopen(firstname, "r")) == NULL) {
1363  /* There is no expectation that every map will have unique items, but this
1364  * is debug output, so leave it in.
1365  */
1366  LOG(llevDebug, "Can't open unique items file for %s\n", name);
1367  return;
1368  }
1369 
1370  m->in_memory = MAP_LOADING;
1371  if (m->tmpname == NULL) /* if we have loaded unique items from */
1372  delete_unique_items(m); /* original map before, don't duplicate them */
1373  load_object(fp, NULL, LO_NOREAD, 0, false);
1374  load_objects(m, fp, 0);
1375  fclose(fp);
1376  m->in_memory = MAP_IN_MEMORY;
1377 }
1378 
1394 int save_map(mapstruct *m, int flag) {
1395  FILE *fp, *fp2;
1396  OutputFile of, of2;
1397  char filename[MAX_BUF], shop[MAX_BUF];
1398  int i, res;
1399 
1400  if (flag && !*m->path) {
1401  LOG(llevError, "Tried to save map without path.\n");
1402  return SAVE_ERROR_NO_PATH;
1403  }
1404 
1405  PROFILE_BEGIN();
1406 
1407  if (flag != SAVE_MODE_NORMAL || (m->unique) || (m->is_template)) {
1408  if (!m->unique && !m->is_template) { /* flag is set */
1409  if (flag == SAVE_MODE_OVERLAY)
1411  else
1412  create_pathname(m->path, filename, MAX_BUF);
1413  } else {
1414  if (m->path[0] != '~') {
1415  LOG(llevError,
1416  "Cannot save unique map '%s' outside of LOCALDIR. Check "
1417  "that all exits to '%s' have FLAG_UNIQUE set correctly.\n",
1418  m->path, m->path);
1419  return SAVE_ERROR_UCREATION;
1420  }
1421  snprintf(filename, sizeof(filename), "%s/%s/%s", settings.localdir, settings.playerdir, m->path+1);
1422  }
1423 
1425  } else {
1426  if (!m->tmpname)
1427  m->tmpname = tempnam(settings.tmpdir, NULL);
1428  strlcpy(filename, m->tmpname, sizeof(filename));
1429  }
1430  m->in_memory = MAP_SAVING;
1431 
1432  fp = of_open(&of, filename);
1433  if (fp == NULL)
1434  return SAVE_ERROR_RCREATION;
1435 
1436  /* legacy */
1437  fprintf(fp, "arch map\n");
1438  if (m->name)
1439  fprintf(fp, "name %s\n", m->name);
1440  if (!flag)
1441  fprintf(fp, "swap_time %d\n", m->swap_time);
1442  if (m->reset_timeout)
1443  fprintf(fp, "reset_timeout %u\n", m->reset_timeout);
1444  if (m->fixed_resettime)
1445  fprintf(fp, "fixed_resettime %d\n", m->fixed_resettime);
1446  /* we unfortunately have no idea if this is a value the creator set
1447  * or a difficulty value we generated when the map was first loaded
1448  */
1449  if (m->difficulty)
1450  fprintf(fp, "difficulty %d\n", m->difficulty);
1451  if (m->region)
1452  fprintf(fp, "region %s\n", m->region->name);
1453  if (m->shopitems) {
1454  print_shop_string(m, shop, sizeof(shop));
1455  fprintf(fp, "shopitems %s\n", shop);
1456  }
1457  if (m->shopgreed)
1458  fprintf(fp, "shopgreed %f\n", m->shopgreed);
1459  if (m->shopmin)
1460  fprintf(fp, "shopmin %" FMT64U "\n", m->shopmin);
1461  if (m->shopmax)
1462  fprintf(fp, "shopmax %" FMT64U "\n", m->shopmax);
1463  if (m->shoprace)
1464  fprintf(fp, "shoprace %s\n", m->shoprace);
1465  if (m->darkness)
1466  fprintf(fp, "darkness %d\n", m->darkness);
1467  if (m->width)
1468  fprintf(fp, "width %d\n", m->width);
1469  if (m->height)
1470  fprintf(fp, "height %d\n", m->height);
1471  if (m->enter_x)
1472  fprintf(fp, "enter_x %d\n", m->enter_x);
1473  if (m->enter_y)
1474  fprintf(fp, "enter_y %d\n", m->enter_y);
1475  if (m->msg)
1476  fprintf(fp, "msg\n%sendmsg\n", m->msg);
1477  if (m->maplore)
1478  fprintf(fp, "maplore\n%sendmaplore\n", m->maplore);
1479  if (m->unique)
1480  fprintf(fp, "unique %d\n", m->unique);
1481  if (m->is_template)
1482  fprintf(fp, "template %d\n", m->is_template);
1483  if (m->outdoor)
1484  fprintf(fp, "outdoor %d\n", m->outdoor);
1485  if (m->nosmooth)
1486  fprintf(fp, "nosmooth %d\n", m->nosmooth);
1487  if (m->last_reset_time)
1488  fprintf(fp, "first_load %ld\n", m->last_reset_time);
1489  if (m->background_music)
1490  fprintf(fp, "background_music %s\n", m->background_music);
1491  if (m->reset_group)
1492  fprintf(fp, "reset_group %s\n", m->reset_group);
1493 
1494  /* Save any tiling information, except on overlays */
1495  if (flag != SAVE_MODE_OVERLAY)
1496  for (i = 0; i < 4; i++)
1497  if (m->tile_path[i])
1498  fprintf(fp, "tile_path_%d %s\n", i+1, m->tile_path[i]);
1499 
1500  fprintf(fp, "end\n");
1501 
1502  /* In the game save unique items in the different file, but
1503  * in the editor save them to the normal map file.
1504  * If unique map, save files in the proper destination (set by
1505  * player)
1506  */
1507  if ((flag == SAVE_MODE_NORMAL || flag == SAVE_MODE_OVERLAY) && !m->unique && !m->is_template) {
1508  char name[MAX_BUF], final_unique[MAX_BUF];
1509 
1510  create_items_path(m->path, name, MAX_BUF);
1511  snprintf(final_unique, sizeof(final_unique), "%s.v00", name);
1512  fp2 = of_open(&of2, final_unique);
1513  if (fp2 == NULL) {
1514  of_cancel(&of);
1515  return SAVE_ERROR_UCREATION;
1516  }
1517  if (flag == SAVE_MODE_OVERLAY) {
1518  /* SO_FLAG_NO_REMOVE is non destructive save, so map is still valid. */
1519  res = save_objects(m, fp, fp2, SAVE_FLAG_NO_REMOVE);
1520  if (res < 0) {
1521  LOG(llevError, "Save error during object save: %d\n", res);
1522  of_cancel(&of);
1523  of_cancel(&of2);
1524  return res;
1525  }
1526  m->in_memory = MAP_IN_MEMORY;
1527  } else {
1528  res = save_objects(m, fp, fp2, 0);
1529  if (res < 0) {
1530  LOG(llevError, "Save error during object save: %d\n", res);
1531  of_cancel(&of);
1532  of_cancel(&of2);
1533  return res;
1534  }
1536  }
1537  if (ftell(fp2) == 0) {
1538  of_cancel(&of2);
1539  /* If there are no unique items left on the map, we need to
1540  * unlink the original unique map so that the unique
1541  * items don't show up again.
1542  */
1543  unlink(final_unique);
1544  } else {
1545  if (!of_close(&of2)) {
1546  of_cancel(&of);
1547  return SAVE_ERROR_URENAME;
1548  }
1549 
1550  if (chmod(final_unique, SAVE_MODE) != 0) {
1551  LOG(llevError, "Could not set permissions on '%s'\n",
1552  final_unique);
1553  }
1554  }
1555  } else { /* save same file when not playing, like in editor */
1556  res = save_objects(m, fp, fp, 0);
1557  if (res < 0) {
1558  LOG(llevError, "Save error during object save: %d\n", res);
1559  of_cancel(&of);
1560  return res;
1561  }
1563  }
1564 
1565  if (!of_close(&of))
1566  return SAVE_ERROR_CLOSE;
1567 
1568  if (chmod(filename, SAVE_MODE) != 0) {
1569  LOG(llevError, "Could not set permissions on '%s'\n", filename);
1570  }
1571 
1572  PROFILE_END(diff,
1573  LOG(llevDebug, "save_map on %s" " took %ld us\n", m->path, diff));
1574 
1575  return SAVE_ERROR_OK;
1576 }
1577 
1587 void clean_object(object *op) {
1588  FOR_INV_PREPARE(op, tmp) {
1589  clean_object(tmp);
1592  object_remove(tmp);
1594  } FOR_INV_FINISH();
1595 }
1596 
1604  int i, j;
1605  object *op;
1606 
1607  for (i = 0; i < MAP_WIDTH(m); i++)
1608  for (j = 0; j < MAP_HEIGHT(m); j++) {
1609  object *previous_obj = NULL;
1610 
1611  while ((op = GET_MAP_OB(m, i, j)) != NULL) {
1612  if (op == previous_obj) {
1613  LOG(llevDebug, "free_all_objects: Link error, bailing out.\n");
1614  break;
1615  }
1616  previous_obj = op;
1617  op = HEAD(op);
1618 
1619  /* If the map isn't in memory, object_free_drop_inventory() will remove and
1620  * free objects in op's inventory. So let it do the job.
1621  */
1622  if (m->in_memory == MAP_IN_MEMORY)
1623  clean_object(op);
1624  object_remove(op);
1626  }
1627  }
1628 #ifdef MANY_CORES
1629  /* I see periodic cores on metalforge where a map has been swapped out, but apparantly
1630  * an item on that map was not saved - look for that condition and die as appropriate -
1631  * this leaves more of the map data intact for better debugging.
1632  */
1633  for (op = objects; op != NULL; op = op->next) {
1634  if (!QUERY_FLAG(op, FLAG_REMOVED) && op->map == m) {
1635  LOG(llevError, "free_all_objects: object %s still on map after it should have been freed\n", op->name);
1636  abort();
1637  }
1638  }
1639 #endif
1640 }
1641 
1651  int i;
1652 
1653  if (!m->in_memory) {
1654  LOG(llevError, "Trying to free freed map.\n");
1655  return;
1656  }
1657 
1659 
1660  if (m->spaces)
1662  if (m->name)
1663  FREE_AND_CLEAR(m->name);
1664  if (m->spaces)
1665  FREE_AND_CLEAR(m->spaces);
1666  if (m->msg)
1667  FREE_AND_CLEAR(m->msg);
1668  if (m->maplore)
1669  FREE_AND_CLEAR(m->maplore);
1670  if (m->shopitems)
1671  FREE_AND_CLEAR(m->shopitems);
1672  if (m->shoprace)
1673  FREE_AND_CLEAR(m->shoprace);
1674  if (m->background_music)
1675  FREE_AND_CLEAR(m->background_music);
1676  if (m->buttons)
1677  free_objectlinkpt(m->buttons);
1678  m->buttons = NULL;
1679  for (i = 0; i < 4; i++) {
1680  if (m->tile_path[i])
1681  FREE_AND_CLEAR(m->tile_path[i]);
1682  m->tile_map[i] = NULL;
1683  }
1684  m->in_memory = MAP_SWAPPED;
1685 }
1686 
1697  mapstruct *tmp, *last;
1698  int i;
1699 
1700  if (!m)
1701  return;
1702  if (m->in_memory == MAP_IN_MEMORY) {
1703  /* change to MAP_SAVING, even though we are not,
1704  * so that object_remove() doesn't do as much work.
1705  */
1706  m->in_memory = MAP_SAVING;
1707  free_map(m);
1708  }
1709  /* move this out of free_map, since tmpname can still be needed if
1710  * the map is swapped out.
1711  */
1712  free(m->tmpname);
1713  m->tmpname = NULL;
1714  FREE_AND_CLEAR_STR_IF(m->reset_group);
1715  last = NULL;
1716  /* We need to look through all the maps and see if any maps
1717  * are pointing at this one for tiling information. Since
1718  * tiling can be assymetric, we just can not look to see which
1719  * maps this map tiles with and clears those.
1720  */
1721  for (tmp = first_map; tmp != NULL; tmp = tmp->next) {
1722  if (tmp->next == m)
1723  last = tmp;
1724 
1725  /* This should hopefully get unrolled on a decent compiler */
1726  for (i = 0; i < 4; i++)
1727  if (tmp->tile_map[i] == m)
1728  tmp->tile_map[i] = NULL;
1729  }
1730 
1731  /* If last is null, then this should be the first map in the list */
1732  if (!last) {
1733  if (m == first_map)
1734  first_map = m->next;
1735  else
1736  /* m->path is a static char, so should hopefully still have
1737  * some useful data in it.
1738  */
1739  LOG(llevError, "delete_map: Unable to find map %s in list\n", m->path);
1740  } else
1741  last->next = m->next;
1742 
1743  free(m);
1744 }
1745 
1759 mapstruct *ready_map_name(const char *name, int flags) {
1760  mapstruct *m;
1761 
1762  if (!name)
1763  return (NULL);
1764 
1765  /* Have we been at this level before? */
1766  m = has_been_loaded(name);
1767 
1768  /* Map is good to go, so just return it */
1769  if (m && (m->in_memory == MAP_LOADING || m->in_memory == MAP_IN_MEMORY)) {
1770  return m;
1771  }
1772 
1773  /* Rewrite old paths starting with LOCALDIR/PLAYERDIR to new '~' paths. */
1774  char buf[MAX_BUF], buf2[MAX_BUF];
1775  snprintf(buf, sizeof(buf), "%s/%s", settings.localdir, settings.playerdir);
1776  if (strncmp(name, buf, strlen(buf)) == 0) {
1777  snprintf(buf2, sizeof(buf2), "~%s", name+strlen(buf)+1);
1778  name = buf2;
1779  }
1780 
1781  /* Paths starting with '~' are unique. */
1782  if (name[0] == '~') {
1784  }
1785 
1786  /* unique maps always get loaded from their original location, and never
1787  * a temp location. Likewise, if map_flush is set, or we have never loaded
1788  * this map, load it now. I removed the reset checking from here -
1789  * it seems the probability of a player trying to enter a map that should
1790  * reset but hasn't yet is quite low, and removing that makes this function
1791  * a bit cleaner (and players probably shouldn't rely on exact timing for
1792  * resets in any case - if they really care, they should use the 'maps command.
1793  */
1794  if ((flags&(MAP_FLUSH|MAP_PLAYER_UNIQUE)) || !m) {
1795  /* first visit or time to reset */
1796  if (m) {
1797  clean_tmp_map(m); /* Doesn't make much difference */
1798  delete_map(m);
1799  }
1800 
1802  if (m == NULL) return NULL;
1803 
1804  /* If a player unique map, no extra unique object file to load.
1805  * if from the editor, likewise.
1806  */
1809 
1811  if (load_overlay_map(name, m) != 0) {
1812  delete_map(m);
1813  m = mapfile_load(name, 0);
1814  if (m == NULL) {
1815  /* Really, this map is bad :( */
1816  return NULL;
1817  }
1818  }
1819  }
1820  } else {
1821  /* If in this loop, we found a temporary map, so load it up. */
1822 
1823  if (load_temporary_map(m) != 0) {
1824  /*
1825  * There was a failure loading the temporary map, fall back to original one.
1826  * load_temporary_map() already logged the error.
1827  */
1828  delete_map(m);
1829  m = mapfile_load(name, 0);
1830  if (m == NULL) {
1831  /* Really, this map is bad :( */
1832  return NULL;
1833  }
1834  }
1836 
1837  clean_tmp_map(m);
1838  m->in_memory = MAP_IN_MEMORY;
1839  /* tempnam() on sun systems (probably others) uses malloc
1840  * to allocated space for the string. Free it here.
1841  * In some cases, load_temporary_map above won't find the
1842  * temporary map, and so has reloaded a new map. If that
1843  * is the case, tmpname is now null
1844  */
1845  free(m->tmpname);
1846  m->tmpname = NULL;
1847  /* It's going to be saved anew anyway */
1848  }
1849 
1850  /* Below here is stuff common to both first time loaded maps and
1851  * temp maps.
1852  */
1853 
1854  decay_objects(m); /* start the decay */
1855 
1856  if (m->outdoor)
1858 
1859  if (!(flags&(MAP_FLUSH))) {
1860  if (m->last_reset_time == 0) {
1861  m->last_reset_time = seconds();
1862  }
1863  }
1864 
1866 
1867  return m;
1868 }
1869 
1886  archetype *at;
1887  int x, y;
1888  int diff = 0;
1889  int i;
1890  int64_t exp_pr_sq, total_exp = 0;
1891 
1892  if (MAP_DIFFICULTY(m)) {
1893  return MAP_DIFFICULTY(m);
1894  }
1895 
1896  for (x = 0; x < MAP_WIDTH(m); x++)
1897  for (y = 0; y < MAP_HEIGHT(m); y++)
1898  FOR_MAP_PREPARE(m, x, y, op) {
1899  if (QUERY_FLAG(op, FLAG_MONSTER))
1900  total_exp += op->stats.exp;
1902  total_exp += op->stats.exp;
1903  // If we have an other_arch on our generator, just use that.
1904  // FIXME: Figure out what to do if we are doing template generation from inventory.
1905  at = op->other_arch ? op->other_arch : NULL;
1906  if (at != NULL) {
1907  // Make sure we can't set off a null pointer dereference in atoi().
1908  const char *val = object_get_value(op, "generator_limit");
1909  int lim = atoi(val ? val : "0");
1910  // We assume, on average, the generator will generate half its contents.
1911  if (!lim || lim >= 16)
1912  total_exp += at->clone.stats.exp*8;
1913  else
1914  total_exp += at->clone.stats.exp*(lim/2);
1915  }
1916  }
1917  } FOR_MAP_FINISH();
1918  // Used to be multiplied by 1000, but this undershot horribly
1919  // once I fixed the calculation for generators.
1920  // I'm trying out some exponentiation, since linear scaling
1921  // seems to overshoot low-level maps and undershoot high-level maps.
1922  // I also feel comfortable, knowing that generators return
1923  // sensible values, to up the max diff this calculates from 20 to 25.
1924  // - Daniel Hawkins 2021-03-04
1925  exp_pr_sq = (pow(total_exp, 1.75))/(MAP_WIDTH(m)*MAP_HEIGHT(m)+1);
1926  diff = 25;
1927  for (i = 1; i < 25; i++)
1928  if (exp_pr_sq <= level_exp(i, 1.0)) {
1929  diff = i;
1930  break;
1931  }
1932 
1933  return diff;
1934 }
1935 
1943  if (m->tmpname == NULL)
1944  return;
1945  (void)unlink(m->tmpname);
1946 }
1947 
1951 void free_all_maps(void) {
1952  int real_maps = 0;
1953 
1954  while (first_map) {
1955  /* I think some of the callers above before it gets here set this to be
1956  * saving, but we still want to free this data
1957  */
1958  if (first_map->in_memory == MAP_SAVING)
1961  real_maps++;
1962  }
1963  LOG(llevDebug, "free_all_maps: Freed %d maps\n", real_maps);
1964 }
1965 
1983 int change_map_light(mapstruct *m, int change) {
1984  int new_level = m->darkness+change;
1985 
1986  /* Nothing to do */
1987  if (!change
1988  || (new_level <= 0 && m->darkness == 0)
1989  || (new_level >= MAX_DARKNESS && m->darkness >= MAX_DARKNESS)) {
1990  return 0;
1991  }
1992 
1993  /* inform all players on the map */
1994  if (change > 0)
1995  ext_info_map(NDI_BLACK, m, MSG_TYPE_MISC, MSG_SUBTYPE_NONE, "It becomes darker.");
1996  else
1997  ext_info_map(NDI_BLACK, m, MSG_TYPE_MISC, MSG_SUBTYPE_NONE, "It becomes brighter.");
1998 
1999  /* Do extra checking. since m->darkness is a unsigned value,
2000  * we need to be extra careful about negative values.
2001  * In general, the checks below are only needed if change
2002  * is not +/-1
2003  */
2004  if (new_level < 0)
2005  m->darkness = 0;
2006  else if (new_level >= MAX_DARKNESS)
2007  m->darkness = MAX_DARKNESS;
2008  else
2009  m->darkness = new_level;
2010 
2011  /* All clients need to get re-updated for the change */
2013  return 1;
2014 }
2015 
2038 static inline void add_face_layer(int low_layer, int high_layer, object *ob, object *layers[], int honor_visibility) {
2039  int l, l1;
2040  object *tmp;
2041 
2042  for (l = low_layer; l <= high_layer; l++) {
2043  if (!layers[l]) {
2044  /* found an empty spot. now, we want to make sure
2045  * highest visibility at top, etc.
2046  */
2047  layers[l] = ob;
2048  if (!honor_visibility)
2049  return;
2050 
2051  /* This is basically a mini bubble sort. Only swap
2052  * position if the lower face has greater (not equal)
2053  * visibility - map stacking is secondary consideration here.
2054  */
2055  for (l1 = (l-1); l1 >= low_layer; l1--) {
2056  if (layers[l1]->face->visibility > layers[l1+1]->face->visibility) {
2057  tmp = layers[l1+1];
2058  layers[l1+1] = layers[l1];
2059  layers[l1] = tmp;
2060  }
2061  }
2062  /* Nothing more to do - face inserted */
2063  return;
2064  }
2065  }
2066  /* If we get here, all the layers have an object..
2067  */
2068  if (!honor_visibility) {
2069  /* Basically, in this case, it is pure stacking logic, so
2070  * new object goes on the top.
2071  */
2072  for (l = low_layer; l < high_layer; l++)
2073  layers[l] = layers[l+1];
2074  layers[high_layer] = ob;
2075  /* If this object doesn't have higher visibility than
2076  * the lowest object, no reason to go further.
2077  */
2078  } else if (ob->face->visibility >= layers[low_layer]->face->visibility) {
2079  /*
2080  * Start at the top (highest visibility) layer and work down.
2081  * once this face exceed that of the layer, push down those
2082  * other layers, and then replace the layer with our object.
2083  */
2084  for (l = high_layer; l >= low_layer; l--) {
2085  if (ob->face->visibility >= layers[l]->face->visibility) {
2086  for (l1 = low_layer; l1 < l; l1++)
2087  layers[l1] = layers[l1+1];
2088  layers[l] = ob;
2089  break;
2090  }
2091  }
2092  }
2093 }
2094 
2107 void update_position(mapstruct *m, int x, int y) {
2108  object *player = NULL;
2109  uint8_t flags = 0, oldflags, light = 0;
2110  object *layers[MAP_LAYERS];
2111 
2112  MoveType move_block = 0, move_slow = 0, move_on = 0, move_off = 0, move_allow = 0;
2113 
2114  oldflags = GET_MAP_FLAGS(m, x, y);
2115  if (!(oldflags&P_NEED_UPDATE)) {
2116  LOG(llevDebug, "update_position called with P_NEED_UPDATE not set: %s (%d, %d)\n", m->path, x, y);
2117  return;
2118  }
2119 
2120  memset(layers, 0, MAP_LAYERS*sizeof(object *));
2121 
2122  FOR_MAP_PREPARE(m, x, y, tmp) {
2123  /* DMs just don't do anything when hidden, including no light. */
2124  if (QUERY_FLAG(tmp, FLAG_WIZ) && tmp->contr->hidden)
2125  continue;
2126 
2127  if (tmp->type == PLAYER)
2128  player = tmp;
2129 
2130  /* This could be made additive I guess (two lights better than
2131  * one). But if so, it shouldn't be a simple additive - 2
2132  * light bulbs do not illuminate twice as far as once since
2133  * it is a dissipation factor that is squared (or is it cubed?)
2134  */
2135  if (tmp->glow_radius > light)
2136  light = tmp->glow_radius;
2137 
2138  /* if this object is visible and not a blank face,
2139  * update the objects that show how this space
2140  * looks.
2141  */
2142  if (!tmp->invisible && tmp->face != blank_face) {
2143  if (tmp->map_layer) {
2144  add_face_layer(tmp->map_layer, map_layer_info[tmp->map_layer].high_layer,
2145  tmp, layers, map_layer_info[tmp->map_layer].honor_visibility);
2146  } else if (tmp->move_type&MOVE_FLYING) {
2148  } else if ((tmp->type == PLAYER || QUERY_FLAG(tmp, FLAG_MONSTER))) {
2150  } else if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
2151  layers[MAP_LAYER_FLOOR] = tmp;
2152  /* floors hide everything else */
2153  memset(layers+1, 0, (MAP_LAYERS-1)*sizeof(object *));
2154  /* Check for FLAG_SEE_ANYWHERE is removed - objects
2155  * with that flag should just have a high visibility
2156  * set - we shouldn't need special code here.
2157  */
2158  } else if (QUERY_FLAG(tmp, FLAG_NO_PICK)) {
2160  } else {
2162  }
2163  }
2164  if (tmp == tmp->above) {
2165  LOG(llevError, "Error in structure of map\n");
2166  exit(-1);
2167  }
2168 
2169  move_slow |= tmp->move_slow;
2170  move_block |= tmp->move_block;
2171  move_on |= tmp->move_on;
2172  move_off |= tmp->move_off;
2173  move_allow |= tmp->move_allow;
2174 
2175  if (QUERY_FLAG(tmp, FLAG_ALIVE))
2176  flags |= P_IS_ALIVE;
2178  flags |= P_NO_MAGIC;
2180  flags |= P_NO_CLERIC;
2181 
2183  flags |= P_BLOCKSVIEW;
2184  } FOR_MAP_FINISH(); /* for stack of objects */
2185 
2186  if (player)
2187  flags |= P_PLAYER;
2188 
2189  /* we don't want to rely on this function to have accurate flags, but
2190  * since we're already doing the work, we calculate them here.
2191  * if they don't match, logic is broken someplace.
2192  */
2193  if (((oldflags&~(P_NEED_UPDATE|P_NO_ERROR)) != flags)
2194  && (!(oldflags&P_NO_ERROR))) {
2195  LOG(llevDebug, "update_position: updated flags do not match old flags: %s (x=%d,y=%d) %x != %x\n",
2196  m->path, x, y, (oldflags&~P_NEED_UPDATE), flags);
2197  }
2198 
2199  SET_MAP_FLAGS(m, x, y, flags);
2200  SET_MAP_MOVE_BLOCK(m, x, y, move_block&~move_allow);
2201  SET_MAP_MOVE_ON(m, x, y, move_on);
2202  SET_MAP_MOVE_OFF(m, x, y, move_off);
2203  SET_MAP_MOVE_SLOW(m, x, y, move_slow);
2204  SET_MAP_LIGHT(m, x, y, light);
2205 
2206  /* Note that player may be NULL here, which is fine - if no player, need
2207  * to clear any value that may be set.
2208  */
2209  SET_MAP_PLAYER(m, x, y, player);
2210 
2211  /* Note it is intentional we copy everything, including NULL values. */
2212  memcpy(GET_MAP_FACE_OBJS(m, x, y), layers, sizeof(object *)*MAP_LAYERS);
2213 }
2214 
2222  int timeout;
2223 
2224  timeout = MAP_RESET_TIMEOUT(map);
2225  if (timeout <= 0)
2226  timeout = MAP_DEFAULTRESET;
2227  if (timeout >= MAP_MAXRESET)
2228  timeout = MAP_MAXRESET;
2229  MAP_RESET_TIMEOUT(map) = timeout;
2230  MAP_WHEN_RESET(map) = seconds()+timeout;
2231 }
2232 
2247 static mapstruct *load_and_link_tiled_map(mapstruct *orig_map, int tile_num) {
2248  int dest_tile = (tile_num+2)%4;
2249  char path[HUGE_BUF];
2250 
2251  path_combine_and_normalize(orig_map->path, orig_map->tile_path[tile_num], path, sizeof(path));
2252 
2253  orig_map->tile_map[tile_num] = ready_map_name(path, 0);
2254  if (orig_map->tile_map[tile_num] == NULL) {
2255  LOG(llevError, "%s has invalid tiled map %s\n", orig_map->path, path);
2256  free(orig_map->tile_path[tile_num]);
2257  orig_map->tile_path[tile_num] = NULL;
2258  return NULL;
2259  }
2260 
2261  /* need to do a strcmp here as the orig_map->path is not a shared string */
2262  if (orig_map->tile_map[tile_num]->tile_path[dest_tile]
2263  && !strcmp(orig_map->tile_map[tile_num]->tile_path[dest_tile], orig_map->path))
2264  orig_map->tile_map[tile_num]->tile_map[dest_tile] = orig_map;
2265 
2266  return orig_map->tile_map[tile_num];
2267 }
2268 
2286 int out_of_map(mapstruct *m, int x, int y) {
2287 
2288  /* Simple case - coordinates are within this local
2289  * map.
2290  */
2291  if (x >= 0 && x < MAP_WIDTH(m) && y >= 0 && y < MAP_HEIGHT(m))
2292  return 0;
2293 
2294  if (x < 0) {
2295  if (!m->tile_path[3])
2296  return 1;
2297  if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) {
2299  /* Verify the tile map loaded correctly */
2300  if (!m->tile_map[3])
2301  return 0;
2302  }
2303  return (out_of_map(m->tile_map[3], x+MAP_WIDTH(m->tile_map[3]), y));
2304  } else if (x >= MAP_WIDTH(m)) {
2305  if (!m->tile_path[1])
2306  return 1;
2307  if (!m->tile_map[1] || m->tile_map[1]->in_memory != MAP_IN_MEMORY) {
2309  /* Verify the tile map loaded correctly */
2310  if (!m->tile_map[1])
2311  return 0;
2312  }
2313  return (out_of_map(m->tile_map[1], x-MAP_WIDTH(m), y));
2314  }
2315 
2316  if (y < 0) {
2317  if (!m->tile_path[0])
2318  return 1;
2319  if (!m->tile_map[0] || m->tile_map[0]->in_memory != MAP_IN_MEMORY) {
2321  /* Verify the tile map loaded correctly */
2322  if (!m->tile_map[0])
2323  return 0;
2324  }
2325  return (out_of_map(m->tile_map[0], x, y+MAP_HEIGHT(m->tile_map[0])));
2326  } else if (y >= MAP_HEIGHT(m)) {
2327  if (!m->tile_path[2])
2328  return 1;
2329  if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY) {
2331  /* Verify the tile map loaded correctly */
2332  if (!m->tile_map[2])
2333  return 0;
2334  }
2335  return (out_of_map(m->tile_map[2], x, y-MAP_HEIGHT(m)));
2336  }
2337  return 1;
2338 }
2339 
2359 mapstruct *get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y) {
2360 
2361  /* Simple case - coordinates are within this local
2362  * map.
2363  */
2364 
2365  if ( !m ) return NULL;
2366  if (*x >= 0 && *x < MAP_WIDTH(m) && *y >= 0 && *y < MAP_HEIGHT(m))
2367  return m;
2368 
2369  do /* With the first case there, we can assume we are out of the map if we get here */
2370  {
2371  // Figure out what map should be in the direction we are off the map, and then
2372  // load that map and look again.
2373  if (*x < 0) {
2374  if (!m->tile_path[3])
2375  return NULL;
2376  if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY){
2378  /* Make sure we loaded properly. */
2379  if (!m->tile_map[3])
2380  return NULL;
2381  }
2382  *x += MAP_WIDTH(m->tile_map[3]);
2383  m = m->tile_map[3];
2384  }
2385  else if (*x >= MAP_WIDTH(m)) {
2386  if (!m->tile_path[1])
2387  return NULL;
2388  if (!m->tile_map[1] || m->tile_map[1]->in_memory != MAP_IN_MEMORY){
2390  /* Make sure we loaded properly. */
2391  if (!m->tile_map[1])
2392  return NULL;
2393  }
2394  *x -= MAP_WIDTH(m);
2395  m = m->tile_map[1];
2396  }
2397  // It is possible that x and y be considered separate compare groups,
2398  // But using an else-if here retains the old behavior that recursion produced.
2399  else if (*y < 0) {
2400  if (!m->tile_path[0])
2401  return NULL;
2402  if (!m->tile_map[0] || m->tile_map[0]->in_memory != MAP_IN_MEMORY){
2404  /* Make sure we loaded properly. */
2405  if (!m->tile_map[0])
2406  return NULL;
2407  }
2408  *y += MAP_HEIGHT(m->tile_map[0]);
2409  m = m->tile_map[0];
2410  }
2411  else if (*y >= MAP_HEIGHT(m)) {
2412  if (!m->tile_path[2])
2413  return NULL;
2414  if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY){
2416  /* Make sure we loaded properly. */
2417  if (!m->tile_map[2])
2418  return NULL;
2419  }
2420  *y -= MAP_HEIGHT(m);
2421  m = m->tile_map[2];
2422  }
2423  // The check here is if our single tile is in the map.
2424  // That is exactly what the OUT_OF_MAP macro does.
2425  } while (OUT_OF_REAL_MAP(m, *x, *y));
2426  return m; /* We have found our map */
2427 }
2428 
2442 static int adjacent_map(const mapstruct *map1, const mapstruct *map2, int *dx, int *dy) {
2443  if (!map1 || !map2)
2444  return 0;
2445 
2446  if (map1 == map2) {
2447  *dx = 0;
2448  *dy = 0;
2449  } else if (map1->tile_map[0] == map2) { /* up */
2450  *dx = 0;
2451  *dy = -MAP_HEIGHT(map2);
2452  } else if (map1->tile_map[1] == map2) { /* right */
2453  *dx = MAP_WIDTH(map1);
2454  *dy = 0;
2455  } else if (map1->tile_map[2] == map2) { /* down */
2456  *dx = 0;
2457  *dy = MAP_HEIGHT(map1);
2458  } else if (map1->tile_map[3] == map2) { /* left */
2459  *dx = -MAP_WIDTH(map2);
2460  *dy = 0;
2461  } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[1] == map2) { /* up right */
2462  *dx = MAP_WIDTH(map1->tile_map[0]);
2463  *dy = -MAP_HEIGHT(map1->tile_map[0]);
2464  } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[3] == map2) { /* up left */
2465  *dx = -MAP_WIDTH(map2);
2466  *dy = -MAP_HEIGHT(map1->tile_map[0]);
2467  } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[0] == map2) { /* right up */
2468  *dx = MAP_WIDTH(map1);
2469  *dy = -MAP_HEIGHT(map2);
2470  } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[2] == map2) { /* right down */
2471  *dx = MAP_WIDTH(map1);
2472  *dy = MAP_HEIGHT(map1->tile_map[1]);
2473  } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[1] == map2) { /* down right */
2474  *dx = MAP_WIDTH(map1->tile_map[2]);
2475  *dy = MAP_HEIGHT(map1);
2476  } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[3] == map2) { /* down left */
2477  *dx = -MAP_WIDTH(map2);
2478  *dy = MAP_HEIGHT(map1);
2479  } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[0] == map2) { /* left up */
2480  *dx = -MAP_WIDTH(map1->tile_map[3]);
2481  *dy = -MAP_HEIGHT(map2);
2482  } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[2] == map2) { /* left down */
2483  *dx = -MAP_WIDTH(map1->tile_map[3]);
2484  *dy = MAP_HEIGHT(map1->tile_map[3]);
2485  } else { /* not "adjacent" enough */
2486  return 0;
2487  }
2488 
2489  return 1;
2490 }
2491 
2519 int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags) {
2520  if (!adjacent_map(op1->map, op2->map, &retval->distance_x, &retval->distance_y)) {
2521  /* be conservative and fill in _some_ data */
2522  retval->distance = 100000;
2523  retval->distance_x = 32767;
2524  retval->distance_y = 32767;
2525  retval->direction = 0;
2526  retval->part = NULL;
2527  return 0;
2528  } else {
2529  object *best;
2530 
2531  retval->distance_x += op2->x-op1->x;
2532  retval->distance_y += op2->y-op1->y;
2533 
2534  best = op1;
2535  /* If this is multipart, find the closest part now */
2536  if (!(flags&0x1) && op1->more) {
2537  object *tmp;
2538  int best_distance = retval->distance_x*retval->distance_x+
2539  retval->distance_y*retval->distance_y, tmpi;
2540 
2541  /* we just take the offset of the piece to head to figure
2542  * distance instead of doing all that work above again
2543  * since the distance fields we set above are positive in the
2544  * same axis as is used for multipart objects, the simply arithmetic
2545  * below works.
2546  */
2547  for (tmp = op1->more; tmp != NULL; tmp = tmp->more) {
2548  tmpi = (op1->x-tmp->x+retval->distance_x)*(op1->x-tmp->x+retval->distance_x)+
2549  (op1->y-tmp->y+retval->distance_y)*(op1->y-tmp->y+retval->distance_y);
2550  if (tmpi < best_distance) {
2551  best_distance = tmpi;
2552  best = tmp;
2553  }
2554  }
2555  if (best != op1) {
2556  retval->distance_x += op1->x-best->x;
2557  retval->distance_y += op1->y-best->y;
2558  }
2559  }
2560  retval->part = best;
2561  retval->distance = isqrt(retval->distance_x*retval->distance_x+retval->distance_y*retval->distance_y);
2562  retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y);
2563  return 1;
2564  }
2565 }
2566 
2587 int get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval) {
2588  if (!adjacent_map(m, op2->map, &retval->distance_x, &retval->distance_y)) {
2589  /* be conservative and fill in _some_ data */
2590  retval->distance = 100000;
2591  retval->distance_x = 32767;
2592  retval->distance_y = 32767;
2593  retval->direction = 0;
2594  retval->part = NULL;
2595  return 0;
2596  } else {
2597  retval->distance_x += op2->x-x;
2598  retval->distance_y += op2->y-y;
2599 
2600  retval->part = NULL;
2601  retval->distance = isqrt(retval->distance_x*retval->distance_x+retval->distance_y*retval->distance_y);
2602  retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y);
2603  return 1;
2604  }
2605 }
2606 
2625 int on_same_map(const object *op1, const object *op2) {
2626  int dx, dy;
2627 
2628  return adjacent_map(op1->map, op2->map, &dx, &dy);
2629 }
2630 
2648 object *map_find_by_flag(mapstruct *map, int x, int y, int flag) {
2649  object *tmp;
2650 
2651  for (tmp = GET_MAP_OB(map, x, y); tmp != NULL; tmp = tmp->above) {
2652  object *head;
2653 
2654  head = HEAD(tmp);
2655  if (QUERY_FLAG(head, flag))
2656  return head;
2657  }
2658  return NULL;
2659 }
2660 
2666  char base[HUGE_BUF], path[HUGE_BUF];
2667  int count;
2668 
2669  if (map->unique) {
2670  snprintf(path, sizeof(path), "%s/%s/%s", settings.localdir, settings.playerdir, map->path+1);
2671  if (unlink(path) != 0) {
2672  LOG(llevError, "Could not delete %s: %s\n", path, strerror(errno));
2673  }
2674  return;
2675  }
2676 
2677  create_items_path(map->path, base, sizeof(base));
2678 
2679  for (count = 0; count < 10; count++) {
2680  snprintf(path, sizeof(path), "%s.v%02d", base, count);
2681  unlink(path);
2682  }
2683 }
2684 
2690 const char *map_get_path(const object *item) {
2691  if (item->map != NULL) {
2692  if (strlen(item->map->path) > 0) {
2693  return item->map->path;
2694  }
2695 
2696  return item->map->name ? item->map->name : "(empty path and name)";
2697  }
2698 
2699  if (item->env != NULL)
2700  return map_get_path(item->env);
2701 
2702  return "(no map and no env!)";
2703 }
mapstruct::tile_path
char * tile_path[4]
Definition: map.h:353
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:171
living::exp
int64_t exp
Definition: living.h:47
S_IWUSR
#define S_IWUSR
Definition: win32.h:47
shopitems::strength
int8_t strength
Definition: map.h:298
PLAYER
@ PLAYER
Definition: object.h:112
object_get_owner
object * object_get_owner(object *op)
Definition: object.cpp:804
output_file.h
path.h
FREE_AND_CLEAR_STR_IF
#define FREE_AND_CLEAR_STR_IF(xyz)
Definition: global.h:200
global.h
FREE_OBJ_NO_DESTROY_CALLBACK
#define FREE_OBJ_NO_DESTROY_CALLBACK
Definition: object.h:536
settings
struct Settings settings
Definition: init.cpp:139
INS_NO_WALK_ON
#define INS_NO_WALK_ON
Definition: object.h:573
banquet.l
l
Definition: banquet.py:164
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
SAVE_MODE
#define SAVE_MODE
Definition: config.h:563
MAP_SAVING
#define MAP_SAVING
Definition: map.h:130
Settings::uniquedir
const char * uniquedir
Definition: global.h:253
llevError
@ llevError
Definition: logger.h:11
MAP_NO_DIFFICULTY
#define MAP_NO_DIFFICULTY
Definition: map.h:94
MAP_LAYER_ITEM3
#define MAP_LAYER_ITEM3
Definition: map.h:45
MOVE_ALL
#define MOVE_ALL
Definition: define.h:398
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
get_empty_map
mapstruct * get_empty_map(int sizex, int sizey)
Definition: map.cpp:842
FLAG_OVERLAY_FLOOR
#define FLAG_OVERLAY_FLOOR
Definition: define.h:255
of_close
int of_close(OutputFile *of)
Definition: output_file.cpp:61
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
archetype::more
archetype * more
Definition: object.h:477
create_items_path
static void create_items_path(const char *s, char *buf, size_t size)
Definition: map.cpp:165
get_region_by_name
region * get_region_by_name(const char *region_name)
Definition: region.cpp:46
of_open
FILE * of_open(OutputFile *of, const char *fname)
Definition: output_file.cpp:30
FLAG_GENERATOR
#define FLAG_GENERATOR
Definition: define.h:248
player
Definition: player.h:105
MAP_RESET_TIMEOUT
#define MAP_RESET_TIMEOUT(m)
Definition: map.h:64
blocked_link
int blocked_link(object *ob, mapstruct *m, int16_t sx, int16_t sy)
Definition: map.cpp:343
load_object
int load_object(FILE *fp, object *op, int bufstate, int map_flags)
Definition: loader.c:5205
strdup_local
#define strdup_local
Definition: compat.h:29
SAVE_FLAG_NO_REMOVE
#define SAVE_FLAG_NO_REMOVE
Definition: map.h:108
diamondslots.x
x
Definition: diamondslots.py:15
delete_unique_items
static void delete_unique_items(mapstruct *m)
Definition: map.cpp:1322
ready_map_name
mapstruct * ready_map_name(const char *name, int flags)
Definition: map.cpp:1759
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
S_IROTH
#define S_IROTH
Definition: win32.h:50
load_temporary_map
static int load_temporary_map(mapstruct *m)
Definition: map.cpp:1251
has_been_loaded
mapstruct * has_been_loaded(const char *name)
Definition: map.cpp:78
print_shop_string
static void print_shop_string(mapstruct *m, char *output_string, int size)
Definition: map.cpp:946
update_position
void update_position(mapstruct *m, int x, int y)
Definition: map.cpp:2107
MapSpace
Definition: map.h:255
MAP_LAYER_FLOOR
#define MAP_LAYER_FLOOR
Definition: map.h:40
add_face_layer
static void add_face_layer(int low_layer, int high_layer, object *ob, object *layers[], int honor_visibility)
Definition: map.cpp:2038
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.cpp:57
FLAG_UNIQUE
#define FLAG_UNIQUE
Definition: define.h:287
FLAG_OBJ_ORIGINAL
#define FLAG_OBJ_ORIGINAL
Definition: define.h:357
object::x
int16_t x
Definition: object.h:335
object::map
struct mapstruct * map
Definition: object.h:305
MoveType
unsigned char MoveType
Definition: define.h:417
Settings::templatedir
const char * templatedir
Definition: global.h:254
guildjoin.ob
ob
Definition: guildjoin.py:42
Settings::localdir
const char * localdir
Definition: global.h:249
shopitems::index
int index
Definition: map.h:300
SET_MAP_MOVE_ON
#define SET_MAP_MOVE_ON(M, X, Y, C)
Definition: map.h:203
CHECK_INV
@ CHECK_INV
Definition: object.h:174
CALLOC
#define CALLOC(x, y)
Definition: compat.h:31
map_path
void map_path(const char *map, int flags, char *pathname, size_t bufsize)
Definition: map.cpp:1165
map_layer_info
static const Map_Layer_Info map_layer_info[MAP_LAYERS]
Definition: map.cpp:62
MAP_LAYERS
#define MAP_LAYERS
Definition: map.h:32
EVENT_MAPLOAD
#define EVENT_MAPLOAD
Definition: events.h:48
Settings::tmpdir
const char * tmpdir
Definition: global.h:255
msgbuf
static char msgbuf[HUGE_BUF]
Definition: loader.c:2079
flags
static const flag_definition flags[]
Definition: gridarta-types-convert.cpp:101
Ice.tmp
int tmp
Definition: Ice.py:207
typedata::name
const char * name
Definition: define.h:91
clean_object
void clean_object(object *op)
Definition: map.cpp:1587
MAP_PLAYER_UNIQUE
#define MAP_PLAYER_UNIQUE
Definition: map.h:93
mode
linux kernel c mode(defun linux-c-mode() "C mode with adjusted defaults for use with the Linux kernel."(interactive)(c-mode)(c-set-style "K&R")(setq c-basic-offset 8))
PROFILE_BEGIN
#define PROFILE_BEGIN(expr)
Definition: global.h:372
MAP_OVERLAY
#define MAP_OVERLAY
Definition: map.h:96
typedata::name_pl
const char * name_pl
Definition: define.h:92
dump_map
void dump_map(const mapstruct *m)
Definition: map.cpp:244
NDI_NAVY
#define NDI_NAVY
Definition: newclient.h:233
FLAG_NO_MAGIC
#define FLAG_NO_MAGIC
Definition: define.h:276
blank_face
const Face * blank_face
Definition: image.cpp:36
P_NO_MAGIC
#define P_NO_MAGIC
Definition: map.h:226
TRANSPORT
@ TRANSPORT
Definition: object.h:113
LO_NEWFILE
#define LO_NEWFILE
Definition: loader.h:17
FLAG_BLOCKSVIEW
#define FLAG_BLOCKSVIEW
Definition: define.h:269
rv_vector::part
object * part
Definition: map.h:375
npc_dialog.filename
filename
Definition: npc_dialog.py:99
mapstruct::path
char path[HUGE_BUF]
Definition: map.h:355
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4337
GET_MAP_FACE_OBJS
#define GET_MAP_FACE_OBJS(M, X, Y)
Definition: map.h:188
P_IS_ALIVE
#define P_IS_ALIVE
Definition: map.h:236
MSG_TYPE_MISC
#define MSG_TYPE_MISC
Definition: newclient.h:402
free_all_maps
void free_all_maps(void)
Definition: map.cpp:1951
buf
StringBuffer * buf
Definition: readable.cpp:1552
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
AB_NO_PASS
#define AB_NO_PASS
Definition: map.h:234
MAP_LAYER_ITEM1
#define MAP_LAYER_ITEM1
Definition: map.h:43
FLAG_NO_PICK
#define FLAG_NO_PICK
Definition: define.h:239
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
mapstruct::width
uint16_t width
Definition: map.h:337
MAP_STYLE
#define MAP_STYLE
Definition: map.h:95
SAVE_MODE_OVERLAY
#define SAVE_MODE_OVERLAY
Definition: map.h:119
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
FLAG_ALIVE
#define FLAG_ALIVE
Definition: define.h:230
INS_ABOVE_FLOOR_ONLY
#define INS_ABOVE_FLOOR_ONLY
Definition: object.h:572
rv_vector::distance_y
int distance_y
Definition: map.h:373
map_remove_unique_files
void map_remove_unique_files(const mapstruct *map)
Definition: map.cpp:2665
LO_NOREAD
#define LO_NOREAD
Definition: loader.h:18
typedata
Definition: define.h:89
save_objects
int save_objects(mapstruct *m, FILE *fp, FILE *fp2, int flag)
Definition: map.cpp:714
PROFILE_END
#define PROFILE_END(var, expr)
Definition: global.h:377
Map_Layer_Info::honor_visibility
uint8_t honor_visibility
Definition: map.cpp:53
object::y
int16_t y
Definition: object.h:335
m
static event_registration m
Definition: citylife.cpp:425
set_darkness_map
void set_darkness_map(mapstruct *m)
Definition: main.cpp:371
rv_vector::distance_x
int distance_x
Definition: map.h:372
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Definition: map.h:127
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.cpp:76
apply_auto_fix
void apply_auto_fix(mapstruct *m)
Definition: main.cpp:258
MAP_LAYER_NO_PICK2
#define MAP_LAYER_NO_PICK2
Definition: map.h:42
MAP_DIFFICULTY
#define MAP_DIFFICULTY(m)
Definition: map.h:65
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1555
item.q
q
Definition: item.py:32
map_size
uint32_t map_size(mapstruct *m)
Definition: map.cpp:798
disinfect.map
map
Definition: disinfect.py:4
P_NEW_MAP
#define P_NEW_MAP
Definition: map.h:249
decay_objects
void decay_objects(mapstruct *m)
Definition: utils.cpp:175
SAVE_ERROR_CLOSE
#define SAVE_ERROR_CLOSE
Definition: map.h:146
object_value_set_shared
bool object_value_set_shared(const object *op, sstring key)
Definition: object.cpp:4381
of_cancel
void of_cancel(OutputFile *of)
Definition: output_file.cpp:89
get_typedata
const typedata * get_typedata(int itemtype)
Definition: item.cpp:327
P_NO_ERROR
#define P_NO_ERROR
Definition: map.h:239
MSG_TYPE_ATTACK_NOKEY
#define MSG_TYPE_ATTACK_NOKEY
Definition: newclient.h:606
check_inv_recursive
object * check_inv_recursive(object *op, const object *trig)
Definition: button.cpp:782
path_combine_and_normalize
char * path_combine_and_normalize(const char *src, const char *dst, char *path, size_t size)
Definition: path.cpp:172
load_unique_objects
static void load_unique_objects(mapstruct *m)
Definition: map.cpp:1347
archetype::clone
object clone
Definition: object.h:478
of
a copper bar weighs and has a value of
Definition: ore.txt:3
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
first_map
mapstruct * first_map
Definition: init.cpp:107
isqrt
int isqrt(int n)
Definition: utils.cpp:559
HEAD
#define HEAD(op)
Definition: object.h:598
clean_tmp_map
void clean_tmp_map(mapstruct *m)
Definition: map.cpp:1942
SAVE_ERROR_RCREATION
#define SAVE_ERROR_RCREATION
Definition: map.h:141
MAP_WHEN_RESET
#define MAP_WHEN_RESET(m)
Definition: map.h:62
change_map_light
int change_map_light(mapstruct *m, int change)
Definition: map.cpp:1983
object::move_type
MoveType move_type
Definition: object.h:434
ext_info_map
void void ext_info_map(int color, const mapstruct *map, uint8_t type, uint8_t subtype, const char *str1)
Definition: main.cpp:334
mapfile_load_lowlevel
mapstruct * mapfile_load_lowlevel(const char *map, const char *pathname, int flags)
Definition: map.cpp:1175
object::face
const Face * face
Definition: object.h:341
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Definition: map.cpp:2286
MAX_DARKNESS
#define MAX_DARKNESS
Definition: define.h:454
MSG_TYPE_ATTACK
#define MSG_TYPE_ATTACK
Definition: newclient.h:398
MOVE_FLYING
#define MOVE_FLYING
Definition: define.h:395
EVENT_MAPUNLOAD
#define EVENT_MAPUNLOAD
Definition: events.h:51
INS_NO_MERGE
#define INS_NO_MERGE
Definition: object.h:571
FLAG_DAMNED
#define FLAG_DAMNED
Definition: define.h:317
SET_MAP_FLAGS
#define SET_MAP_FLAGS(M, X, Y, C)
Definition: map.h:160
remove_button_link
void remove_button_link(object *op)
Definition: button.cpp:693
MAP_LAYER_LIVING1
#define MAP_LAYER_LIVING1
Definition: map.h:46
shopitems::name_pl
const char * name_pl
Definition: map.h:296
MAP_LAYER_FLY1
#define MAP_LAYER_FLY1
Definition: map.h:48
object_free
void object_free(object *ob, int flags)
Definition: object.cpp:1587
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:191
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:677
MAP_DEFAULTRESET
#define MAP_DEFAULTRESET
Definition: config.h:427
free_map
void free_map(mapstruct *m)
Definition: map.cpp:1650
disinfect.count
int count
Definition: disinfect.py:7
level_exp
int64_t level_exp(int level, double expmul)
Definition: living.cpp:1874
free_all_objects
static void free_all_objects(mapstruct *m)
Definition: map.cpp:1603
archetype
Definition: object.h:474
P_PLAYER
#define P_PLAYER
Definition: map.h:235
Settings::playerdir
const char * playerdir
Definition: global.h:250
sproto.h
get_map_from_coord
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
Definition: map.cpp:2359
get_rangevector_from_mapcoord
int get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval)
Definition: map.cpp:2587
map_find_by_flag
object * map_find_by_flag(mapstruct *map, int x, int y, int flag)
Definition: map.cpp:2648
delete_map
void delete_map(mapstruct *m)
Definition: map.cpp:1696
MSG_SUBTYPE_NONE
#define MSG_SUBTYPE_NONE
Definition: newclient.h:409
ob_blocked
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Definition: map.cpp:478
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
NDI_BLACK
#define NDI_BLACK
Definition: newclient.h:231
SAVE_ERROR_NO_PATH
#define SAVE_ERROR_NO_PATH
Definition: map.h:144
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.cpp:2095
link_multipart_objects
static void link_multipart_objects(mapstruct *m)
Definition: map.cpp:574
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
get_typedata_by_name
const typedata * get_typedata_by_name(const char *name)
Definition: item.cpp:347
get_linked_map
mapstruct * get_linked_map(void)
Definition: map.cpp:775
seconds
long seconds(void)
Definition: time.cpp:344
MAP_WIDTH
#define MAP_WIDTH(m)
Definition: map.h:74
create_template_pathname
void create_template_pathname(const char *name, char *buf, size_t size)
Definition: map.cpp:144
P_OUT_OF_MAP
#define P_OUT_OF_MAP
Definition: map.h:248
MAX_BUF
#define MAX_BUF
Definition: define.h:35
INS_ON_TOP
#define INS_ON_TOP
Definition: object.h:574
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.cpp:222
object_new
object * object_new(void)
Definition: object.cpp:1268
create_overlay_pathname
void create_overlay_pathname(const char *name, char *buf, size_t size)
Definition: map.cpp:124
OB_MOVE_BLOCK
#define OB_MOVE_BLOCK(ob1, ob2)
Definition: define.h:423
shopitems::typenum
int typenum
Definition: map.h:297
set_map_reset_time
void set_map_reset_time(mapstruct *map)
Definition: map.cpp:2221
path
pluglist shows those as well as a short text describing each the list will simply appear empty The keyword for the Python plugin is Python plugout< keyword > Unloads a given identified by its _keyword_ So if you want to unload the Python you need to do plugout Python plugin< libname > Loads a given whose _filename_ is libname So in the case of you d have to do a plugin cfpython so Note that all filenames are relative to the default plugin path(SHARE/plugins). Console messages. ----------------- When Crossfire starts
free_string
void free_string(sstring str)
Definition: shstr.cpp:280
SAVE_MODE_NORMAL
#define SAVE_MODE_NORMAL
Definition: map.h:117
SAVE_ERROR_UCREATION
#define SAVE_ERROR_UCREATION
Definition: map.h:142
Map_Layer_Info::high_layer
uint8_t high_layer
Definition: map.cpp:52
SET_MAP_MOVE_SLOW
#define SET_MAP_MOVE_SLOW(M, X, Y, C)
Definition: map.h:198
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Definition: map.h:216
find_dir_2
int find_dir_2(int x, int y)
Definition: object.cpp:3668
load_and_link_tiled_map
static mapstruct * load_and_link_tiled_map(mapstruct *orig_map, int tile_num)
Definition: map.cpp:2247
Face::visibility
uint8_t visibility
Definition: face.h:16
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
MAP_LAYER_NO_PICK1
#define MAP_LAYER_NO_PICK1
Definition: map.h:41
INS_MAP_LOAD
#define INS_MAP_LOAD
Definition: object.h:576
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:251
fatal
void fatal(enum fatal_error err)
Definition: utils.cpp:570
MapSpace::flags
uint8_t flags
Definition: map.h:259
load_map_header
static int load_map_header(FILE *fp, mapstruct *m)
Definition: map.cpp:988
FREE_AND_CLEAR
#define FREE_AND_CLEAR(xyz)
Definition: global.h:193
shopitems::name
const char * name
Definition: map.h:295
adjacent_map
static int adjacent_map(const mapstruct *map1, const mapstruct *map2, int *dx, int *dy)
Definition: map.cpp:2442
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.cpp:299
item
Definition: item.py:1
P_NEED_UPDATE
#define P_NEED_UPDATE
Definition: map.h:238
mapstruct
Definition: map.h:314
create_pathname
char * create_pathname(const char *name, char *buf, size_t size)
Definition: map.cpp:103
give.op
op
Definition: give.py:33
autojail.value
value
Definition: autojail.py:6
Floor.t
t
Definition: Floor.py:62
mapstruct::in_memory
uint32_t in_memory
Definition: map.h:335
rv_vector
Definition: map.h:370
update_buttons
void update_buttons(mapstruct *m)
Definition: button.cpp:227
MAP_SWAPPED
#define MAP_SWAPPED
Definition: map.h:128
objects
object * objects
Definition: object.cpp:294
exit
Install Bug reporting Credits but rather whatever guild name you are using *With the current map and server there are three they and GreenGoblin *Whatever name you give the folder should but it will still use GUILD_TEMPLATE *You can change what guild it uses by editing the map files Modify Map or objects if you want to use the optional Python based Guild Storage hall The first three are on the main the next two are in the guild_hq and the final one is in hallofjoining Withe the Storage three objects are found on the main floor and the last two are in the basement It s not that but you will need a map editor You find the object that has the click edit and change the line script options(which currently is "GUILD_TEMPALTE") to the guild you wish to use. And make sure you use the same one for all of them or it won 't work. Here 's a quick HOWTO for using the map editor to make these changes edit the mainfloor map exit(x15, y29 - set to/Edit/This/Exit/Path in the template) back to the world map as well. If you are using the Storage Hall map(storage_hall)
shopitems
Definition: map.h:294
map_get_path
const char * map_get_path(const object *item)
Definition: map.cpp:2690
diamondslots.y
y
Definition: diamondslots.py:16
SET_MAP_MOVE_BLOCK
#define SET_MAP_MOVE_BLOCK(M, X, Y, C)
Definition: map.h:193
on_same_map
int on_same_map(const object *op1, const object *op2)
Definition: map.cpp:2625
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
OutputFile
Definition: output_file.h:41
MAP_HEIGHT
#define MAP_HEIGHT(m)
Definition: map.h:76
save_object_in_sb
void save_object_in_sb(StringBuffer *sb, object *op, const int flag)
Definition: object.cpp:5295
MAP_ENTER_Y
#define MAP_ENTER_Y(m)
Definition: map.h:83
SAVE_ERROR_URENAME
#define SAVE_ERROR_URENAME
Definition: map.h:145
guild_entry.x1
int x1
Definition: guild_entry.py:33
Settings::mapdir
const char * mapdir
Definition: global.h:251
mapstruct::tile_map
mapstruct * tile_map[4]
Definition: map.h:354
typedata::number
int number
Definition: define.h:90
object_remove_from_active_list
void object_remove_from_active_list(object *op)
Definition: object.cpp:1387
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:229
mapstruct::spaces
MapSpace * spaces
Definition: map.h:345
S_IRUSR
#define S_IRUSR
Definition: win32.h:56
get_rangevector
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
Definition: map.cpp:2519
create-tower.tile
tile
Definition: create-tower.py:8
update_all_map_los
void update_all_map_los(mapstruct *map)
Definition: los.cpp:567
allocate_map
void allocate_map(mapstruct *m)
Definition: map.cpp:812
castle_read.key
key
Definition: castle_read.py:64
MAP_LAYER_FLY2
#define MAP_LAYER_FLY2
Definition: map.h:49
FMT64U
#define FMT64U
Definition: compat.h:17
SAVE_ERROR_OK
#define SAVE_ERROR_OK
Definition: map.h:140
loader.h
object_fix_multipart
void object_fix_multipart(object *tmp)
Definition: object.cpp:4676
Settings::datadir
const char * datadir
Definition: global.h:248
S_IWOTH
#define S_IWOTH
Definition: win32.h:41
fix_container_multipart
static void fix_container_multipart(object *container)
Definition: map.cpp:533
MAP_ENTER_X
#define MAP_ENTER_X(m)
Definition: map.h:81
strip_endline
void strip_endline(char *buf)
Definition: utils.cpp:314
object_remove
void object_remove(object *op)
Definition: object.cpp:1828
EVENT_MAPREADY
#define EVENT_MAPREADY
Definition: events.h:49
MAP_FLUSH
#define MAP_FLUSH
Definition: map.h:92
GET_MAP_FLAGS
#define GET_MAP_FLAGS(M, X, Y)
Definition: map.h:158
DOOR
@ DOOR
Definition: object.h:131
object_sum_weight
signed long object_sum_weight(object *op)
Definition: object.cpp:568
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
MAP_LAYER_LIVING2
#define MAP_LAYER_LIVING2
Definition: map.h:47
LL_NORMAL
#define LL_NORMAL
Definition: loader.h:12
OB_TYPE_MOVE_BLOCK
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Definition: define.h:432
S_IWGRP
#define S_IWGRP
Definition: win32.h:44
P_NO_CLERIC
#define P_NO_CLERIC
Definition: map.h:237
make_path_to_file
void make_path_to_file(const char *filename)
Definition: porting.cpp:164
save_map
int save_map(mapstruct *m, int flag)
Definition: map.cpp:1394
calculate_difficulty
int calculate_difficulty(mapstruct *m)
Definition: map.cpp:1885
FLAG_IS_LINKED
#define FLAG_IS_LINKED
Definition: define.h:315
mapstruct::next
mapstruct * next
Definition: map.h:315
object::stats
living stats
Definition: object.h:378
object::more
object * more
Definition: object.h:303
SET_MAP_PLAYER
#define SET_MAP_PLAYER(M, X, Y, C)
Definition: map.h:168
blocks_prayer
sstring blocks_prayer
Definition: init.cpp:126
MAP_TIMEOUT
#define MAP_TIMEOUT(m)
Definition: map.h:66
StringBuffer
Definition: stringbuffer.cpp:25
mapfile_load
mapstruct * mapfile_load(const char *map, int flags)
Definition: map.cpp:1216
LO_REPEAT
#define LO_REPEAT
Definition: loader.h:15
parse_shop_string
static shopitems * parse_shop_string(const char *input_string, const mapstruct *map)
Definition: map.cpp:864
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
MAP_MAXRESET
#define MAP_MAXRESET
Definition: config.h:425
SAVE_FLAG_SAVE_UNPAID
#define SAVE_FLAG_SAVE_UNPAID
Definition: map.h:107
rv_vector::direction
int direction
Definition: map.h:374
SET_MAP_LIGHT
#define SET_MAP_LIGHT(M, X, Y, L)
Definition: map.h:165
if
if(!(yy_init))
Definition: loader.c:2626
rv_vector::distance
unsigned int distance
Definition: map.h:371
map_layer_name
const char *const map_layer_name[MAP_LAYERS]
Definition: map.cpp:45
MAP_LOADING
#define MAP_LOADING
Definition: map.h:129
load_overlay_map
static int load_overlay_map(const char *filename, mapstruct *m)
Definition: map.cpp:1287
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:670
check_path
int check_path(const char *name, int prepend_dir)
Definition: map.cpp:200
altar_valkyrie.res
int res
Definition: altar_valkyrie.py:74
S_IRGRP
#define S_IRGRP
Definition: win32.h:53
dump_all_maps
void dump_all_maps(void)
Definition: map.cpp:267
events_execute_global_event
void events_execute_global_event(int eventcode,...)
Definition: events.cpp:27
load_objects
void load_objects(mapstruct *m, FILE *fp, int mapflags)
Definition: map.cpp:602
llevDebug
@ llevDebug
Definition: logger.h:13
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
P_BLOCKSVIEW
#define P_BLOCKSVIEW
Definition: map.h:225
LL_MORE
#define LL_MORE
Definition: loader.h:11
SET_MAP_MOVE_OFF
#define SET_MAP_MOVE_OFF(M, X, Y, C)
Definition: map.h:208
Map_Layer_Info
Definition: map.cpp:51