Crossfire Server, Trunk  1.75.0
shop.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
21 #include "global.h"
22 
23 #include <assert.h>
24 #include <cmath>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "shop.h"
29 #include "sproto.h"
30 
39 #define SPECIALISATION_EFFECT 0.5
40 
42 #define DISAPPROVAL_RATIO 0.2
43 
45 #define NEUTRAL_RATIO 0.8
46 
48 #define MAX_BUY_REDUCTION 0.1f
49 
50 #define MAX_SELL_EXTRA 0.1f
51 
52 static uint64_t pay_from_container(object *pl, object *pouch, uint64_t to_pay);
53 static uint64_t value_limit(uint64_t val, int quantity, const object *who, int isshop);
54 static double shop_specialisation_ratio(const object *item, const mapstruct *map);
55 static double shop_greed(const mapstruct *map);
56 
57 #define NUM_COINS 5
59 #define LARGEST_COIN_GIVEN 2
62 static const char *const coins[] = {
63  "ambercoin",
64  "jadecoin",
65  "platinacoin",
66  "goldcoin",
67  "silvercoin",
68  NULL
69 };
70 
75 uint64_t price_base(const object *obj) {
76  // When there are zero objects, there is really one.
77  const int number = NROF(obj);
78  const bool identified = is_identified(obj);
79  uint64_t val = (uint64_t)obj->value * number;
80 
81  // Objects with price adjustments skip the rest of the calculations.
82  const char *key = object_get_value(obj, "price_adjustment");
83  if (key != NULL) {
84  float ratio = atof(key);
85  return val * ratio;
86  }
87 
88  // Money and gems have fixed prices at shops.
89  if (obj->type == MONEY || obj->type == GEM) {
90  return val;
91  }
92 
93  // If unidentified, price item based on its archetype.
94  if (!identified && obj->arch) {
95  val = obj->arch->clone.value * number;
96  }
97 
103  if (QUERY_FLAG(obj, FLAG_BLESSED)){
104  val *= 1.15;
105  } else if (QUERY_FLAG(obj, FLAG_CURSED)) {
106  val *= 0.8;
107  } else if (QUERY_FLAG(obj, FLAG_DAMNED)) {
108  val *= 0.6;
109  }
110 
111  // If an item is identified to have an enchantment above its archetype
112  // enchantment, increase price exponentially.
113  if (obj->arch != NULL && identified) {
114  int diff = obj->magic - obj->arch->clone.magic;
115  val *= pow(1.15, diff);
116  }
117 
118  // FIXME: Is the 'baseline' 50 charges per wand?
119  if (obj->type == WAND) {
120  val *= obj->stats.food / 50.0;
121  }
122 
123  /* we need to multiply these by 4.0 to keep buy costs roughly the same
124  * (otherwise, you could buy a potion of charisma for around 400 pp.
125  * Arguable, the costs in the archetypes should be updated to better
126  * reflect values (potion charisma list for 1250 gold)
127  */
128  val *= 4; // FIXME
129 
130  return val;
131 }
132 
133 uint64_t price_approx(const object *tmp, object *who) {
134  uint64_t val = price_base(tmp);
135 
136  /* If we are approximating, then the value returned should
137  * be allowed to be wrong however merely using a random number
138  * each time will not be sufficient, as then multiple examinations
139  * would give different answers, so we'll use the count instead.
140  * By taking the sine of the count, a value between -1 and 1 is
141  * generated, we then divide by the square root of the bargaining
142  * skill and the appropriate identification skills, so that higher
143  * level players get better estimates. (We need a +1 there to
144  * prevent dividing by zero.)
145  */
146  const typedata *tmptype = get_typedata(tmp->type);
147  int lev_identify = 0;
148 
149  if (tmptype) {
150  int idskill1 = tmptype->identifyskill;
151  if (idskill1) {
152  int idskill2 = tmptype->identifyskill2;
153  if (find_skill_by_number(who, idskill1)) {
154  lev_identify = find_skill_by_number(who, idskill1)->level;
155  }
156  if (idskill2 && find_skill_by_number(who, idskill2)) {
157  lev_identify += find_skill_by_number(who, idskill2)->level;
158  }
159  }
160  } else {
161  LOG(llevError, "Query_cost: item %s hasn't got a valid type\n", tmp->name);
162  }
163  val += val * (sin(tmp->count) / sqrt(lev_identify * 3 + 1.0));
164 
165  return val;
166 }
167 
173 static float shop_cha_modifier(int charisma) {
174  return tanh((charisma+15.0)/20);
175 }
176 
184 float shop_efficiency(const object *player) {
185  return shop_greed(player->map)
186  * shop_approval(player->map, player)
187  * shop_cha_modifier(player->stats.Cha);
188 }
189 
190 uint64_t shop_price_buy(const object *tmp, object *who) {
191  assert(who != NULL && who->type == PLAYER);
192  const uint64_t val = price_base(tmp);
193  const char *key = object_get_value(tmp, "price_adjustment_buy");
194  float adj = 1;
195  if (key != NULL) {
196  adj = atof(key);
197  }
198  float E = shop_efficiency(who);
199  const float adj_val = val * adj / E;
200  if (getenv("CF_DEBUG_SHOP")) {
201  LOG(llevDebug, "price_buy %s %lu*adj(%.2f)/E(%.2f) = %.2f\n",
202  tmp->arch->name, val, adj, E, adj_val);
203  }
204  if (std::isfinite(adj_val)) {
205  return adj_val;
206  } else {
207  return UINT64_MAX;
208  }
209 }
210 
211 uint64_t shop_price_sell(const object *tmp, object *who) {
212  assert(who != NULL && who->type == PLAYER);
213  const uint64_t val = price_base(tmp);
214  const char *key = object_get_value(tmp, "price_adjustment_sell");
215  float adj = 1;
216  if (key != NULL) {
217  adj = atof(key);
218  }
219  float spec = shop_specialisation_ratio(tmp, who->map);
220  float E = shop_efficiency(who);
221  const uint64_t adj_val = val * adj * spec * E;
222 
223  /* Limit amount of money you can get for really great items. */
224  int number = NROF(tmp);
225  uint64_t limval = value_limit(adj_val, number, who, 1);
226 
227  if (getenv("CF_DEBUG_SHOP")) {
228  LOG(llevDebug, "price_sell %s %lu*adj(%.2f)*s(%.2f)*E(%.2f) = %lu limited to %lu\n",
229  tmp->arch->name, val, adj, spec, E, adj_val, limval);
230  }
231  return limval;
232 }
233 
245 static archetype *find_next_coin(uint64_t c, int *cointype) {
246  archetype *coin;
247 
248  do {
249  if (coins[*cointype] == NULL)
250  return NULL;
251  coin = find_archetype(coins[*cointype]);
252  if (coin == NULL)
253  return NULL;
254  *cointype += 1;
255  } while (coin->clone.value > (int64_t) c);
256 
257  return coin;
258 }
259 
277 char* cost_string_from_value(uint64_t cost, int largest_coin) {
278  archetype *coin, *next_coin;
279  uint32_t num;
280  int cointype = largest_coin;
281 
282  if (cointype < 0)
283  cointype = 0;
284  else if (cointype >= NUM_COINS)
285  cointype = NUM_COINS - 1;
286 
288  if (cost == UINT64_MAX) {
289  stringbuffer_append_string(buf, "an unimaginable sum of money");
290  goto done;
291  }
292 
293  coin = find_next_coin(cost, &cointype);
294  if (coin == NULL) {
295  stringbuffer_append_string(buf, "nothing");
296  goto done;
297  }
298 
299  num = cost/coin->clone.value;
300  /* so long as nrof is 32 bit, this is true.
301  * If it takes more coins than a person can possibly carry, this
302  * is basically true.
303  */
304  if ((cost/coin->clone.value) > UINT32_MAX) {
305  stringbuffer_append_string(buf, "an unimaginable sum of money");
306  goto done;
307  }
308 
309  cost -= (uint64_t)num*(uint64_t)coin->clone.value;
310  if (num == 1)
311  stringbuffer_append_printf(buf, "1 %s", coin->clone.name);
312  else
313  stringbuffer_append_printf(buf, "%u %ss", num, coin->clone.name);
314 
315  next_coin = find_next_coin(cost, &cointype);
316  if (next_coin == NULL)
317  goto done;
318 
319  do {
320  coin = next_coin;
321  num = cost/coin->clone.value;
322  cost -= (uint64_t)num*(uint64_t)coin->clone.value;
323 
324  if (cost == 0)
325  next_coin = NULL;
326  else
327  next_coin = find_next_coin(cost, &cointype);
328 
329  if (next_coin) {
330  /* There will be at least one more string to add to the list,
331  * use a comma.
332  */
334  } else {
336  }
337  if (num == 1)
338  stringbuffer_append_printf(buf, "1 %s", coin->clone.name);
339  else
340  stringbuffer_append_printf(buf, "%u %ss", num, coin->clone.name);
341  } while (next_coin);
342 
343 done:
344  return stringbuffer_finish(buf);
345 }
346 
357 static StringBuffer *real_money_value(const object *coin, StringBuffer *buf) {
358  assert(coin->type == MONEY);
359  assert(buf);
360 
361  stringbuffer_append_printf(buf, "%ld %s", (long)coin->nrof, coin->nrof == 1 ? coin->name : coin->name_pl);
362  return buf;
363 }
364 
365 char *cost_str(uint64_t cost) {
367 }
368 
369 char *cost_approx_str(const object *tmp, object *who) {
370  uint64_t approx_val = price_approx(tmp, who);
371  int idskill1 = 0;
372  int idskill2 = 0;
373  const typedata *tmptype;
374 
376 
377  /* money it's pretty hard to not give the exact price, so skip all logic and just return the real value. */
378  if (tmp->type == MONEY) {
380  }
381 
382  tmptype = get_typedata(tmp->type);
383  if (tmptype) {
384  idskill1 = tmptype->identifyskill;
385  idskill2 = tmptype->identifyskill2;
386  }
387 
388  /* we show an approximate price if
389  * 1) we are approximating
390  * 2) there either is no id skill(s) for the item, or we don't have them
391  * 3) we don't have bargaining skill either
392  */
393  if (!idskill1 || !find_skill_by_number(who, idskill1)) {
394  if (!idskill2 || !find_skill_by_number(who, idskill2)) {
395  if (!find_skill_by_number(who, SK_BARGAINING)) {
396  int num;
397  int cointype = LARGEST_COIN_GIVEN;
398  archetype *coin = find_next_coin(approx_val, &cointype);
399 
400  if (coin == NULL) {
401  stringbuffer_append_string(buf, "nothing");
402  return stringbuffer_finish(buf);
403  }
404 
405  num = approx_val/coin->clone.value;
406  if (num == 1)
407  stringbuffer_append_printf(buf, "about one %s", coin->clone.name);
408  else if (num < 5)
409  stringbuffer_append_printf(buf, "a few %s", coin->clone.name_pl);
410  else if (num < 10)
411  stringbuffer_append_printf(buf, "several %s", coin->clone.name_pl);
412  else if (num < 25)
413  stringbuffer_append_printf(buf, "a moderate amount of %s", coin->clone.name_pl);
414  else if (num < 100)
415  stringbuffer_append_printf(buf, "lots of %s", coin->clone.name_pl);
416  else if (num < 1000)
417  stringbuffer_append_printf(buf, "a great many %s", coin->clone.name_pl);
418  else
419  stringbuffer_append_printf(buf, "a vast quantity of %s", coin->clone.name_pl);
420  return stringbuffer_finish(buf);
421  }
422  }
423  }
424 
425  // If we get here, return the price we guessed.
427  return cost_str(approx_val);
428 }
429 
430 uint64_t query_money(const object *op) {
431  uint64_t total = 0;
432 
433  if (op->type != PLAYER && op->type != CONTAINER) {
434  LOG(llevError, "Query money called with non player/container\n");
435  return 0;
436  }
437  FOR_INV_PREPARE(op, tmp) {
438  if (tmp->type == MONEY) {
439  total += (uint64_t)tmp->nrof*(uint64_t)tmp->value;
440  } else if (tmp->type == CONTAINER
441  && QUERY_FLAG(tmp, FLAG_APPLIED)
442  && (tmp->race == NULL || strstr(tmp->race, "gold"))) {
443  total += query_money(tmp);
444  }
445  } FOR_INV_FINISH();
446  return total;
447 }
448 
461 int pay_for_amount(uint64_t to_pay, object *pl) {
462  if (to_pay == 0)
463  return 1;
464  if (to_pay > query_money(pl))
465  return 0;
466 
467  to_pay = pay_from_container(pl, pl, to_pay);
468 
469  FOR_INV_PREPARE(pl, pouch) {
470  if (to_pay <= 0)
471  break;
472  if (pouch->type == CONTAINER
473  && QUERY_FLAG(pouch, FLAG_APPLIED)
474  && (pouch->race == NULL || strstr(pouch->race, "gold"))) {
475  to_pay = pay_from_container(pl, pouch, to_pay);
476  }
477  } FOR_INV_FINISH();
478  if (to_pay > 0) {
479  LOG(llevError, "pay_for_amount: Cannot remove enough money -- %" FMT64U " remains\n", to_pay);
480  }
481 
482  fix_object(pl);
483  return 1;
484 }
485 
501 int pay_for_item(object *op, object *pl, uint64_t reduction) {
502  uint64_t to_pay = shop_price_buy(op, pl);
503  assert(to_pay >= reduction);
504  to_pay -= reduction;
505 
506  if (to_pay == 0)
507  return 1;
508  if (to_pay > query_money(pl))
509  return 0;
510 
511  to_pay = pay_from_container(pl, pl, to_pay);
512 
513  FOR_INV_PREPARE(pl, pouch) {
514  if (to_pay <= 0)
515  break;
516  if (pouch->type == CONTAINER
517  && QUERY_FLAG(pouch, FLAG_APPLIED)
518  && (pouch->race == NULL || strstr(pouch->race, "gold"))) {
519  to_pay = pay_from_container(pl, pouch, to_pay);
520  }
521  } FOR_INV_FINISH();
522  if (to_pay > 0) {
523  LOG(llevError, "pay_for_item: Cannot remove enough money -- %" FMT64U " remains\n", to_pay);
524  }
526  SET_FLAG(op, FLAG_WAS_WIZ);
527  fix_object(pl);
528  return 1;
529 }
530 
542 static int64_t remove_value(object *coin_objs[], int64_t remain) {
543  int i;
544 
545  for (i = 0; i < NUM_COINS; i++) {
546  int count;
547  int64_t num_coins;
548 
549  if ((int64_t)coin_objs[i]->nrof * coin_objs[i]->value > remain) {
550  num_coins = remain/coin_objs[i]->value;
551  if ((uint64_t)num_coins*(uint64_t)coin_objs[i]->value < (uint64_t) remain) {
552  num_coins++;
553  }
554  } else {
555  num_coins = coin_objs[i]->nrof;
556  }
557  remain -= (int64_t)num_coins*(int64_t)coin_objs[i]->value;
558  coin_objs[i]->nrof -= num_coins;
559  /* Now start making change. Start at the coin value
560  * below the one we just did, and work down to
561  * the lowest value.
562  */
563  count = i-1;
564  while (remain < 0 && count >= 0) {
565  num_coins = -remain/coin_objs[count]->value;
566  coin_objs[count]->nrof += num_coins;
567  remain += num_coins*coin_objs[count]->value;
568  count--;
569  }
570  }
571 
572  return remain;
573 }
574 
583 static void add_value(object *coin_objs[], int64_t value) {
584  int i;
585 
586  for (i = NUM_COINS-LARGEST_COIN_GIVEN-1; i >= 0; i--) {
587  uint32_t nrof;
588 
589  nrof = (uint32_t)(value/coin_objs[i]->value);
590  value -= nrof*coin_objs[i]->value;
591  coin_objs[i]->nrof += nrof;
592  }
593 }
594 
607 static void insert_objects(object *pl, object *container, object *objects[], int objects_len) {
608  int i, one = 0;
609 
610  for (i = 0; i < objects_len; i++) {
611  if (objects[i]->nrof > 0) {
612  object_insert_in_ob(objects[i], container);
613  one = 1;
614  } else {
616  }
617  }
618  if (one)
619  esrv_update_item(UPD_WEIGHT, pl, container);
620 }
621 
635 static uint64_t pay_from_container(object *pl, object *pouch, uint64_t to_pay) {
636  size_t i;
637  int64_t remain;
638  object *coin_objs[NUM_COINS];
639  object *other_money[16]; /* collects MONEY objects not matching coins[] */
640  size_t other_money_len; /* number of allocated entries in other_money[] */
641  archetype *at;
642 
643  if (pouch->type != PLAYER && pouch->type != CONTAINER)
644  return to_pay;
645 
646  remain = to_pay;
647  for (i = 0; i < NUM_COINS; i++)
648  coin_objs[i] = NULL;
649 
650  /* This hunk should remove all the money objects from the player/container */
651  other_money_len = 0;
652  FOR_INV_PREPARE(pouch, tmp) {
653  if (tmp->type == MONEY) {
654  for (i = 0; i < NUM_COINS; i++) {
655  if (!strcmp(coins[NUM_COINS-1-i], tmp->arch->name)
656  && (tmp->value == tmp->arch->clone.value)) {
657  /* This should not happen, but if it does, just
658  * merge the two.
659  */
660  if (coin_objs[i] != NULL) {
661  LOG(llevError, "%s has two money entries of (%s)\n", pouch->name, coins[NUM_COINS-1-i]);
662  object_remove(tmp);
663  coin_objs[i]->nrof += tmp->nrof;
665  } else {
666  object_remove(tmp);
667  coin_objs[i] = tmp;
668  }
669  break;
670  }
671  }
672  if (i == NUM_COINS) {
673  if (other_money_len >= sizeof(other_money)/sizeof(*other_money)) {
674  LOG(llevError, "pay_for_item: Cannot store non-standard money object %s\n", tmp->arch->name);
675  } else {
676  object_remove(tmp);
677  other_money[other_money_len++] = tmp;
678  }
679  }
680  }
681  } FOR_INV_FINISH();
682 
683  /* Fill in any gaps in the coin_objs array - needed to make change. */
684  /* Note that the coin_objs array goes from least value to greatest value */
685  for (i = 0; i < NUM_COINS; i++)
686  if (coin_objs[i] == NULL) {
687  at = find_archetype(coins[NUM_COINS-1-i]);
688  if (at == NULL) {
689  continue;
690  }
691  coin_objs[i] = object_new();
692  object_copy(&at->clone, coin_objs[i]);
693  coin_objs[i]->nrof = 0;
694  }
695 
696  /* Try to pay from standard coins first. */
697  remain = remove_value(coin_objs, remain);
698 
699  /* Now pay from non-standard coins until all is paid. */
700  for (i = 0; i < other_money_len && remain > 0; i++) {
701  uint32_t nrof;
702  object *coin;
703 
704  coin = other_money[i];
705 
706  /* Find the minimal number of coins to use. This prevents converting
707  * excess non-standard coins to standard money.
708  */
709  nrof = (remain+coin->value-1)/coin->value;
710  if (nrof > coin->nrof) {
711  nrof = coin->nrof;
712  }
713  coin->nrof -= nrof;
714  add_value(coin_objs, nrof*coin->value);
715 
716  remain = remove_value(coin_objs, remain);
717  }
718 
719  /* re-insert remaining coins into player */
720  insert_objects(pl, pouch, coin_objs, NUM_COINS);
721  insert_objects(pl, pouch, other_money, other_money_len);
722 
723  return(remain);
724 }
725 
726 uint64_t add_with_overflow(uint64_t a, uint64_t b) {
727  if (a == UINT64_MAX) {
728  return a;
729  }
730 
731  if (UINT64_MAX - a < b) {
732  // Overflow
733  return UINT64_MAX;
734  } else {
735  return a + b;
736  }
737 }
738 
739 struct unpaid_count {
740  object *pl;
741  int count;
742  uint64_t price;
743 };
744 
752 static void unpaid_iter(object *item, void (*callback)(object *item, void *data), void *data) {
754  if (QUERY_FLAG(item, FLAG_UNPAID)) {
755  callback(item, data);
756  }
757  if (item->inv) {
758  unpaid_iter(item->inv, callback, data);
759  }
761 }
762 
763 static void count_unpaid_callback(object *item, void *data) {
764  struct unpaid_count *args = (struct unpaid_count *)data;
765  args->count++;
766  args->price = add_with_overflow(args->price, shop_price_buy(item, args->pl));
767 }
768 
781 static void count_unpaid(object *pl, object *item, int *unpaid_count, uint64_t *unpaid_price) {
782  struct unpaid_count args = {pl, 0, 0};
783  unpaid_iter(item, count_unpaid_callback, &args);
784  *unpaid_count = args.count;
785  *unpaid_price = args.price;
786 }
787 
795 static void count_coins(object *item, uint32_t *coincount) {
797  /* Merely converting the player's monetary wealth won't do.
798  * If we did that, we could print the wrong numbers for the
799  * coins, so we count the money instead.
800  */
801  for (int i = 0; i < NUM_COINS; i++) {
802  if (!strcmp(coins[i], item->arch->name)) {
803  coincount[i] += item->nrof;
804  break;
805  }
806  }
807  if (item->inv) {
808  count_coins(item->inv, coincount);
809  }
811 }
812 
821 static uint64_t compute_price_variation_with_bargaining(object *pl, uint64_t price, float max_variation) {
823  if (skill && skill->level > 0) {
824  return rndm(0, price * (max_variation * skill->level / settings.max_level));
825  }
826  return 0;
827 }
828 
841 int can_pay(object *pl) {
842  int unpaid_count = 0, i;
843  uint64_t unpaid_price = 0;
844  uint32_t coincount[NUM_COINS];
845 
846  if (!pl || pl->type != PLAYER) {
847  LOG(llevError, "can_pay(): called against something that isn't a player\n");
848  return 0;
849  }
850  uint64_t player_wealth = query_money(pl);
851 
852  for (i = 0; i < NUM_COINS; i++)
853  coincount[i] = 0;
854 
855  count_unpaid(pl, pl->inv, &unpaid_count, &unpaid_price);
856  count_coins(pl->inv, coincount);
857 
858  if (unpaid_price > player_wealth) {
859  char buf[MAX_BUF], coinbuf[MAX_BUF];
860  int denominations = 0;
861  char *value = cost_str(unpaid_price);
862 
863  snprintf(buf, sizeof(buf), "You have %d unpaid items that would cost you %s, ", unpaid_count, value);
864  free(value);
865  for (i = 0; i < NUM_COINS; i++) {
866  if (coincount[i] > 0 && coins[i]) {
867  if (denominations == 0)
868  snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "but you only have");
869  denominations++;
870  archetype *arch = find_archetype(coins[i]);
871  if (arch != NULL)
872  {
873  snprintf(coinbuf, sizeof(coinbuf), " %u %s,", coincount[i], arch->clone.name_pl);
874  snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s", coinbuf);
875  }
876  }
877  }
878  if (denominations == 0)
879  snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "but you don't have any money.");
880  else if (denominations > 1)
884  return 0;
885  } else
886  return 1;
887 }
888 
889 static void shop_pay_unpaid_callback(object *op, void *data) {
890  object *pl = (object *)data;
891  char name_op[MAX_BUF];
892  uint64_t price = shop_price_buy(op, pl);
894  if (!pay_for_item(op, pl, reduction)) {
895  uint64_t i = price - query_money(pl);
896  char *missing = cost_str(i);
897 
898  CLEAR_FLAG(op, FLAG_UNPAID);
899  query_name(op, name_op, MAX_BUF);
902  "You lack %s to buy %s.",
903  missing, name_op);
904  free(missing);
905  SET_FLAG(op, FLAG_UNPAID);
906  return;
907  } else {
908  // TODO: Figure out how to pass in the shop owner for player shops.
909  if (events_execute_object_event(op, EVENT_BOUGHT, pl, NULL, NULL, SCRIPT_FIX_ALL) != 0)
910  return;
911 
912  object *tmp;
913  char *value = cost_str(price - reduction);
914 
915  CLEAR_FLAG(op, FLAG_UNPAID);
918  query_name(op, name_op, MAX_BUF);
919 
920  if (reduction > 0) {
921  char *reduction_str = cost_str(reduction);
924  "You paid %s for %s after bargaining a reduction of %s.",
925  value, name_op, reduction_str);
926  change_exp(pl, reduction, "bargaining", SK_EXP_NONE);
927  free(reduction_str);
928  } else {
931  "You paid %s for %s.",
932  value, name_op);
933  }
934  free(value);
935  tmp = object_merge(op, NULL);
936  if (pl->type == PLAYER && !tmp) {
937  /* If item wasn't merged we update it. If merged, object_merge() handled everything for us. */
939  }
940  }
941 }
942 
949 int shop_pay_unpaid(object *pl, object *op) {
950  if (!op) {
951  return 1;
952  }
954  return 1;
955 }
956 
968 void sell_item(object *op, object *pl) {
969  object *tmp;
970  archetype *at;
971  char obj_name[MAX_BUF];
972 
973  query_name(op, obj_name, MAX_BUF);
974 
975  if (pl == NULL || pl->type != PLAYER) {
976  LOG(llevDebug, "Object other than player tried to sell something.\n");
977  return;
978  }
979 
980  if (events_execute_object_event(op, EVENT_SELLING, pl, NULL, NULL, SCRIPT_FIX_ALL) != 0)
981  return;
982 
984 
985  object_set_value(op, CUSTOM_NAME_FIELD, NULL, 0);
986 
987  uint64_t price = shop_price_sell(op, pl);
988  if (price == 0) {
991  "We're not interested in %s.",
992  obj_name);
993  return;
994  }
995 
997  char *value_str = cost_str(price + extra_gain);
998 
999  if (extra_gain > 0) {
1000  change_exp(pl, extra_gain, "bargaining", SK_EXP_NONE);
1001  char *extra_str = cost_str(extra_gain);
1003  "You receive %s for %s, after bargaining for %s more than proposed.", value_str, obj_name, extra_str);
1004  free(extra_str);
1005  price += extra_gain;
1006  } else {
1008  "You receive %s for %s.", value_str, obj_name);
1009  }
1010  free(value_str);
1011 
1012  for (int count = LARGEST_COIN_GIVEN; coins[count] != NULL; count++) {
1013  at = find_archetype(coins[count]);
1014  if (at == NULL)
1015  LOG(llevError, "Could not find %s archetype\n", coins[count]);
1016  else if ((price/at->clone.value) > 0) {
1017  FOR_INV_PREPARE(pl, pouch) {
1018  if (pouch->type == CONTAINER
1019  && QUERY_FLAG(pouch, FLAG_APPLIED)
1020  && pouch->race
1021  && strstr(pouch->race, "gold")) {
1022  int w = at->clone.weight*(100-pouch->stats.Str)/100;
1023  int n = price/at->clone.value;
1024 
1025  if (w == 0)
1026  w = 1; /* Prevent divide by zero */
1027  if (n > 0
1028  && (!pouch->weight_limit || pouch->carrying+w <= pouch->weight_limit)) {
1029  if (pouch->weight_limit
1030  && (pouch->weight_limit-pouch->carrying)/w < n)
1031  n = (pouch->weight_limit-pouch->carrying)/w;
1032 
1033  tmp = object_new();
1034  object_copy(&at->clone, tmp);
1035  tmp->nrof = n;
1036  price -= (uint64_t)tmp->nrof*(uint64_t)tmp->value;
1037  tmp = object_insert_in_ob(tmp, pouch);
1039  }
1040  }
1041  } FOR_INV_FINISH();
1042  if (price/at->clone.value > 0) {
1043  tmp = object_new();
1044  object_copy(&at->clone, tmp);
1045  tmp->nrof = price/tmp->value;
1046  price -= (uint64_t)tmp->nrof*(uint64_t)tmp->value;
1047  tmp = object_insert_in_ob(tmp, pl);
1049  }
1050  }
1051  }
1052 
1053  if (price != 0) {
1054  LOG(llevError, "Warning - payment not zero: %" PRIo64 "\n", price);
1055  }
1056 
1057  SET_FLAG(op, FLAG_UNPAID);
1058  identify(op);
1059 }
1060 
1076 static double shop_specialisation_ratio(const object *item, const mapstruct *map) {
1077  shopitems *items = map->shopitems;
1078  double ratio = SPECIALISATION_EFFECT, likedness = 0.001;
1079  int i;
1080 
1081  if (item == NULL) {
1082  LOG(llevError, "shop_specialisation_ratio: passed a NULL item for map %s\n", map->path);
1083  return 0;
1084  }
1085  if (item->type == (uint8_t)-1) {
1086  LOG(llevError, "shop_specialisation_ratio: passed an item with an invalid type\n");
1087  /*
1088  * I'm not really sure what the /right/ thing to do here is,
1089  * these types of item shouldn't exist anyway, but returning
1090  * the ratio is probably the best bet.."
1091  */
1092  return ratio;
1093  }
1094  if (map->shopitems) {
1095  for (i = 0; i < items[0].index; i++)
1096  if (items[i].typenum == item->type || (items[i].typenum == -1 && likedness == 0.001))
1097  likedness = items[i].strength/100.0;
1098  }
1099  if (likedness > 1.0) { /* someone has been rather silly with the map headers. */
1100  LOG(llevDebug, "shop_specialisation ratio: item type %d on map %s is above 100%%\n", item->type, map->path);
1101  likedness = 1.0;
1102  }
1103  if (likedness < -1.0) {
1104  LOG(llevDebug, "shop_specialisation ratio: item type %d on map %s is below -100%%\n", item->type, map->path);
1105  likedness = -1.0;
1106  }
1107  ratio = ratio+(1.0-ratio)*likedness;
1108  if (ratio <= 0.1)
1109  ratio = 0.1; /* if the ratio were much lower than this, we would get silly prices */
1110  return ratio;
1111 }
1112 
1127 static double shop_greed(const mapstruct *map) {
1128  float greed = map->shopgreed;
1129  if (greed == 0) {
1130  greed = 1;
1131  }
1132  return tanh(-greed+2.0)/2 + 0.5;
1133 }
1134 
1135 double shop_approval(const mapstruct *map, const object *player) {
1136  double approval = 1.0;
1137  if (map->shoprace) {
1138  approval = NEUTRAL_RATIO;
1139  if (player->race && !strcmp(player->race, map->shoprace))
1140  approval = 1.0;
1141  }
1142  return approval;
1143 }
1144 
1164 static uint64_t value_limit(uint64_t val, int quantity, const object *who, int isshop) {
1165  uint64_t newval, unit_price;
1166  mapstruct *map;
1167 
1168  unit_price = val/quantity;
1169  if (!isshop || !who) {
1170  if (unit_price > 10000)
1171  newval = 8000+isqrt(unit_price)*20;
1172  else
1173  newval = unit_price;
1174  } else {
1175  if (!who->map) {
1176  LOG(llevError, "value_limit: asked shop price for ob %s on NULL map\n", who->name);
1177  return val;
1178  }
1179  map = who->map;
1180  if (map->shopmin && unit_price < map->shopmin)
1181  return 0;
1182  else if (unit_price > map->shopmax/2)
1183  newval = MIN((map->shopmax/2)+isqrt(unit_price-map->shopmax/2), map->shopmax);
1184  else if (unit_price > 10000)
1185  newval = 8000+isqrt(unit_price)*20;
1186  else
1187  newval = unit_price;
1188  }
1189  newval *= quantity;
1190  return newval;
1191 }
1192 
1198 int shop_describe(const object *op) {
1199  mapstruct *map = op->map;
1200  /*shopitems *items=map->shopitems;*/
1201  int pos = 0, i;
1202  double opinion = 0;
1203  char tmp[MAX_BUF] = "\0", *value;
1204 
1205  if (op->type != PLAYER)
1206  return 0;
1207 
1208  /*check if there is a shop specified for this map */
1209  if (map->shopitems
1210  || map->shopgreed
1211  || map->shoprace
1212  || map->shopmin
1213  || map->shopmax) {
1215  "From looking at the nearby shop you determine that it trades in:");
1216 
1217  if (map->shopitems) {
1218  for (i = 0; i < map->shopitems[0].index; i++) {
1219  if (map->shopitems[i].name && map->shopitems[i].strength > 10) {
1220  snprintf(tmp+pos, sizeof(tmp)-pos, "%s, ", map->shopitems[i].name_pl);
1221  pos += strlen(tmp+pos);
1222  }
1223  }
1224  }
1225  if (!pos)
1226  strcpy(tmp, "a little of everything.");
1227 
1228  /* format the string into a list */
1229  make_list_like(tmp);
1230  draw_ext_info(NDI_UNIQUE, 0, op,
1232 
1233  if (map->shopmax) {
1234  value = cost_str(map->shopmax);
1237  "It won't trade for items above %s.",
1238  value);
1239  free(value);
1240  }
1241 
1242  if (map->shopmin) {
1243  value = cost_str(map->shopmin);
1246  "It won't trade in items worth less than %s.",
1247  value);
1248  free(value);
1249  }
1250 
1251  if (map->shopgreed) {
1252  if (map->shopgreed > 2.0)
1253  draw_ext_info(NDI_UNIQUE, 0, op,
1255  "It tends to overcharge massively.");
1256  else if (map->shopgreed > 1.5)
1257  draw_ext_info(NDI_UNIQUE, 0, op,
1259  "It tends to overcharge substantially.");
1260  else if (map->shopgreed > 1.1)
1261  draw_ext_info(NDI_UNIQUE, 0, op,
1263  "It tends to overcharge slightly.");
1264  else if (map->shopgreed < 0.9)
1265  draw_ext_info(NDI_UNIQUE, 0, op,
1267  "It tends to undercharge.");
1268  }
1269  if (map->shoprace) {
1270  opinion = shop_approval(map, op);
1271  if (opinion > 0.8)
1272  draw_ext_info(NDI_UNIQUE, 0, op,
1274  "You think the shopkeeper likes you.");
1275  else if (opinion > 0.5)
1276  draw_ext_info(NDI_UNIQUE, 0, op,
1278  "The shopkeeper seems unconcerned by you.");
1279  else
1280  draw_ext_info(NDI_UNIQUE, 0, op,
1282  "The shopkeeper seems to have taken a dislike to you.");
1283  }
1285  "There is no shop nearby.");
1286 
1287  return 1;
1288 }
1289 
1293 static bool coords_in_shop(mapstruct *map, int x, int y) {
1294  FOR_MAP_PREPARE(map, x, y, floor)
1295  if (floor->type == SHOP_FLOOR) return true;
1296  FOR_MAP_FINISH();
1297  return false;
1298 }
1299 
1300 bool shop_contains(object *ob) {
1301  if (!ob->map) return 0;
1302  return coords_in_shop(ob->map, ob->x, ob->y);
1303 }
mapstruct::shopgreed
double shopgreed
How much our shopkeeper overcharges.
Definition: map.h:348
EVENT_GSOLD
#define EVENT_GSOLD
Player sold object in shop, but global.
Definition: events.h:58
object::name_pl
sstring name_pl
The plural name of the object.
Definition: object.h:323
cost_approx_str
char * cost_approx_str(const object *tmp, object *who)
Return a textual cost approximation in a newly-allocated string.
Definition: shop.cpp:369
shopitems::strength
int8_t strength
The degree of specialisation the shop has in this item, as a percentage from -100 to 100.
Definition: map.h:299
shop_approval
double shop_approval(const mapstruct *map, const object *player)
Return the approval ratio for a shop for a given player.
Definition: shop.cpp:1135
PLAYER
@ PLAYER
Definition: object.h:112
global.h
sell_item
void sell_item(object *op, object *pl)
Player is selling an item.
Definition: shop.cpp:968
settings
struct Settings settings
Server settings.
Definition: init.cpp:139
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:724
shop_cha_modifier
static float shop_cha_modifier(int charisma)
Calculate the buy price multiplier based on a player's charisma.
Definition: shop.cpp:173
Settings::max_level
int16_t max_level
This is read out of exp_table.
Definition: global.h:304
unpaid_count::price
uint64_t price
Definition: shop.cpp:742
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
find_skill_by_number
object * find_skill_by_number(object *who, int skillno)
This returns the first skill pointer of the given subtype (the one that accumulates exp,...
Definition: main.cpp:375
WAND
@ WAND
Definition: object.h:225
unpaid_count::count
int count
Definition: shop.cpp:741
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
player
One player.
Definition: player.h:105
object::inv
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
LARGEST_COIN_GIVEN
#define LARGEST_COIN_GIVEN
Never give amber or jade, but accept them.
Definition: shop.cpp:59
MAX_SELL_EXTRA
#define MAX_SELL_EXTRA
Maximum price increase when selling an item with bargaining skill.
Definition: shop.cpp:50
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
mapstruct::shopmin
uint64_t shopmin
Minimum price a shop will trade for.
Definition: map.h:349
compute_price_variation_with_bargaining
static uint64_t compute_price_variation_with_bargaining(object *pl, uint64_t price, float max_variation)
Compute a percent of the price which will be used as extra or reduction.
Definition: shop.cpp:821
unpaid_iter
static void unpaid_iter(object *item, void(*callback)(object *item, void *data), void *data)
Search for unpaid items in 'item' and call 'callback' on each item.
Definition: shop.cpp:752
EVENT_GBOUGHT
#define EVENT_GBOUGHT
Player bought object in shop, but global.
Definition: events.h:57
object_merge
object * object_merge(object *op, object *top)
This function goes through all objects below and including top, and merges op to the first matching o...
Definition: object.cpp:2051
cost_str
char * cost_str(uint64_t cost)
Definition: shop.cpp:365
stringbuffer_append_printf
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Append a formatted string to a string buffer instance.
Definition: stringbuffer.cpp:138
find_next_coin
static archetype * find_next_coin(uint64_t c, int *cointype)
Find the coin type that is worth more than 'c'.
Definition: shop.cpp:245
FALSE
#define FALSE
Definition: compat.h:14
add_value
static void add_value(object *coin_objs[], int64_t value)
This function adds a given amount to a list of coins.
Definition: shop.cpp:583
c
static event_registration c
Definition: citylife.cpp:422
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
SPECIALISATION_EFFECT
#define SPECIALISATION_EFFECT
This is a measure of how effective store specialisation is.
Definition: shop.cpp:39
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.cpp:57
coords_in_shop
static bool coords_in_shop(mapstruct *map, int x, int y)
Check if the given map coordinates are in a shop.
Definition: shop.cpp:1293
UPD_WEIGHT
#define UPD_WEIGHT
Definition: newclient.h:319
SHOP_FLOOR
@ SHOP_FLOOR
Definition: object.h:188
if
if(!(yy_init))
Definition: loader.cpp:36428
GEM
@ GEM
Definition: object.h:172
object::x
int16_t x
Definition: object.h:335
price_approx
uint64_t price_approx(const object *tmp, object *who)
Adjust the value of the given item based on the player's skills.
Definition: shop.cpp:133
insert_objects
static void insert_objects(object *pl, object *container, object *objects[], int objects_len)
Insert a list of objects into a player object.
Definition: shop.cpp:607
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
typedata::identifyskill
int identifyskill
Skill used to identify this object class.
Definition: define.h:93
shopitems::index
int index
Being the size of the shopitems array.
Definition: map.h:301
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
MIN
#define MIN(x, y)
Definition: compat.h:21
object::count
tag_t count
Unique object number for this object.
Definition: object.h:307
object_copy
void object_copy(const object *src_ob, object *dest_ob)
Copy object first frees everything allocated by the second object, and then copies the contents of th...
Definition: object.cpp:1192
fix_object
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.cpp:1132
FLAG_BLESSED
#define FLAG_BLESSED
Item has a blessing, opposite of cursed/damned.
Definition: define.h:369
shop_pay_unpaid_callback
static void shop_pay_unpaid_callback(object *op, void *data)
Definition: shop.cpp:889
MSG_TYPE_SHOP_PAYMENT
#define MSG_TYPE_SHOP_PAYMENT
Messages about payment, lack of funds.
Definition: newclient.h:513
coins
static const char *const coins[]
Coins to use for shopping.
Definition: shop.cpp:62
rndm
int rndm(int min, int max)
Returns a number between min and max.
Definition: utils.cpp:162
SK_EXP_NONE
#define SK_EXP_NONE
Player gets nothing.
Definition: skills.h:80
NEUTRAL_RATIO
#define NEUTRAL_RATIO
Price a shopkeeper will give someone they neither like nor dislike.
Definition: shop.cpp:45
mapstruct::path
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:355
object_get_value
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4346
MSG_TYPE_SHOP_MISC
#define MSG_TYPE_SHOP_MISC
Random messages.
Definition: newclient.h:516
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
events_execute_object_event
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Execute an event on the specified object.
Definition: events.cpp:308
buf
StringBuffer * buf
Definition: readable.cpp:1565
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.cpp:2857
pay_for_item
int pay_for_item(object *op, object *pl, uint64_t reduction)
Player attemps to buy an item, if she has enough money then remove coins as needed from active contai...
Definition: shop.cpp:501
NUM_COINS
#define NUM_COINS
Number of coin types.
Definition: shop.cpp:57
real_money_value
static StringBuffer * real_money_value(const object *coin, StringBuffer *buf)
Returns a string representing the money's value, in plain coins.
Definition: shop.cpp:357
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
mapstruct::shopitems
struct shopitems * shopitems
List of item-types the map's shop will trade in.
Definition: map.h:346
typedata
Link an object type with skill needed to identify, and general name.
Definition: define.h:89
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
Definition: stringbuffer.cpp:76
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1560
NROF
static uint32_t NROF(const object *const ob)
Returns ob->nrof, unless it is 0, in which case return 1.
Definition: object.h:625
FLAG_WAS_WIZ
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:234
get_typedata
const typedata * get_typedata(int itemtype)
Definition: item.cpp:323
shop_price_sell
uint64_t shop_price_sell(const object *tmp, object *who)
Adjust the value of an item to be sold based on the player's bargaining skill and charisma.
Definition: shop.cpp:211
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:588
EVENT_SELLING
#define EVENT_SELLING
Object is being sold by another one.
Definition: events.h:30
shop_pay_unpaid
int shop_pay_unpaid(object *pl, object *op)
Pay as many unpaid items as possible, recursing on op->inv and op->below.
Definition: shop.cpp:949
query_money
uint64_t query_money(const object *op)
Determine the amount of money the given object contains, including what is inside containers.
Definition: shop.cpp:430
shop_specialisation_ratio
static double shop_specialisation_ratio(const object *item, const mapstruct *map)
Returns the ratio of the price that a shop will offer for an item based on the shop's specialisation.
Definition: shop.cpp:1076
mapstruct::shoprace
char * shoprace
The preffered race of the local shopkeeper.
Definition: map.h:347
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:748
unpaid_count
Definition: shop.cpp:739
CONTAINER
@ CONTAINER
Definition: object.h:236
done
int done
Definition: readable.cpp:1566
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:387
object::value
int32_t value
How much money it is worth (or contains)
Definition: object.h:360
is_identified
int is_identified(const object *op)
Return true if the item is identified, either because it is of a type that doesn't ever need identifi...
Definition: item.cpp:1353
isqrt
int isqrt(int n)
Compute the square root.
Definition: utils.cpp:562
cost_string_from_value
char * cost_string_from_value(uint64_t cost, int largest_coin)
Converts a price to number of coins.
Definition: shop.cpp:277
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
FLAG_DAMNED
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:317
object::magic
int8_t magic
Any magical bonuses to this item.
Definition: object.h:358
MAX_BUY_REDUCTION
#define MAX_BUY_REDUCTION
Maximum price reduction when buying an item with bargaining skill.
Definition: shop.cpp:48
UPD_FLAGS
#define UPD_FLAGS
Definition: newclient.h:318
shopitems::name_pl
const char * name_pl
Plural name.
Definition: map.h:297
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:671
living::food
int32_t food
How much food in stomach.
Definition: living.h:48
change_exp
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Changes experience to a player/monster.
Definition: living.cpp:2179
SK_BARGAINING
@ SK_BARGAINING
Bargaining.
Definition: skills.h:28
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
add_with_overflow
uint64_t add_with_overflow(uint64_t a, uint64_t b)
Definition: shop.cpp:726
sproto.h
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
Definition: stringbuffer.cpp:95
FOR_OB_AND_BELOW_PREPARE
#define FOR_OB_AND_BELOW_PREPARE(op_)
Constructs a loop iterating over an object and all objects below it in the same pile.
Definition: define.h:744
MSG_TYPE_SHOP
#define MSG_TYPE_SHOP
Definition: newclient.h:406
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
shop_describe
int shop_describe(const object *op)
A player is examining a shop, so describe it.
Definition: shop.cpp:1198
object_new
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it.
Definition: object.cpp:1273
shopitems::typenum
int typenum
Itemtype number we need to match, -1 if it is the default price.
Definition: map.h:298
EVENT_BOUGHT
#define EVENT_BOUGHT
Object is being bought by player.
Definition: events.h:23
mapstruct::shopmax
uint64_t shopmax
MMaximum price a shop will offer.
Definition: map.h:350
object::weight
int32_t weight
Attributes of the object.
Definition: object.h:375
StringBuffer
A buffer that will be expanded as content is added to it.
Definition: stringbuffer.cpp:25
value_limit
static uint64_t value_limit(uint64_t val, int quantity, const object *who, int isshop)
Limit the value of items based on the wealth of the shop.
Definition: shop.cpp:1164
count_coins
static void count_coins(object *item, uint32_t *coincount)
Count the number of coins for each type, for all items below item and in inventory.
Definition: shop.cpp:795
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:717
shop_price_buy
uint64_t shop_price_buy(const object *tmp, object *who)
Adjust the value of an item to be bought based on the player's bargaining skill and charisma.
Definition: shop.cpp:190
UINT32_MAX
#define UINT32_MAX
Definition: loader.cpp:84
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:265
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
MSG_TYPE_SHOP_SELL
#define MSG_TYPE_SHOP_SELL
Messages about selling items.
Definition: newclient.h:515
shopitems::name
const char * name
Name of the item in question, null if it is the default item.
Definition: map.h:296
shop_contains
bool shop_contains(object *ob)
Check if an object is in a shop.
Definition: shop.cpp:1300
stringbuffer_delete
void stringbuffer_delete(StringBuffer *sb)
Totally delete a string buffer.
Definition: stringbuffer.cpp:71
remove_value
static int64_t remove_value(object *coin_objs[], int64_t remain)
This function removes a given amount from a list of coins.
Definition: shop.cpp:542
price_base
uint64_t price_base(const object *obj)
Price an item based on its value or archetype value, type, identification/BUC status,...
Definition: shop.cpp:75
mapstruct
This is a game-map.
Definition: map.h:315
floor
Magical Runes Runes are magical inscriptions on the dungeon floor
Definition: runes-guide.txt:3
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:265
shop.h
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.cpp:359
unpaid_count::pl
object * pl
Definition: shop.cpp:740
objects
object * objects
Pointer to the list of used objects.
Definition: object.cpp:294
shopitems
Shop-related information for a map.
Definition: map.h:295
make_list_like
void make_list_like(char *input)
Taking a string as an argument, mutate it into a string that looks like a list.
Definition: utils.cpp:368
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
shop_efficiency
float shop_efficiency(const object *player)
Return the shop's efficiency (E) for a player, a number greater than (but not equal to) zero and less...
Definition: shop.cpp:184
MSG_TYPE_SHOP_LISTING
#define MSG_TYPE_SHOP_LISTING
Shop listings - inventory, what it deals in.
Definition: newclient.h:511
shop_greed
static double shop_greed(const mapstruct *map)
Gets a shop's greed.
Definition: shop.cpp:1127
typedata::identifyskill2
int identifyskill2
Second skill used to identify this object class.
Definition: define.h:94
data
====Textual A command containing textual data has data fields separated by one ASCII space character. word::A sequence of ASCII characters that does not contain the space or nul character. This is to distinguish it from the _string_, which may contain space characters. Not to be confused with a machine word. int::A _word_ containing the textual representation of an integer. Not to be confused with any of the binary integers in the following section. Otherwise known as the "string value of integer data". Must be parsed, e.g. using `atoi()` to get the actual integer value. string::A sequence of ASCII characters. This must only appear at the end of a command, since spaces are used to separate fields of a textual message.=====Binary All multi-byte integers are transmitted in network byte order(MSB first). int8::1-byte(8-bit) integer int16::2-byte(16-bit) integer int32::4-byte(32-bit) integer lstring::A length-prefixed string, which consists of an `int8` followed by that many bytes of the actual string. This is used to transmit a string(that may contain spaces) in the middle of binary data. l2string::Like _lstring_, but is prefixed with an `int16` to support longer strings Implementation Notes ~~~~~~~~~~~~~~~~~~~~ - Typical implementations read two bytes to determine the length of the subsequent read for the actual message, then read and parse the data from each message according to the commands described below. To send a message, the sender builds the message in a buffer, counts the length of the message, sends the length, and finally sends the actual message. TIP:Incorrectly transmitting or receiving the `length` field can lead to apparent "no response" issues as the client or server blocks to read the entire length of the message. - Since the protocol is highly interactive, it may be useful to set `TCP_NODELAY` on both the client and server. - If you are using a language with a buffered output stream, remember to flush the stream after a complete message. - If the connection is lost(which will also happen if the output buffer overflowing), the player is saved and the server cleans up. This does open up some abuses, but there is no perfect solution here. - The server only reads data from the socket if the player has an action. This isn 't really good, since many of the commands below might not be actual commands for the player. The alternative is to look at the data, and if it is a player command and there isn 't time, store it away to be processed later. But this increases complexity, in that the server must start buffering the commands. Fortunately, for now, there are few such client commands. Commands -------- In the documentation below, `S->C` represents a message to the client from the server, and `C->S` represents a message to the server from the client. Commands are documented in a brief format like:C->S:version< csval >[scval[vinfo]] Fields are enclosed like `< this >`. Optional fields are denoted like `[this]`. Spaces that appear in the command are literal, i.e. the<< _version > > command above uses spaces to separate its fields, but the command below does not:C->S:accountlogin< name >< password > As described in<< _messages > >, if a command contains data, then the command is separated from the data by a literal space. Many of the commands below refer to 'object tags'. Whenever the server creates an object, it creates a unique tag for that object(starting at 1 when the server is first run, and ever increasing.) Tags are unique, but are not consistent between runs. Thus, the client can not store tags when it exits and hope to re-use them when it joins the server at a later time - tags are only valid for the current connection. The protocol commands are broken into various sections which based somewhat on what the commands are for(ie, item related commands, map commands, image commands, etc.) In this way, all the commands related to similar functionality is in the same place. Initialization ~~~~~~~~~~~~~~ version ^^^^^^^ C->S:version< csval >[scval[vinfo]] S->C:version< csval >[scval[vinfo]] Used by the client and server to exchange which version of the Crossfire protocol they understand. Neither send this in response to the other - they should both send this shortly after a connection is established. csval::int, version level of C->S communications scval::int, version level of S->C communications vinfo::string, that is purely for informative that general client/server info(ie, javaclient, x11client, winclient, sinix server, etc). It is purely of interest of server admins who can see what type of clients people are using.=====Version ID If a new command is added to the protocol in the C->S direction, then the version number in csval will get increased. Likewise, the same is true for the scval. The version are currently integers, in the form ABCD. A=1, and will likely for quite a while. This will only really change if needed from rollover of B. B represents major protocol changes - if B mismatches, the clients will be totally unusable. Such an example would be change of map or item sending commands(either new commands or new format.) C represents more minor but still significant changes - clients might still work together, but some features that used to work may now fail due to the mismatch. An example may be a change in the meaning of some field in some command - providing the field is the same size, it still should be decoded properly, but the meaning won 't be processed properly. D represents very minor changes or new commands. Things should work no worse if D does not match, however if they do match, some new features might be included. An example of the would be the C->S mark command to mark items. Server not understanding this just means that the server can not process it, and will ignore it.=====Handling As far as the client is concerned, its _scval_ must be at least equal to the server, and its _csval_ should not be newer than the server. The server does not care about the version command it receives right now - all it currently does is log mismatches. In theory, the server should keep track of what the client has, and adjust the commands it sends respectively in the S->C direction. The server is resilant enough that it won 't crash with a version mismatch(however, client may end up sending commands that the server just ignores). It is really up to the client to enforce versioning and quit if the versions don 't match. NOTE:Since all packets have the length as the first 2 bytes, all that either the client or server needs to be able to do is look at the first string and see if it understands it. If not, it knows how many bytes it can skip. As such, exact version matches should not be necessary for proper operation - however, both the client and server needs to be coded to handle such cases.=====History _scval_ and _vinfo_ were added in version 1020. Before then, there was only one version sent in the version command. NOTE:For the most part, this has been obsoleted by the setup command which always return status and whether it understood the command or not. However there are still some cases where using this versioning is useful - an example it the addition of the requestinfo/replyinfo commands - the client wants to wait for acknowledge of all the replyinfo commands it has issued before sending the addme command. However, if the server doesn 't understand these options, the client will never get a response. With the versioning, the client can look at the version and know if it should wait for a response or if the server will never send back. setup ^^^^^ C->S, S->C:setup< option1 >< value1 >< option2 >< value2 > ... Sent by the client to request protocol option changes. This can be at any point during the life of a connection, but usually sent at least once right after the<< _version > > command. The server responds with a message in the same format confirming what configuration options were set. The server only sends a setup command in response to one from the client. The sc_version should be updated in the server if commands have been obsoleted such that old clients may not be able to play. option::word, name of configuration option value::word, value of configuration option. May need further parsing according to the setup options below=====Setup Options There are really 2 set of setup commands here:. Those that control preferences of the client(how big is the map, what faceset to use, etc). . Those that describe capabilities of the client(client supports this protocol command or that) .Setup Options[options="autowidth,header"]|===========================|Command|Description|beat|Ask the server to enable heartbeat support. When heartbeat is enabled, the client must send the server a command every three seconds. If no commands need to be sent, use the `beat` no-op command. Clients that do not contact the server within the interval are assumed to have a temporary connection failure.|bot(0/1 value)|If set to 1, the client will not be considered a player when updating information to the metaserver. This is to avoid having a server with many bots appear more crowded than others.|darkness(0/1 value)|If set to 1(default), the server will send darkness information in the map protocol commands. If 0, the server will not include darkness, thus saving a minor amount of bandwidth. Since the client is free to ignore the darkness information, this does not allow the client to cheat. In the case of the old 'map' protocol command, turning darkness off will result in the masking faces not getting sent to the client.|extended_stats(0/1 value)|If set to 1, the server will send the CS_STAT_RACE_xxx and CS_STAT_BASE_xxx values too, so the client can display various status related to statistics. Default is 0.|facecache(0/1)|Determines if the client is caching images(1) or wants the images sent to it without caching them(0). Default is 0. This replaces the setfacemode command.|faceset(8 bit)|Faceset the client wishes to use. If the faceset is not valid, the server returns the faceset the client will be using(default 0).|loginmethod(8 bit)|Client sends this to server to note login support. This is basically used as a subset of the csversion/scversion to find out what level of login support the server and client support. Current defined values:0:no advanced support - only legacy login method 1:account based login(described more below) 2:new character creation support This list may grow - for example, advanced character creation could become a feature.|map2cmd:(1)|This indicates client support for the map2 protocol command. See the map2 protocol details above for the main differences. Obsolete:This is the only supported mode now, but many clients use it as a sanity check for protocol versions, so the server still replies. It doesn 't do anything with the data|mapsize(int x) X(int y)|Sets the map size to x X y. Note the spaces here are only for clarity - there should be no spaces when actually sent(it should be 11x11 or 25x25). The default map size unless changed is 11x11. The minimum map size the server will allow is 9x9(no technical reason this could be smaller, but I don 't think the game would be smaller). The maximum map size supported in the current protocol is 63x63. However, each server can have its maximum map size sent to most any value. If the client sends an invalid mapsize command or a mapsize of 0x0, the server will respond with a mapsize that is the maximum size the server supports. Thus, if the client wants to know the maximum map size, it can just do a 'mapsize 0x0' or 'mapsize' and it will get the maximum size back. The server will constrain the provided mapsize x &y to the configured minumum and maximums. For example, if the maximum map size is 25x25, the minimum map size is 9x9, and the client sends a 31x7 mapsize request, the mapsize will be set to 25x9 and the server will send back a mapsize 25x9 setup command. When the values are valid, the server will send back a mapsize XxY setup command. Note that this is from its parsed values, so it may not match stringwise with what the client sent, but will match 0 wise. For example, the client may send a 'mapsize 025X025' command, in which case the server will respond with a 'mapsize 25x25' command - the data is functionally the same. The server will send an updated map view when this command is sent.|notifications(int value)|Value indicating what notifications the client accepts. It is incremental, a value means "all notifications till this level". The following levels are supported:1:quest-related notifications("addquest" and "updquest") 2:knowledge-related notifications("addknowledge") 3:character status flags(overloaded, blind,...)|num_look_objects(int value)|The maximum number of objects shown in the ground view. If more objects are present, fake objects are created for selecting the previous/next group of items. Defaults to 50 if not set. The server may adjust the given value to a suitable one data
Definition: protocol.txt:379
FMT64U
#define FMT64U
Definition: compat.h:17
UPD_NAME
#define UPD_NAME
Definition: newclient.h:321
count_unpaid_callback
static void count_unpaid_callback(object *item, void *data)
Definition: shop.cpp:763
Settings::real_wiz
uint8_t real_wiz
Use mud-like wizards.
Definition: global.h:273
skill
skill
Definition: arch-handbook.txt:585
object_remove
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to.
Definition: object.cpp:1833
a
Magical Runes Runes are magical inscriptions on the dungeon which cast a spell or detonate when something steps on them Flying objects don t detonate runes Beware ! Runes are invisible most of the time They are only visible occasionally ! There are several runes which are there are some special runes which may only be called with the invoke and people may apply it to read it Maybe useful for mazes ! This rune will not nor is it ordinarily invisible Partial Visibility of they ll be visible only part of the time They have a(your level/2) chance of being visible in any given round
FLAG_PLAYER_SOLD
#define FLAG_PLAYER_SOLD
Object was sold to a shop by a player.
Definition: define.h:252
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:236
archetype::name
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
object::nrof
uint32_t nrof
Number of objects.
Definition: object.h:342
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
object_set_value
int object_set_value(object *op, const char *key, const char *value, int add_key)
Updates the key in op to value.
Definition: object.cpp:4499
can_pay
int can_pay(object *pl)
Checks all unpaid items in op's inventory, adds up all the money they have, and checks that they can ...
Definition: shop.cpp:841
FLAG_CURSED
#define FLAG_CURSED
The object is cursed.
Definition: define.h:316
pay_for_amount
int pay_for_amount(uint64_t to_pay, object *pl)
Takes the amount of money from the the player inventory and from it's various pouches using the pay_f...
Definition: shop.cpp:461
CUSTOM_NAME_FIELD
#define CUSTOM_NAME_FIELD
Key in an object for the player-assigned custom name.
Definition: object.h:98
count_unpaid
static void count_unpaid(object *pl, object *item, int *unpaid_count, uint64_t *unpaid_price)
Sum the amount to pay for all unpaid items and find available money.
Definition: shop.cpp:781
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:664
events_execute_global_event
void events_execute_global_event(int eventcode,...)
Execute a global event.
Definition: events.cpp:30
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
MONEY
@ MONEY
Definition: object.h:142
pay_from_container
static uint64_t pay_from_container(object *pl, object *pouch, uint64_t to_pay)
This pays for the item, and takes the proper amount of money off the specified container (pouch or pl...
Definition: shop.cpp:635
identify
object * identify(object *op)
Identifies an item.
Definition: item.cpp:1426