1 | /* |
1 | /* |
2 | * static char *rcsid_c_object_c = |
2 | * static char *rcsid_c_object_c = |
3 | * "$Id: c_object.c,v 1.1.1.1 2006/02/03 07:14:29 root Exp $"; |
3 | * "$Id: c_object.c,v 1.4 2006/06/26 00:06:43 root Exp $"; |
4 | */ |
4 | */ |
5 | /* |
5 | /* |
6 | CrossFire, A Multiplayer game for X-windows |
6 | CrossFire, A Multiplayer game for X-windows |
7 | |
7 | |
8 | Copyright (C) 2002 Mark Wedel & Crossfire Development Team |
8 | Copyright (C) 2002 Mark Wedel & Crossfire Development Team |
… | |
… | |
52 | }\ |
52 | }\ |
53 | last->next=NULL;\ |
53 | last->next=NULL;\ |
54 | last->ob=(NEW);\ |
54 | last->ob=(NEW);\ |
55 | last->id=(COUNT); |
55 | last->id=(COUNT); |
56 | |
56 | |
|
|
57 | /** |
57 | /* Search the inventory of 'pl' for what matches best with params. |
58 | * Search the inventory of 'pl' for what matches best with params. |
58 | * we use item_matched_string above - this gives us consistent behaviour |
59 | * we use item_matched_string above - this gives us consistent behaviour |
59 | * between many commands. Return the best match, or NULL if no match. |
60 | * between many commands. Return the best match, or NULL if no match. |
|
|
61 | * aflag is used with apply -u , and apply -a to |
|
|
62 | * only unapply applied, or apply unapplied objects |
60 | */ |
63 | **/ |
61 | object *find_best_object_match(object *pl, const char *params) |
64 | static object *find_best_apply_object_match(object *pl, const char *params, enum apply_flag aflag) |
62 | { |
65 | { |
63 | object *tmp, *best=NULL; |
66 | object *tmp, *best=NULL; |
64 | int match_val=0,tmpmatch; |
67 | int match_val=0,tmpmatch; |
65 | |
68 | |
66 | for (tmp=pl->inv; tmp; tmp=tmp->below) { |
69 | for (tmp=pl->inv; tmp; tmp=tmp->below) { |
67 | if (tmp->invisible) continue; |
70 | if (tmp->invisible) continue; |
68 | if ((tmpmatch=item_matched_string(pl, tmp, params))>match_val) { |
71 | if ((tmpmatch=item_matched_string(pl, tmp, params))>match_val) { |
|
|
72 | if ((aflag==AP_APPLY) && (QUERY_FLAG(tmp,FLAG_APPLIED))) continue; |
|
|
73 | if ((aflag==AP_UNAPPLY) && (!QUERY_FLAG(tmp,FLAG_APPLIED))) continue; |
69 | match_val=tmpmatch; |
74 | match_val=tmpmatch; |
70 | best=tmp; |
75 | best=tmp; |
71 | } |
76 | } |
72 | } |
77 | } |
73 | return best; |
78 | return best; |
74 | } |
79 | } |
75 | /* Simlilar to find_best_object_match , but accepts an |
80 | |
76 | * additional parameter for apply -u , and apply -a to |
81 | /** |
77 | * only unapply applied , or apply unapplied objects |
82 | * Shortcut to find_best_apply_object_match(pl, params, AF_NULL); |
78 | */ |
83 | **/ |
79 | static object *find_best_apply_object_match(object *pl, char *params, enum apply_flag aflag) |
84 | object *find_best_object_match(object *pl, const char *params) |
80 | { |
85 | { |
81 | object *tmp, *best=NULL; |
86 | return find_best_apply_object_match(pl, params, AP_NULL); |
82 | int match_val=0,tmpmatch; |
|
|
83 | |
|
|
84 | for (tmp=pl->inv; tmp; tmp=tmp->below) { |
|
|
85 | if (tmp->invisible) continue; |
|
|
86 | if ((tmpmatch=item_matched_string(pl, tmp, params))>match_val) { |
|
|
87 | if ((aflag==AP_APPLY) && (QUERY_FLAG(tmp,FLAG_APPLIED))) continue; |
|
|
88 | if ((aflag==AP_UNAPPLY) && (!QUERY_FLAG(tmp,FLAG_APPLIED))) continue; |
|
|
89 | match_val=tmpmatch; |
|
|
90 | best=tmp; |
|
|
91 | } |
|
|
92 | } |
|
|
93 | return best; |
|
|
94 | } |
87 | } |
95 | |
88 | |
96 | /* |
89 | /* |
97 | * Notes about item creation: |
90 | * Notes about item creation: |
98 | * 1) It is similar in syntax to the dm create command. |
91 | * 1) It is similar in syntax to the dm create command. |
… | |
… | |
431 | } |
424 | } |
432 | return change_skill(pl,skill, 0); |
425 | return change_skill(pl,skill, 0); |
433 | } |
426 | } |
434 | |
427 | |
435 | |
428 | |
436 | /* These functions (command_search, command_disarm) are really juse wrappers for |
429 | /* These functions (command_search, command_disarm) are really just wrappers for |
437 | * things like 'use_skill ...'). In fact, they should really be obsoleted |
430 | * things like 'use_skill ...'). In fact, they should really be obsoleted |
438 | * and replaced with those. |
431 | * and replaced with those. |
439 | */ |
432 | */ |
440 | int command_search (object *op, char *params) { |
433 | int command_search (object *op, char *params) { |
441 | return use_skill(op, skill_names[SK_FIND_TRAPS]); |
434 | return use_skill(op, skill_names[SK_FIND_TRAPS]); |
… | |
… | |
520 | "You can put only %s into the %s.", sack->race, query_name(sack)); |
513 | "You can put only %s into the %s.", sack->race, query_name(sack)); |
521 | return 0; |
514 | return 0; |
522 | } |
515 | } |
523 | if (op->type == SPECIAL_KEY && sack->slaying && op->slaying) { |
516 | if (op->type == SPECIAL_KEY && sack->slaying && op->slaying) { |
524 | new_draw_info_format(NDI_UNIQUE, 0, pl, |
517 | new_draw_info_format(NDI_UNIQUE, 0, pl, |
525 | "You can't want put the key into %s.", query_name(sack)); |
518 | "You can't put the key into %s.", query_name(sack)); |
526 | return 0; |
519 | return 0; |
527 | } |
520 | } |
528 | if (sack->weight_limit && sack->carrying + (nrof ? nrof : 1) * |
521 | if (sack->weight_limit && sack->carrying + (nrof ? nrof : 1) * |
529 | (op->weight + (op->type==CONTAINER?(op->carrying*op->stats.Str):0)) |
522 | (op->weight + (op->type==CONTAINER?(op->carrying*op->stats.Str):0)) |
530 | * (100 - sack->stats.Str) / 100 > sack->weight_limit) { |
523 | * (100 - sack->stats.Str) / 100 > sack->weight_limit) { |
… | |
… | |
810 | |
803 | |
811 | /* |
804 | /* |
812 | * This function was part of drop, now is own function. |
805 | * This function was part of drop, now is own function. |
813 | * Player 'op' tries to put object 'tmp' into sack 'sack', |
806 | * Player 'op' tries to put object 'tmp' into sack 'sack', |
814 | * if nrof is non zero, then nrof objects is tried to put into sack. |
807 | * if nrof is non zero, then nrof objects is tried to put into sack. |
|
|
808 | * Note that the 'sack' in question can now be a transport, |
|
|
809 | * so this function isn't named very good anymore. |
815 | */ |
810 | */ |
816 | void put_object_in_sack (object *op, object *sack, object *tmp, uint32 nrof) |
811 | void put_object_in_sack (object *op, object *sack, object *tmp, uint32 nrof) |
817 | { |
812 | { |
818 | tag_t tmp_tag, tmp2_tag; |
813 | tag_t tmp_tag, tmp2_tag; |
819 | object *tmp2, *sack2; |
814 | object *tmp2, *sack2; |
820 | char buf[MAX_BUF]; |
815 | char buf[MAX_BUF]; |
821 | |
816 | |
822 | if (sack==tmp) return; /* Can't put an object in itself */ |
817 | if (sack==tmp) return; /* Can't put an object in itself */ |
823 | if (sack->type != CONTAINER) { |
818 | if (sack->type != CONTAINER && sack->type != TRANSPORT) { |
824 | new_draw_info_format(NDI_UNIQUE, 0,op, |
819 | new_draw_info_format(NDI_UNIQUE, 0,op, |
825 | "The %s is not a container.", query_name(sack)); |
820 | "The %s is not a container.", query_name(sack)); |
826 | return; |
821 | return; |
827 | } |
822 | } |
828 | if (QUERY_FLAG(tmp,FLAG_STARTEQUIP)) { |
823 | if (QUERY_FLAG(tmp,FLAG_STARTEQUIP)) { |
829 | new_draw_info_format(NDI_UNIQUE, 0,op, |
824 | new_draw_info_format(NDI_UNIQUE, 0,op, |
830 | "You cannot put the %s in the container.", query_name(tmp)); |
825 | "You cannot put the %s in the %s.", query_name(tmp), |
831 | return; |
826 | query_name(sack)); |
|
|
827 | return; |
832 | } |
828 | } |
833 | if (tmp->type == CONTAINER && tmp->inv) { |
829 | if (tmp->type == CONTAINER && tmp->inv) { |
834 | |
830 | |
835 | /* Eneq(@csd.uu.se): If the object to be dropped is a container |
831 | /* Eneq(@csd.uu.se): If the object to be dropped is a container |
836 | * we instead move the contents of that container into the active |
832 | * we instead move the contents of that container into the active |
837 | * container, this is only done if the object has something in it. |
833 | * container, this is only done if the object has something in it. |
838 | */ |
834 | */ |
839 | sack2 = tmp; |
835 | sack2 = tmp; |
840 | new_draw_info_format(NDI_UNIQUE, 0,op, "You move the items from %s into %s.", |
836 | new_draw_info_format(NDI_UNIQUE, 0,op, "You move the items from %s into %s.", |
841 | query_name(tmp), query_name(op->container)); |
837 | query_name(tmp), query_name(sack)); |
842 | for (tmp2 = tmp->inv; tmp2; tmp2 = tmp) { |
838 | for (tmp2 = tmp->inv; tmp2; tmp2 = tmp) { |
843 | tmp = tmp2->below; |
839 | tmp = tmp2->below; |
844 | if (sack_can_hold(op, op->container, tmp2,tmp2->nrof)) |
840 | if ((sack->type == CONTAINER && sack_can_hold(op, op->container, tmp2,tmp2->nrof)) || |
|
|
841 | (sack->type == TRANSPORT && transport_can_hold(sack, tmp2, tmp2->nrof))) { |
845 | put_object_in_sack (op, sack, tmp2, 0); |
842 | put_object_in_sack (op, sack, tmp2, 0); |
846 | else { |
843 | } else { |
847 | sprintf(buf,"Your %s fills up.", query_name(op->container)); |
844 | sprintf(buf,"Your %s fills up.", query_name(sack)); |
848 | new_draw_info(NDI_UNIQUE, 0,op, buf); |
845 | new_draw_info(NDI_UNIQUE, 0,op, buf); |
849 | break; |
846 | break; |
850 | } |
|
|
851 | } |
847 | } |
|
|
848 | } |
852 | esrv_update_item (UPD_WEIGHT, op, sack2); |
849 | esrv_update_item (UPD_WEIGHT, op, sack2); |
853 | return; |
850 | return; |
854 | } |
851 | } |
855 | |
852 | |
|
|
853 | /* Don't worry about this for containers - our caller should have |
|
|
854 | * already checked this. |
|
|
855 | */ |
856 | if (! sack_can_hold (op, sack, tmp,(nrof?nrof:tmp->nrof))) |
856 | if ((sack->type == CONTAINER) && !sack_can_hold (op, sack, tmp,(nrof?nrof:tmp->nrof))) |
857 | return; |
857 | return; |
858 | |
858 | |
859 | if(QUERY_FLAG(tmp, FLAG_APPLIED)) { |
859 | if(QUERY_FLAG(tmp, FLAG_APPLIED)) { |
860 | if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE)) |
860 | if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE)) |
861 | return; |
861 | return; |
862 | } |
862 | } |
863 | |
863 | |
864 | /* we want to put some portion of the item into the container */ |
864 | /* we want to put some portion of the item into the container */ |
865 | if (nrof && tmp->nrof != nrof) { |
865 | if (nrof && tmp->nrof != nrof) { |
866 | object *tmp2 = tmp; |
866 | object *tmp2 = tmp; |
… | |
… | |
877 | else /* this can proably be replaced with an update */ |
877 | else /* this can proably be replaced with an update */ |
878 | esrv_send_item (op, tmp2); |
878 | esrv_send_item (op, tmp2); |
879 | } else |
879 | } else |
880 | remove_ob(tmp); |
880 | remove_ob(tmp); |
881 | |
881 | |
882 | sprintf(buf, "You put the %s in ", query_name(tmp)); |
882 | new_draw_info_format(NDI_UNIQUE, 0,op, "You put the %s in %s.", |
883 | strcat (buf, query_name(sack)); |
883 | query_name(tmp), query_name(sack)); |
884 | strcat (buf, "."); |
|
|
885 | tmp_tag = tmp->count; |
884 | tmp_tag = tmp->count; |
886 | tmp2 = insert_ob_in_ob(tmp, sack); |
885 | tmp2 = insert_ob_in_ob(tmp, sack); |
887 | new_draw_info(NDI_UNIQUE, 0,op,buf); |
|
|
888 | fix_player(op); /* This is overkill, fix_player() is called somewhere */ |
886 | fix_player(op); /* This is overkill, fix_player() is called somewhere */ |
889 | /* in object.c */ |
887 | /* in object.c */ |
890 | |
888 | |
891 | /* If an object merged (and thus, different object), we need to |
889 | /* If an object merged (and thus, different object), we need to |
892 | * delete the original. |
890 | * delete the original. |
893 | */ |
891 | */ |
894 | if (tmp2 != tmp) |
892 | if (tmp2 != tmp) |
895 | esrv_del_item (op->contr, tmp_tag); |
893 | esrv_del_item (op->contr, tmp_tag); |
896 | |
894 | |
897 | esrv_send_item (op, tmp2); |
895 | esrv_send_item (op, tmp2); |
|
|
896 | |
|
|
897 | /* If a transport, need to update all the players in the transport |
|
|
898 | * the view of what is in it. |
|
|
899 | */ |
|
|
900 | if (sack->type == TRANSPORT) { |
|
|
901 | for (tmp=sack->inv; tmp; tmp=tmp->below) { |
|
|
902 | if (tmp->type == PLAYER) tmp->contr->socket.update_look=1; |
|
|
903 | } |
|
|
904 | } else { |
898 | /* update the sacks weight */ |
905 | /* update the sacks weight */ |
899 | esrv_update_item (UPD_WEIGHT, op, sack); |
906 | esrv_update_item (UPD_WEIGHT, op, sack); |
|
|
907 | } |
900 | } |
908 | } |
901 | |
909 | |
902 | /* |
910 | /* |
903 | * This function was part of drop, now is own function. |
911 | * This function was part of drop, now is own function. |
904 | * Player 'op' tries to drop object 'tmp', if tmp is non zero, then |
912 | * Player 'op' tries to drop object 'tmp', if tmp is non zero, then |
… | |
… | |
944 | else |
952 | else |
945 | esrv_send_item (op, tmp2); |
953 | esrv_send_item (op, tmp2); |
946 | } |
954 | } |
947 | } else |
955 | } else |
948 | remove_ob (tmp); |
956 | remove_ob (tmp); |
|
|
957 | |
949 | /* Lauwenmark: Handle for plugin drop event */ |
958 | /* Lauwenmark: Handle for plugin drop event */ |
950 | if (execute_event(tmp, EVENT_DROP,op,NULL,NULL,SCRIPT_FIX_ALL)!= 0) |
959 | if (execute_event(tmp, EVENT_DROP,op,NULL,NULL,SCRIPT_FIX_ALL)!= 0) |
951 | return; |
960 | return; |
952 | |
961 | |
953 | if (QUERY_FLAG (tmp, FLAG_STARTEQUIP)) { |
962 | if (QUERY_FLAG (tmp, FLAG_STARTEQUIP)) { |
… | |
… | |
1002 | fix_player(op); /* This is overkill, fix_player() is called somewhere */ |
1011 | fix_player(op); /* This is overkill, fix_player() is called somewhere */ |
1003 | /* in object.c */ |
1012 | /* in object.c */ |
1004 | |
1013 | |
1005 | if (op->type == PLAYER) |
1014 | if (op->type == PLAYER) |
1006 | { |
1015 | { |
1007 | op->contr->socket.update_look = 1; |
1016 | op->contr->socket.update_look = 1; |
1008 | /* esrv_send_item (op, tmp);*/ |
|
|
1009 | /* Need to update the weight for the player */ |
1017 | /* Need to update the weight for the player */ |
1010 | esrv_send_item (op, op); |
1018 | esrv_send_item (op, op); |
1011 | } |
1019 | } |
1012 | } |
1020 | } |
1013 | |
1021 | |
1014 | void drop(object *op, object *tmp) |
1022 | void drop(object *op, object *tmp) |
1015 | { |
1023 | { |
… | |
… | |
1487 | } |
1495 | } |
1488 | |
1496 | |
1489 | if (tmp->value && !QUERY_FLAG(tmp, FLAG_STARTEQUIP) && !QUERY_FLAG(tmp, FLAG_NO_PICK)) { |
1497 | if (tmp->value && !QUERY_FLAG(tmp, FLAG_STARTEQUIP) && !QUERY_FLAG(tmp, FLAG_NO_PICK)) { |
1490 | object *floor; |
1498 | object *floor; |
1491 | sprintf(buf,"You reckon %s worth %s.", |
1499 | sprintf(buf,"You reckon %s worth %s.", |
1492 | tmp->nrof>1?"they are":"it is",query_cost_string(tmp,op,F_SELL | F_APPROX)); |
1500 | tmp->nrof>1?"they are":"it is",query_cost_string(tmp,op, F_TRUE | F_APPROX)); |
1493 | new_draw_info(NDI_UNIQUE, 0,op,buf); |
1501 | new_draw_info(NDI_UNIQUE, 0,op,buf); |
1494 | floor = get_map_ob (op->map, op->x, op->y); |
1502 | floor = get_map_ob (op->map, op->x, op->y); |
1495 | if (floor && floor->type == SHOP_FLOOR) { |
1503 | if (floor && floor->type == SHOP_FLOOR) { |
1496 | if(QUERY_FLAG(tmp, FLAG_UNPAID)) |
1504 | if(QUERY_FLAG(tmp, FLAG_UNPAID)) |
1497 | sprintf(buf,"%s would cost you %s.", |
1505 | sprintf(buf,"%s would cost you %s.", |
… | |
… | |
1775 | if (params) { |
1783 | if (params) { |
1776 | /* Let's skip white spaces */ |
1784 | /* Let's skip white spaces */ |
1777 | while(' '==*params) params++; |
1785 | while(' '==*params) params++; |
1778 | |
1786 | |
1779 | /* Checking the first part */ |
1787 | /* Checking the first part */ |
1780 | if (itemnumber = atoi(params)) { |
1788 | if ((itemnumber = atoi(params))!=0) { |
1781 | for (item=op->inv; item && ((item->count != itemnumber) || item->invisible); item=item->below); |
1789 | for (item=op->inv; item && ((item->count != itemnumber) || item->invisible); item=item->below); |
1782 | if (!item) { |
1790 | if (!item) { |
1783 | new_draw_info(NDI_UNIQUE,0,op,"Tried to rename an invalid item."); |
1791 | new_draw_info(NDI_UNIQUE,0,op,"Tried to rename an invalid item."); |
1784 | return 1; |
1792 | return 1; |
1785 | } |
1793 | } |