1 | /* |
1 | /* |
2 | * static char *rcsid_map_c = |
2 | * static char *rcsid_map_c = |
3 | * "$Id: map.c,v 1.1.1.1 2006/02/03 07:11:37 root Exp $"; |
3 | * "$Id: map.c,v 1.8 2006/03/20 23:07:50 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 | |
… | |
… | |
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 | */ |
… | |
… | |
207 | * Prints out debug-information about a map. |
210 | * Prints out debug-information about a map. |
208 | * Dumping these at llevError doesn't seem right, but is |
211 | * Dumping these at llevError doesn't seem right, but is |
209 | * necessary to make sure the information is in fact logged. |
212 | * necessary to make sure the information is in fact logged. |
210 | */ |
213 | */ |
211 | |
214 | |
212 | void dump_map(mapstruct *m) { |
215 | void dump_map(const mapstruct *m) { |
213 | LOG(llevError,"Map %s status: %d.\n",m->path,m->in_memory); |
216 | LOG(llevError,"Map %s status: %d.\n",m->path,m->in_memory); |
214 | LOG(llevError,"Size: %dx%d Start: %d,%d\n", |
217 | LOG(llevError,"Size: %dx%d Start: %d,%d\n", |
215 | MAP_WIDTH(m), MAP_HEIGHT(m), |
218 | MAP_WIDTH(m), MAP_HEIGHT(m), |
216 | MAP_ENTER_X(m), MAP_ENTER_Y(m)); |
219 | MAP_ENTER_X(m), MAP_ENTER_Y(m)); |
217 | |
220 | |
218 | if(m->msg!=NULL) |
221 | if(m->msg!=NULL) |
219 | LOG(llevError,"Message:\n%s",m->msg); |
222 | LOG(llevError,"Message:\n%s",m->msg); |
|
|
223 | |
|
|
224 | if(m->maplore!=NULL) |
|
|
225 | LOG(llevError,"Lore:\n%s",m->maplore); |
220 | |
226 | |
221 | if(m->tmpname!=NULL) |
227 | if(m->tmpname!=NULL) |
222 | LOG(llevError,"Tmpname: %s\n",m->tmpname); |
228 | LOG(llevError,"Tmpname: %s\n",m->tmpname); |
223 | |
229 | |
224 | LOG(llevError,"Difficulty: %d\n",m->difficulty); |
230 | LOG(llevError,"Difficulty: %d\n",m->difficulty); |
… | |
… | |
304 | * go further. Not true for players - all sorts of special |
310 | * go further. Not true for players - all sorts of special |
305 | * things we need to do for players. |
311 | * things we need to do for players. |
306 | */ |
312 | */ |
307 | if (ob->type != PLAYER && ! (mflags & P_IS_ALIVE) && (blocked==0)) return 0; |
313 | if (ob->type != PLAYER && ! (mflags & P_IS_ALIVE) && (blocked==0)) return 0; |
308 | |
314 | |
|
|
315 | /* if there isn't anytyhing alive on this space, and this space isn't |
|
|
316 | * otherwise blocked, we can return now. Only if there is a living |
|
|
317 | * creature do we need to investigate if it is part of this creature |
|
|
318 | * or another. Likewise, only if something is blocking us do we |
|
|
319 | * need to investigate if there is a special circumstance that would |
|
|
320 | * let the player through (inventory checkers for example) |
|
|
321 | */ |
|
|
322 | if (!(mflags & P_IS_ALIVE) && !OB_TYPE_MOVE_BLOCK(ob, blocked)) return 0; |
309 | |
323 | |
310 | if(ob->head != NULL) |
324 | if(ob->head != NULL) |
311 | ob=ob->head; |
325 | ob=ob->head; |
312 | |
326 | |
313 | /* We basically go through the stack of objects, and if there is |
327 | /* We basically go through the stack of objects, and if there is |
… | |
… | |
381 | * Note this used to be arch_blocked, but with new movement |
395 | * Note this used to be arch_blocked, but with new movement |
382 | * code, we need to have actual object to check its move_type |
396 | * code, we need to have actual object to check its move_type |
383 | * against the move_block values. |
397 | * against the move_block values. |
384 | */ |
398 | */ |
385 | |
399 | |
386 | int ob_blocked(object *ob,mapstruct *m,sint16 x,sint16 y) { |
400 | int ob_blocked(const object *ob,mapstruct *m,sint16 x,sint16 y) { |
387 | archetype *tmp; |
401 | archetype *tmp; |
388 | int flag; |
402 | int flag; |
389 | mapstruct *m1; |
403 | mapstruct *m1; |
390 | sint16 sx, sy; |
404 | sint16 sx, sy; |
391 | |
405 | |
… | |
… | |
401 | flag = get_map_flags(m, &m1, x+tmp->clone.x,y+tmp->clone.y, &sx, &sy); |
415 | flag = get_map_flags(m, &m1, x+tmp->clone.x,y+tmp->clone.y, &sx, &sy); |
402 | |
416 | |
403 | if (flag & P_OUT_OF_MAP) return P_OUT_OF_MAP; |
417 | if (flag & P_OUT_OF_MAP) return P_OUT_OF_MAP; |
404 | if (flag & P_IS_ALIVE) return P_IS_ALIVE; |
418 | if (flag & P_IS_ALIVE) return P_IS_ALIVE; |
405 | |
419 | |
|
|
420 | /* find_first_free_spot() calls this function. However, often |
|
|
421 | * ob doesn't have any move type (when used to place exits) |
|
|
422 | * so the AND operation in OB_TYPE_MOVE_BLOCK doesn't work. |
|
|
423 | */ |
|
|
424 | |
|
|
425 | if (ob->move_type == 0 && GET_MAP_MOVE_BLOCK(m1, sx, sy) != MOVE_ALL) continue; |
|
|
426 | |
406 | /* Note it is intentional that we check ob - the movement type of the |
427 | /* Note it is intentional that we check ob - the movement type of the |
407 | * head of the object should correspond for the entire object. |
428 | * head of the object should correspond for the entire object. |
408 | */ |
429 | */ |
409 | |
|
|
410 | if (OB_TYPE_MOVE_BLOCK(ob, GET_MAP_MOVE_BLOCK(m1, sx, sy))) |
430 | if (OB_TYPE_MOVE_BLOCK(ob, GET_MAP_MOVE_BLOCK(m1, sx, sy))) |
411 | return AB_NO_PASS; |
431 | return AB_NO_PASS; |
412 | |
432 | |
413 | } |
433 | } |
414 | return 0; |
434 | return 0; |
… | |
… | |
659 | |
679 | |
660 | if(m->spaces==NULL) |
680 | if(m->spaces==NULL) |
661 | fatal(OUT_OF_MEMORY); |
681 | fatal(OUT_OF_MEMORY); |
662 | } |
682 | } |
663 | |
683 | |
664 | /* Creatures and returns a map of the specific size. Used |
684 | /* Create and returns a map of the specific size. Used |
665 | * in random map code and the editor. |
685 | * in random map code and the editor. |
666 | */ |
686 | */ |
667 | mapstruct *get_empty_map(int sizex, int sizey) { |
687 | mapstruct *get_empty_map(int sizex, int sizey) { |
668 | mapstruct *m = get_linked_map(); |
688 | mapstruct *m = get_linked_map(); |
669 | m->width = sizex; |
689 | m->width = sizex; |
… | |
… | |
778 | * return 0 on success, 1 on failure. |
798 | * return 0 on success, 1 on failure. |
779 | */ |
799 | */ |
780 | |
800 | |
781 | static int load_map_header(FILE *fp, mapstruct *m) |
801 | static int load_map_header(FILE *fp, mapstruct *m) |
782 | { |
802 | { |
783 | char buf[HUGE_BUF], msgbuf[HUGE_BUF], *key=NULL, *value, *end; |
803 | char buf[HUGE_BUF], msgbuf[HUGE_BUF], maplorebuf[HUGE_BUF], *key=NULL, *value, *end; |
784 | int msgpos=0; |
804 | int msgpos=0; |
|
|
805 | int maplorepos=0; |
785 | |
806 | |
786 | while (fgets(buf, HUGE_BUF-1, fp)!=NULL) { |
807 | while (fgets(buf, HUGE_BUF-1, fp)!=NULL) { |
787 | buf[HUGE_BUF-1] = 0; |
808 | buf[HUGE_BUF-1] = 0; |
788 | key = buf; |
809 | key = buf; |
789 | while (isspace(*key)) key++; |
810 | while (isspace(*key)) key++; |
… | |
… | |
843 | * keep the empty message. Also, msgbuf contains garbage data |
864 | * keep the empty message. Also, msgbuf contains garbage data |
844 | * when msgpos is zero, so copying it results in crashes |
865 | * when msgpos is zero, so copying it results in crashes |
845 | */ |
866 | */ |
846 | if (msgpos != 0) |
867 | if (msgpos != 0) |
847 | m->msg = strdup_local(msgbuf); |
868 | m->msg = strdup_local(msgbuf); |
|
|
869 | } |
|
|
870 | else if (!strcmp(key,"maplore")) { |
|
|
871 | while (fgets(buf, HUGE_BUF-1, fp)!=NULL) { |
|
|
872 | if (!strcmp(buf,"endmaplore\n")) break; |
|
|
873 | else { |
|
|
874 | /* slightly more efficient than strcat */ |
|
|
875 | strcpy(maplorebuf+maplorepos, buf); |
|
|
876 | maplorepos += strlen(buf); |
|
|
877 | } |
|
|
878 | } |
|
|
879 | if (maplorepos != 0) |
|
|
880 | m->maplore = strdup_local(maplorebuf); |
848 | } |
881 | } |
849 | else if (!strcmp(key,"end")) { |
882 | else if (!strcmp(key,"end")) { |
850 | break; |
883 | break; |
851 | } |
884 | } |
852 | else if (value == NULL) { |
885 | else if (value == NULL) { |
… | |
… | |
1019 | close_and_delete(fp, comp); |
1052 | close_and_delete(fp, comp); |
1020 | m->in_memory=MAP_IN_MEMORY; |
1053 | m->in_memory=MAP_IN_MEMORY; |
1021 | if (!MAP_DIFFICULTY(m)) |
1054 | if (!MAP_DIFFICULTY(m)) |
1022 | MAP_DIFFICULTY(m)=calculate_difficulty(m); |
1055 | MAP_DIFFICULTY(m)=calculate_difficulty(m); |
1023 | set_map_reset_time(m); |
1056 | set_map_reset_time(m); |
|
|
1057 | if (load_original_map_callback) |
|
|
1058 | load_original_map_callback(m); |
1024 | return (m); |
1059 | return (m); |
1025 | } |
1060 | } |
1026 | |
1061 | |
1027 | /* |
1062 | /* |
1028 | * Loads a map, which has been loaded earlier, from file. |
1063 | * Loads a map, which has been loaded earlier, from file. |
… | |
… | |
1068 | |
1103 | |
1069 | m->in_memory=MAP_LOADING; |
1104 | m->in_memory=MAP_LOADING; |
1070 | load_objects (m, fp, 0); |
1105 | load_objects (m, fp, 0); |
1071 | close_and_delete(fp, comp); |
1106 | close_and_delete(fp, comp); |
1072 | m->in_memory=MAP_IN_MEMORY; |
1107 | m->in_memory=MAP_IN_MEMORY; |
|
|
1108 | if (load_temporary_map_callback) |
|
|
1109 | load_temporary_map_callback(m); |
1073 | return m; |
1110 | return m; |
1074 | } |
1111 | } |
1075 | |
1112 | |
1076 | /* |
1113 | /* |
1077 | * Loads a map, which has been loaded earlier, from file. |
1114 | * Loads a map, which has been loaded earlier, from file. |
… | |
… | |
1113 | *****************************************************************************/ |
1150 | *****************************************************************************/ |
1114 | |
1151 | |
1115 | /* This goes through map 'm' and removed any unique items on the map. */ |
1152 | /* This goes through map 'm' and removed any unique items on the map. */ |
1116 | static void delete_unique_items(mapstruct *m) |
1153 | static void delete_unique_items(mapstruct *m) |
1117 | { |
1154 | { |
1118 | int i,j,unique=0; |
1155 | int i,j,unique; |
1119 | object *op, *next; |
1156 | object *op, *next; |
1120 | |
1157 | |
1121 | for(i=0; i<MAP_WIDTH(m); i++) |
1158 | for(i=0; i<MAP_WIDTH(m); i++) |
1122 | for(j=0; j<MAP_HEIGHT(m); j++) { |
1159 | for(j=0; j<MAP_HEIGHT(m); j++) { |
1123 | unique=0; |
1160 | unique=0; |
… | |
… | |
1259 | if (m->width) fprintf(fp,"width %d\n", m->width); |
1296 | if (m->width) fprintf(fp,"width %d\n", m->width); |
1260 | if (m->height) fprintf(fp,"height %d\n", m->height); |
1297 | if (m->height) fprintf(fp,"height %d\n", m->height); |
1261 | if (m->enter_x) fprintf(fp,"enter_x %d\n", m->enter_x); |
1298 | if (m->enter_x) fprintf(fp,"enter_x %d\n", m->enter_x); |
1262 | if (m->enter_y) fprintf(fp,"enter_y %d\n", m->enter_y); |
1299 | if (m->enter_y) fprintf(fp,"enter_y %d\n", m->enter_y); |
1263 | if (m->msg) fprintf(fp,"msg\n%sendmsg\n", m->msg); |
1300 | if (m->msg) fprintf(fp,"msg\n%sendmsg\n", m->msg); |
|
|
1301 | if (m->maplore) fprintf(fp,"maplore\n%sendmaplore\n", m->maplore); |
1264 | if (m->unique) fprintf(fp,"unique %d\n", m->unique); |
1302 | if (m->unique) fprintf(fp,"unique %d\n", m->unique); |
1265 | if (m->template) fprintf(fp,"template %d\n", m->template); |
1303 | if (m->template) fprintf(fp,"template %d\n", m->template); |
1266 | if (m->outdoor) fprintf(fp,"outdoor %d\n", m->outdoor); |
1304 | if (m->outdoor) fprintf(fp,"outdoor %d\n", m->outdoor); |
1267 | if (m->temp) fprintf(fp, "temp %d\n", m->temp); |
1305 | if (m->temp) fprintf(fp, "temp %d\n", m->temp); |
1268 | if (m->pressure) fprintf(fp, "pressure %d\n", m->pressure); |
1306 | if (m->pressure) fprintf(fp, "pressure %d\n", m->pressure); |
… | |
… | |
1395 | } |
1433 | } |
1396 | if (flag && m->spaces) free_all_objects(m); |
1434 | if (flag && m->spaces) free_all_objects(m); |
1397 | if (m->name) FREE_AND_CLEAR(m->name); |
1435 | if (m->name) FREE_AND_CLEAR(m->name); |
1398 | if (m->spaces) FREE_AND_CLEAR(m->spaces); |
1436 | if (m->spaces) FREE_AND_CLEAR(m->spaces); |
1399 | if (m->msg) FREE_AND_CLEAR(m->msg); |
1437 | if (m->msg) FREE_AND_CLEAR(m->msg); |
|
|
1438 | if (m->maplore) FREE_AND_CLEAR(m->maplore); |
1400 | if (m->shopitems) FREE_AND_CLEAR(m->shopitems); |
1439 | if (m->shopitems) FREE_AND_CLEAR(m->shopitems); |
1401 | if (m->shoprace) FREE_AND_CLEAR(m->shoprace); |
1440 | if (m->shoprace) FREE_AND_CLEAR(m->shoprace); |
1402 | if (m->buttons) |
1441 | if (m->buttons) |
1403 | free_objectlinkpt(m->buttons); |
1442 | free_objectlinkpt(m->buttons); |
1404 | m->buttons = NULL; |
1443 | m->buttons = NULL; |
… | |
… | |
1625 | } |
1664 | } |
1626 | |
1665 | |
1627 | void clean_tmp_map(mapstruct *m) { |
1666 | void clean_tmp_map(mapstruct *m) { |
1628 | if(m->tmpname == NULL) |
1667 | if(m->tmpname == NULL) |
1629 | return; |
1668 | return; |
|
|
1669 | if (clean_temporary_map_callback) |
|
|
1670 | clean_temporary_map_callback (m); |
1630 | (void) unlink(m->tmpname); |
1671 | (void) unlink(m->tmpname); |
1631 | } |
1672 | } |
1632 | |
1673 | |
1633 | void free_all_maps(void) |
1674 | void free_all_maps(void) |
1634 | { |
1675 | { |
… | |
… | |
1692 | void update_position (mapstruct *m, int x, int y) { |
1733 | void update_position (mapstruct *m, int x, int y) { |
1693 | object *tmp, *last = NULL; |
1734 | object *tmp, *last = NULL; |
1694 | uint8 flags = 0, oldflags, light=0, anywhere=0; |
1735 | uint8 flags = 0, oldflags, light=0, anywhere=0; |
1695 | New_Face *top,*floor, *middle; |
1736 | New_Face *top,*floor, *middle; |
1696 | object *top_obj, *floor_obj, *middle_obj; |
1737 | object *top_obj, *floor_obj, *middle_obj; |
1697 | MoveType move_block=0, move_slow=0, move_on=0, move_off=0; |
1738 | MoveType move_block=0, move_slow=0, move_on=0, move_off=0, move_allow=0; |
1698 | |
1739 | |
1699 | oldflags = GET_MAP_FLAGS(m,x,y); |
1740 | oldflags = GET_MAP_FLAGS(m,x,y); |
1700 | if (!(oldflags & P_NEED_UPDATE)) { |
1741 | if (!(oldflags & P_NEED_UPDATE)) { |
1701 | LOG(llevDebug,"update_position called with P_NEED_UPDATE not set: %s (%d, %d)\n", |
1742 | LOG(llevDebug,"update_position called with P_NEED_UPDATE not set: %s (%d, %d)\n", |
1702 | m->path, x, y); |
1743 | m->path, x, y); |
… | |
… | |
1765 | |
1806 | |
1766 | move_slow |= tmp->move_slow; |
1807 | move_slow |= tmp->move_slow; |
1767 | move_block |= tmp->move_block; |
1808 | move_block |= tmp->move_block; |
1768 | move_on |= tmp->move_on; |
1809 | move_on |= tmp->move_on; |
1769 | move_off |= tmp->move_off; |
1810 | move_off |= tmp->move_off; |
|
|
1811 | move_allow |= tmp->move_allow; |
1770 | |
1812 | |
1771 | if (QUERY_FLAG(tmp,FLAG_ALIVE)) |
1813 | if (QUERY_FLAG(tmp,FLAG_ALIVE)) |
1772 | flags |= P_IS_ALIVE; |
1814 | flags |= P_IS_ALIVE; |
1773 | if (QUERY_FLAG(tmp,FLAG_NO_MAGIC)) |
1815 | if (QUERY_FLAG(tmp,FLAG_NO_MAGIC)) |
1774 | flags |= P_NO_MAGIC; |
1816 | flags |= P_NO_MAGIC; |
… | |
… | |
1788 | LOG(llevDebug,"update_position: updated flags do not match old flags: %s (old=%d,new=%d) %x != %x\n", |
1830 | LOG(llevDebug,"update_position: updated flags do not match old flags: %s (old=%d,new=%d) %x != %x\n", |
1789 | m->path, x, y, |
1831 | m->path, x, y, |
1790 | (oldflags & ~P_NEED_UPDATE), flags); |
1832 | (oldflags & ~P_NEED_UPDATE), flags); |
1791 | } |
1833 | } |
1792 | SET_MAP_FLAGS(m, x, y, flags); |
1834 | SET_MAP_FLAGS(m, x, y, flags); |
1793 | SET_MAP_MOVE_BLOCK(m, x, y, move_block); |
1835 | SET_MAP_MOVE_BLOCK(m, x, y, move_block & ~move_allow); |
1794 | SET_MAP_MOVE_ON(m, x, y, move_on); |
1836 | SET_MAP_MOVE_ON(m, x, y, move_on); |
1795 | SET_MAP_MOVE_OFF(m, x, y, move_off); |
1837 | SET_MAP_MOVE_OFF(m, x, y, move_off); |
1796 | SET_MAP_MOVE_SLOW(m, x, y, move_slow); |
1838 | SET_MAP_MOVE_SLOW(m, x, y, move_slow); |
1797 | |
1839 | |
1798 | /* At this point, we have a floor face (if there is a floor), |
1840 | /* At this point, we have a floor face (if there is a floor), |
… | |
… | |
1918 | * case. This generally shouldn't happen, but if the |
1960 | * case. This generally shouldn't happen, but if the |
1919 | * map loads fail below, it could happen. |
1961 | * map loads fail below, it could happen. |
1920 | */ |
1962 | */ |
1921 | if (!m) return 0; |
1963 | if (!m) return 0; |
1922 | |
1964 | |
1923 | /* Simple case - coordinates are within this local |
|
|
1924 | * map. |
|
|
1925 | */ |
|
|
1926 | if ( x>=0 && x<MAP_WIDTH(m) && y>=0 && y < MAP_HEIGHT(m)) |
|
|
1927 | return 0; |
|
|
1928 | |
|
|
1929 | if (x<0) { |
1965 | if (x<0) { |
1930 | if (!m->tile_path[3]) return 1; |
1966 | if (!m->tile_path[3]) return 1; |
1931 | if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) { |
1967 | if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) { |
1932 | load_and_link_tiled_map(m, 3); |
1968 | load_and_link_tiled_map(m, 3); |
1933 | } |
1969 | } |
… | |
… | |
1952 | if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY) { |
1988 | if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY) { |
1953 | load_and_link_tiled_map(m, 2); |
1989 | load_and_link_tiled_map(m, 2); |
1954 | } |
1990 | } |
1955 | return (out_of_map(m->tile_map[2], x, y - MAP_HEIGHT(m))); |
1991 | return (out_of_map(m->tile_map[2], x, y - MAP_HEIGHT(m))); |
1956 | } |
1992 | } |
|
|
1993 | |
|
|
1994 | /* Simple case - coordinates are within this local |
|
|
1995 | * map. |
|
|
1996 | */ |
1957 | return 1; |
1997 | return 0; |
1958 | } |
1998 | } |
1959 | |
1999 | |
1960 | /* This is basically the same as out_of_map above, but |
2000 | /* This is basically the same as out_of_map above, but |
1961 | * instead we return NULL if no map is valid (coordinates |
2001 | * instead we return NULL if no map is valid (coordinates |
1962 | * out of bounds and no tiled map), otherwise it returns |
2002 | * out of bounds and no tiled map), otherwise it returns |
… | |
… | |
1966 | * and then figuring out what the real map is |
2006 | * and then figuring out what the real map is |
1967 | */ |
2007 | */ |
1968 | mapstruct *get_map_from_coord(mapstruct *m, sint16 *x, sint16 *y) |
2008 | mapstruct *get_map_from_coord(mapstruct *m, sint16 *x, sint16 *y) |
1969 | { |
2009 | { |
1970 | |
2010 | |
1971 | /* Simple case - coordinates are within this local |
|
|
1972 | * map. |
|
|
1973 | */ |
|
|
1974 | |
|
|
1975 | if (*x>=0 && *x<MAP_WIDTH(m) && *y>=0 && *y < MAP_HEIGHT(m)) |
|
|
1976 | return m; |
|
|
1977 | |
|
|
1978 | if (*x<0) { |
2011 | if (*x<0) { |
1979 | if (!m->tile_path[3]) return NULL; |
2012 | if (!m->tile_path[3]) return NULL; |
1980 | if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) |
2013 | if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) |
1981 | load_and_link_tiled_map(m, 3); |
2014 | load_and_link_tiled_map(m, 3); |
1982 | |
2015 | |
… | |
… | |
2005 | load_and_link_tiled_map(m, 2); |
2038 | load_and_link_tiled_map(m, 2); |
2006 | |
2039 | |
2007 | *y -= MAP_HEIGHT(m); |
2040 | *y -= MAP_HEIGHT(m); |
2008 | return (get_map_from_coord(m->tile_map[2], x, y)); |
2041 | return (get_map_from_coord(m->tile_map[2], x, y)); |
2009 | } |
2042 | } |
2010 | return NULL; /* Shouldn't get here */ |
2043 | |
|
|
2044 | /* Simple case - coordinates are within this local |
|
|
2045 | * map. |
|
|
2046 | */ |
|
|
2047 | |
|
|
2048 | return m; |
|
|
2049 | } |
|
|
2050 | |
|
|
2051 | /** |
|
|
2052 | * Return whether map2 is adjacent to map1. If so, store the distance from |
|
|
2053 | * map1 to map2 in dx/dy. |
|
|
2054 | */ |
|
|
2055 | static int adjacent_map(const mapstruct *map1, const mapstruct *map2, int *dx, int *dy) { |
|
|
2056 | if (!map1 || !map2) |
|
|
2057 | return 0; |
|
|
2058 | |
|
|
2059 | if (map1 == map2) { |
|
|
2060 | *dx = 0; |
|
|
2061 | *dy = 0; |
|
|
2062 | |
|
|
2063 | } else if (map1->tile_map[0] == map2) { /* up */ |
|
|
2064 | *dx = 0; |
|
|
2065 | *dy = -MAP_HEIGHT(map2); |
|
|
2066 | } else if (map1->tile_map[1] == map2) { /* right */ |
|
|
2067 | *dx = MAP_WIDTH(map1); |
|
|
2068 | *dy = 0; |
|
|
2069 | } else if (map1->tile_map[2] == map2) { /* down */ |
|
|
2070 | *dx = 0; |
|
|
2071 | *dy = MAP_HEIGHT(map1); |
|
|
2072 | } else if (map1->tile_map[3] == map2) { /* left */ |
|
|
2073 | *dx = -MAP_WIDTH(map2); |
|
|
2074 | *dy = 0; |
|
|
2075 | |
|
|
2076 | } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[1] == map2) { /* up right */ |
|
|
2077 | *dx = MAP_WIDTH(map1->tile_map[0]); |
|
|
2078 | *dy = -MAP_HEIGHT(map1->tile_map[0]); |
|
|
2079 | } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[3] == map2) { /* up left */ |
|
|
2080 | *dx = -MAP_WIDTH(map2); |
|
|
2081 | *dy = -MAP_HEIGHT(map1->tile_map[0]); |
|
|
2082 | } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[0] == map2) { /* right up */ |
|
|
2083 | *dx = MAP_WIDTH(map1); |
|
|
2084 | *dy = -MAP_HEIGHT(map2); |
|
|
2085 | } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[2] == map2) { /* right down */ |
|
|
2086 | *dx = MAP_WIDTH(map1); |
|
|
2087 | *dy = MAP_HEIGHT(map1->tile_map[1]); |
|
|
2088 | } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[1] == map2) { /* down right */ |
|
|
2089 | *dx = MAP_WIDTH(map1->tile_map[2]); |
|
|
2090 | *dy = MAP_HEIGHT(map1); |
|
|
2091 | } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[3] == map2) { /* down left */ |
|
|
2092 | *dx = -MAP_WIDTH(map2); |
|
|
2093 | *dy = MAP_HEIGHT(map1); |
|
|
2094 | } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[0] == map2) { /* left up */ |
|
|
2095 | *dx = -MAP_WIDTH(map1->tile_map[3]); |
|
|
2096 | *dy = -MAP_HEIGHT(map2); |
|
|
2097 | } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[2] == map2) { /* left down */ |
|
|
2098 | *dx = -MAP_WIDTH(map1->tile_map[3]); |
|
|
2099 | *dy = MAP_HEIGHT(map1->tile_map[3]); |
|
|
2100 | |
|
|
2101 | } else { /* not "adjacent" enough */ |
|
|
2102 | return 0; |
|
|
2103 | } |
|
|
2104 | |
|
|
2105 | return 1; |
2011 | } |
2106 | } |
2012 | |
2107 | |
2013 | /* From map.c |
2108 | /* From map.c |
2014 | * This is used by get_player to determine where the other |
2109 | * This is used by get_player to determine where the other |
2015 | * creature is. get_rangevector takes into account map tiling, |
2110 | * creature is. get_rangevector takes into account map tiling, |
… | |
… | |
2029 | * |
2124 | * |
2030 | * currently, the only flag supported (0x1) is don't translate for |
2125 | * currently, the only flag supported (0x1) is don't translate for |
2031 | * closest body part of 'op1' |
2126 | * closest body part of 'op1' |
2032 | */ |
2127 | */ |
2033 | |
2128 | |
2034 | void get_rangevector(object *op1, object *op2, rv_vector *retval, int flags) |
2129 | void get_rangevector(object *op1, object *op2, rv_vector *retval, int flags) { |
2035 | { |
2130 | if (!adjacent_map(op1->map, op2->map, &retval->distance_x, &retval->distance_y)) { |
|
|
2131 | /* be conservative and fill in _some_ data */ |
|
|
2132 | retval->distance = 100000; |
|
|
2133 | retval->distance_x = 32767; |
|
|
2134 | retval->distance_y = 32767; |
|
|
2135 | retval->direction = 0; |
|
|
2136 | retval->part = 0; |
|
|
2137 | } else { |
2036 | object *best; |
2138 | object *best; |
2037 | |
2139 | |
2038 | if (op1->map->tile_map[0] == op2->map) { |
|
|
2039 | retval->distance_x = op2->x - op1->x; |
2140 | retval->distance_x += op2->x-op1->x; |
2040 | retval->distance_y = -(op1->y +(MAP_HEIGHT(op2->map)- op2->y)); |
|
|
2041 | |
|
|
2042 | } |
|
|
2043 | else if (op1->map->tile_map[1] == op2->map) { |
|
|
2044 | retval->distance_y = op2->y - op1->y; |
2141 | retval->distance_y += op2->y-op1->y; |
2045 | retval->distance_x = (MAP_WIDTH(op1->map) - op1->x) + op2->x; |
|
|
2046 | } |
|
|
2047 | else if (op1->map->tile_map[2] == op2->map) { |
|
|
2048 | retval->distance_x = op2->x - op1->x; |
|
|
2049 | retval->distance_y = (MAP_HEIGHT(op1->map) - op1->y) +op2->y; |
|
|
2050 | |
2142 | |
2051 | } |
|
|
2052 | else if (op1->map->tile_map[3] == op2->map) { |
|
|
2053 | retval->distance_y = op2->y - op1->y; |
|
|
2054 | retval->distance_x = -(op1->x +(MAP_WIDTH(op2->map)- op2->x)); |
|
|
2055 | } |
|
|
2056 | else if (op1->map == op2->map) { |
|
|
2057 | retval->distance_x = op2->x - op1->x; |
|
|
2058 | retval->distance_y = op2->y - op1->y; |
|
|
2059 | |
|
|
2060 | } |
|
|
2061 | best = op1; |
2143 | best = op1; |
2062 | /* If this is multipart, find the closest part now */ |
2144 | /* If this is multipart, find the closest part now */ |
2063 | if (!(flags & 0x1) && op1->more) { |
2145 | if (!(flags&0x1) && op1->more) { |
2064 | object *tmp; |
2146 | object *tmp; |
2065 | int best_distance = retval->distance_x * retval->distance_x + |
2147 | int best_distance = retval->distance_x*retval->distance_x+ |
2066 | retval->distance_y * retval->distance_y, tmpi; |
2148 | retval->distance_y*retval->distance_y, tmpi; |
2067 | |
2149 | |
2068 | /* we just tkae the offset of the piece to head to figure |
2150 | /* we just take the offset of the piece to head to figure |
2069 | * distance instead of doing all that work above again |
2151 | * distance instead of doing all that work above again |
2070 | * since the distance fields we set above are positive in the |
2152 | * since the distance fields we set above are positive in the |
2071 | * same axis as is used for multipart objects, the simply arithemetic |
2153 | * same axis as is used for multipart objects, the simply arithmetic |
2072 | * below works. |
2154 | * below works. |
2073 | */ |
2155 | */ |
2074 | for (tmp=op1->more; tmp; tmp=tmp->more) { |
2156 | for (tmp = op1->more; tmp != NULL; tmp = tmp->more) { |
2075 | tmpi = (op1->x - tmp->x + retval->distance_x) * (op1->x - tmp->x + retval->distance_x) + |
2157 | tmpi = (op1->x-tmp->x+retval->distance_x)*(op1->x-tmp->x+retval->distance_x)+ |
2076 | (op1->y - tmp->y + retval->distance_y) * (op1->y - tmp->y + retval->distance_y); |
2158 | (op1->y-tmp->y+retval->distance_y)*(op1->y-tmp->y+retval->distance_y); |
2077 | if (tmpi < best_distance) { |
2159 | if (tmpi < best_distance) { |
2078 | best_distance = tmpi; |
2160 | best_distance = tmpi; |
2079 | best = tmp; |
2161 | best = tmp; |
2080 | } |
2162 | } |
2081 | } |
2163 | } |
2082 | if (best != op1) { |
2164 | if (best != op1) { |
2083 | retval->distance_x += op1->x - best->x; |
2165 | retval->distance_x += op1->x-best->x; |
2084 | retval->distance_y += op1->y - best->y; |
2166 | retval->distance_y += op1->y-best->y; |
2085 | } |
2167 | } |
2086 | } |
2168 | } |
2087 | retval->part = best; |
2169 | retval->part = best; |
2088 | retval->distance = isqrt(retval->distance_x*retval->distance_x + retval->distance_y*retval->distance_y); |
2170 | retval->distance = isqrt(retval->distance_x*retval->distance_x+retval->distance_y*retval->distance_y); |
2089 | retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y); |
2171 | retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y); |
|
|
2172 | } |
2090 | } |
2173 | } |
2091 | |
2174 | |
2092 | /* this is basically the same as get_rangevector above, but instead of |
2175 | /* this is basically the same as get_rangevector above, but instead of |
2093 | * the first parameter being an object, it instead is the map |
2176 | * the first parameter being an object, it instead is the map |
2094 | * and x,y coordinates - this is used for path to player - |
2177 | * and x,y coordinates - this is used for path to player - |
… | |
… | |
2098 | * be more consistant with the above function and also in case they are needed |
2181 | * be more consistant with the above function and also in case they are needed |
2099 | * for something in the future. Also, since no object is pasted, the best |
2182 | * for something in the future. Also, since no object is pasted, the best |
2100 | * field of the rv_vector is set to NULL. |
2183 | * field of the rv_vector is set to NULL. |
2101 | */ |
2184 | */ |
2102 | |
2185 | |
2103 | void get_rangevector_from_mapcoord(mapstruct *m, int x, int y, object *op2, rv_vector *retval,int flags) |
2186 | void get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval, int flags) { |
2104 | { |
2187 | if (!adjacent_map(m, op2->map, &retval->distance_x, &retval->distance_y)) { |
2105 | if (m->tile_map[0] == op2->map) { |
2188 | /* be conservative and fill in _some_ data */ |
|
|
2189 | retval->distance = 100000; |
|
|
2190 | retval->distance_x = 32767; |
|
|
2191 | retval->distance_y = 32767; |
|
|
2192 | retval->direction = 0; |
|
|
2193 | retval->part = 0; |
|
|
2194 | } else { |
2106 | retval->distance_x = op2->x - x; |
2195 | retval->distance_x += op2->x-x; |
2107 | retval->distance_y = -(y +(MAP_HEIGHT(op2->map)- op2->y)); |
|
|
2108 | |
|
|
2109 | } |
|
|
2110 | else if (m->tile_map[1] == op2->map) { |
|
|
2111 | retval->distance_y = op2->y - y; |
2196 | retval->distance_y += op2->y-y; |
2112 | retval->distance_x = (MAP_WIDTH(m) - x) + op2->x; |
|
|
2113 | } |
|
|
2114 | else if (m->tile_map[2] == op2->map) { |
|
|
2115 | retval->distance_x = op2->x - x; |
|
|
2116 | retval->distance_y = (MAP_HEIGHT(m) - y) +op2->y; |
|
|
2117 | |
2197 | |
2118 | } |
|
|
2119 | else if (m->tile_map[3] == op2->map) { |
|
|
2120 | retval->distance_y = op2->y - y; |
|
|
2121 | retval->distance_x = -(x +(MAP_WIDTH(op2->map)- op2->y)); |
|
|
2122 | } |
|
|
2123 | else if (m == op2->map) { |
|
|
2124 | retval->distance_x = op2->x - x; |
|
|
2125 | retval->distance_y = op2->y - y; |
|
|
2126 | |
|
|
2127 | } |
|
|
2128 | retval->part = NULL; |
2198 | retval->part = NULL; |
2129 | retval->distance = isqrt(retval->distance_x*retval->distance_x + retval->distance_y*retval->distance_y); |
2199 | retval->distance = isqrt(retval->distance_x*retval->distance_x+retval->distance_y*retval->distance_y); |
2130 | retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y); |
2200 | retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y); |
|
|
2201 | } |
2131 | } |
2202 | } |
2132 | |
2203 | |
2133 | /* Returns true of op1 and op2 are effectively on the same map |
2204 | /* Returns true of op1 and op2 are effectively on the same map |
2134 | * (as related to map tiling). Note that this looks for a path from |
2205 | * (as related to map tiling). Note that this looks for a path from |
2135 | * op1 to op2, so if the tiled maps are assymetric and op2 has a path |
2206 | * op1 to op2, so if the tiled maps are assymetric and op2 has a path |
2136 | * to op1, this will still return false. |
2207 | * to op1, this will still return false. |
2137 | * Note we only look one map out to keep the processing simple |
2208 | * Note we only look one map out to keep the processing simple |
2138 | * and efficient. This could probably be a macro. |
2209 | * and efficient. This could probably be a macro. |
2139 | * MSW 2001-08-05 |
2210 | * MSW 2001-08-05 |
2140 | */ |
2211 | */ |
2141 | int on_same_map(object *op1, object *op2) |
2212 | int on_same_map(const object *op1, const object *op2) { |
2142 | { |
2213 | int dx, dy; |
2143 | mapstruct *tmp; |
|
|
2144 | |
2214 | |
2145 | /* If the object isn't on a map, can't be on the same map, now can it? |
2215 | return adjacent_map(op1->map, op2->map, &dx, &dy); |
2146 | * this check also prevents crashes below. |
|
|
2147 | */ |
|
|
2148 | if (op1->map == NULL || op2->map == NULL) return FALSE; |
|
|
2149 | |
|
|
2150 | /* on same map? */ |
|
|
2151 | if (op1->map == op2->map) return TRUE; |
|
|
2152 | |
|
|
2153 | /* on adjacent map? */ |
|
|
2154 | if (op1->map->tile_map[0] == op2->map) return TRUE; |
|
|
2155 | if (op1->map->tile_map[1] == op2->map) return TRUE; |
|
|
2156 | if (op1->map->tile_map[2] == op2->map) return TRUE; |
|
|
2157 | if (op1->map->tile_map[3] == op2->map) return TRUE; |
|
|
2158 | |
|
|
2159 | /* on diagonally adjacent map? */ |
|
|
2160 | tmp = op1->map->tile_map[0]; |
|
|
2161 | if (tmp != NULL) { |
|
|
2162 | if (tmp->tile_map[1] == op2->map || tmp->tile_map[3] == op2->map) return TRUE; |
|
|
2163 | } |
|
|
2164 | |
|
|
2165 | tmp = op1->map->tile_map[1]; |
|
|
2166 | if (tmp != NULL) { |
|
|
2167 | if (tmp->tile_map[0] == op2->map || tmp->tile_map[2] == op2->map) return TRUE; |
|
|
2168 | } |
|
|
2169 | |
|
|
2170 | tmp = op1->map->tile_map[2]; |
|
|
2171 | if (tmp != NULL) { |
|
|
2172 | if (tmp->tile_map[1] == op2->map || tmp->tile_map[3] == op2->map) return TRUE; |
|
|
2173 | } |
|
|
2174 | |
|
|
2175 | tmp = op1->map->tile_map[3]; |
|
|
2176 | if (tmp != NULL) { |
|
|
2177 | if (tmp->tile_map[0] == op2->map || tmp->tile_map[2] == op2->map) return TRUE; |
|
|
2178 | } |
|
|
2179 | |
|
|
2180 | return FALSE; |
|
|
2181 | } |
2216 | } |