1 | /* |
1 | /* |
2 | * This file is part of Deliantra, the Roguelike Realtime MMORPG. |
2 | * This file is part of Deliantra, the Roguelike Realtime MMORPG. |
3 | * |
3 | * |
4 | * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
4 | * Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 | * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team |
5 | * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team |
6 | * Copyright (©) 1992,2007 Frank Tore Johansen |
6 | * Copyright (©) 1992,2007 Frank Tore Johansen |
7 | * |
7 | * |
8 | * Deliantra is free software: you can redistribute it and/or modify |
8 | * Deliantra is free software: you can redistribute it and/or modify it under |
9 | * it under the terms of the GNU General Public License as published by |
9 | * the terms of the Affero GNU General Public License as published by the |
10 | * the Free Software Foundation, either version 3 of the License, or |
10 | * Free Software Foundation, either version 3 of the License, or (at your |
11 | * (at your option) any later version. |
11 | * option) any later version. |
12 | * |
12 | * |
13 | * This program is distributed in the hope that it will be useful, |
13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. |
16 | * GNU General Public License for more details. |
17 | * |
17 | * |
18 | * You should have received a copy of the GNU General Public License |
18 | * You should have received a copy of the Affero GNU General Public License |
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | * and the GNU General Public License along with this program. If not, see |
|
|
20 | * <http://www.gnu.org/licenses/>. |
20 | * |
21 | * |
21 | * The authors can be reached via e-mail to <support@deliantra.net> |
22 | * The authors can be reached via e-mail to <support@deliantra.net> |
22 | */ |
23 | */ |
23 | |
24 | |
24 | #include <global.h> |
25 | #include <global.h> |
… | |
… | |
74 | |
75 | |
75 | sint64 |
76 | sint64 |
76 | query_cost (const object *tmp, object *who, int flag) |
77 | query_cost (const object *tmp, object *who, int flag) |
77 | { |
78 | { |
78 | double val; |
79 | double val; |
79 | int number; /* used to better calculate value */ |
|
|
80 | int no_bargain; |
80 | int no_bargain; |
81 | int identified; |
81 | int identified; |
82 | int not_cursed; |
82 | int not_cursed; |
83 | int approximate; |
83 | int approximate; |
84 | int shop; |
84 | int shop; |
… | |
… | |
109 | |
109 | |
110 | LOG (llevError, "Query_cost: Gem type with unknown flag %d: %s\n", flag, tmp->debug_desc ()); |
110 | LOG (llevError, "Query_cost: Gem type with unknown flag %d: %s\n", flag, tmp->debug_desc ()); |
111 | return 0; |
111 | return 0; |
112 | } |
112 | } |
113 | |
113 | |
114 | number = tmp->nrof; |
114 | int number = tmp->number_of (); |
115 | if (number == 0) |
115 | |
116 | number = 1; |
|
|
117 | if (QUERY_FLAG (tmp, FLAG_IDENTIFIED) || !need_identify (tmp) || identified) |
116 | if (QUERY_FLAG (tmp, FLAG_IDENTIFIED) || !need_identify (tmp) || identified) |
118 | { |
117 | { |
119 | if (!not_cursed && (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED))) |
118 | if (!not_cursed && (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED))) |
120 | return 0; |
119 | return 0; |
121 | else |
120 | else |
122 | val = tmp->value * number; |
121 | val = tmp->value * number; |
123 | } |
122 | } |
124 | /* This area deals with objects that are not identified, but can be */ |
123 | /* This area deals with objects that are not identified, but can be */ |
125 | else |
124 | else |
126 | { |
125 | { |
127 | if (tmp->arch != NULL) |
126 | if (flag == F_BUY) |
128 | { |
127 | { |
129 | if (flag == F_BUY) |
128 | LOG (llevError | logBacktrace, "Asking for buy-value of unidentified object: %s\n", tmp->debug_desc ()); |
|
|
129 | val = tmp->arch->value * 50 * number; |
|
|
130 | } |
|
|
131 | else |
|
|
132 | { /* Trying to sell something, or get true value */ |
|
|
133 | if (tmp->type == POTION) |
|
|
134 | val = number * 40; /* Don't want to give anything away */ |
|
|
135 | else |
130 | { |
136 | { |
131 | LOG (llevError | logBacktrace, "Asking for buy-value of unidentified object.\n"); |
137 | /* Get 2/3'rd value for applied objects, 1/3'rd for totally |
132 | val = tmp->arch->value * 50 * number; |
138 | * unknown objects |
|
|
139 | */ |
|
|
140 | if (QUERY_FLAG (tmp, FLAG_BEEN_APPLIED)) |
|
|
141 | val = number * tmp->arch->value * 2 / 3; |
|
|
142 | else |
|
|
143 | val = number * tmp->arch->value / 3; |
133 | } |
144 | } |
134 | else |
|
|
135 | { /* Trying to sell something, or get true value */ |
|
|
136 | if (tmp->type == POTION) |
|
|
137 | val = number * 40; /* Don't want to give anything away */ |
|
|
138 | else |
|
|
139 | { |
|
|
140 | /* Get 2/3'rd value for applied objects, 1/3'rd for totally |
|
|
141 | * unknown objects |
|
|
142 | */ |
|
|
143 | if (QUERY_FLAG (tmp, FLAG_BEEN_APPLIED)) |
|
|
144 | val = number * tmp->arch->value * 2 / 3; |
|
|
145 | else |
|
|
146 | val = number * tmp->arch->value / 3; |
|
|
147 | } |
|
|
148 | } |
|
|
149 | } |
|
|
150 | else |
|
|
151 | { /* No archetype with this object */ |
|
|
152 | LOG (llevDebug, "In sell item: Have object with no archetype: %s\n", &tmp->name); |
|
|
153 | if (flag == F_BUY) |
|
|
154 | { |
|
|
155 | LOG (llevError | logBacktrace, "Asking for buy-value of unidentified object without arch.\n"); |
|
|
156 | val = number * tmp->value * 10; |
|
|
157 | } |
|
|
158 | else |
|
|
159 | val = number * tmp->value / 5; |
|
|
160 | } |
145 | } |
161 | } |
146 | } |
162 | |
147 | |
163 | /* If the item has been applied or identifed or does not need to be |
148 | /* If the item has been applied or identifed or does not need to be |
164 | * identified, AND the object is magical and the archetype is non |
149 | * identified, AND the object is magical and the archetype is non |
… | |
… | |
465 | } |
450 | } |
466 | |
451 | |
467 | for (tmp = op->inv; tmp; tmp = tmp->below) |
452 | for (tmp = op->inv; tmp; tmp = tmp->below) |
468 | if (tmp->type == MONEY) |
453 | if (tmp->type == MONEY) |
469 | total += tmp->nrof * (sint64)tmp->value; |
454 | total += tmp->nrof * (sint64)tmp->value; |
470 | else if (tmp->type == CONTAINER && QUERY_FLAG (tmp, FLAG_APPLIED) && (tmp->race == NULL || strstr (tmp->race, "gold"))) |
455 | else if (tmp->type == CONTAINER && QUERY_FLAG (tmp, FLAG_APPLIED) && (!tmp->race || tmp->race.contains ("gold"))) |
471 | total += query_money (tmp); |
456 | total += query_money (tmp); |
472 | |
457 | |
473 | return total; |
458 | return total; |
474 | } |
459 | } |
475 | |
460 | |
… | |
… | |
490 | return 0; |
475 | return 0; |
491 | |
476 | |
492 | pay_from_container (pl, pl, to_pay); |
477 | pay_from_container (pl, pl, to_pay); |
493 | |
478 | |
494 | for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) |
479 | for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) |
495 | if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && (pouch->race == NULL || strstr (pouch->race, "gold"))) |
480 | if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && (!pouch->race || pouch->race.contains ("gold"))) |
496 | pay_from_container (pl, pouch, to_pay); |
481 | pay_from_container (pl, pouch, to_pay); |
497 | |
482 | |
498 | pl->update_stats (); |
483 | pl->update_stats (); |
499 | return 1; |
484 | return 1; |
500 | } |
485 | } |
… | |
… | |
527 | change_exp (pl, saved_money, "bargaining", SK_EXP_NONE); |
512 | change_exp (pl, saved_money, "bargaining", SK_EXP_NONE); |
528 | |
513 | |
529 | pay_from_container (pl, pl, to_pay); |
514 | pay_from_container (pl, pl, to_pay); |
530 | |
515 | |
531 | for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) |
516 | for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) |
532 | if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && (pouch->race == NULL || strstr (pouch->race, "gold"))) |
517 | if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && (!pouch->race || pouch->race.contains ("gold"))) |
533 | pay_from_container (pl, pouch, to_pay); |
518 | pay_from_container (pl, pouch, to_pay); |
534 | |
519 | |
535 | pl->update_stats (); |
520 | pl->update_stats (); |
536 | |
521 | |
537 | return 1; |
522 | return 1; |
… | |
… | |
611 | } |
596 | } |
612 | |
597 | |
613 | for (i = 0; i < NUM_COINS; i++) |
598 | for (i = 0; i < NUM_COINS; i++) |
614 | { |
599 | { |
615 | object &coin = *coin_objs[i]; |
600 | object &coin = *coin_objs[i]; |
616 | sint64 num_coins = min ((to_pay + coin.value - 1) / coin.value, coin.nrof); |
601 | sint64 num_coins = min ((to_pay + coin.value - 1) / coin.value, (sint64) coin.nrof); |
617 | to_pay -= num_coins * coin.value; |
602 | to_pay -= num_coins * coin.value; |
618 | |
603 | |
619 | coin.nrof -= num_coins; |
604 | coin.nrof -= num_coins; |
620 | /* Now start making change. Start at the coin value |
605 | /* Now start making change. Start at the coin value |
621 | * below the one we just did, and work down to |
606 | * below the one we just did, and work down to |
… | |
… | |
664 | unpaid_price += query_cost (item, pl, F_BUY | F_SHOP); |
649 | unpaid_price += query_cost (item, pl, F_BUY | F_SHOP); |
665 | } |
650 | } |
666 | |
651 | |
667 | if (unpaid_price > player_wealth) |
652 | if (unpaid_price > player_wealth) |
668 | { |
653 | { |
669 | dynbuf_text buf; |
654 | dynbuf_text &buf = msg_dynbuf; buf.clear (); |
670 | |
655 | |
671 | buf << "You have " << unpaid_count |
656 | buf << "You have " << unpaid_count |
672 | << " unpaid item(s) that would cost you " << cost_string_from_value (unpaid_price, 0) |
657 | << " unpaid item(s) that would cost you " << cost_string_from_value (unpaid_price, 0) |
673 | << ". You need another " << cost_string_from_value (unpaid_price - player_wealth, 0) |
658 | << ". You need another " << cost_string_from_value (unpaid_price - player_wealth, 0) |
674 | << " to be able to afford that. " |
659 | << " to be able to afford that. " |
675 | "H<You cannot leave a shop with items you cannot pay - drop those unpaid items first.>"; |
660 | "H<You cannot leave a shop without paying - drop unpaid items first to be able to leave.>"; |
676 | |
661 | |
677 | pl->failmsg (buf); |
662 | pl->failmsg (buf); |
678 | |
663 | |
679 | return 0; |
664 | return 0; |
680 | } |
665 | } |
… | |
… | |
755 | LOG (llevError, "Could not find %s archetype\n", coins[count]); |
740 | LOG (llevError, "Could not find %s archetype\n", coins[count]); |
756 | else if ((amount / at->value) > 0) |
741 | else if ((amount / at->value) > 0) |
757 | { |
742 | { |
758 | for (pouch = pl->inv; pouch; pouch = pouch->below) |
743 | for (pouch = pl->inv; pouch; pouch = pouch->below) |
759 | { |
744 | { |
760 | if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && pouch->race && strstr (pouch->race, "gold")) |
745 | if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && pouch->race.contains ("gold")) |
761 | { |
746 | { |
762 | int w = at->weight * (100 - pouch->stats.Str) / 100; |
747 | int w = at->weight * (100 - pouch->stats.Str) / 100; |
763 | int n = amount / at->value; |
748 | int n = amount / at->value; |
764 | |
749 | |
765 | if (w == 0) |
750 | if (w == 0) |
… | |
… | |
979 | |
964 | |
980 | /* gives a desciption of the shop on their current map to the player op. */ |
965 | /* gives a desciption of the shop on their current map to the player op. */ |
981 | int |
966 | int |
982 | describe_shop (const object *op) |
967 | describe_shop (const object *op) |
983 | { |
968 | { |
|
|
969 | dynbuf_text buf; |
984 | maptile *map = op->map; |
970 | maptile *map = op->map; |
985 | |
971 | |
986 | /*shopitems *items=map->shopitems; */ |
972 | /*shopitems *items=map->shopitems; */ |
987 | int pos = 0, i; |
973 | int pos = 0, i; |
988 | double opinion = 0; |
974 | double opinion = 0; |
989 | char tmp[MAX_BUF] = "\0"; |
|
|
990 | |
975 | |
991 | if (op->type != PLAYER) |
976 | if (op->type != PLAYER) |
992 | return 0; |
977 | return 0; |
993 | |
978 | |
994 | /*check if there is a shop specified for this map */ |
979 | /*check if there is a shop specified for this map */ |
995 | if (map->shopitems || map->shopgreed || map->shoprace || map->shopmin || map->shopmax) |
980 | if (map->shopitems || map->shopgreed || map->shoprace || map->shopmin || map->shopmax) |
996 | { |
981 | { |
997 | new_draw_info (NDI_UNIQUE, 0, op, "From looking at the nearby shop you determine that it trades in:"); |
982 | buf << "From looking at the nearby shop you determine that it trades in "; |
|
|
983 | |
|
|
984 | char tmp[MAX_BUF]; |
998 | |
985 | |
999 | if (map->shopitems) |
986 | if (map->shopitems) |
1000 | for (i = 0; i < map->shopitems[0].index; i++) |
987 | for (i = 0; i < map->shopitems[0].index; i++) |
1001 | if (map->shopitems[i].name && map->shopitems[i].strength > 10) |
988 | if (map->shopitems[i].name && map->shopitems[i].strength > 10) |
1002 | { |
989 | { |
1003 | snprintf (tmp + pos, sizeof (tmp) - pos, "%s, ", map->shopitems[i].name_pl); |
990 | snprintf (tmp + pos, sizeof (tmp) - pos, "%s, ", map->shopitems[i].name_pl); |
1004 | pos += strlen (tmp + pos); |
991 | pos += strlen (tmp + pos); |
1005 | } |
992 | } |
1006 | |
993 | |
1007 | if (!pos) |
994 | if (pos) |
|
|
995 | make_list_like (tmp); |
|
|
996 | else |
1008 | strcat (tmp, "a little of everything."); |
997 | strcat (tmp, "a little of everything."); |
1009 | |
998 | |
1010 | /* format the string into a list */ |
999 | /* format the string into a list */ |
1011 | make_list_like (tmp); |
1000 | buf << tmp << "\n\n"; |
1012 | new_draw_info_format (NDI_UNIQUE, 0, op, "%s", tmp); |
|
|
1013 | |
1001 | |
1014 | if (map->shopmax) |
1002 | if (map->shopmax) |
1015 | new_draw_info_format (NDI_UNIQUE, 0, op, "It won't trade for items above %s.", cost_string_from_value (map->shopmax, 0)); |
1003 | buf << "It won't trade for items above " << cost_string_from_value (map->shopmax, 0) << ".\n\n"; |
1016 | |
1004 | |
1017 | if (map->shopmin) |
1005 | if (map->shopmin) |
1018 | new_draw_info_format (NDI_UNIQUE, 0, op, "It won't trade in items worth less than %s.", cost_string_from_value (map->shopmin, 0)); |
1006 | buf << "It won't trade in items worth less than " << cost_string_from_value (map->shopmin, 0) << ".\n\n"; |
1019 | |
1007 | |
1020 | if (map->shopgreed) |
1008 | if (map->shopgreed) |
1021 | { |
1009 | { |
1022 | if (map->shopgreed > 2.0) |
1010 | if (map->shopgreed > 2.0) |
1023 | new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge massively."); |
1011 | buf << "It tends to overcharge massively.\n\n"; |
1024 | else if (map->shopgreed > 1.5) |
1012 | else if (map->shopgreed > 1.5) |
1025 | new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge substantially."); |
1013 | buf << "It tends to overcharge substantially.\n\n"; |
1026 | else if (map->shopgreed > 1.1) |
1014 | else if (map->shopgreed > 1.1) |
1027 | new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge slightly."); |
1015 | buf << "It tends to overcharge slightly.\n\n"; |
1028 | else if (map->shopgreed < 0.9) |
1016 | else if (map->shopgreed < 0.9) |
1029 | new_draw_info (NDI_UNIQUE, 0, op, "It tends to undercharge."); |
1017 | buf << "It tends to undercharge.\n\n"; |
1030 | } |
1018 | } |
1031 | |
1019 | |
1032 | if (map->shoprace) |
1020 | if (map->shoprace) |
1033 | { |
1021 | { |
1034 | opinion = shopkeeper_approval (map, op); |
1022 | opinion = shopkeeper_approval (map, op); |
|
|
1023 | |
1035 | if (opinion > 0.8) |
1024 | if (opinion > 0.8) |
1036 | new_draw_info (NDI_UNIQUE, 0, op, "You think the shopkeeper likes you."); |
1025 | buf << "You think the shopkeeper likes you.\n\n"; |
1037 | else if (opinion > 0.5) |
1026 | else if (opinion > 0.5) |
1038 | new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper seems unconcerned by you."); |
1027 | buf << "The shopkeeper seems unconcerned by you.\n\n"; |
1039 | else |
1028 | else |
1040 | new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper seems to have taken a dislike to you."); |
1029 | buf << "The shopkeeper seems to have taken a dislike to you.\n\n"; |
1041 | } |
1030 | } |
1042 | } |
1031 | } |
1043 | else |
1032 | else |
1044 | new_draw_info (NDI_UNIQUE, 0, op, "There is no shop nearby."); |
1033 | buf << "There is no shop nearby.\n\n"; |
|
|
1034 | |
|
|
1035 | op->contr->infobox (MSG_CHANNEL ("shopinfo"), buf); |
1045 | |
1036 | |
1046 | return 1; |
1037 | return 1; |
1047 | } |
1038 | } |
1048 | |
1039 | |
1049 | struct shopinv |
1040 | struct shopinv |
… | |
… | |
1117 | items[*numitems].item_sort = strdup (query_base_name (tmp, 0)); |
1108 | items[*numitems].item_sort = strdup (query_base_name (tmp, 0)); |
1118 | items[*numitems].item_real = strdup (query_base_name (tmp, 1)); |
1109 | items[*numitems].item_real = strdup (query_base_name (tmp, 1)); |
1119 | (*numitems)++; |
1110 | (*numitems)++; |
1120 | break; |
1111 | break; |
1121 | } |
1112 | } |
|
|
1113 | |
1122 | SET_FLAG (tmp, FLAG_UNPAID); |
1114 | SET_FLAG (tmp, FLAG_UNPAID); |
1123 | } |
1115 | } |
1124 | |
1116 | |
1125 | void |
1117 | void |
1126 | shop_listing (object *sign, object *op) |
1118 | shop_listing (object *sign, object *op) |
1127 | { |
1119 | { |
1128 | int i, j, numitems = 0, numallocated = 0, x1, x2, y1, y2; |
1120 | int i, j, x1, x2, y1, y2; |
1129 | const char *shop_coords = sign->kv (shstr_shop_coords); |
1121 | const char *shop_coords = sign->kv (shstr_shop_coords); |
1130 | object *stack; |
1122 | object *stack; |
1131 | shopinv *items; |
1123 | shopinv *items; |
1132 | |
1124 | |
1133 | /* Should never happen, but just in case a monster does apply a sign */ |
1125 | /* Should never happen, but just in case a monster does apply a sign */ |
1134 | if (op->type != PLAYER) |
1126 | if (!op->is_player ()) |
1135 | return; |
1127 | return; |
|
|
1128 | |
|
|
1129 | dynbuf_text &buf = msg_dynbuf; buf.clear (); |
1136 | |
1130 | |
1137 | if (!(shop_coords && sscanf (shop_coords, "%d,%d,%d,%d", &x1, &y1, &x2, &y2))) |
1131 | if (!(shop_coords && sscanf (shop_coords, "%d,%d,%d,%d", &x1, &y1, &x2, &y2))) |
1138 | { |
1132 | { |
1139 | x1 = 0; |
1133 | x1 = 0; |
1140 | y1 = 0; |
1134 | y1 = 0; |
1141 | x2 = op->map->width - 1; |
1135 | x2 = op->map->width - 1; |
1142 | y2 = op->map->height - 1; |
1136 | y2 = op->map->height - 1; |
1143 | } |
1137 | } |
1144 | |
1138 | |
1145 | items = (shopinv *) malloc (40 * sizeof (shopinv)); |
|
|
1146 | numallocated = 40; |
1139 | int numallocated = 40; |
|
|
1140 | int numitems = 0; |
|
|
1141 | items = (shopinv *)malloc (sizeof (shopinv) * numallocated); |
1147 | |
1142 | |
1148 | /* Find all the appropriate items */ |
1143 | /* Find all the appropriate items */ |
1149 | for (i = x1; i <= x2; i++) |
1144 | for (i = x1; i <= x2; i++) |
1150 | { |
|
|
1151 | for (j = y1; j < y2; j++) |
1145 | for (j = y1; j < y2; j++) |
|
|
1146 | if (is_in_shop (op->map, i, j)) |
1152 | { |
1147 | { |
1153 | if (is_in_shop (op->map, i, j)) |
1148 | stack = GET_MAP_OB (op->map, i, j); |
|
|
1149 | |
|
|
1150 | while (stack) |
1154 | { |
1151 | { |
1155 | stack = GET_MAP_OB (op->map, i, j); |
1152 | if (QUERY_FLAG (stack, FLAG_UNPAID)) |
1156 | |
|
|
1157 | while (stack) |
|
|
1158 | { |
1153 | { |
1159 | if (QUERY_FLAG (stack, FLAG_UNPAID)) |
|
|
1160 | { |
|
|
1161 | if (numitems == numallocated) |
1154 | if (numitems == numallocated) |
1162 | { |
|
|
1163 | items = (shopinv *) realloc (items, sizeof (shopinv) * (numallocated + 10)); |
1155 | items = (shopinv *)realloc (items, sizeof (shopinv) * (numallocated *= 2)); |
1164 | numallocated += 10; |
|
|
1165 | } |
|
|
1166 | |
1156 | |
1167 | add_shop_item (stack, items, &numitems, &numallocated); |
1157 | add_shop_item (stack, items, &numitems, &numallocated); |
1168 | } |
|
|
1169 | |
|
|
1170 | stack = stack->above; |
|
|
1171 | } |
1158 | } |
|
|
1159 | |
|
|
1160 | stack = stack->above; |
1172 | } |
1161 | } |
1173 | } |
1162 | } |
1174 | } |
|
|
1175 | |
1163 | |
1176 | if (numitems == 0) |
1164 | buf << (numitems ? "T<This shop contains:>\n\n" |
1177 | { |
1165 | : "T<This shop is currently empty.>"); |
1178 | new_draw_info (NDI_UNIQUE, 0, op, "The shop is currently empty.\n"); |
|
|
1179 | free (items); |
|
|
1180 | return; |
|
|
1181 | } |
|
|
1182 | |
1166 | |
1183 | qsort (items, numitems, sizeof (shopinv), (int (*)(const void *, const void *)) shop_sort); |
1167 | qsort (items, numitems, sizeof (shopinv), (int (*)(const void *, const void *)) shop_sort); |
1184 | |
|
|
1185 | new_draw_info (NDI_UNIQUE, 0, op, "\nThe shop contains:"); |
|
|
1186 | |
1168 | |
1187 | for (i = 0; i < numitems; i++) |
1169 | for (i = 0; i < numitems; i++) |
1188 | { |
1170 | { |
1189 | /* Collapse items of the same name together */ |
1171 | /* Collapse items of the same name together */ |
1190 | if ((i + 1) < numitems && !strcmp (items[i].item_real, items[i + 1].item_real)) |
1172 | if ((i + 1) < numitems && !strcmp (items[i].item_real, items[i + 1].item_real)) |
1191 | { |
|
|
1192 | items[i + 1].nrof += items[i].nrof; |
1173 | items[i + 1].nrof += items[i].nrof; |
1193 | free (items[i].item_sort); |
|
|
1194 | free (items[i].item_real); |
|
|
1195 | } |
|
|
1196 | else |
1174 | else |
1197 | { |
|
|
1198 | new_draw_info_format (NDI_UNIQUE, 0, op, "%d %s", |
|
|
1199 | items[i].nrof ? items[i].nrof : 1, items[i].nrof == 1 ? items[i].item_sort : items[i].item_real); |
1175 | buf.printf (" %4d %s\n", items[i].nrof ? items[i].nrof : 1, items[i].nrof == 1 ? items[i].item_sort : items[i].item_real); |
|
|
1176 | |
1200 | free (items[i].item_sort); |
1177 | free (items[i].item_sort); |
1201 | free (items[i].item_real); |
1178 | free (items[i].item_real); |
1202 | } |
|
|
1203 | } |
1179 | } |
|
|
1180 | |
|
|
1181 | op->contr->infobox (MSG_CHANNEL ("shopitems"), buf); |
1204 | |
1182 | |
1205 | free (items); |
1183 | free (items); |
1206 | } |
1184 | } |
1207 | |
1185 | |
1208 | /* elmex: this function checks whether the object is in a shop */ |
1186 | /* elmex: this function checks whether the object is in a shop */ |