1 | /* |
1 | /* |
2 | * static char *rcsid_map_c = |
2 | * static char *rcsid_map_c = |
3 | * "$Id: map.C,v 1.4 2006/08/15 18:12:20 elmex Exp $"; |
3 | * "$Id: map.C,v 1.9 2006/08/27 16:15:11 root Exp $"; |
4 | */ |
4 | */ |
5 | |
5 | |
6 | /* |
6 | /* |
7 | CrossFire, A Multiplayer game for X-windows |
7 | CrossFire, A Multiplayer game for X-windows |
8 | |
8 | |
… | |
… | |
37 | |
37 | |
38 | #include "path.h" |
38 | #include "path.h" |
39 | |
39 | |
40 | |
40 | |
41 | extern int nrofallocobjects,nroffreeobjects; |
41 | extern int nrofallocobjects,nroffreeobjects; |
42 | |
|
|
43 | void (*load_original_map_callback)(mapstruct *map); |
|
|
44 | void (*load_temporary_map_callback)(mapstruct *map); |
|
|
45 | void (*clean_temporary_map_callback)(mapstruct *map); |
|
|
46 | |
42 | |
47 | /* |
43 | /* |
48 | * Returns the mapstruct which has a name matching the given argument. |
44 | * Returns the mapstruct which has a name matching the given argument. |
49 | * return NULL if no match is found. |
45 | * return NULL if no match is found. |
50 | */ |
46 | */ |
… | |
… | |
520 | * Loads (ands parses) the objects into a given map from the specified |
516 | * Loads (ands parses) the objects into a given map from the specified |
521 | * file pointer. |
517 | * file pointer. |
522 | * mapflags is the same as we get with load_original_map |
518 | * mapflags is the same as we get with load_original_map |
523 | */ |
519 | */ |
524 | |
520 | |
525 | void load_objects (mapstruct *m, FILE *fp, int mapflags) { |
521 | void load_objects (mapstruct *m, FILE *fp, object_thawer &thawer, int mapflags) { |
526 | int i,j,bufstate=LO_NEWFILE; |
522 | int i,j,bufstate=LO_NEWFILE; |
527 | int unique; |
523 | int unique; |
528 | object *op, *prev=NULL,*last_more=NULL, *otmp; |
524 | object *op, *prev=NULL,*last_more=NULL, *otmp; |
529 | |
525 | |
530 | op=get_object(); |
526 | op=get_object(); |
531 | op->map = m; /* To handle buttons correctly */ |
527 | op->map = m; /* To handle buttons correctly */ |
532 | |
528 | |
533 | while((i=load_object(fp,op,bufstate, mapflags))) { |
529 | while((i = load_object (fp, thawer, op, bufstate, mapflags))) { |
534 | /* Since the loading of the map header does not load an object |
530 | /* Since the loading of the map header does not load an object |
535 | * anymore, we need to pass LO_NEWFILE for the first object loaded, |
531 | * anymore, we need to pass LO_NEWFILE for the first object loaded, |
536 | * and then switch to LO_REPEAT for faster loading. |
532 | * and then switch to LO_REPEAT for faster loading. |
537 | */ |
533 | */ |
538 | bufstate = LO_REPEAT; |
534 | bufstate = LO_REPEAT; |
… | |
… | |
592 | /* This saves all the objects on the map in a non destructive fashion. |
588 | /* This saves all the objects on the map in a non destructive fashion. |
593 | * Modified by MSW 2001-07-01 to do in a single pass - reduces code, |
589 | * Modified by MSW 2001-07-01 to do in a single pass - reduces code, |
594 | * and we only save the head of multi part objects - this is needed |
590 | * and we only save the head of multi part objects - this is needed |
595 | * in order to do map tiling properly. |
591 | * in order to do map tiling properly. |
596 | */ |
592 | */ |
597 | void save_objects (mapstruct *m, FILE *fp, FILE *fp2, int flag) { |
593 | void save_objects (mapstruct *m, FILE *fp, object_freezer &freezer, FILE *fp2, object_freezer &freezer2, int flag) { |
598 | int i, j = 0,unique=0; |
594 | int i, j = 0,unique=0; |
599 | object *op; |
595 | object *op; |
600 | /* first pass - save one-part objects */ |
596 | /* first pass - save one-part objects */ |
601 | for(i = 0; i < MAP_WIDTH(m); i++) |
597 | for(i = 0; i < MAP_WIDTH(m); i++) |
602 | for (j = 0; j < MAP_HEIGHT(m); j++) { |
598 | for (j = 0; j < MAP_HEIGHT(m); j++) { |
… | |
… | |
612 | |
608 | |
613 | if (op->head || op->owner) |
609 | if (op->head || op->owner) |
614 | continue; |
610 | continue; |
615 | |
611 | |
616 | if (unique || QUERY_FLAG(op, FLAG_UNIQUE)) |
612 | if (unique || QUERY_FLAG(op, FLAG_UNIQUE)) |
617 | save_object( fp2 , op, 3); |
613 | save_object( fp2 , freezer2, op, 3); |
618 | else |
614 | else |
619 | if (flag == 0 || |
615 | if (flag == 0 || |
620 | (flag == 2 && (!QUERY_FLAG(op, FLAG_OBJ_ORIGINAL) && |
616 | (flag == 2 && (!QUERY_FLAG(op, FLAG_OBJ_ORIGINAL) && |
621 | !QUERY_FLAG(op, FLAG_UNPAID)))) |
617 | !QUERY_FLAG(op, FLAG_UNPAID)))) |
622 | save_object(fp, op, 3); |
618 | save_object(fp, freezer, op, 3); |
623 | |
619 | |
624 | } /* for this space */ |
620 | } /* for this space */ |
625 | } /* for this j */ |
621 | } /* for this j */ |
626 | } |
622 | } |
627 | |
623 | |
… | |
… | |
1035 | if((fp=open_and_uncompress(pathname, 0, &comp))==NULL) { |
1031 | if((fp=open_and_uncompress(pathname, 0, &comp))==NULL) { |
1036 | LOG(llevError, "Can't open %s: %s\n", pathname, strerror_local(errno)); |
1032 | LOG(llevError, "Can't open %s: %s\n", pathname, strerror_local(errno)); |
1037 | return (NULL); |
1033 | return (NULL); |
1038 | } |
1034 | } |
1039 | |
1035 | |
|
|
1036 | object_thawer thawer (filename); |
|
|
1037 | |
1040 | m = get_linked_map(); |
1038 | m = get_linked_map(); |
1041 | |
1039 | |
1042 | strcpy (m->path, filename); |
1040 | strcpy (m->path, filename); |
1043 | if (load_map_header(fp, m)) { |
1041 | if (load_map_header(fp, m)) { |
1044 | LOG(llevError,"Error loading map header for %s, flags=%d\n", |
1042 | LOG(llevError,"Error loading map header for %s, flags=%d\n", |
… | |
… | |
1049 | |
1047 | |
1050 | allocate_map(m); |
1048 | allocate_map(m); |
1051 | m->compressed = comp; |
1049 | m->compressed = comp; |
1052 | |
1050 | |
1053 | m->in_memory=MAP_LOADING; |
1051 | m->in_memory=MAP_LOADING; |
1054 | load_objects (m, fp, flags & (MAP_BLOCK|MAP_STYLE)); |
1052 | load_objects (m, fp, thawer, flags & (MAP_BLOCK|MAP_STYLE)); |
1055 | close_and_delete(fp, comp); |
1053 | close_and_delete(fp, comp); |
1056 | m->in_memory=MAP_IN_MEMORY; |
1054 | m->in_memory=MAP_IN_MEMORY; |
1057 | if (!MAP_DIFFICULTY(m)) |
1055 | if (!MAP_DIFFICULTY(m)) |
1058 | MAP_DIFFICULTY(m)=calculate_difficulty(m); |
1056 | MAP_DIFFICULTY(m)=calculate_difficulty(m); |
1059 | set_map_reset_time(m); |
1057 | set_map_reset_time(m); |
1060 | if (load_original_map_callback) |
1058 | INVOKE_MAP (LOAD, m); |
1061 | load_original_map_callback(m); |
|
|
1062 | return (m); |
1059 | return (m); |
1063 | } |
1060 | } |
1064 | |
1061 | |
1065 | /* |
1062 | /* |
1066 | * Loads a map, which has been loaded earlier, from file. |
1063 | * Loads a map, which has been loaded earlier, from file. |
… | |
… | |
1090 | m = load_original_map(buf, 0); |
1087 | m = load_original_map(buf, 0); |
1091 | if(m==NULL) return NULL; |
1088 | if(m==NULL) return NULL; |
1092 | fix_auto_apply(m); /* Chests which open as default */ |
1089 | fix_auto_apply(m); /* Chests which open as default */ |
1093 | return m; |
1090 | return m; |
1094 | } |
1091 | } |
1095 | |
1092 | |
|
|
1093 | object_thawer thawer (m->tmpname); |
1096 | |
1094 | |
1097 | if (load_map_header(fp, m)) { |
1095 | if (load_map_header(fp, m)) { |
1098 | LOG(llevError,"Error loading map header for %s (%s)\n", |
1096 | LOG(llevError,"Error loading map header for %s (%s)\n", |
1099 | m->path, m->tmpname); |
1097 | m->path, m->tmpname); |
1100 | delete_map(m); |
1098 | delete_map(m); |
… | |
… | |
1103 | } |
1101 | } |
1104 | m->compressed = comp; |
1102 | m->compressed = comp; |
1105 | allocate_map(m); |
1103 | allocate_map(m); |
1106 | |
1104 | |
1107 | m->in_memory=MAP_LOADING; |
1105 | m->in_memory=MAP_LOADING; |
1108 | load_objects (m, fp, 0); |
1106 | load_objects (m, fp, thawer, 0); |
1109 | close_and_delete(fp, comp); |
1107 | close_and_delete(fp, comp); |
1110 | m->in_memory=MAP_IN_MEMORY; |
1108 | m->in_memory=MAP_IN_MEMORY; |
1111 | if (load_temporary_map_callback) |
1109 | INVOKE_MAP (SWAPIN, m); |
1112 | load_temporary_map_callback(m); |
|
|
1113 | return m; |
1110 | return m; |
1114 | } |
1111 | } |
1115 | |
1112 | |
1116 | /* |
1113 | /* |
1117 | * Loads a map, which has been loaded earlier, from file. |
1114 | * Loads a map, which has been loaded earlier, from file. |
… | |
… | |
1128 | |
1125 | |
1129 | if((fp=open_and_uncompress(pathname, 0, &comp))==NULL) { |
1126 | if((fp=open_and_uncompress(pathname, 0, &comp))==NULL) { |
1130 | /* LOG(llevDebug,"Can't open overlay %s\n", pathname);*/ |
1127 | /* LOG(llevDebug,"Can't open overlay %s\n", pathname);*/ |
1131 | return m; |
1128 | return m; |
1132 | } |
1129 | } |
|
|
1130 | |
|
|
1131 | object_thawer thawer (pathname); |
1133 | |
1132 | |
1134 | if (load_map_header(fp, m)) { |
1133 | if (load_map_header(fp, m)) { |
1135 | LOG(llevError,"Error loading map header for overlay %s (%s)\n", |
1134 | LOG(llevError,"Error loading map header for overlay %s (%s)\n", |
1136 | m->path, pathname); |
1135 | m->path, pathname); |
1137 | delete_map(m); |
1136 | delete_map(m); |
… | |
… | |
1140 | } |
1139 | } |
1141 | m->compressed = comp; |
1140 | m->compressed = comp; |
1142 | /*allocate_map(m);*/ |
1141 | /*allocate_map(m);*/ |
1143 | |
1142 | |
1144 | m->in_memory=MAP_LOADING; |
1143 | m->in_memory=MAP_LOADING; |
1145 | load_objects (m, fp, MAP_OVERLAY); |
1144 | load_objects (m, fp, thawer, MAP_OVERLAY); |
1146 | close_and_delete(fp, comp); |
1145 | close_and_delete(fp, comp); |
1147 | m->in_memory=MAP_IN_MEMORY; |
1146 | m->in_memory=MAP_IN_MEMORY; |
1148 | return m; |
1147 | return m; |
1149 | } |
1148 | } |
1150 | |
1149 | |
… | |
… | |
1199 | */ |
1198 | */ |
1200 | LOG(llevDebug, "Can't open unique items file for %s\n", create_items_path(m->path)); |
1199 | LOG(llevDebug, "Can't open unique items file for %s\n", create_items_path(m->path)); |
1201 | return; |
1200 | return; |
1202 | } |
1201 | } |
1203 | |
1202 | |
|
|
1203 | object_thawer thawer (firstname); |
|
|
1204 | |
1204 | m->in_memory=MAP_LOADING; |
1205 | m->in_memory=MAP_LOADING; |
1205 | if (m->tmpname == NULL) /* if we have loaded unique items from */ |
1206 | if (m->tmpname == NULL) /* if we have loaded unique items from */ |
1206 | delete_unique_items(m); /* original map before, don't duplicate them */ |
1207 | delete_unique_items(m); /* original map before, don't duplicate them */ |
1207 | load_object(fp, NULL, LO_NOREAD,0); |
1208 | load_object(fp, thawer, NULL, LO_NOREAD,0); |
1208 | load_objects (m, fp, 0); |
1209 | load_objects (m, fp, thawer, 0); |
1209 | close_and_delete(fp, comp); |
1210 | close_and_delete(fp, comp); |
1210 | m->in_memory=MAP_IN_MEMORY; |
1211 | m->in_memory=MAP_IN_MEMORY; |
1211 | } |
1212 | } |
1212 | |
1213 | |
1213 | |
1214 | |
… | |
… | |
1220 | * (this should have been updated when first loaded) |
1221 | * (this should have been updated when first loaded) |
1221 | */ |
1222 | */ |
1222 | |
1223 | |
1223 | int new_save_map(mapstruct *m, int flag) { |
1224 | int new_save_map(mapstruct *m, int flag) { |
1224 | FILE *fp, *fp2; |
1225 | FILE *fp, *fp2; |
1225 | char filename[MAX_BUF],buf[MAX_BUF], shop[MAX_BUF]; |
1226 | char filename[MAX_BUF],buf[MAX_BUF], buf_s[MAX_BUF], |
|
|
1227 | shop[MAX_BUF], filename_s[MAX_BUF]; |
1226 | int i; |
1228 | int i; |
1227 | |
1229 | |
1228 | if (flag && !*m->path) { |
1230 | if (flag && !*m->path) { |
1229 | LOG(llevError,"Tried to save map without path.\n"); |
1231 | LOG(llevError,"Tried to save map without path.\n"); |
1230 | return -1; |
1232 | return -1; |
… | |
… | |
1251 | } else { |
1253 | } else { |
1252 | if (!m->tmpname) |
1254 | if (!m->tmpname) |
1253 | m->tmpname = tempnam_local(settings.tmpdir,NULL); |
1255 | m->tmpname = tempnam_local(settings.tmpdir,NULL); |
1254 | strcpy(filename, m->tmpname); |
1256 | strcpy(filename, m->tmpname); |
1255 | } |
1257 | } |
1256 | LOG(llevDebug,"Saving map %s\n",m->path); |
1258 | LOG(llevDebug,"Saving map %s to %s\n", m->path, filename); |
1257 | m->in_memory = MAP_SAVING; |
1259 | m->in_memory = MAP_SAVING; |
1258 | |
1260 | |
1259 | unlink (filename); // do not overwrite backups if done via hardlinks |
1261 | sprintf (filename_s, "%s~", filename); |
1260 | |
1262 | |
1261 | /* Compress if it isn't a temporary save. Do compress if unique */ |
1263 | /* Compress if it isn't a temporary save. Do compress if unique */ |
1262 | if (m->compressed && (m->unique || m->templatemap || flag)) { |
1264 | if (m->compressed && (m->unique || m->templatemap || flag)) { |
1263 | char buf[MAX_BUF]; |
1265 | char buf[MAX_BUF]; |
1264 | strcpy(buf, uncomp[m->compressed][2]); |
1266 | strcpy(buf, uncomp[m->compressed][2]); |
1265 | strcat(buf, " > "); |
1267 | strcat(buf, " > "); |
1266 | strcat(buf, filename); |
1268 | strcat(buf, filename_s); |
1267 | fp = popen(buf, "w"); |
1269 | fp = popen(buf, "w"); |
1268 | } else |
1270 | } else |
1269 | fp = fopen(filename, "w"); |
1271 | fp = fopen(filename_s, "w"); |
1270 | |
1272 | |
1271 | if(fp == NULL) { |
1273 | if(fp == NULL) { |
1272 | LOG(llevError, "Cannot write %s: %s\n", filename, strerror_local(errno)); |
1274 | LOG(llevError, "Cannot write %s: %s\n", filename_s, strerror_local(errno)); |
1273 | return -1; |
1275 | return -1; |
1274 | } |
1276 | } |
|
|
1277 | |
|
|
1278 | object_freezer freezer (filename); |
1275 | |
1279 | |
1276 | /* legacy */ |
1280 | /* legacy */ |
1277 | fprintf(fp,"arch map\n"); |
1281 | fprintf(fp,"arch map\n"); |
1278 | if (m->name) fprintf(fp,"name %s\n", m->name); |
1282 | if (m->name) fprintf(fp,"name %s\n", m->name); |
1279 | if (!flag) fprintf(fp,"swap_time %d\n", m->swap_time); |
1283 | if (!flag) fprintf(fp,"swap_time %d\n", m->swap_time); |
… | |
… | |
1327 | /* In the game save unique items in the different file, but |
1331 | /* In the game save unique items in the different file, but |
1328 | * in the editor save them to the normal map file. |
1332 | * in the editor save them to the normal map file. |
1329 | * If unique map, save files in the proper destination (set by |
1333 | * If unique map, save files in the proper destination (set by |
1330 | * player) |
1334 | * player) |
1331 | */ |
1335 | */ |
1332 | fp2 = fp; /* save unique items into fp2 */ |
|
|
1333 | if ((flag == 0 || flag == 2) && !m->unique && !m->templatemap) { |
1336 | if ((flag == 0 || flag == 2) && !m->unique && !m->templatemap) { |
1334 | sprintf (buf,"%s.v00",create_items_path (m->path)); |
1337 | sprintf (buf,"%s.v00",create_items_path (m->path)); |
|
|
1338 | sprintf (buf_s, "%s~", buf); |
1335 | if ((fp2 = fopen (buf, "w")) == NULL) { |
1339 | if ((fp2 = fopen (buf_s, "w")) == NULL) { |
1336 | LOG(llevError, "Can't open unique items file %s\n", buf); |
1340 | LOG(llevError, "Can't open unique items file %s\n", buf_s); |
1337 | } |
1341 | } |
|
|
1342 | |
|
|
1343 | object_freezer freezer2 (buf); |
|
|
1344 | |
1338 | if (flag == 2) |
1345 | if (flag == 2) |
1339 | save_objects(m, fp, fp2, 2); |
1346 | save_objects(m, fp, freezer, fp2, freezer2, 2); |
1340 | else |
1347 | else |
1341 | save_objects (m, fp, fp2, 0); |
1348 | save_objects (m, fp,freezer, fp2, freezer2, 0); |
1342 | if (fp2 != NULL) { |
1349 | if (fp2 != NULL) { |
1343 | if (ftell (fp2) == 0) { |
1350 | if (ftell (fp2) == 0) { |
1344 | fclose (fp2); |
1351 | fclose (fp2); |
|
|
1352 | rename (buf_s, buf); |
1345 | unlink (buf); |
1353 | unlink (buf); |
1346 | } else { |
1354 | } else { |
1347 | fclose (fp2); |
1355 | fclose (fp2); |
|
|
1356 | rename (buf_s, buf); |
1348 | chmod (buf, SAVE_MODE); |
1357 | chmod (buf, SAVE_MODE); |
1349 | } |
1358 | } |
1350 | } |
1359 | } |
1351 | } else { /* save same file when not playing, like in editor */ |
1360 | } else { /* save same file when not playing, like in editor */ |
1352 | save_objects(m, fp, fp, 0); |
1361 | save_objects(m, fp, freezer, fp, freezer, 0); |
1353 | } |
1362 | } |
1354 | |
1363 | |
1355 | if (m->compressed && (m->unique || m->templatemap || flag)) |
1364 | if (m->compressed && (m->unique || m->templatemap || flag)) |
1356 | pclose(fp); |
1365 | pclose(fp); |
1357 | else |
1366 | else |
1358 | fclose(fp); |
1367 | fclose(fp); |
|
|
1368 | |
|
|
1369 | rename (filename_s, filename); |
1359 | |
1370 | |
1360 | chmod (filename, SAVE_MODE); |
1371 | chmod (filename, SAVE_MODE); |
1361 | return 0; |
1372 | return 0; |
1362 | } |
1373 | } |
1363 | |
1374 | |
… | |
… | |
1676 | } |
1687 | } |
1677 | |
1688 | |
1678 | void clean_tmp_map(mapstruct *m) { |
1689 | void clean_tmp_map(mapstruct *m) { |
1679 | if(m->tmpname == NULL) |
1690 | if(m->tmpname == NULL) |
1680 | return; |
1691 | return; |
1681 | if (clean_temporary_map_callback) |
1692 | INVOKE_MAP (CLEAN, m); |
1682 | clean_temporary_map_callback (m); |
|
|
1683 | (void) unlink(m->tmpname); |
1693 | (void) unlink(m->tmpname); |
1684 | } |
1694 | } |
1685 | |
1695 | |
1686 | void free_all_maps(void) |
1696 | void free_all_maps(void) |
1687 | { |
1697 | { |
… | |
… | |
1827 | if (QUERY_FLAG(tmp,FLAG_NO_MAGIC)) |
1837 | if (QUERY_FLAG(tmp,FLAG_NO_MAGIC)) |
1828 | flags |= P_NO_MAGIC; |
1838 | flags |= P_NO_MAGIC; |
1829 | if (QUERY_FLAG(tmp,FLAG_DAMNED)) |
1839 | if (QUERY_FLAG(tmp,FLAG_DAMNED)) |
1830 | flags |= P_NO_CLERIC; |
1840 | flags |= P_NO_CLERIC; |
1831 | if (tmp->type == SAFE_GROUND) |
1841 | if (tmp->type == SAFE_GROUND) |
1832 | flags |= P_SAFE; |
1842 | flags |= P_SAFE | P_NO_CLERIC | P_NO_MAGIC; |
1833 | |
1843 | |
1834 | if (QUERY_FLAG(tmp,FLAG_BLOCKSVIEW)) |
1844 | if (QUERY_FLAG(tmp,FLAG_BLOCKSVIEW)) |
1835 | flags |= P_BLOCKSVIEW; |
1845 | flags |= P_BLOCKSVIEW; |
1836 | } /* for stack of objects */ |
1846 | } /* for stack of objects */ |
1837 | |
1847 | |