Crossfire Server  1.75.0
mapper.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire map browser generator.
3  *
4  * Author: Nicolas Weeger <nicolas.weeger@laposte.net>, (C) 2006-2021.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
180 #include <ctype.h>
181 #include <errno.h>
182 #include <stdio.h>
183 #include <stdlib.h>
184 #include <string.h>
185 #include <strings.h>
186 #include <sys/stat.h>
187 #include <sys/types.h>
188 #include <time.h>
189 
190 #include "global.h"
191 #include "sproto.h"
192 #include "image.h"
193 #include "quest.h"
194 
195 extern "C" {
196 #include <gd.h>
197 #include <gdfonts.h>
198 #include <gdfontl.h>
199 #include <gdfontg.h>
200 }
201 
202 #include "inja.hpp"
203 #include <map>
204 #include <set>
205 
206 static std::vector<gdImagePtr> gdfaces;
207 
210  const char *name;
211  const char *message;
212  int x, y;
213 };
214 
216 typedef std::vector<struct_npc_info *> npc_list;
217 
220  struct struct_race **races;
221  size_t count;
222  size_t allocated;
223 };
224 
228  size_t count;
229  size_t allocated;
230 };
231 
235  size_t count;
236  size_t allocated;
237 };
238 
241  char *path;
242  char *name;
243  char *filename;
244  char *lore;
246  int level, pic_was_done, max_monster, min_monster;
251 
253 
255 
258 
260  int height, width;
262  struct struct_map_info *tiles[4];
263 };
264 
267 
270 
273  char *name;
274  int power;
276  char *diff;
278 };
279 
280 static std::vector<struct_equipment *> special_equipment;
284 struct struct_race {
285  char *name;
286  int count;
288 };
289 
292 static std::set<std::string> reset_groups;
295 enum class SearchType {
296  Region = 1,
297  Map,
298  Item,
299  Monster,
300  Quest,
301  Count
302 };
303 
305 static std::string SearchName[int(SearchType::Count)] = {
306  "(invalid)",
307  "region",
308  "map",
309  "item",
310  "monster",
311  "quest",
312 };
313 
319 static void init_race_list(struct_race_list *list) {
320  list->races = NULL;
321  list->count = 0;
322  list->allocated = 0;
323 }
324 
335 static void add_race_to_list(struct_race *race, struct_race_list *list, int check) {
336  if (check) {
337  size_t test;
338 
339  for (test = 0; test < list->count; test++) {
340  if (list->races[test] == race)
341  return;
342  }
343  }
344 
345  if (list->allocated == list->count) {
346  list->allocated += 50;
347  list->races = (struct_race **)realloc(list->races, sizeof(struct_race *)*list->allocated);
348  }
349  list->races[list->count] = race;
350  list->count++;
351 }
352 
354 static char root[500];
355 
357 static int pics_allocated;
358 
359 /* Options */
360 static int generate_pics = 1;
361 static int force_pics = 0;
362 static int sizes[] = {32, 16, 8, 4, 2};
363 static const int num_sizes = sizeof(sizes)/sizeof(int);
364 #define size_large sizes[0]
365 #define size_small sizes[1]
366 static int map_limit = -1;
367 static int show_maps = 0;
368 static int world_map = 1;
369 static int world_exit_info = 1;
370 static int tileset = 0;
371 static bool detail_quests = false;
372 static bool list_system_quests = false;
373 static bool display_rendered_template = false;
374 static bool build_search_file = false;
377 static int created_pics = 0;
378 static int cached_pics = 0;
382  OF_PNG = 0,
383  OF_JPG = 1
384 };
385 
387 static const char *output_extensions[] = {
388  ".png",
389  ".jpg"
390 };
391 
394 
396 static int jpeg_quality = -1;
397 
399 static int rawmaps = 0;
400 
402 static int warn_no_path = 0;
403 
408  int sum_x, sum_y, sum;
409  int is_world;
410 };
411 
412 static struct struct_region_info **regions = NULL;
413 static size_t region_count = 0;
414 static size_t region_allocated = 0;
416 static int list_unused_maps = 0;
417 static std::vector<char *> found_maps;
419 /* Path/exit info */
420 static gdImagePtr infomap;
422 static int color_linked_exit;
423 static int color_road;
424 static int color_blocking;
425 static int color_slowing;
427 static int **elevation_info;
428 static int elevation_min;
429 static int elevation_max;
431 /* Whether to compute links between regions or not (expensive). */
432 static bool do_regions_link = false;
433 /* Links between regions, key is source, value are destinations. */
434 static std::map<region *, std::set<region *>> region_links;
435 
437 #define S_DOOR 0
438 #define S_KEY 1
439 #define S_CONTAINER 2
440 #define S_DETECTOR 3
441 #define S_CONNECT 4
442 #define S_MAX 5
443 
446  char *slaying;
448 };
449 
451 static size_t slaying_count = 0;
452 static size_t slaying_allocated = 0;
459 static void init_map_list(struct_map_list *list) {
460  list->maps = NULL;
461  list->count = 0;
462  list->allocated = 0;
463 }
464 
465 static void add_map(struct_map_info *info, struct_map_list *list);
466 
467 static int is_special_equipment(object *item) {
468  if (item->name == item->arch->clone.name && item->title == item->arch->clone.title)
469  return 0;
470  if (QUERY_FLAG(item, FLAG_NO_PICK))
471  return 0;
472  if (item->move_block == MOVE_ALL)
473  return 0;
474 
475  if (IS_SHIELD(item) || IS_WEAPON(item) || IS_ARMOR(item) || IS_ARROW(item) || (item->type == ROD) || (item->type == WAND) || (item->type == RING) || (item->type == AMULET))
476  return 1;
477 
478  return 0;
479 }
480 
487  struct_equipment *add = (struct_equipment *)calloc(1, sizeof(struct_equipment));
488 
489  init_map_list(&add->origin);
490  return add;
491 }
492 
499 static void free_equipment(struct_equipment *equip) {
500  free(equip->diff);
501  free(equip->name);
502  free(equip);
503 }
504 
513 static bool sort_equipment(const struct_equipment *l, const struct_equipment *r) {
514  int cmp = strcasecmp(l->name, r->name);
515  if (cmp)
516  return cmp < 0;
517  if (l->power != r->power)
518  return l->power < r->power;
519  if (l->calc_power != r->calc_power)
520  return l->calc_power < r->calc_power;
521 
522  return strcasecmp(l->diff, r->diff) < 0;
523 }
524 
534  assert(item);
535  auto existing = std::find_if(special_equipment.begin(), special_equipment.end(),
536  [&] (const auto *e) { return !sort_equipment(e, item) && !sort_equipment(item, e); });
537 
538  if (existing != special_equipment.end()) {
539  free_equipment(item);
540  return *existing;
541  }
542 
543  special_equipment.push_back(item);
544 
545  return item;
546 }
547 
557 static void add_one_item(object *item, struct_map_info *map) {
560  int x, y;
561  sstring name, namepl;
562  uint32_t nrof;
563  object *base;
564 
565  x = item->x;
566  y = item->y;
567  name = item->name;
568  namepl = item->name_pl;
569  nrof = item->nrof;
570 
571  if (item->artifact != NULL) {
572  const artifact *artifact;
573 
574  artifact = find_artifact(item, item->artifact);
575  if (artifact == NULL) {
576  LOG(llevError, "could not find artifact %s [%d] to save data\n", item->artifact, item->type);
577  base = arch_to_object(item->arch);
578  } else {
579  base = arch_to_object(item->arch);
580  give_artifact_abilities(base, artifact->item);
581  }
582  }
583  else {
584  base = arch_to_object(item->arch);
585  }
586 
587  item->x = base->x;
588  item->y = base->y;
589  item->name = base->name;
590  item->name_pl = base->name_pl;
591  item->nrof = base->nrof;
592 
593  if (QUERY_FLAG(item, FLAG_IDENTIFIED) && !QUERY_FLAG(base, FLAG_IDENTIFIED)) {
595  SET_FLAG(base, FLAG_IDENTIFIED);
596  }
597  if (QUERY_FLAG(item, FLAG_UNPAID))
598  SET_FLAG(base, FLAG_UNPAID);
599  get_ob_diff(bf, item, base);
601 
602  add->diff = stringbuffer_finish(bf);
603 
604  item->x = x;
605  item->y = y;
606  item->name = name;
607  item->name_pl = namepl;
608  item->nrof = nrof;
609 
610  if (add->diff == NULL || strcmp(add->diff, "") == 0) {
611  free_equipment(add);
612  return;
613  }
614 
615  add->name = strdup(item->name);
616  add->power = item->item_power;
617  add->calc_power = calc_item_power(item);
618 
619  add = ensure_unique(add);
620  add_map(map, &add->origin);
621 }
622 
631 static void check_equipment(object *item, struct_map_info *map) {
632  if (is_special_equipment(item))
633  add_one_item(item, map);
634 
635  FOR_INV_PREPARE(item, inv)
636  check_equipment(inv, map);
637  FOR_INV_FINISH();
638 }
639 
648 static struct_race *get_race(const char *name) {
649  size_t test;
650  struct_race *item;
651 
652  for (test = 0; test < races.count; test++) {
653  if (strcmp(races.races[test]->name, name) == 0) {
654  races.races[test]->count++;
655  return races.races[test];
656  }
657  }
658 
659  item = (struct_race *)calloc(1, sizeof(struct_race));
660  item->name = strdup(name);
661  item->count = 1;
662  init_map_list(&item->origin);
663 
664  add_race_to_list(item, &races, 0);
665 
666  return item;
667 }
668 
677 static void add_monster(object *monster, struct_map_info *map) {
678  struct_race *race;
679 
680  if (monster->head && monster != monster->head)
681  return;
682 
683  map->min_monster = MIN(monster->level, map->min_monster);
684  map->max_monster = MAX(monster->level, map->max_monster);
685 
686  race = get_race(monster->name ? monster->name : "(null race)");
687  add_map(map, &race->origin);
688  add_race_to_list(race, &map->monsters, 1);
689 }
690 
699 static int sort_race(const void *a, const void *b) {
700  const struct_race *l = *(const struct_race **)a;
701  const struct_race *r = *(const struct_race **)b;
702  return strcasecmp(l->name, r->name);
703 }
704 
712 static int is_road(object *item) {
713  int test;
714  /* Archetypes used as roads. */
715  const char *roads[] = {
716  "cobblestones",
717  "flagstone",
718  "ice_stone",
719  "snow",
720  NULL };
721  const char *partial[] = {
722  "dirtroad_",
723  NULL };
724 
725  for (test = 0; partial[test] != NULL; test++) {
726  if (strstr(item->arch->name, partial[test]) != NULL)
727  return 1;
728  }
729 
730  if (!QUERY_FLAG(item, FLAG_IS_FLOOR))
731  return 0;
732 
733  for (test = 0; roads[test] != NULL; test++) {
734  if (strcmp(item->arch->name, roads[test]) == 0)
735  return 1;
736  }
737 
738  return 0;
739 }
740 
748 static int is_blocking(object *item) {
749  return item->move_block == MOVE_ALL ? 1 : 0;
750 }
751 
762 static int get_elevation_color(int elevation, gdImagePtr elevationmap) {
763  if (elevation > 0)
764  return gdImageColorResolve(elevationmap, 200*elevation/elevation_max, 0, 0);
765  else
766  return gdImageColorResolve(elevationmap, 0, 0, 200*elevation/elevation_min);
767 }
768 
777 static void do_exit_map(mapstruct *map) {
778  int tx, ty, x, y;
779  object *test;
780 
781  if (sscanf(map->path, "/world/world_%d_%d", &x, &y) != 2)
782  return;
783 
784  x -= 100;
785  y -= 100;
786 
787  for (tx = 0; tx < MAP_WIDTH(map); tx++) {
788  for (ty = 0; ty < MAP_HEIGHT(map); ty++) {
789  FOR_MAP_PREPARE(map, tx, ty, item) {
790  test = HEAD(item);
791 
792  // Do this before we check for blocked tiles,
793  // otherwise we don't receive elevation data for blocked tiles.
794  int elevation = item->elevation;
795  if (elevation != 0) {
796  elevation_min = MIN(elevation_min, elevation);
797  elevation_max = MAX(elevation_max, elevation);
798  elevation_info[x*50+tx][y*50+ty] = elevation;
799  }
800 
801  if (test->type == EXIT || test->type == TELEPORTER) {
802  if (!test->slaying)
803  gdImageSetPixel(infomap, x*50+tx, y*50+ty, color_unlinked_exit);
804  else
805  gdImageSetPixel(infomap, x*50+tx, y*50+ty, color_linked_exit);
806  } else if (is_road(test))
807  gdImageSetPixel(infomap, x*50+tx, y*50+ty, color_road);
808  else if (is_blocking(test)) {
809  gdImageSetPixel(infomap, x*50+tx, y*50+ty, color_blocking);
810  /* can't get on the spot, so no need to go on. */
811  break;
812  } else if (test->move_slow != 0)
813  gdImageSetPixel(infomap, x*50+tx, y*50+ty, color_slowing);
814 
815  } FOR_MAP_FINISH();
816  }
817  }
818 }
819 
820 void do_auto_apply(mapstruct *m);
821 
834 static void relative_path(const char *from, const char *to, char *result) {
835  const char *fslash;
836  const char *rslash;
837 
838  result[0] = '\0';
839 
840  fslash = strchr(from+1, '/');
841  if (!fslash) {
842  strcpy(result, to+1);
843  return;
844  }
845 
846  rslash = strchr(to+1, '/');
847  while (fslash && rslash && (fslash-from == rslash-to) && strncmp(from, to, fslash-from+1) == 0) {
848  from = fslash+1;
849  to = rslash+1;
850  fslash = strchr(fslash+1, '/');
851  rslash = strchr(rslash+1, '/');
852  }
853 
854  while (fslash) {
855  strcat(result, "../");
856  fslash = strchr(fslash+1, '/');
857  }
858  if (strlen(result) && result[strlen(result)-1] == '/' && *to == '/')
859  result[strlen(result)-1] = '\0';
860  strcat(result, to);
861 }
862 
873 static int compare_map_info(const struct_map_info *left, const struct_map_info *right) {
874  int c;
875 
876  if (left->tiled_group)
877  left = left->tiled_group;
878  if (right->tiled_group)
879  right = right->tiled_group;
880 
881  // Shortcut -- if both are the same pointer, return 0.
882  // This occurs when tiled maps of the same set are compared to each other.
883  if (left == right)
884  return 0;
885 
886  c = strcasecmp(left->name, right->name);
887  if (c)
888  return c;
889 
890  return strcasecmp(left->path, right->path);
891 }
892 
903 static int sort_map_info(const void *left, const void *right) {
904  const struct_map_info *l = *(const struct_map_info **)left;
905  const struct_map_info *r = *(const struct_map_info **)right;
906  return compare_map_info(l, r);
907 }
908 
919 static int sort_region(const void *left, const void *right) {
920  return strcmp((*((struct_region_info **)left))->reg->name, (*((struct_region_info **)right))->reg->name);
921 }
922 
923 /************************************
924  Start of quest-related definitions.
925 ************************************/
926 
930  char *description;
931  struct struct_quest *quest;
932 };
933 
935 struct struct_quest {
936  char *name;
937  char *description;
938  int number;
941 };
942 
943 static struct_quest **quests = NULL;
945 static int quests_count = 0;
947 static int quests_allocated = 0;
950  list->list = NULL;
951  list->count = 0;
952  list->allocated = 0;
953 }
954 
956  if (list->count == list->allocated) {
957  list->allocated += 10;
958  list->list = (struct_map_in_quest **)realloc(list->list, sizeof(struct_map_in_quest *)*list->allocated);
959  }
960  list->list[list->count++] = item;
961 }
962 
968 static struct_quest *find_quest_info(const char *name) {
969  int test;
970  for (test = 0; test < quests_count; test++) {
971  if (strcmp(quests[test]->name, name) == 0)
972  return quests[test];
973  }
974  return NULL;
975 }
976 
985 static struct_quest *get_quest_info(const char *name) {
986  struct_quest *add = find_quest_info(name);
987  if (add) {
988  return add;
989  }
990 
991  if (quests_count == quests_allocated) {
992  quests_allocated += 10;
993  quests = (struct_quest **)realloc(quests, sizeof(struct_quest *)*quests_allocated);
994  }
995  add = (struct_quest *)calloc(1, sizeof(struct_quest));
996  add->name = strdup(name);
997  add->number = quests_count;
999  quests[quests_count] = add;
1000  quests_count++;
1001  return add;
1002 }
1003 
1014 static void add_map_to_quest(struct_map_info *map, const char *name, const char *description) {
1015  struct_map_in_quest *add;
1016  struct_quest *quest = get_quest_info(name);
1017 
1018  add = (struct_map_in_quest *)calloc(1, sizeof(struct_map_in_quest));
1019  add->map = map;
1020  add->quest = quest;
1021  add->description = strdup(description);
1022  while (strlen(add->description) && add->description[strlen(add->description)-1] == '\n')
1023  add->description[strlen(add->description)-1] = '\0';
1024  add_to_struct_map_in_quest_list(&quest->maps, add);
1026 }
1027 
1036 static int sort_struct_map_in_quest(const void *left, const void *right) {
1037  int c;
1038 
1039  const struct_map_in_quest *l = *(const struct_map_in_quest **)left;
1040  const struct_map_in_quest *r = *(const struct_map_in_quest **)right;
1041  const struct_map_info *ml = l->map;
1042  const struct_map_info *mr = r->map;
1043 
1044  if (ml->tiled_group)
1045  ml = ml->tiled_group;
1046  if (mr->tiled_group)
1047  mr = mr->tiled_group;
1048 
1049  c = strcasecmp(ml->name, mr->name);
1050  if (c)
1051  return c;
1052 
1053  return strcasecmp(ml->path, mr->path);
1054 }
1055 
1064 static int sort_struct_quest(const void *left, const void *right) {
1065  const struct_quest *l = *(const struct_quest **)left;
1066  const struct_quest *r = *(const struct_quest **)right;
1067  return strcasecmp(l->name, r->name);
1068 }
1069 
1080 static void define_quest(const char *name, struct_map_info *mainmap, const char *description) {
1081  struct_quest *quest = get_quest_info(name);
1082 
1083  if (quest->description || quest->mainmap) {
1084  printf("warning, multiple quest definition for %s, found in %s and %s.\n", quest->name, quest->mainmap ? quest->mainmap->path : "(unknown map)", mainmap->path);
1085  return;
1086  }
1087  quest->description = strdup(description);
1088  while (strlen(quest->description) && quest->description[strlen(quest->description)-1] == '\n')
1089  quest->description[strlen(quest->description)-1] = '\0';
1090  quest->mainmap = mainmap;
1091 }
1092 
1100  char *start, *end, *next;
1101  char name[500];
1102  char description[500];
1103 
1104  start = strstr(map->lore, "@def");
1105  while (start) {
1106  description[0] = '\0';
1107  /* find name */
1108  end = strstr(start, "\n");
1109  if (end) {
1110  strncpy(name, start+5, end-start-5);
1111  name[end-start-5] = '\0';
1112  next = end+1;
1113  end = strstr(next, "@end");
1114  if (end) {
1115  strncpy(description, next, end-next);
1116  description[end-next] = '\0';
1117  /* need to erase the text. */
1118  memmove(start, end+4, strlen(map->lore)-(end-start+3));
1119  end = start;
1120  }
1121  else {
1122  strcpy(description, next);
1123  *start = '\0';
1124  end = NULL;
1125  }
1126  } else {
1127  strcpy(name, start);
1128  *start = '\0';
1129  end = NULL;
1130  }
1131 
1132  define_quest(name, map, description);
1133  start = end ? strstr(end, "@def") : NULL;
1134  }
1135 
1136  start = strstr(map->lore, "@quest");
1137  while (start) {
1138  description[0] = '\0';
1139  /* find name */
1140  end = strstr(start, "\n");
1141  if (end) {
1142  strncpy(name, start+7, end-start-7);
1143  name[end-start-7] = '\0';
1144  next = end+1;
1145  end = strstr(next, "@end");
1146  if (end) {
1147  strncpy(description, next, end-next);
1148  description[end-next] = '\0';
1149  /* need to erase the text. */
1150  memmove(start, end+4, strlen(map->lore)-(end-start+3));
1151  end = start;
1152  }
1153  else {
1154  strcpy(description, next);
1155  *start = '\0';
1156  end = NULL;
1157  }
1158  } else {
1159  strcpy(name, start);
1160  *start = '\0';
1161  end = NULL;
1162  }
1163 
1164  add_map_to_quest(map, name, description);
1165  start = end ? strstr(end, "@quest") : NULL;
1166  }
1167 }
1168 
1169 /************************************
1170  End of quest-related definitions.
1171 ************************************/
1172 
1173 /*********
1174 NPC-related stuff
1175 ********/
1176 
1184 static struct_npc_info *create_npc_info(const object *npc) {
1185  struct_npc_info *info = (struct_npc_info *)calloc(1, sizeof(struct_npc_info));
1186 
1187  info->name = strdup(npc->name ? npc->name : "(null name)");
1188  info->message = strdup(npc->msg ? npc->msg : "(null msg)");
1189  info->x = npc->x;
1190  info->y = npc->y;
1191 
1192  return info;
1193 }
1194 
1202 static void add_npc_to_map(npc_list *list, const object *npc) {
1203  list->push_back(create_npc_info(npc));
1204 }
1205 /* end of NPC stuff */
1206 
1218 static void add_map(struct_map_info *info, struct_map_list *list) {
1219  size_t map;
1220 
1221  for (map = 0; map < list->count; map++)
1222  if (list->maps[map] == info)
1223  return;
1224 
1225  if (list->count == list->allocated) {
1226  list->allocated += 50;
1227  list->maps = (struct_map_info **)realloc(list->maps, list->allocated*sizeof(struct_map_info *));
1228  }
1229  list->maps[list->count] = info;
1230  list->count++;
1231 }
1232 
1240  struct_map_info *add = (struct_map_info *)calloc(1, sizeof(struct_map_info));
1241 
1242  add->min_monster = 2000;
1243  init_map_list(&add->exits_to);
1244  init_map_list(&add->exits_from);
1245  init_map_list(&add->tiled_maps);
1247  init_race_list(&add->monsters);
1248  add->npcs = new npc_list();
1249  add->readable = new npc_list();
1250  add->tiled_group = NULL;
1251 
1252  return add;
1253 }
1254 
1263 
1264  add_map(add, &tiled_map_list);
1265  return add;
1266 }
1267 
1277 static void merge_tiled_maps(struct_map_info *map, struct_map_info *tiled_map) {
1278  size_t g;
1279  struct_map_info *group = tiled_map->tiled_group;
1280  struct_map_info *change;
1281 
1282  while (group->tiled_maps.count > 0) {
1283  change = group->tiled_maps.maps[group->tiled_maps.count-1];
1284  change->tiled_group = map->tiled_group;
1285  add_map(change, &map->tiled_group->tiled_maps);
1286  group->tiled_maps.count--;
1287  }
1288 
1289  for (g = 0; g < tiled_map_list.count; g++) {
1290  if (tiled_map_list.maps[g] == group) {
1291  if (g < tiled_map_list.count-1)
1292  tiled_map_list.maps[g] = tiled_map_list.maps[tiled_map_list.count-1];
1293  tiled_map_list.count--;
1294  free(group);
1295  return;
1296  }
1297  }
1298  printf("tiled_map not in tiled_map_list!");
1299  abort();
1300 
1301 }
1302 
1311 static struct_map_info *get_map_info(const char *path) {
1312  struct_map_info *add;
1313  char *tmp;
1314 
1315  for (size_t map = 0; map < maps_list.count; map++) {
1316  if (strcmp(maps_list.maps[map]->path, path) == 0)
1317  return maps_list.maps[map];
1318  }
1319 
1320  add = create_map_info();
1321  add->path = strdup(path);
1322  tmp = strrchr((char *)path, '/');
1323  if (tmp)
1324  add->filename = strdup(tmp+1);
1325  else
1326  add->filename = strdup(path);
1327 
1328  add_map(add, &maps_list);
1329  return add;
1330 }
1331 
1338 static void list_map(const char *path) {
1339  for (auto map = found_maps.begin(); map != found_maps.end(); ++map) {
1340  if (strcmp(path, *map) == 0) {
1341  free(*map);
1342  found_maps.erase(map);
1343  return;
1344  }
1345  }
1346  printf("Map processed but not found in directory reading? %s\n", path);
1347 }
1348 
1359 static void add_map_to_region(struct_map_info *map, region *reg) {
1360  size_t test;
1361  int x, y;
1362 
1363  for (test = 0; test < region_count; test++) {
1364  if (regions[test]->reg == reg)
1365  break;
1366  }
1367  if (test == region_count) {
1368  if (test == region_allocated) {
1369  region_allocated++;
1370  regions = (struct_region_info **)realloc(regions, sizeof(struct_region_info *)*region_allocated);
1371  regions[test] = (struct_region_info *)calloc(1, sizeof(struct_region_info));
1372  }
1373  region_count++;
1374  regions[test]->reg = reg;
1375  }
1376  add_map(map, &regions[test]->maps_list);
1377  if (sscanf(map->path, "/world/world_%d_%d", &x, &y) == 2) {
1378  regions[test]->sum_x += (x-100);
1379  regions[test]->sum_y += (y-100);
1380  regions[test]->sum++;
1381  regions[test]->is_world = 1;
1382  }
1383 }
1384 
1393 static void save_picture(FILE *file, gdImagePtr pic) {
1394  if (output_format == OF_PNG)
1395  gdImagePng(pic, file);
1396  else
1397  gdImageJpeg(pic, file, jpeg_quality);
1398 }
1399 
1407 static void add_region_link(mapstruct *source, mapstruct *dest) {
1408  region *s, *d;
1409 
1410  s = get_region_by_map(source);
1411  d = get_region_by_map(dest);
1412  if (s == d)
1413  return;
1414 
1415  region_links[s].insert(d);
1416 }
1417 
1426 static int is_slaying(object *item) {
1427  return (item->type == LOCKED_DOOR || item->type == SPECIAL_KEY || item->type == CONTAINER || item->type == CHECK_INV);
1428 }
1429 
1430 
1439 static struct_slaying_info *get_slaying_struct(const char *slaying) {
1440  for (size_t l = 0; l < slaying_count; l++) {
1441  if (!strcmp(slaying_info[l]->slaying, slaying))
1442  return slaying_info[l];
1443  }
1444  if (slaying_count == slaying_allocated) {
1445  slaying_allocated += 10;
1446  slaying_info = (struct_slaying_info **)realloc(slaying_info, sizeof(struct_slaying_info *)*slaying_allocated);
1447  }
1448 
1449  struct_slaying_info *add = (struct_slaying_info *)calloc(1, sizeof(struct_slaying_info));
1450  add->slaying = strdup(slaying);
1451  for (size_t l = 0; l < S_MAX; l++)
1452  init_map_list(&add->maps[l]);
1453 
1454  slaying_info[slaying_count] = add;
1455  slaying_count++;
1456 
1457  return add;
1458 }
1459 
1470 static void add_map_to_slaying(struct_slaying_info *info, int item, struct_map_info *map) {
1471  add_map(map, &info->maps[item]);
1472 }
1473 
1482 static void add_slaying(struct_map_info *map, object *item) {
1483  struct_slaying_info *info;
1484 
1485  if (!item->slaying)
1486  /* can be undefined */
1487  return;
1488 
1489  info = get_slaying_struct(item->slaying);
1490  if (item->type == LOCKED_DOOR)
1491  add_map_to_slaying(info, S_DOOR, map);
1492  else if (item->type == SPECIAL_KEY)
1493  add_map_to_slaying(info, S_KEY, map);
1494  else if (item->type == CONTAINER)
1495  add_map_to_slaying(info, S_CONTAINER, map);
1496  else if (item->type == DETECTOR)
1497  add_map_to_slaying(info, S_DETECTOR, map);
1498  else
1499  add_map_to_slaying(info, S_CONNECT, map);
1500 }
1501 
1510 static void check_slaying_inventory(struct_map_info *map, object *item) {
1511  FOR_INV_PREPARE(item, inv) {
1512  if (is_slaying(inv))
1513  add_slaying(map, inv);
1514  check_slaying_inventory(map, inv);
1515  } FOR_INV_FINISH();
1516 }
1517 
1518 static void generate_picture_path(const char *path, size_t pic_size, char *out, size_t len) {
1519  snprintf(out, len, "%s%s.x%zu%s", root, path, pic_size + 1, output_extensions[output_format]);
1520 }
1521 
1522 static void write_pictures_from_real_size(const char *path, gdImagePtr real, int width, int height) {
1523  char picpath[MAX_BUF];
1524 
1525  generate_picture_path(path, 0, picpath, sizeof(picpath));
1526  make_path_to_file(picpath);
1527  FILE *out = fopen(picpath, "wb+");
1528  save_picture(out, real);
1529  fclose(out);
1530 
1531  for (size_t i = 1; i < num_sizes; i++) {
1532  generate_picture_path(path, i, picpath, sizeof(picpath));
1533  gdImagePtr small = gdImageCreateTrueColor(width*sizes[i], height*sizes[i]);
1534  gdImageCopyResampled(small, real, 0, 0, 0, 0, width*sizes[i], height*sizes[i], width*size_large, height*size_large);
1535  out = fopen(picpath, "wb+");
1536  save_picture(out, small);
1537  fclose(out);
1538  gdImageDestroy(small);
1539  }
1540 }
1541 
1550 static void process_map(struct_map_info *info) {
1551  mapstruct *m;
1552  int x, y, isworld;
1553  gdImagePtr pic = nullptr;
1554  struct stat stats;
1555  struct stat statspic;
1556  char exit_path[500];
1557  char tmppath[MAX_BUF];
1558  char picpath[num_sizes][MAX_BUF];
1559  int needpic = 0;
1560  struct_map_info *link;
1561 
1562  if (list_unused_maps)
1563  list_map(info->path);
1564 
1565  if (show_maps)
1566  printf(" processing map %s\n", info->path);
1567 
1568  m = ready_map_name(info->path, 0);
1569  if (!m) {
1570  printf("couldn't load map %s\n", info->path);
1571  return;
1572  }
1573 
1574  do_exit_map(m);
1575 
1576  if (!rawmaps)
1577  do_auto_apply(m);
1578 
1579  info->level = m->difficulty;
1580  if (m->maplore) {
1581  info->lore = strdup(m->maplore);
1582  process_map_lore(info);
1583  }
1584  if (m->reset_group) {
1585  info->reset_group = add_string(m->reset_group);
1586  reset_groups.insert(m->reset_group);
1587  }
1588 
1589  isworld = (sscanf(info->path, "/world/world_%d_%d", &x, &y) == 2);
1590 
1591  if (m->name)
1592  info->name = strdup(m->name);
1593  else
1594  info->name = strdup(info->filename);
1595 
1596  info->cfregion = get_region_by_map(m);
1597  add_map_to_region(info, info->cfregion);
1598 
1599  for (int i = 0; i < num_sizes; i++) {
1600  generate_picture_path(info->path, i, picpath[i], sizeof(picpath[i]));
1601  }
1602 
1603  if (force_pics)
1604  needpic = 1;
1605  else if (generate_pics) {
1606  create_pathname(info->path, tmppath, MAX_BUF);
1607  stat(tmppath, &stats);
1608  if (stat(picpath[0], &statspic) || (statspic.st_mtime < stats.st_mtime))
1609  needpic = 1;
1610  }
1611  else
1612  needpic = 0;
1613 
1614  if (needpic) {
1615  pic = gdImageCreateTrueColor(MAP_WIDTH(m)*size_large, MAP_HEIGHT(m)*size_large);
1616  created_pics++;
1617  }
1618  else
1619  cached_pics++;
1620 
1621  for (x = 0; x < 4; x++)
1622  if (m->tile_path[x] != NULL) {
1623  path_combine_and_normalize(m->path, m->tile_path[x], exit_path, sizeof(exit_path));
1624  create_pathname(exit_path, tmppath, MAX_BUF);
1625  if (stat(tmppath, &stats)) {
1626  printf(" map %s doesn't exist in map %s, for tile %d.\n", exit_path, info->path, x);
1627  }
1628 
1629  if (isworld) {
1630  link = get_map_info(exit_path);
1631  add_map(link, &info->exits_from);
1632  add_map(info, &link->exits_to);
1633 
1634  if (do_regions_link) {
1635  mapstruct *link = ready_map_name(exit_path, 0);
1636 
1637  if (link && link != m) {
1638  /* no need to link a map with itself. Also, if the exit points to the same map, we don't
1639  * want to reset it. */
1640  add_region_link(m, link);
1641  link->reset_time = 1;
1642  link->in_memory = MAP_IN_MEMORY;
1643  delete_map(link);
1644  }
1645  }
1646  } else {
1647  link = get_map_info(exit_path);
1648  info->tiles[x] = link;
1649  if (link->tiled_group) {
1650  if (info->tiled_group && link->tiled_group != info->tiled_group) {
1651  merge_tiled_maps(info, link);
1652  continue;
1653  }
1654  if (link->tiled_group == info->tiled_group) {
1655  continue;
1656  }
1657  if (!info->tiled_group) {
1658  add_map(info, &link->tiled_group->tiled_maps);
1659  continue;
1660  }
1661  }
1662 
1663  if (!info->tiled_group) {
1664  info->tiled_group = create_tiled_map();
1665  add_map(info, &info->tiled_group->tiled_maps);
1666  }
1667  link->tiled_group = info->tiled_group;
1668  add_map(link, &info->tiled_group->tiled_maps);
1669  }
1670  }
1671 
1672  info->width = MAP_WIDTH(m);
1673  info->height = MAP_HEIGHT(m);
1674 
1675  for (x = MAP_WIDTH(m)-1; x >= 0; x--)
1676  for (y = MAP_HEIGHT(m)-1; y >= 0; y--) {
1677  FOR_MAP_PREPARE(m, x, y, item) {
1678  if (item->type == EXIT || item->type == TELEPORTER || item->type == PLAYER_CHANGER) {
1679  char ep[500];
1680  const char *start;
1681 
1682  if (!item->slaying) {
1683  ep[0] = '\0';
1684  if (warn_no_path)
1685  printf(" exit without any path at %d, %d on %s\n", item->x, item->y, info->path);
1686  } else {
1687  memset(ep, 0, 500);
1688  if (strcmp(item->slaying, "/!"))
1689  strcpy(ep, EXIT_PATH(item));
1690  else {
1691  if (!item->msg) {
1692  printf(" random map without message in %s at %d, %d\n", info->path, item->x, item->y);
1693  } else {
1694  /* Some maps have a 'exit_on_final_map' flag, ignore it. */
1695  start = strstr(item->msg, "\nfinal_map ");
1696  if (!start && strncmp(item->msg, "final_map", strlen("final_map")) == 0)
1697  /* Message start is final_map, nice */
1698  start = item->msg;
1699  if (start) {
1700  char *end = strchr((char *)start+1, '\n');
1701 
1702  start += strlen("final_map")+2;
1703  strncpy(ep, start, end-start);
1704  }
1705  }
1706  }
1707 
1708  if (strlen(ep)) {
1709  path_combine_and_normalize(m->path, ep, exit_path, 500);
1710  create_pathname(exit_path, tmppath, MAX_BUF);
1711  if (stat(tmppath, &stats)) {
1712  printf(" map %s doesn't exist in map %s, at %d, %d.\n", ep, info->path, item->x, item->y);
1713  } else {
1714  link = get_map_info(exit_path);
1715  add_map(link, &info->exits_from);
1716  add_map(info, &link->exits_to);
1717 
1718  if (do_regions_link) {
1719  mapstruct *link = ready_map_name(exit_path, 0);
1720 
1721  if (link && link != m) {
1722  /* no need to link a map with itself. Also, if the exit points to the same map, we don't
1723  * want to reset it. */
1724  add_region_link(m, link);
1725  link->reset_time = 1;
1726  link->in_memory = MAP_IN_MEMORY;
1727  delete_map(link);
1728  }
1729  }
1730  }
1731  }
1732  }
1733  } else if (is_slaying(item))
1734  add_slaying(info, item);
1735 
1736  check_equipment(item, info);
1737 
1738  check_slaying_inventory(info, item);
1739 
1740  if (QUERY_FLAG(item, FLAG_MONSTER)) {
1741  /* need to get the "real" archetype, as the item's archetype can certainly be a temporary one. */
1742  archetype *arch = find_archetype(item->arch->name);
1743 
1744  add_monster(item, info);
1745  if (arch != NULL && (QUERY_FLAG(item, FLAG_UNAGGRESSIVE) || QUERY_FLAG(item, FLAG_FRIENDLY)) && (item->msg != arch->clone.msg) && (item->msg != NULL))
1746  add_npc_to_map(info->npcs, item);
1747  } else if ((item->type == SIGN || item->type == BOOK) && (item->msg != item->arch->clone.msg) && (item->msg != NULL)) {
1748  add_npc_to_map(info->readable, item);
1749  }
1750 
1751  if (item->invisible)
1752  continue;
1753 
1754  if (needpic) {
1755  int sx, sy, hx, hy;
1756 
1757  if (gdfaces.size() <= item->face->number)
1758  gdfaces.resize(item->face->number + 1, nullptr);
1759 
1760  if (gdfaces[item->face->number] == NULL) {
1761  face_sets *fs = find_faceset(get_face_fallback(tileset, item->face->number));
1762 
1763  gdfaces[item->face->number] = gdImageCreateFromPngPtr(fs->faces[item->face->number].datalen, fs->faces[item->face->number].data);
1764  pics_allocated++;
1765  }
1766  if (item->head || item->more) {
1767  object_get_multi_size(item, &sx, &sy, &hx, &hy);
1768  } else {
1769  hx = 0;
1770  hy = 0;
1771  }
1772  if (gdfaces[item->face->number] != NULL && ((!item->head && !item->more) || (item->arch->clone.x+hx == 0 && item->arch->clone.y+hy == 0))) {
1773  gdImageCopy(pic, gdfaces[item->face->number], x*size_large, y*size_large, 0, 0, gdfaces[item->face->number]->sx, gdfaces[item->face->number]->sy);
1774  }
1775  }
1776  } FOR_MAP_FINISH();
1777  }
1778 
1779  if (needpic) {
1781  gdImageDestroy(pic);
1782  info->pic_was_done = 1;
1783  }
1784 
1785  m->reset_time = 1;
1786  m->in_memory = MAP_IN_MEMORY;
1787  delete_map(m);
1788 }
1789 
1793 static void write_world_map(void) {
1794 #define SIZE 50
1795  int x, y;
1796  FILE *out;
1797  int wx, wy;
1798  char file[500];
1799  char mapleft[10], maptop[10], mapright[10], mapbottom[10], mappath[5000];
1800  char name[100];
1801  gdImagePtr pic;
1802  gdImagePtr small;
1803  gdFontPtr font;
1804  int color;
1805 
1806  if (!world_map)
1807  return;
1808 
1809  printf("Generating world map in world.html...");
1810  fflush(stdout);
1811 
1812  pic = gdImageCreateTrueColor(SIZE*30, SIZE*30);
1813 
1814  strcpy(file, root);
1815  strcat(file, "/world.html");
1816 
1817  wx = 100;
1818  wy = 100;
1819 
1820  for (y = 0; y < 30; y++) {
1821  for (x = 0; x < 30; x++) {
1822  snprintf(name, sizeof(name), "world_%d_%d", wx, wy);
1823  snprintf(mapleft, sizeof(mapleft), "%d", SIZE*x);
1824  snprintf(maptop, sizeof(maptop), "%d", SIZE*y);
1825  snprintf(mapright, sizeof(mapright), "%d", SIZE*(x+1)-1);
1826  snprintf(mapbottom, sizeof(mapbottom), "%d", SIZE*(y+1)-1);
1827 
1828  snprintf(mappath, sizeof(mappath), "%s/world/%s.x1%s", root, name, output_extensions[output_format]);
1829 
1830  out = fopen(mappath, "rb");
1831  if (!out) {
1832  printf("\n warning: large pic not found for world_%d_%d", wx, wy);
1833  wx++;
1834  continue;
1835  }
1836  if (output_format == OF_PNG)
1837  small = gdImageCreateFromPng(out);
1838  else
1839  small = gdImageCreateFromJpeg(out);
1840  fclose(out);
1841  if (!small) {
1842  printf("\n warning: pic not found for world_%d_%d", wx, wy);
1843  wx++;
1844  continue;
1845  }
1846  gdImageCopyResized(pic, small, SIZE*x, SIZE*y, 0, 0, SIZE, SIZE, small->sx, small->sy);
1847  gdImageDestroy(small);
1848 
1849  wx++;
1850  }
1851  wy++;
1852  wx = 100;
1853  }
1854 
1855  snprintf(mappath, sizeof(mappath), "%s/world_raw%s", root, output_extensions[output_format]);
1856  out = fopen(mappath, "wb+");
1857  save_picture(out, pic);
1858  fclose(out);
1859 
1860  /* Write region names. */
1861  small = gdImageCreateTrueColor(SIZE*30, SIZE*30);
1862  font = gdFontGetGiant();
1863  color = gdImageColorAllocateAlpha(pic, 255, 0, 0, 20);
1864  for (size_t region = 0; region < region_allocated; region++) {
1865  if (!regions[region]->is_world || regions[region]->sum == 0)
1866  continue;
1867 
1868  x = regions[region]->sum_x*SIZE/regions[region]->sum+SIZE/2-strlen(regions[region]->reg->name)*font->w/2;
1869  y = regions[region]->sum_y*SIZE/regions[region]->sum+SIZE/2-font->h/2;
1870  gdImageString(small, font, x, y, (unsigned char *)regions[region]->reg->name, color);
1871  gdImageString(pic, font, x, y, (unsigned char *)regions[region]->reg->name, color);
1872 
1873  /* For exit/road map, size isn't the same. */
1874  x = regions[region]->sum_x*50/regions[region]->sum+50/2-strlen(regions[region]->reg->name)*font->w/2;
1875  y = regions[region]->sum_y*50/regions[region]->sum+50/2-font->h/2;
1876  gdImageString(infomap, font, x, y, (unsigned char *)regions[region]->reg->name, color);
1877  }
1878 
1879  snprintf(mappath, sizeof(mappath), "%s/world_regions%s", root, output_extensions[output_format]);
1880  out = fopen(mappath, "wb+");
1881  save_picture(out, small);
1882  fclose(out);
1883  gdImageDestroy(small);
1884 
1885  snprintf(mappath, sizeof(mappath), "%s/world%s", root, output_extensions[output_format]);
1886  out = fopen(mappath, "wb+");
1887  save_picture(out, pic);
1888  fclose(out);
1889  gdImageDestroy(pic);
1890 
1891  printf(" done.\n");
1892 #undef SIZE
1893 }
1894 
1896 static void fix_map_names(void) {
1897  for (size_t map = 0; map < maps_list.count; map++) {
1898  if (maps_list.maps[map]->name)
1899  continue;
1900  if (!maps_list.maps[map]->filename) {
1901  printf("map without path!\n");
1902  abort();
1903  }
1904  maps_list.maps[map]->name = strdup(maps_list.maps[map]->filename);
1905  }
1906 }
1907 
1914 static void fix_tiled_map(void) {
1915  size_t map, tile;
1916  char name[500];
1917  char *slash, *test;
1918  region *cfregion;
1919 
1920  for (map = 0; map < tiled_map_list.count; map++) {
1921  if (tiled_map_list.maps[map]->tiled_maps.count == 0) {
1922  printf("empty tiled map group!");
1923  abort();
1924  }
1925 
1926  snprintf(name, sizeof(name), "tiled_map_group_%zu", map);
1927  tiled_map_list.maps[map]->filename = strdup(name);
1928 
1929  cfregion = NULL;
1930  test = NULL;
1931 
1932  for (tile = 0; tile < tiled_map_list.maps[map]->tiled_maps.count; tile++) {
1933  if (tiled_map_list.maps[map]->tiled_maps.maps[tile]->cfregion == NULL)
1934  /* map not processed, ignore it. */
1935  continue;
1936 
1937  if (!cfregion)
1938  cfregion = tiled_map_list.maps[map]->tiled_maps.maps[tile]->cfregion;
1939  else if (cfregion != tiled_map_list.maps[map]->tiled_maps.maps[tile]->cfregion) {
1940  printf("*** warning: tiled maps %s and %s not in same region (%s and %s).\n",
1941  tiled_map_list.maps[map]->tiled_maps.maps[0]->path, tiled_map_list.maps[map]->tiled_maps.maps[tile]->path,
1942  tiled_map_list.maps[map]->tiled_maps.maps[0]->cfregion->name, tiled_map_list.maps[map]->tiled_maps.maps[tile]->cfregion->name);
1943  cfregion = NULL;
1944  }
1945 
1946  if (strcmp(tiled_map_list.maps[map]->tiled_maps.maps[tile]->name, tiled_map_list.maps[map]->tiled_maps.maps[tile]->filename)) {
1947  /* map has a custom name, use it */
1948  if (!test)
1949  test = tiled_map_list.maps[map]->tiled_maps.maps[tile]->name;
1950  }
1951  }
1952 
1953  if (!test) {
1954  /* this can happen of course if only partial maps were processed, but well... */
1955  printf("*** warning: tiled map without any name. First map path %s\n", tiled_map_list.maps[map]->tiled_maps.maps[0]->path);
1956  test = name;
1957  }
1958 
1959  tiled_map_list.maps[map]->name = strdup(test);
1960  tiled_map_list.maps[map]->cfregion = cfregion;
1961 
1962  strncpy(name, tiled_map_list.maps[map]->tiled_maps.maps[0]->path, sizeof(name));
1963  slash = strrchr(name, '/');
1964  if (!slash)
1965  snprintf(name, sizeof(name), "/");
1966  else
1967  *(slash+1) = '\0';
1968  strncat(name, tiled_map_list.maps[map]->filename, sizeof(name) - strlen(name) - 1);
1969  tiled_map_list.maps[map]->path = strdup(name);
1970  }
1971 }
1972 
1983 static void fix_exits_for_map(struct_map_info *current, struct_map_list *from, int is_from) {
1984  int map, max;
1985  struct_map_info *group;
1986 
1987  max = from->count-1;
1988  for (map = max; map >= 0; map--) {
1989  if (from->maps[map]->tiled_group) {
1990  group = from->maps[map]->tiled_group;
1991  if (map != max)
1992  from->maps[map] = from->maps[max];
1993  from->count--;
1994  max--;
1995  add_map(group, from);
1996  add_map(current->tiled_group ? current->tiled_group : current, is_from ? &group->exits_to : &group->exits_from);
1997  }
1998  }
1999 }
2000 
2002 static void fix_exits_to_tiled_maps(void) {
2003  int map, max;
2004  struct_map_info *group;
2005 
2006  for (map = 0; static_cast<size_t>(map) < maps_list.count; map++) {
2007  fix_exits_for_map(maps_list.maps[map], &maps_list.maps[map]->exits_from, 1);
2008  fix_exits_for_map(maps_list.maps[map], &maps_list.maps[map]->exits_to, 0);
2009  }
2010 
2011  for (size_t region = 0; region < region_count; region++) {
2012  max = regions[region]->maps_list.count-1;
2013  for (map = max; map >= 0; map--) {
2014  if (regions[region]->maps_list.maps[map]->tiled_group) {
2015  group = regions[region]->maps_list.maps[map]->tiled_group;
2016  if (map != max)
2017  regions[region]->maps_list.maps[map] = regions[region]->maps_list.maps[max];
2018  regions[region]->maps_list.count--;
2019  max--;
2020  add_map(group, &regions[region]->maps_list);
2021  }
2022  }
2023  }
2024 }
2025 
2030 static void fix_tiled_map_monsters(void) {
2031  int map, max;
2032  struct_map_info *group;
2033 
2034  for (size_t race = 0; race < races.count; race++) {
2035  max = races.races[race]->origin.count-1;
2036  for (map = max; map >= 0; map--) {
2037  if (races.races[race]->origin.maps[map]->tiled_group) {
2038  group = races.races[race]->origin.maps[map]->tiled_group;
2039  if (map != max)
2040  races.races[race]->origin.maps[map] = races.races[race]->origin.maps[max];
2041  races.races[race]->origin.count--;
2042  max--;
2043  add_map(group, &races.races[race]->origin);
2044  }
2045  }
2046  }
2047 
2048  for (map = 0; static_cast<size_t>(map) < maps_list.count; map++) {
2049  if (maps_list.maps[map]->tiled_group) {
2050  for (size_t race = 0; race < maps_list.maps[map]->monsters.count; race++) {
2051  add_race_to_list(maps_list.maps[map]->monsters.races[race], &maps_list.maps[map]->tiled_group->monsters, 1);
2052  }
2053  }
2054  }
2055 }
2056 
2058  size_t test;
2059  char picpath[500];
2060  struct stat stats;
2061 
2062  for (size_t size = 0; size < num_sizes; size++) {
2063  generate_picture_path(map->path, size, picpath, sizeof(picpath));
2064  if (stat(picpath, &stats))
2065  return 1;
2066  }
2067 
2068  for (test = 0; test < map->tiled_maps.count; test++) {
2069  if (map->tiled_maps.maps[test]->pic_was_done)
2070  return 1;
2071  }
2072 
2073  return 0;
2074 }
2075 
2088  int xmin = 0, xmax = 0, ymin = 0, ymax = 0, count, last;
2089  size_t tiled;
2090  char picpath[500];
2091  gdImagePtr large, load;
2092  FILE *out;
2093  struct_map_info *current;
2094 
2095  if (!generate_pics)
2096  return;
2097 
2098  printf(" Generating composite map for %s...", map->name);
2099  fflush(stdout);
2100 
2101  if (!tiled_map_need_pic(map)) {
2102  printf(" already uptodate.\n");
2103  return;
2104  }
2105 
2106  count = map->tiled_maps.count;
2107  if (count == 0) {
2108  printf("Tiled map without tiled maps?\n");
2109  abort();
2110  }
2111  map->tiled_maps.maps[0]->processed = 1;
2112  map->tiled_maps.maps[0]->tiled_x_from = 0;
2113  map->tiled_maps.maps[0]->tiled_y_from = 0;
2114 
2115  while (count > 0) {
2116  last = count;
2117 
2118  for (tiled = 0; tiled < map->tiled_maps.count; tiled++) {
2119  current = map->tiled_maps.maps[tiled];
2120  if (current->processed != 1)
2121  continue;
2122 
2123  count--;
2124 
2125  if ((current->tiles[0]) && (current->tiles[0]->processed == 0)) {
2126  current->tiles[0]->processed = 1;
2127  current->tiles[0]->tiled_x_from = current->tiled_x_from;
2128  current->tiles[0]->tiled_y_from = current->tiled_y_from-current->tiles[0]->height;
2129  }
2130  if ((current->tiles[1]) && (current->tiles[1]->processed == 0)) {
2131  current->tiles[1]->processed = 1;
2132  current->tiles[1]->tiled_x_from = current->tiled_x_from+current->width;
2133  current->tiles[1]->tiled_y_from = current->tiled_y_from;
2134  }
2135  if ((current->tiles[2]) && (current->tiles[2]->processed == 0)) {
2136  current->tiles[2]->processed = 1;
2137  current->tiles[2]->tiled_x_from = current->tiled_x_from;
2138  current->tiles[2]->tiled_y_from = current->tiled_y_from+current->height;
2139  }
2140  if ((current->tiles[3]) && (current->tiles[3]->processed == 0)) {
2141  current->tiles[3]->processed = 1;
2142  current->tiles[3]->tiled_x_from = current->tiled_x_from-current->tiles[3]->width;
2143  current->tiles[3]->tiled_y_from = current->tiled_y_from;
2144  }
2145  }
2146 
2147  if (last == count) {
2148  printf("do_tiled_map_picture: didn't process any map in %s (%d left)??\n", map->path, last);
2149  abort();
2150  }
2151  }
2152 
2153  for (tiled = 0; tiled < map->tiled_maps.count; tiled++) {
2154  if (map->tiled_maps.maps[tiled]->tiled_x_from < xmin)
2155  xmin = map->tiled_maps.maps[tiled]->tiled_x_from;
2156  if (map->tiled_maps.maps[tiled]->tiled_y_from < ymin)
2157  ymin = map->tiled_maps.maps[tiled]->tiled_y_from;
2158  if (map->tiled_maps.maps[tiled]->tiled_x_from+map->tiled_maps.maps[tiled]->width > xmax)
2159  xmax = map->tiled_maps.maps[tiled]->tiled_x_from+map->tiled_maps.maps[tiled]->width;
2160  if (map->tiled_maps.maps[tiled]->tiled_y_from+map->tiled_maps.maps[tiled]->height > ymax)
2161  ymax = map->tiled_maps.maps[tiled]->tiled_y_from+map->tiled_maps.maps[tiled]->height;
2162  }
2163 
2164  large = gdImageCreateTrueColor(size_large*(xmax-xmin), size_large*(ymax-ymin));
2165 
2166  for (tiled = 0; tiled < map->tiled_maps.count; tiled++) {
2167  generate_picture_path(map->tiled_maps.maps[tiled]->path, 0, picpath, sizeof(picpath));
2168 
2169  out = fopen(picpath, "rb");
2170  if (!out) {
2171  printf("\n do_tiled_map_picture: warning: pic file %s not found for %s (errno=%d)\n", picpath, map->tiled_maps.maps[tiled]->path, errno);
2172  continue;
2173  }
2174  if (output_format == OF_PNG)
2175  load = gdImageCreateFromPng(out);
2176  else
2177  load = gdImageCreateFromJpeg(out);
2178  fclose(out);
2179  if (!load) {
2180  printf("\n do_tiled_map_picture: warning: pic not found for %s\n", map->tiled_maps.maps[tiled]->path);
2181  continue;
2182  }
2183  gdImageCopy(large, load, size_large*(map->tiled_maps.maps[tiled]->tiled_x_from-xmin), size_large*(map->tiled_maps.maps[tiled]->tiled_y_from-ymin), 0, 0, load->sx, load->sy);
2184  gdImageDestroy(load);
2185  }
2186 
2187  write_pictures_from_real_size(map->path, large, xmax-xmin, ymax-ymin);
2188 
2189  gdImageDestroy(large);
2190 
2191  printf(" done.\n");
2192 }
2193 
2196 
2197  do_tiled_map_picture(map);
2198 
2201 // write_map_page(map);
2202 }
2203 
2205 static void write_tiled_maps(void) {
2206  printf("Writing tiled map information...\n");
2207 
2208  for (size_t map = 0; map < tiled_map_list.count; map++)
2209  write_tiled_map_page(tiled_map_list.maps[map]);
2210 
2211  printf(" done.\n");
2212 }
2213 
2214 static std::vector<quest_definition *> system_quests;
2215 
2216 static void quest_callback(const quest_definition *quest, void *) {
2217  if (list_system_quests || !quest->quest_is_system) {
2218  system_quests.push_back(const_cast<quest_definition *>(quest));
2219  }
2220 }
2221 
2222 static std::shared_ptr<inja::Environment> env;
2223 static nlohmann::json all_data;
2224 static std::set<std::string> rendered_templates;
2225 static std::map<struct_map_info *, std::string> reverse_maps;
2226 static std::map<region *, std::string> reverse_regions;
2233 static struct_map_info *find_map_by_key(const std::string &key) {
2234  auto found = std::find_if(reverse_maps.cbegin(), reverse_maps.cend(), [&key] (auto c) { return c.second == key; });
2235  if (found != reverse_maps.cend())
2236  return found->first;
2237  return nullptr;
2238 }
2239 
2245 static region *find_region_by_key(const std::string &key) {
2246  auto found = std::find_if(reverse_regions.cbegin(), reverse_regions.cend(), [&key] (auto c) { return c.second == key; });
2247  if (found != reverse_regions.cend())
2248  return found->first;
2249  return nullptr;
2250 }
2251 
2257 static nlohmann::json create_maps_array(struct_map_list &maps) {
2258  nlohmann::json result = nlohmann::json::array();
2259  for (size_t m = 0; m < maps.count; m++) {
2260  auto map = reverse_maps.find(maps.maps[m]);
2261  if (map != reverse_maps.end()) {
2262  result.push_back(map->second);
2263  }
2264  }
2265  return result;
2266 }
2267 
2273 static nlohmann::json create_npc_array(npc_list &list) {
2274  nlohmann::json result;
2275  for (size_t n = 0; n < list.size(); n++) {
2276  auto npc = list[n];
2277  result.push_back({
2278  { "name", npc->name },
2279  { "x", npc->x },
2280  { "y", npc->y },
2281  { "message", npc->message },
2282  });
2283  }
2284  return result;
2285 }
2286 
2292 static nlohmann::json create_race_array(struct_race_list &list) {
2293  nlohmann::json result;
2294  for (size_t n = 0; n < list.count; n++) {
2295  auto race = list.races[n];
2296  result.push_back({
2297  { "name", race->name },
2298  { "count", race->count },
2299  });
2300  }
2301  return result;
2302 }
2303 
2310  nlohmann::json ret = nlohmann::json::array();
2311  for (size_t m = 0; m < list.count; m++) {
2312  auto q = list.list[m];
2313  if (!q->map || !q->description)
2314  continue;
2315  ret.push_back({
2316  { "map", reverse_maps.find(q->map)->second },
2317  { "description", q->description },
2318  { "quest", q->quest->name },
2319  { "number", q->quest->number },
2320  });
2321  }
2322 
2323  return ret;
2324 }
2325 
2326 static const char *remove_trailing_slash(const char *path)
2327 {
2328  return path && path[0] == '/' ? path + 1 : path;
2329 }
2330 
2337 static nlohmann::json create_map_object(struct_map_info *map, const std::string &key) {
2338  return {
2339  { "_key", key },
2340  { "name", map->name },
2341  { "path", remove_trailing_slash(map->path) },
2342  { "region", map->cfregion ? reverse_regions[map->cfregion] : "reg_ffff" },
2343  { "level", map->level },
2344  { "reset_group", map->reset_group ? map->reset_group : "" },
2345  { "lore", map->lore && map->lore[0] ? map->lore : "" },
2346  { "exits_to", create_maps_array(map->exits_to) },
2347  { "exits_from", create_maps_array(map->exits_from) },
2348  { "npcs", create_npc_array(*map->npcs) },
2349  { "readables", create_npc_array(*map->readable) },
2350  { "monsters", create_race_array(map->monsters) },
2351  { "quests", create_map_in_quest_array(map->quests) },
2352  };
2353 }
2354 
2361 static nlohmann::json create_quest_object(struct_quest *quest, const std::string &key) {
2362  return {
2363  { "_key", key },
2364  { "number", quest->number },
2365  { "name", quest->name ? quest->name : "" },
2366  { "description", quest->description ? quest->description : "" },
2367  { "main_map", quest->mainmap ? reverse_maps.find(quest->mainmap)->second : "" },
2368  { "maps", create_map_in_quest_array(quest->maps) },
2369  };
2370 }
2371 
2377  char buf[50];
2378  for (size_t map = 0; map < list.count; map++) {
2379  auto cur = list.maps[map];
2380  if (cur->tiled_group)
2381  continue;
2382  snprintf(buf, sizeof(buf), "map_%04lu", map);
2383  reverse_maps.insert(std::make_pair(cur, buf));
2384  qsort(cur->exits_to.maps, cur->exits_to.count, sizeof(struct_map_info *), sort_map_info);
2385  qsort(cur->exits_from.maps, cur->exits_from.count, sizeof(struct_map_info *), sort_map_info);
2386  qsort(cur->monsters.races, cur->monsters.count, sizeof(struct_race *), sort_race);
2387  }
2388 }
2389 
2396  for (size_t map = 0; map < src.count; map++)
2397  add_map(src.maps[map], &dest);
2398 }
2399 
2405 static nlohmann::json create_region_array(const std::set<region *> &regions) {
2406  nlohmann::json ret = nlohmann::json::array();
2407  for (auto reg : regions) {
2408  auto r = reverse_regions.find(reg);
2409  if (r != reverse_regions.end()) {
2410  ret.push_back((*r).second);
2411  }
2412  }
2413  return ret;
2414 }
2415 
2416 static inja::TemplateStorage templateCache;
2417 static inja::Template get_template(const std::string &filename) {
2418  auto find = templateCache.find(filename);
2419  if (find != templateCache.end()) {
2420  return find->second;
2421  }
2422  inja::Template parsed = env->parse_template(filename);
2423  templateCache[filename] = parsed;
2424  return parsed;
2425 }
2426 
2431 static void fill_json(nlohmann::json &json) {
2432  nlohmann::json maps;
2433  char buf[10];
2434  struct_map_list all_maps;
2435  bool need_unknown_region = false;
2436  nlohmann::json search;
2437 
2438  init_map_list(&all_maps);
2439  append_map_list(all_maps, maps_list);
2440  append_map_list(all_maps, tiled_map_list);
2441  qsort(all_maps.maps, all_maps.count, sizeof(struct_map_info *), sort_map_info);
2442 
2443  fill_reverse_maps(all_maps);
2444 
2445  for (size_t reg = 0; reg < region_count; reg++) {
2446  auto region = regions[reg];
2447  snprintf(buf, sizeof(buf), "reg_%04lu", reg);
2448  reverse_regions.insert(std::make_pair(region->reg, buf));
2449  }
2450 
2451  for (size_t reg = 0; reg < region_count; reg++) {
2452  auto region = regions[reg];
2453  qsort(region->maps_list.maps, region->maps_list.count, sizeof(struct_map_info *), sort_map_info);
2454  nlohmann::json r = {
2455  { "_key", reverse_regions[region->reg] },
2456  { "_index", reg },
2457  { "name", region->reg->name },
2458  { "longname", region->reg->longname },
2459  { "description", region->reg->msg ? region->reg->msg : "" },
2460  { "maps", create_maps_array(region->maps_list) },
2461  { "links", create_region_array(region_links[region->reg]) },
2462  };
2463  json["regions"].push_back(r);
2464  auto link = env->render(get_template("search-links/region"), r);
2465  search["reg_" + std::to_string(reg)] = {
2466  { "type" , SearchType::Region },
2467  { "name", region->reg->longname },
2468  { "text", std::string(region->reg->msg ? region->reg->msg : "") },
2469  { "url", link },
2470  };
2471  }
2472 
2473  size_t map_index = 0;
2474  for (auto map : reverse_maps) {
2475  auto cur = map.first;
2476  if (cur->tiled_group)
2477  continue;
2478  if (cur->cfregion == nullptr)
2479  need_unknown_region = true;
2480  auto m = create_map_object(cur, map.second);
2481  m["_index"] = map_index;
2482  json["maps"].push_back(m);
2483  auto link = env->render(get_template("search-links/map"), m);
2484  search["map_" + std::to_string(map_index++)] = {
2485  { "type", SearchType::Map },
2486  { "name", cur->name },
2487  { "text", std::string(cur->lore ? cur->lore : "") },
2488  { "url", link },
2489  };
2490  }
2491 
2492  if (need_unknown_region) {
2493  json["regions"].push_back({
2494  { "_key", "reg_ffff" },
2495  { "name", "unknown" },
2496  { "longname", "unknown" },
2497  { "description", "unknown" },
2498  { "maps", nlohmann::json::array() },
2499  { "links", nlohmann::json::array() },
2500  });
2501  }
2502 
2503  json["reset_groups"] = nlohmann::json::array();
2504  for (const auto &rg : reset_groups) {
2505  json["reset_groups"].push_back(rg);
2506  }
2507 
2508  json["items"] = nlohmann::json::array();
2509  for (size_t idx = 0; idx < special_equipment.size(); idx++) {
2510  auto eq = special_equipment[idx];
2511  nlohmann::json item = {
2512  { "_index", idx },
2513  { "name", eq->name },
2514  { "power", eq->power },
2515  { "calc_power", eq->calc_power },
2516  { "diff", eq->diff },
2517  { "maps", create_maps_array(eq->origin) },
2518  };
2519  json["items"][idx] = item;
2520  auto link = env->render(get_template("search-links/item"), item);
2521  search["item_" + std::to_string(idx)] = {
2522  { "type", SearchType::Item },
2523  { "name", eq->name },
2524  { "url", link },
2525  };
2526  }
2527 
2528  json["monsters"] = nlohmann::json::array();
2529  for (size_t item = 0; item < races.count; item++) {
2530  auto race = races.races[item];
2531  qsort(race->origin.maps, race->origin.count, sizeof(struct_map_info *), sort_map_info);
2532  nlohmann::json m = {
2533  { "_index", item },
2534  { "name", race->name },
2535  { "count", race->count },
2536  { "maps", create_maps_array(race->origin) },
2537  };
2538  json["monsters"].push_back(m);
2539  auto link = env->render(get_template("search-links/monster"), m);
2540  search["monster_" + std::to_string(item)] = {
2541  { "type", SearchType::Monster },
2542  { "name", race->name },
2543  { "url", link },
2544  };
2545  }
2546 
2547  json["system_quests"] = nlohmann::json::array();
2548  for (size_t q = 0; q < system_quests.size(); q++) {
2549  auto quest = system_quests[q];
2550  nlohmann::json j({
2551  { "_index", q },
2552  { "code", quest->quest_code },
2553  { "title", quest->quest_title },
2554  { "description", quest->quest_description ? quest->quest_description : "" },
2555  { "replayable", quest->quest_restart },
2556  { "steps", nlohmann::json::array() },
2557  { "maps", nlohmann::json::array() },
2558  });
2559 
2560  if (detail_quests) {
2561  std::sort(quest->steps.begin(), quest->steps.end(), [] (auto left, auto right) { return left->step < right->step; });
2562  for (size_t s = 0; s < quest->steps.size(); s++) {
2563  j["steps"].push_back({
2564  { "description", quest->steps[s]->step_description ? quest->steps[s]->step_description : "" },
2565  { "is_completion", quest->steps[s]->is_completion_step ? true : false },
2566  });
2567  }
2568 
2569  auto qim = find_quest_info(quest->quest_code);
2570  if (qim) {
2571  for (size_t m = 0; m < qim->maps.count; m++) {
2572  auto map = reverse_maps.find(qim->maps.list[m]->map);
2573  assert(map != reverse_maps.end());
2574  j["maps"].push_back({
2575  { "description", qim->maps.list[m]->description },
2576  { "map", map->second },
2577  });
2578  }
2579  }
2580  }
2581  json["system_quests"].push_back(j);
2582  search["quest_" + std::to_string(q)] = {
2583  { "type", SearchType::Quest },
2584  { "name", quest->quest_title ? quest->quest_title : "" },
2585  { "text", quest->quest_description ? quest->quest_description : "" },
2586  { "url", "system_quests.html#q" + std::to_string(q) },
2587  };
2588  }
2589 
2590  json["slaying"] = nlohmann::json::array();
2591  for (size_t s = 0; s < slaying_count; s++) {
2592  auto info = slaying_info[s];
2593  json["slaying"].push_back({
2594  { "slaying", info->slaying },
2595  { "doors", create_maps_array(info->maps[S_DOOR]) },
2596  { "keys", create_maps_array(info->maps[S_KEY]) },
2597  { "containers", create_maps_array(info->maps[S_CONTAINER]) },
2598  { "detectors", create_maps_array(info->maps[S_DETECTOR]) },
2599  { "connections", create_maps_array(info->maps[S_CONNECT]) },
2600  });
2601  }
2602 
2603  json["quests"] = nlohmann::json::array();
2604  for (int quest = 0; quest < quests_count; quest++) {
2605  qsort(quests[quest]->maps.list, quests[quest]->maps.count, sizeof(struct_map_in_quest *), sort_struct_map_in_quest);
2606  char buf[100];
2607  snprintf(buf, sizeof(buf), "quest_%d", quests[quest]->number);
2608  json["quests"].push_back(create_quest_object(quests[quest], buf));
2609  }
2610 
2611  json["has_search"] = build_search_file;
2612  if (build_search_file) {
2613  std::string out(root);
2614  out += "/search_data.js";
2615  std::ofstream sf(out, std::ios_base::trunc);
2616  sf << "var search_data = " << search << ";" << std::endl;
2617  sf << "var search_type = { ";
2618  std::string sep;
2619  for (int i = 1; i < int(SearchType::Count); i++) {
2620  sf << sep << i << ": \"" << SearchName[i] << "\"";
2621  sep = ", ";
2622  }
2623  sf << " };" << std::endl;
2624  }
2625 }
2626 
2628 static std::vector<std::string> path_stack;
2629 
2630 void add_template_to_render(const std::string &template_name, const std::string &output_name, const std::string &param);
2631 
2637 static std::string path_from_current(const std::string &path) {
2638  auto p(path);
2639  char rel[1000];
2640  if (p[0] != '/')
2641  p = '/' + p;
2642  auto current(path_stack.back());
2643  if (current[0] != '/')
2644  current = '/' + current;
2645  relative_path(current.c_str(), p.c_str(), rel);
2646  return rel;
2647 }
2648 
2654 static nlohmann::json generate_page_and_link(inja::Arguments &args) {
2655  auto template_name = args.at(0)->get<std::string>();
2656  auto output_name(template_name);
2657  auto param = (args.size() > 1 ? args.at(1)->get<std::string>() : "");
2658 
2659  if (!param.empty()) {
2660  output_name = param + "_" + output_name;
2661  if (param.substr(0, 4) == "map_") {
2662  auto map = find_map_by_key(param);
2663  if (map != nullptr) {
2664  output_name = std::string(map->path + 1) + ".html";
2665  }
2666  }
2667  if (param.substr(0, 4) == "reg_") {
2668  auto reg = find_region_by_key(param);
2669  if (reg != nullptr) {
2670  output_name = std::string(reg->name) + ".html";
2671  }
2672  }
2673  }
2674 
2675  if (template_name != "search_data.js" && template_name != "search_index.js")
2676  add_template_to_render(template_name, output_name, param);
2677  return path_from_current(output_name);
2678 }
2679 
2685 static nlohmann::json generate_picture_link(inja::Arguments &args) {
2686  auto what = args.at(0)->get<std::string>();
2687  if (what.substr(0, 4) == "map_") {
2688  auto map = find_map_by_key(what);
2689  if (map == nullptr)
2690  return "";
2691  int size = 0;
2692  if (args.size() > 1) {
2693  size = args.at(1)->get<int>() - 1;
2694  }
2695  char picpath[1000];
2696  snprintf(picpath, sizeof(picpath), "%s.x%d%s", map->path, size + 1, output_extensions[output_format]);
2697  return path_from_current(picpath);
2698  }
2699  return "";
2700 }
2701 
2706 public:
2707  std::string template_name;
2708  std::string output_name;
2709  std::string param;
2710 };
2711 static std::vector<pageToRender> pages;
2719 void add_template_to_render(const std::string &template_name, const std::string &output_name, const std::string &param) {
2720  auto on(output_name);
2721  if (on[0] != '/')
2722  on = '/' + on;
2723  if (rendered_templates.find(on) != rendered_templates.end())
2724  return;
2725 
2726  rendered_templates.insert(on);
2727  pageToRender r;
2728  r.template_name = template_name;
2729  r.output_name = on;
2730  r.param = param;
2731  pages.push_back(r);
2732 }
2733 
2734 static std::vector<std::string> split(const std::string &field, const std::string &by) {
2735  std::vector<std::string> result;
2736  size_t start = 0, found;
2737  while ((found = field.find(by, start)) != std::string::npos) {
2738  result.push_back(field.substr(start, found - start));
2739  start = found + 1;
2740  }
2741  result.push_back(field.substr(start));
2742  return result;
2743 }
2744 
2745 static std::string templates_root("templates/");
2746 static std::vector<std::string> templates;
2751 static void init_renderer_env() {
2752  env = std::make_shared<inja::Environment>(templates_root, std::string(root) + "/");
2753  env->add_callback("link_to_page", generate_page_and_link);
2754  env->add_callback("substr", [] (inja::Arguments &args) {
2755  std::string str = args.at(0)->get<std::string>();
2756  size_t start = args.at(1)->get<size_t>();
2757  size_t len = args.size() > 2 ? args.at(2)->get<size_t>() : std::string::npos;
2758  return str.substr(start, len);
2759  });
2760  env->add_callback("picture", generate_picture_link);
2761  env->add_callback("pad", [] (inja::Arguments &args) {
2762  char buf[50];
2763  int val = args.at(0)->get<int>(), digits = args.at(1)->get<int>();
2764  snprintf(buf, sizeof(buf), "%0*d", digits, val);
2765  return std::string(buf);
2766  });
2767  env->add_callback("path_to_root", 0, [] (inja::Arguments &) {
2768  std::string root;
2769  auto current(path_stack.back());
2770  if (current[0] == '/')
2771  current = current.substr(1);
2772  size_t start = 0;
2773  while ((start = current.find('/', start)) != std::string::npos) {
2774  start++;
2775  root += "../";
2776  }
2777  return root;
2778  });
2779  env->add_callback("get_by_field", 3, [] (inja::Arguments &args) {
2780  const auto &src = args.at(0);
2781  auto field = args.at(1)->get<std::string>();
2782  const auto &value = args.at(2);
2783  auto found = std::find_if(src->begin(), src->end(), [&field, &value] (auto item) {
2784  return item[field] == *value;
2785  });
2786  if (found == src->end()) {
2787  return nlohmann::json();
2788  }
2789  return *found;
2790  });
2791  env->add_callback("get_list_by_field", 3, [] (inja::Arguments &args) {
2792  nlohmann::json ret = nlohmann::json::array();
2793  const auto &src = args.at(0);
2794  auto field = args.at(1)->get<std::string>();
2795  const auto filter = args.at(2);
2796  if (filter->is_array()) {
2797  std::copy_if(src->begin(), src->end(), std::back_inserter(ret), [&] (auto &item) {
2798  auto val = item[field];
2799  return std::find_if(filter->begin(), filter->end(), [&] (auto li) { return val == li; }) != filter->end();
2800  });
2801  } else {
2802  std::copy_if(src->begin(), src->end(), std::back_inserter(ret), [&] (auto &item) {
2803  return filter->get<std::string>() == item[field];
2804  });
2805  }
2806  return ret;
2807  });
2808  env->add_callback("sort", [] (inja::Arguments &args) {
2809  const auto &src = args.at(0);
2810  std::vector<nlohmann::json> ret;
2811  for (auto i : *src) {
2812  ret.push_back(i);
2813  }
2814  auto fields = split(args.at(1)->get<std::string>(), ",");
2815  bool invert = args.size() > 2 ? args.at(2)->get<bool>() : false;
2816  bool ignore_case = args.size() > 3 ? args.at(3)->get<bool>() : true;
2817  std::sort(ret.begin(), ret.end(), [&] (auto left, auto right) {
2818  for (auto field : fields) {
2819  nlohmann::json l = left[field], r = right[field];
2820  if (ignore_case && l.is_string() && r.is_string()) {
2821  std::string ls(l.get<std::string>()), rs(r.get<std::string>());
2822  std::transform(ls.begin(), ls.end(), ls.begin(), [](unsigned char c){ return std::tolower(c); });
2823  std::transform(rs.begin(), rs.end(), rs.begin(), [](unsigned char c){ return std::tolower(c); });
2824  if (ls == rs) {
2825  continue;
2826  }
2827  return invert ? (rs < ls) : (ls < rs);
2828  }
2829  if (r == l) {
2830  continue;
2831  }
2832  return invert ? (r < l) : (l < r);
2833  }
2834  return false;
2835  });
2836  return ret;
2837  });
2838 
2839  env->set_trim_blocks(true);
2840  env->set_lstrip_blocks(true);
2841 }
2842 
2844 static const char *ignore_path[] = {
2845  "/Info",
2846  "/editor",
2847  "/python",
2848  "/styles",
2849  "/templates",
2850  "/test",
2851  "/unlinked",
2852  NULL };
2853 
2855 static const char *ignore_name[] = {
2856  ".",
2857  "..",
2858  ".git",
2859  ".svn",
2860  "README",
2861  NULL };
2862 
2869 static void find_maps(const char *from) {
2870  struct dirent *file;
2871  struct stat statbuf;
2872  int status, ignore;
2873  char path[1024], full[HUGE_BUF];
2874  DIR *dir;
2875 
2876  for (ignore = 0; ignore_path[ignore] != NULL; ignore++) {
2877  if (strcmp(from, ignore_path[ignore]) == 0)
2878  return;
2879  }
2880 
2881  snprintf(path, sizeof(path), "%s/%s%s", settings.datadir, settings.mapdir, from);
2882  dir = opendir(path);
2883 
2884  if (dir) {
2885  for (file = readdir(dir); file; file = readdir(dir)) {
2886 
2887  for (ignore = 0; ignore_name[ignore] != NULL; ignore++) {
2888  if (strcmp(file->d_name, ignore_name[ignore]) == 0)
2889  break;
2890  }
2891  if (ignore_name[ignore] != NULL)
2892  continue;
2893 
2894  snprintf(full, sizeof(full), "%s/%s", path, file->d_name);
2895 
2896  status = stat(full, &statbuf);
2897  snprintf(full, sizeof(full), "%s/%s", from, file->d_name);
2898  if ((status != -1) && (S_ISDIR(statbuf.st_mode))) {
2899  find_maps(full);
2900  continue;
2901  }
2902  found_maps.push_back(strdup(full));
2903  }
2904  closedir(dir);
2905  }
2906 }
2907 
2909 static void dump_unused_maps(void) {
2910  FILE *dump;
2911  char path[1024];
2912 
2913  snprintf(path, sizeof(path), "%s/%s", root, "maps.unused");
2914  dump = fopen(path, "w+");
2915  if (dump == NULL) {
2916  printf("Unable to open file maps.unused!\n");
2917  return;
2918  }
2919  for (auto map = found_maps.cbegin(); map != found_maps.cend(); ++map) {
2920  fprintf(dump, "%s\n", *map);
2921  }
2922  fclose(dump);
2923  printf("%ld unused maps.\n", found_maps.size());
2924 }
2925 
2927 static void write_world_info(void) {
2928  FILE *file;
2929  char path[strlen(root) + 150 + strlen(output_extensions[output_format])];
2930  int x, y;
2931  gdImagePtr elevationmap;
2932 
2933  if (!world_exit_info)
2934  return;
2935 
2936 
2937  printf("Saving exit/blocking/road information...");
2938  snprintf(path, sizeof(path), "%s/%s%s", root, "world_info", output_extensions[output_format]);
2939  file = fopen(path, "wb+");
2940  save_picture(file, infomap);
2941  fclose(file);
2942  printf("done.\n");
2943  gdImageDestroy(infomap);
2944  infomap = NULL;
2945 
2946  if (elevation_min == 0 || elevation_max == 0) {
2947  puts("Error: Could not save elevation world map due to not finding any minimum or maximum elevation.");
2948  return;
2949  }
2950 
2951  elevationmap = gdImageCreateTrueColor(30*50, 30*50);;
2952 
2953  for (x = 0; x < 30*50; x++) {
2954  for (y = 0; y < 30*50; y++) {
2955  gdImageSetPixel(elevationmap, x, y, get_elevation_color(elevation_info[x][y], elevationmap));
2956  }
2957  }
2958 
2959  printf("Saving elevation world map...");
2960  snprintf(path, sizeof(path), "%s/%s%s", root, "world_elevation", output_extensions[output_format]);
2961  file = fopen(path, "wb+");
2962  save_picture(file, elevationmap);
2963  fclose(file);
2964  printf("done.\n");
2965  gdImageDestroy(elevationmap);
2966  elevationmap = NULL;
2967 }
2968 
2979 static int sort_slaying(const void *left, const void *right) {
2981  struct_slaying_info *r = *(struct_slaying_info **)right;
2982 
2983  return strcasecmp(l->slaying, r->slaying);
2984 }
2985 
2992 static void do_help(const char *program) {
2993  printf("Crossfire Mapper will generate pictures of maps, and create indexes for all maps and regions.\n\n");
2994  printf("Syntax: %s\n\n", program);
2995  printf("Optional arguments:\n");
2996  printf(" -nopics don't generate pictures.\n");
2997  printf(" -root=<path> destination path. Default 'html'.\n");
2998  printf(" -limit=<number> stop processing after this number of maps, -1 to do all maps (default).\n");
2999  printf(" -showmaps outputs the name of maps as they are processed.\n");
3000  printf(" -jpg[=quality] generate jpg pictures, instead of default png. Quality should be 0-95, -1 for automatic.\n");
3001  printf(" -forcepics force to regenerate pics, even if pics's date is after map's.\n");
3002  printf(" -addmap=<map> adds a map to process. Path is relative to map's directory root.\n");
3003  printf(" -rawmaps generates maps pics without items on random (shop, treasure) tiles.\n");
3004  printf(" -warnnopath inform when an exit has no path set.\n");
3005  printf(" -listunusedmaps finds all unused maps in the maps directory.\n");
3006  printf(" -noworldmap don't write the world map in world.png.\n");
3007  printf(" -noregionslink don't generate regions relation file.\n");
3008  printf(" -regionslink generate regions relation file.\n");
3009  printf(" -noexitmap don't generate map of exits.\n");
3010  printf(" -exitmap generate map of exits.\n");
3011  printf(" -tileset=<number> use specified tileset to generate the pictures. Default 0 (standard).\n");
3012  printf(" -details-quests list all quests steps. Default no.\n");
3013  printf(" -list-system-quests include 'system' quests in quest list. Default no.\n");
3014  printf(" -templates-dir=[dir] set the directory to get templates from. Default 'templates/'.\n");
3015  printf(" -add-template=[file] add a template to process. May be specified multiple times. If empty, 'index.html' is used.\n");
3016  printf(" -list-template-to-process display the name of the template about to be rendered. Useful for debugging.");
3017  printf("\n\n");
3018  exit(0);
3019 }
3020 
3029 static void do_parameters(int argc, char **argv) {
3030  int arg = 1;
3031  char path[500];
3032 
3033  root[0] = '\0';
3034 
3035  while (arg < argc) {
3036  if (strcmp(argv[arg], "-nopics") == 0)
3037  generate_pics = 0;
3038  else if (strncmp(argv[arg], "-root=", 6) == 0)
3039  strncpy(root, argv[arg]+6, 500);
3040  else if (strncmp(argv[arg], "-limit=", 7) == 0)
3041  map_limit = atoi(argv[arg]+7);
3042  else if (strcmp(argv[arg], "-showmaps") == 0)
3043  show_maps = 1;
3044  else if (strcmp(argv[arg], "-jpg") == 0) {
3045  output_format = OF_JPG;
3046  if (argv[arg][4] == '=') {
3047  jpeg_quality = atoi(argv[arg]+5);
3048  if (jpeg_quality < 0)
3049  jpeg_quality = -1;
3050  }
3051  }
3052  else if (strcmp(argv[arg], "-forcepics") == 0)
3053  force_pics = 1;
3054  else if (strncmp(argv[arg], "-addmap=", 8) == 0) {
3055  if (*(argv[arg]+8) == '/')
3056  strncpy(path, argv[arg]+8, 500);
3057  else
3058  snprintf(path, 500, "/%s", argv[arg]+8);
3059  add_map(get_map_info(path), &maps_list);
3060  }
3061  else if (strcmp(argv[arg], "-rawmaps") == 0)
3062  rawmaps = 1;
3063  else if (strcmp(argv[arg], "-warnnopath") == 0)
3064  warn_no_path = 1;
3065  else if (strcmp(argv[arg], "-listunusedmaps") == 0)
3066  list_unused_maps = 1;
3067  else if (strcmp(argv[arg], "-noworldmap") == 0)
3068  world_map = 0;
3069  else if (strcmp(argv[arg], "-noregionslink") == 0)
3070  do_regions_link = false;
3071  else if (strcmp(argv[arg], "-regionslink") == 0)
3072  do_regions_link = true;
3073  else if (strcmp(argv[arg], "-noexitmap") == 0)
3074  world_exit_info = 0;
3075  else if (strcmp(argv[arg], "-exitmap") == 0)
3076  world_exit_info = 1;
3077  else if (strncmp(argv[arg], "-tileset=", 9) == 0) {
3078  tileset = atoi(argv[arg]+9);
3079  /* check of validity is done in main() as we need to actually have the sets loaded. */
3080  } else if (strcmp(argv[arg], "-detail-quests") == 0) {
3081  detail_quests = 1;
3082  } else if (strcmp(argv[arg], "-list-system-quests") == 0) {
3083  list_system_quests = 1;
3084  } else if (strncmp(argv[arg], "-templates-dir=", 15) == 0) {
3085  templates_root = argv[arg] + 15;
3086  } else if (strncmp(argv[arg], "-add-template=", 14) == 0) {
3087  templates.push_back(argv[arg] + 14);
3088  } else if (strcmp(argv[arg], "-list-template-to-process") == 0) {
3089  display_rendered_template = 1;
3090  } else if (strncmp(argv[arg], "-build-search-data", 18) == 0) {
3091  build_search_file = true;
3092  } else
3093  do_help(argv[0]);
3094  arg++;
3095  }
3096  if (!strlen(root))
3097  strcpy(root, "html");
3098  if (root[strlen(root)-1] == '/')
3099  root[strlen(root)-1] = '\0';
3100  if (map_limit < -1)
3101  map_limit = -1;
3102 
3103  if (templates_root.empty()) {
3104  templates_root = "templates/";
3105  } else if (templates_root[templates_root.length() - 1] != '/') {
3106  templates_root.append("/");
3107  }
3108 }
3109 
3113 static void create_destination(void) {
3114  char dummy[502];
3115 
3116  strcpy(dummy, root);
3117  strcat(dummy, "/a");
3118  make_path_to_file(dummy);
3119 }
3120 
3129 static const char *yesno(int value) {
3130  return (value ? "yes" : "no");
3131 }
3132 
3133 int main(int argc, char **argv) {
3134  size_t current_map = 0, i;
3135  char max[50];
3136  region *dummy;
3137 
3138  init_map_list(&maps_list);
3139  init_map_list(&tiled_map_list);
3140  init_race_list(&races);
3141  pics_allocated = 0;
3142 
3143  do_parameters(argc, argv);
3144 
3145  printf("Initializing Crossfire data...\n");
3146 
3148 
3149  init_globals();
3150  init_library();
3151  init_readable();
3152 
3153  init_gods();
3154 
3155  /* Add a dummy region so unlinked maps can be identified. */
3156  dummy = get_region_struct();
3157  dummy->fallback = 1;
3158  dummy->name = strdup_local("unlinked");
3159  dummy->longname = strdup_local("This dummy region contains all maps without a region set.");
3160  dummy->longname = strdup_local("This dummy region contains all maps without a region set.");
3161  all_regions.push_back(dummy);
3162 
3163  printf("\n\n done.\n\n");
3164 
3165  if (!is_valid_faceset(tileset)) {
3166  printf("Erreor: invalid tileset %d!\n", tileset);
3167  exit(1);
3168  }
3169 
3170  if (templates.empty()) {
3171  templates.push_back("index.html");
3172  }
3173 
3175  gdfaces.resize(get_faces_count(), nullptr);
3176 
3177  if (map_limit != -1)
3178  snprintf(max, sizeof(max), "%d", map_limit);
3179  else
3180  strcpy(max, "(none)");
3181  printf("Crossfire map browser generator\n");
3182  printf("-------------------------------\n\n");
3183  printf("Parameters:\n");
3184  printf(" path to write files: %s\n", root);
3185  printf(" maximum number of maps to process: %s\n", max);
3186  printf(" will generate map picture: %s\n", yesno(generate_pics));
3187  printf(" will always generate map picture: %s\n", yesno(force_pics));
3188  printf(" picture output format: %s\n", output_extensions[output_format]);
3189  if (output_format == OF_JPG)
3190  printf(" JPEG quality: %d\n", jpeg_quality);
3191  printf(" show map being processed: %s\n", yesno(show_maps));
3192  printf(" generate raw maps: %s\n", yesno(rawmaps));
3193  printf(" warn of exit without path: %s\n", yesno(warn_no_path));
3194  printf(" list unused maps: %s\n", yesno(list_unused_maps));
3195  printf(" generate world map: %s\n", yesno(world_map));
3196  printf(" generate exit map: %s\n", yesno(world_exit_info));
3197  printf(" generate regions link file: %s\n", yesno(do_regions_link));
3198  printf(" tileset: %s\n", find_faceset(tileset)->fullname);
3199  printf(" detail quest steps: %s\n", yesno(detail_quests));
3200  printf(" list system quests: %s\n", yesno(list_system_quests));
3201  printf(" templates directory: %s\n", templates_root.c_str());
3202  printf(" templates to process: ");
3203  const char *sep = "";
3204  for (auto f : templates) {
3205  printf("%s%s", sep, f.c_str());
3206  sep = ", ";
3207  }
3208  printf("\n");
3209  printf(" display template to process: %s\n", yesno(display_rendered_template));
3210  printf("\n");
3211 
3212  if (list_unused_maps) {
3213  printf("listing all maps...");
3214  find_maps("");
3215  printf("done, %ld maps found.\n", found_maps.size());
3216  }
3217 
3218  /* exit/blocking information. */
3219  infomap = gdImageCreateTrueColor(30*50, 30*50);
3220  color_unlinked_exit = gdImageColorResolve(infomap, 255, 0, 0);
3221  color_linked_exit = gdImageColorResolve(infomap, 255, 255, 255);
3222  color_road = gdImageColorResolve(infomap, 0, 255, 0);
3223  color_blocking = gdImageColorResolve(infomap, 0, 0, 255);
3224  color_slowing = gdImageColorResolve(infomap, 0, 0, 127);
3225  elevation_info = (int **)calloc(50*30, sizeof(int *));
3226  for (i = 0; i < 50*30; i++)
3227  elevation_info[i] = (int *)calloc(50*30, sizeof(int));
3228  elevation_min = 0;
3229  elevation_max = 0;
3230 
3231  printf("browsing maps...\n");
3232 
3234 
3235  while (current_map < maps_list.count) {
3236  process_map(maps_list.maps[current_map++]);
3237  if (current_map%100 == 0) {
3238  printf(" %zu maps processed, %d map pictures created, %d map pictures were uptodate. %d faces used.\n", current_map, created_pics, cached_pics, pics_allocated);
3239  }
3240  if ((map_limit != -1) && (current_map == static_cast<size_t>(map_limit))) {
3241  printf(" --- map limit reached, stopping ---\n");
3242  break;
3243  }
3244  }
3245 
3246  printf(" finished map parsing, %zu maps processed, %d map pictures created, %d map pictures were uptodate. Total %d faces used.\n", current_map, created_pics, cached_pics, pics_allocated);
3247 
3248  if (list_unused_maps)
3249  dump_unused_maps();
3250 
3252  fix_map_names();
3253  fix_tiled_map();
3255  write_tiled_maps();
3256 
3257  write_world_map();
3258  write_world_info();
3259 
3260  qsort(maps_list.maps, maps_list.count, sizeof(struct_map_info *), sort_map_info);
3261  qsort(regions, region_count, sizeof(struct_region_info *), sort_region);
3262  std::sort(special_equipment.begin(), special_equipment.end(), sort_equipment);
3263  qsort(slaying_info, slaying_count, sizeof(struct_slaying_info *), sort_slaying);
3264  qsort(races.races, races.count, sizeof(struct_race *), sort_race);
3265  qsort(quests, quests_count, sizeof(struct_quest *), sort_struct_quest);
3266 
3268  std::sort(system_quests.begin(), system_quests.end(), [] (const auto &left, const auto &right) { return strcmp(left->quest_code, right->quest_code) < 0; });
3269 
3271 
3272  fill_json(all_data);
3273 
3274  for (auto file : templates) {
3275  if (!file.empty()) {
3276  add_template_to_render(file, file, "");
3277  }
3278  }
3279 
3280  const auto fullStart = time(nullptr);
3281  printf("rendering pages...");
3282  if (display_rendered_template)
3283  printf("\n");
3284  fflush(stdout);
3285 
3286  while (!pages.empty()) {
3287  auto p = pages.back();
3288  pages.pop_back();
3289  if (p.param.empty())
3290  all_data.erase("param");
3291  else
3292  all_data["param"] = p.param;
3293  const auto start = time(nullptr);
3294  if (display_rendered_template) {
3295  printf(" rendering page %s (%s)... ", p.template_name.c_str(), p.param.c_str());
3296  fflush(stdout);
3297  }
3298  path_stack.push_back(p.output_name);
3299  inja::Template temp = get_template(p.template_name);
3300  env->write(temp, all_data, p.output_name);
3301  path_stack.pop_back();
3302  const auto elapsed = time(nullptr) - start;
3303  if (display_rendered_template) {
3304  printf("took %ld seconds\n", elapsed);
3305  }
3306  }
3307 
3308  const auto elapsed = time(nullptr) - fullStart;
3309  printf(" done, took %ld seconds\n", elapsed);
3310 
3311  return 0;
3312 }
3313 
3315  int x, y;
3316 
3317  if (m == NULL)
3318  return;
3319 
3320  for (x = 0; x < MAP_WIDTH(m); x++)
3321  for (y = 0; y < MAP_HEIGHT(m); y++)
3322  FOR_MAP_PREPARE(m, x, y, tmp) {
3323  if (tmp->inv) {
3324  FOR_INV_PREPARE(tmp, invtmp) {
3325  if (QUERY_FLAG(invtmp, FLAG_AUTO_APPLY))
3326  apply_auto(invtmp);
3327  else if (invtmp->type == TREASURE && HAS_RANDOM_ITEMS(invtmp)) {
3328  while ((invtmp->stats.hp--) > 0)
3329  create_treasure(invtmp->randomitems, invtmp, 0, m->difficulty, 0);
3330  invtmp->randomitems = NULL;
3331  } else if (invtmp
3332  && invtmp->arch
3333  && invtmp->type != TREASURE
3334  && invtmp->type != SPELL
3335  && invtmp->type != CLASS
3336  && HAS_RANDOM_ITEMS(invtmp)) {
3337  create_treasure(invtmp->randomitems, invtmp, 0, m->difficulty, 0);
3338  /* Need to clear this so that we never try to create
3339  * treasure again for this object
3340  */
3341  invtmp->randomitems = NULL;
3342  }
3343  } FOR_INV_FINISH();
3344  /* This is really temporary - the code at the bottom will
3345  * also set randomitems to null. The problem is there are bunches
3346  * of maps/players already out there with items that have spells
3347  * which haven't had the randomitems set to null yet.
3348  * MSW 2004-05-13
3349  *
3350  * And if it's a spellbook, it's better to set randomitems to NULL too,
3351  * else you get two spells in the book ^_-
3352  * Ryo 2004-08-16
3353  */
3354  if (tmp->type == WAND
3355  || tmp->type == ROD
3356  || tmp->type == SCROLL
3357  || tmp->type == FIREWALL
3358  || tmp->type == POTION
3359  || tmp->type == ALTAR
3360  || tmp->type == SPELLBOOK)
3361  tmp->randomitems = NULL;
3362  }
3363 
3364  if (QUERY_FLAG(tmp, FLAG_AUTO_APPLY))
3365  apply_auto(tmp);
3366  else if ((tmp->type == TREASURE || (tmp->type == CONTAINER)) && HAS_RANDOM_ITEMS(tmp)) {
3367  while ((tmp->stats.hp--) > 0)
3368  create_treasure(tmp->randomitems, tmp, 0, m->difficulty, 0);
3369  tmp->randomitems = NULL;
3370  } else if (tmp->type == TIMED_GATE) {
3371  object *head = HEAD(tmp);
3372 
3373  if (QUERY_FLAG(head, FLAG_IS_LINKED)) {
3374  tmp->speed = 0;
3375  object_update_speed(tmp);
3376  }
3377  /* This function can be called everytime a map is loaded, even when
3378  * swapping back in. As such, we don't want to create the treasure
3379  * over and ove again, so after we generate the treasure, blank out
3380  * randomitems so if it is swapped in again, it won't make anything.
3381  * This is a problem for the above objects, because they have counters
3382  * which say how many times to make the treasure.
3383  */
3384  } else if (tmp
3385  && tmp->arch
3386  && tmp->type != PLAYER
3387  && tmp->type != TREASURE
3388  && tmp->type != SPELL
3389  && tmp->type != PLAYER_CHANGER
3390  && tmp->type != CLASS
3391  && HAS_RANDOM_ITEMS(tmp)) {
3392  create_treasure(tmp->randomitems, tmp, 0, m->difficulty, 0);
3393  tmp->randomitems = NULL;
3394  }
3395  } FOR_MAP_FINISH();
3396 
3397  for (x = 0; x < MAP_WIDTH(m); x++)
3398  for (y = 0; y < MAP_HEIGHT(m); y++)
3399  FOR_MAP_PREPARE(m, x, y, tmp) {
3400  if (tmp->above
3401  && (tmp->type == TRIGGER_BUTTON || tmp->type == TRIGGER_PEDESTAL))
3402  check_trigger(tmp, tmp->above);
3403  } FOR_MAP_FINISH();
3404 }
3405 
3406 #ifndef DOXYGEN_SHOULD_SKIP_THIS
3407 
3412 void draw_ext_info(int, int, const object *, uint8_t, uint8_t, const char *txt) {
3413  fprintf(logfile, "%s\n", txt);
3414 }
3415 
3416 void draw_ext_info_format(int, int, const object *, uint8_t, uint8_t, const char *format, ...) {
3417  va_list ap;
3418 
3419  va_start(ap, format);
3420  vfprintf(logfile, format, ap);
3421  va_end(ap);
3422 }
3423 
3424 void ext_info_map(int, const mapstruct *, uint8_t, uint8_t, const char *str1) {
3425  fprintf(logfile, "ext_info_map: %s\n", str1);
3426 }
3427 
3428 void move_firewall(object *) {
3429 }
3430 
3431 void emergency_save(int) {
3432 }
3433 
3434 void clean_tmp_files(void) {
3435 }
3436 
3437 void esrv_send_item(object *, object *) {
3438 }
3439 
3440 void dragon_ability_gain(object *, int, int) {
3441 }
3442 
3443 void set_darkness_map(mapstruct *) {
3444 }
3445 
3446 object *find_skill_by_number(object *, int) {
3447  return NULL;
3448 }
3449 
3450 void esrv_del_item(player *, object *) {
3451 }
3452 
3453 void esrv_update_item(int, object *, object *) {
3454 }
3455 
3456 void esrv_update_spells(player *) {
3457 }
3458 
3459 void rod_adjust(object *) {
3460 }
3461 
3462 /*
3463  * This a modified version of apply_auto: BOOK are not generated, so they don't pollute
3464  * the readable list.
3465  */
3466 int apply_auto(object *op) {
3467  object *tmp = NULL;
3468  int i;
3469 
3470  switch (op->type) {
3471  case SHOP_FLOOR:
3472  if (!HAS_RANDOM_ITEMS(op))
3473  return 0;
3474  do {
3475  i = 10; /* let's give it 10 tries */
3476  while ((tmp = generate_treasure(op->randomitems, op->stats.exp ? (int)op->stats.exp : MAX(op->map->difficulty, 5))) == NULL && --i)
3477  ;
3478  if (tmp == NULL)
3479  return 0;
3480  if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED) || tmp->type == BOOK) {
3482  tmp = NULL;
3483  }
3484  } while (!tmp);
3485  SET_FLAG(tmp, FLAG_UNPAID);
3486  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
3488  tmp = identify(tmp);
3489  break;
3490 
3491  case TREASURE:
3492  if (QUERY_FLAG(op, FLAG_IS_A_TEMPLATE))
3493  return 0;
3494 
3495  while ((op->stats.hp--) > 0)
3496  create_treasure(op->randomitems, op, 0, op->stats.exp ? (int)op->stats.exp : op->map == NULL ? 14 : op->map->difficulty, 0);
3497 
3498  /* If we generated an object and put it in this object inventory,
3499  * move it to the parent object as the current object is about
3500  * to disappear. An example of this item is the random_ *stuff
3501  * that is put inside other objects.
3502  */
3503  FOR_INV_PREPARE(op, tmp) {
3504  object_remove(tmp);
3505  if (op->env && tmp->type != BOOK)
3506  object_insert_in_ob(tmp, op->env);
3507  else
3509  }
3510  FOR_INV_FINISH();
3511  object_remove(op);
3513  break;
3514  }
3515  return tmp ? 1 : 0;
3516 }
3517 
3518 void apply_auto_fix(mapstruct *) {
3519 }
3520 
3522  return NULL;
3523 }
3524 
3525 player *find_player_partial_name(const char *) {
3526  return NULL;
3527 }
3528 
3529 Account_Chars *account_char_load(const char *) {
3530  return NULL;
3531 }
3532 
3534 }
3535 
3537 }
3538 
3539 void command_help(object *, const char *) {
3540 }
3541 
3542 void account_logout(const char *) {
3543 }
3544 
3545 #endif /* dummy DOXYGEN_SHOULD_SKIP_THIS */
struct_map_in_quest_list quests
Definition: mapper.cpp:249
Error, serious thing.
Definition: logger.h:11
#define dirent
Definition: global.h:215
void clean_tmp_files(void)
Save unique maps and clean up temporary map files unless recycling temporary maps.
Definition: main.cpp:351
static int list_unused_maps
If set, program will list maps found in directory but not linked from the first maps.
Definition: mapper.cpp:416
static event_registration c
Definition: citylife.cpp:424
static nlohmann::json all_data
All JSON data available to templates.
Definition: mapper.cpp:2223
static struct_map_info * create_tiled_map(void)
Create a new tiled map and link it to the tiled map list.
Definition: mapper.cpp:1261
char * slaying
Slaying value.
Definition: mapper.cpp:446
char first_map_path[MAX_BUF]
The start-level.
Definition: init.cpp:120
static int warn_no_path
Whether to warn of exits without a path.
Definition: mapper.cpp:402
static int dump(const std::set< std::string > &items, const char *name)
static size_t slaying_count
Count of items in slaying_info.
Definition: mapper.cpp:451
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:305
static nlohmann::json create_quest_object(struct_quest *quest, const std::string &key)
Return a JSON quest object.
Definition: mapper.cpp:2361
#define FLAG_UNPAID
Object hasn&#39;t been paid for yet.
Definition: define.h:223
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:303
struct_map_info * map
Linked map.
Definition: mapper.cpp:929
See Ring.
Definition: object.h:190
static std::string SearchName[int(SearchType::Count)]
Search names for types, for the JS search engine.
Definition: mapper.cpp:305
static std::map< region *, std::set< region * > > region_links
Definition: mapper.cpp:434
int8_t item_power
Power rating of the object.
Definition: object.h:372
static struct_quest * get_quest_info(const char *name)
Gets the information for a quest, create the field if needed.
Definition: mapper.cpp:985
int calc_item_power(const object *op)
This takes an object &#39;op&#39; and figures out what its item_power rating should be.
Definition: item.cpp:318
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
face_info * faces
images in this faceset
Definition: image.h:26
static int world_map
If set, will generate a world map.
Definition: mapper.cpp:368
static void process_map_lore(struct_map_info *map)
Extracts from the map&#39;s lore quest information if found.
Definition: mapper.cpp:1099
Definition of an in-game quest.
Definition: quest.h:37
List of maps.
Definition: mapper.cpp:233
static void write_tiled_map_page(struct_map_info *map)
Writes the page for a tiled map group.
Definition: mapper.cpp:2195
FILE * logfile
Used by server/daemon.c.
Definition: init.cpp:114
static const char * remove_trailing_slash(const char *path)
Definition: mapper.cpp:2326
region * get_region_by_map(mapstruct *m)
Gets a region from a map.
Definition: region.cpp:71
void esrv_send_item(object *pl, object *op)
Sends item&#39;s info to player.
Definition: main.cpp:354
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
void init_readable(void)
Initialize linked lists utilized by message functions in tailor_readable_ob()
Definition: readable.cpp:904
struct struct_map_in_quest ** list
Definition: mapper.cpp:227
static nlohmann::json generate_picture_link(inja::Arguments &args)
Return the link to the picture of the specified item.
Definition: mapper.cpp:2685
See Scroll.
Definition: object.h:226
Region information.
Definition: mapper.cpp:405
static size_t region_allocated
Allocated size of regions.
Definition: mapper.cpp:414
struct_race_list monsters
Definition: mapper.cpp:254
int apply_auto(object *op)
Map was just loaded, handle op&#39;s initialization.
Definition: main.cpp:211
static void fix_exits_for_map(struct_map_info *current, struct_map_list *from, int is_from)
Changes for the list all maps to the tiled map they are part of, if applicable.
Definition: mapper.cpp:1983
static int sort_struct_quest(const void *left, const void *right)
Sorts 2 struct_quest, on the map&#39;s name or path.
Definition: mapper.cpp:1064
#define strdup_local
Definition: compat.h:29
static enum output_format_type output_format
Selected output format.
Definition: mapper.cpp:393
struct_map_list maps[S_MAX]
Definition: mapper.cpp:447
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
static void generate_picture_path(const char *path, size_t pic_size, char *out, size_t len)
Definition: mapper.cpp:1518
static std::vector< std::string > split(const std::string &field, const std::string &by)
Definition: mapper.cpp:2734
std::string output_name
Output file name.
Definition: mapper.cpp:2708
struct_map_list tiled_maps
Definition: mapper.cpp:252
static void init_renderer_env()
Initialize env and set various callbacks and options.
Definition: mapper.cpp:2751
static int elevation_max
Lowest elevation found.
Definition: mapper.cpp:429
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:233
#define FLAG_IS_FLOOR
Can&#39;t see what&#39;s underneath this object.
Definition: define.h:290
archetype * find_archetype(const char *name)
Definition: assets.cpp:270
static std::string path_from_current(const std::string &path)
Compute the relative path from the specified file to the current file.
Definition: mapper.cpp:2637
char * name
Quest&#39;s name.
Definition: mapper.cpp:936
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
void init_library(void)
It is vital that init_library() is called by any functions using this library.
Definition: init.cpp:315
int level
Definition: readable.cpp:1561
size_t allocated
Allocated space.
Definition: mapper.cpp:222
static struct_equipment * ensure_unique(struct_equipment *item)
Searches the item list for an identical item, except maps.
Definition: mapper.cpp:533
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.cpp:359
See Spellbook.
Definition: object.h:208
static struct_map_info * get_map_info(const char *path)
Gets or creates if required the info structure for a map.
Definition: mapper.cpp:1311
sstring slaying
Which race to do double damage to.
Definition: object.h:327
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
#define MAP_HEIGHT(m)
Map height.
Definition: map.h:78
static int get_elevation_color(int elevation, gdImagePtr elevationmap)
Gets the color for an elevation.
Definition: mapper.cpp:762
static std::set< std::string > reset_groups
All defined reset groups.
Definition: mapper.cpp:292
size_t allocated
Definition: mapper.cpp:236
struct_map_info * mainmap
Map defining the quest.
Definition: mapper.cpp:939
npc_list * readable
Definition: mapper.cpp:257
std::vector< region * > all_regions
Definition: init.cpp:108
struct_map_in_quest_list maps
Maps part of this quest.
Definition: mapper.cpp:940
#define IS_WEAPON(op)
Definition: define.h:163
DIR * opendir(const char *)
Object for applying character class modifications to someone.
Definition: object.h:143
void make_path_to_file(const char *filename)
Checks if any directories in the given path doesn&#39;t exist, and creates if necessary.
Definition: porting.cpp:164
void quest_for_each(quest_op op, void *user)
Iterate over all quests.
Definition: assets.cpp:543
See Rod.
Definition: object.h:114
#define SIZE
int get_face_fallback(int faceset, uint16_t imageno)
This returns the set we will actually use when sending a face.
Definition: image.cpp:133
static nlohmann::json create_npc_array(npc_list &list)
Return an array of NPC information.
Definition: mapper.cpp:2273
int16_t y
Position in the map for this object.
Definition: object.h:335
static int elevation_min
Maximal elevation found.
Definition: mapper.cpp:428
#define FREE_OBJ_NO_DESTROY_CALLBACK
Do not run the destroy callback.
Definition: object.h:547
static const char * output_extensions[]
Extensions depending on output format.
Definition: mapper.cpp:387
face_sets * find_faceset(int id)
Definition: assets.cpp:332
char * description
Description, from the main map&#39;s lore.
Definition: mapper.cpp:937
int count
Number found on map.
Definition: mapper.cpp:286
int number
Unique quest identifier.
Definition: mapper.cpp:938
See Button Trigger.
Definition: object.h:137
uint32_t reset_time
Server time when map gets reset, seconds since epoch.
Definition: map.h:327
MoveType move_block
What movement types this blocks.
Definition: object.h:437
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
LogLevel debug
Default debugging level.
Definition: global.h:244
PNG, default value.
Definition: mapper.cpp:382
See Amulet.
Definition: object.h:144
static const char * yesno(int value)
Helper to write yes/no.
Definition: mapper.cpp:3129
#define MAX(x, y)
Definition: compat.h:24
static void fix_map_names(void)
Ensures all maps have a name (if there was a limit to map processing, some maps will have a NULL name...
Definition: mapper.cpp:1896
const char * name
NPC&#39;s name.
Definition: mapper.cpp:210
int16_t x
Definition: object.h:335
static int color_slowing
Slows movement.
Definition: mapper.cpp:425
Global type definitions and header inclusions.
void init_globals(void)
Initialises all global variables.
Definition: init.cpp:387
const char * message
NPC&#39;s message.
Definition: mapper.cpp:211
static void add_map_to_quest(struct_map_info *map, const char *name, const char *description)
Links a map to a quest.
Definition: mapper.cpp:1014
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.cpp:308
char * longname
Official title of the region, this might be defined to be the same as name.
Definition: map.h:286
struct struct_quest * quest
Point back to the quest.
Definition: mapper.cpp:931
peterm: detector is an object which notices the presense of another object and is triggered like butt...
Definition: object.h:154
static int color_road
Road or equivalent.
Definition: mapper.cpp:423
struct_map_list exits_to
Definition: mapper.cpp:248
See Wand & Staff.
Definition: object.h:225
static void fill_json(nlohmann::json &json)
Add all global variables to the data available to templates.
Definition: mapper.cpp:2431
static struct_map_info * create_map_info(void)
Returns an initialised struct_map_info.
Definition: mapper.cpp:1239
#define MIN(x, y)
Definition: compat.h:21
One special item (weapon, shield, ...).
Definition: mapper.cpp:272
static nlohmann::json create_map_object(struct_map_info *map, const std::string &key)
Return a JSON map object.
Definition: mapper.cpp:2337
static std::shared_ptr< inja::Environment > env
Rendering environment.
Definition: mapper.cpp:2222
static void append_map_list(struct_map_list &dest, struct_map_list &src)
Append the contents of src to dest.
Definition: mapper.cpp:2395
static const int num_sizes
Definition: mapper.cpp:363
static int world_exit_info
If set, will generate a world map of exits.
Definition: mapper.cpp:369
#define MOVE_ALL
Mask of all movement types.
Definition: define.h:404
void esrv_del_item(player *pl, object *ob)
Tells the client to delete an item.
Definition: main.cpp:381
region * reg
Region.
Definition: mapper.cpp:406
static bool detail_quests
Whether to show all quests details or not.
Definition: mapper.cpp:371
One region with bells.
Definition: cfcitybell.cpp:38
One quest.
Definition: mapper.cpp:935
static std::map< struct_map_info *, std::string > reverse_maps
Link between a map and its unique identifier.
Definition: mapper.cpp:2225
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:129
int16_t level
Level of creature or object.
Definition: object.h:361
static size_t slaying_allocated
Allocated size of slaying_info.
Definition: mapper.cpp:452
static void check_equipment(object *item, struct_map_info *map)
Checks if item and its inventory are worthy to be listed.
Definition: mapper.cpp:631
void object_free(object *ob, int flags)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.cpp:1577
#define S_CONNECT
Definition: mapper.cpp:441
#define FREE_OBJ_FREE_INVENTORY
Free inventory objects; if not set, drop inventory.
Definition: object.h:546
sstring reset_group
For reset purpose, all maps in the same group reset at the same time.
Definition: map.h:332
SearchType
Search values, for the JS search engine.
Definition: mapper.cpp:295
See Sign & Magic Mouth.
Definition: object.h:216
static struct struct_region_info ** regions
Found regions.
Definition: mapper.cpp:412
Link between a quest and a map.
Definition: mapper.cpp:928
See Book.
Definition: object.h:119
int8_t fallback
Whether, in the event of a region not existing, this should be the one we fall back on as the default...
Definition: map.h:290
See Exit.
Definition: object.h:186
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
This calls the appropriate treasure creation function.
Definition: treasure.cpp:287
object * identify(object *op)
Identifies an item.
Definition: item.cpp:1446
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
int check_trigger(object *op, object *cause)
Definition: button.cpp:518
void object_get_multi_size(const object *ob, int *sx, int *sy, int *hx, int *hy)
Computes the size of a multitile object.
Definition: object.cpp:4729
Image-related structures.
static void free_equipment(struct_equipment *equip)
Frees a struct_equipment.
Definition: mapper.cpp:499
static std::vector< gdImagePtr > gdfaces
Definition: mapper.cpp:206
static std::vector< pageToRender > pages
List of pages to render.
Definition: mapper.cpp:2711
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
static int show_maps
If set, will generate much information on map loaded.
Definition: mapper.cpp:367
#define S_CONTAINER
Definition: mapper.cpp:439
static std::vector< quest_definition * > system_quests
Definition: mapper.cpp:2214
region * get_region_struct(void)
Allocates and zeros a region struct, this isn&#39;t free()&#39;d anywhere, so might be a memory leak...
Definition: region.cpp:293
static void merge_tiled_maps(struct_map_info *map, struct_map_info *tiled_map)
Merge two tiled maps groups.
Definition: mapper.cpp:1277
See Treasure.
Definition: object.h:115
void account_logout(const char *account_name)
Remove &#39;account_name&#39; from the list of logged in accounts.
Definition: account.cpp:337
See Special Key.
Definition: object.h:129
static void define_quest(const char *name, struct_map_info *mainmap, const char *description)
Sets the main map for a quest.
Definition: mapper.cpp:1080
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
static int is_blocking(object *item)
Checks if item blocks movement or not.
Definition: mapper.cpp:748
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:360
region * cfregion
Definition: mapper.cpp:245
static nlohmann::json create_race_array(struct_race_list &list)
Return an array of monster information.
Definition: mapper.cpp:2292
object * env
Pointer to the object which is the environment.
Definition: object.h:301
#define SET_FLAG(xyz, p)
Definition: define.h:384
uint8_t * data
Image data.
Definition: image.h:11
One page to render, with its parameters.
Definition: mapper.cpp:2705
static nlohmann::json create_map_in_quest_array(struct_map_in_quest_list &list)
Return an array of map-in-quest items.
Definition: mapper.cpp:2309
#define FLAG_UNAGGRESSIVE
Monster doesn&#39;t attack players.
Definition: define.h:259
#define QUERY_FLAG(xyz, p)
Definition: define.h:386
const artifact * find_artifact(const object *op, const char *name)
Searches and returns a specific artifact compatible with an object, NULL if not found.
Definition: artifact.cpp:585
static void check_slaying_inventory(struct_map_info *map, object *item)
Recursively checks if the object should be considered for slaying information.
Definition: mapper.cpp:1510
static struct_map_list maps_list
Maps to process or found.
Definition: mapper.cpp:266
static nlohmann::json create_maps_array(struct_map_list &maps)
Return an array of map identifiers.
Definition: mapper.cpp:2257
bool quest_is_system
If set then the quest isn&#39;t counted or listed.
Definition: quest.h:45
void give_artifact_abilities(object *op, const object *artifact)
Fixes the given object, giving it the abilities and titles it should have due to the second artifact-...
Definition: artifact.cpp:230
struct struct_map_info * tiled_group
Definition: mapper.cpp:259
void account_char_save(Account_Chars *chars)
Saves the character information for the given account.
void object_give_identified_properties(object *op)
Ensure op has all its "identified" properties set.
Definition: item.cpp:1365
#define S_MAX
Definition: mapper.cpp:442
static int created_pics
Picture statistics.
Definition: mapper.cpp:377
Information about a NPC with a custom message.
Definition: mapper.cpp:209
#define size_large
Definition: mapper.cpp:364
int strcasecmp(const char *s1, const char *s2)
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.cpp:1545
#define FLAG_IDENTIFIED
Item is identifiable (e.g.
Definition: define.h:248
static int color_blocking
Block all movement.
Definition: mapper.cpp:424
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:700
static int rawmaps
Whether to generate raw pics or instancied ones.
Definition: mapper.cpp:399
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
int is_world
If set, this region has at least one map part of the world, thus region name should be written...
Definition: mapper.cpp:409
char * name
Monster&#39;s name.
Definition: mapper.cpp:285
char * name
Shortend name of the region as maps refer to it.
Definition: map.h:280
object * head
Points to the main object of a large body.
Definition: object.h:304
SockList * player_get_delayed_buffer(player *pl)
Get a delayed socket buffer, that will be sent after the player&#39;s tick is complete.
Definition: player.cpp:4506
struct struct_map_info * tiles[4]
Definition: mapper.cpp:262
static void create_destination(void)
Ensures destination directory exists.
Definition: mapper.cpp:3113
This is a game-map.
Definition: map.h:320
static void add_map_to_region(struct_map_info *map, region *reg)
Links a map to a region.
Definition: mapper.cpp:1359
static void do_tiled_map_picture(struct_map_info *map)
Generates the large and small pictures for a tiled map.
Definition: mapper.cpp:2087
static struct_slaying_info ** slaying_info
Found slaying fields.
Definition: mapper.cpp:450
std::vector< struct_npc_info * > npc_list
List of NPCs with a custom message.
Definition: mapper.cpp:216
int main(int argc, char **argv)
Definition: mapper.cpp:3133
int power
Item power as declared by the item itself.
Definition: mapper.cpp:274
static int jpeg_quality
Quality for jpg pictures.
Definition: mapper.cpp:396
static int force_pics
To force picture regeneration even if map didn&#39;t change.
Definition: mapper.cpp:361
#define EXIT_PATH(xyz)
Definition: define.h:439
char * name
Item&#39;s name.
Definition: mapper.cpp:273
size_t count
Number of races.
Definition: mapper.cpp:221
#define FLAG_IS_A_TEMPLATE
Object has no ingame life until instantiated.
Definition: define.h:362
static bool do_regions_link
Definition: mapper.cpp:432
static int is_slaying(object *item)
Is the slaying field relevant for this item?
Definition: mapper.cpp:1426
static void process_map(struct_map_info *info)
Processes a map.
Definition: mapper.cpp:1550
char * tile_path[4]
Path to adjoining maps.
Definition: map.h:358
static int sort_slaying(const void *left, const void *right)
Helper function to sort an array of struct_slaying_info.
Definition: mapper.cpp:2979
static void add_race_to_list(struct_race *race, struct_race_list *list, int check)
Appends a race to a race list.
Definition: mapper.cpp:335
char * maplore
Map lore information.
Definition: map.h:357
Map information.
Definition: mapper.cpp:240
static std::vector< std::string > path_stack
Path, relative to output root, of pages being generated.
Definition: mapper.cpp:2628
#define S_DOOR
Connection/slaying information.
Definition: mapper.cpp:437
static void write_world_map(void)
Generates a big world map.
Definition: mapper.cpp:1793
See Potion.
Definition: object.h:116
size_t get_faces_count()
Definition: assets.cpp:297
static int generate_pics
Whether to generate the picture or not.
Definition: mapper.cpp:360
struct Settings settings
Global settings.
Definition: init.cpp:139
static inja::TemplateStorage templateCache
Definition: mapper.cpp:2416
static const char * ignore_path[]
Directories to ignore for map search.
Definition: mapper.cpp:2844
static void init_struct_map_in_quest_list(struct_map_in_quest_list *list)
Definition: mapper.cpp:949
static gdImagePtr infomap
World map with exits / roads / blocking / ...
Definition: mapper.cpp:420
char * path_combine_and_normalize(const char *src, const char *dst, char *path, size_t size)
Combines the 2 paths.
Definition: path.cpp:172
static int sort_struct_map_in_quest(const void *left, const void *right)
Sorts 2 struct_map_in_quest, on the map&#39;s name or path.
Definition: mapper.cpp:1036
static int quests_allocated
Allocated items in quests.
Definition: mapper.cpp:947
See Spell.
Definition: object.h:219
static std::vector< struct_equipment * > special_equipment
Special equipment list.
Definition: mapper.cpp:280
std::string template_name
Template name to use.
Definition: mapper.cpp:2707
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:609
void emergency_save(int flag)
Save all players.
Definition: main.cpp:347
See Locked Door.
Definition: object.h:128
living stats
Str, Con, Dex, etc.
Definition: object.h:378
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
void add_template_to_render(const std::string &template_name, const std::string &output_name, const std::string &param)
Push the specified template, with optional param, on the list of files to process.
Definition: mapper.cpp:2719
#define IS_SHIELD(op)
Definition: define.h:170
static struct_slaying_info * get_slaying_struct(const char *slaying)
Returns a struct_slaying_info for specified slaying.
Definition: mapper.cpp:1439
See Magic Wall.
Definition: object.h:173
static struct_map_list tiled_map_list
Pseudo-maps grouping other maps.
Definition: mapper.cpp:269
static struct_race_list races
Monsters found in maps.
Definition: mapper.cpp:290
void delete_map(mapstruct *m)
Frees the map, including the mapstruct.
Definition: map.cpp:1705
static void add_region_link(mapstruct *source, mapstruct *dest)
Creates a link between two maps if they are on different regions.
Definition: mapper.cpp:1407
static void write_world_info(void)
Writes the exit information world map.
Definition: mapper.cpp:2927
char * filename
Filename of the map.
Definition: mapper.cpp:243
Structure handling character information for an account.
Definition: account_char.h:27
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
static std::string templates_root("templates/")
Directory to get templates from, with a leading /.
char * description
Description associated with the map for the quest.
Definition: mapper.cpp:930
slaying information.
Definition: mapper.cpp:445
void command_help(object *op, const char *params)
Player is asking for some help.
Definition: c_misc.cpp:1770
static int map_limit
Maximum number of maps to browse, -1 for all.
Definition: mapper.cpp:366
See Container.
Definition: object.h:236
See Player Changer.
Definition: object.h:167
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:340
static int sort_map_info(const void *left, const void *right)
Sorts the struct_map_info according to the map name or the path if equal.
Definition: mapper.cpp:903
struct_map_list maps_list
Maps in the region.
Definition: mapper.cpp:407
void move_firewall(object *op)
Move for FIREWALL.
Definition: main.cpp:343
static void add_to_struct_map_in_quest_list(struct_map_in_quest_list *list, struct_map_in_quest *item)
Definition: mapper.cpp:955
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:753
MoveType move_slow
Movement types this slows down.
Definition: object.h:441
char * diff
Result of get_ob_diff() with the item&#39;s clone.
Definition: mapper.cpp:276
#define FLAG_CURSED
The object is cursed.
Definition: define.h:304
See Player.
Definition: object.h:112
const char * datadir
Read only data files.
Definition: global.h:249
static void add_monster(object *monster, struct_map_info *map)
Adds a monster to the monster list.
Definition: mapper.cpp:677
int is_valid_faceset(int fsn)
Checks specified faceset is valid.
Definition: image.cpp:117
struct treasurelist * randomitems
Items to be generated.
Definition: object.h:395
static struct_npc_info * create_npc_info(const object *npc)
Create the struct_npc_info from the specified NPC.
Definition: mapper.cpp:1184
static void add_map_to_slaying(struct_slaying_info *info, int item, struct_map_info *map)
Adds the specified map to the slaying information if not already present.
Definition: mapper.cpp:1470
static struct_map_info * find_map_by_key(const std::string &key)
Get the map with the specified key, nullptr if not found.
Definition: mapper.cpp:2233
static void quest_callback(const quest_definition *quest, void *)
Definition: mapper.cpp:2216
static int cached_pics
Non recreated pics.
Definition: mapper.cpp:378
sstring name_pl
The plural name of the object.
Definition: object.h:323
#define FLAG_AUTO_APPLY
Will be applied when created.
Definition: define.h:237
static int tileset
Tileset to use to generate pics.
Definition: mapper.cpp:370
static void find_maps(const char *from)
Recursively find all all maps in a directory.
Definition: mapper.cpp:2869
static int is_road(object *item)
Checks if object is considered a road or not.
Definition: mapper.cpp:712
Account_Chars * account_char_load(const char *account_name)
For a given account name, load the character information and return it.
static inja::Template get_template(const std::string &filename)
Definition: mapper.cpp:2417
static std::set< std::string > rendered_templates
List of generated files, to not generate multiple times.
Definition: mapper.cpp:2224
See Altar.
Definition: object.h:127
static event_registration m
Definition: citylife.cpp:424
static int color_linked_exit
Exit leading to another map.
Definition: mapper.cpp:422
char * create_pathname(const char *name, char *buf, size_t size)
Get the full path to a map file.
Definition: map.cpp:104
static bool sort_equipment(const struct_equipment *l, const struct_equipment *r)
Sort 2 struct_equipment.
Definition: mapper.cpp:513
object * generate_treasure(treasurelist *t, int difficulty)
Generate a treasure from a list generating a single item.
Definition: treasure.cpp:319
static nlohmann::json create_region_array(const std::set< region *> &regions)
Return an array of region identifiers.
Definition: mapper.cpp:2405
uint16_t datalen
Length of data.
Definition: image.h:12
struct struct_race ** races
Races on the list.
Definition: mapper.cpp:220
sstring name
The name of the object, obviously...
Definition: object.h:319
static struct_race * get_race(const char *name)
Returns the race for specified name.
Definition: mapper.cpp:648
See Shop Floor.
Definition: object.h:188
sstring title
Of foo, etc.
Definition: object.h:325
#define MAP_WIDTH(m)
Map width.
Definition: map.h:76
static void fix_tiled_map_monsters(void)
Makes all monsters point to tiled maps instead of map when appliable, and merge map monster to tiled ...
Definition: mapper.cpp:2030
uint32_t nrof
Number of objects.
Definition: object.h:342
static struct_quest * find_quest_info(const char *name)
Gets the information for a quest if it exists.
Definition: mapper.cpp:968
const char * mapdir
Where the map files are.
Definition: global.h:252
static void do_exit_map(mapstruct *map)
Proceses exit / road / blocking information for specified map into the global infomap map...
Definition: mapper.cpp:777
static void init_race_list(struct_race_list *list)
Blanks a struct_race_list.
Definition: mapper.cpp:319
Utility structure to group map-quest link structure.
Definition: mapper.cpp:226
char * msg
The description of the region.
Definition: map.h:288
#define CLEAR_FLAG(xyz, p)
Definition: define.h:385
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
void account_char_free(Account_Chars *chars)
This frees all data associated with the character information.
struct dirent * readdir(DIR *)
static std::map< region *, std::string > reverse_regions
Link between a region and its unique identifier.
Definition: mapper.cpp:2226
See Timed Gate.
Definition: object.h:133
void get_ob_diff(StringBuffer *sb, const object *op, const object *op2)
Returns a pointer to a static string which contains all variables which are different in the two give...
Definition: object.cpp:4971
#define S_KEY
Definition: mapper.cpp:438
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.cpp:1334
void init_gods(void)
This takes a look at all of the archetypes to find the objects which correspond to the GODS (type GOD...
Definition: holy.cpp:59
static std::vector< std::string > templates
List of template files to start processing from.
Definition: mapper.cpp:2746
void apply_auto_fix(mapstruct *m)
Go through the entire map (only the first time when an original map is loaded) and performs special a...
Definition: main.cpp:258
int calc_power
Item power calculated via calc_item_power().
Definition: mapper.cpp:275
static void do_help(const char *program)
Prints usage information, and exit.
Definition: mapper.cpp:2992
JPG.
Definition: mapper.cpp:383
static void relative_path(const char *from, const char *to, char *result)
Computes the shortest path from one file to another.
Definition: mapper.cpp:834
static void dump_unused_maps(void)
Writes the list of unused maps, maps found in the directories but not linked from the other maps...
Definition: mapper.cpp:2909
std::string param
Optional template parameter.
Definition: mapper.cpp:2709
static int tiled_map_need_pic(struct_map_info *map)
Definition: mapper.cpp:2057
static int sort_region(const void *left, const void *right)
Sorts an array of struct_region_info by region name.
Definition: mapper.cpp:919
static size_t region_count
Count of regions.
Definition: mapper.cpp:413
static bool build_search_file
If set, will build the &#39;search_data.js&#39; file.
Definition: mapper.cpp:374
static const char * ignore_name[]
File names to ignore for map search.
Definition: mapper.cpp:2855
static void do_parameters(int argc, char **argv)
Handles command-line parameters.
Definition: mapper.cpp:3029
static bool list_system_quests
Whether to show &#39;system&#39; quests or not.
Definition: mapper.cpp:372
static region * find_region_by_key(const std::string &key)
Get the region with the specified key, nullptr if not found.
Definition: mapper.cpp:2245
int64_t exp
Experience.
Definition: living.h:47
#define FLAG_MONSTER
Will attack players.
Definition: define.h:232
int closedir(DIR *)
static void fill_reverse_maps(struct_map_list &list)
Fill the reverse_maps array with the provided list.
Definition: mapper.cpp:2376
output_format_type
Map output formats.
Definition: mapper.cpp:381
#define S_DETECTOR
Definition: mapper.cpp:440
void dragon_ability_gain(object *who, int atnr, int level)
When a dragon-player gains a new stage of evolution, he gets some treasure.
Definition: main.cpp:365
static void init_map_list(struct_map_list *list)
Initialises a list structure.
Definition: mapper.cpp:459
One player.
Definition: player.h:107
char * name
Map&#39;s name as defined in the map file.
Definition: mapper.cpp:242
static void write_pictures_from_real_size(const char *path, gdImagePtr real, int width, int height)
Definition: mapper.cpp:1522
sstring reset_group
Definition: mapper.cpp:250
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:746
static int sizes[]
Definition: mapper.cpp:362
struct struct_map_info ** maps
Definition: mapper.cpp:234
StringBuffer * buf
Definition: readable.cpp:1563
#define IS_ARMOR(op)
Definition: define.h:166
static void add_slaying(struct_map_info *map, object *item)
Adds the item&#39;s information to the map.
Definition: mapper.cpp:1482
static void list_map(const char *path)
Marks specified path as processed.
Definition: mapper.cpp:1338
static int quests_count
Count of quests.
Definition: mapper.cpp:945
struct_map_list origin
Maps to find said monster.
Definition: mapper.cpp:287
One monster race in the maps.
Definition: mapper.cpp:284
A buffer that will be expanded as content is added to it.
void rod_adjust(object *rod)
Adjusts rod attributes.
Definition: main.cpp:390
uint16_t difficulty
What level the player should be to play here.
Definition: map.h:338
static void write_tiled_maps(void)
Outputs all tiled map pages.
Definition: mapper.cpp:2205
void set_darkness_map(mapstruct *m)
Set the darkness level for a map, based on the time of the day.
Definition: main.cpp:371
void esrv_update_spells(player *pl)
This looks for any spells the player may have that have changed their stats.
Definition: main.cpp:386
static void fix_tiled_map(void)
Ensures all tiled maps have a name, a region, a filename and a path.
Definition: mapper.cpp:1914
int sum
Sum of locations, to compute name position.
Definition: mapper.cpp:408
object * find_skill_by_number(object *who, int skillno)
This returns the first skill pointer of the given subtype (the one that accumulates exp...
Definition: main.cpp:375
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:721
const char * sstring
Definition: sstring.h:2
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.cpp:2842
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
static int pics_allocated
Number of created pictures for GD.
Definition: mapper.cpp:357
struct_map_list origin
Map(s) this item is found in.
Definition: mapper.cpp:277
static struct_equipment * get_equipment(void)
Gets an empty struct_equipment.
Definition: mapper.cpp:486
This is a game region.
Definition: map.h:279
static nlohmann::json generate_page_and_link(inja::Arguments &args)
Create a link to a page, generating it if needed.
Definition: mapper.cpp:2654
#define FLAG_NO_PICK
Object can&#39;t be picked up.
Definition: define.h:226
mapstruct * ready_map_name(const char *name, int flags)
Makes sure the given map is loaded and swapped in.
Definition: map.cpp:1777
static bool display_rendered_template
Whether to display the template to be rendered or not.
Definition: mapper.cpp:373
static std::vector< char * > found_maps
Maps found in directories.
Definition: mapper.cpp:417
static std::unordered_map< std::string, mapzone * > maps
All defined maps, with the path as key.
Definition: citylife.cpp:91
#define IS_ARROW(op)
Definition: define.h:178
void void ext_info_map(int color, const mapstruct *map, uint8_t type, uint8_t subtype, const char *str1)
Writes to everyone on the specified map.
Definition: main.cpp:334
size_t count
Definition: mapper.cpp:235
#define tolower(C)
Simple macro to convert a letter to lowercase.
Definition: c_new.cpp:30
static struct_quest ** quests
All quests in the game.
Definition: mapper.cpp:943
struct_map_list exits_from
Definition: mapper.cpp:247
static void add_map(struct_map_info *info, struct_map_list *list)
Adds a map to specified array, if it isn&#39;t already.
Definition: mapper.cpp:1218
This is one artifact, ie one special item.
Definition: artifact.h:14
Information about one face set.
Definition: image.h:17
player * find_player_partial_name(const char *plname)
Find a player by a partial name.
Definition: player.cpp:114
static int color_unlinked_exit
Color for exits without a path set.
Definition: mapper.cpp:421
sstring artifact
If set, the item is the artifact with this name and the matching type.
Definition: object.h:322
static void fix_exits_to_tiled_maps(void)
Changes all exits to maps in a tiled map to point directly to the tiled map.
Definition: mapper.cpp:2002
See Teleporter.
Definition: object.h:146
object clone
An object from which to do object_copy()
Definition: object.h:487
static void add_one_item(object *item, struct_map_info *map)
Adds an item to the list of special items.
Definition: mapper.cpp:557
Collection of races.
Definition: mapper.cpp:219
static int is_special_equipment(object *item)
Definition: mapper.cpp:467
#define HAS_RANDOM_ITEMS(op)
This return TRUE if object has still randomitems which could be expanded.
Definition: define.h:184
static void save_picture(FILE *file, gdImagePtr pic)
Saves a map to a file, based on jpg/png settings.
Definition: mapper.cpp:1393
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:693
npc_list * npcs
Definition: mapper.cpp:256
static int sort_race(const void *a, const void *b)
Sort 2 struct_race.
Definition: mapper.cpp:699
char * name
Name of map as given by its creator.
Definition: map.h:323
static int ** elevation_info
All elevation spots in the "world_" maps.
Definition: mapper.cpp:427
object * item
Special values of the artifact.
Definition: artifact.h:15
int16_t hp
Hit Points.
Definition: living.h:40
void do_auto_apply(mapstruct *m)
Definition: mapper.cpp:3314
char * path
Full path of the map from the start directory.
Definition: mapper.cpp:241
static char root[500]
Path to store generated files.
Definition: mapper.cpp:354
static void add_npc_to_map(npc_list *list, const object *npc)
Add the specified NPC to the list.
Definition: mapper.cpp:1202
int y
Coordinates in the map.
Definition: mapper.cpp:212
b.t.
Definition: object.h:174
static int compare_map_info(const struct_map_info *left, const struct_map_info *right)
Compares struct_map_info according to the map name or the path if equal.
Definition: mapper.cpp:873