1 | /* |
1 | /* |
2 | * static char *rcsid_map_c = |
2 | * static char *rcsid_map_c = |
3 | * "$Id: map.c,v 1.1.1.2 2006/02/22 18:01:21 elmex Exp $"; |
3 | * "$Id: map.c,v 1.14 2006/08/13 17:16:00 elmex dead $"; |
4 | */ |
4 | */ |
5 | |
5 | |
6 | /* |
6 | /* |
7 | CrossFire, A Multiplayer game for X-windows |
7 | CrossFire, A Multiplayer game for X-windows |
8 | |
8 | |
… | |
… | |
38 | #include "path.h" |
38 | #include "path.h" |
39 | |
39 | |
40 | |
40 | |
41 | extern int nrofallocobjects,nroffreeobjects; |
41 | extern int nrofallocobjects,nroffreeobjects; |
42 | |
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); |
43 | |
46 | |
44 | /* |
47 | /* |
45 | * Returns the mapstruct which has a name matching the given argument. |
48 | * Returns the mapstruct which has a name matching the given argument. |
46 | * return NULL if no match is found. |
49 | * return NULL if no match is found. |
47 | */ |
50 | */ |
… | |
… | |
587 | * 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 |
588 | * in order to do map tiling properly. |
591 | * in order to do map tiling properly. |
589 | */ |
592 | */ |
590 | void save_objects (mapstruct *m, FILE *fp, FILE *fp2, int flag) { |
593 | void save_objects (mapstruct *m, FILE *fp, FILE *fp2, int flag) { |
591 | int i, j = 0,unique=0; |
594 | int i, j = 0,unique=0; |
592 | object *op, *otmp; |
595 | object *op; |
593 | /* first pass - save one-part objects */ |
596 | /* first pass - save one-part objects */ |
594 | for(i = 0; i < MAP_WIDTH(m); i++) |
597 | for(i = 0; i < MAP_WIDTH(m); i++) |
595 | for (j = 0; j < MAP_HEIGHT(m); j++) { |
598 | for (j = 0; j < MAP_HEIGHT(m); j++) { |
596 | unique=0; |
599 | unique=0; |
597 | for(op = get_map_ob (m, i, j); op; op = otmp) { |
600 | for(op = get_map_ob (m, i, j); op; op = op->above) { |
598 | otmp = op->above; |
|
|
599 | |
|
|
600 | if (QUERY_FLAG(op,FLAG_IS_FLOOR) && QUERY_FLAG(op, FLAG_UNIQUE)) |
601 | if (QUERY_FLAG(op,FLAG_IS_FLOOR) && QUERY_FLAG(op, FLAG_UNIQUE)) |
601 | unique=1; |
602 | unique=1; |
602 | |
603 | |
603 | if(op->type == PLAYER) { |
604 | if(op->type == PLAYER) { |
604 | LOG(llevDebug, "Player on map that is being saved\n"); |
605 | LOG(llevDebug, "Player on map that is being saved\n"); |
… | |
… | |
676 | |
677 | |
677 | if(m->spaces==NULL) |
678 | if(m->spaces==NULL) |
678 | fatal(OUT_OF_MEMORY); |
679 | fatal(OUT_OF_MEMORY); |
679 | } |
680 | } |
680 | |
681 | |
681 | /* Creatures and returns a map of the specific size. Used |
682 | /* Create and returns a map of the specific size. Used |
682 | * in random map code and the editor. |
683 | * in random map code and the editor. |
683 | */ |
684 | */ |
684 | mapstruct *get_empty_map(int sizex, int sizey) { |
685 | mapstruct *get_empty_map(int sizex, int sizey) { |
685 | mapstruct *m = get_linked_map(); |
686 | mapstruct *m = get_linked_map(); |
686 | m->width = sizex; |
687 | m->width = sizex; |
… | |
… | |
702 | int i=0, number_of_entries=0; |
703 | int i=0, number_of_entries=0; |
703 | const typedata *current_type; |
704 | const typedata *current_type; |
704 | |
705 | |
705 | shop_string=strdup_local(input_string); |
706 | shop_string=strdup_local(input_string); |
706 | p=shop_string; |
707 | p=shop_string; |
707 | LOG(llevDebug, "parsing %s\n", input_string); |
|
|
708 | /* first we'll count the entries, we'll need that for allocating the array shortly */ |
708 | /* first we'll count the entries, we'll need that for allocating the array shortly */ |
709 | while (p) { |
709 | while (p) { |
710 | p=strchr(p, ';'); |
710 | p=strchr(p, ';'); |
711 | number_of_entries++; |
711 | number_of_entries++; |
712 | if (p) p++; |
712 | if (p) p++; |
… | |
… | |
1049 | close_and_delete(fp, comp); |
1049 | close_and_delete(fp, comp); |
1050 | m->in_memory=MAP_IN_MEMORY; |
1050 | m->in_memory=MAP_IN_MEMORY; |
1051 | if (!MAP_DIFFICULTY(m)) |
1051 | if (!MAP_DIFFICULTY(m)) |
1052 | MAP_DIFFICULTY(m)=calculate_difficulty(m); |
1052 | MAP_DIFFICULTY(m)=calculate_difficulty(m); |
1053 | set_map_reset_time(m); |
1053 | set_map_reset_time(m); |
|
|
1054 | if (load_original_map_callback) |
|
|
1055 | load_original_map_callback(m); |
1054 | return (m); |
1056 | return (m); |
1055 | } |
1057 | } |
1056 | |
1058 | |
1057 | /* |
1059 | /* |
1058 | * Loads a map, which has been loaded earlier, from file. |
1060 | * Loads a map, which has been loaded earlier, from file. |
… | |
… | |
1098 | |
1100 | |
1099 | m->in_memory=MAP_LOADING; |
1101 | m->in_memory=MAP_LOADING; |
1100 | load_objects (m, fp, 0); |
1102 | load_objects (m, fp, 0); |
1101 | close_and_delete(fp, comp); |
1103 | close_and_delete(fp, comp); |
1102 | m->in_memory=MAP_IN_MEMORY; |
1104 | m->in_memory=MAP_IN_MEMORY; |
|
|
1105 | if (load_temporary_map_callback) |
|
|
1106 | load_temporary_map_callback(m); |
1103 | return m; |
1107 | return m; |
1104 | } |
1108 | } |
1105 | |
1109 | |
1106 | /* |
1110 | /* |
1107 | * Loads a map, which has been loaded earlier, from file. |
1111 | * Loads a map, which has been loaded earlier, from file. |
… | |
… | |
1143 | *****************************************************************************/ |
1147 | *****************************************************************************/ |
1144 | |
1148 | |
1145 | /* This goes through map 'm' and removed any unique items on the map. */ |
1149 | /* This goes through map 'm' and removed any unique items on the map. */ |
1146 | static void delete_unique_items(mapstruct *m) |
1150 | static void delete_unique_items(mapstruct *m) |
1147 | { |
1151 | { |
1148 | int i,j,unique=0; |
1152 | int i,j,unique; |
1149 | object *op, *next; |
1153 | object *op, *next; |
1150 | |
1154 | |
1151 | for(i=0; i<MAP_WIDTH(m); i++) |
1155 | for(i=0; i<MAP_WIDTH(m); i++) |
1152 | for(j=0; j<MAP_HEIGHT(m); j++) { |
1156 | for(j=0; j<MAP_HEIGHT(m); j++) { |
1153 | unique=0; |
1157 | unique=0; |
… | |
… | |
1243 | m->tmpname = tempnam_local(settings.tmpdir,NULL); |
1247 | m->tmpname = tempnam_local(settings.tmpdir,NULL); |
1244 | strcpy(filename, m->tmpname); |
1248 | strcpy(filename, m->tmpname); |
1245 | } |
1249 | } |
1246 | LOG(llevDebug,"Saving map %s\n",m->path); |
1250 | LOG(llevDebug,"Saving map %s\n",m->path); |
1247 | m->in_memory = MAP_SAVING; |
1251 | m->in_memory = MAP_SAVING; |
|
|
1252 | |
|
|
1253 | unlink (filename); // do not overwrite backups if done via hardlinks |
1248 | |
1254 | |
1249 | /* Compress if it isn't a temporary save. Do compress if unique */ |
1255 | /* Compress if it isn't a temporary save. Do compress if unique */ |
1250 | if (m->compressed && (m->unique || m->template || flag)) { |
1256 | if (m->compressed && (m->unique || m->template || flag)) { |
1251 | char buf[MAX_BUF]; |
1257 | char buf[MAX_BUF]; |
1252 | strcpy(buf, uncomp[m->compressed][2]); |
1258 | strcpy(buf, uncomp[m->compressed][2]); |
… | |
… | |
1611 | * have a difficulty set than using this function - human calculation |
1617 | * have a difficulty set than using this function - human calculation |
1612 | * is much better than this functions guesswork. |
1618 | * is much better than this functions guesswork. |
1613 | */ |
1619 | */ |
1614 | |
1620 | |
1615 | int calculate_difficulty(mapstruct *m) { |
1621 | int calculate_difficulty(mapstruct *m) { |
1616 | object *op; |
1622 | object *op; |
1617 | archetype *at; |
1623 | archetype *at; |
1618 | int x,y; |
1624 | int x, y, i, diff; |
1619 | int diff=0; |
1625 | long monster_cnt = 0; |
1620 | int i; |
1626 | double avgexp = 0; |
1621 | sint64 exp_pr_sq, total_exp=0; |
1627 | sint64 total_exp = 0; |
1622 | |
1628 | |
1623 | if (MAP_DIFFICULTY(m)) { |
1629 | if (MAP_DIFFICULTY (m)) |
|
|
1630 | { |
1624 | LOG(llevDebug, "Using stored map difficulty: %d\n", MAP_DIFFICULTY(m)); |
1631 | LOG(llevDebug, "Using stored map difficulty: %d\n", MAP_DIFFICULTY (m)); |
1625 | return MAP_DIFFICULTY(m); |
1632 | return MAP_DIFFICULTY (m); |
1626 | } |
|
|
1627 | |
|
|
1628 | for(x=0;x<MAP_WIDTH(m);x++) |
|
|
1629 | for(y=0;y<MAP_HEIGHT(m);y++) |
|
|
1630 | for(op=get_map_ob(m,x,y);op!=NULL;op=op->above) { |
|
|
1631 | if(QUERY_FLAG(op,FLAG_MONSTER)) |
|
|
1632 | total_exp+=op->stats.exp; |
|
|
1633 | if(QUERY_FLAG(op,FLAG_GENERATOR)) { |
|
|
1634 | total_exp+=op->stats.exp; |
|
|
1635 | at=type_to_archetype(GENERATE_TYPE(op)); |
|
|
1636 | if(at!=NULL) |
|
|
1637 | total_exp+=at->clone.stats.exp*8; |
|
|
1638 | } |
|
|
1639 | } |
1633 | } |
1640 | #ifdef NEWCALC |
1634 | |
1641 | (int)exp_pr_sq=((double)1000*total_exp)/(m->map_object->x*m->map_object->y+1); |
1635 | for(x = 0; x < MAP_WIDTH(m); x++) |
1642 | for(i=20;i>0;i--) |
1636 | for(y = 0; y < MAP_HEIGHT(m); y++) |
1643 | if(exp_pr_sq>level_exp(i,1.0)) { |
1637 | for(op = get_map_ob(m, x, y); op != NULL; op = op->above) |
1644 | diff=i; |
1638 | { |
1645 | break; |
1639 | if(QUERY_FLAG (op, FLAG_MONSTER)) |
1646 | } |
1640 | { |
1647 | #else |
1641 | total_exp += op->stats.exp; |
1648 | exp_pr_sq=((double)1000*total_exp)/(MAP_WIDTH(m)*MAP_HEIGHT(m)+1); |
1642 | monster_cnt++; |
1649 | diff=20; |
1643 | } |
1650 | for(i=1;i<20;i++) |
1644 | |
1651 | if(exp_pr_sq<=level_exp(i,1.0)) { |
1645 | if(QUERY_FLAG (op, FLAG_GENERATOR)) |
1652 | diff=i; |
1646 | { |
1653 | break; |
1647 | total_exp += op->stats.exp; |
1654 | } |
1648 | at = type_to_archetype(GENERATE_TYPE (op)); |
1655 | #endif |
1649 | |
1656 | return diff; |
1650 | if(at != NULL) |
|
|
1651 | total_exp += at->clone.stats.exp * 8; |
|
|
1652 | |
|
|
1653 | monster_cnt++; |
|
|
1654 | } |
|
|
1655 | } |
|
|
1656 | |
|
|
1657 | avgexp = (double) total_exp / monster_cnt; |
|
|
1658 | |
|
|
1659 | for (i = 1; i <= settings.max_level; i++) |
|
|
1660 | { |
|
|
1661 | if ((level_exp (i, 1) - level_exp (i - 1, 1)) > (100 * avgexp)) |
|
|
1662 | { |
|
|
1663 | /* LOG(llevDebug, "Calculated difficulty for map: %s: %d\n", m->name, i); */ |
|
|
1664 | return i; |
|
|
1665 | } |
|
|
1666 | } |
1657 | } |
1667 | } |
1658 | |
1668 | |
1659 | void clean_tmp_map(mapstruct *m) { |
1669 | void clean_tmp_map(mapstruct *m) { |
1660 | if(m->tmpname == NULL) |
1670 | if(m->tmpname == NULL) |
1661 | return; |
1671 | return; |
|
|
1672 | if (clean_temporary_map_callback) |
|
|
1673 | clean_temporary_map_callback (m); |
1662 | (void) unlink(m->tmpname); |
1674 | (void) unlink(m->tmpname); |
1663 | } |
1675 | } |
1664 | |
1676 | |
1665 | void free_all_maps(void) |
1677 | void free_all_maps(void) |
1666 | { |
1678 | { |
… | |
… | |
1694 | return 0; |
1706 | return 0; |
1695 | } |
1707 | } |
1696 | |
1708 | |
1697 | /* inform all players on the map */ |
1709 | /* inform all players on the map */ |
1698 | if (change>0) |
1710 | if (change>0) |
1699 | new_info_map(NDI_BLACK, m,"It becomes darker."); |
1711 | new_info_map(NDI_BLACK|NDI_UNIQUE, m,"It becomes darker."); |
1700 | else |
1712 | else |
1701 | new_info_map(NDI_BLACK, m,"It becomes brighter."); |
1713 | new_info_map(NDI_BLACK|NDI_UNIQUE, m,"It becomes brighter."); |
1702 | |
1714 | |
1703 | /* Do extra checking. since m->darkness is a unsigned value, |
1715 | /* Do extra checking. since m->darkness is a unsigned value, |
1704 | * we need to be extra careful about negative values. |
1716 | * we need to be extra careful about negative values. |
1705 | * In general, the checks below are only needed if change |
1717 | * In general, the checks below are only needed if change |
1706 | * is not +/-1 |
1718 | * is not +/-1 |
… | |
… | |
1951 | * case. This generally shouldn't happen, but if the |
1963 | * case. This generally shouldn't happen, but if the |
1952 | * map loads fail below, it could happen. |
1964 | * map loads fail below, it could happen. |
1953 | */ |
1965 | */ |
1954 | if (!m) return 0; |
1966 | if (!m) return 0; |
1955 | |
1967 | |
1956 | /* Simple case - coordinates are within this local |
|
|
1957 | * map. |
|
|
1958 | */ |
|
|
1959 | if ( x>=0 && x<MAP_WIDTH(m) && y>=0 && y < MAP_HEIGHT(m)) |
|
|
1960 | return 0; |
|
|
1961 | |
|
|
1962 | if (x<0) { |
1968 | if (x<0) { |
1963 | if (!m->tile_path[3]) return 1; |
1969 | if (!m->tile_path[3]) return 1; |
1964 | if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) { |
1970 | if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) { |
1965 | load_and_link_tiled_map(m, 3); |
1971 | load_and_link_tiled_map(m, 3); |
1966 | } |
1972 | } |
… | |
… | |
1985 | if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY) { |
1991 | if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY) { |
1986 | load_and_link_tiled_map(m, 2); |
1992 | load_and_link_tiled_map(m, 2); |
1987 | } |
1993 | } |
1988 | return (out_of_map(m->tile_map[2], x, y - MAP_HEIGHT(m))); |
1994 | return (out_of_map(m->tile_map[2], x, y - MAP_HEIGHT(m))); |
1989 | } |
1995 | } |
|
|
1996 | |
|
|
1997 | /* Simple case - coordinates are within this local |
|
|
1998 | * map. |
|
|
1999 | */ |
1990 | return 1; |
2000 | return 0; |
1991 | } |
2001 | } |
1992 | |
2002 | |
1993 | /* This is basically the same as out_of_map above, but |
2003 | /* This is basically the same as out_of_map above, but |
1994 | * instead we return NULL if no map is valid (coordinates |
2004 | * instead we return NULL if no map is valid (coordinates |
1995 | * out of bounds and no tiled map), otherwise it returns |
2005 | * out of bounds and no tiled map), otherwise it returns |
… | |
… | |
1999 | * and then figuring out what the real map is |
2009 | * and then figuring out what the real map is |
2000 | */ |
2010 | */ |
2001 | mapstruct *get_map_from_coord(mapstruct *m, sint16 *x, sint16 *y) |
2011 | mapstruct *get_map_from_coord(mapstruct *m, sint16 *x, sint16 *y) |
2002 | { |
2012 | { |
2003 | |
2013 | |
2004 | /* Simple case - coordinates are within this local |
|
|
2005 | * map. |
|
|
2006 | */ |
|
|
2007 | |
|
|
2008 | if (*x>=0 && *x<MAP_WIDTH(m) && *y>=0 && *y < MAP_HEIGHT(m)) |
|
|
2009 | return m; |
|
|
2010 | |
|
|
2011 | if (*x<0) { |
2014 | if (*x<0) { |
2012 | if (!m->tile_path[3]) return NULL; |
2015 | if (!m->tile_path[3]) return NULL; |
2013 | if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) |
2016 | if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) |
2014 | load_and_link_tiled_map(m, 3); |
2017 | load_and_link_tiled_map(m, 3); |
2015 | |
2018 | |
… | |
… | |
2038 | load_and_link_tiled_map(m, 2); |
2041 | load_and_link_tiled_map(m, 2); |
2039 | |
2042 | |
2040 | *y -= MAP_HEIGHT(m); |
2043 | *y -= MAP_HEIGHT(m); |
2041 | return (get_map_from_coord(m->tile_map[2], x, y)); |
2044 | return (get_map_from_coord(m->tile_map[2], x, y)); |
2042 | } |
2045 | } |
2043 | return NULL; /* Shouldn't get here */ |
2046 | |
|
|
2047 | /* Simple case - coordinates are within this local |
|
|
2048 | * map. |
|
|
2049 | */ |
|
|
2050 | |
|
|
2051 | return m; |
2044 | } |
2052 | } |
2045 | |
2053 | |
2046 | /** |
2054 | /** |
2047 | * Return whether map2 is adjacent to map1. If so, store the distance from |
2055 | * Return whether map2 is adjacent to map1. If so, store the distance from |
2048 | * map1 to map2 in dx/dy. |
2056 | * map1 to map2 in dx/dy. |