00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00034 #include <stdio.h>
00035 #include <global.h>
00036 #include <sproto.h>
00037
00038 #include <loader.h>
00039 #ifndef WIN32
00040 #include <unistd.h>
00041 #endif
00042
00043 #include "path.h"
00044
00045 extern int nrofallocobjects, nroffreeobjects;
00046
00047 static void free_all_objects(mapstruct *m);
00048
00054 const char *map_layer_name[MAP_LAYERS] = {
00055 "floor", "no_pick", "no_pick", "item", "item",
00056 "item", "living", "living", "fly", "fly"
00057 };
00058
00060 typedef struct Map_Layer_Info {
00061 uint8 high_layer;
00062 uint8 honor_visibility;
00063 } Map_Layer_Info;
00064
00071 static Map_Layer_Info map_layer_info[MAP_LAYERS] = {
00072 { MAP_LAYER_FLOOR, 1 },
00073 { MAP_LAYER_NO_PICK2, 0 }, { MAP_LAYER_NO_PICK2, 0 },
00074 { MAP_LAYER_ITEM3, 1 }, { MAP_LAYER_ITEM3, 1 }, { MAP_LAYER_ITEM3, 1 },
00075 { MAP_LAYER_LIVING2, 1 }, { MAP_LAYER_LIVING2, 1 },
00076 { MAP_LAYER_FLY2, 1 }, { MAP_LAYER_FLY2, 1 }
00077 };
00078
00087 mapstruct *has_been_loaded(const char *name) {
00088 mapstruct *map;
00089
00090 if (!name || !*name)
00091 return NULL;
00092
00093 for (map = first_map; map; map = map->next)
00094 if (!strcmp(name, map->path))
00095 break;
00096 return (map);
00097 }
00098
00114 char *create_pathname(const char *name, char *buf, size_t size) {
00115
00116
00117
00118 if (*name == '/')
00119 snprintf(buf, size, "%s/%s%s", settings.datadir, settings.mapdir, name);
00120 else
00121 snprintf(buf, size, "%s/%s/%s", settings.datadir, settings.mapdir, name);
00122 return buf;
00123 }
00124
00135 void create_overlay_pathname(const char *name, char *buf, size_t size) {
00136
00137
00138
00139 if (*name == '/')
00140 snprintf(buf, size, "%s/%s%s", settings.localdir, settings.mapdir, name);
00141 else
00142 snprintf(buf, size, "%s/%s/%s", settings.localdir, settings.mapdir, name);
00143 }
00144
00155 void create_template_pathname(const char *name, char *buf, size_t size) {
00156
00157
00158
00159 if (*name == '/')
00160 snprintf(buf, size, "%s/%s%s", settings.localdir, settings.templatedir, name);
00161 else
00162 snprintf(buf, size, "%s/%s/%s", settings.localdir, settings.templatedir, name);
00163 }
00164
00178 static void create_items_path(const char *s, char *buf, size_t size) {
00179 char *t;
00180
00181 if (*s == '/')
00182 s++;
00183
00184 snprintf(buf, size, "%s/%s/", settings.localdir, settings.uniquedir);
00185 t = buf+strlen(buf);
00186 snprintf(t, buf+size-t, "%s", s);
00187
00188 while (*t != '\0') {
00189 if (*t == '/')
00190 *t = '@';
00191 t++;
00192 }
00193 }
00194
00216 int check_path(const char *name, int prepend_dir) {
00217 char buf[MAX_BUF];
00218 #ifndef WIN32
00219 char *endbuf;
00220 struct stat statbuf;
00221 int mode = 0, i;
00222 #endif
00223
00224 if (prepend_dir)
00225 create_pathname(name, buf, MAX_BUF);
00226 else
00227 snprintf(buf, sizeof(buf), "%s", name);
00228 #ifdef WIN32
00229 return(_access(buf, 0));
00230 #else
00231
00232
00233
00234
00235
00236
00237 endbuf = buf+strlen(buf);
00238
00239 for (i = 0; i < NROF_COMPRESS_METHODS; i++) {
00240 if (uncomp[i][0])
00241 snprintf(endbuf, buf+sizeof(buf)-endbuf, "%s", uncomp[i][0]);
00242 else
00243 *endbuf = '\0';
00244 if (!stat(buf, &statbuf))
00245 break;
00246 }
00247 if (i == NROF_COMPRESS_METHODS)
00248 return (-1);
00249 if (!S_ISREG(statbuf.st_mode))
00250 return (-1);
00251
00252 if (((statbuf.st_mode&S_IRGRP) && getegid() == statbuf.st_gid)
00253 || ((statbuf.st_mode&S_IRUSR) && geteuid() == statbuf.st_uid)
00254 || (statbuf.st_mode&S_IROTH))
00255 mode |= 4;
00256
00257 if ((statbuf.st_mode&S_IWGRP && getegid() == statbuf.st_gid)
00258 || (statbuf.st_mode&S_IWUSR && geteuid() == statbuf.st_uid)
00259 || (statbuf.st_mode&S_IWOTH))
00260 mode |= 2;
00261
00262 return (mode);
00263 #endif
00264 }
00265
00275 void dump_map(const mapstruct *m) {
00276 LOG(llevError, "Map %s status: %d.\n", m->path, m->in_memory);
00277 LOG(llevError, "Size: %dx%d Start: %d,%d\n", MAP_WIDTH(m), MAP_HEIGHT(m), MAP_ENTER_X(m), MAP_ENTER_Y(m));
00278
00279 if (m->msg != NULL)
00280 LOG(llevError, "Message:\n%s", m->msg);
00281
00282 if (m->maplore != NULL)
00283 LOG(llevError, "Lore:\n%s", m->maplore);
00284
00285 if (m->tmpname != NULL)
00286 LOG(llevError, "Tmpname: %s\n", m->tmpname);
00287
00288 LOG(llevError, "Difficulty: %d\n", m->difficulty);
00289 LOG(llevError, "Darkness: %d\n", m->darkness);
00290 }
00291
00298 void dump_all_maps(void) {
00299 mapstruct *m;
00300
00301 for (m = first_map; m != NULL; m = m->next) {
00302 dump_map(m);
00303 }
00304 }
00305
00330 int get_map_flags(mapstruct *oldmap, mapstruct **newmap, sint16 x, sint16 y, sint16 *nx, sint16 *ny) {
00331 sint16 newx, newy;
00332 int retval = 0;
00333 mapstruct *mp;
00334
00335 if (out_of_map(oldmap, x, y))
00336 return P_OUT_OF_MAP;
00337 newx = x;
00338 newy = y;
00339 mp = get_map_from_coord(oldmap, &newx, &newy);
00340 if (mp != oldmap)
00341 retval |= P_NEW_MAP;
00342 if (newmap)
00343 *newmap = mp;
00344 if (nx)
00345 *nx = newx;
00346 if (ny)
00347 *ny = newy;
00348 retval |= mp->spaces[newx+mp->width*newy].flags;
00349 return retval;
00350 }
00351
00373 int blocked_link(object *ob, mapstruct *m, int sx, int sy) {
00374 object *tmp, *tmp_head;
00375 int mflags, blocked;
00376
00377
00378
00379
00380 if (OUT_OF_REAL_MAP(m, sx, sy)) {
00381 LOG(llevError, "blocked_link: Passed map, x, y coordinates outside of map\n");
00382 return 1;
00383 }
00384
00385
00386 if (ob->type == TRANSPORT && ob->move_type == 0)
00387 return 0;
00388
00389
00390
00391
00392 mflags = m->spaces[sx+m->width*sy].flags;
00393
00394 blocked = GET_MAP_MOVE_BLOCK(m, sx, sy);
00395
00396
00397
00398
00399
00400 if (ob->type != PLAYER && !(mflags&P_IS_ALIVE) && (blocked == 0))
00401 return 0;
00402
00403
00404
00405
00406
00407
00408
00409
00410 if (!(mflags&P_IS_ALIVE) && !OB_TYPE_MOVE_BLOCK(ob, blocked))
00411 return 0;
00412
00413 if (ob->head != NULL)
00414 ob = ob->head;
00415
00416
00417
00418
00419
00420
00421 for (tmp = GET_MAP_OB(m, sx, sy); tmp != NULL; tmp = tmp->above) {
00422
00423 if (tmp->head)
00424 tmp_head = tmp->head;
00425 else
00426 tmp_head = tmp;
00427 if (tmp_head == ob) {
00428 continue;
00429
00430 } else if (tmp->type == CHECK_INV && OB_MOVE_BLOCK(ob, tmp)) {
00431
00432
00433
00434
00435 if (tmp->last_sp) {
00436 if (check_inv_recursive(ob, tmp) == NULL) {
00437 if (tmp->msg) {
00438
00439
00440
00441
00442
00443
00444 draw_ext_info(NDI_UNIQUE|NDI_NAVY, 0, ob,
00445 MSG_TYPE_ATTACK, MSG_TYPE_ATTACK_NOKEY,
00446 tmp->msg, tmp->msg);
00447 }
00448 return 1;
00449 }
00450 else
00451 continue;
00452 } else {
00453
00454
00455
00456 if (check_inv_recursive(ob, tmp) != NULL) {
00457 if (tmp->msg) {
00458 draw_ext_info(NDI_UNIQUE|NDI_NAVY, 0, ob,
00459 MSG_TYPE_ATTACK, MSG_TYPE_ATTACK_NOKEY,
00460 tmp->msg, tmp->msg);
00461 }
00462 return 1;
00463 }
00464 else
00465 continue;
00466 }
00467 }
00468 else {
00469
00470
00471
00472
00473
00474
00475 if (OB_MOVE_BLOCK(ob, tmp))
00476 return 1;
00477 if (QUERY_FLAG(tmp, FLAG_ALIVE)
00478 && tmp->head != ob
00479 && tmp != ob
00480 && tmp->type != DOOR
00481 && !(QUERY_FLAG(tmp, FLAG_WIZ) && tmp->contr->hidden))
00482 return 1;
00483 }
00484
00485 }
00486 return 0;
00487 }
00488
00525 int ob_blocked(const object *ob, mapstruct *m, sint16 x, sint16 y) {
00526 archetype *tmp;
00527 int flag;
00528 mapstruct *m1;
00529 sint16 sx, sy;
00530 const object *part;
00531
00532 if (ob == NULL) {
00533 flag = get_map_flags(m, &m1, x, y, &sx, &sy);
00534 if (flag&P_OUT_OF_MAP)
00535 return P_OUT_OF_MAP;
00536
00537
00538 return(GET_MAP_MOVE_BLOCK(m1, sx, sy));
00539 }
00540
00541 for (tmp = ob->arch, part = ob; tmp != NULL; tmp = tmp->more, part = part->more) {
00542 flag = get_map_flags(m, &m1, x+tmp->clone.x, y+tmp->clone.y, &sx, &sy);
00543
00544 if (flag&P_OUT_OF_MAP)
00545 return P_OUT_OF_MAP;
00546 if (flag&P_IS_ALIVE)
00547 return P_IS_ALIVE;
00548
00549
00550
00551
00552
00553
00554 if (ob->move_type == 0 && GET_MAP_MOVE_BLOCK(m1, sx, sy) != MOVE_ALL)
00555 continue;
00556
00557
00558 if (ob->type == TRANSPORT && part->move_type == 0)
00559 continue;
00560
00561
00562
00563
00564 if (OB_TYPE_MOVE_BLOCK(ob, GET_MAP_MOVE_BLOCK(m1, sx, sy)))
00565 return AB_NO_PASS;
00566 }
00567 return 0;
00568 }
00569
00580 void fix_container(object *container) {
00581 object *tmp = container->inv, *next;
00582
00583 container->inv = NULL;
00584 while (tmp != NULL) {
00585 next = tmp->below;
00586 if (tmp->inv)
00587 fix_container(tmp);
00588 (void)insert_ob_in_ob(tmp, container);
00589 tmp = next;
00590 }
00591
00592
00593
00594 sum_weight(container);
00595 }
00596
00607 static void fix_container_multipart(object *container) {
00608 object *tmp = container->inv, *next;
00609
00610 while (tmp != NULL) {
00611 archetype *at;
00612 object *op, *last;
00613
00614 next = tmp->below;
00615 if (tmp->inv)
00616 fix_container_multipart(tmp);
00617
00618 for (at = tmp->arch->more, last = tmp; at != NULL; at = at->more, last = op) {
00619
00620
00621
00622 op = arch_to_object(at);
00623 op->head = tmp;
00624 op->env = tmp->env;
00625 last->more = op;
00626 if (tmp->name != op->name) {
00627 if (op->name)
00628 free_string(op->name);
00629 op->name = add_string(tmp->name);
00630 }
00631 if (tmp->title != op->title) {
00632 if (op->title)
00633 free_string(op->title);
00634 op->title = add_string(tmp->title);
00635 }
00636 CLEAR_FLAG(op, FLAG_REMOVED);
00637 }
00638 tmp = next;
00639 }
00640 }
00641
00652 static void link_multipart_objects(mapstruct *m) {
00653 int x, y;
00654 object *tmp, *above;
00655
00656 for (x = 0; x < MAP_WIDTH(m); x++)
00657 for (y = 0; y < MAP_HEIGHT(m); y++)
00658 for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = above) {
00659 above = tmp->above;
00660 if (tmp->inv)
00661 fix_container_multipart(tmp);
00662
00663
00664 if (tmp->head || tmp->more)
00665 continue;
00666
00667 fix_multipart_object(tmp);
00668 }
00669 }
00670
00682 static void load_objects(mapstruct *m, FILE *fp, int mapflags) {
00683 int i, j, bufstate = LO_NEWFILE;
00684 int unique;
00685 object *op, *prev = NULL, *last_more = NULL, *otmp;
00686
00687 op = get_object();
00688 op->map = m;
00689
00690 while ((i = load_object(fp, op, bufstate, mapflags))) {
00691
00692
00693
00694
00695 bufstate = LO_REPEAT;
00696
00697
00698
00699
00700
00701 if (op->arch == NULL) {
00702 LOG(llevDebug, "Discarding object without arch: %s\n", op->name ? op->name : "(null)");
00703 continue;
00704 }
00705
00706 switch (i) {
00707 case LL_NORMAL:
00708
00709 if ((QUERY_FLAG(op, FLAG_IS_FLOOR) || QUERY_FLAG(op, FLAG_OVERLAY_FLOOR))
00710 && mapflags&MAP_OVERLAY)
00711 insert_ob_in_map(op, m, op, INS_NO_MERGE|INS_NO_WALK_ON|INS_ABOVE_FLOOR_ONLY|INS_MAP_LOAD);
00712 else
00713 insert_ob_in_map(op, m, op, INS_NO_MERGE|INS_NO_WALK_ON|INS_ON_TOP|INS_MAP_LOAD);
00714
00715 if (op->inv)
00716 sum_weight(op);
00717
00718 prev = op,
00719 last_more = op;
00720 break;
00721
00722 case LL_MORE:
00723 insert_ob_in_map(op, m, op, INS_NO_MERGE|INS_NO_WALK_ON|INS_ABOVE_FLOOR_ONLY);
00724 op->head = prev,
00725 last_more->more = op,
00726 last_more = op;
00727 break;
00728 }
00729 if (mapflags&MAP_STYLE) {
00730 remove_from_active_list(op);
00731 }
00732 op = get_object();
00733 op->map = m;
00734 }
00735 for (i = 0; i < m->width; i++) {
00736 for (j = 0; j < m->height; j++) {
00737 unique = 0;
00738
00739 for (otmp = GET_MAP_OB(m, i, j); otmp; otmp = otmp->above) {
00740 if (QUERY_FLAG(otmp, FLAG_UNIQUE))
00741 unique = 1;
00742 if (!(mapflags&(MAP_OVERLAY|MAP_PLAYER_UNIQUE) || unique))
00743 SET_FLAG(otmp, FLAG_OBJ_ORIGINAL);
00744 }
00745 }
00746 }
00747 free_object(op);
00748 link_multipart_objects(m);
00749 }
00750
00768 static int save_objects(mapstruct *m, FILE *fp, FILE *fp2, int flag) {
00769 int i, j = 0, unique = 0, res;
00770 object *op, *otmp;
00771
00772
00773 for (i = 0; i < MAP_WIDTH(m); i++)
00774 for (j = 0; j < MAP_HEIGHT(m); j++) {
00775 unique = 0;
00776 for (op = GET_MAP_OB(m, i, j); op; op = otmp) {
00777 otmp = op->above;
00778
00779 if (QUERY_FLAG(op, FLAG_IS_FLOOR) && QUERY_FLAG(op, FLAG_UNIQUE))
00780 unique = 1;
00781
00782 if (op->type == PLAYER) {
00783 LOG(llevDebug, "Player on map that is being saved\n");
00784 continue;
00785 }
00786
00787 if (op->head || op->owner)
00788 continue;
00789
00790 if (unique || QUERY_FLAG(op, FLAG_UNIQUE))
00791 res = save_object(fp2, op, SAVE_FLAG_SAVE_UNPAID|SAVE_FLAG_NO_REMOVE);
00792 else
00793 if (flag == 0
00794 || (flag == SAVE_FLAG_NO_REMOVE && (!QUERY_FLAG(op, FLAG_OBJ_ORIGINAL) && !QUERY_FLAG(op, FLAG_UNPAID))))
00795 res = save_object(fp, op, SAVE_FLAG_SAVE_UNPAID|SAVE_FLAG_NO_REMOVE);
00796
00797 if (res != 0)
00798 return res;
00799 }
00800 }
00801
00802 return 0;
00803 }
00804
00816 mapstruct *get_linked_map(void) {
00817 mapstruct *map = (mapstruct *)calloc(1, sizeof(mapstruct));
00818 mapstruct *mp;
00819
00820 if (map == NULL)
00821 fatal(OUT_OF_MEMORY);
00822
00823 for (mp = first_map; mp != NULL && mp->next != NULL; mp = mp->next)
00824 ;
00825 if (mp == NULL)
00826 first_map = map;
00827 else
00828 mp->next = map;
00829
00830 map->in_memory = MAP_SWAPPED;
00831
00832
00833
00834 MAP_WIDTH(map) = 16;
00835 MAP_HEIGHT(map) = 16;
00836 MAP_RESET_TIMEOUT(map) = 0;
00837 MAP_TIMEOUT(map) = 300;
00838 MAP_ENTER_X(map) = 0;
00839 MAP_ENTER_Y(map) = 0;
00840 map->last_reset_time.tv_sec = 0;
00841 return map;
00842 }
00843
00854 static void allocate_map(mapstruct *m) {
00855 m->in_memory = MAP_IN_MEMORY;
00856
00857
00858
00859
00860 if (m->spaces) {
00861 LOG(llevError, "allocate_map called with already allocated map (%s)\n", m->path);
00862 free(m->spaces);
00863 }
00864
00865 m->spaces = calloc(1, MAP_WIDTH(m)*MAP_HEIGHT(m)*sizeof(MapSpace));
00866
00867 if (m->spaces == NULL)
00868 fatal(OUT_OF_MEMORY);
00869 }
00870
00884 mapstruct *get_empty_map(int sizex, int sizey) {
00885 mapstruct *m = get_linked_map();
00886 m->width = sizex;
00887 m->height = sizey;
00888 m->in_memory = MAP_SWAPPED;
00889 allocate_map(m);
00890 return m;
00891 }
00892
00904 static shopitems *parse_shop_string(const char *input_string) {
00905 char *shop_string, *p, *q, *next_semicolon, *next_colon;
00906 shopitems *items = NULL;
00907 int i = 0, number_of_entries = 0;
00908 const typedata *current_type;
00909
00910 shop_string = strdup_local(input_string);
00911 p = shop_string;
00912 LOG(llevDebug, "parsing %s\n", input_string);
00913
00914 while (p) {
00915 p = strchr(p, ';');
00916 number_of_entries++;
00917 if (p)
00918 p++;
00919 }
00920 p = shop_string;
00921 strip_endline(p);
00922 items = CALLOC(number_of_entries+1, sizeof(shopitems));
00923 memset(items, 0, (sizeof(shopitems)*number_of_entries+1));
00924 for (i = 0; i < number_of_entries; i++) {
00925 if (!p) {
00926 LOG(llevError, "parse_shop_string: I seem to have run out of string, that shouldn't happen.\n");
00927 break;
00928 }
00929 next_semicolon = strchr(p, ';');
00930 next_colon = strchr(p, ':');
00931
00932 if (next_colon &&(!next_semicolon || next_colon < next_semicolon))
00933 items[i].strength = atoi(strchr(p, ':')+1);
00934
00935 if (isdigit(*p) || *p == '*') {
00936 items[i].typenum = atoi(p);
00937 current_type = get_typedata(items[i].typenum);
00938 if (current_type) {
00939 items[i].name = current_type->name;
00940 items[i].name_pl = current_type->name_pl;
00941 }
00942 } else {
00943 q = strpbrk(p, ";:");
00944 if (q)
00945 *q = '\0';
00946
00947 current_type = get_typedata_by_name(p);
00948 if (current_type) {
00949 items[i].name = current_type->name;
00950 items[i].typenum = current_type->number;
00951 items[i].name_pl = current_type->name_pl;
00952 } else {
00953
00954
00955 LOG(llevError, "invalid type %s defined in shopitems in string %s\n", p, input_string);
00956 }
00957 }
00958 items[i].index = number_of_entries;
00959 if (next_semicolon)
00960 p = ++next_semicolon;
00961 else
00962 p = NULL;
00963 }
00964 free(shop_string);
00965 return items;
00966 }
00967
00979 static void print_shop_string(mapstruct *m, char *output_string, int size) {
00980 int i;
00981 char tmp[MAX_BUF];
00982
00983 output_string[0] = '\0';
00984 for (i = 0; i < m->shopitems[0].index; i++) {
00985 if (m->shopitems[i].typenum) {
00986 if (m->shopitems[i].strength) {
00987 snprintf(tmp, sizeof(tmp), "%s:%d;", m->shopitems[i].name, m->shopitems[i].strength);
00988 } else
00989 snprintf(tmp, sizeof(tmp), "%s;", m->shopitems[i].name);
00990 } else {
00991 if (m->shopitems[i].strength) {
00992 snprintf(tmp, sizeof(tmp), "*:%d;", m->shopitems[i].strength);
00993 } else
00994 snprintf(tmp, sizeof(tmp), "*");
00995 }
00996 snprintf(output_string+strlen(output_string), size-strlen(output_string), "%s", tmp);
00997 }
00998 }
00999
01019 static int load_map_header(FILE *fp, mapstruct *m) {
01020 char buf[HUGE_BUF], *key = NULL, *value;
01021
01022 m->width = m->height = 0;
01023 while (fgets(buf, sizeof(buf), fp) != NULL) {
01024 char *p;
01025
01026 p = strchr(buf, '\n');
01027 if (p == NULL) {
01028 LOG(llevError, "Error loading map header - did not find a newline - perhaps file is truncated? Buf=%s\n", buf);
01029 return 1;
01030 }
01031 *p = '\0';
01032
01033 key = buf;
01034 while (isspace(*key))
01035 key++;
01036 if (*key == 0)
01037 continue;
01038 value = strchr(key, ' ');
01039 if (value) {
01040 *value = 0;
01041 value++;
01042 while (isspace(*value)) {
01043 value++;
01044 if (*value == '\0') {
01045
01046 value = NULL;
01047 break;
01048 }
01049 }
01050 }
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067 if (!strcmp(key, "msg")) {
01068 char msgbuf[HUGE_BUF];
01069 int msgpos = 0;
01070
01071 while (fgets(buf, sizeof(buf), fp) != NULL) {
01072 if (!strcmp(buf, "endmsg\n"))
01073 break;
01074 else {
01075 snprintf(msgbuf+msgpos, sizeof(msgbuf)-msgpos, "%s", buf);
01076 msgpos += strlen(buf);
01077 }
01078 }
01079
01080
01081
01082
01083
01084 if (msgpos != 0) {
01085
01086 free(m->msg);
01087 m->msg = strdup_local(msgbuf);
01088 }
01089 } else if (!strcmp(key, "maplore")) {
01090 char maplorebuf[HUGE_BUF];
01091 int maplorepos = 0;
01092
01093 while (fgets(buf, HUGE_BUF-1, fp) != NULL) {
01094 if (!strcmp(buf, "endmaplore\n"))
01095 break;
01096 else {
01097 snprintf(maplorebuf+maplorepos, sizeof(maplorebuf)-maplorepos, "%s", buf);
01098 maplorepos += strlen(buf);
01099 }
01100 }
01101 if (maplorepos != 0)
01102 m->maplore = strdup_local(maplorebuf);
01103 } else if (!strcmp(key, "end")) {
01104 break;
01105 } else if (value == NULL) {
01106 LOG(llevError, "Got '%s' line without parameter in map header\n", key);
01107 } else if (!strcmp(key, "arch")) {
01108
01109 if (strcmp(value, "map"))
01110 LOG(llevError, "loading map and got a non 'arch map' line(%s %s)?\n", key, value);
01111 } else if (!strcmp(key, "name")) {
01112
01113 free(m->name);
01114 m->name = strdup_local(value);
01115
01116
01117
01118
01119 } else if (!strcmp(key, "hp") || !strcmp(key, "enter_x")) {
01120 m->enter_x = atoi(value);
01121 } else if (!strcmp(key, "sp") || !strcmp(key, "enter_y")) {
01122 m->enter_y = atoi(value);
01123 } else if (!strcmp(key, "x") || !strcmp(key, "width")) {
01124 m->width = atoi(value);
01125 } else if (!strcmp(key, "y") || !strcmp(key, "height")) {
01126 m->height = atoi(value);
01127 } else if (!strcmp(key, "weight") || !strcmp(key, "reset_timeout")) {
01128 m->reset_timeout = atoi(value);
01129 } else if (!strcmp(key, "value") || !strcmp(key, "swap_time")) {
01130 m->timeout = atoi(value);
01131 } else if (!strcmp(key, "level") || !strcmp(key, "difficulty")) {
01132 m->difficulty = atoi(value);
01133 } else if (!strcmp(key, "invisible") || !strcmp(key, "darkness")) {
01134 m->darkness = atoi(value);
01135 } else if (!strcmp(key, "stand_still") || !strcmp(key, "fixed_resettime")) {
01136 m->fixed_resettime = atoi(value);
01137 } else if (!strcmp(key, "unique")) {
01138 m->unique = atoi(value);
01139 } else if (!strcmp(key, "template")) {
01140 m->is_template = atoi(value);
01141 } else if (!strcmp(key, "region")) {
01142 m->region = get_region_by_name(value);
01143 } else if (!strcmp(key, "shopitems")) {
01144 m->shopitems = parse_shop_string(value);
01145 } else if (!strcmp(key, "shopgreed")) {
01146 m->shopgreed = atof(value);
01147 } else if (!strcmp(key, "shopmin")) {
01148 m->shopmin = atol(value);
01149 } else if (!strcmp(key, "shopmax")) {
01150 m->shopmax = atol(value);
01151 } else if (!strcmp(key, "shoprace")) {
01152 m->shoprace = strdup_local(value);
01153 } else if (!strcmp(key, "outdoor")) {
01154 m->outdoor = atoi(value);
01155 } else if (!strcmp(key, "nosmooth")) {
01156 m->nosmooth = atoi(value);
01157 } else if (!strcmp(key, "first_load")) {
01158 m->last_reset_time.tv_sec = atoi(value);
01159 } else if (!strncmp(key, "tile_path_", 10)) {
01160 int tile = atoi(key+10);
01161
01162 if (tile < 1 || tile > 4) {
01163 LOG(llevError, "load_map_header: tile location %d out of bounds (%s)\n", tile, m->path);
01164 } else {
01165 char path[HUGE_BUF];
01166
01167 if (m->tile_path[tile-1]) {
01168 LOG(llevError, "load_map_header: tile location %d duplicated (%s)\n", tile, m->path);
01169 free(m->tile_path[tile-1]);
01170 m->tile_path[tile-1] = NULL;
01171 }
01172
01173 if (check_path(value, 1) != -1) {
01174
01175 snprintf(path, sizeof(path), "%s", value);
01176 } else {
01177
01178 path_combine_and_normalize(m->path, value, path, sizeof(path));
01179
01180 if (check_path(path, 1) == -1) {
01181 LOG(llevError, "get_map_header: Bad tile path %s %s\n", m->path, value);
01182 path[0] = '\0';
01183 }
01184 }
01185
01186 if (*path != '\0') {
01187
01188 m->tile_path[tile-1] = strdup_local(path);
01189 }
01190 }
01191 } else if (!strcmp(key, "background_music")) {
01192 m->background_music = strdup_local(value);
01193 } else {
01194 LOG(llevError, "Got unknown value in map header: %s %s\n", key, value);
01195 }
01196 }
01197 if ((m->width == 0) || (m->height == 0)) {
01198 LOG(llevError, "Map width or height not specified\n");
01199 return 1;
01200 }
01201 if (!key || strcmp(key, "end")) {
01202 LOG(llevError, "Got premature eof on map header!\n");
01203 return 1;
01204 }
01205 return 0;
01206 }
01207
01226 mapstruct *load_original_map(const char *filename, int flags) {
01227 FILE *fp;
01228 mapstruct *m;
01229 int comp;
01230 char pathname[MAX_BUF];
01231
01232 LOG(llevDebug, "load_original_map: %s (%x)\n", filename, flags);
01233 if (flags&MAP_PLAYER_UNIQUE)
01234 snprintf(pathname, sizeof(pathname), "%s", filename);
01235 else if (flags&MAP_OVERLAY)
01236 create_overlay_pathname(filename, pathname, MAX_BUF);
01237 else
01238 create_pathname(filename, pathname, MAX_BUF);
01239
01240 if ((fp = open_and_uncompress(pathname, 0, &comp)) == NULL) {
01241 char err[MAX_BUF];
01242
01243 LOG((flags&MAP_PLAYER_UNIQUE) ? llevDebug : llevError, "Can't open %s: %s\n", pathname, strerror_local(errno, err, sizeof(err)));
01244 return (NULL);
01245 }
01246
01247 m = get_linked_map();
01248
01249 strcpy(m->path, filename);
01250 if (load_map_header(fp, m)) {
01251 LOG(llevError, "Error loading map header for %s, flags=%d\n", filename, flags);
01252 delete_map(m);
01253 return NULL;
01254 }
01255
01256 allocate_map(m);
01257 m->compressed = comp;
01258
01259 m->in_memory = MAP_LOADING;
01260 load_objects(m, fp, flags&(MAP_BLOCK|MAP_STYLE));
01261 close_and_delete(fp, comp);
01262 m->in_memory = MAP_IN_MEMORY;
01263 if (!MAP_DIFFICULTY(m))
01264 MAP_DIFFICULTY(m) = calculate_difficulty(m);
01265 set_map_reset_time(m);
01266
01267
01268 update_buttons(m);
01269
01270
01271 execute_global_event(EVENT_MAPLOAD, m);
01272
01273 return (m);
01274 }
01275
01288 static mapstruct *load_temporary_map(mapstruct *m) {
01289 FILE *fp;
01290 int comp;
01291 char buf[MAX_BUF];
01292
01293 if (!m->tmpname) {
01294 LOG(llevError, "No temporary filename for map %s\n", m->path);
01295 snprintf(buf, sizeof(buf), "%s", m->path);
01296 delete_map(m);
01297 m = load_original_map(buf, 0);
01298 if (m == NULL)
01299 return NULL;
01300 fix_auto_apply(m);
01301 return m;
01302 }
01303
01304 if ((fp = open_and_uncompress(m->tmpname, 0, &comp)) == NULL) {
01305 LOG(llevError, "Cannot open %s: %s\n", m->tmpname, strerror_local(errno, buf, sizeof(buf)));
01306 snprintf(buf, sizeof(buf), "%s", m->path);
01307 delete_map(m);
01308 m = load_original_map(buf, 0);
01309 if (m == NULL)
01310 return NULL;
01311 fix_auto_apply(m);
01312 return m;
01313 }
01314
01315 if (load_map_header(fp, m)) {
01316 LOG(llevError, "Error loading map header for %s (%s)\n", m->path, m->tmpname);
01317 delete_map(m);
01318 m = load_original_map(m->path, 0);
01319 return NULL;
01320 }
01321 m->compressed = comp;
01322 allocate_map(m);
01323
01324 m->in_memory = MAP_LOADING;
01325 load_objects(m, fp, 0);
01326 close_and_delete(fp, comp);
01327 m->in_memory = MAP_IN_MEMORY;
01328 return m;
01329 }
01330
01341 static mapstruct *load_overlay_map(const char *filename, mapstruct *m) {
01342 FILE *fp;
01343 int comp;
01344 char pathname[MAX_BUF];
01345
01346 create_overlay_pathname(filename, pathname, MAX_BUF);
01347
01348 if ((fp = open_and_uncompress(pathname, 0, &comp)) == NULL) {
01349
01350 return m;
01351 }
01352
01353 if (load_map_header(fp, m)) {
01354 LOG(llevError, "Error loading map header for overlay %s (%s)\n", m->path, pathname);
01355 delete_map(m);
01356 m = load_original_map(m->path, 0);
01357 return NULL;
01358 }
01359 m->compressed = comp;
01360
01361
01362 m->in_memory = MAP_LOADING;
01363 load_objects(m, fp, MAP_OVERLAY);
01364 close_and_delete(fp, comp);
01365 m->in_memory = MAP_IN_MEMORY;
01366 return m;
01367 }
01368
01369
01370
01371
01372
01379 static void delete_unique_items(mapstruct *m) {
01380 int i, j, unique = 0;
01381 object *op, *next;
01382
01383 for (i = 0; i < MAP_WIDTH(m); i++)
01384 for (j = 0; j < MAP_HEIGHT(m); j++) {
01385 unique = 0;
01386 for (op = GET_MAP_OB(m, i, j); op; op = next) {
01387 next = op->above;
01388 if (QUERY_FLAG(op, FLAG_IS_FLOOR) && QUERY_FLAG(op, FLAG_UNIQUE))
01389 unique = 1;
01390 if (op->head == NULL && (QUERY_FLAG(op, FLAG_UNIQUE) || unique)) {
01391 clean_object(op);
01392 if (QUERY_FLAG(op, FLAG_IS_LINKED))
01393 remove_button_link(op);
01394 remove_ob(op);
01395 free_object(op);
01396 }
01397 }
01398 }
01399 }
01400
01406 static void load_unique_objects(mapstruct *m) {
01407 FILE *fp;
01408 int comp, count;
01409 char firstname[MAX_BUF], name[MAX_BUF];
01410
01411 create_items_path(m->path, name, MAX_BUF);
01412 for (count = 0; count < 10; count++) {
01413 snprintf(firstname, sizeof(firstname), "%s.v%02d", name, count);
01414 if (!access(firstname, R_OK))
01415 break;
01416 }
01417
01418 if (count == 10)
01419 return;
01420
01421 if ((fp = open_and_uncompress(firstname, 0, &comp)) == NULL) {
01422
01423
01424
01425 LOG(llevDebug, "Can't open unique items file for %s\n", name);
01426 return;
01427 }
01428
01429 m->in_memory = MAP_LOADING;
01430 if (m->tmpname == NULL)
01431 delete_unique_items(m);
01432 load_object(fp, NULL, LO_NOREAD, 0);
01433 load_objects(m, fp, 0);
01434 close_and_delete(fp, comp);
01435 m->in_memory = MAP_IN_MEMORY;
01436 }
01437
01453 int save_map(mapstruct *m, int flag) {
01454 #define TEMP_EXT ".savefile"
01455 FILE *fp, *fp2;
01456 char filename[MAX_BUF], buf[MAX_BUF], shop[MAX_BUF], final[MAX_BUF];
01457 int i, res;
01458
01459 if (flag && !*m->path) {
01460 LOG(llevError, "Tried to save map without path.\n");
01461 return SAVE_ERROR_NO_PATH;
01462 }
01463
01464 if (flag != SAVE_MODE_NORMAL || (m->unique) || (m->is_template)) {
01465 if (!m->unique && !m->is_template) {
01466 if (flag == SAVE_MODE_OVERLAY)
01467 create_overlay_pathname(m->path, filename, MAX_BUF);
01468 else
01469 create_pathname(m->path, filename, MAX_BUF);
01470 } else
01471 snprintf(filename, sizeof(filename), "%s", m->path);
01472
01473
01474
01475
01476
01477 if (m->compressed
01478 && strcmp((filename+strlen(filename)-strlen(uncomp[m->compressed][0])), uncomp[m->compressed][0]))
01479 strcat(filename, uncomp[m->compressed][0]);
01480 make_path_to_file(filename);
01481 } else {
01482 if (!m->tmpname)
01483 m->tmpname = tempnam_local(settings.tmpdir, NULL);
01484 snprintf(filename, sizeof(filename), "%s", m->tmpname);
01485 }
01486 LOG(llevDebug, "Saving map %s\n", m->path);
01487 m->in_memory = MAP_SAVING;
01488
01489
01490 if (m->compressed && (m->unique || m->is_template || flag != SAVE_MODE_NORMAL)) {
01491 char buf[MAX_BUF];
01492 snprintf(buf, sizeof(buf), "%s > %s%s", uncomp[m->compressed][2], filename, TEMP_EXT);
01493 snprintf(final, sizeof(final), "%s", filename);
01494 fp = popen(buf, "w");
01495 } else {
01496 snprintf(final, sizeof(final), "%s", filename);
01497 snprintf(filename, sizeof(filename), "%s%s", final, TEMP_EXT);
01498 fp = fopen(filename, "w");
01499 }
01500
01501 if (fp == NULL) {
01502 LOG(llevError, "Cannot open regular objects file %s: %s\n", filename, strerror_local(errno, buf, sizeof(buf)));
01503 return SAVE_ERROR_RCREATION;
01504 }
01505
01506
01507 fprintf(fp, "arch map\n");
01508 if (m->name) fprintf(fp, "name %s\n", m->name);
01509 if (!flag) fprintf(fp, "swap_time %d\n", m->swap_time);
01510 if (m->reset_timeout) fprintf(fp, "reset_timeout %u\n", m->reset_timeout);
01511 if (m->fixed_resettime) fprintf(fp, "fixed_resettime %d\n", m->fixed_resettime);
01512
01513
01514
01515 if (m->difficulty) fprintf(fp, "difficulty %d\n", m->difficulty);
01516 if (m->region) fprintf(fp, "region %s\n", m->region->name);
01517 if (m->shopitems) {
01518 print_shop_string(m, shop, sizeof(shop));
01519 fprintf(fp, "shopitems %s\n", shop);
01520 }
01521 if (m->shopgreed) fprintf(fp, "shopgreed %f\n", m->shopgreed);
01522 if (m->shopmin) fprintf(fp, "shopmin %"FMT64U"\n", m->shopmin);
01523 if (m->shopmax) fprintf(fp, "shopmax %"FMT64U"\n", m->shopmax);
01524 if (m->shoprace) fprintf(fp, "shoprace %s\n", m->shoprace);
01525 if (m->darkness) fprintf(fp, "darkness %d\n", m->darkness);
01526 if (m->width) fprintf(fp, "width %d\n", m->width);
01527 if (m->height) fprintf(fp, "height %d\n", m->height);
01528 if (m->enter_x) fprintf(fp, "enter_x %d\n", m->enter_x);
01529 if (m->enter_y) fprintf(fp, "enter_y %d\n", m->enter_y);
01530 if (m->msg) fprintf(fp, "msg\n%sendmsg\n", m->msg);
01531 if (m->maplore) fprintf(fp, "maplore\n%sendmaplore\n", m->maplore);
01532 if (m->unique) fprintf(fp, "unique %d\n", m->unique);
01533 if (m->is_template) fprintf(fp, "template %d\n", m->is_template);
01534 if (m->outdoor) fprintf(fp, "outdoor %d\n", m->outdoor);
01535 if (m->nosmooth) fprintf(fp, "nosmooth %d\n", m->nosmooth);
01536 if (m->last_reset_time.tv_sec) fprintf(fp, "first_load %d\n", (int)m->last_reset_time.tv_sec);
01537 if (m->background_music) fprintf(fp, "background_music %s\n", m->background_music);
01538
01539
01540 if (flag != SAVE_MODE_OVERLAY)
01541 for (i = 0; i < 4; i++)
01542 if (m->tile_path[i])
01543 fprintf(fp, "tile_path_%d %s\n", i+1, m->tile_path[i]);
01544
01545 fprintf(fp, "end\n");
01546
01547
01548
01549
01550
01551
01552 fp2 = fp;
01553 if ((flag == SAVE_MODE_NORMAL || flag == SAVE_MODE_OVERLAY) && !m->unique && !m->is_template) {
01554 char name[MAX_BUF], final_unique[MAX_BUF];
01555
01556 create_items_path(m->path, name, MAX_BUF);
01557 snprintf(final_unique, sizeof(final_unique), "%s.v00", name);
01558 snprintf(buf, sizeof(buf), "%s%s", final_unique, TEMP_EXT);
01559 if ((fp2 = fopen(buf, "w")) == NULL) {
01560 LOG(llevError, "Can't open unique items file %s\n", buf);
01561 return SAVE_ERROR_UCREATION;
01562 }
01563 if (flag == SAVE_MODE_OVERLAY) {
01564
01565 res = save_objects(m, fp, fp2, SAVE_FLAG_NO_REMOVE);
01566 if (res < 0) {
01567 LOG(llevError, "Save error during object save: %d\n", res);
01568 return res;
01569 }
01570 m->in_memory = MAP_IN_MEMORY;
01571 } else {
01572 res = save_objects(m, fp, fp2, 0);
01573 if (res < 0) {
01574 LOG(llevError, "Save error during object save: %d\n", res);
01575 return res;
01576 }
01577 free_all_objects(m);
01578 }
01579 if (fp2 != NULL) {
01580 if (ftell(fp2) == 0) {
01581 fclose(fp2);
01582 unlink(buf);
01583
01584
01585
01586
01587 unlink(final_unique);
01588 } else {
01589 fflush(fp2);
01590 fclose(fp2);
01591 unlink(final_unique);
01592 if (rename(buf, final_unique) == -1) {
01593 LOG(llevError, "Couldn't rename unique file %s to %s\n", buf, final_unique);
01594 return SAVE_ERROR_URENAME;
01595 }
01596 chmod(final_unique, SAVE_MODE);
01597 }
01598 }
01599 } else {
01600 res = save_objects(m, fp, fp, 0);
01601 if (res < 0) {
01602 LOG(llevError, "Save error during object save: %d\n", res);
01603 return res;
01604 }
01605 free_all_objects(m);
01606 }
01607
01608 if (m->compressed && (m->unique || m->is_template || flag != SAVE_MODE_NORMAL)) {
01609 fflush(fp);
01610 if (pclose(fp) == -1) {
01611 LOG(llevError, "pclose error!\n");
01612 return SAVE_ERROR_CLOSE;
01613 }
01614 } else {
01615 fflush(fp);
01616 if (fclose(fp) != 0) {
01617 LOG(llevError, "fclose error!\n");
01618 return SAVE_ERROR_CLOSE;
01619 }
01620 }
01621 unlink(final);
01622 if (rename(filename, final) == -1) {
01623 LOG(llevError, "Couldn't rename regular file %s to %s\n", filename, final);
01624 return SAVE_ERROR_RRENAME;
01625 }
01626
01627 chmod(final, SAVE_MODE);
01628 return SAVE_ERROR_OK;
01629 }
01630
01640 void clean_object(object *op) {
01641 object *tmp, *next;
01642
01643 for (tmp = op->inv; tmp; tmp = next) {
01644 next = tmp->below;
01645 clean_object(tmp);
01646 if (QUERY_FLAG(tmp, FLAG_IS_LINKED))
01647 remove_button_link(tmp);
01648 remove_ob(tmp);
01649 free_object(tmp);
01650 }
01651 }
01652
01659 static void free_all_objects(mapstruct *m) {
01660 int i, j;
01661 object *op;
01662
01663 for (i = 0; i < MAP_WIDTH(m); i++)
01664 for (j = 0; j < MAP_HEIGHT(m); j++) {
01665 object *previous_obj = NULL;
01666
01667 while ((op = GET_MAP_OB(m, i, j)) != NULL) {
01668 if (op == previous_obj) {
01669 LOG(llevDebug, "free_all_objects: Link error, bailing out.\n");
01670 break;
01671 }
01672 previous_obj = op;
01673 if (op->head != NULL)
01674 op = op->head;
01675
01676
01677
01678
01679 if (m->in_memory == MAP_IN_MEMORY)
01680 clean_object(op);
01681 remove_ob(op);
01682 free_object(op);
01683 }
01684 }
01685 #ifdef MANY_CORES
01686
01687
01688
01689
01690 for (op = objects; op != NULL; op = op->next) {
01691 if (!QUERY_FLAG(op, FLAG_REMOVED) && op->map == m) {
01692 LOG(llevDebug, "free_all_objects: object %s still on map after it should have been freed\n", op->name);
01693 abort();
01694 }
01695 }
01696 #endif
01697 }
01698
01707 void free_map(mapstruct *m) {
01708 int i;
01709
01710 if (!m->in_memory) {
01711 LOG(llevError, "Trying to free freed map.\n");
01712 return;
01713 }
01714
01715
01716 execute_global_event(EVENT_MAPUNLOAD, m);
01717
01718 if (m->spaces) free_all_objects(m);
01719 if (m->name) FREE_AND_CLEAR(m->name);
01720 if (m->spaces) FREE_AND_CLEAR(m->spaces);
01721 if (m->msg) FREE_AND_CLEAR(m->msg);
01722 if (m->maplore) FREE_AND_CLEAR(m->maplore);
01723 if (m->shopitems) FREE_AND_CLEAR(m->shopitems);
01724 if (m->shoprace) FREE_AND_CLEAR(m->shoprace);
01725 if (m->background_music) FREE_AND_CLEAR(m->background_music);
01726 if (m->buttons) free_objectlinkpt(m->buttons);
01727 m->buttons = NULL;
01728 for (i = 0; i < 4; i++) {
01729 if (m->tile_path[i])
01730 FREE_AND_CLEAR(m->tile_path[i]);
01731 m->tile_map[i] = NULL;
01732 }
01733 m->in_memory = MAP_SWAPPED;
01734 }
01735
01745 void delete_map(mapstruct *m) {
01746 mapstruct *tmp, *last;
01747 int i;
01748
01749 if (!m)
01750 return;
01751 if (m->in_memory == MAP_IN_MEMORY) {
01752
01753
01754
01755 m->in_memory = MAP_SAVING;
01756 free_map(m);
01757 }
01758
01759
01760
01761 if (m->tmpname) {
01762 free(m->tmpname);
01763 m->tmpname = NULL;
01764 }
01765 last = NULL;
01766
01767
01768
01769
01770
01771 for (tmp = first_map; tmp != NULL; tmp = tmp->next) {
01772 if (tmp->next == m)
01773 last = tmp;
01774
01775
01776 for (i = 0; i < 4; i++)
01777 if (tmp->tile_map[i] == m)
01778 tmp->tile_map[i] = NULL;
01779 }
01780
01781
01782 if (!last) {
01783 if (m == first_map)
01784 first_map = m->next;
01785 else
01786
01787
01788
01789 LOG(llevError, "delete_map: Unable to find map %s in list\n", m->path);
01790 } else
01791 last->next = m->next;
01792
01793 free(m);
01794 }
01795
01809 mapstruct *ready_map_name(const char *name, int flags) {
01810 mapstruct *m;
01811
01812 if (!name)
01813 return (NULL);
01814
01815
01816 m = has_been_loaded(name);
01817
01818
01819 if (m && (m->in_memory == MAP_LOADING || m->in_memory == MAP_IN_MEMORY)) {
01820 return m;
01821 }
01822
01823
01824
01825
01826
01827
01828
01829
01830
01831 if ((flags&(MAP_FLUSH|MAP_PLAYER_UNIQUE)) || !m) {
01832
01833
01834 if (m) {
01835 clean_tmp_map(m);
01836 delete_map(m);
01837 }
01838
01839
01840 if (flags&MAP_PLAYER_UNIQUE)
01841 LOG(llevDebug, "Trying to load map %s.\n", name);
01842 else {
01843 char fullpath[MAX_BUF];
01844
01845 create_pathname(name, fullpath, MAX_BUF);
01846 LOG(llevDebug, "Trying to load map %s.\n", fullpath);
01847 }
01848
01849 if (!(m = load_original_map(name, (flags&MAP_PLAYER_UNIQUE))))
01850 return (NULL);
01851
01852 fix_auto_apply(m);
01853
01854
01855
01856
01857 if (!(flags&(MAP_FLUSH|MAP_PLAYER_UNIQUE)))
01858 load_unique_objects(m);
01859
01860 if (!(flags&(MAP_FLUSH|MAP_PLAYER_UNIQUE|MAP_OVERLAY))) {
01861 m = load_overlay_map(name, m);
01862 if (m == NULL)
01863 return NULL;
01864 }
01865 } else {
01866
01867
01868 m = load_temporary_map(m);
01869 if (m == NULL)
01870 return NULL;
01871 load_unique_objects(m);
01872
01873 clean_tmp_map(m);
01874 m->in_memory = MAP_IN_MEMORY;
01875
01876
01877
01878
01879
01880
01881 if (m->tmpname)
01882 free(m->tmpname);
01883 m->tmpname = NULL;
01884
01885 }
01886
01887
01888
01889
01890
01891 decay_objects(m);
01892
01893 if (m->outdoor)
01894 set_darkness_map(m);
01895 if (!(flags&(MAP_FLUSH))) {
01896 if (m->last_reset_time.tv_sec == 0)
01897 gettimeofday(&(m->last_reset_time), NULL);
01898 }
01899 return m;
01900 }
01901
01917 int calculate_difficulty(mapstruct *m) {
01918 object *op;
01919 archetype *at;
01920 int x, y;
01921 int diff = 0;
01922 int i;
01923 sint64 exp_pr_sq, total_exp = 0;
01924
01925 if (MAP_DIFFICULTY(m)) {
01926 return MAP_DIFFICULTY(m);
01927 }
01928
01929 for (x = 0; x < MAP_WIDTH(m); x++)
01930 for (y = 0; y < MAP_HEIGHT(m); y++)
01931 for (op = GET_MAP_OB(m, x, y); op != NULL; op = op->above) {
01932 if (QUERY_FLAG(op, FLAG_MONSTER))
01933 total_exp += op->stats.exp;
01934 if (QUERY_FLAG(op, FLAG_GENERATOR)) {
01935 total_exp += op->stats.exp;
01936 at = get_archetype_by_type_subtype(GENERATE_TYPE(op), -1);
01937 if (at != NULL)
01938 total_exp += at->clone.stats.exp*8;
01939 }
01940 }
01941
01942 exp_pr_sq = ((double)1000*total_exp)/(MAP_WIDTH(m)*MAP_HEIGHT(m)+1);
01943 diff = 20;
01944 for (i = 1; i < 20; i++)
01945 if (exp_pr_sq <= level_exp(i, 1.0)) {
01946 diff = i;
01947 break;
01948 }
01949
01950 return diff;
01951 }
01952
01959 void clean_tmp_map(mapstruct *m) {
01960 if (m->tmpname == NULL)
01961 return;
01962 (void)unlink(m->tmpname);
01963 }
01964
01968 void free_all_maps(void) {
01969 int real_maps = 0;
01970
01971 while (first_map) {
01972
01973
01974
01975 if (first_map->in_memory == MAP_SAVING)
01976 first_map->in_memory = MAP_IN_MEMORY;
01977 delete_map(first_map);
01978 real_maps++;
01979 }
01980 LOG(llevDebug, "free_all_maps: Freed %d maps\n", real_maps);
01981 }
01982
02000 int change_map_light(mapstruct *m, int change) {
02001 int new_level = m->darkness+change;
02002
02003
02004 if (!change
02005 || (new_level <= 0 && m->darkness == 0)
02006 || (new_level >= MAX_DARKNESS && m->darkness >= MAX_DARKNESS)) {
02007 return 0;
02008 }
02009
02010
02011 if (change > 0)
02012 ext_info_map(NDI_BLACK, m, MSG_TYPE_MISC, MSG_SUBTYPE_NONE, "It becomes darker.", NULL);
02013 else
02014 ext_info_map(NDI_BLACK, m, MSG_TYPE_MISC, MSG_SUBTYPE_NONE, "It becomes brighter.", NULL);
02015
02016
02017
02018
02019
02020
02021 if (new_level < 0)
02022 m->darkness = 0;
02023 else if (new_level >= MAX_DARKNESS)
02024 m->darkness = MAX_DARKNESS;
02025 else
02026 m->darkness = new_level;
02027
02028
02029 update_all_map_los(m);
02030 return 1;
02031 }
02032
02055 static inline void add_face_layer(int low_layer, int high_layer, object *ob, object *layers[], int honor_visibility) {
02056 int l, l1;
02057 object *tmp;
02058
02059 for (l = low_layer; l <= high_layer; l++) {
02060 if (!layers[l]) {
02061
02062
02063
02064 layers[l] = ob;
02065 if (!honor_visibility)
02066 return;
02067
02068
02069
02070
02071
02072 for (l1 = (l-1); l1 >= low_layer; l1--) {
02073 if (layers[l1]->face->visibility > layers[l1+1]->face->visibility) {
02074 tmp = layers[l1+1];
02075 layers[l1+1] = layers[l1];
02076 layers[l1] = tmp;
02077 }
02078 }
02079
02080 return;
02081 }
02082 }
02083
02084
02085 if (!honor_visibility) {
02086
02087
02088
02089 for (l = low_layer; l < high_layer; l++)
02090 layers[l] = layers[l+1];
02091 layers[high_layer] = ob;
02092
02093
02094
02095 } else if (ob->face->visibility >= layers[low_layer]->face->visibility) {
02096
02097
02098
02099
02100
02101 for (l = high_layer; l >= low_layer; l--) {
02102 if (ob->face->visibility >= layers[l]->face->visibility) {
02103 for (l1 = low_layer; l1 < l; l1++)
02104 layers[l1] = layers[l1+1];
02105 layers[l] = ob;
02106 break;
02107 }
02108 }
02109 }
02110 }
02111
02124 void update_position(mapstruct *m, int x, int y) {
02125 object *tmp, *player = NULL;
02126 uint8 flags = 0, oldflags, light = 0;
02127 object *layers[MAP_LAYERS];
02128
02129 MoveType move_block = 0, move_slow = 0, move_on = 0, move_off = 0, move_allow = 0;
02130
02131 oldflags = GET_MAP_FLAGS(m, x, y);
02132 if (!(oldflags&P_NEED_UPDATE)) {
02133 LOG(llevDebug, "update_position called with P_NEED_UPDATE not set: %s (%d, %d)\n", m->path, x, y);
02134 return;
02135 }
02136
02137 memset(layers, 0, MAP_LAYERS*sizeof(object *));
02138
02139 for (tmp = GET_MAP_OB(m, x, y); tmp; tmp = tmp->above) {
02140
02141
02142 if (QUERY_FLAG(tmp, FLAG_WIZ) && tmp->contr->hidden)
02143 continue;
02144
02145 if (tmp->type == PLAYER)
02146 player = tmp;
02147
02148
02149
02150
02151
02152
02153 if (tmp->glow_radius > light)
02154 light = tmp->glow_radius;
02155
02156
02157
02158
02159
02160 if (!tmp->invisible && tmp->face != blank_face) {
02161 if (tmp->map_layer) {
02162 add_face_layer(tmp->map_layer, map_layer_info[tmp->map_layer].high_layer,
02163 tmp, layers, map_layer_info[tmp->map_layer].honor_visibility);
02164 } else if (tmp->move_type&MOVE_FLYING) {
02165 add_face_layer(MAP_LAYER_FLY1, MAP_LAYER_FLY2, tmp, layers, 1);
02166 } else if ((tmp->type == PLAYER || QUERY_FLAG(tmp, FLAG_MONSTER))) {
02167 add_face_layer(MAP_LAYER_LIVING1, MAP_LAYER_LIVING2, tmp, layers, 1);
02168 } else if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) {
02169 layers[MAP_LAYER_FLOOR] = tmp;
02170
02171 memset(layers+1, 0, (MAP_LAYERS-1)*sizeof(object *));
02172
02173
02174
02175
02176 } else if (QUERY_FLAG(tmp, FLAG_NO_PICK)) {
02177 add_face_layer(MAP_LAYER_NO_PICK1, MAP_LAYER_NO_PICK2, tmp, layers, 0);
02178 } else {
02179 add_face_layer(MAP_LAYER_ITEM1, MAP_LAYER_ITEM3, tmp, layers, 1);
02180 }
02181 }
02182 if (tmp == tmp->above) {
02183 LOG(llevError, "Error in structure of map\n");
02184 exit(-1);
02185 }
02186
02187 move_slow |= tmp->move_slow;
02188 move_block |= tmp->move_block;
02189 move_on |= tmp->move_on;
02190 move_off |= tmp->move_off;
02191 move_allow |= tmp->move_allow;
02192
02193 if (QUERY_FLAG(tmp, FLAG_ALIVE))
02194 flags |= P_IS_ALIVE;
02195 if (QUERY_FLAG(tmp, FLAG_NO_MAGIC))
02196 flags |= P_NO_MAGIC;
02197 if (QUERY_FLAG(tmp, FLAG_DAMNED))
02198 flags |= P_NO_CLERIC;
02199
02200 if (QUERY_FLAG(tmp, FLAG_BLOCKSVIEW))
02201 flags |= P_BLOCKSVIEW;
02202 }
02203
02204 if (player)
02205 flags |= P_PLAYER;
02206
02207
02208
02209
02210
02211 if (((oldflags&~(P_NEED_UPDATE|P_NO_ERROR)) != flags)
02212 && (!(oldflags&P_NO_ERROR))) {
02213 LOG(llevDebug, "update_position: updated flags do not match old flags: %s (old=%d,new=%d) %x != %x\n",
02214 m->path, x, y, (oldflags&~P_NEED_UPDATE), flags);
02215 }
02216
02217 SET_MAP_FLAGS(m, x, y, flags);
02218 SET_MAP_MOVE_BLOCK(m, x, y, move_block&~move_allow);
02219 SET_MAP_MOVE_ON(m, x, y, move_on);
02220 SET_MAP_MOVE_OFF(m, x, y, move_off);
02221 SET_MAP_MOVE_SLOW(m, x, y, move_slow);
02222 SET_MAP_LIGHT(m, x, y, light);
02223
02224
02225
02226
02227 SET_MAP_PLAYER(m, x, y, player);
02228
02229
02230 memcpy(GET_MAP_FACE_OBJS(m, x, y), layers, sizeof(object *)*MAP_LAYERS);
02231 }
02232
02239 void set_map_reset_time(mapstruct *map) {
02240 int timeout;
02241
02242 timeout = MAP_RESET_TIMEOUT(map);
02243 if (timeout <= 0)
02244 timeout = MAP_DEFAULTRESET;
02245 if (timeout >= MAP_MAXRESET)
02246 timeout = MAP_MAXRESET;
02247 MAP_WHEN_RESET(map) = seconds()+timeout;
02248 }
02249
02267 static mapstruct *load_and_link_tiled_map(mapstruct *orig_map, int tile_num) {
02268 int dest_tile = (tile_num+2)%4;
02269 char path[HUGE_BUF];
02270
02271 path_combine_and_normalize(orig_map->path, orig_map->tile_path[tile_num], path, sizeof(path));
02272
02273 orig_map->tile_map[tile_num] = ready_map_name(path, 0);
02274
02275
02276 if (orig_map->tile_map[tile_num]->tile_path[dest_tile]
02277 && !strcmp(orig_map->tile_map[tile_num]->tile_path[dest_tile], orig_map->path))
02278 orig_map->tile_map[tile_num]->tile_map[dest_tile] = orig_map;
02279
02280 return orig_map->tile_map[tile_num];
02281 }
02282
02300 int out_of_map(mapstruct *m, int x, int y) {
02301
02302
02303
02304
02305 if (!m)
02306 return 0;
02307
02308
02309
02310
02311 if (x >= 0 && x < MAP_WIDTH(m) && y >= 0 && y < MAP_HEIGHT(m))
02312 return 0;
02313
02314 if (x < 0) {
02315 if (!m->tile_path[3])
02316 return 1;
02317 if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) {
02318 load_and_link_tiled_map(m, 3);
02319 }
02320 return (out_of_map(m->tile_map[3], x+MAP_WIDTH(m->tile_map[3]), y));
02321 }
02322 if (x >= MAP_WIDTH(m)) {
02323 if (!m->tile_path[1])
02324 return 1;
02325 if (!m->tile_map[1] || m->tile_map[1]->in_memory != MAP_IN_MEMORY) {
02326 load_and_link_tiled_map(m, 1);
02327 }
02328 return (out_of_map(m->tile_map[1], x-MAP_WIDTH(m), y));
02329 }
02330 if (y < 0) {
02331 if (!m->tile_path[0])
02332 return 1;
02333 if (!m->tile_map[0] || m->tile_map[0]->in_memory != MAP_IN_MEMORY) {
02334 load_and_link_tiled_map(m, 0);
02335 }
02336 return (out_of_map(m->tile_map[0], x, y+MAP_HEIGHT(m->tile_map[0])));
02337 }
02338 if (y >= MAP_HEIGHT(m)) {
02339 if (!m->tile_path[2])
02340 return 1;
02341 if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY) {
02342 load_and_link_tiled_map(m, 2);
02343 }
02344 return (out_of_map(m->tile_map[2], x, y-MAP_HEIGHT(m)));
02345 }
02346 return 1;
02347 }
02348
02366 mapstruct *get_map_from_coord(mapstruct *m, sint16 *x, sint16 *y) {
02367
02368
02369
02370
02371
02372 if (*x >= 0 && *x < MAP_WIDTH(m) && *y >= 0 && *y < MAP_HEIGHT(m))
02373 return m;
02374
02375 if (*x < 0) {
02376 if (!m->tile_path[3])
02377 return NULL;
02378 if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY)
02379 load_and_link_tiled_map(m, 3);
02380
02381 *x += MAP_WIDTH(m->tile_map[3]);
02382 return (get_map_from_coord(m->tile_map[3], x, y));
02383 }
02384 if (*x >= MAP_WIDTH(m)) {
02385 if (!m->tile_path[1])
02386 return NULL;
02387 if (!m->tile_map[1] || m->tile_map[1]->in_memory != MAP_IN_MEMORY)
02388 load_and_link_tiled_map(m, 1);
02389
02390 *x -= MAP_WIDTH(m);
02391 return (get_map_from_coord(m->tile_map[1], x, y));
02392 }
02393 if (*y < 0) {
02394 if (!m->tile_path[0])
02395 return NULL;
02396 if (!m->tile_map[0] || m->tile_map[0]->in_memory != MAP_IN_MEMORY)
02397 load_and_link_tiled_map(m, 0);
02398
02399 *y += MAP_HEIGHT(m->tile_map[0]);
02400 return (get_map_from_coord(m->tile_map[0], x, y));
02401 }
02402 if (*y >= MAP_HEIGHT(m)) {
02403 if (!m->tile_path[2])
02404 return NULL;
02405 if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY)
02406 load_and_link_tiled_map(m, 2);
02407
02408 *y -= MAP_HEIGHT(m);
02409 return (get_map_from_coord(m->tile_map[2], x, y));
02410 }
02411 return NULL;
02412 }
02413
02427 static int adjacent_map(const mapstruct *map1, const mapstruct *map2, int *dx, int *dy) {
02428 if (!map1 || !map2)
02429 return 0;
02430
02431 if (map1 == map2) {
02432 *dx = 0;
02433 *dy = 0;
02434 } else if (map1->tile_map[0] == map2) {
02435 *dx = 0;
02436 *dy = -MAP_HEIGHT(map2);
02437 } else if (map1->tile_map[1] == map2) {
02438 *dx = MAP_WIDTH(map1);
02439 *dy = 0;
02440 } else if (map1->tile_map[2] == map2) {
02441 *dx = 0;
02442 *dy = MAP_HEIGHT(map1);
02443 } else if (map1->tile_map[3] == map2) {
02444 *dx = -MAP_WIDTH(map2);
02445 *dy = 0;
02446 } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[1] == map2) {
02447 *dx = MAP_WIDTH(map1->tile_map[0]);
02448 *dy = -MAP_HEIGHT(map1->tile_map[0]);
02449 } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[3] == map2) {
02450 *dx = -MAP_WIDTH(map2);
02451 *dy = -MAP_HEIGHT(map1->tile_map[0]);
02452 } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[0] == map2) {
02453 *dx = MAP_WIDTH(map1);
02454 *dy = -MAP_HEIGHT(map2);
02455 } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[2] == map2) {
02456 *dx = MAP_WIDTH(map1);
02457 *dy = MAP_HEIGHT(map1->tile_map[1]);
02458 } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[1] == map2) {
02459 *dx = MAP_WIDTH(map1->tile_map[2]);
02460 *dy = MAP_HEIGHT(map1);
02461 } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[3] == map2) {
02462 *dx = -MAP_WIDTH(map2);
02463 *dy = MAP_HEIGHT(map1);
02464 } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[0] == map2) {
02465 *dx = -MAP_WIDTH(map1->tile_map[3]);
02466 *dy = -MAP_HEIGHT(map2);
02467 } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[2] == map2) {
02468 *dx = -MAP_WIDTH(map1->tile_map[3]);
02469 *dy = MAP_HEIGHT(map1->tile_map[3]);
02470 } else {
02471 return 0;
02472 }
02473
02474 return 1;
02475 }
02476
02504 void get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags) {
02505 if (!adjacent_map(op1->map, op2->map, &retval->distance_x, &retval->distance_y)) {
02506
02507 retval->distance = 100000;
02508 retval->distance_x = 32767;
02509 retval->distance_y = 32767;
02510 retval->direction = 0;
02511 retval->part = NULL;
02512 } else {
02513 object *best;
02514
02515 retval->distance_x += op2->x-op1->x;
02516 retval->distance_y += op2->y-op1->y;
02517
02518 best = op1;
02519
02520 if (!(flags&0x1) && op1->more) {
02521 object *tmp;
02522 int best_distance = retval->distance_x*retval->distance_x+
02523 retval->distance_y*retval->distance_y, tmpi;
02524
02525
02526
02527
02528
02529
02530
02531 for (tmp = op1->more; tmp != NULL; tmp = tmp->more) {
02532 tmpi = (op1->x-tmp->x+retval->distance_x)*(op1->x-tmp->x+retval->distance_x)+
02533 (op1->y-tmp->y+retval->distance_y)*(op1->y-tmp->y+retval->distance_y);
02534 if (tmpi < best_distance) {
02535 best_distance = tmpi;
02536 best = tmp;
02537 }
02538 }
02539 if (best != op1) {
02540 retval->distance_x += op1->x-best->x;
02541 retval->distance_y += op1->y-best->y;
02542 }
02543 }
02544 retval->part = best;
02545 retval->distance = isqrt(retval->distance_x*retval->distance_x+retval->distance_y*retval->distance_y);
02546 retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y);
02547 }
02548 }
02549
02573 void get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval, int flags) {
02574 if (!adjacent_map(m, op2->map, &retval->distance_x, &retval->distance_y)) {
02575
02576 retval->distance = 100000;
02577 retval->distance_x = 32767;
02578 retval->distance_y = 32767;
02579 retval->direction = 0;
02580 retval->part = NULL;
02581 } else {
02582 retval->distance_x += op2->x-x;
02583 retval->distance_y += op2->y-y;
02584
02585 retval->part = NULL;
02586 retval->distance = isqrt(retval->distance_x*retval->distance_x+retval->distance_y*retval->distance_y);
02587 retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y);
02588 }
02589 }
02590
02609 int on_same_map(const object *op1, const object *op2) {
02610 int dx, dy;
02611
02612 return adjacent_map(op1->map, op2->map, &dx, &dy);
02613 }