ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/shop.C
(Generate patch)

Comparing deliantra/server/server/shop.C (file contents):
Revision 1.56 by root, Mon Sep 29 10:20:49 2008 UTC vs.
Revision 1.77 by root, Sun Apr 4 02:51:57 2010 UTC

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,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team 5 * Copyright (©) 2002 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen 6 * Copyright (©) 1992 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>
25#include <spells.h> 26#include <spells.h>
26#include <skills.h> 27#include <skills.h>
27#include <living.h> 28#include <living.h>
28#include <sproto.h> 29#include <sproto.h>
29#include <math.h>
30 30
31/* this is a measure of how effective store specialisation is. A general store 31/* this is a measure of how effective store specialisation is. A general store
32 * will offer this proportion of the 'maximum' price, a specialised store will 32 * will offer this proportion of the 'maximum' price, a specialised store will
33 * offer a range of prices around it such that the maximum price is always one 33 * offer a range of prices around it such that the maximum price is always one
34 * therefore making this number higher, makes specialisation less effective. 34 * therefore making this number higher, makes specialisation less effective.
74 74
75sint64 75sint64
76query_cost (const object *tmp, object *who, int flag) 76query_cost (const object *tmp, object *who, int flag)
77{ 77{
78 double val; 78 double val;
79 int number; /* used to better calculate value */
80 int no_bargain; 79 int no_bargain;
81 int identified; 80 int identified;
82 int not_cursed; 81 int not_cursed;
83 int approximate; 82 int approximate;
84 int shop; 83 int shop;
109 108
110 LOG (llevError, "Query_cost: Gem type with unknown flag %d: %s\n", flag, tmp->debug_desc ()); 109 LOG (llevError, "Query_cost: Gem type with unknown flag %d: %s\n", flag, tmp->debug_desc ());
111 return 0; 110 return 0;
112 } 111 }
113 112
114 number = tmp->nrof; 113 int number = tmp->number_of ();
115 if (number == 0) 114
116 number = 1;
117 if (QUERY_FLAG (tmp, FLAG_IDENTIFIED) || !need_identify (tmp) || identified) 115 if (QUERY_FLAG (tmp, FLAG_IDENTIFIED) || !need_identify (tmp) || identified)
118 { 116 {
119 if (!not_cursed && (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED))) 117 if (!not_cursed && (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED)))
120 return 0; 118 return 0;
121 else 119 else
122 val = tmp->value * number; 120 val = tmp->value * number;
123 } 121 }
124 /* This area deals with objects that are not identified, but can be */ 122 /* This area deals with objects that are not identified, but can be */
125 else 123 else
126 { 124 {
127 if (tmp->arch != NULL)
128 {
129 if (flag == F_BUY) 125 if (flag == F_BUY)
126 {
127 LOG (llevError | logBacktrace, "Asking for buy-value of unidentified object: %s\n", tmp->debug_desc ());
128 val = tmp->arch->value * 50 * number;
129 }
130 else
131 { /* Trying to sell something, or get true value */
132 if (tmp->type == POTION)
133 val = number * 40; /* Don't want to give anything away */
134 else
130 { 135 {
131 LOG (llevError | logBacktrace, "Asking for buy-value of unidentified object.\n"); 136 /* Get 2/3'rd value for applied objects, 1/3'rd for totally
132 val = tmp->arch->value * 50 * number; 137 * unknown objects
138 */
139 if (QUERY_FLAG (tmp, FLAG_BEEN_APPLIED))
140 val = number * tmp->arch->value * 2 / 3;
141 else
142 val = number * tmp->arch->value / 3;
133 } 143 }
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 } 144 }
161 } 145 }
162 146
163 /* If the item has been applied or identifed or does not need to be 147 /* 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 148 * identified, AND the object is magical and the archetype is non
465 } 449 }
466 450
467 for (tmp = op->inv; tmp; tmp = tmp->below) 451 for (tmp = op->inv; tmp; tmp = tmp->below)
468 if (tmp->type == MONEY) 452 if (tmp->type == MONEY)
469 total += tmp->nrof * (sint64)tmp->value; 453 total += tmp->nrof * (sint64)tmp->value;
470 else if (tmp->type == CONTAINER && QUERY_FLAG (tmp, FLAG_APPLIED) && (tmp->race == NULL || strstr (tmp->race, "gold"))) 454 else if (tmp->type == CONTAINER && QUERY_FLAG (tmp, FLAG_APPLIED) && (!tmp->race || tmp->race.contains ("gold")))
471 total += query_money (tmp); 455 total += query_money (tmp);
472 456
473 return total; 457 return total;
474} 458}
475 459
490 return 0; 474 return 0;
491 475
492 pay_from_container (pl, pl, to_pay); 476 pay_from_container (pl, pl, to_pay);
493 477
494 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) 478 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"))) 479 if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && (!pouch->race || pouch->race.contains ("gold")))
496 pay_from_container (pl, pouch, to_pay); 480 pay_from_container (pl, pouch, to_pay);
497 481
498 pl->update_stats (); 482 pl->update_stats ();
499 return 1; 483 return 1;
500} 484}
527 change_exp (pl, saved_money, "bargaining", SK_EXP_NONE); 511 change_exp (pl, saved_money, "bargaining", SK_EXP_NONE);
528 512
529 pay_from_container (pl, pl, to_pay); 513 pay_from_container (pl, pl, to_pay);
530 514
531 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) 515 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"))) 516 if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && (!pouch->race || pouch->race.contains ("gold")))
533 pay_from_container (pl, pouch, to_pay); 517 pay_from_container (pl, pouch, to_pay);
534 518
535 pl->update_stats (); 519 pl->update_stats ();
536 520
537 return 1; 521 return 1;
577 // This should not happen, but if it does, just merge the two. 561 // This should not happen, but if it does, just merge the two.
578 if (coin_objs [i]) 562 if (coin_objs [i])
579 { 563 {
580 LOG (llevError, "%s has two money entries of (%s)\n", &pouch->name, coins[NUM_COINS - 1 - i]); 564 LOG (llevError, "%s has two money entries of (%s)\n", &pouch->name, coins[NUM_COINS - 1 - i]);
581 coin_objs[i]->nrof += tmp->nrof; 565 coin_objs[i]->nrof += tmp->nrof;
582 tmp->destroy (true); 566 tmp->destroy ();
583 } 567 }
584 else 568 else
585 { 569 {
586 tmp->remove (); 570 tmp->remove ();
587 coin_objs[i] = tmp; 571 coin_objs[i] = tmp;
604 at = archetype::find (coins[NUM_COINS - 1 - i]); 588 at = archetype::find (coins[NUM_COINS - 1 - i]);
605 589
606 if (at == NULL) 590 if (at == NULL)
607 LOG (llevError, "Could not find %s archetype\n", coins[NUM_COINS - 1 - i]); 591 LOG (llevError, "Could not find %s archetype\n", coins[NUM_COINS - 1 - i]);
608 592
609 coin_objs[i] = arch_to_object (at); 593 coin_objs[i] = at->instance ();
610 coin_objs[i]->nrof = 0; 594 coin_objs[i]->nrof = 0;
611 } 595 }
612 596
613 for (i = 0; i < NUM_COINS; i++) 597 for (i = 0; i < NUM_COINS; i++)
614 { 598 {
615 object &coin = *coin_objs[i]; 599 object &coin = *coin_objs[i];
616 sint64 num_coins = min ((to_pay + coin.value - 1) / coin.value, coin.nrof); 600 sint64 num_coins = min ((to_pay + coin.value - 1) / coin.value, (sint64) coin.nrof);
617 to_pay -= num_coins * coin.value; 601 to_pay -= num_coins * coin.value;
618 602
619 coin.nrof -= num_coins; 603 coin.nrof -= num_coins;
620 /* Now start making change. Start at the coin value 604 /* Now start making change. Start at the coin value
621 * below the one we just did, and work down to 605 * below the one we just did, and work down to
634 618
635 for (i = 0; i < NUM_COINS; i++) 619 for (i = 0; i < NUM_COINS; i++)
636 if (coin_objs[i]->nrof) 620 if (coin_objs[i]->nrof)
637 insert_ob_in_ob (coin_objs [i], pouch); 621 insert_ob_in_ob (coin_objs [i], pouch);
638 else 622 else
639 coin_objs[i]->destroy (true); 623 coin_objs[i]->destroy ();
640} 624}
641 625
642/* Checks all unpaid items in op's inventory, adds up all the money they 626/* Checks all unpaid items in op's inventory, adds up all the money they
643 * have, and checks that they can actually afford what they want to buy. 627 * have, and checks that they can actually afford what they want to buy.
644 * Returns 1 if they can, and 0 if they can't. also prints an appropriate message 628 * Returns 1 if they can, and 0 if they can't. also prints an appropriate message
664 unpaid_price += query_cost (item, pl, F_BUY | F_SHOP); 648 unpaid_price += query_cost (item, pl, F_BUY | F_SHOP);
665 } 649 }
666 650
667 if (unpaid_price > player_wealth) 651 if (unpaid_price > player_wealth)
668 { 652 {
669 dynbuf_text buf; 653 dynbuf_text &buf = msg_dynbuf; buf.clear ();
670 654
671 buf << "You have " << unpaid_count 655 buf << "You have " << unpaid_count
672 << " unpaid item(s) that would cost you " << cost_string_from_value (unpaid_price, 0) 656 << " 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) 657 << ". You need another " << cost_string_from_value (unpaid_price - player_wealth, 0)
674 << " to be able to afford that."; 658 << " to be able to afford that. "
659 "H<You cannot leave a shop without paying - drop unpaid items first to be able to leave.>";
675 660
676 pl->failmsg (buf); 661 pl->failmsg (buf);
677 662
678 return 0; 663 return 0;
679 } 664 }
754 LOG (llevError, "Could not find %s archetype\n", coins[count]); 739 LOG (llevError, "Could not find %s archetype\n", coins[count]);
755 else if ((amount / at->value) > 0) 740 else if ((amount / at->value) > 0)
756 { 741 {
757 for (pouch = pl->inv; pouch; pouch = pouch->below) 742 for (pouch = pl->inv; pouch; pouch = pouch->below)
758 { 743 {
759 if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && pouch->race && strstr (pouch->race, "gold")) 744 if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && pouch->race.contains ("gold"))
760 { 745 {
761 int w = at->weight * (100 - pouch->stats.Str) / 100; 746 int w = at->weight * (100 - pouch->stats.Str) / 100;
762 int n = amount / at->value; 747 int n = amount / at->value;
763 748
764 if (w == 0) 749 if (w == 0)
767 if (n > 0 && (!pouch->weight_limit || pouch->carrying + w <= pouch->weight_limit)) 752 if (n > 0 && (!pouch->weight_limit || pouch->carrying + w <= pouch->weight_limit))
768 { 753 {
769 if (pouch->weight_limit && (pouch->weight_limit - pouch->carrying) / w < n) 754 if (pouch->weight_limit && (pouch->weight_limit - pouch->carrying) / w < n)
770 n = (pouch->weight_limit - pouch->carrying) / w; 755 n = (pouch->weight_limit - pouch->carrying) / w;
771 756
772 object *tmp = arch_to_object (at); 757 object *tmp = at->instance ();
773 tmp->nrof = n; 758 tmp->nrof = n;
774 amount -= tmp->nrof * tmp->value; 759 amount -= tmp->nrof * tmp->value;
775 pouch->insert (tmp); 760 pouch->insert (tmp);
776 } 761 }
777 } 762 }
778 } 763 }
779 764
780 if (amount / at->value > 0) 765 if (amount / at->value > 0)
781 { 766 {
782 object *tmp = arch_to_object (at); 767 object *tmp = at->instance ();
783 tmp->nrof = amount / tmp->value; 768 tmp->nrof = amount / tmp->value;
784 amount -= tmp->nrof * tmp->value; 769 amount -= tmp->nrof * tmp->value;
785 pl->insert (tmp); 770 pl->insert (tmp);
786 } 771 }
787 } 772 }
866 */ 851 */
867static double 852static double
868shop_specialisation_ratio (const object *item, const maptile *map) 853shop_specialisation_ratio (const object *item, const maptile *map)
869{ 854{
870 shopitems *items = map->shopitems; 855 shopitems *items = map->shopitems;
871 double likedness = 0.; 856 int likedness = 0;
872 int i; 857 int i;
873 858
874 if (item == NULL) 859 if (item == NULL)
875 { 860 {
876 LOG (llevError, "shop_specialisation_ratio: passed a NULL item for map %s\n", &map->path); 861 LOG (llevError, "shop_specialisation_ratio: passed a NULL item for map %s\n", &map->path);
886 */ 871 */
887 return SPECIALISATION_EFFECT; 872 return SPECIALISATION_EFFECT;
888 } 873 }
889 874
890 if (map->shopitems) 875 if (map->shopitems)
891 {
892 for (i = 0; i < items[0].index; i++) 876 for (i = 0; i < items[0].index; i++)
893 if (items[i].typenum == item->type || (!items[i].typenum && likedness == 0.001)) 877 if (items[i].typenum == item->type || (!items[i].typenum && !likedness))
894 likedness = items[i].strength / 100.0; 878 likedness = items[i].strength;
895 }
896 879
897 if (likedness > 1.0) 880 if (likedness > 100)
898 { /* someone has been rather silly with the map headers. */ 881 { /* someone has been rather silly with the map headers. */
899 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is above 100%%\n", item->type, &map->path); 882 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is above 100%%\n", item->type, &map->path);
900 likedness = 1.0; 883 likedness = 100;
901 } 884 }
902 885
903 if (likedness < -1.0) 886 if (likedness < -100)
904 { 887 {
905 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is below -100%%\n", item->type, &map->path); 888 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is below -100%%\n", item->type, &map->path);
906 likedness = -1.0; 889 likedness = -100;
907 } 890 }
908 891
909 return lerp (likedness, -1., 1., SPECIALISATION_EFFECT, 1.); 892 return lerp (double (likedness), -100., 100., SPECIALISATION_EFFECT, 1.);
910} 893}
911 894
912/*returns the greed of the shop on map, or 1 if it isn't specified. */ 895/*returns the greed of the shop on map, or 1 if it isn't specified. */
913static double 896static double
914shop_greed (const maptile *map) 897shop_greed (const maptile *map)
964 tmpshopmax = map->shopmax ? map->shopmax : 100000; // 20 royalties default 947 tmpshopmax = map->shopmax ? map->shopmax : 100000; // 20 royalties default
965 948
966 if (map->shopmin && unit_price < map->shopmin) 949 if (map->shopmin && unit_price < map->shopmin)
967 return 0; 950 return 0;
968 else if (unit_price > tmpshopmax / 2) 951 else if (unit_price > tmpshopmax / 2)
969 newval = MIN ((tmpshopmax / 2) + isqrt (unit_price - tmpshopmax / 2), tmpshopmax); 952 newval = min ((tmpshopmax / 2) + isqrt (unit_price - tmpshopmax / 2), tmpshopmax);
970 else 953 else
971 newval = unit_price; 954 newval = unit_price;
972 } 955 }
973 956
974 newval *= quantity; 957 newval *= quantity;
978 961
979/* gives a desciption of the shop on their current map to the player op. */ 962/* gives a desciption of the shop on their current map to the player op. */
980int 963int
981describe_shop (const object *op) 964describe_shop (const object *op)
982{ 965{
966 dynbuf_text buf;
983 maptile *map = op->map; 967 maptile *map = op->map;
984 968
985 /*shopitems *items=map->shopitems; */ 969 /*shopitems *items=map->shopitems; */
986 int pos = 0, i; 970 int pos = 0, i;
987 double opinion = 0; 971 double opinion = 0;
988 char tmp[MAX_BUF] = "\0";
989 972
990 if (op->type != PLAYER) 973 if (op->type != PLAYER)
991 return 0; 974 return 0;
992 975
993 /*check if there is a shop specified for this map */ 976 /*check if there is a shop specified for this map */
994 if (map->shopitems || map->shopgreed || map->shoprace || map->shopmin || map->shopmax) 977 if (map->shopitems || map->shopgreed || map->shoprace || map->shopmin || map->shopmax)
995 { 978 {
996 new_draw_info (NDI_UNIQUE, 0, op, "From looking at the nearby shop you determine that it trades in:"); 979 buf << "From looking at the nearby shop you determine that it trades in ";
980 int lastcomma = 0, prevcomma = 0;
997 981
998 if (map->shopitems) 982 if (map->shopitems)
999 for (i = 0; i < map->shopitems[0].index; i++) 983 for (i = 0; i < map->shopitems[0].index; i++)
1000 if (map->shopitems[i].name && map->shopitems[i].strength > 10) 984 if (map->shopitems[i].name && map->shopitems[i].strength > 10)
1001 { 985 {
1002 snprintf (tmp + pos, sizeof (tmp) - pos, "%s, ", map->shopitems[i].name_pl); 986 buf << map->shopitems[i].name_pl;
1003 pos += strlen (tmp + pos); 987 prevcomma = lastcomma;
988 lastcomma = buf.size (); // remember offset
989 buf << ", ";
1004 } 990 }
1005 991
1006 if (!pos) 992 if (lastcomma)
993 {
994 buf.splice (lastcomma, 2);
995
996 if (prevcomma)
997 buf.splice (prevcomma, 2, " and ");
998 }
999 else
1007 strcat (tmp, "a little of everything."); 1000 buf << "a little of everything.";
1008 1001
1009 /* format the string into a list */ 1002 buf << ".\n\n";
1010 make_list_like (tmp);
1011 new_draw_info_format (NDI_UNIQUE, 0, op, "%s", tmp);
1012 1003
1013 if (map->shopmax) 1004 if (map->shopmax)
1014 new_draw_info_format (NDI_UNIQUE, 0, op, "It won't trade for items above %s.", cost_string_from_value (map->shopmax, 0)); 1005 buf << "It won't trade for items above " << cost_string_from_value (map->shopmax, 0) << ".\n\n";
1015 1006
1016 if (map->shopmin) 1007 if (map->shopmin)
1017 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)); 1008 buf << "It won't trade in items worth less than " << cost_string_from_value (map->shopmin, 0) << ".\n\n";
1018 1009
1019 if (map->shopgreed) 1010 if (map->shopgreed)
1020 { 1011 {
1021 if (map->shopgreed > 2.0) 1012 if (map->shopgreed > 2.0)
1022 new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge massively."); 1013 buf << "It tends to overcharge massively.\n\n";
1023 else if (map->shopgreed > 1.5) 1014 else if (map->shopgreed > 1.5)
1024 new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge substantially."); 1015 buf << "It tends to overcharge substantially.\n\n";
1025 else if (map->shopgreed > 1.1) 1016 else if (map->shopgreed > 1.1)
1026 new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge slightly."); 1017 buf << "It tends to overcharge slightly.\n\n";
1027 else if (map->shopgreed < 0.9) 1018 else if (map->shopgreed < 0.9)
1028 new_draw_info (NDI_UNIQUE, 0, op, "It tends to undercharge."); 1019 buf << "It tends to undercharge.\n\n";
1029 } 1020 }
1030 1021
1031 if (map->shoprace) 1022 if (map->shoprace)
1032 { 1023 {
1033 opinion = shopkeeper_approval (map, op); 1024 opinion = shopkeeper_approval (map, op);
1025
1034 if (opinion > 0.8) 1026 if (opinion > 0.8)
1035 new_draw_info (NDI_UNIQUE, 0, op, "You think the shopkeeper likes you."); 1027 buf << "You think the shopkeeper likes you.\n\n";
1036 else if (opinion > 0.5) 1028 else if (opinion > 0.5)
1037 new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper seems unconcerned by you."); 1029 buf << "The shopkeeper seems unconcerned by you.\n\n";
1038 else 1030 else
1039 new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper seems to have taken a dislike to you."); 1031 buf << "The shopkeeper seems to have taken a dislike to you.\n\n";
1040 } 1032 }
1041 } 1033 }
1042 else 1034 else
1043 new_draw_info (NDI_UNIQUE, 0, op, "There is no shop nearby."); 1035 buf << "There is no shop nearby.\n\n";
1036
1037 op->contr->infobox (MSG_CHANNEL ("shopinfo"), buf);
1044 1038
1045 return 1; 1039 return 1;
1046} 1040}
1047 1041
1048struct shopinv 1042struct shopinv
1116 items[*numitems].item_sort = strdup (query_base_name (tmp, 0)); 1110 items[*numitems].item_sort = strdup (query_base_name (tmp, 0));
1117 items[*numitems].item_real = strdup (query_base_name (tmp, 1)); 1111 items[*numitems].item_real = strdup (query_base_name (tmp, 1));
1118 (*numitems)++; 1112 (*numitems)++;
1119 break; 1113 break;
1120 } 1114 }
1115
1121 SET_FLAG (tmp, FLAG_UNPAID); 1116 SET_FLAG (tmp, FLAG_UNPAID);
1122} 1117}
1123 1118
1124void 1119void
1125shop_listing (object *sign, object *op) 1120shop_listing (object *sign, object *op)
1126{ 1121{
1127 int i, j, numitems = 0, numallocated = 0, x1, x2, y1, y2; 1122 int i, j, x1, x2, y1, y2;
1128 const char *shop_coords = sign->kv (shstr_shop_coords); 1123 const char *shop_coords = sign->kv (shstr_shop_coords);
1129 object *stack; 1124 object *stack;
1130 shopinv *items; 1125 shopinv *items;
1131 1126
1132 /* Should never happen, but just in case a monster does apply a sign */ 1127 /* Should never happen, but just in case a monster does apply a sign */
1133 if (op->type != PLAYER) 1128 if (!op->is_player ())
1134 return; 1129 return;
1130
1131 dynbuf_text &buf = msg_dynbuf; buf.clear ();
1135 1132
1136 if (!(shop_coords && sscanf (shop_coords, "%d,%d,%d,%d", &x1, &y1, &x2, &y2))) 1133 if (!(shop_coords && sscanf (shop_coords, "%d,%d,%d,%d", &x1, &y1, &x2, &y2)))
1137 { 1134 {
1138 x1 = 0; 1135 x1 = 0;
1139 y1 = 0; 1136 y1 = 0;
1140 x2 = op->map->width - 1; 1137 x2 = op->map->width - 1;
1141 y2 = op->map->height - 1; 1138 y2 = op->map->height - 1;
1142 } 1139 }
1143 1140
1144 items = (shopinv *) malloc (40 * sizeof (shopinv));
1145 numallocated = 40; 1141 int numallocated = 40;
1142 int numitems = 0;
1143 items = (shopinv *)malloc (sizeof (shopinv) * numallocated);
1146 1144
1147 /* Find all the appropriate items */ 1145 /* Find all the appropriate items */
1148 for (i = x1; i <= x2; i++) 1146 for (i = x1; i <= x2; i++)
1149 {
1150 for (j = y1; j < y2; j++) 1147 for (j = y1; j < y2; j++)
1148 if (op->map->is_in_shop (i, j))
1151 { 1149 {
1152 if (is_in_shop (op->map, i, j)) 1150 stack = GET_MAP_OB (op->map, i, j);
1151
1152 while (stack)
1153 { 1153 {
1154 stack = GET_MAP_OB (op->map, i, j); 1154 if (QUERY_FLAG (stack, FLAG_UNPAID))
1155
1156 while (stack)
1157 { 1155 {
1158 if (QUERY_FLAG (stack, FLAG_UNPAID))
1159 {
1160 if (numitems == numallocated) 1156 if (numitems == numallocated)
1161 {
1162 items = (shopinv *) realloc (items, sizeof (shopinv) * (numallocated + 10)); 1157 items = (shopinv *)realloc (items, sizeof (shopinv) * (numallocated *= 2));
1163 numallocated += 10;
1164 }
1165 1158
1166 add_shop_item (stack, items, &numitems, &numallocated); 1159 add_shop_item (stack, items, &numitems, &numallocated);
1167 }
1168
1169 stack = stack->above;
1170 } 1160 }
1161
1162 stack = stack->above;
1171 } 1163 }
1172 } 1164 }
1173 }
1174 1165
1175 if (numitems == 0) 1166 buf << (numitems ? "T<This shop contains:>\n\n"
1176 { 1167 : "T<This shop is currently empty.>");
1177 new_draw_info (NDI_UNIQUE, 0, op, "The shop is currently empty.\n");
1178 free (items);
1179 return;
1180 }
1181 1168
1182 qsort (items, numitems, sizeof (shopinv), (int (*)(const void *, const void *)) shop_sort); 1169 qsort (items, numitems, sizeof (shopinv), (int (*)(const void *, const void *)) shop_sort);
1183
1184 new_draw_info (NDI_UNIQUE, 0, op, "\nThe shop contains:");
1185 1170
1186 for (i = 0; i < numitems; i++) 1171 for (i = 0; i < numitems; i++)
1187 { 1172 {
1188 /* Collapse items of the same name together */ 1173 /* Collapse items of the same name together */
1189 if ((i + 1) < numitems && !strcmp (items[i].item_real, items[i + 1].item_real)) 1174 if ((i + 1) < numitems && !strcmp (items[i].item_real, items[i + 1].item_real))
1190 {
1191 items[i + 1].nrof += items[i].nrof; 1175 items[i + 1].nrof += items[i].nrof;
1192 free (items[i].item_sort);
1193 free (items[i].item_real);
1194 }
1195 else 1176 else
1196 {
1197 new_draw_info_format (NDI_UNIQUE, 0, op, "%d %s",
1198 items[i].nrof ? items[i].nrof : 1, items[i].nrof == 1 ? items[i].item_sort : items[i].item_real); 1177 buf.printf (" %4d %s\n", items[i].nrof ? items[i].nrof : 1, items[i].nrof == 1 ? items[i].item_sort : items[i].item_real);
1178
1199 free (items[i].item_sort); 1179 free (items[i].item_sort);
1200 free (items[i].item_real); 1180 free (items[i].item_real);
1201 }
1202 } 1181 }
1182
1183 op->contr->infobox (MSG_CHANNEL ("shopitems"), buf);
1203 1184
1204 free (items); 1185 free (items);
1205}
1206
1207/* elmex: this function checks whether the object is in a shop */
1208bool
1209is_in_shop (object *o)
1210{
1211 if (!o->is_on_map ())
1212 return false;
1213
1214 return is_in_shop (o->map, o->x, o->y);
1215} 1186}
1216 1187
1217/* elmex: this function checks whether we are in a shop or not 1188/* elmex: this function checks whether we are in a shop or not
1218 - change 2007-11-26: enhanced the O(n) case by stopping at the first 1189 - change 2007-11-26: enhanced the O(n) case by stopping at the first
1219 floor tile. this possibly will make map bugs where shopfloors are above 1190 floor tile. this possibly will make map bugs where shopfloors are above
1220 floors more obvious. 1191 floors more obvious.
1221*/ 1192*/
1222
1223bool 1193bool
1224is_in_shop (maptile *map, int x, int y) 1194maptile::is_in_shop (int x, int y) const
1225{ 1195{
1226 for (object *floor = GET_MAP_OB (map, x, y); floor; floor = floor->above) 1196 for (object *floor = at (x, y).bot; floor; floor = floor->above)
1227 if (QUERY_FLAG (floor, FLAG_IS_FLOOR)) 1197 if (floor->flag [FLAG_IS_FLOOR])
1228 return floor->type == SHOP_FLOOR; 1198 return floor->type == SHOP_FLOOR;
1229 1199
1230 return false; 1200 return false;
1231} 1201}
1232 1202

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines