1 | /* |
1 | /* |
2 | * static char *rcsid_map_c = |
2 | * static char *rcsid_map_c = |
3 | * "$Id: map.c,v 1.2 2006/02/08 03:46:15 root Exp $"; |
3 | * "$Id: map.c,v 1.9 2006/03/28 06:54:31 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; |
… | |
… | |
570 | * 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 |
571 | * in order to do map tiling properly. |
591 | * in order to do map tiling properly. |
572 | */ |
592 | */ |
573 | void save_objects (mapstruct *m, FILE *fp, FILE *fp2, int flag) { |
593 | void save_objects (mapstruct *m, FILE *fp, FILE *fp2, int flag) { |
574 | int i, j = 0,unique=0; |
594 | int i, j = 0,unique=0; |
575 | object *op, *otmp; |
595 | object *op; |
576 | /* first pass - save one-part objects */ |
596 | /* first pass - save one-part objects */ |
577 | for(i = 0; i < MAP_WIDTH(m); i++) |
597 | for(i = 0; i < MAP_WIDTH(m); i++) |
578 | for (j = 0; j < MAP_HEIGHT(m); j++) { |
598 | for (j = 0; j < MAP_HEIGHT(m); j++) { |
579 | unique=0; |
599 | unique=0; |
580 | for(op = get_map_ob (m, i, j); op; op = otmp) { |
600 | for(op = get_map_ob (m, i, j); op; op = op->above) { |
581 | otmp = op->above; |
|
|
582 | |
|
|
583 | 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)) |
584 | unique=1; |
602 | unique=1; |
585 | |
603 | |
586 | if(op->type == PLAYER) { |
604 | if(op->type == PLAYER) { |
587 | LOG(llevDebug, "Player on map that is being saved\n"); |
605 | LOG(llevDebug, "Player on map that is being saved\n"); |
… | |
… | |
659 | |
677 | |
660 | if(m->spaces==NULL) |
678 | if(m->spaces==NULL) |
661 | fatal(OUT_OF_MEMORY); |
679 | fatal(OUT_OF_MEMORY); |
662 | } |
680 | } |
663 | |
681 | |
664 | /* Creatures and returns a map of the specific size. Used |
682 | /* Create and returns a map of the specific size. Used |
665 | * in random map code and the editor. |
683 | * in random map code and the editor. |
666 | */ |
684 | */ |
667 | mapstruct *get_empty_map(int sizex, int sizey) { |
685 | mapstruct *get_empty_map(int sizex, int sizey) { |
668 | mapstruct *m = get_linked_map(); |
686 | mapstruct *m = get_linked_map(); |
669 | m->width = sizex; |
687 | m->width = sizex; |
… | |
… | |
778 | * return 0 on success, 1 on failure. |
796 | * return 0 on success, 1 on failure. |
779 | */ |
797 | */ |
780 | |
798 | |
781 | static int load_map_header(FILE *fp, mapstruct *m) |
799 | static int load_map_header(FILE *fp, mapstruct *m) |
782 | { |
800 | { |
783 | char buf[HUGE_BUF], msgbuf[HUGE_BUF], *key=NULL, *value, *end; |
801 | char buf[HUGE_BUF], msgbuf[HUGE_BUF], maplorebuf[HUGE_BUF], *key=NULL, *value, *end; |
784 | int msgpos=0; |
802 | int msgpos=0; |
|
|
803 | int maplorepos=0; |
785 | |
804 | |
786 | while (fgets(buf, HUGE_BUF-1, fp)!=NULL) { |
805 | while (fgets(buf, HUGE_BUF-1, fp)!=NULL) { |
787 | buf[HUGE_BUF-1] = 0; |
806 | buf[HUGE_BUF-1] = 0; |
788 | key = buf; |
807 | key = buf; |
789 | while (isspace(*key)) key++; |
808 | while (isspace(*key)) key++; |
… | |
… | |
843 | * keep the empty message. Also, msgbuf contains garbage data |
862 | * keep the empty message. Also, msgbuf contains garbage data |
844 | * when msgpos is zero, so copying it results in crashes |
863 | * when msgpos is zero, so copying it results in crashes |
845 | */ |
864 | */ |
846 | if (msgpos != 0) |
865 | if (msgpos != 0) |
847 | m->msg = strdup_local(msgbuf); |
866 | m->msg = strdup_local(msgbuf); |
|
|
867 | } |
|
|
868 | else if (!strcmp(key,"maplore")) { |
|
|
869 | while (fgets(buf, HUGE_BUF-1, fp)!=NULL) { |
|
|
870 | if (!strcmp(buf,"endmaplore\n")) break; |
|
|
871 | else { |
|
|
872 | /* slightly more efficient than strcat */ |
|
|
873 | strcpy(maplorebuf+maplorepos, buf); |
|
|
874 | maplorepos += strlen(buf); |
|
|
875 | } |
|
|
876 | } |
|
|
877 | if (maplorepos != 0) |
|
|
878 | m->maplore = strdup_local(maplorebuf); |
848 | } |
879 | } |
849 | else if (!strcmp(key,"end")) { |
880 | else if (!strcmp(key,"end")) { |
850 | break; |
881 | break; |
851 | } |
882 | } |
852 | else if (value == NULL) { |
883 | else if (value == NULL) { |
… | |
… | |
1019 | close_and_delete(fp, comp); |
1050 | close_and_delete(fp, comp); |
1020 | m->in_memory=MAP_IN_MEMORY; |
1051 | m->in_memory=MAP_IN_MEMORY; |
1021 | if (!MAP_DIFFICULTY(m)) |
1052 | if (!MAP_DIFFICULTY(m)) |
1022 | MAP_DIFFICULTY(m)=calculate_difficulty(m); |
1053 | MAP_DIFFICULTY(m)=calculate_difficulty(m); |
1023 | set_map_reset_time(m); |
1054 | set_map_reset_time(m); |
|
|
1055 | if (load_original_map_callback) |
|
|
1056 | load_original_map_callback(m); |
1024 | return (m); |
1057 | return (m); |
1025 | } |
1058 | } |
1026 | |
1059 | |
1027 | /* |
1060 | /* |
1028 | * Loads a map, which has been loaded earlier, from file. |
1061 | * Loads a map, which has been loaded earlier, from file. |
… | |
… | |
1068 | |
1101 | |
1069 | m->in_memory=MAP_LOADING; |
1102 | m->in_memory=MAP_LOADING; |
1070 | load_objects (m, fp, 0); |
1103 | load_objects (m, fp, 0); |
1071 | close_and_delete(fp, comp); |
1104 | close_and_delete(fp, comp); |
1072 | m->in_memory=MAP_IN_MEMORY; |
1105 | m->in_memory=MAP_IN_MEMORY; |
|
|
1106 | if (load_temporary_map_callback) |
|
|
1107 | load_temporary_map_callback(m); |
1073 | return m; |
1108 | return m; |
1074 | } |
1109 | } |
1075 | |
1110 | |
1076 | /* |
1111 | /* |
1077 | * Loads a map, which has been loaded earlier, from file. |
1112 | * Loads a map, which has been loaded earlier, from file. |
… | |
… | |
1113 | *****************************************************************************/ |
1148 | *****************************************************************************/ |
1114 | |
1149 | |
1115 | /* This goes through map 'm' and removed any unique items on the map. */ |
1150 | /* This goes through map 'm' and removed any unique items on the map. */ |
1116 | static void delete_unique_items(mapstruct *m) |
1151 | static void delete_unique_items(mapstruct *m) |
1117 | { |
1152 | { |
1118 | int i,j,unique=0; |
1153 | int i,j,unique; |
1119 | object *op, *next; |
1154 | object *op, *next; |
1120 | |
1155 | |
1121 | for(i=0; i<MAP_WIDTH(m); i++) |
1156 | for(i=0; i<MAP_WIDTH(m); i++) |
1122 | for(j=0; j<MAP_HEIGHT(m); j++) { |
1157 | for(j=0; j<MAP_HEIGHT(m); j++) { |
1123 | unique=0; |
1158 | unique=0; |
… | |
… | |
1259 | if (m->width) fprintf(fp,"width %d\n", m->width); |
1294 | if (m->width) fprintf(fp,"width %d\n", m->width); |
1260 | if (m->height) fprintf(fp,"height %d\n", m->height); |
1295 | if (m->height) fprintf(fp,"height %d\n", m->height); |
1261 | if (m->enter_x) fprintf(fp,"enter_x %d\n", m->enter_x); |
1296 | 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); |
1297 | 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); |
1298 | if (m->msg) fprintf(fp,"msg\n%sendmsg\n", m->msg); |
|
|
1299 | if (m->maplore) fprintf(fp,"maplore\n%sendmaplore\n", m->maplore); |
1264 | if (m->unique) fprintf(fp,"unique %d\n", m->unique); |
1300 | if (m->unique) fprintf(fp,"unique %d\n", m->unique); |
1265 | if (m->template) fprintf(fp,"template %d\n", m->template); |
1301 | if (m->template) fprintf(fp,"template %d\n", m->template); |
1266 | if (m->outdoor) fprintf(fp,"outdoor %d\n", m->outdoor); |
1302 | if (m->outdoor) fprintf(fp,"outdoor %d\n", m->outdoor); |
1267 | if (m->temp) fprintf(fp, "temp %d\n", m->temp); |
1303 | if (m->temp) fprintf(fp, "temp %d\n", m->temp); |
1268 | if (m->pressure) fprintf(fp, "pressure %d\n", m->pressure); |
1304 | if (m->pressure) fprintf(fp, "pressure %d\n", m->pressure); |
… | |
… | |
1395 | } |
1431 | } |
1396 | if (flag && m->spaces) free_all_objects(m); |
1432 | if (flag && m->spaces) free_all_objects(m); |
1397 | if (m->name) FREE_AND_CLEAR(m->name); |
1433 | if (m->name) FREE_AND_CLEAR(m->name); |
1398 | if (m->spaces) FREE_AND_CLEAR(m->spaces); |
1434 | if (m->spaces) FREE_AND_CLEAR(m->spaces); |
1399 | if (m->msg) FREE_AND_CLEAR(m->msg); |
1435 | if (m->msg) FREE_AND_CLEAR(m->msg); |
|
|
1436 | if (m->maplore) FREE_AND_CLEAR(m->maplore); |
1400 | if (m->shopitems) FREE_AND_CLEAR(m->shopitems); |
1437 | if (m->shopitems) FREE_AND_CLEAR(m->shopitems); |
1401 | if (m->shoprace) FREE_AND_CLEAR(m->shoprace); |
1438 | if (m->shoprace) FREE_AND_CLEAR(m->shoprace); |
1402 | if (m->buttons) |
1439 | if (m->buttons) |
1403 | free_objectlinkpt(m->buttons); |
1440 | free_objectlinkpt(m->buttons); |
1404 | m->buttons = NULL; |
1441 | m->buttons = NULL; |
… | |
… | |
1625 | } |
1662 | } |
1626 | |
1663 | |
1627 | void clean_tmp_map(mapstruct *m) { |
1664 | void clean_tmp_map(mapstruct *m) { |
1628 | if(m->tmpname == NULL) |
1665 | if(m->tmpname == NULL) |
1629 | return; |
1666 | return; |
|
|
1667 | if (clean_temporary_map_callback) |
|
|
1668 | clean_temporary_map_callback (m); |
1630 | (void) unlink(m->tmpname); |
1669 | (void) unlink(m->tmpname); |
1631 | } |
1670 | } |
1632 | |
1671 | |
1633 | void free_all_maps(void) |
1672 | void free_all_maps(void) |
1634 | { |
1673 | { |
… | |
… | |
1692 | void update_position (mapstruct *m, int x, int y) { |
1731 | void update_position (mapstruct *m, int x, int y) { |
1693 | object *tmp, *last = NULL; |
1732 | object *tmp, *last = NULL; |
1694 | uint8 flags = 0, oldflags, light=0, anywhere=0; |
1733 | uint8 flags = 0, oldflags, light=0, anywhere=0; |
1695 | New_Face *top,*floor, *middle; |
1734 | New_Face *top,*floor, *middle; |
1696 | object *top_obj, *floor_obj, *middle_obj; |
1735 | object *top_obj, *floor_obj, *middle_obj; |
1697 | MoveType move_block=0, move_slow=0, move_on=0, move_off=0; |
1736 | MoveType move_block=0, move_slow=0, move_on=0, move_off=0, move_allow=0; |
1698 | |
1737 | |
1699 | oldflags = GET_MAP_FLAGS(m,x,y); |
1738 | oldflags = GET_MAP_FLAGS(m,x,y); |
1700 | if (!(oldflags & P_NEED_UPDATE)) { |
1739 | if (!(oldflags & P_NEED_UPDATE)) { |
1701 | LOG(llevDebug,"update_position called with P_NEED_UPDATE not set: %s (%d, %d)\n", |
1740 | LOG(llevDebug,"update_position called with P_NEED_UPDATE not set: %s (%d, %d)\n", |
1702 | m->path, x, y); |
1741 | m->path, x, y); |
… | |
… | |
1765 | |
1804 | |
1766 | move_slow |= tmp->move_slow; |
1805 | move_slow |= tmp->move_slow; |
1767 | move_block |= tmp->move_block; |
1806 | move_block |= tmp->move_block; |
1768 | move_on |= tmp->move_on; |
1807 | move_on |= tmp->move_on; |
1769 | move_off |= tmp->move_off; |
1808 | move_off |= tmp->move_off; |
|
|
1809 | move_allow |= tmp->move_allow; |
1770 | |
1810 | |
1771 | if (QUERY_FLAG(tmp,FLAG_ALIVE)) |
1811 | if (QUERY_FLAG(tmp,FLAG_ALIVE)) |
1772 | flags |= P_IS_ALIVE; |
1812 | flags |= P_IS_ALIVE; |
1773 | if (QUERY_FLAG(tmp,FLAG_NO_MAGIC)) |
1813 | if (QUERY_FLAG(tmp,FLAG_NO_MAGIC)) |
1774 | flags |= P_NO_MAGIC; |
1814 | flags |= P_NO_MAGIC; |
… | |
… | |
1788 | LOG(llevDebug,"update_position: updated flags do not match old flags: %s (old=%d,new=%d) %x != %x\n", |
1828 | LOG(llevDebug,"update_position: updated flags do not match old flags: %s (old=%d,new=%d) %x != %x\n", |
1789 | m->path, x, y, |
1829 | m->path, x, y, |
1790 | (oldflags & ~P_NEED_UPDATE), flags); |
1830 | (oldflags & ~P_NEED_UPDATE), flags); |
1791 | } |
1831 | } |
1792 | SET_MAP_FLAGS(m, x, y, flags); |
1832 | SET_MAP_FLAGS(m, x, y, flags); |
1793 | SET_MAP_MOVE_BLOCK(m, x, y, move_block); |
1833 | SET_MAP_MOVE_BLOCK(m, x, y, move_block & ~move_allow); |
1794 | SET_MAP_MOVE_ON(m, x, y, move_on); |
1834 | SET_MAP_MOVE_ON(m, x, y, move_on); |
1795 | SET_MAP_MOVE_OFF(m, x, y, move_off); |
1835 | SET_MAP_MOVE_OFF(m, x, y, move_off); |
1796 | SET_MAP_MOVE_SLOW(m, x, y, move_slow); |
1836 | SET_MAP_MOVE_SLOW(m, x, y, move_slow); |
1797 | |
1837 | |
1798 | /* At this point, we have a floor face (if there is a floor), |
1838 | /* At this point, we have a floor face (if there is a floor), |
… | |
… | |
1918 | * case. This generally shouldn't happen, but if the |
1958 | * case. This generally shouldn't happen, but if the |
1919 | * map loads fail below, it could happen. |
1959 | * map loads fail below, it could happen. |
1920 | */ |
1960 | */ |
1921 | if (!m) return 0; |
1961 | if (!m) return 0; |
1922 | |
1962 | |
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) { |
1963 | if (x<0) { |
1930 | if (!m->tile_path[3]) return 1; |
1964 | if (!m->tile_path[3]) return 1; |
1931 | if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) { |
1965 | if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) { |
1932 | load_and_link_tiled_map(m, 3); |
1966 | load_and_link_tiled_map(m, 3); |
1933 | } |
1967 | } |
… | |
… | |
1952 | if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY) { |
1986 | if (!m->tile_map[2] || m->tile_map[2]->in_memory != MAP_IN_MEMORY) { |
1953 | load_and_link_tiled_map(m, 2); |
1987 | load_and_link_tiled_map(m, 2); |
1954 | } |
1988 | } |
1955 | return (out_of_map(m->tile_map[2], x, y - MAP_HEIGHT(m))); |
1989 | return (out_of_map(m->tile_map[2], x, y - MAP_HEIGHT(m))); |
1956 | } |
1990 | } |
|
|
1991 | |
|
|
1992 | /* Simple case - coordinates are within this local |
|
|
1993 | * map. |
|
|
1994 | */ |
1957 | return 1; |
1995 | return 0; |
1958 | } |
1996 | } |
1959 | |
1997 | |
1960 | /* This is basically the same as out_of_map above, but |
1998 | /* This is basically the same as out_of_map above, but |
1961 | * instead we return NULL if no map is valid (coordinates |
1999 | * instead we return NULL if no map is valid (coordinates |
1962 | * out of bounds and no tiled map), otherwise it returns |
2000 | * out of bounds and no tiled map), otherwise it returns |
… | |
… | |
1966 | * and then figuring out what the real map is |
2004 | * and then figuring out what the real map is |
1967 | */ |
2005 | */ |
1968 | mapstruct *get_map_from_coord(mapstruct *m, sint16 *x, sint16 *y) |
2006 | mapstruct *get_map_from_coord(mapstruct *m, sint16 *x, sint16 *y) |
1969 | { |
2007 | { |
1970 | |
2008 | |
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) { |
2009 | if (*x<0) { |
1979 | if (!m->tile_path[3]) return NULL; |
2010 | if (!m->tile_path[3]) return NULL; |
1980 | if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) |
2011 | if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) |
1981 | load_and_link_tiled_map(m, 3); |
2012 | load_and_link_tiled_map(m, 3); |
1982 | |
2013 | |
… | |
… | |
2005 | load_and_link_tiled_map(m, 2); |
2036 | load_and_link_tiled_map(m, 2); |
2006 | |
2037 | |
2007 | *y -= MAP_HEIGHT(m); |
2038 | *y -= MAP_HEIGHT(m); |
2008 | return (get_map_from_coord(m->tile_map[2], x, y)); |
2039 | return (get_map_from_coord(m->tile_map[2], x, y)); |
2009 | } |
2040 | } |
2010 | return NULL; /* Shouldn't get here */ |
|
|
2011 | } |
|
|
2012 | |
2041 | |
|
|
2042 | /* Simple case - coordinates are within this local |
|
|
2043 | * map. |
|
|
2044 | */ |
|
|
2045 | |
|
|
2046 | return m; |
|
|
2047 | } |
|
|
2048 | |
|
|
2049 | /** |
2013 | // return wether map2 is adjacent to map1 and store their distance |
2050 | * Return whether map2 is adjacent to map1. If so, store the distance from |
2014 | // in dx/dy if yes. |
2051 | * map1 to map2 in dx/dy. |
|
|
2052 | */ |
2015 | static int adjacent_map (mapstruct *map1, mapstruct *map2, int *dx, int *dy) |
2053 | static int adjacent_map(const mapstruct *map1, const mapstruct *map2, int *dx, int *dy) { |
2016 | { |
|
|
2017 | if (!map1 || !map2) |
2054 | if (!map1 || !map2) |
2018 | return 0; |
2055 | return 0; |
2019 | |
2056 | |
2020 | else if (map1 == map2) |
2057 | if (map1 == map2) { |
|
|
2058 | *dx = 0; |
2021 | *dx = *dy = 0; |
2059 | *dy = 0; |
2022 | |
2060 | |
2023 | else if (map1->tile_map[0] == map2) // up |
2061 | } else if (map1->tile_map[0] == map2) { /* up */ |
|
|
2062 | *dx = 0; |
2024 | (*dx = 0), (*dy = -MAP_HEIGHT (map2)); |
2063 | *dy = -MAP_HEIGHT(map2); |
2025 | else if (map1->tile_map[1] == map2) // right |
2064 | } else if (map1->tile_map[1] == map2) { /* right */ |
2026 | (*dx = MAP_WIDTH (map2)), (*dy = 0); |
2065 | *dx = MAP_WIDTH(map1); |
|
|
2066 | *dy = 0; |
2027 | else if (map1->tile_map[2] == map2) // down |
2067 | } else if (map1->tile_map[2] == map2) { /* down */ |
2028 | (*dx = 0), (*dy = MAP_HEIGHT (map2)); |
2068 | *dx = 0; |
|
|
2069 | *dy = MAP_HEIGHT(map1); |
2029 | else if (map1->tile_map[3] == map2) // left |
2070 | } else if (map1->tile_map[3] == map2) { /* left */ |
2030 | (*dx = -MAP_WIDTH (map2)), (*dy = 0); |
2071 | *dx = -MAP_WIDTH(map2); |
|
|
2072 | *dy = 0; |
2031 | |
2073 | |
2032 | else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[1] == map2) // up right |
2074 | } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[1] == map2) { /* up right */ |
2033 | (*dx = MAP_WIDTH (map2)), (*dy = -MAP_HEIGHT (map1->tile_map[0])); |
2075 | *dx = MAP_WIDTH(map1->tile_map[0]); |
|
|
2076 | *dy = -MAP_HEIGHT(map1->tile_map[0]); |
2034 | else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[3] == map2) // up left |
2077 | } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[3] == map2) { /* up left */ |
2035 | (*dx = -MAP_WIDTH (map2)), (*dy = -MAP_HEIGHT (map1->tile_map[0])); |
2078 | *dx = -MAP_WIDTH(map2); |
|
|
2079 | *dy = -MAP_HEIGHT(map1->tile_map[0]); |
2036 | else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[0] == map2) // right up |
2080 | } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[0] == map2) { /* right up */ |
2037 | (*dx = MAP_HEIGHT (map1->tile_map[1])), (*dy = -MAP_WIDTH (map2)); |
2081 | *dx = MAP_WIDTH(map1); |
|
|
2082 | *dy = -MAP_HEIGHT(map2); |
2038 | else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[2] == map2) // right down |
2083 | } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[2] == map2) { /* right down */ |
2039 | (*dx = MAP_HEIGHT (map1->tile_map[1])), (*dy = MAP_WIDTH (map2)); |
2084 | *dx = MAP_WIDTH(map1); |
|
|
2085 | *dy = MAP_HEIGHT(map1->tile_map[1]); |
2040 | else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[1] == map2) // down right |
2086 | } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[1] == map2) { /* down right */ |
2041 | (*dx = MAP_WIDTH (map2)), (*dy = MAP_HEIGHT (map1->tile_map[2])); |
2087 | *dx = MAP_WIDTH(map1->tile_map[2]); |
|
|
2088 | *dy = MAP_HEIGHT(map1); |
2042 | else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[3] == map2) // down left |
2089 | } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[3] == map2) { /* down left */ |
2043 | (*dx = -MAP_WIDTH (map2)), (*dy = MAP_HEIGHT (map1->tile_map[2])); |
2090 | *dx = -MAP_WIDTH(map2); |
|
|
2091 | *dy = MAP_HEIGHT(map1); |
2044 | else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[0] == map2) // left up |
2092 | } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[0] == map2) { /* left up */ |
2045 | (*dx = -MAP_HEIGHT (map1->tile_map[3])), (*dy = -MAP_WIDTH (map2)); |
2093 | *dx = -MAP_WIDTH(map1->tile_map[3]); |
|
|
2094 | *dy = -MAP_HEIGHT(map2); |
2046 | else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[2] == map2) // left down |
2095 | } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[2] == map2) { /* left down */ |
2047 | (*dx = MAP_HEIGHT (map1->tile_map[3])), (*dy = MAP_WIDTH (map2)); |
2096 | *dx = -MAP_WIDTH(map1->tile_map[3]); |
|
|
2097 | *dy = MAP_HEIGHT(map1->tile_map[3]); |
2048 | |
2098 | |
2049 | else // not "adjacent" enough |
2099 | } else { /* not "adjacent" enough */ |
|
|
2100 | return 0; |
|
|
2101 | } |
|
|
2102 | |
2050 | return 0; |
2103 | return 1; |
2051 | |
|
|
2052 | return 1; |
|
|
2053 | } |
2104 | } |
2054 | |
2105 | |
2055 | /* From map.c |
2106 | /* From map.c |
2056 | * This is used by get_player to determine where the other |
2107 | * This is used by get_player to determine where the other |
2057 | * creature is. get_rangevector takes into account map tiling, |
2108 | * creature is. get_rangevector takes into account map tiling, |
… | |
… | |
2071 | * |
2122 | * |
2072 | * currently, the only flag supported (0x1) is don't translate for |
2123 | * currently, the only flag supported (0x1) is don't translate for |
2073 | * closest body part of 'op1' |
2124 | * closest body part of 'op1' |
2074 | */ |
2125 | */ |
2075 | |
2126 | |
2076 | void get_rangevector(object *op1, object *op2, rv_vector *retval, int flags) |
2127 | void get_rangevector(object *op1, object *op2, rv_vector *retval, int flags) { |
2077 | { |
|
|
2078 | if (!adjacent_map (op1->map, op2->map, &(retval->distance_x), &(retval->distance_y))) |
2128 | if (!adjacent_map(op1->map, op2->map, &retval->distance_x, &retval->distance_y)) { |
2079 | { |
|
|
2080 | // be conservative and fill in _some_ data |
2129 | /* be conservative and fill in _some_ data */ |
2081 | retval->distance = 100000; |
2130 | retval->distance = 100000; |
2082 | retval->distance_x = 32767; |
2131 | retval->distance_x = 32767; |
2083 | retval->distance_y = 32767; |
2132 | retval->distance_y = 32767; |
2084 | retval->direction = 0; |
2133 | retval->direction = 0; |
2085 | retval->part = 0; |
2134 | retval->part = 0; |
2086 | } |
|
|
2087 | else |
2135 | } else { |
2088 | { |
|
|
2089 | object *best; |
2136 | object *best; |
2090 | |
2137 | |
2091 | retval->distance_x += op2->x - op1->x; |
2138 | retval->distance_x += op2->x-op1->x; |
2092 | retval->distance_y += op2->y - op1->y; |
2139 | retval->distance_y += op2->y-op1->y; |
2093 | |
2140 | |
2094 | best = op1; |
2141 | best = op1; |
2095 | /* If this is multipart, find the closest part now */ |
2142 | /* If this is multipart, find the closest part now */ |
2096 | if (!(flags & 0x1) && op1->more) { |
2143 | if (!(flags&0x1) && op1->more) { |
2097 | object *tmp; |
2144 | object *tmp; |
2098 | int best_distance = retval->distance_x * retval->distance_x + |
2145 | int best_distance = retval->distance_x*retval->distance_x+ |
2099 | retval->distance_y * retval->distance_y, tmpi; |
2146 | retval->distance_y*retval->distance_y, tmpi; |
2100 | |
2147 | |
2101 | /* we just tkae the offset of the piece to head to figure |
2148 | /* we just take the offset of the piece to head to figure |
2102 | * distance instead of doing all that work above again |
2149 | * distance instead of doing all that work above again |
2103 | * since the distance fields we set above are positive in the |
2150 | * since the distance fields we set above are positive in the |
2104 | * same axis as is used for multipart objects, the simply arithemetic |
2151 | * same axis as is used for multipart objects, the simply arithmetic |
2105 | * below works. |
2152 | * below works. |
2106 | */ |
2153 | */ |
2107 | for (tmp=op1->more; tmp; tmp=tmp->more) { |
2154 | for (tmp = op1->more; tmp != NULL; tmp = tmp->more) { |
2108 | tmpi = (op1->x - tmp->x + retval->distance_x) * (op1->x - tmp->x + retval->distance_x) + |
2155 | tmpi = (op1->x-tmp->x+retval->distance_x)*(op1->x-tmp->x+retval->distance_x)+ |
2109 | (op1->y - tmp->y + retval->distance_y) * (op1->y - tmp->y + retval->distance_y); |
2156 | (op1->y-tmp->y+retval->distance_y)*(op1->y-tmp->y+retval->distance_y); |
2110 | if (tmpi < best_distance) { |
2157 | if (tmpi < best_distance) { |
2111 | best_distance = tmpi; |
2158 | best_distance = tmpi; |
2112 | best = tmp; |
2159 | best = tmp; |
2113 | } |
2160 | } |
2114 | } |
2161 | } |
2115 | if (best != op1) { |
2162 | if (best != op1) { |
2116 | retval->distance_x += op1->x - best->x; |
2163 | retval->distance_x += op1->x-best->x; |
2117 | retval->distance_y += op1->y - best->y; |
2164 | retval->distance_y += op1->y-best->y; |
2118 | } |
2165 | } |
2119 | } |
2166 | } |
2120 | retval->part = best; |
2167 | retval->part = best; |
2121 | retval->distance = isqrt(retval->distance_x*retval->distance_x + retval->distance_y*retval->distance_y); |
2168 | retval->distance = isqrt(retval->distance_x*retval->distance_x+retval->distance_y*retval->distance_y); |
2122 | retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y); |
2169 | retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y); |
2123 | } |
2170 | } |
2124 | } |
2171 | } |
2125 | |
2172 | |
2126 | /* this is basically the same as get_rangevector above, but instead of |
2173 | /* this is basically the same as get_rangevector above, but instead of |
2127 | * the first parameter being an object, it instead is the map |
2174 | * the first parameter being an object, it instead is the map |
2128 | * and x,y coordinates - this is used for path to player - |
2175 | * and x,y coordinates - this is used for path to player - |
… | |
… | |
2132 | * be more consistant with the above function and also in case they are needed |
2179 | * be more consistant with the above function and also in case they are needed |
2133 | * for something in the future. Also, since no object is pasted, the best |
2180 | * for something in the future. Also, since no object is pasted, the best |
2134 | * field of the rv_vector is set to NULL. |
2181 | * field of the rv_vector is set to NULL. |
2135 | */ |
2182 | */ |
2136 | |
2183 | |
2137 | void get_rangevector_from_mapcoord(mapstruct *m, int x, int y, object *op2, rv_vector *retval,int flags) |
2184 | void get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval, int flags) { |
2138 | { |
|
|
2139 | if (!adjacent_map (m, op2->map, &(retval->distance_x), &(retval->distance_y))) |
2185 | if (!adjacent_map(m, op2->map, &retval->distance_x, &retval->distance_y)) { |
2140 | { |
|
|
2141 | // be conservative and fill in _some_ data |
2186 | /* be conservative and fill in _some_ data */ |
2142 | retval->distance = 100000; |
2187 | retval->distance = 100000; |
2143 | retval->distance_x = 32767; |
2188 | retval->distance_x = 32767; |
2144 | retval->distance_y = 32767; |
2189 | retval->distance_y = 32767; |
2145 | retval->direction = 0; |
2190 | retval->direction = 0; |
2146 | retval->part = 0; |
2191 | retval->part = 0; |
2147 | } |
|
|
2148 | else |
2192 | } else { |
2149 | { |
|
|
2150 | retval->distance_x += op2->x - x; |
2193 | retval->distance_x += op2->x-x; |
2151 | retval->distance_y += op2->y - y; |
2194 | retval->distance_y += op2->y-y; |
2152 | |
2195 | |
2153 | retval->part = NULL; |
2196 | retval->part = NULL; |
2154 | retval->distance = isqrt(retval->distance_x*retval->distance_x + retval->distance_y*retval->distance_y); |
2197 | retval->distance = isqrt(retval->distance_x*retval->distance_x+retval->distance_y*retval->distance_y); |
2155 | retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y); |
2198 | retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y); |
2156 | } |
2199 | } |
2157 | } |
2200 | } |
2158 | |
2201 | |
2159 | /* Returns true of op1 and op2 are effectively on the same map |
2202 | /* Returns true of op1 and op2 are effectively on the same map |
2160 | * (as related to map tiling). Note that this looks for a path from |
2203 | * (as related to map tiling). Note that this looks for a path from |
2161 | * op1 to op2, so if the tiled maps are assymetric and op2 has a path |
2204 | * op1 to op2, so if the tiled maps are assymetric and op2 has a path |
2162 | * to op1, this will still return false. |
2205 | * to op1, this will still return false. |
2163 | * Note we only look one map out to keep the processing simple |
2206 | * Note we only look one map out to keep the processing simple |
2164 | * and efficient. This could probably be a macro. |
2207 | * and efficient. This could probably be a macro. |
2165 | * MSW 2001-08-05 |
2208 | * MSW 2001-08-05 |
2166 | */ |
2209 | */ |
2167 | int on_same_map(object *op1, object *op2) |
2210 | int on_same_map(const object *op1, const object *op2) { |
2168 | { |
|
|
2169 | int dx, dy; |
2211 | int dx, dy; |
2170 | |
2212 | |
2171 | return adjacent_map (op1->map, op2->map, &dx, &dy); |
2213 | return adjacent_map(op1->map, op2->map, &dx, &dy); |
2172 | } |
2214 | } |