1 | /* |
1 | /* |
2 | * static char *rcsid_shop_c = |
2 | * static char *rcsid_shop_c = |
3 | * "$Id: shop.c,v 1.17 2006/07/11 10:35:20 root Exp $"; |
3 | * "$Id: shop.c,v 1.19 2006/07/11 18:00:46 elmex 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 | |
… | |
… | |
335 | /* so long as nrof is 32 bit, this is true. |
335 | /* so long as nrof is 32 bit, this is true. |
336 | * If it takes more coins than a person can possibly carry, this |
336 | * If it takes more coins than a person can possibly carry, this |
337 | * is basically true. |
337 | * is basically true. |
338 | */ |
338 | */ |
339 | if ( (cost / coin->clone.value) > UINT32_MAX) { |
339 | if ( (cost / coin->clone.value) > UINT32_MAX) { |
340 | strcpy(buf,"an unimaginable sum of money."); |
340 | strcpy(buf,"an unimaginable sum of money"); |
341 | return buf; |
341 | return buf; |
342 | } |
342 | } |
343 | |
343 | |
344 | cost -= (uint64)num * (uint64)coin->clone.value; |
344 | cost -= (uint64)num * (uint64)coin->clone.value; |
345 | sprintf(buf, "%d %s", num, num > 1 ? coin->clone.name_pl : coin->clone.name); |
345 | sprintf(buf, "%d %s", num, num > 1 ? coin->clone.name_pl : coin->clone.name); |
… | |
… | |
719 | } |
719 | } |
720 | } |
720 | } |
721 | return 1; |
721 | return 1; |
722 | } |
722 | } |
723 | |
723 | |
|
|
724 | /* written by elmex: |
|
|
725 | * moved this code from sell_item () here to have a function |
|
|
726 | * that pays the player an amount. Mainly put the code here to |
|
|
727 | * be able to call it from a plugin. |
|
|
728 | * |
|
|
729 | * If the player can't carry all the money that is paid, it gets inserted |
|
|
730 | * in his inventory anyway. This is the best alternative to not pay any money |
|
|
731 | * or put it on the ground under the player. This way the player can still |
|
|
732 | * go somewhere and unload the money at a safe place. |
|
|
733 | * |
|
|
734 | */ |
|
|
735 | void pay_player (object *pl, uint64 amount) { |
|
|
736 | int count = 0; |
|
|
737 | archetype *at = 0; |
|
|
738 | object *pouch = 0, *tmp = 0; |
|
|
739 | |
|
|
740 | for (count = 0; coins[count] != NULL; count++) |
|
|
741 | { |
|
|
742 | at = find_archetype (coins[count]); |
|
|
743 | |
|
|
744 | if (at == NULL) |
|
|
745 | LOG(llevError, "Could not find %s archetype\n", coins[count]); |
|
|
746 | else if ((amount / at->clone.value) > 0) |
|
|
747 | { |
|
|
748 | for (pouch=pl->inv; pouch; pouch=pouch->below) |
|
|
749 | { |
|
|
750 | if (pouch->type == CONTAINER |
|
|
751 | && QUERY_FLAG (pouch, FLAG_APPLIED) |
|
|
752 | && pouch->race |
|
|
753 | && strstr (pouch->race, "gold")) |
|
|
754 | { |
|
|
755 | int w = at->clone.weight * (100 - pouch->stats.Str) / 100; |
|
|
756 | int n = amount / at->clone.value; |
|
|
757 | |
|
|
758 | if (w == 0) |
|
|
759 | w = 1; /* Prevent divide by zero */ |
|
|
760 | |
|
|
761 | if (n > 0 && (!pouch->weight_limit || pouch->carrying + w <= pouch->weight_limit)) |
|
|
762 | { |
|
|
763 | if (pouch->weight_limit && (pouch->weight_limit - pouch->carrying) / w < n) |
|
|
764 | n = (pouch->weight_limit - pouch->carrying) / w; |
|
|
765 | |
|
|
766 | tmp = get_object (); |
|
|
767 | copy_object (&at->clone, tmp); |
|
|
768 | tmp->nrof = n; |
|
|
769 | amount -= (uint64)tmp->nrof * (uint64)tmp->value; |
|
|
770 | tmp = insert_ob_in_ob (tmp, pouch); |
|
|
771 | esrv_send_item (pl, tmp); |
|
|
772 | esrv_send_item (pl, pouch); |
|
|
773 | esrv_update_item (UPD_WEIGHT, pl, pouch); |
|
|
774 | esrv_send_item (pl, pl); |
|
|
775 | } |
|
|
776 | } |
|
|
777 | } |
|
|
778 | |
|
|
779 | if (amount / at->clone.value > 0) |
|
|
780 | { |
|
|
781 | tmp = get_object (); |
|
|
782 | copy_object (&at->clone, tmp); |
|
|
783 | tmp->nrof = amount / tmp->value; |
|
|
784 | amount -= (uint64)tmp->nrof * (uint64)tmp->value; |
|
|
785 | tmp = insert_ob_in_ob (tmp, pl); |
|
|
786 | esrv_send_item (pl, tmp); |
|
|
787 | esrv_send_item (pl, pl); |
|
|
788 | } |
|
|
789 | } |
|
|
790 | } |
|
|
791 | |
|
|
792 | if (amount != 0) |
|
|
793 | #ifndef WIN32 |
|
|
794 | LOG (llevError,"Warning - payment in pay_player () not zero: %llu\n", amount); |
|
|
795 | #else |
|
|
796 | LOG (llevError,"Warning - payment in pay_player () not zero: %I64u\n", amount); |
|
|
797 | #endif |
|
|
798 | } |
|
|
799 | |
|
|
800 | /* elmex: this is for the bank plugin :( */ |
|
|
801 | uint64 pay_player_arch (object *pl, const char *arch, uint64 amount) { |
|
|
802 | archetype *at = find_archetype (arch); |
|
|
803 | object *tmp = NULL; |
|
|
804 | |
|
|
805 | if (at == NULL) |
|
|
806 | return 0; |
|
|
807 | |
|
|
808 | if (amount > 0) |
|
|
809 | { |
|
|
810 | tmp = get_object (); |
|
|
811 | copy_object (&at->clone, tmp); |
|
|
812 | tmp->nrof = amount; |
|
|
813 | tmp = insert_ob_in_ob (tmp, pl); |
|
|
814 | esrv_send_item (pl, tmp); |
|
|
815 | esrv_send_item (pl, pl); |
|
|
816 | } |
|
|
817 | |
|
|
818 | return 1; |
|
|
819 | } |
724 | |
820 | |
725 | /* Modified function to give out platinum coins. This function uses |
821 | /* Modified function to give out platinum coins. This function uses |
726 | * the coins[] array to know what coins are available, just like |
822 | * the coins[] array to know what coins are available, just like |
727 | * buy item. |
823 | * buy item. |
728 | * |
824 | * |
729 | * Modified to fill available race: gold containers before dumping |
825 | * Modified to fill available race: gold containers before dumping |
730 | * remaining coins in character's inventory. |
826 | * remaining coins in character's inventory. |
731 | */ |
827 | */ |
732 | void sell_item(object *op, object *pl) { |
828 | void sell_item(object *op, object *pl) { |
733 | uint64 i=query_cost(op,pl,F_SELL | F_SHOP), extra_gain; |
829 | uint64 amount = query_cost (op,pl,F_SELL | F_SHOP), extra_gain; |
734 | int count; |
|
|
735 | object *tmp, *pouch; |
|
|
736 | archetype *at; |
|
|
737 | |
830 | |
738 | if(pl==NULL||pl->type!=PLAYER) { |
831 | if(pl==NULL || pl->type != PLAYER) |
|
|
832 | { |
739 | LOG(llevDebug,"Object other than player tried to sell something.\n"); |
833 | LOG(llevDebug,"Object other than player tried to sell something.\n"); |
740 | return; |
834 | return; |
|
|
835 | } |
|
|
836 | |
|
|
837 | if(op->custom_name) |
|
|
838 | FREE_AND_CLEAR_STR (op->custom_name); |
|
|
839 | |
|
|
840 | if(!amount) |
741 | } |
841 | { |
742 | |
|
|
743 | if(op->custom_name) FREE_AND_CLEAR_STR(op->custom_name); |
|
|
744 | |
|
|
745 | if(!i) { |
|
|
746 | new_draw_info_format(NDI_UNIQUE, 0, pl, |
842 | new_draw_info_format (NDI_UNIQUE, 0, pl, |
747 | "We're not interested in %s.",query_name(op)); |
843 | "We're not interested in %s.", query_name (op)); |
748 | |
844 | |
749 | /* Even if the character doesn't get anything for it, it may still be |
845 | /* Even if the character doesn't get anything for it, it may still be |
750 | * worth something. If so, make it unpaid |
846 | * worth something. If so, make it unpaid |
751 | */ |
847 | */ |
752 | if (op->value) { |
848 | if (op->value) |
|
|
849 | { |
753 | SET_FLAG(op, FLAG_UNPAID); |
850 | SET_FLAG(op, FLAG_UNPAID); |
754 | SET_FLAG(op, FLAG_PLAYER_SOLD); |
851 | SET_FLAG(op, FLAG_PLAYER_SOLD); |
755 | } |
852 | } |
|
|
853 | |
756 | identify(op); |
854 | identify (op); |
757 | return; |
855 | return; |
758 | } |
856 | } |
759 | |
857 | |
760 | /* We compare the price with the one for a player |
858 | /* We compare the price with the one for a player |
761 | * without bargaining skill. |
859 | * without bargaining skill. |
762 | * This determins the amount of exp (if any) gained for bargaining. |
860 | * This determins the amount of exp (if any) gained for bargaining. |
763 | * exp/10 -> 1 for each gold coin |
861 | * exp/10 -> 1 for each gold coin |
764 | */ |
862 | */ |
765 | extra_gain = i - query_cost(op,pl,F_SELL | F_NO_BARGAIN | F_SHOP); |
863 | extra_gain = amount - query_cost (op, pl, F_SELL | F_NO_BARGAIN | F_SHOP); |
766 | |
864 | |
767 | if (extra_gain > 0) |
865 | if (extra_gain > 0) |
768 | change_exp(pl,extra_gain/10,"bargaining",SK_EXP_NONE); |
866 | change_exp(pl, extra_gain / 10, "bargaining", SK_EXP_NONE); |
769 | |
|
|
770 | for (count=0; coins[count]!=NULL; count++) { |
|
|
771 | at = find_archetype(coins[count]); |
|
|
772 | if (at==NULL) LOG(llevError, "Could not find %s archetype\n", coins[count]); |
|
|
773 | else if ((i/at->clone.value) > 0) { |
|
|
774 | for ( pouch=pl->inv ; pouch ; pouch=pouch->below ) { |
|
|
775 | if ( pouch->type==CONTAINER && QUERY_FLAG(pouch, FLAG_APPLIED) && pouch->race && strstr(pouch->race, "gold") ) { |
|
|
776 | int w = at->clone.weight * (100-pouch->stats.Str)/100; |
|
|
777 | int n = i/at->clone.value; |
|
|
778 | |
867 | |
779 | if (w==0) w=1; /* Prevent divide by zero */ |
868 | pay_player (pl, amount); |
780 | if ( n>0 && (!pouch->weight_limit || pouch->carrying+w<=pouch->weight_limit)) { |
|
|
781 | if (pouch->weight_limit && (pouch->weight_limit-pouch->carrying)/w<n) |
|
|
782 | n = (pouch->weight_limit-pouch->carrying)/w; |
|
|
783 | |
869 | |
784 | tmp = get_object(); |
|
|
785 | copy_object(&at->clone, tmp); |
|
|
786 | tmp->nrof = n; |
|
|
787 | i -= (uint64)tmp->nrof * (uint64)tmp->value; |
|
|
788 | tmp = insert_ob_in_ob(tmp, pouch); |
|
|
789 | esrv_send_item (pl, tmp); |
|
|
790 | esrv_send_item (pl, pouch); |
|
|
791 | esrv_update_item (UPD_WEIGHT, pl, pouch); |
|
|
792 | esrv_send_item (pl, pl); |
|
|
793 | } |
|
|
794 | } |
|
|
795 | } |
|
|
796 | if (i/at->clone.value > 0) { |
|
|
797 | tmp = get_object(); |
|
|
798 | copy_object(&at->clone, tmp); |
|
|
799 | tmp->nrof = i/tmp->value; |
|
|
800 | i -= (uint64)tmp->nrof * (uint64)tmp->value; |
|
|
801 | tmp = insert_ob_in_ob(tmp, pl); |
|
|
802 | esrv_send_item (pl, tmp); |
|
|
803 | esrv_send_item (pl, pl); |
|
|
804 | } |
|
|
805 | } |
|
|
806 | } |
|
|
807 | |
|
|
808 | if (i!=0) |
|
|
809 | #ifndef WIN32 |
|
|
810 | LOG(llevError,"Warning - payment not zero: %llu\n", i); |
|
|
811 | #else |
|
|
812 | LOG(llevError,"Warning - payment not zero: %I64u\n", i); |
|
|
813 | #endif |
|
|
814 | |
|
|
815 | new_draw_info_format(NDI_UNIQUE, 0, pl, |
870 | new_draw_info_format (NDI_UNIQUE, 0, pl, |
816 | "You receive %s for %s.",query_cost_string(op,pl,F_SELL | F_SHOP), |
871 | "You receive %s for %s.", query_cost_string (op, pl, F_SELL | F_SHOP), |
817 | query_name(op)); |
872 | query_name (op)); |
|
|
873 | |
818 | SET_FLAG(op, FLAG_UNPAID); |
874 | SET_FLAG (op, FLAG_UNPAID); |
819 | identify(op); |
875 | identify (op); |
820 | } |
876 | } |
|
|
877 | |
821 | |
878 | |
822 | /* returns a double that is the ratio of the price that a shop will offer for |
879 | /* returns a double that is the ratio of the price that a shop will offer for |
823 | * item based on the shops specialisation. Does not take account of greed, |
880 | * item based on the shops specialisation. Does not take account of greed, |
824 | * returned value is between (2*SPECIALISATION_EFFECT-1) and 1 and in any |
881 | * returned value is between (2*SPECIALISATION_EFFECT-1) and 1 and in any |
825 | * event is never less than 0.1 (calling functions divide by it) |
882 | * event is never less than 0.1 (calling functions divide by it) |
… | |
… | |
887 | * below the minimum value the shop is prepared to trade in, then we don't |
944 | * below the minimum value the shop is prepared to trade in, then we don't |
888 | * want it and offer nothing. If it isn't a shop, check whether we should do generic |
945 | * want it and offer nothing. If it isn't a shop, check whether we should do generic |
889 | * value reduction. |
946 | * value reduction. |
890 | * |
947 | * |
891 | */ |
948 | */ |
892 | static uint64 value_limit(uint64 val, int quantity, const object *who, int isshop) { |
949 | static uint64 value_limit (uint64 val, int quantity, const object *who, int isshop) { |
893 | uint64 newval, unit_price; |
950 | uint64 newval, unit_price, tmpshopmax; |
894 | mapstruct *map; |
951 | mapstruct *map; |
|
|
952 | |
895 | unit_price=val/quantity; |
953 | unit_price = val / quantity; |
|
|
954 | |
896 | if (!isshop || !who) { |
955 | if (!isshop || !who) |
|
|
956 | { |
897 | if (unit_price > 250000) |
957 | if (unit_price > 250000) |
898 | newval = 250000. - pow (250000., .75) * 65. + pow (unit_price, .75) * 65.; |
958 | newval = 250000. - pow (250000., .75) * 65. + pow (unit_price, .75) * 65.; |
899 | else |
959 | else |
900 | newval=unit_price; |
960 | newval = unit_price; |
901 | } else { |
961 | } |
|
|
962 | else |
|
|
963 | { |
902 | if (!who->map) { |
964 | if (!who->map) |
|
|
965 | { |
903 | LOG(llevError, "value_limit: asked shop price for ob %s on NULL map\n", who->name); |
966 | LOG(llevError, "value_limit: asked shop price for ob %s on NULL map\n", who->name); |
904 | return val; |
967 | return val; |
905 | } |
968 | } |
906 | map=who->map; |
969 | |
|
|
970 | map = who->map; |
|
|
971 | |
|
|
972 | tmpshopmax = map->shopmax ? map->shopmax : 100000; // 20 royalties default |
|
|
973 | |
907 | if (map->shopmin && unit_price < map->shopmin) return 0; |
974 | if (map->shopmin && unit_price < map->shopmin) |
908 | else if (map->shopmax && unit_price > map->shopmax/2) |
975 | return 0; |
|
|
976 | else if (unit_price > tmpshopmax / 2) |
909 | newval=MIN((map->shopmax/2)+isqrt(unit_price-map->shopmax/2), map->shopmax); |
977 | newval = MIN ((tmpshopmax / 2) + isqrt (unit_price - tmpshopmax / 2), tmpshopmax); |
910 | else if (unit_price > 250000) |
978 | else |
911 | newval = 250000. - pow (250000., .75) * 65. + pow (unit_price, .75) * 65.; |
|
|
912 | else |
|
|
913 | newval=unit_price; |
979 | newval=unit_price; |
914 | } |
980 | } |
|
|
981 | |
915 | newval *= quantity; |
982 | newval *= quantity; |
|
|
983 | |
916 | return newval; |
984 | return newval; |
917 | } |
985 | } |
918 | |
986 | |
919 | /* gives a desciption of the shop on their current map to the player op. */ |
987 | /* gives a desciption of the shop on their current map to the player op. */ |
920 | int describe_shop(const object *op) { |
988 | int describe_shop(const object *op) { |
921 | mapstruct *map = op->map; |
989 | mapstruct *map = op->map; |