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.85 by elmex, Wed May 5 09:42:52 2010 UTC vs.
Revision 1.95 by root, Sat Nov 17 23:40:04 2018 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 (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
4 * Copyright (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team 5 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2002 Mark Wedel & Crossfire Development Team 6 * Copyright (©) 2002 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992 Frank Tore Johansen 7 * Copyright (©) 1992 Frank Tore Johansen
7 * 8 *
8 * Deliantra is free software: you can redistribute it and/or modify it under 9 * Deliantra is free software: you can redistribute it and/or modify it under
9 * the terms of the Affero GNU General Public License as published by the 10 * the terms of the Affero GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your 11 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version. 12 * option) any later version.
12 * 13 *
13 * This program is distributed in the hope that it will be useful, 14 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details. 17 * GNU General Public License for more details.
17 * 18 *
18 * You should have received a copy of the Affero GNU General Public License 19 * You should have received a copy of the Affero GNU General Public License
19 * and the GNU General Public License along with this program. If not, see 20 * and the GNU General Public License along with this program. If not, see
20 * <http://www.gnu.org/licenses/>. 21 * <http://www.gnu.org/licenses/>.
21 * 22 *
22 * The authors can be reached via e-mail to <support@deliantra.net> 23 * The authors can be reached via e-mail to <support@deliantra.net>
23 */ 24 */
24 25
25#include <global.h> 26#include <global.h>
26#include <spells.h> 27#include <spells.h>
29#include <sproto.h> 30#include <sproto.h>
30 31
31/* this is a measure of how effective store specialisation is. A general store 32/* 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 33 * 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 34 * 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. 35 * therefore making this number higher, makes specialisation less effective.
35 * setting this value above 1 or to a negative value would have interesting, 36 * setting this value above 1 or to a negative value would have interesting,
36 * (though not useful) effects. 37 * (though not useful) effects.
37 */ 38 */
38#define SPECIALISATION_EFFECT .5 39#define SPECIALISATION_EFFECT .5
39 40
55 * would not be done. 56 * would not be done.
56 * 57 *
57 * Added F_APPROX flag, which means that the price returned should be wrong by 58 * Added F_APPROX flag, which means that the price returned should be wrong by
58 * an amount related to the player's bargaining skill. 59 * an amount related to the player's bargaining skill.
59 * 60 *
60 * Added F_SHOP flag to mean that the specialisation of the shop on the player's 61 * Added F_SHOP flag to mean that the specialisation of the shop on the player's
61 * current map should be taken into account when determining the price. Shops that 62 * current map should be taken into account when determining the price. Shops that
62 * specialise in what is being traded will give better prices than those that do not. 63 * specialise in what is being traded will give better prices than those that do not.
63 * 64 *
64 * CF 0.91.4 - This function got changed around a bit. Now the 65 * CF 0.91.4 - This function got changed around a bit. Now the
65 * number of object is multiplied by the value early on. This fixes problems 66 * number of object is multiplied by the value early on. This fixes problems
66 * with items worth very little. What happened before is that various 67 * with items worth very little. What happened before is that various
67 * divisions took place, the value got rounded to 0 (Being an int), and 68 * divisions took place, the value got rounded to 0 (Being an int), and
255 { 256 {
256 if (flag == F_SELL) 257 if (flag == F_SELL)
257 val *= shop_specialisation_ratio (tmp, who->map) * shopkeeper_approval (who->map, who) / shop_greed (who->map); 258 val *= shop_specialisation_ratio (tmp, who->map) * shopkeeper_approval (who->map, who) / shop_greed (who->map);
258 else if (flag == F_BUY) 259 else if (flag == F_BUY)
259 { 260 {
260 /* 261 /*
261 * when buying, if the item was sold by another player, it is ok to 262 * when buying, if the item was sold by another player, it is ok to
262 * let the item be sold cheaper, according to the specialisation of 263 * let the item be sold cheaper, according to the specialisation of
263 * the shop. If a player sold an item here, then his sale price was 264 * the shop. If a player sold an item here, then his sale price was
264 * multiplied by the specialisation ratio, to do the same to the buy 265 * multiplied by the specialisation ratio, to do the same to the buy
265 * price will not generate extra money. However, the 266 * price will not generate extra money. However, the
266 * same is not true of generated items, these have to /divide/ by the 267 * same is not true of generated items, these have to /divide/ by the
267 * specialisation, so that the price is never less than what they could 268 * specialisation, so that the price is never less than what they could
268 * be sold for (otherwise players could camp map resets to make money). 269 * be sold for (otherwise players could camp map resets to make money).
269 * In game terms, a non-specialist shop, might not recognise the true 270 * In game terms, a non-specialist shop, might not recognise the true
270 * value of the items they sell (much like how people sometimes find 271 * value of the items they sell (much like how people sometimes find
271 * antiques in a junk shop in real life). 272 * antiques in a junk shop in real life).
272 */ 273 */
273 if (tmp->flag [FLAG_PLAYER_SOLD]) 274 if (tmp->flag [FLAG_PLAYER_SOLD])
274 val *= shop_specialisation_ratio (tmp, who->map); 275 val *= shop_specialisation_ratio (tmp, who->map);
275 else 276 else
276 val /= shop_specialisation_ratio (tmp, who->map); 277 val /= shop_specialisation_ratio (tmp, who->map);
277 278
278 val *= shop_greed (who->map) / shopkeeper_approval (who->map, who); 279 val *= shop_greed (who->map) / shopkeeper_approval (who->map, who);
279 } 280 }
280 281
281 /* we will also have an extra 0-5% variation between shops of the same type 282 /* we will also have an extra 0-5% variation between shops of the same type
282 * for valuable items (below a value of 50 this effect wouldn't be very 283 * for valuable items (below a value of 50 this effect wouldn't be very
283 * pointful, and could give fun with rounding. 284 * pointful, and could give fun with rounding.
284 */ 285 */
285 //TODO: why use cosf at all, just % and scale linearly, gives more even distribution 286 //TODO: why use cosf at all, just % and scale linearly, gives more even distribution
286 if (val > 50) 287 if (val > 50)
287 val *= 1 + .05f * cosf ((tmp->uuid.seq & 0xffff) * M_PI * 2. / 0x10000); 288 val *= 1 + .05f * cosf ((tmp->uuid.seq & 0xffff) * M_PI * 2. / 0x10000);
443 } 444 }
444 445
445 for (tmp = op->inv; tmp; tmp = tmp->below) 446 for (tmp = op->inv; tmp; tmp = tmp->below)
446 if (tmp->type == MONEY) 447 if (tmp->type == MONEY)
447 total += tmp->nrof * (sint64)tmp->value; 448 total += tmp->nrof * (sint64)tmp->value;
448 else if (tmp->type == CONTAINER && tmp->flag [FLAG_APPLIED] && (!tmp->race || tmp->race.contains ("gold"))) 449 else if (tmp->type == CONTAINER && tmp->flag [FLAG_APPLIED] && (!tmp->race || tmp->race.contains (shstr_gold)))
449 total += query_money (tmp); 450 total += query_money (tmp);
450 451
451 return total; 452 return total;
452} 453}
453 454
468 return 0; 469 return 0;
469 470
470 pay_from_container (pl, pl, to_pay); 471 pay_from_container (pl, pl, to_pay);
471 472
472 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) 473 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below)
473 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && (!pouch->race || pouch->race.contains ("gold"))) 474 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && (!pouch->race || pouch->race.contains (shstr_gold)))
474 pay_from_container (pl, pouch, to_pay); 475 pay_from_container (pl, pouch, to_pay);
475 476
476 pl->update_stats (); 477 pl->update_stats ();
477 return 1; 478 return 1;
478} 479}
505 change_exp (pl, saved_money, shstr_bargaining, SK_EXP_NONE); 506 change_exp (pl, saved_money, shstr_bargaining, SK_EXP_NONE);
506 507
507 pay_from_container (pl, pl, to_pay); 508 pay_from_container (pl, pl, to_pay);
508 509
509 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) 510 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below)
510 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && (!pouch->race || pouch->race.contains ("gold"))) 511 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && (!pouch->race || pouch->race.contains (shstr_gold)))
511 pay_from_container (pl, pouch, to_pay); 512 pay_from_container (pl, pouch, to_pay);
512 513
513 pl->update_stats (); 514 pl->update_stats ();
514 515
515 return 1; 516 return 1;
617 coin_objs[i]->destroy (); 618 coin_objs[i]->destroy ();
618} 619}
619 620
620/* Checks all unpaid items in op's inventory, adds up all the money they 621/* Checks all unpaid items in op's inventory, adds up all the money they
621 * have, and checks that they can actually afford what they want to buy. 622 * have, and checks that they can actually afford what they want to buy.
622 * Returns 1 if they can, and 0 if they can't. also prints an appropriate message 623 * Returns 1 if they can, and 0 if they can't. also prints an appropriate message
623 * to the player 624 * to the player
624 */ 625 */
625int 626int
626can_pay (object *pl) 627can_pay (object *pl)
627{ 628{
720void 721void
721pay_player (object *pl, sint64 amount) 722pay_player (object *pl, sint64 amount)
722{ 723{
723 int count = 0; 724 int count = 0;
724 archetype *at = 0; 725 archetype *at = 0;
725 object *pouch = 0, *tmp = 0; 726 object *pouch = 0;
726 727
727 for (count = 0; coins[count]; count++) 728 for (count = 0; coins[count]; count++)
728 { 729 {
729 at = archetype::find (coins[count]); 730 at = archetype::find (coins[count]);
730 731
732 LOG (llevError, "Could not find %s archetype\n", coins[count]); 733 LOG (llevError, "Could not find %s archetype\n", coins[count]);
733 else if ((amount / at->value) > 0) 734 else if ((amount / at->value) > 0)
734 { 735 {
735 for (pouch = pl->inv; pouch; pouch = pouch->below) 736 for (pouch = pl->inv; pouch; pouch = pouch->below)
736 { 737 {
737 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && pouch->race.contains ("gold")) 738 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && pouch->race.contains (shstr_gold))
738 { 739 {
739 int w = at->weight * (100 - pouch->stats.Str) / 100; 740 int w = at->weight * (100 - pouch->stats.Str) / 100;
740 int n = amount / at->value; 741 int n = amount / at->value;
741 742
742 if (w == 0) 743 if (w == 0)
837 838
838 return true; 839 return true;
839} 840}
840 841
841/* returns a double that is the ratio of the price that a shop will offer for 842/* returns a double that is the ratio of the price that a shop will offer for
842 * item based on the shops specialisation. Does not take account of greed, 843 * item based on the shops specialisation. Does not take account of greed,
843 * returned value is between SPECIALISATION_EFFECT and 1. 844 * returned value is between SPECIALISATION_EFFECT and 1.
844 */ 845 */
845static double 846static double
846shop_specialisation_ratio (const object *item, const maptile *map) 847shop_specialisation_ratio (const object *item, const maptile *map)
847{ 848{
855 return 0; 856 return 0;
856 } 857 }
857 858
858 if (!item->type) 859 if (!item->type)
859 { 860 {
860 LOG (llevError, "shop_specialisation_ratio: passed an item with an invalid type\n"); 861 LOG (llevError, "shop_specialisation_ratio: passed an item with an invalid type: %s\n", item->debug_desc ());
861 /* 862 /*
862 * I'm not really sure what the /right/ thing to do here is, these types of 863 * I'm not really sure what the /right/ thing to do here is, these types of
863 * item shouldn't exist anyway, but returning the ratio is probably the best bet.." 864 * item shouldn't exist anyway, but returning the ratio is probably the best bet.."
864 */ 865 */
865 return SPECIALISATION_EFFECT; 866 return SPECIALISATION_EFFECT;
866 } 867 }
867 868
868 if (map->shopitems) 869 if (map->shopitems)
870 if (items[i].typenum == item->type || (!items[i].typenum && !likedness)) 871 if (items[i].typenum == item->type || (!items[i].typenum && !likedness))
871 likedness = items[i].strength; 872 likedness = items[i].strength;
872 873
873 if (likedness > 100) 874 if (likedness > 100)
874 { /* someone has been rather silly with the map headers. */ 875 { /* someone has been rather silly with the map headers. */
875 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is above 100%%\n", item->type, &map->path); 876 LOG (llevDebug, "shop_specialisation ratio: item %s on map %s is above 100%%\n", item->debug_desc (), &map->path);
876 likedness = 100; 877 likedness = 100;
877 } 878 }
878 879
879 if (likedness < -100) 880 if (likedness < -100)
880 { 881 {
881 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is below -100%%\n", item->type, &map->path); 882 LOG (llevDebug, "shop_specialisation ratio: item %s on map %s is below -100%%\n", item->debug_desc (), &map->path);
882 likedness = -100; 883 likedness = -100;
883 } 884 }
884 885
885 return lerp (double (likedness), -100., 100., SPECIALISATION_EFFECT, 1.); 886 return lerp (double (likedness), -100., 100., SPECIALISATION_EFFECT, 1.);
886} 887}
904 ? DISLIKE_RATIO 905 ? DISLIKE_RATIO
905 : 1.; 906 : 1.;
906} 907}
907 908
908/* limit the value of items based on the wealth of the shop. If the item is close 909/* limit the value of items based on the wealth of the shop. If the item is close
909 * to the maximum value a shop will offer, we start to reduce it, if the item is 910 * to the maximum value a shop will offer, we start to reduce it, if the item is
910 * below the minimum value the shop is prepared to trade in, then we don't 911 * below the minimum value the shop is prepared to trade in, then we don't
911 * want it and offer nothing. If it isn't a shop, check whether we should do generic 912 * want it and offer nothing. If it isn't a shop, check whether we should do generic
912 * value reduction. 913 * value reduction.
913 * 914 *
914 */ 915 */
915static sint64 916static sint64
916value_limit (sint64 val, int quantity, const object *who, int isshop) 917value_limit (sint64 val, int quantity, const object *who, int isshop)
917{ 918{
918 sint64 newval, unit_price, tmpshopmax; 919 sint64 newval, unit_price, tmpshopmax;
958{ 959{
959 dynbuf_text buf; 960 dynbuf_text buf;
960 maptile *map = op->map; 961 maptile *map = op->map;
961 962
962 /*shopitems *items=map->shopitems; */ 963 /*shopitems *items=map->shopitems; */
963 int pos = 0, i; 964 int i;
964 double opinion = 0; 965 double opinion = 0;
965 966
966 if (op->type != PLAYER) 967 if (op->type != PLAYER)
967 return 0; 968 return 0;
968 969
1112 1113
1113void 1114void
1114shop_listing (object *sign, object *op) 1115shop_listing (object *sign, object *op)
1115{ 1116{
1116 int i, j, x1, x2, y1, y2; 1117 int i, j, x1, x2, y1, y2;
1117 const char *shop_coords = sign->kv (shstr_shop_coords); 1118 const char *shop_coords = sign->kv [shstr_shop_coords];
1118 object *stack; 1119 object *stack;
1119 shopinv *items; 1120 shopinv *items;
1120 1121
1121 /* Should never happen, but just in case a monster does apply a sign */ 1122 /* Should never happen, but just in case a monster does apply a sign */
1122 if (!op->is_player ()) 1123 if (!op->is_player ())

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines