00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00213 #include <time.h>
00214 #include <stdio.h>
00215
00216 #include <strings.h>
00217
00218 #include <global.h>
00219 #include <sproto.h>
00220 #include <image.h>
00221
00222 #include <gd.h>
00223 #include <gdfonts.h>
00224 #include <gdfontl.h>
00225 #include <gdfontg.h>
00226
00227 static gdImagePtr *gdfaces;
00228
00229 extern int nrofpixmaps;
00230
00232 typedef struct struct_npc_info {
00233 const char *name;
00234 const char *message;
00235 int x, y;
00236 } struct_npc_info;
00237
00239 typedef struct struct_npc_list {
00240 struct_npc_info **npc;
00241 int count;
00242 int allocated;
00243 } struct_npc_list;
00244
00246 typedef struct struct_race_list {
00247 struct struct_race **races;
00248 int count;
00249 int allocated;
00250 } struct_race_list;
00251
00253 typedef struct {
00254 struct struct_map_in_quest **list;
00255 int count;
00256 int allocated;
00257 } struct_map_in_quest_list;
00258
00260 typedef struct {
00261 struct struct_map_info **maps;
00262 int count;
00263 int allocated;
00264 } struct_map_list;
00265
00267 typedef struct struct_map_info {
00268 char *path;
00269 char *name;
00270 char *filename;
00271 char *lore;
00272 region *cfregion;
00273 int level, pic_was_done, max_monster, min_monster;
00274 struct_map_list exits_from;
00275 struct_map_list exits_to;
00276 struct_map_in_quest_list quests;
00277
00278 struct_map_list tiled_maps;
00279
00280 struct_race_list monsters;
00281
00282 struct_npc_list npcs;
00283
00284 struct struct_map_info *tiled_group;
00285 int height, width;
00286 int tiled_x_from, tiled_y_from, processed;
00287 struct struct_map_info *tiles[4];
00288 } struct_map_info;
00289
00291 static struct_map_list maps_list;
00292
00294 static struct_map_list tiled_map_list;
00295
00297 typedef struct struct_equipment {
00298 char *name;
00299 int power;
00300 int calc_power;
00301 char *diff;
00302 struct_map_list origin;
00303 } struct_equipment;
00304
00305 static struct_equipment **special_equipment = NULL;
00307 static int equipment_count = 0;
00309 static int equipment_allocated = 0;
00313 typedef struct struct_race {
00314 char *name;
00315 int count;
00316 struct_map_list origin;
00317 } struct_race;
00318
00319 static struct_race_list races;
00326 static void init_race_list(struct_race_list *list) {
00327 list->races = NULL;
00328 list->count = 0;
00329 list->allocated = 0;
00330 }
00331
00342 static void add_race_to_list(struct_race *race, struct_race_list *list, int check) {
00343 if (check) {
00344 int test;
00345
00346 for (test = 0; test < list->count; test++) {
00347 if (list->races[test] == race)
00348 return;
00349 }
00350 }
00351
00352 if (list->allocated == list->count) {
00353 list->allocated += 50;
00354 list->races = realloc(list->races, sizeof(struct_race *)*list->allocated);
00355 }
00356 list->races[list->count] = race;
00357 list->count++;
00358 }
00359
00361 static char root[500];
00362
00364 static int pics_allocated;
00365
00366
00367 static int generate_pics = 1;
00368 static int force_pics = 0;
00369 static int generate_index = 1;
00370 static int size_small = 16;
00371 static int map_limit = -1;
00372 static int show_maps = 0;
00373 static int world_map = 1;
00374 static int world_exit_info = 1;
00375 static int tileset = 0;
00377 static char *world_template;
00378 static char *world_row_template;
00379 static char *world_map_template;
00381 static char *map_template;
00382 static char *map_no_exit_template;
00383 static char *map_with_exit_template;
00384 static char *map_exit_template;
00385 static char *map_no_exit_to_template;
00386 static char *map_with_exit_to_template;
00387 static char *map_exit_to_template;
00388 static char *map_lore_template;
00389 static char *map_no_lore_template;
00390 static char *map_no_monster_template;
00391 static char *map_monster_before_template;
00392 static char *map_monster_between_template;
00393 static char *map_monster_one_template;
00394 static char *map_monster_after_template;
00396 static char *index_template;
00397 static char *index_letter;
00398 static char *index_map;
00400 static char *region_template;
00401 static char *region_letter_template;
00402 static char *region_map_template;
00404 static char *index_region_template;
00405 static char *index_region_region_template;
00407 static char *level_template;
00408 static char *level_value_template;
00409 static char *level_map_template;
00410
00411 static char *index_quest_template;
00412 static char *quest_template;
00413 static char *quest_map_template;
00414
00415 static char *map_no_quest_template;
00416 static char *map_with_quests_template;
00417 static char *map_one_quest_template;
00418
00420 static int created_pics = 0;
00421 static int cached_pics = 0;
00424 enum output_format_type {
00425 OF_PNG = 0,
00426 OF_JPG = 1
00427 };
00428
00430 static const char *output_extensions[] = {
00431 ".png",
00432 ".jpg"
00433 };
00434
00436 static enum output_format_type output_format = OF_PNG;
00437
00439 static int jpeg_quality = -1;
00440
00442 static int rawmaps = 0;
00443
00445 static int warn_no_path = 0;
00446
00448 typedef struct struct_region_info {
00449 region *reg;
00450 struct_map_list maps_list;
00451 int sum_x, sum_y, sum;
00452 int is_world;
00453 } struct_region_info;
00454
00455 static struct struct_region_info **regions = NULL;
00456 static int region_count = 0;
00457 static int region_allocated = 0;
00459 static int list_unused_maps = 0;
00460 static char **found_maps = NULL;
00461 static int found_maps_count = 0;
00462 static int found_maps_allocated = 0;
00464
00465 static gdImagePtr infomap;
00466 static int color_unlinked_exit;
00467 static int color_linked_exit;
00468 static int color_road;
00469 static int color_blocking;
00470 static int color_slowing;
00472 static int **elevation_info;
00473 static int elevation_min;
00474 static int elevation_max;
00476
00477 static int do_regions_link = 0;
00478 static char **regions_link;
00479 static int regions_link_count = 0;
00480 static int regions_link_allocated = 0;
00481
00483 #define S_DOOR 0
00484 #define S_KEY 1
00485 #define S_CONTAINER 2
00486 #define S_DETECTOR 3
00487 #define S_CONNECT 4
00488 #define S_MAX 5
00489
00491 typedef struct {
00492 char *slaying;
00493 struct_map_list maps[S_MAX];
00494 } struct_slaying_info;
00495
00496 static struct_slaying_info **slaying_info = NULL;
00497 static int slaying_count = 0;
00498 static int slaying_allocated = 0;
00505 static void init_map_list(struct_map_list *list) {
00506 list->maps = NULL;
00507 list->count = 0;
00508 list->allocated = 0;
00509 }
00510
00511 static void add_map(struct_map_info *info, struct_map_list *list);
00512
00513 static int is_special_equipment(object *item) {
00514 if (item->name == item->arch->clone.name)
00515 return 0;
00516 if (QUERY_FLAG(item, FLAG_NO_PICK))
00517 return 0;
00518 if (item->move_block == MOVE_ALL)
00519 return 0;
00520
00521 if (IS_SHIELD(item) || IS_WEAPON(item) || IS_ARMOR(item) || IS_ARROW(item) || (item->type == ROD) || (item->type == WAND))
00522 return 1;
00523
00524 return 0;
00525 }
00526
00532 static struct_equipment *get_equipment(void) {
00533 struct_equipment *add = calloc(1, sizeof(struct_equipment));
00534
00535 init_map_list(&add->origin);
00536 return add;
00537 }
00538
00545 static void free_equipment(struct_equipment *equip) {
00546 free(equip->diff);
00547 free(equip->name);
00548 free(equip);
00549 }
00550
00559 static struct_equipment *ensure_unique(struct_equipment *item) {
00560 int check;
00561 struct_equipment *comp;
00562
00563 for (check = 0; check < equipment_count; check++) {
00564 comp = special_equipment[check];
00565
00566 if (strcmp(comp->name, item->name))
00567 continue;
00568 if (comp->power != item->power)
00569 continue;
00570 if (comp->calc_power != item->calc_power)
00571 continue;
00572 if (strcmp(comp->diff, item->diff))
00573 continue;
00574
00575 free_equipment(item);
00576 return comp;
00577 }
00578
00579 if (equipment_count == equipment_allocated) {
00580 equipment_allocated += 50;
00581 special_equipment = realloc(special_equipment, sizeof(struct_equipment *)*equipment_allocated);
00582 }
00583 special_equipment[equipment_count] = item;
00584 equipment_count++;
00585
00586 return item;
00587 }
00588
00598 static void add_one_item(object *item, struct_map_info *map) {
00599 struct_equipment *add = get_equipment();
00600 StringBuffer *bf = stringbuffer_new();
00601 int x, y;
00602 sstring name, namepl;
00603
00604 x = item->x;
00605 y = item->y;
00606 name = item->name;
00607 namepl = item->name_pl;
00608
00609 item->x = item->arch->clone.x;
00610 item->y = item->arch->clone.y;
00611 item->name = item->arch->clone.name;
00612 item->name_pl = item->arch->clone.name_pl;
00613 get_ob_diff(bf, item, &item->arch->clone);
00614 add->diff = stringbuffer_finish(bf);
00615
00616 item->x = x;
00617 item->y = y;
00618 item->name = name;
00619 item->name_pl = namepl;
00620
00621 if (add->diff == NULL || strcmp(add->diff, "") == 0) {
00622 free_equipment(add);
00623 return;
00624 }
00625
00626 add->name = strdup(item->name);
00627 add->power = item->item_power;
00628 add->calc_power = calc_item_power(item, 0);
00629
00630 add = ensure_unique(add);
00631 add_map(map, &add->origin);
00632 }
00633
00642 static void check_equipment(object *item, struct_map_info *map) {
00643 object *inv;
00644
00645 if (is_special_equipment(item))
00646 add_one_item(item, map);
00647
00648 for (inv = item->inv; inv; inv = inv->below) {
00649 check_equipment(inv, map);
00650 }
00651 }
00652
00661 static int sort_equipment(const void *a, const void *b) {
00662 const struct_equipment *l = *(const struct_equipment **)a;
00663 const struct_equipment *r = *(const struct_equipment **)b;
00664 int c = l->power-r->power;
00665
00666 if (c)
00667 return c;
00668 return strcasecmp(l->name, r->name);
00669 }
00670
00679 static struct_race *get_race(const char *name) {
00680 int test;
00681 struct_race *item;
00682
00683 for (test = 0; test < races.count; test++) {
00684 if (strcmp(races.races[test]->name, name) == 0) {
00685 races.races[test]->count++;
00686 return races.races[test];
00687 }
00688 }
00689
00690 item = calloc(1, sizeof(struct_race));
00691 item->name = strdup(name);
00692 item->count = 1;
00693 init_map_list(&item->origin);
00694
00695 add_race_to_list(item, &races, 0);
00696
00697 return item;
00698 }
00699
00708 static void add_monster(object *monster, struct_map_info *map) {
00709 struct_race *race;
00710
00711 if (monster->head && monster != monster->head)
00712 return;
00713
00714 map->min_monster = MIN(monster->level, map->min_monster);
00715 map->max_monster = MAX(monster->level, map->max_monster);
00716
00717 race = get_race(monster->name);
00718 add_map(map, &race->origin);
00719 add_race_to_list(race, &map->monsters, 1);
00720 }
00721
00730 static int sort_race(const void *a, const void *b) {
00731 const struct_race *l = *(const struct_race **)a;
00732 const struct_race *r = *(const struct_race **)b;
00733 return strcasecmp(l->name, r->name);
00734 }
00735
00743 static int is_road(object *item) {
00744 int test;
00745
00746 const char *roads[] = {
00747 "cobblestones",
00748 "flagstone",
00749 "ice_stone",
00750 "snow",
00751 NULL };
00752 const char *partial[] = {
00753 "dirtroad_",
00754 NULL };
00755
00756 for (test = 0; partial[test] != NULL; test++) {
00757 if (strstr(item->arch->name, partial[test]) != NULL)
00758 return 1;
00759 }
00760
00761 if (!QUERY_FLAG(item, FLAG_IS_FLOOR))
00762 return 0;
00763
00764 for (test = 0; roads[test] != NULL; test++) {
00765 if (strcmp(item->arch->name, roads[test]) == 0)
00766 return 1;
00767 }
00768
00769 return 0;
00770 }
00771
00779 static int is_blocking(object *item) {
00780 return item->move_block == MOVE_ALL ? 1 : 0;
00781 }
00782
00793 static int get_elevation_color(int elevation, gdImagePtr elevationmap) {
00794 if (elevation > 0)
00795 return gdImageColorResolve(elevationmap, 200*elevation/elevation_max, 0, 0);
00796 else
00797 return gdImageColorResolve(elevationmap, 0, 0, 200*elevation/elevation_min);
00798 }
00799
00808 static void do_exit_map(mapstruct *map) {
00809 int tx, ty, x, y;
00810 object *item, *test;
00811
00812 if (sscanf(map->path, "/world/world_%d_%d", &x, &y) != 2)
00813 return;
00814
00815 x -= 100;
00816 y -= 100;
00817
00818 for (tx = 0; tx < MAP_WIDTH(map); tx++) {
00819 for (ty = 0; ty < MAP_HEIGHT(map); ty++) {
00820 item = GET_MAP_OB(map, tx, ty);
00821 while (item) {
00822 test = item->head ? item->head : item;
00823
00824 if (test->type == EXIT || test->type == TELEPORTER) {
00825 if (!test->slaying)
00826 gdImageSetPixel(infomap, x*50+tx, y*50+ty, color_unlinked_exit);
00827 else
00828 gdImageSetPixel(infomap, x*50+tx, y*50+ty, color_linked_exit);
00829 } else if (is_road(test))
00830 gdImageSetPixel(infomap, x*50+tx, y*50+ty, color_road);
00831 else if (is_blocking(test)) {
00832 gdImageSetPixel(infomap, x*50+tx, y*50+ty, color_blocking);
00833
00834 break;
00835 } else if (test->move_slow != 0)
00836 gdImageSetPixel(infomap, x*50+tx, y*50+ty, color_slowing);
00837
00838 if (item->elevation) {
00839 elevation_min = MIN(elevation_min, item->elevation);
00840 elevation_max = MAX(elevation_max, item->elevation);
00841 elevation_info[x*50+tx][y*50+ty] = item->elevation;
00842 }
00843
00844 item = item->above;
00845 }
00846 }
00847 }
00848 }
00849
00850 void do_auto_apply(mapstruct *m);
00851
00862 static int sortbyname(const void *a, const void *b) {
00863 return (strcmp(*(const char **)a, *(const char **)b));
00864 }
00865
00876 static char *cat_template(char *source, char *add) {
00877 if (!source)
00878 return add;
00879 source = realloc(source, strlen(source)+strlen(add)+1);
00880 strcat(source, add);
00881 free(add);
00882 return source;
00883 }
00884
00895 static void read_template(const char *name, char **buffer) {
00896 FILE *file;
00897 struct stat info;
00898
00899 if (stat(name, &info)) {
00900 printf("Couldn't stat template %s!\n", name);
00901 exit(1);
00902 }
00903
00904 (*buffer) = calloc(1, info.st_size+1);
00905 if (!(*buffer)) {
00906 printf("Template %s calloc failed!\n", name);
00907 exit(1);
00908 }
00909
00910 if (info.st_size == 0) {
00911 (*buffer)[0] = '\0';
00912 return;
00913 }
00914
00915 file = fopen(name, "rb");
00916 if (!file) {
00917 printf("Couldn't open template %s!\n", name);
00918 free(*buffer);
00919 exit(1);
00920 }
00921 if (fread(*buffer, info.st_size, 1, file) != 1) {
00922 printf("Couldn't read template %s!\n", name);
00923 free(*buffer);
00924 fclose(file);
00925 exit(1);
00926 }
00927 fclose(file);
00928 }
00929
00947 static char *do_template(const char *template, const char **vars, const char **values) {
00948 int count = 0;
00949 const char *sharp = template;
00950 int maxlen = 0;
00951 int var = 0;
00952 char *result;
00953 char *current_result;
00954 const char *end;
00955
00956 while ((sharp = strchr(sharp, '#')) != NULL) {
00957 sharp++;
00958 count++;
00959 }
00960 if (!count)
00961 return strdup(template);
00962 if (count%2) {
00963 printf("Malformed template, mismatched #!\n");
00964 return strdup(template);
00965 }
00966
00967 while (vars[var] != NULL) {
00968 if (strlen(values[var]) > maxlen)
00969 maxlen = strlen(values[var]);
00970 var++;
00971 }
00972 result = calloc(1, strlen(template)+maxlen*(count/2)+1);
00973 if (!result)
00974 return NULL;
00975 current_result = result;
00976
00977 sharp = template;
00978 while ((sharp = strchr(sharp, '#')) != NULL) {
00979 end = strchr(sharp+1, '#');
00980 strncpy(current_result, template, sharp-template);
00981 if (end == sharp+1) {
00982 strcat(current_result, "#");
00983 }
00984 else {
00985 current_result = current_result+strlen(current_result);
00986 var = 0;
00987 while (vars[var] != NULL && (strncmp(vars[var], sharp+1, end-sharp-1) || (strlen(vars[var]) != end-sharp-1)))
00988
00989 var++;
00990 if (vars[var] == NULL)
00991 printf("Wrong tag: %s\n", sharp);
00992 else
00993 strcpy(current_result, values[var]);
00994 }
00995 current_result = current_result+strlen(current_result);
00996 sharp = end+1;
00997 template = sharp;
00998 }
00999 strcat(current_result, template);
01000 return result;
01001 }
01002
01015 static void relative_path(const char *from, const char *to, char *result) {
01016 const char *fslash;
01017 const char *rslash;
01018
01019 result[0] = '\0';
01020
01021 fslash = strchr(from+1, '/');
01022 if (!fslash) {
01023 strcpy(result, to+1);
01024 return;
01025 }
01026
01027 rslash = strchr(to+1, '/');
01028 while (fslash && rslash && (fslash-from == rslash-to) && strncmp(from, to, fslash-from+1) == 0) {
01029 from = fslash+1;
01030 to = rslash+1;
01031 fslash = strchr(fslash+1, '/');
01032 rslash = strchr(rslash+1, '/');
01033 }
01034
01035 while (fslash) {
01036 strcat(result, "../");
01037 fslash = strchr(fslash+1, '/');
01038 }
01039 if (strlen(result) && result[strlen(result)-1] == '/' && *to == '/')
01040 result[strlen(result)-1] = '\0';
01041 strcat(result, to);
01042 }
01043
01054 static int sort_mapname(const void *left, const void *right) {
01055 const char *l = *(const char **)left;
01056 const char *r = *(const char **)right;
01057 const char *sl = strrchr(l, '/');
01058 const char *sr = strrchr(r, '/');
01059 int c;
01060
01061 if (!sl)
01062 sl = l;
01063 if (!sr)
01064 sr = r;
01065 c = strcasecmp(sl, sr);
01066 if (c)
01067 return c;
01068
01069 return strcasecmp(l, r);
01070 }
01071
01082 static int compare_map_info(const struct_map_info *left, const struct_map_info *right) {
01083 int c;
01084
01085 if (left->tiled_group)
01086 left = left->tiled_group;
01087 if (right->tiled_group)
01088 right = right->tiled_group;
01089
01090 c = strcasecmp(left->name, right->name);
01091 if (c)
01092 return c;
01093
01094 return strcasecmp(left->path, right->path);
01095 }
01096
01107 static int sort_map_info(const void *left, const void *right) {
01108 const struct_map_info *l = *(const struct_map_info **)left;
01109 const struct_map_info *r = *(const struct_map_info **)right;
01110 return compare_map_info(l, r);
01111 }
01112
01123 static int sort_map_info_by_level(const void *left, const void *right) {
01124 const struct_map_info *l = *(const struct_map_info **)left;
01125 const struct_map_info *r = *(const struct_map_info **)right;
01126 int c = l->level-r->level;
01127 if (c)
01128 return c;
01129 return compare_map_info(l, r);
01130 }
01131
01142 static int sort_region(const void *left, const void *right) {
01143 return strcmp((*((struct_region_info **)left))->reg->name, (*((struct_region_info **)right))->reg->name);
01144 }
01145
01146
01147
01148
01149
01151 typedef struct struct_map_in_quest {
01152 struct_map_info *map;
01153 char *description;
01154 struct struct_quest *quest;
01155 } struct_map_in_quest;
01156
01158 typedef struct struct_quest {
01159 char *name;
01160 char *description;
01161 int number;
01162 struct_map_info *mainmap;
01163 struct_map_in_quest_list maps;
01164 } struct_quest;
01165
01166 static struct_quest **quests = NULL;
01168 static int quests_count = 0;
01170 static int quests_allocated = 0;
01172 static void init_struct_map_in_quest_list(struct_map_in_quest_list *list) {
01173 list->list = NULL;
01174 list->count = 0;
01175 list->allocated = 0;
01176 }
01177
01178 static void add_to_struct_map_in_quest_list(struct_map_in_quest_list *list, struct_map_in_quest *item) {
01179 if (list->count == list->allocated) {
01180 list->allocated += 10;
01181 list->list = realloc(list->list, sizeof(struct_map_in_quest *)*list->allocated);
01182 }
01183 list->list[list->count++] = item;
01184 }
01185
01194 static struct_quest *get_quest_info(const char *name) {
01195 int test;
01196 struct_quest *add;
01197
01198 for (test = 0; test < quests_count; test++) {
01199 if (strcmp(quests[test]->name, name) == 0)
01200 return quests[test];
01201 }
01202
01203 if (quests_count == quests_allocated) {
01204 quests_allocated += 10;
01205 quests = realloc(quests, sizeof(struct_quest *)*quests_allocated);
01206 }
01207 add = calloc(1, sizeof(struct_quest));
01208 add->name = strdup(name);
01209 add->number = quests_count;
01210 init_struct_map_in_quest_list(&add->maps);
01211 quests[quests_count] = add;
01212 quests_count++;
01213 return add;
01214 }
01215
01226 static void add_map_to_quest(struct_map_info *map, const char *name, const char *description) {
01227 struct_map_in_quest *add;
01228 struct_quest *quest = get_quest_info(name);
01229
01230 add = calloc(1, sizeof(struct_map_in_quest));
01231 add->map = map;
01232 add->quest = quest;
01233 add->description = strdup(description);
01234 while (strlen(add->description) && add->description[strlen(add->description)-1] == '\n')
01235 add->description[strlen(add->description)-1] = '\0';
01236 add_to_struct_map_in_quest_list(&quest->maps, add);
01237 add_to_struct_map_in_quest_list(&map->quests, add);
01238 }
01239
01248 static int sort_struct_map_in_quest(const void *left, const void *right) {
01249 int c;
01250
01251 const struct_map_in_quest *l = *(const struct_map_in_quest **)left;
01252 const struct_map_in_quest *r = *(const struct_map_in_quest **)right;
01253 const struct_map_info *ml = l->map;
01254 const struct_map_info *mr = r->map;
01255
01256 if (ml->tiled_group)
01257 ml = ml->tiled_group;
01258 if (mr->tiled_group)
01259 mr = mr->tiled_group;
01260
01261 c = strcasecmp(ml->name, mr->name);
01262 if (c)
01263 return c;
01264
01265 return strcasecmp(ml->path, mr->path);
01266 }
01267
01278 static void define_quest(const char *name, struct_map_info *mainmap, const char *description) {
01279 struct_quest *quest = get_quest_info(name);
01280
01281 if (quest->description || quest->mainmap) {
01282 printf("warning, multiple quest definition for %s, found in %s and %s.\n", quest->name, quest->mainmap ? quest->mainmap->path : "(unknown map)", mainmap->path);
01283 return;
01284 }
01285 quest->description = strdup(description);
01286 while (strlen(quest->description) && quest->description[strlen(quest->description)-1] == '\n')
01287 quest->description[strlen(quest->description)-1] = '\0';
01288 quest->mainmap = mainmap;
01289 }
01290
01297 static void process_map_lore(struct_map_info *map) {
01298 char *start, *end, *next;
01299 char name[500];
01300 char description[500];
01301
01302 start = strstr(map->lore, "@def");
01303 while (start) {
01304 description[0] = '\0';
01305
01306 end = strstr(start, "\n");
01307 if (end) {
01308 strncpy(name, start+5, end-start-5);
01309 name[end-start-5] = '\0';
01310 next = end+1;
01311 end = strstr(next, "@end");
01312 if (end) {
01313 strncpy(description, next, end-next);
01314 description[end-next] = '\0';
01315
01316 memcpy(start, end+4, strlen(map->lore)-(end-start+3));
01317 end = start;
01318 }
01319 else {
01320 strcpy(description, next);
01321 *start = '\0';
01322 end = NULL;
01323 }
01324 } else {
01325 strcpy(name, start);
01326 *start = '\0';
01327 end = NULL;
01328 }
01329
01330 define_quest(name, map, description);
01331 start = end ? strstr(end, "@def") : NULL;
01332 }
01333
01334 start = strstr(map->lore, "@quest");
01335 while (start) {
01336 description[0] = '\0';
01337
01338 end = strstr(start, "\n");
01339 if (end) {
01340 strncpy(name, start+7, end-start-7);
01341 name[end-start-7] = '\0';
01342 next = end+1;
01343 end = strstr(next, "@end");
01344 if (end) {
01345 strncpy(description, next, end-next);
01346 description[end-next] = '\0';
01347
01348 memcpy(start, end+4, strlen(map->lore)-(end-start+3));
01349 end = start;
01350 }
01351 else {
01352 strcpy(description, next);
01353 *start = '\0';
01354 end = NULL;
01355 }
01356 } else {
01357 strcpy(name, start);
01358 *start = '\0';
01359 end = NULL;
01360 }
01361
01362 add_map_to_quest(map, name, description);
01363 start = end ? strstr(end, "@quest") : NULL;
01364 }
01365 }
01366
01370 static void write_quests_page(void) {
01371 int quest, map;
01372 FILE *out;
01373 char path[500];
01374 char mappath[500];
01375 char mainmappath[500];
01376 char questid[500];
01377 const char *map_vars[] = { "MAPPATH", "MAPNAME", "MAPTEXT", NULL };
01378 const char *map_vals[] = { mappath, NULL, NULL, NULL };
01379 const char *quest_vars[] = { "QUESTNAME", "QUESTTEXT", "QUESTMAPS", "QUESTID", "MAINMAPPATH", "MAINMAPNAME", NULL };
01380 const char *quest_vals[] = { NULL, NULL, NULL, questid, mainmappath, NULL, NULL };
01381 const char *idx_vars[] = { "QUESTS", NULL };
01382 const char *idx_vals[] = { NULL, NULL };
01383 char *text_map = NULL;
01384 char *text_quest = NULL;
01385 char *text_idx = NULL;
01386
01387 printf("Writing quest index...");
01388
01389 for (quest = 0; quest < quests_count; quest++) {
01390 qsort(quests[quest]->maps.list, quests[quest]->maps.count, sizeof(struct_map_in_quest *), sort_struct_map_in_quest);
01391 for (map = 0; map < quests[quest]->maps.count; map++) {
01392 snprintf(mappath, sizeof(mappath), "%s.html", quests[quest]->maps.list[map]->map->path+1);
01393 map_vals[1] = quests[quest]->maps.list[map]->map->name;
01394 map_vals[2] = quests[quest]->maps.list[map]->description ? quests[quest]->maps.list[map]->description : "(no description)";
01395 text_map = cat_template(text_map, do_template(quest_map_template, map_vars, map_vals));
01396 }
01397 if (!text_map)
01398 text_map = strdup("");
01399
01400 quest_vals[0] = quests[quest]->name;
01401 quest_vals[1] = quests[quest]->description ? quests[quest]->description : "(main map not processed)";
01402 quest_vals[2] = text_map;
01403 snprintf(questid, sizeof(questid), "quest_%d", quests[quest]->number);
01404 if (quests[quest]->mainmap) {
01405 snprintf(mainmappath, sizeof(mainmappath), "%s.html", quests[quest]->mainmap->path+1);
01406 quest_vals[5] = quests[quest]->mainmap->name;
01407 } else {
01408 snprintf(mainmappath, sizeof(mainmappath), "#");
01409 quest_vals[5] = "";
01410 }
01411 text_quest = cat_template(text_quest, do_template(quest_template, quest_vars, quest_vals));
01412 free(text_map);
01413 text_map = NULL;
01414 }
01415
01416 if (!text_quest)
01417 text_quest = strdup("No quest.");
01418
01419 idx_vals[0] = text_quest;
01420 text_idx = do_template(index_quest_template, idx_vars, idx_vals);
01421 free(text_quest);
01422
01423 snprintf(path, sizeof(path), "%s/quests.html", root);
01424 out = fopen(path, "w+");
01425 fprintf(out, text_idx);
01426 fclose(out);
01427 free(text_idx);
01428
01429 printf(" done.\n");
01430 }
01431
01432
01433
01434
01435
01436
01437
01438
01439
01445 static void init_npc_list(struct_npc_list *list) {
01446 list->allocated = 0;
01447 list->count = 0;
01448 list->npc = NULL;
01449 }
01450
01458 static struct_npc_info *create_npc_info(const object *npc) {
01459 struct_npc_info *info = calloc(1, sizeof(struct_npc_info));
01460
01461 info->name = strdup(npc->name);
01462 info->message = strdup(npc->msg);
01463 info->x = npc->x;
01464 info->y = npc->y;
01465
01466 return info;
01467 }
01468
01476 static void add_npc_to_map(struct_map_info *map, const object *npc) {
01477 if (map->npcs.count == map->npcs.allocated) {
01478 map->npcs.allocated += 50;
01479 map->npcs.npc = realloc(map->npcs.npc, map->npcs.allocated*sizeof(struct_npc_info *));
01480 }
01481
01482 map->npcs.npc[map->npcs.count] = create_npc_info(npc);
01483 map->npcs.count++;
01484 }
01485
01486
01498 static void add_map(struct_map_info *info, struct_map_list *list) {
01499 int map;
01500
01501 for (map = 0; map < list->count; map++)
01502 if (list->maps[map] == info)
01503 return;
01504
01505 if (list->count == list->allocated) {
01506 list->allocated += 50;
01507 list->maps = realloc(list->maps, list->allocated*sizeof(struct_map_info *));
01508 }
01509 list->maps[list->count] = info;
01510 list->count++;
01511 }
01512
01523 static void replace_map(struct_map_info *find, struct_map_info *replace_by, struct_map_list *list) {
01524 int map;
01525
01526 for (map = 0; map < list->count; map++) {
01527 if (list->maps[map] == find) {
01528 list->maps[map] = replace_by;
01529 return;
01530 }
01531 }
01532 printf("replace_map: couldn't find map %s.\n", find->path);
01533 }
01534
01541 static struct_map_info *create_map_info(void) {
01542 struct_map_info *add = calloc(1, sizeof(struct_map_info));
01543
01544 add->min_monster = 2000;
01545 init_map_list(&add->exits_to);
01546 init_map_list(&add->exits_from);
01547 init_map_list(&add->tiled_maps);
01548 init_struct_map_in_quest_list(&add->quests);
01549 init_race_list(&add->monsters);
01550 init_npc_list(&add->npcs);
01551 add->tiled_group = NULL;
01552
01553 return add;
01554 }
01555
01562 static struct_map_info *create_tiled_map(void) {
01563 struct_map_info *add = create_map_info();
01564
01565 add_map(add, &tiled_map_list);
01566 return add;
01567 }
01568
01580 static void merge_tiled_maps(struct_map_info *map, int tile, struct_map_info *tiled_map) {
01581 int g;
01582 struct_map_info *group = tiled_map->tiled_group;
01583 struct_map_info *change;
01584
01585 while (group->tiled_maps.count > 0) {
01586 change = group->tiled_maps.maps[group->tiled_maps.count-1];
01587 change->tiled_group = map->tiled_group;
01588 add_map(change, &map->tiled_group->tiled_maps);
01589 group->tiled_maps.count--;
01590 }
01591
01592 for (g = 0; g < tiled_map_list.count; g++) {
01593 if (tiled_map_list.maps[g] == group) {
01594 if (g < tiled_map_list.count-1)
01595 tiled_map_list.maps[g] = tiled_map_list.maps[tiled_map_list.count-1];
01596 tiled_map_list.count--;
01597 free(group);
01598 return;
01599 }
01600 }
01601 printf("tiled_map not in tiled_map_list!");
01602 abort();
01603
01604 }
01605
01614 static struct_map_info *get_map_info(const char *path) {
01615 int map;
01616 struct_map_info *add;
01617 char *tmp;
01618
01619 for (map = 0; map < maps_list.count; map++) {
01620 if (strcmp(maps_list.maps[map]->path, path) == 0)
01621 return maps_list.maps[map];
01622 }
01623
01624 add = create_map_info();
01625 add->path = strdup(path);
01626 tmp = strrchr(path, '/');
01627 if (tmp)
01628 add->filename = strdup(tmp+1);
01629 else
01630 add->filename = strdup(path);
01631
01632 add_map(add, &maps_list);
01633 return add;
01634 }
01635
01642 static void list_map(const char *path) {
01643 int index;
01644
01645 for (index = 0; index < found_maps_count; index++) {
01646 if (found_maps[index] && strcmp(path, found_maps[index]) == 0) {
01647 free(found_maps[index]);
01648 found_maps[index] = NULL;
01649 return;
01650 }
01651 }
01652 printf("Map processed but not found in directory reading? %s\n", path);
01653 }
01654
01665 static void add_map_to_region(struct_map_info *map, region *reg) {
01666 int test;
01667 int x, y;
01668
01669 for (test = 0; test < region_count; test++) {
01670 if (regions[test]->reg == reg)
01671 break;
01672 }
01673 if (test == region_count) {
01674 if (test == region_allocated) {
01675 region_allocated++;
01676 regions = realloc(regions, sizeof(struct_region_info *)*region_allocated);
01677 regions[test] = calloc(1, sizeof(struct_region_info));
01678 }
01679 region_count++;
01680 regions[test]->reg = reg;
01681 }
01682 add_map(map, ®ions[test]->maps_list);
01683 if (sscanf(map->path, "/world/world_%d_%d", &x, &y) == 2) {
01684 regions[test]->sum_x += (x-100);
01685 regions[test]->sum_y += (y-100);
01686 regions[test]->sum++;
01687 regions[test]->is_world = 1;
01688 }
01689 }
01690
01699 static void save_picture(FILE *file, gdImagePtr pic) {
01700 if (output_format == OF_PNG)
01701 gdImagePng(pic, file);
01702 else
01703 gdImageJpeg(pic, file, jpeg_quality);
01704 }
01705
01715 static void add_region_link(mapstruct *source, mapstruct *dest, const char *linkname) {
01716 int search = 0;
01717 char entry[500];
01718 region *s, *d;
01719
01720 s = get_region_by_map(source);
01721 d = get_region_by_map(dest);
01722 if (s == d)
01723 return;
01724
01725 if (linkname && 0)
01726 snprintf(entry, sizeof(entry), "%s -> %s [ label = \"%s\" ]\n", s->name, d->name, linkname);
01727 else
01728 snprintf(entry, sizeof(entry), "%s -> %s\n", s->name, d->name);
01729
01730 for (search = 0; search < regions_link_count; search++) {
01731 if (strcmp(regions_link[search], entry) == 0)
01732 return;
01733 }
01734
01735 if (regions_link_count == regions_link_allocated) {
01736 regions_link_allocated += 10;
01737 regions_link = realloc(regions_link, sizeof(const char *)*regions_link_allocated);
01738 }
01739 regions_link[regions_link_count] = strdup(entry);
01740 regions_link_count++;
01741 }
01742
01751 static int is_slaying(object *item) {
01752 return (item->type == LOCKED_DOOR || item->type == SPECIAL_KEY || item->type == CONTAINER || item->type == CHECK_INV);
01753 }
01754
01755
01764 static struct_slaying_info *get_slaying_struct(const char *slaying) {
01765 struct_slaying_info *add;
01766 int l;
01767
01768 for (l = 0; l < slaying_count; l++) {
01769 if (!strcmp(slaying_info[l]->slaying, slaying))
01770 return slaying_info[l];
01771 }
01772 if (slaying_count == slaying_allocated) {
01773 slaying_allocated += 10;
01774 slaying_info = (struct_slaying_info **)realloc(slaying_info, sizeof(struct_slaying_info *)*slaying_allocated);
01775 }
01776
01777 add = (struct_slaying_info *)calloc(1, sizeof(struct_slaying_info));
01778 add->slaying = strdup(slaying);
01779 for (l = 0; l < S_MAX; l++)
01780 init_map_list(&add->maps[l]);
01781
01782 slaying_info[slaying_count] = add;
01783 slaying_count++;
01784
01785 return add;
01786 }
01787
01798 static void add_map_to_slaying(struct_slaying_info *info, int item, struct_map_info *map) {
01799 add_map(map, &info->maps[item]);
01800 }
01801
01810 static void add_slaying(struct_map_info *map, object *item) {
01811 struct_slaying_info *info;
01812
01813 if (!item->slaying)
01814
01815 return;
01816
01817 info = get_slaying_struct(item->slaying);
01818 if (item->type == LOCKED_DOOR)
01819 add_map_to_slaying(info, S_DOOR, map);
01820 else if (item->type == SPECIAL_KEY)
01821 add_map_to_slaying(info, S_KEY, map);
01822 else if (item->type == CONTAINER)
01823 add_map_to_slaying(info, S_CONTAINER, map);
01824 else
01825 add_map_to_slaying(info, S_CONNECT, map);
01826 }
01827
01836 static void check_slaying_inventory(struct_map_info *map, object *item) {
01837 object *inv;
01838
01839 for (inv = item->inv; inv; inv = inv->below) {
01840 if (is_slaying(inv))
01841 add_slaying(map, inv);
01842 check_slaying_inventory(map, inv);
01843 }
01844 }
01845
01854 static void process_map(struct_map_info *info) {
01855 mapstruct *m;
01856 int x, y, isworld;
01857 object *item;
01858 FILE *out;
01859 gdImagePtr pic;
01860 gdImagePtr small;
01861 struct stat stats;
01862 struct stat statspic;
01863 char exit_path[500];
01864 char tmppath[MAX_BUF];
01865 char picpath[MAX_BUF], smallpicpath[MAX_BUF];
01866 int needpic = 0;
01867 struct_map_info *link;
01868
01869 if (list_unused_maps)
01870 list_map(info->path);
01871
01872 if (show_maps)
01873 printf(" processing map %s\n", info->path);
01874
01875 m = ready_map_name(info->path, 0);
01876 if (!m) {
01877 printf("couldn't load map %s\n", info->path);
01878 return;
01879 }
01880
01881 do_exit_map(m);
01882
01883 if (!rawmaps)
01884 do_auto_apply(m);
01885
01886 info->level = m->difficulty;
01887 if (m->maplore) {
01888 info->lore = strdup(m->maplore);
01889 process_map_lore(info);
01890 }
01891
01892 isworld = (sscanf(info->path, "/world/world_%d_%d", &x, &y) == 2);
01893
01894 if (m->name)
01895 info->name = strdup(m->name);
01896 else
01897 info->name = strdup(info->filename);
01898
01899 info->cfregion = get_region_by_map(m);
01900 add_map_to_region(info, info->cfregion);
01901
01902 snprintf(picpath, sizeof(picpath), "%s%s%s", root, info->path, output_extensions[output_format]);
01903 snprintf(smallpicpath, sizeof(smallpicpath), "%s%s.small%s", root, info->path, output_extensions[output_format]);
01904
01905 if (force_pics)
01906 needpic = 1;
01907 else if (generate_pics) {
01908 create_pathname(info->path, tmppath, MAX_BUF);
01909 stat(tmppath, &stats);
01910 if (stat(picpath, &statspic) || (statspic.st_mtime < stats.st_mtime))
01911 needpic = 1;
01912 else if (stat(smallpicpath, &statspic) || (statspic.st_mtime < stats.st_mtime))
01913 needpic = 1;
01914 }
01915 else
01916 needpic = 0;
01917
01918 if (needpic) {
01919 pic = gdImageCreateTrueColor(MAP_WIDTH(m)*32, MAP_HEIGHT(m)*32);
01920 created_pics++;
01921 }
01922 else
01923 cached_pics++;
01924
01925 for (x = 0; x < 4; x++)
01926 if (m->tile_path[x] != NULL) {
01927 path_combine_and_normalize(m->path, m->tile_path[x], exit_path, sizeof(exit_path));
01928 create_pathname(exit_path, tmppath, MAX_BUF);
01929 if (stat(tmppath, &stats)) {
01930 printf(" map %s doesn't exist in map %s, for tile %d.\n", exit_path, info->path, x);
01931 }
01932
01933 if (isworld) {
01934 link = get_map_info(exit_path);
01935 add_map(link, &info->exits_from);
01936 add_map(info, &link->exits_to);
01937
01938 if (do_regions_link) {
01939 mapstruct *link = ready_map_name(exit_path, 0);
01940
01941 if (link && link != m) {
01942
01943
01944 add_region_link(m, link, NULL);
01945 link->reset_time = 1;
01946 link->in_memory = MAP_IN_MEMORY;
01947 delete_map(link);
01948 }
01949 }
01950 } else {
01951 link = get_map_info(exit_path);
01952 info->tiles[x] = link;
01953 if (link->tiled_group) {
01954 if (info->tiled_group && link->tiled_group != info->tiled_group) {
01955 merge_tiled_maps(info, x, link);
01956 continue;
01957 }
01958 if (link->tiled_group == info->tiled_group) {
01959 continue;
01960 }
01961 if (!info->tiled_group) {
01962 add_map(info, &link->tiled_group->tiled_maps);
01963 continue;
01964 }
01965 }
01966
01967 if (!info->tiled_group) {
01968 info->tiled_group = create_tiled_map();
01969 add_map(info, &info->tiled_group->tiled_maps);
01970 }
01971 link->tiled_group = info->tiled_group;
01972 add_map(link, &info->tiled_group->tiled_maps);
01973 }
01974 }
01975
01976 info->width = MAP_WIDTH(m);
01977 info->height = MAP_HEIGHT(m);
01978
01979 for (x = MAP_WIDTH(m)-1; x >= 0; x--)
01980 for (y = MAP_HEIGHT(m)-1; y >= 0; y--) {
01981 for (item = GET_MAP_OB(m, x, y); item; item = item->above) {
01982 if (item->type == EXIT || item->type == TELEPORTER || item->type == PLAYER_CHANGER) {
01983 char ep[500];
01984 const char *start;
01985
01986 if (!item->slaying) {
01987 ep[0] = '\0';
01988 if (warn_no_path)
01989 printf(" exit without any path at %d, %d on %s\n", item->x, item->y, info->path);
01990 } else {
01991 memset(ep, 0, 500);
01992 if (strcmp(item->slaying, "/!"))
01993 strcpy(ep, EXIT_PATH(item));
01994 else {
01995 if (!item->msg) {
01996 printf(" random map without message in %s at %d, %d\n", info->path, item->x, item->y);
01997 } else {
01998
01999 start = strstr(item->msg, "\nfinal_map ");
02000 if (!start && strncmp(item->msg, "final_map", strlen("final_map")) == 0)
02001
02002 start = item->msg;
02003 if (start) {
02004 char *end = strchr(start+1, '\n');
02005
02006 start += strlen("final_map")+2;
02007 strncpy(ep, start, end-start);
02008 }
02009 }
02010 }
02011
02012 if (strlen(ep)) {
02013 path_combine_and_normalize(m->path, ep, exit_path, 500);
02014 create_pathname(exit_path, tmppath, MAX_BUF);
02015 if (stat(tmppath, &stats)) {
02016 printf(" map %s doesn't exist in map %s, at %d, %d.\n", ep, info->path, item->x, item->y);
02017 } else {
02018 link = get_map_info(exit_path);
02019 add_map(link, &info->exits_from);
02020 add_map(info, &link->exits_to);
02021
02022 if (do_regions_link) {
02023 mapstruct *link = ready_map_name(exit_path, 0);
02024
02025 if (link && link != m) {
02026
02027
02028 add_region_link(m, link, item->arch->clone.name);
02029 link->reset_time = 1;
02030 link->in_memory = MAP_IN_MEMORY;
02031 delete_map(link);
02032 }
02033 }
02034 }
02035 }
02036 }
02037 } else if (is_slaying(item))
02038 add_slaying(info, item);
02039
02040 check_equipment(item, info);
02041
02042 check_slaying_inventory(info, item);
02043
02044 if (QUERY_FLAG(item, FLAG_MONSTER)) {
02045
02046 archetype *arch = find_archetype(item->arch->name);
02047
02048 add_monster(item, info);
02049 if ((QUERY_FLAG(item, FLAG_UNAGGRESSIVE) || QUERY_FLAG(item, FLAG_FRIENDLY)) && (item->msg != arch->clone.msg) && (item->msg != NULL))
02050 add_npc_to_map(info, item);
02051 }
02052
02053 if (item->invisible)
02054 continue;
02055
02056 if (needpic) {
02057 int sx, sy, hx, hy;
02058
02059 if (gdfaces[item->face->number] == NULL) {
02060 int set = get_face_fallback(tileset, item->face->number);
02061
02062 gdfaces[item->face->number] = gdImageCreateFromPngPtr(facesets[set].faces[item->face->number].datalen, facesets[set].faces[item->face->number].data);
02063 pics_allocated++;
02064 }
02065 if (item->head || item->more) {
02066 get_multi_size(item, &sx, &sy, &hx, &hy);
02067 } else {
02068 hx = 0;
02069 hy = 0;
02070 }
02071 if (gdfaces[item->face->number] != NULL && ((!item->head && !item->more) || (item->arch->clone.x+hx == 0 && item->arch->clone.y+hy == 0))) {
02072 gdImageCopy(pic, gdfaces[item->face->number], x*32, y*32, 0, 0, gdfaces[item->face->number]->sx, gdfaces[item->face->number]->sy);
02073 }
02074 }
02075 }
02076 }
02077
02078 if (needpic) {
02079 make_path_to_file(picpath);
02080 out = fopen(picpath, "wb+");
02081 save_picture(out, pic);
02082 fclose(out);
02083
02084 small = gdImageCreateTrueColor(MAP_WIDTH(m)*size_small, MAP_HEIGHT(m)*size_small);
02085 gdImageCopyResampled(small, pic, 0, 0, 0, 0, MAP_WIDTH(m)*size_small, MAP_HEIGHT(m)*size_small, MAP_WIDTH(m)*32, MAP_HEIGHT(m)*32);
02086
02087 out = fopen(smallpicpath, "wb+");
02088 save_picture(out, small);
02089 fclose(out);
02090 gdImageDestroy(small);
02091
02092 gdImageDestroy(pic);
02093
02094 info->pic_was_done = 1;
02095 }
02096
02097 m->reset_time = 1;
02098 m->in_memory = MAP_IN_MEMORY;
02099 delete_map(m);
02100 }
02101
02122 static char *do_map_index(const char *dest, struct_map_list *maps_list,
02123 const char *template_page, const char *template_letter,
02124 const char *template_map, const char **vars,
02125 const char **values) {
02126 #define VARSADD 6
02127 int map;
02128 char *string;
02129 char mappath[500];
02130 char maphtml[500];
02131 char count[50];
02132 char lettercount[50];
02133 char *tmp;
02134 const char **idx_vars;
02135 const char **idx_values;
02136 char str_letter[2];
02137 char last_letter;
02138 char index_path[500];
02139 char *mapstext = NULL;
02140 int byletter;
02141 int basevalues, realcount = 0;
02142 struct_map_info *last_group = NULL;
02143
02144 if (!generate_index)
02145 return strdup("");
02146
02147 if (vars)
02148 for (basevalues = 0; vars[basevalues] != NULL; basevalues++)
02149 ;
02150 else
02151 basevalues = 0;
02152
02153 idx_vars = malloc(sizeof(char *)*(basevalues+VARSADD));
02154 idx_vars[0] = "MAPCOUNT";
02155 memcpy(&idx_vars[1], vars, sizeof(char *)*basevalues);
02156 idx_vars[basevalues+VARSADD-1] = NULL;
02157
02158 idx_values = malloc(sizeof(char *)*(basevalues+VARSADD-1));
02159 memcpy(&idx_values[1], values, sizeof(char *)*basevalues);
02160
02161 string = NULL;
02162
02163 idx_values[0] = count;
02164
02165 snprintf(count, sizeof(count), "%d", maps_list->count);
02166
02167 idx_vars[basevalues+1] = "MAPNAME";
02168 idx_vars[basevalues+2] = "MAPPATH";
02169 idx_vars[basevalues+3] = "MAPHTML";
02170 idx_vars[basevalues+4] = NULL;
02171
02172 qsort(maps_list->maps, maps_list->count, sizeof(const char *), sort_map_info);
02173
02174 last_letter = '\0';
02175 str_letter[0] = '\0';
02176 str_letter[1] = '\0';
02177
02178 strcpy(index_path, "/");
02179 strcat(index_path, dest);
02180
02181 string = NULL;
02182 for (map = 0; map < maps_list->count; map++) {
02183 if (tolower(maps_list->maps[map]->name[0]) != last_letter) {
02184 if (mapstext != NULL) {
02185 idx_vars[basevalues+1] = "MAPS";
02186 idx_vars[basevalues+2] = "LETTER";
02187 idx_vars[basevalues+3] = "LETTERCOUNT";
02188 idx_vars[basevalues+4] = NULL;
02189 idx_values[basevalues+1] = mapstext;
02190 idx_values[basevalues+2] = str_letter;
02191 snprintf(lettercount, sizeof(lettercount), "%d", byletter);
02192 idx_values[basevalues+3] = lettercount;
02193 string = cat_template(string, do_template(template_letter, idx_vars, idx_values));
02194 free(mapstext);
02195 mapstext = NULL;
02196 idx_values[basevalues+2] = NULL;
02197 }
02198 last_letter = tolower(maps_list->maps[map]->name[0]);
02199 str_letter[0] = last_letter;
02200 byletter = 0;
02201 last_group = NULL;
02202 }
02203
02204 if (last_group && last_group == maps_list->maps[map]->tiled_group)
02205 continue;
02206 else
02207 last_group = maps_list->maps[map]->tiled_group;
02208
02209 realcount++;
02210 idx_vars[basevalues+1] = "MAPNAME";
02211 idx_vars[basevalues+2] = "MAPPATH";
02212 idx_vars[basevalues+3] = "MAPHTML";
02213 idx_values[basevalues+1] = last_group ? last_group->name : (maps_list->maps[map]->name ? maps_list->maps[map]->name : maps_list->maps[map]->path);
02214 relative_path(index_path, last_group ? last_group->path : maps_list->maps[map]->path, mappath);
02215 strcpy(maphtml, mappath);
02216 strcat(maphtml, ".html");
02217 idx_values[basevalues+2] = mappath;
02218 idx_values[basevalues+3] = maphtml;
02219 mapstext = cat_template(mapstext, do_template(template_map, idx_vars, idx_values));
02220 byletter++;
02221 }
02222 if (last_letter != '\0') {
02223 idx_vars[basevalues+1] = "MAPS";
02224 idx_vars[basevalues+2] = "LETTER";
02225 idx_vars[basevalues+3] = "LETTERCOUNT";
02226 idx_vars[basevalues+4] = NULL;
02227 idx_values[basevalues+1] = mapstext;
02228 idx_values[basevalues+2] = str_letter;
02229 snprintf(lettercount, sizeof(lettercount), "%d", byletter);
02230 idx_values[basevalues+3] = lettercount;
02231 string = cat_template(string, do_template(template_letter, idx_vars, idx_values));
02232 free(mapstext);
02233 mapstext = NULL;
02234 idx_values[basevalues+2] = NULL;
02235 }
02236
02237 snprintf(count, sizeof(count), "%d", realcount);
02238 idx_values[basevalues+1] = string;
02239 idx_vars[basevalues+1] = "LETTERS";
02240 idx_vars[basevalues+2] = NULL;
02241 tmp = do_template(template_page, idx_vars, idx_values);
02242 free(string);
02243 free(idx_vars);
02244 free(idx_values);
02245 return tmp;
02246 }
02247
02257 static void write_region_page(struct_region_info *reg) {
02258 char *string;
02259 FILE *index;
02260 char html[500];
02261 const char *vars[] = { "REGIONNAME", "REGIONHTML", "REGIONLONGNAME", "REGIONDESC", NULL };
02262 const char *values[] = { reg->reg->name, html, NULL, NULL };
02263
02264 printf("Generating map index for region %s...", reg->reg->name);
02265
02266 values[2] = get_region_longname(reg->reg);
02267 values[3] = get_region_msg(reg->reg);
02268
02269 strcpy(html, reg->reg->name);
02270 strcat(html, ".html");
02271
02272 string = do_map_index(html, ®->maps_list, region_template, region_letter_template, region_map_template, vars, values);
02273
02274 strcpy(html, root);
02275 strcat(html, "/");
02276 strcat(html, reg->reg->name);
02277 strcat(html, ".html");
02278 index = fopen(html, "w+");
02279 fprintf(index, string);
02280 fclose(index);
02281 free(string);
02282
02283 printf(" done.\n");
02284
02285 }
02286
02290 static void write_all_regions(void) {
02291 int reg;
02292
02293 qsort(regions, region_count, sizeof(struct_region_info *), sort_region);
02294
02295 for (reg = 0; reg < region_count; reg++)
02296 write_region_page(regions[reg]);
02297 }
02298
02302 static void write_maps_index(void) {
02303 char index_path[500];
02304 char *tmp;
02305 FILE *index;
02306
02307 printf("Generating global map index in maps.html...");
02308
02309 tmp = do_map_index("maps.html", &maps_list, index_template, index_letter, index_map, NULL, NULL);
02310
02311 strcpy(index_path, root);
02312 strcat(index_path, "/maps.html");
02313 index = fopen(index_path, "w+");
02314 fprintf(index, tmp);
02315 fclose(index);
02316 free(tmp);
02317
02318 printf(" done.\n");
02319 }
02320
02324 static void write_region_index(void) {
02325 char *txt;
02326 char *final;
02327 char count[10];
02328 struct_region_info *region;
02329 int reg;
02330 char file[500];
02331 const char *vars[] = { "REGIONCOUNT", "REGIONFILE", "REGIONNAME", NULL };
02332 const char *values[] = { count, file, NULL };
02333 FILE *out;
02334
02335 printf("Generating regions index in regions.html...");
02336
02337 snprintf(count, sizeof(count), "%d", region_count);
02338 txt = NULL;
02339
02340 for (reg = 0; reg < region_count; reg++) {
02341 region = regions[reg];
02342 snprintf(file, sizeof(file), "%s.html", region->reg->name);
02343 values[2] = get_region_longname(region->reg);
02344 txt = cat_template(txt, do_template(index_region_region_template, vars, values));
02345 }
02346 vars[1] = "REGIONS";
02347 values[1] = txt;
02348 vars[2] = NULL;
02349 final = do_template(index_region_template, vars, values);
02350 free(txt);
02351
02352 strcpy(file, root);
02353 strcat(file, "/regions.html");
02354 out = fopen(file, "w+");
02355 fprintf(out, final);
02356 fclose(out);
02357 free(final);
02358
02359 printf(" done.\n");
02360 }
02361
02365 static void write_world_map(void) {
02366 #define SIZE 50
02367 int x, y;
02368 FILE *out;
02369 int wx, wy;
02370 char file[500];
02371 char *map = NULL;
02372 char *total;
02373 char *row = NULL;
02374 char mapleft[10], maptop[10], mapright[10], mapbottom[10];
02375 const char *vars[] = { NULL, NULL, "MAPLEFT", "MAPTOP", "MAPRIGHT", "MAPBOTTOM", NULL };
02376 const char *values[] = { NULL, NULL, mapleft, maptop, mapright, mapbottom, NULL };
02377 char name[100];
02378 char mappath[500], mapraw[500], mapregion[500];
02379 gdImagePtr pic;
02380 gdImagePtr small;
02381 gdFontPtr font;
02382 int region, color;
02383
02384 if (!world_map)
02385 return;
02386
02387 printf("Generating world map in world.html...");
02388 fflush(stdout);
02389
02390 pic = gdImageCreateTrueColor(SIZE*30, SIZE*30);
02391
02392 strcpy(file, root);
02393 strcat(file, "/world.html");
02394
02395 wx = 100;
02396 wy = 100;
02397
02398 for (y = 0; y < 30; y++) {
02399 for (x = 0; x < 30; x++) {
02400 values[0] = name;
02401 vars[0] = "MAPNAME";
02402 vars[1] = "MAPPATH";
02403 values[1] = mappath,
02404 snprintf(name, sizeof(name), "world_%d_%d", wx, wy);
02405 snprintf(mappath, sizeof(mappath), "world/%s.html", name);
02406 snprintf(mapleft, sizeof(mapleft), "%d", SIZE*x);
02407 snprintf(maptop, sizeof(maptop), "%d", SIZE*y);
02408 snprintf(mapright, sizeof(mapright), "%d", SIZE*(x+1)-1);
02409 snprintf(mapbottom, sizeof(mapbottom), "%d", SIZE*(y+1)-1);
02410
02411 map = cat_template(map, do_template(world_map_template, vars, values));
02412
02413 snprintf(mappath, sizeof(mappath), "%s/world/%s%s", root, name, output_extensions[output_format]);
02414
02415 out = fopen(mappath, "rb");
02416 if (!out) {
02417 printf("\n warning: large pic not found for world_%d_%d", wx, wy);
02418 wx++;
02419 continue;
02420 }
02421 if (output_format == OF_PNG)
02422 small = gdImageCreateFromPng(out);
02423 else
02424 small = gdImageCreateFromJpeg(out);
02425 fclose(out);
02426 if (!small) {
02427 printf("\n warning: pic not found for world_%d_%d", wx, wy);
02428 wx++;
02429 continue;
02430 }
02431 gdImageCopyResized(pic, small, SIZE*x, SIZE*y, 0, 0, SIZE, SIZE, small->sx, small->sy);
02432 gdImageDestroy(small);
02433
02434 wx++;
02435 }
02436 wy++;
02437 wx = 100;
02438 values[0] = map;
02439 vars[0] = "MAPS";
02440 vars[1] = NULL;
02441 row = cat_template(row, do_template(world_row_template, vars, values));
02442 free(map);
02443 map = NULL;
02444 }
02445 snprintf(mappath, sizeof(mappath), "world%s", output_extensions[output_format]);
02446 snprintf(mapraw, sizeof(mapraw), "world_raw%s", output_extensions[output_format]);
02447 snprintf(mapregion, sizeof(mapregion), "world_regions%s", output_extensions[output_format]);
02448
02449 values[0] = row;
02450 vars[0] = "MAPS";
02451 values[1] = mappath;
02452 vars[1] = "WORLDMAP";
02453 values[2] = mapraw;
02454 vars[2] = "WORLDRAW";
02455 values[3] = mapregion;
02456 vars[3] = "WORLDREGIONS";
02457 vars[4] = NULL;
02458 total = do_template(world_template, vars, values);
02459 free(row);
02460 out = fopen(file, "w+");
02461 fprintf(out, total);
02462 free(total);
02463 fclose(out);
02464
02465 snprintf(mappath, sizeof(mappath), "%s/world_raw%s", root, output_extensions[output_format]);
02466 out = fopen(mappath, "wb+");
02467 save_picture(out, pic);
02468 fclose(out);
02469
02470
02471 small = gdImageCreateTrueColor(SIZE*30, SIZE*30);
02472 font = gdFontGetGiant();
02473 color = gdImageColorAllocateAlpha(pic, 255, 0, 0, 20);
02474 for (region = 0; region < region_allocated; region++) {
02475 if (!regions[region]->is_world || regions[region]->sum == 0)
02476 continue;
02477
02478 x = regions[region]->sum_x*SIZE/regions[region]->sum+SIZE/2-strlen(regions[region]->reg->name)*font->w/2;
02479 y = regions[region]->sum_y*SIZE/regions[region]->sum+SIZE/2-font->h/2;
02480 gdImageString(small, font, x, y, regions[region]->reg->name, color);
02481 gdImageString(pic, font, x, y, regions[region]->reg->name, color);
02482
02483
02484 x = regions[region]->sum_x*50/regions[region]->sum+50/2-strlen(regions[region]->reg->name)*font->w/2;
02485 y = regions[region]->sum_y*50/regions[region]->sum+50/2-font->h/2;
02486 gdImageString(infomap, font, x, y, regions[region]->reg->name, color);
02487 }
02488
02489 snprintf(mappath, sizeof(mappath), "%s/world_regions%s", root, output_extensions[output_format]);
02490 out = fopen(mappath, "wb+");
02491 save_picture(out, small);
02492 fclose(out);
02493 gdImageDestroy(small);
02494
02495 snprintf(mappath, sizeof(mappath), "%s/world%s", root, output_extensions[output_format]);
02496 out = fopen(mappath, "wb+");
02497 save_picture(out, pic);
02498 fclose(out);
02499 gdImageDestroy(pic);
02500
02501 printf(" done.\n");
02502 #undef SIZE
02503 }
02504
02511 static void write_map_page(struct_map_info *map) {
02512 char *exits_text;
02513 char *exits_to;
02514 char *maplore;
02515 char *tmp;
02516 char *quests, *quest;
02517 char *monsters;
02518
02519 char htmlpath[500];
02520 char mappic[500];
02521 char mapsmallpic[500];
02522 char indexpath[500];
02523 char regionpath[500];
02524 char regionname[500];
02525 char regionindexpath[500];
02526 char worldmappath[500];
02527 char exit_path[500];
02528 char maplevel[5], minmonster[5], maxmonster[5];
02529 FILE *out;
02530 char questpath[500], questtemp[500];
02531 const char *quest_vars[] = { "NAME", "PATH", "TEXT", NULL };
02532 const char *quest_vals[] = { NULL, questpath, NULL, NULL };
02533 const char *q_vars[] = { "QUESTS", NULL };
02534 const char *q_vals[] = { NULL, NULL };
02535 const char *m_vars[] = { "NAME", NULL };
02536 const char *m_vals[] = { NULL, NULL };
02537 const char *vars[] = { "NAME", "MAPPATH", "MAPNAME", "MAPPIC", "MAPSMALLPIC", "MAPEXITFROM", "INDEXPATH", "REGIONPATH", "REGIONNAME", "REGIONINDEXPATH", "WORLDMAPPATH", "MAPLORE", "MAPEXITTO", "MAPLEVEL", "QUESTS", "MONSTERS", "MINMONSTER", "MAXMONSTER", NULL, NULL, NULL };
02538 const char *values[] = { map->path, htmlpath, map->name, mappic, mapsmallpic, "", indexpath, regionpath, regionname, regionindexpath, worldmappath, "", "", maplevel, NULL, "", minmonster, maxmonster, NULL, NULL, NULL };
02539 int vars_count = 0;
02540
02541 while (vars[vars_count])
02542 vars_count++;
02543
02544 snprintf(minmonster, sizeof(minmonster), "%d", map->min_monster);
02545 snprintf(maxmonster, sizeof(maxmonster), "%d", map->max_monster);
02546
02547 relative_path(map->path, "/maps.html", indexpath);
02548 relative_path(map->path, "/world.html", worldmappath);
02549 relative_path(map->path, "/regions.html", regionindexpath);
02550
02551 if (map->cfregion) {
02552 strcpy(regionname, get_region_longname(map->cfregion));
02553 strcpy(exit_path, "/");
02554 strcat(exit_path, map->cfregion->name);
02555 strcat(exit_path, ".html");
02556 relative_path(map->path, exit_path, regionpath);
02557 } else {
02558 regionpath[0]='\0';
02559 snprintf(regionname, sizeof(regionname), "(map was not processed)");
02560 }
02561
02562 snprintf(mappic, sizeof(mappic), "%s%s", map->filename, output_extensions[output_format]);
02563 snprintf(mapsmallpic, sizeof(mapsmallpic), "%s.small%s", map->filename, output_extensions[output_format]);
02564
02565 snprintf(htmlpath, sizeof(htmlpath), "%s%s.html", root, map->path);
02566 make_path_to_file(htmlpath);
02567
02568 values[14] = "";
02569
02570 snprintf(maplevel, sizeof(maplevel), "%d", map->level);
02571 if (map->lore && map->lore[0] != '\0') {
02572 values[11] = map->lore;
02573 maplore = do_template(map_lore_template, vars, values);
02574 } else {
02575 maplore = do_template(map_no_lore_template, vars, values);
02576 }
02577 values[11] = maplore;
02578
02579 if (map->exits_from.count) {
02580 char *one_exit = NULL;
02581 int exit;
02582 char relative[500];
02583
02584 vars[vars_count] = "EXITNAME";
02585 vars[vars_count+1] = "EXITFILE";
02586
02587 qsort(map->exits_from.maps, map->exits_from.count, sizeof(const char *), sort_map_info);
02588 for (exit = 0; exit < map->exits_from.count; exit++) {
02589 relative_path(map->path, map->exits_from.maps[exit]->path, relative);
02590 values[vars_count] = map->exits_from.maps[exit]->name;
02591 strcat(relative, ".html");
02592 values[vars_count+1] = relative;
02593 one_exit = cat_template(one_exit, do_template(map_exit_template, vars, values));
02594 }
02595 vars[vars_count] = "EXIT";
02596 vars[vars_count+1] = NULL;
02597 values[vars_count] = one_exit;
02598 exits_text = do_template(map_with_exit_template, vars, values);
02599 free(one_exit);
02600 }
02601 else
02602 exits_text = do_template(map_no_exit_template, vars, values);
02603
02604 values[5] = exits_text;
02605
02606 if (map->exits_to.count) {
02607 char *one_exit = NULL;
02608 int exit;
02609 char relative[500];
02610
02611 vars[vars_count] = "EXITNAME";
02612 vars[vars_count+1] = "EXITFILE";
02613
02614 qsort(map->exits_to.maps, map->exits_to.count, sizeof(struct_map_info *), sort_map_info);
02615 for (exit = 0; exit < map->exits_to.count; exit++) {
02616 relative_path(map->path, map->exits_to.maps[exit]->path, relative);
02617 values[vars_count] = map->exits_to.maps[exit]->name;
02618 strcat(relative, ".html");
02619 values[vars_count+1] = relative;
02620 one_exit = cat_template(one_exit, do_template(map_exit_to_template, vars, values));
02621 }
02622 vars[vars_count] = "EXIT";
02623 vars[vars_count+1] = NULL;
02624 values[vars_count] = one_exit;
02625 exits_to = do_template(map_with_exit_to_template, vars, values);
02626 free(one_exit);
02627 } else
02628 exits_to = do_template(map_no_exit_to_template, vars, values);
02629
02630 values[12] = exits_to;
02631
02632 if (map->quests.count) {
02633 int q;
02634
02635 quest = NULL;
02636 for (q = 0; q < map->quests.count; q++) {
02637 quest_vals[0] = map->quests.list[q]->quest->name;
02638 relative_path(map->path, "/quests.html", questtemp);
02639 snprintf(questpath, sizeof(questpath), "%s#quest_%d", questtemp, map->quests.list[q]->quest->number);
02640 quest_vals[2] = map->quests.list[q]->description;
02641 quest = cat_template(quest, do_template(map_one_quest_template, quest_vars, quest_vals));
02642 }
02643
02644 q_vals[0] = quest;
02645 quests = do_template(map_with_quests_template, q_vars, q_vals);
02646 free(quest);
02647 quest = NULL;
02648 } else
02649 quests = strdup(map_no_quest_template);
02650 values[14] = quests;
02651
02652 if (map->monsters.count) {
02653 int m;
02654
02655 qsort(map->monsters.races, map->monsters.count, sizeof(struct_race *), sort_race);
02656
02657 monsters = do_template(map_monster_before_template, vars, values);
02658 for (m = 0; m < map->monsters.count; m++) {
02659 m_vals[0] = map->monsters.races[m]->name;
02660 monsters = cat_template(monsters, do_template(map_monster_one_template, m_vars, m_vals));
02661 if (m != map->monsters.count-1)
02662 monsters = cat_template(monsters, do_template(map_monster_between_template, vars, values));
02663 }
02664 monsters = cat_template(monsters, do_template(map_monster_after_template, vars, values));
02665 } else
02666 monsters = do_template(map_no_monster_template, vars, values);
02667 values[15] = monsters;
02668
02669 vars[vars_count] = NULL;
02670 out = fopen(htmlpath, "w+");
02671 tmp = do_template(map_template, vars, values);
02672 fprintf(out, tmp);
02673 fclose(out);
02674 free(tmp);
02675 free(exits_text);
02676 free(exits_to);
02677 free(maplore);
02678 free(quests);
02679 free(monsters);
02680 }
02681
02683 static void fix_map_names(void) {
02684 int map;
02685
02686 for (map = 0; map < maps_list.count; map++) {
02687 if (maps_list.maps[map]->name)
02688 continue;
02689 if (!maps_list.maps[map]->filename) {
02690 printf("map without path!\n");
02691 abort();
02692 }
02693 maps_list.maps[map]->name = strdup(maps_list.maps[map]->filename);
02694 }
02695 }
02696
02703 static void fix_tiled_map(void) {
02704 int map, tile;
02705 char name[500];
02706 char *slash, *test;
02707 region *cfregion;
02708
02709 for (map = 0; map < tiled_map_list.count; map++) {
02710 if (tiled_map_list.maps[map]->tiled_maps.count == 0) {
02711 printf("empty tiled map group!");
02712 abort();
02713 }
02714
02715 snprintf(name, sizeof(name), "tiled_map_group_%d", map);
02716 tiled_map_list.maps[map]->filename = strdup(name);
02717
02718 cfregion = NULL;
02719 test = NULL;
02720
02721 for (tile = 0; tile < tiled_map_list.maps[map]->tiled_maps.count; tile++) {
02722 if (tiled_map_list.maps[map]->tiled_maps.maps[tile]->cfregion == NULL)
02723
02724 continue;
02725
02726 if (!cfregion)
02727 cfregion = tiled_map_list.maps[map]->tiled_maps.maps[tile]->cfregion;
02728 else if (cfregion != tiled_map_list.maps[map]->tiled_maps.maps[tile]->cfregion) {
02729 printf("*** warning: tiled maps %s and %s not in same region (%s and %s).\n",
02730 tiled_map_list.maps[map]->tiled_maps.maps[0]->path, tiled_map_list.maps[map]->tiled_maps.maps[tile]->path,
02731 tiled_map_list.maps[map]->tiled_maps.maps[0]->cfregion->name, tiled_map_list.maps[map]->tiled_maps.maps[tile]->cfregion->name);
02732 cfregion = NULL;
02733 }
02734
02735 if (strcmp(tiled_map_list.maps[map]->tiled_maps.maps[tile]->name, tiled_map_list.maps[map]->tiled_maps.maps[tile]->filename)) {
02736
02737 if (!test)
02738 test = tiled_map_list.maps[map]->tiled_maps.maps[tile]->name;
02739 }
02740 }
02741
02742 if (!test) {
02743
02744 printf("*** warning: tiled map without any name. First map path %s\n", tiled_map_list.maps[map]->tiled_maps.maps[0]->path);
02745 test = name;
02746 }
02747
02748 tiled_map_list.maps[map]->name = strdup(test);
02749 tiled_map_list.maps[map]->cfregion = cfregion;
02750
02751 strncpy(name, tiled_map_list.maps[map]->tiled_maps.maps[0]->path, sizeof(name));
02752 slash = strrchr(name, '/');
02753 if (!slash)
02754 snprintf(name, sizeof(name), "/");
02755 else
02756 *(slash+1) = '\0';
02757 strncat(name, tiled_map_list.maps[map]->filename, sizeof(name));
02758 tiled_map_list.maps[map]->path = strdup(name);
02759 }
02760 }
02761
02772 static void fix_exits_for_map(struct_map_info *current, struct_map_list *from, int is_from) {
02773 int map, max;
02774 struct_map_info *group;
02775
02776 max = from->count-1;
02777 for (map = max; map >= 0; map--) {
02778 if (from->maps[map]->tiled_group) {
02779 group = from->maps[map]->tiled_group;
02780 if (map != max)
02781 from->maps[map] = from->maps[max];
02782 from->count--;
02783 max--;
02784 add_map(group, from);
02785 add_map(current->tiled_group ? current->tiled_group : current, is_from ? &group->exits_to : &group->exits_from);
02786 }
02787 }
02788 }
02789
02791 static void fix_exits_to_tiled_maps(void) {
02792 int map, region, max;
02793 struct_map_info *group;
02794
02795 for (map = 0; map < maps_list.count; map++) {
02796 fix_exits_for_map(maps_list.maps[map], &maps_list.maps[map]->exits_from, 1);
02797 fix_exits_for_map(maps_list.maps[map], &maps_list.maps[map]->exits_to, 0);
02798 }
02799
02800 for (region = 0; region < region_count; region++) {
02801 max = regions[region]->maps_list.count-1;
02802 for (map = max; map >= 0; map--) {
02803 if (regions[region]->maps_list.maps[map]->tiled_group) {
02804 group = regions[region]->maps_list.maps[map]->tiled_group;
02805 if (map != max)
02806 regions[region]->maps_list.maps[map] = regions[region]->maps_list.maps[max];
02807 regions[region]->maps_list.count--;
02808 max--;
02809 add_map(group, ®ions[region]->maps_list);
02810 }
02811 }
02812 }
02813 }
02814
02819 static void fix_tiled_map_monsters(void) {
02820 int map, race, max;
02821 struct_map_info *group;
02822
02823 for (race = 0; race < races.count; race++) {
02824 max = races.races[race]->origin.count-1;
02825 for (map = max; map >= 0; map--) {
02826 if (races.races[race]->origin.maps[map]->tiled_group) {
02827 group = races.races[race]->origin.maps[map]->tiled_group;
02828 if (map != max)
02829 races.races[race]->origin.maps[map] = races.races[race]->origin.maps[max];
02830 races.races[race]->origin.count--;
02831 max--;
02832 add_map(group, &races.races[race]->origin);
02833 }
02834 }
02835 }
02836
02837 for (map = 0; map < maps_list.count; map++) {
02838 if (maps_list.maps[map]->tiled_group) {
02839 for (race = 0; race < maps_list.maps[map]->monsters.count; race++) {
02840 add_race_to_list(maps_list.maps[map]->monsters.races[race], &maps_list.maps[map]->tiled_group->monsters, 1);
02841 }
02842 }
02843 }
02844 }
02845
02847 static void write_all_maps(void) {
02848 int map;
02849
02850 printf("Writing map pages...");
02851
02852 for (map = 0; map < maps_list.count; map++)
02853 if (!maps_list.maps[map]->tiled_group)
02854 write_map_page(maps_list.maps[map]);
02855
02856 printf(" done.\n");
02857 }
02858
02859 static int tiled_map_need_pic(struct_map_info *map) {
02860 int test;
02861 char picpath[500];
02862 struct stat stats;
02863
02864 snprintf(picpath, sizeof(picpath), "%s%s%s", root, map->path, output_extensions[output_format]);
02865 if (stat(picpath, &stats))
02866 return 1;
02867
02868 snprintf(picpath, sizeof(picpath), "%s%s.small%s", root, map->path, output_extensions[output_format]);
02869 if (stat(picpath, &stats))
02870 return 1;
02871
02872 for (test = 0; test < map->tiled_maps.count; test++) {
02873 if (map->tiled_maps.maps[test]->pic_was_done)
02874 return 1;
02875 }
02876
02877 return 0;
02878 }
02879
02891 static void do_tiled_map_picture(struct_map_info *map) {
02892 int xmin = 0, xmax = 0, ymin = 0, ymax = 0, tiled, count, last;
02893 char picpath[500];
02894 gdImagePtr small, large, load;
02895 FILE *out;
02896 struct_map_info *current;
02897
02898 if (!generate_pics)
02899 return;
02900
02901 printf(" Generating composite map for %s...", map->name);
02902 fflush(stdout);
02903
02904 if (!tiled_map_need_pic(map)) {
02905 printf(" already uptodate.\n");
02906 return;
02907 }
02908
02909 count = map->tiled_maps.count;
02910 if (count == 0) {
02911 printf("Tiled map without tiled maps?\n");
02912 abort();
02913 }
02914 map->tiled_maps.maps[0]->processed = 1;
02915 map->tiled_maps.maps[0]->tiled_x_from = 0;
02916 map->tiled_maps.maps[0]->tiled_y_from = 0;
02917
02918 while (count > 0) {
02919 last = count;
02920
02921 for (tiled = 0; tiled < map->tiled_maps.count; tiled++) {
02922 current = map->tiled_maps.maps[tiled];
02923 if (current->processed != 1)
02924 continue;
02925
02926 count--;
02927
02928 if ((current->tiles[0]) && (current->tiles[0]->processed == 0)) {
02929 current->tiles[0]->processed = 1;
02930 current->tiles[0]->tiled_x_from = current->tiled_x_from;
02931 current->tiles[0]->tiled_y_from = current->tiled_y_from-current->tiles[0]->height;
02932 }
02933 if ((current->tiles[1]) && (current->tiles[1]->processed == 0)) {
02934 current->tiles[1]->processed = 1;
02935 current->tiles[1]->tiled_x_from = current->tiled_x_from+current->width;
02936 current->tiles[1]->tiled_y_from = current->tiled_y_from;
02937 }
02938 if ((current->tiles[2]) && (current->tiles[2]->processed == 0)) {
02939 current->tiles[2]->processed = 1;
02940 current->tiles[2]->tiled_x_from = current->tiled_x_from;
02941 current->tiles[2]->tiled_y_from = current->tiled_y_from+current->height;
02942 }
02943 if ((current->tiles[3]) && (current->tiles[3]->processed == 0)) {
02944 current->tiles[3]->processed = 1;
02945 current->tiles[3]->tiled_x_from = current->tiled_x_from-current->tiles[3]->width;
02946 current->tiles[3]->tiled_y_from = current->tiled_y_from;
02947 }
02948 }
02949
02950 if (last == count) {
02951 printf("do_tiled_map_picture: didn't process any map in %s (%d left)??\n", map->path, last);
02952 abort();
02953 }
02954 }
02955
02956 for (tiled = 0; tiled < map->tiled_maps.count; tiled++) {
02957 if (map->tiled_maps.maps[tiled]->tiled_x_from < xmin)
02958 xmin = map->tiled_maps.maps[tiled]->tiled_x_from;
02959 if (map->tiled_maps.maps[tiled]->tiled_y_from < ymin)
02960 ymin = map->tiled_maps.maps[tiled]->tiled_y_from;
02961 if (map->tiled_maps.maps[tiled]->tiled_x_from+map->tiled_maps.maps[tiled]->width > xmax)
02962 xmax = map->tiled_maps.maps[tiled]->tiled_x_from+map->tiled_maps.maps[tiled]->width;
02963 if (map->tiled_maps.maps[tiled]->tiled_y_from+map->tiled_maps.maps[tiled]->height > ymax)
02964 ymax = map->tiled_maps.maps[tiled]->tiled_y_from+map->tiled_maps.maps[tiled]->height;
02965 }
02966
02967 large = gdImageCreateTrueColor(32*(xmax-xmin), 32*(ymax-ymin));
02968 small = gdImageCreateTrueColor(size_small*(xmax-xmin), size_small*(ymax-ymin));
02969
02970 for (tiled = 0; tiled < map->tiled_maps.count; tiled++) {
02971 snprintf(picpath, sizeof(picpath), "%s%s%s", root, map->tiled_maps.maps[tiled]->path, output_extensions[output_format]);
02972
02973 out = fopen(picpath, "rb");
02974 if (!out) {
02975 printf("\n do_tiled_map_picture: warning: pic file not found for %s (errno=%d)\n", map->tiled_maps.maps[tiled]->path, errno);
02976 continue;
02977 }
02978 if (output_format == OF_PNG)
02979 load = gdImageCreateFromPng(out);
02980 else
02981 load = gdImageCreateFromJpeg(out);
02982 fclose(out);
02983 if (!load) {
02984 printf("\n do_tiled_map_picture: warning: pic not found for %s\n", map->tiled_maps.maps[tiled]->path);
02985 continue;
02986 }
02987 gdImageCopy(large, load, 32*(map->tiled_maps.maps[tiled]->tiled_x_from-xmin), 32*(map->tiled_maps.maps[tiled]->tiled_y_from-ymin), 0, 0, load->sx, load->sy);
02988 gdImageDestroy(load);
02989
02990 snprintf(picpath, sizeof(picpath), "%s%s.small%s", root, map->tiled_maps.maps[tiled]->path, output_extensions[output_format]);
02991 out = fopen(picpath, "rb");
02992 if (output_format == OF_PNG)
02993 load = gdImageCreateFromPng(out);
02994 else
02995 load = gdImageCreateFromJpeg(out);
02996 fclose(out);
02997 if (!load) {
02998 printf("\n do_tiled_map_picture: warning: small pic not found for %s\n", map->tiled_maps.maps[tiled]->path);
02999 continue;
03000 }
03001 gdImageCopy(small, load, size_small*(map->tiled_maps.maps[tiled]->tiled_x_from-xmin), size_small*(map->tiled_maps.maps[tiled]->tiled_y_from-ymin), 0, 0, load->sx, load->sy);
03002 gdImageDestroy(load);
03003 }
03004
03005 snprintf(picpath, sizeof(picpath), "%s%s%s", root, map->path, output_extensions[output_format]);
03006 out = fopen(picpath, "wb+");
03007 save_picture(out, large);
03008 fclose(out);
03009
03010 snprintf(picpath, sizeof(picpath), "%s%s.small%s", root, map->path, output_extensions[output_format]);
03011 out = fopen(picpath, "wb+");
03012 save_picture(out, small);
03013 fclose(out);
03014
03015 gdImageDestroy(small);
03016 gdImageDestroy(large);
03017
03018 printf(" done.\n");
03019 }
03020
03022 static void write_tiled_map_page(struct_map_info *map) {
03023
03024 do_tiled_map_picture(map);
03025
03028 write_map_page(map);
03029 }
03030
03032 static void write_tiled_maps(void) {
03033 int map;
03034
03035 printf("Writing tiled map information...\n");
03036
03037 for (map = 0; map < tiled_map_list.count; map++)
03038 write_tiled_map_page(tiled_map_list.maps[map]);
03039
03040 printf(" done.\n");
03041 }
03042
03044 static void write_maps_by_level(void) {
03045 int map;
03046 FILE *out;
03047 char name[500];
03048 char mappath[500];
03049 char *letters = NULL;
03050 char *maps = NULL;
03051 char *level = NULL;
03052 int lastlevel = -1;
03053 char strlevel[10];
03054 char strcount[10];
03055 const char *val_vars[] = { "LEVEL", "MAPS", NULL };
03056 const char *val_values[] = { strlevel, NULL, NULL };
03057 const char *map_vars[] = { "MAPNAME", "MAPPATH", NULL };
03058 const char *map_values[] = { NULL, mappath, NULL };
03059 const char *idx_vars[] = { "COUNT", "LEVELS", NULL };
03060 const char *idx_values[] = { strcount, NULL, NULL };
03061 int levelcount = 0;
03062 struct_map_info *last_tiled = NULL;
03063 struct_map_info *process;
03064
03065 printf("Writing map index by level...");
03066
03067 snprintf(name, sizeof(name), "%s/index_by_level.html", root);
03068
03069 qsort(maps_list.maps, maps_list.count, sizeof(struct_map_info *), sort_map_info_by_level);
03070
03071 for (map = 0; map < maps_list.count; map++) {
03072 process = maps_list.maps[map];
03073 if (maps_list.maps[map]->level != lastlevel) {
03074 if (maps) {
03075 snprintf(strlevel, sizeof(strlevel), "%d", lastlevel);
03076 val_values[1] = maps;
03077 letters = cat_template(letters, do_template(level_value_template, val_vars, val_values));
03078 free(maps);
03079 maps = NULL;
03080 }
03081 lastlevel = process->level;
03082 levelcount++;
03083 last_tiled = NULL;
03084 } else
03085 if (last_tiled && last_tiled == process->tiled_group)
03086
03087 continue;
03088
03089 if (process->tiled_group) {
03090 process = process->tiled_group;
03091 last_tiled = process;
03092 } else
03093 last_tiled = process->tiled_group;
03094
03095 map_values[0] = process->name;
03096 snprintf(mappath, sizeof(mappath), "%s.html", process->path+1);
03097 maps = cat_template(maps, do_template(level_map_template, map_vars, map_values));
03098 }
03099
03100 snprintf(strlevel, sizeof(strlevel), "%d", lastlevel);
03101 val_values[1] = maps;
03102 letters = cat_template(letters, do_template(level_value_template, val_vars, val_values));
03103 free(maps);
03104 maps = NULL;
03105
03106 snprintf(strcount, sizeof(strcount), "%d", levelcount);
03107 idx_values[1] = letters;
03108 level = do_template(level_template, idx_vars, idx_values);
03109 free(letters);
03110
03111 out = fopen(name, "w+");
03112 fprintf(out, level);
03113 fclose(out);
03114 free(level);
03115
03116 printf(" done.\n");
03117 }
03118
03122 static void write_equipment_index(void) {
03123 int item, map;
03124 FILE *out;
03125 char name[500];
03126
03127 printf("Generating special equipment list..");
03128 fflush(stdout);
03129
03130 qsort(special_equipment, equipment_count, sizeof(struct_equipment *), sort_equipment);
03131
03132 snprintf(name, sizeof(name), "%s/items.html", root);
03133 out = fopen(name, "w+");
03134
03135 fprintf(out, "<html><head><title>Item list</title></head></body><h1>Special items found in maps</h1>\n");
03136 fprintf(out, "<table border=\"1\"><tr><th>Name</th><th>Map(s)</th><th>Item power</th><th>Calc item power</th><th>Description</th></tr>\n");
03137
03138 for (item = 0; item < equipment_count; item++) {
03139 fprintf(out, "<tr><td>%s</td><td><ul>", special_equipment[item]->name);
03140
03141 for (map = 0; map < special_equipment[item]->origin.count; map++)
03142 fprintf(out, "<li>%s</li>\n", special_equipment[item]->origin.maps[map]->path);
03143
03144 fprintf(out, "</ul></td><td>%d</td><td>%d</td><td><pre>%s</pre></td></tr>\n", special_equipment[item]->power, special_equipment[item]->calc_power, special_equipment[item]->diff);
03145 }
03146 fprintf(out, "</body></html>\n");
03147 fclose(out);
03148
03149 printf(" done.\n");
03150 }
03151
03155 static void write_race_index(void) {
03156 int item, map;
03157 FILE *out;
03158 char name[500];
03159
03160 printf("Generating monster list...");
03161 fflush(stdout);
03162
03163 qsort(races.races, races.count, sizeof(struct_race *), sort_race);
03164
03165 snprintf(name, sizeof(name), "%s/monsters.html", root);
03166 out = fopen(name, "w+");
03167
03168 fprintf(out, "<html><head><title>Monster list</title></head></body><h1>Monsters found in maps</h1>\n");
03169 fprintf(out, "<table border=\"1\"><tr><th>Name</th><th>Count</th><th>Map(s)</th></tr>\n");
03170
03171 for (item = 0; item < races.count; item++) {
03172 fprintf(out, "<tr><td>%s</td><td>%d</td><td>Found on %d maps:<ul>", races.races[item]->name, races.races[item]->count, races.races[item]->origin.count);
03173
03174 qsort(races.races[item]->origin.maps, races.races[item]->origin.count, sizeof(struct_map_info *), sort_map_info);
03175
03176 for (map = 0; map < races.races[item]->origin.count; map++)
03177 fprintf(out, "<li>%s</li>\n", races.races[item]->origin.maps[map]->path);
03178
03179 fprintf(out, "</ul></td></tr>\n");
03180 }
03181 fprintf(out, "</body></html>\n");
03182 fclose(out);
03183
03184 printf(" done.\n");
03185 }
03186
03188 static const char *ignore_path[] = {
03189 "/Info",
03190 "/editor",
03191 "/python",
03192 "/styles",
03193 "/templates",
03194 "/test",
03195 "/unlinked",
03196 NULL };
03197
03199 static const char *ignore_name[] = {
03200 ".",
03201 "..",
03202 ".svn",
03203 "README",
03204 NULL };
03205
03212 static void find_maps(const char *from) {
03213 struct dirent *file;
03214 struct stat statbuf;
03215 int status, ignore;
03216 char path[1024], full[1024];
03217 DIR *dir;
03218
03219 for (ignore = 0; ignore_path[ignore] != NULL; ignore++) {
03220 if (strcmp(from, ignore_path[ignore]) == 0)
03221 return;
03222 }
03223
03224 snprintf(path, sizeof(path), "%s/%s%s", settings.datadir, settings.mapdir, from);
03225 dir = opendir(path);
03226
03227 if (dir) {
03228 for (file = readdir(dir); file; file = readdir(dir)) {
03229
03230 for (ignore = 0; ignore_name[ignore] != NULL; ignore++) {
03231 if (strcmp(file->d_name, ignore_name[ignore]) == 0)
03232 break;
03233 }
03234 if (ignore_name[ignore] != NULL)
03235 continue;
03236
03237 snprintf(full, sizeof(full), "%s/%s", path, file->d_name);
03238
03239 status = stat(full, &statbuf);
03240 if ((status != -1) && (S_ISDIR(statbuf.st_mode))) {
03241 snprintf(full, sizeof(full), "%s/%s", from, file->d_name);
03242 find_maps(full);
03243 continue;
03244 }
03245 if (found_maps_count == found_maps_allocated) {
03246 found_maps_allocated += 50;
03247 found_maps = realloc(found_maps, found_maps_allocated*sizeof(char *));
03248 }
03249 snprintf(full, sizeof(full), "%s/%s", from, file->d_name);
03250 found_maps[found_maps_count++] = strdup(full);
03251 }
03252 closedir(dir);
03253 }
03254 }
03255
03257 static void dump_unused_maps(void) {
03258 FILE *dump;
03259 char path[1024];
03260 int index, found = 0;
03261
03262 snprintf(path, sizeof(path), "%s/%s", root, "maps.unused");
03263 dump = fopen(path, "w+");
03264 if (dump == NULL) {
03265 printf("Unable to open file maps.unused!\n");
03266 return;
03267 }
03268 for (index = 0; index < found_maps_count; index++) {
03269 if (found_maps[index] != NULL) {
03270 fprintf(dump, "%s\n", found_maps[index]);
03271 free(found_maps[index]);
03272 found++;
03273 }
03274 }
03275 fclose(dump);
03276 printf("%d unused maps.\n", found);
03277 }
03278
03280 static void write_world_info(void) {
03281 FILE *file;
03282 char path[MAX_BUF];
03283 int x, y;
03284 gdImagePtr elevationmap;
03285
03286 if (!world_exit_info)
03287 return;
03288
03289 printf("Saving exit/blocking/road information...");
03290 snprintf(path, sizeof(path), "%s/%s%s", root, "world_info", output_extensions[output_format]);
03291 file = fopen(path, "wb+");
03292 save_picture(file, infomap);
03293 fclose(file);
03294 printf("done.\n");
03295 gdImageDestroy(infomap);
03296 infomap = NULL;
03297
03298 if (elevation_min == 0 || elevation_max == 0) {
03299 puts("Error: Could not save elevation world map due to not finding any minimum or maximum elevation.");
03300 return;
03301 }
03302
03303 elevationmap = gdImageCreateTrueColor(30*50, 30*50);;
03304
03305 for (x = 0; x < 30*50; x++) {
03306 for (y = 0; y < 30*50; y++) {
03307 gdImageSetPixel(elevationmap, x, y, get_elevation_color(elevation_info[x][y], elevationmap));
03308 }
03309 }
03310
03311 printf("Saving elevation world map...");
03312 snprintf(path, sizeof(path), "%s/%s%s", root, "world_elevation", output_extensions[output_format]);
03313 file = fopen(path, "wb+");
03314 save_picture(file, elevationmap);
03315 fclose(file);
03316 printf("done.\n");
03317 gdImageDestroy(elevationmap);
03318 elevationmap = NULL;
03319 }
03320
03322 static void write_regions_link(void) {
03323 FILE *file;
03324 char path[MAX_BUF];
03325 int link;
03326
03327 if (!do_regions_link)
03328 return;
03329
03330 printf("Writing regions link file...");
03331 snprintf(path, sizeof(path), "%s/%s", root, "region_links.dot");
03332 file = fopen(path, "wb+");
03333 fprintf(file, "digraph {\n");
03334 for (link = 0; link < regions_link_count; link++)
03335 fprintf(file, regions_link[link]);
03336 fprintf(file, "}\n");
03337 fclose(file);
03338 printf("done.\n");
03339 }
03340
03349 static void write_slaying_map_name(FILE *file, struct_map_info *map) {
03350 fprintf(file, "<a href=\"%s.html\">%s</a> (full map path: %s)", map->tiled_group ? map->tiled_group->path+1 : map->path+1, map->name, map->path);
03351 }
03352
03367 static void write_one_slaying_info(FILE *file, struct_slaying_info *info, int item, const char *with, const char *without) {
03368 int map;
03369
03370 if (info->maps[item].count == 0) {
03371 if (without)
03372 fprintf(file, without);
03373 return;
03374 }
03375
03376 qsort(info->maps[item].maps, info->maps[item].count, sizeof(const char *), sort_mapname);
03377
03378 fprintf(file, with);
03379 fprintf(file, "<ul>\n");
03380 for (map = 0; map < info->maps[item].count; map++) {
03381 fprintf(file, "\t<li>");
03382 write_slaying_map_name(file, info->maps[item].maps[map]);
03383 fprintf(file, "</li>\n");
03384 }
03385 fprintf(file, "</ul>\n");
03386 }
03387
03398 static int sort_slaying(const void *left, const void *right) {
03399 struct_slaying_info *l = *(struct_slaying_info **)left;
03400 struct_slaying_info *r = *(struct_slaying_info **)right;
03401
03402 return strcasecmp(l->slaying, r->slaying);
03403 }
03404
03408 static void write_slaying_info(void) {
03409 FILE *file;
03410 char path[MAX_BUF];
03411 int lock;
03412 struct_slaying_info *info;
03413
03414 printf("Writing slaying info file...");
03415
03416 qsort(slaying_info, slaying_count, sizeof(struct_slaying_info *), sort_slaying);
03417
03418 snprintf(path, sizeof(path), "%s/%s", root, "slaying_info.html");
03419 file = fopen(path, "wb+");
03420
03421 fprintf(file, "<html>\n<head>\n<title>Slaying information</title>\n</head>\n<body>\n");
03422 fprintf(file, "<p>This is a list of various slaying fields on keys, containers, doors, detectors.</p>");
03423
03424 for (lock = 0; lock < slaying_count; lock++) {
03425 info = slaying_info[lock];
03426 fprintf(file, "<h1>%s</h1>\n", info->slaying);
03427
03428 if (info->maps[S_DOOR].count == 0 && info->maps[S_CONTAINER].count == 0 && info->maps[S_CONNECT].count == 0) {
03429 fprintf(file, "No door, container or detector matching this slaying.<br />\n");
03430 } else {
03431 write_one_slaying_info(file, info, S_DOOR, "Connected doors:\n", NULL);
03432 write_one_slaying_info(file, info, S_CONTAINER, "Matching containers:\n", NULL);
03433 write_one_slaying_info(file, info, S_CONNECT, "Detectors and such:\n", NULL);
03434 }
03435 write_one_slaying_info(file, info, S_KEY, "Matching keys:\n", "No key with this slaying.<br />\n");
03436 }
03437
03438 fprintf(file, "</body>\n</html>\n");
03439
03440 fclose(file);
03441 printf("done.\n");
03442 }
03443
03447 static void write_npc_list(void) {
03448 FILE *file;
03449 char path[MAX_BUF];
03450 int map, npc;
03451
03452 printf("Writing NPC info file...");
03453
03454 qsort(slaying_info, slaying_count, sizeof(struct_slaying_info *), sort_slaying);
03455
03456 snprintf(path, sizeof(path), "%s/%s", root, "npc_info.html");
03457 file = fopen(path, "wb+");
03458
03459 fprintf(file, "<html>\n<head>\n<title>NPCs who have a special message</title>\n</head>\n<body>\n");
03460 fprintf(file, "<p>This is a list of NPCs having a special message.</p>");
03461 fprintf(file, "<ul>\n");
03462
03463 for (map = 0; map < maps_list.count; map++) {
03464 if (maps_list.maps[map]->npcs.count == 0)
03465 continue;
03466 fprintf(file, "<li>%s</li>\n<ul>", maps_list.maps[map]->path);
03467 for (npc = 0; npc < maps_list.maps[map]->npcs.count; npc++) {
03468 fprintf(file, "<li>%s (%d,%d): <br /><pre>%s</pre></li>\n", maps_list.maps[map]->npcs.npc[npc]->name, maps_list.maps[map]->npcs.npc[npc]->x, maps_list.maps[map]->npcs.npc[npc]->y, maps_list.maps[map]->npcs.npc[npc]->message);
03469 }
03470 fprintf(file, "</ul>\n</li>\n");
03471 }
03472
03473 fprintf(file, "</ul>\n");
03474 fprintf(file, "</body>\n</html>\n");
03475
03476 fclose(file);
03477 printf("done.\n");
03478 }
03479
03486 static void do_help(const char *program) {
03487 printf("Crossfire Mapper will generate pictures of maps, and create indexes for all maps and regions.\n\n");
03488 printf("Syntax: %s\n\n", program);
03489 printf("Optional arguments:\n");
03490 printf(" -nopics don't generate pictures.\n");
03491 printf(" -noindex don't generate global map index.\n");
03492 printf(" -root=<path> destination path. Default 'html'.\n");
03493 printf(" -limit=<number> stop processing after this number of maps, -1 to do all maps (default).\n");
03494 printf(" -showmaps outputs the name of maps as they are processed.\n");
03495 printf(" -jpg[=quality] generate jpg pictures, instead of default png. Quality should be 0-95, -1 for automatic.\n");
03496 printf(" -forcepics force to regenerate pics, even if pics's date is after map's.\n");
03497 printf(" -addmap=<map> adds a map to process. Path is relative to map's directory root.\n");
03498 printf(" -rawmaps generates maps pics without items on random (shop, treasure) tiles.\n");
03499 printf(" -warnnopath inform when an exit has no path set.\n");
03500 printf(" -listunusedmaps finds all unused maps in the maps directory.\n");
03501 printf(" -noworldmap don't write the world map in world.png.\n");
03502 printf(" -noregionslink don't generate regions relation file.\n");
03503 printf(" -regionslink generate regions relation file.\n");
03504 printf(" -noexitmap don't generate map of exits.\n");
03505 printf(" -exitmap generate map of exits.\n");
03506 printf(" -tileset=<number> use specified tileset to generate the pictures. Default 0 (standard).\n");
03507 printf("\n\n");
03508 exit(0);
03509 }
03510
03519 static void do_parameters(int argc, char **argv) {
03520 int arg = 1;
03521 char path[500];
03522
03523 root[0] = '\0';
03524
03525 while (arg < argc) {
03526 if (strcmp(argv[arg], "-nopics") == 0)
03527 generate_pics = 0;
03528 else if (strcmp(argv[arg], "-noindex") == 0)
03529 generate_index = 0;
03530 else if (strncmp(argv[arg], "-root=", 6) == 0)
03531 strncpy(root, argv[arg]+6, 500);
03532 else if (strncmp(argv[arg], "-limit=", 7) == 0)
03533 map_limit = atoi(argv[arg]+7);
03534 else if (strcmp(argv[arg], "-showmaps") == 0)
03535 show_maps = 1;
03536 else if (strcmp(argv[arg], "-jpg") == 0) {
03537 output_format = OF_JPG;
03538 if (argv[arg][4] == '=') {
03539 jpeg_quality = atoi(argv[arg]+5);
03540 if (jpeg_quality < 0)
03541 jpeg_quality = -1;
03542 }
03543 }
03544 else if (strcmp(argv[arg], "-forcepics") == 0)
03545 force_pics = 1;
03546 else if (strncmp(argv[arg], "-addmap=", 8) == 0) {
03547 if (*(argv[arg]+8) == '/')
03548 strncpy(path, argv[arg]+8, 500);
03549 else
03550 snprintf(path, 500, "/%s", argv[arg]+8);
03551 add_map(get_map_info(path), &maps_list);
03552 }
03553 else if (strcmp(argv[arg], "-rawmaps") == 0)
03554 rawmaps = 1;
03555 else if (strcmp(argv[arg], "-warnnopath") == 0)
03556 warn_no_path = 1;
03557 else if (strcmp(argv[arg], "-listunusedmaps") == 0)
03558 list_unused_maps = 1;
03559 else if (strcmp(argv[arg], "-noworldmap") == 0)
03560 world_map = 0;
03561 else if (strcmp(argv[arg], "-noregionslink") == 0)
03562 do_regions_link = 0;
03563 else if (strcmp(argv[arg], "-regionslink") == 0)
03564 do_regions_link = 1;
03565 else if (strcmp(argv[arg], "-noexitmap") == 0)
03566 world_exit_info = 0;
03567 else if (strcmp(argv[arg], "-exitmap") == 0)
03568 world_exit_info = 1;
03569 else if (strncmp(argv[arg], "-tileset=", 9) == 0) {
03570 tileset = atoi(argv[arg]+9);
03571
03572 } else
03573 do_help(argv[0]);
03574 arg++;
03575 }
03576 if (!strlen(root))
03577 strcpy(root, "html");
03578 if (root[strlen(root)-1] == '/')
03579 root[strlen(root)-1] = '\0';
03580 if (map_limit < -1)
03581 map_limit = -1;
03582 }
03583
03587 static void create_destination(void) {
03588 char dummy[502];
03589
03590 strcpy(dummy, root);
03591 strcat(dummy, "/a");
03592 make_path_to_file(dummy);
03593 }
03594
03603 static const char *yesno(int value) {
03604 return (value ? "yes" : "no");
03605 }
03606
03607 int main(int argc, char **argv) {
03608 int current_map = 0, i;
03609 char max[50];
03610 region *dummy;
03611
03612 init_map_list(&maps_list);
03613 init_map_list(&tiled_map_list);
03614 init_race_list(&races);
03615 pics_allocated = 0;
03616
03617 do_parameters(argc, argv);
03618
03619 printf("Initializing Crossfire data...\n");
03620
03621 settings.debug = 0;
03622
03623 init_globals();
03624 init_library();
03625 init_archetypes();
03626 init_artifacts();
03627 init_formulae();
03628 init_readable();
03629 init_regions();
03630
03631 init_gods();
03632 read_client_images();
03633
03634
03635 dummy = get_region_struct();
03636 dummy->fallback = 1;
03637 dummy->name = add_string("unlinked");
03638 dummy->longname = add_string("This dummy region contains all maps without a region set.");
03639 dummy->longname = add_string("This dummy region contains all maps without a region set.");
03640 dummy->next = first_region;
03641 first_region = dummy;
03642
03643 printf("\n\n done.\n\n");
03644
03645 if (!is_valid_faceset(tileset)) {
03646 printf("Erreor: invalid tileset %d!\n", tileset);
03647 exit(1);
03648 }
03649
03650 create_destination();
03651 gdfaces = calloc(1, sizeof(gdImagePtr)*nrofpixmaps);
03652
03653 read_template("templates/map.template", &map_template);
03654 read_template("templates/map_no_exit.template", &map_no_exit_template);
03655 read_template("templates/map_with_exit.template", &map_with_exit_template);
03656 read_template("templates/map_exit.template", &map_exit_template);
03657 read_template("templates/map_no_exit_to.template", &map_no_exit_to_template);
03658 read_template("templates/map_with_exit_to.template", &map_with_exit_to_template);
03659 read_template("templates/map_exit_to.template", &map_exit_to_template);
03660 read_template("templates/map_lore.template", &map_lore_template);
03661 read_template("templates/map_no_lore.template", &map_no_lore_template);
03662 read_template("templates/map_no_monster.template", &map_no_monster_template);
03663 read_template("templates/map_monster_before.template", &map_monster_before_template);
03664 read_template("templates/map_monster_between.template", &map_monster_between_template);
03665 read_template("templates/map_monster_one.template", &map_monster_one_template);
03666 read_template("templates/map_monster_after.template", &map_monster_after_template);
03667
03668 read_template("templates/index.template", &index_template);
03669 read_template("templates/index_letter.template", &index_letter);
03670 read_template("templates/index_map.template", &index_map);
03671
03672 read_template("templates/region.template", ®ion_template);
03673 read_template("templates/region_letter.template", ®ion_letter_template);
03674 read_template("templates/region_map.template", ®ion_map_template);
03675
03676 read_template("templates/index_region.template", &index_region_template);
03677 read_template("templates/index_region_region.template", &index_region_region_template);
03678
03679 read_template("templates/world.template", &world_template);
03680 read_template("templates/world_row.template", &world_row_template);
03681 read_template("templates/world_map.template", &world_map_template);
03682
03683 read_template("templates/level.template", &level_template);
03684 read_template("templates/level_value.template", &level_value_template);
03685 read_template("templates/level_map.template", &level_map_template);
03686
03687 read_template("templates/quests.template", &index_quest_template);
03688 read_template("templates/quests_quest.template", &quest_template);
03689 read_template("templates/quests_map.template", &quest_map_template);
03690
03691 read_template("templates/map_with_quests.template", &map_with_quests_template);
03692 read_template("templates/map_one_quest.template", &map_one_quest_template);
03693 read_template("templates/map_no_quest.template", &map_no_quest_template);
03694
03695 if (map_limit != -1)
03696 snprintf(max, sizeof(max), "%d", map_limit);
03697 else
03698 strcpy(max, "(none)");
03699 printf("Crossfire map browser generator\n");
03700 printf("-------------------------------\n\n");
03701 printf("Parameters:\n");
03702 printf(" path to write files: %s\n", root);
03703 printf(" maximum number of maps to process: %s\n", max);
03704 printf(" will generate map picture: %s\n", yesno(generate_pics));
03705 printf(" will always generate map picture: %s\n", yesno(force_pics));
03706 printf(" picture output format: %s\n", output_extensions[output_format]);
03707 if (output_format == OF_JPG)
03708 printf(" JPEG quality: %d\n", jpeg_quality);
03709 printf(" will generate map index: %s\n", yesno(generate_index));
03710 printf(" show map being processed: %s\n", yesno(show_maps));
03711 printf(" generate raw maps: %s\n", yesno(rawmaps));
03712 printf(" warn of exit without path: %s\n", yesno(warn_no_path));
03713 printf(" list unused maps: %s\n", yesno(list_unused_maps));
03714 printf(" generate world map: %s\n", yesno(world_map));
03715 printf(" generate exit map: %s\n", yesno(world_exit_info));
03716 printf(" generate regions link file: %s\n", yesno(do_regions_link));
03717 printf(" tileset: %s\n", facesets[tileset].fullname);
03718 printf("\n");
03719
03720 if (list_unused_maps) {
03721 printf("listing all maps...");
03722 find_maps("");
03723 printf("done, %d maps found.\n", found_maps_count);
03724 qsort(found_maps, found_maps_count, sizeof(char *), sortbyname);
03725 }
03726
03727
03728 infomap = gdImageCreateTrueColor(30*50, 30*50);
03729 color_unlinked_exit = gdImageColorResolve(infomap, 255, 0, 0);
03730 color_linked_exit = gdImageColorResolve(infomap, 255, 255, 255);
03731 color_road = gdImageColorResolve(infomap, 0, 255, 0);
03732 color_blocking = gdImageColorResolve(infomap, 0, 0, 255);
03733 color_slowing = gdImageColorResolve(infomap, 0, 0, 127);
03734 elevation_info = calloc(50*30, sizeof(int *));
03735 for (i = 0; i < 50*30; i++)
03736 elevation_info[i] = calloc(50*30, sizeof(int));
03737 elevation_min = 0;
03738 elevation_max = 0;
03739
03740 printf("browsing maps...\n");
03741
03742 get_map_info(first_map_path);
03743
03744 while (current_map < maps_list.count) {
03745 process_map(maps_list.maps[current_map++]);
03746 if (current_map%100 == 0) {
03747 printf(" %d maps processed, %d map pictures created, %d map pictures were uptodate. %d faces used.\n", current_map, created_pics, cached_pics, pics_allocated);
03748 }
03749 if ((map_limit != -1) && (current_map == map_limit)) {
03750 printf(" --- map limit reached, stopping ---\n");
03751 break;
03752 }
03753 }
03754
03755 printf(" finished map parsing, %d maps processed, %d map pictures created, %d map pictures were uptodate. Total %d faces used.\n", current_map, created_pics, cached_pics, pics_allocated);
03756
03757 if (list_unused_maps)
03758 dump_unused_maps();
03759
03760 fix_exits_to_tiled_maps();
03761 fix_map_names();
03762 fix_tiled_map();
03763 fix_tiled_map_monsters();
03764
03765 write_all_maps();
03766 write_maps_index();
03767 write_maps_by_level();
03768 write_tiled_maps();
03769
03770 write_all_regions();
03771 write_region_index();
03772
03773 write_world_map();
03774 write_world_info();
03775
03776 write_regions_link();
03777 write_slaying_info();
03778
03779 write_quests_page();
03780
03781 write_equipment_index();
03782 write_race_index();
03783 write_npc_list();
03784
03785 return 0;
03786 }
03787
03788 void do_auto_apply(mapstruct *m) {
03789 object *tmp, *above = NULL;
03790 int x, y;
03791
03792 if (m == NULL)
03793 return;
03794
03795 for (x = 0; x < MAP_WIDTH(m); x++)
03796 for (y = 0; y < MAP_HEIGHT(m); y++)
03797 for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = above) {
03798 above = tmp->above;
03799
03800 if (tmp->inv) {
03801 object *invtmp, *invnext;
03802
03803 for (invtmp = tmp->inv; invtmp != NULL; invtmp = invnext) {
03804 invnext = invtmp->below;
03805
03806 if (QUERY_FLAG(invtmp, FLAG_AUTO_APPLY))
03807 auto_apply(invtmp);
03808 else if (invtmp->type == TREASURE && HAS_RANDOM_ITEMS(invtmp)) {
03809 while ((invtmp->stats.hp--) > 0)
03810 create_treasure(invtmp->randomitems, invtmp, 0, m->difficulty, 0);
03811 invtmp->randomitems = NULL;
03812 } else if (invtmp
03813 && invtmp->arch
03814 && invtmp->type != TREASURE
03815 && invtmp->type != SPELL
03816 && invtmp->type != CLASS
03817 && HAS_RANDOM_ITEMS(invtmp)) {
03818 create_treasure(invtmp->randomitems, invtmp, 0, m->difficulty, 0);
03819
03820
03821
03822 invtmp->randomitems = NULL;
03823 }
03824 }
03825
03826
03827
03828
03829
03830
03831
03832
03833
03834
03835 if (tmp->type == WAND
03836 || tmp->type == ROD
03837 || tmp->type == SCROLL
03838 || tmp->type == HORN
03839 || tmp->type == FIREWALL
03840 || tmp->type == POTION
03841 || tmp->type == ALTAR
03842 || tmp->type == SPELLBOOK)
03843 tmp->randomitems = NULL;
03844 }
03845
03846 if (QUERY_FLAG(tmp, FLAG_AUTO_APPLY))
03847 auto_apply(tmp);
03848 else if ((tmp->type == TREASURE || (tmp->type == CONTAINER)) && HAS_RANDOM_ITEMS(tmp)) {
03849 while ((tmp->stats.hp--) > 0)
03850 create_treasure(tmp->randomitems, tmp, 0, m->difficulty, 0);
03851 tmp->randomitems = NULL;
03852 } else if (tmp->type == TIMED_GATE) {
03853 object *head = tmp->head != NULL ? tmp->head : tmp;
03854
03855 if (QUERY_FLAG(head, FLAG_IS_LINKED)) {
03856 tmp->speed = 0;
03857 update_ob_speed(tmp);
03858 }
03859
03860
03861
03862
03863
03864
03865
03866 } else if (tmp
03867 && tmp->arch
03868 && tmp->type != PLAYER
03869 && tmp->type != TREASURE
03870 && tmp->type != SPELL
03871 && tmp->type != PLAYER_CHANGER
03872 && tmp->type != CLASS
03873 && HAS_RANDOM_ITEMS(tmp)) {
03874 create_treasure(tmp->randomitems, tmp, GT_APPLY, m->difficulty, 0);
03875 tmp->randomitems = NULL;
03876 }
03877 }
03878
03879 for (x = 0; x < MAP_WIDTH(m); x++)
03880 for (y = 0; y < MAP_HEIGHT(m); y++)
03881 for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above)
03882 if (tmp->above
03883 && (tmp->type == TRIGGER_BUTTON || tmp->type == TRIGGER_PEDESTAL))
03884 check_trigger(tmp, tmp->above);
03885 }
03886
03887 #ifndef DOXYGEN_SHOULD_SKIP_THIS
03888
03893 void draw_ext_info(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *txt, const char *txt2) {
03894 fprintf(logfile, "%s\n", txt);
03895 }
03896
03897 void draw_ext_info_format(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *new_format, const char *old_format, ...) {
03898 va_list ap;
03899
03900 va_start(ap, old_format);
03901 vfprintf(logfile, old_format, ap);
03902 va_end(ap);
03903 }
03904
03905 void ext_info_map(int color, const mapstruct *map, uint8 type, uint8 subtype, const char *str1, const char *str2) {
03906 fprintf(logfile, "ext_info_map: %s\n", str2);
03907 }
03908
03909 void move_firewall(object *ob) {
03910 }
03911
03912 void emergency_save(int x) {
03913 }
03914
03915 void clean_tmp_files(void) {
03916 }
03917
03918 void esrv_send_item(object *ob, object *obx) {
03919 }
03920
03921 void dragon_ability_gain(object *ob, int x, int y) {
03922 }
03923
03924 void set_darkness_map(mapstruct *m) {
03925 }
03926
03927 object *find_skill_by_number(object *who, int skillno) {
03928 return NULL;
03929 }
03930
03931 void esrv_del_item(player *pl, int tag) {
03932 }
03933
03934 void esrv_update_item(int flags, object *pl, object *op) {
03935 }
03936
03937 void esrv_update_spells(player *pl) {
03938 }
03939
03940 void monster_check_apply(object *ob, object *obt) {
03941 }
03942
03943 void trap_adjust(object *ob, int x) {
03944 }
03945
03946 int execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix) {
03947 return 0;
03948 }
03949
03950 int execute_global_event(int eventcode, ...) {
03951 return 0;
03952 }
03953
03954 int auto_apply(object *op) {
03955 object *tmp = NULL, *tmp2;
03956 int i;
03957
03958 switch (op->type) {
03959 case SHOP_FLOOR:
03960 if (!HAS_RANDOM_ITEMS(op))
03961 return 0;
03962 do {
03963 i = 10;
03964 while ((tmp = generate_treasure(op->randomitems, op->stats.exp ? (int)op->stats.exp : MAX(op->map->difficulty, 5))) == NULL && --i)
03965 ;
03966 if (tmp == NULL)
03967 return 0;
03968 if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) {
03969 free_object(tmp);
03970 tmp = NULL;
03971 }
03972 } while (!tmp);
03973 tmp->x = op->x;
03974 tmp->y = op->y;
03975 SET_FLAG(tmp, FLAG_UNPAID);
03976 insert_ob_in_map(tmp, op->map, NULL, 0);
03977 CLEAR_FLAG(op, FLAG_AUTO_APPLY);
03978 identify(tmp);
03979 break;
03980
03981 case TREASURE:
03982 if (QUERY_FLAG(op, FLAG_IS_A_TEMPLATE))
03983 return 0;
03984
03985 while ((op->stats.hp--) > 0)
03986 create_treasure(op->randomitems, op, op->map ? GT_ENVIRONMENT : 0, op->stats.exp ? (int)op->stats.exp : op->map == NULL ? 14 : op->map->difficulty, 0);
03987
03988
03989
03990
03991
03992
03993 for (tmp = op->inv; tmp; tmp = tmp2) {
03994 tmp2 = tmp->below;
03995 remove_ob(tmp);
03996 if (op->env)
03997 insert_ob_in_ob(tmp, op->env);
03998 else
03999 free_object(tmp);
04000 }
04001 remove_ob(op);
04002 free_object(op);
04003 break;
04004 }
04005 return tmp ? 1 : 0;
04006 }
04007
04008 void fix_auto_apply(mapstruct *m) {
04009 }
04010
04011 #endif