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 
71 uint64_t price_approx(const object *tmp, object *who) {
72  uint64_t val = price_base(tmp);
73 
74  /* If we are approximating, then the value returned should
75  * be allowed to be wrong however merely using a random number
76  * each time will not be sufficient, as then multiple examinations
77  * would give different answers, so we'll use the count instead.
78  * By taking the sine of the count, a value between -1 and 1 is
79  * generated, we then divide by the square root of the bargaining
80  * skill and the appropriate identification skills, so that higher
81  * level players get better estimates. (We need a +1 there to
82  * prevent dividing by zero.)
83  */
84  const typedata *tmptype = get_typedata(tmp->type);
85  int lev_identify = 0;
86 
87  if (tmptype) {
88  int idskill1 = tmptype->identifyskill;
89  if (idskill1) {
90  int idskill2 = tmptype->identifyskill2;
91  if (find_skill_by_number(who, idskill1)) {
92  lev_identify = find_skill_by_number(who, idskill1)->level;
93  }
94  if (idskill2 && find_skill_by_number(who, idskill2)) {
95  lev_identify += find_skill_by_number(who, idskill2)->level;
96  }
97  }
98  } else {
99  LOG(llevError, "Query_cost: item %s hasn't got a valid type\n", tmp->name);
100  }
101  val += val * (sin(tmp->count) / sqrt(lev_identify * 3 + 1.0));
102 
103  return val;
104 }
105 
111 static float shop_cha_modifier(int charisma) {
112  return tanh((charisma+15.0)/20);
113 }
114 
122 float shop_efficiency(const object *player) {
123  return shop_greed(player->map)
124  * shop_approval(player->map, player)
125  * shop_cha_modifier(player->stats.Cha);
126 }
127 
128 uint64_t shop_price_buy(const object *tmp, object *who) {
129  assert(who != NULL && who->type == PLAYER);
130  // price tags override any buy price
131  if (object_value_set(tmp, "price")) {
132  const char *price = object_get_value(tmp, "price");
133  return NROF(tmp)*strtol(price, NULL, 10);
134  }
135  const uint64_t val = price_base(tmp);
136  const char *key = object_get_value(tmp, "price_adjustment_buy");
137  float adj = 1;
138  if (key != NULL) {
139  adj = atof(key);
140  }
141  float E = shop_efficiency(who);
142  const float adj_val = val * adj / E;
143  if (getenv("CF_DEBUG_SHOP")) {
144  LOG(llevDebug, "price_buy %s %lu*adj(%.2f)/E(%.2f) = %.2f\n",
145  tmp->arch->name, val, adj, E, adj_val);
146  }
147  if (std::isfinite(adj_val)) {
148  return adj_val;
149  } else {
150  return UINT64_MAX;
151  }
152 }
153 
154 uint64_t shop_price_sell(const object *tmp, object *who) {
155  assert(who != NULL && who->type == PLAYER);
156  const uint64_t val = price_base(tmp);
157  const char *key = object_get_value(tmp, "price_adjustment_sell");
158  float adj = 1;
159  if (key != NULL) {
160  adj = atof(key);
161  }
162  float spec = shop_specialisation_ratio(tmp, who->map);
163  float E = shop_efficiency(who);
164  const uint64_t adj_val = val * adj * spec * E;
165 
166  /* Limit amount of money you can get for really great items. */
167  int number = NROF(tmp);
168  uint64_t limval = value_limit(adj_val, number, who, 1);
169 
170  if (getenv("CF_DEBUG_SHOP")) {
171  LOG(llevDebug, "price_sell %s %lu*adj(%.2f)*s(%.2f)*E(%.2f) = %lu limited to %lu\n",
172  tmp->arch->name, val, adj, spec, E, adj_val, limval);
173  }
174  return limval;
175 }
176 
188 static archetype *find_next_coin(uint64_t c, int *cointype) {
189  archetype *coin;
190 
191  do {
192  if (coins[*cointype] == NULL)
193  return NULL;
194  coin = find_archetype(coins[*cointype]);
195  if (coin == NULL)
196  return NULL;
197  *cointype += 1;
198  } while (coin->clone.value > (int64_t) c);
199 
200  return coin;
201 }
202 
220 char* cost_string_from_value(uint64_t cost, int largest_coin) {
221  archetype *coin, *next_coin;
222  uint32_t num;
223  int cointype = largest_coin;
224 
225  if (cointype < 0)
226  cointype = 0;
227  else if (cointype >= NUM_COINS)
228  cointype = NUM_COINS - 1;
229 
231  if (cost == UINT64_MAX) {
232  stringbuffer_append_string(buf, "an unimaginable sum of money");
233  goto done;
234  }
235 
236  coin = find_next_coin(cost, &cointype);
237  if (coin == NULL) {
238  stringbuffer_append_string(buf, "nothing");
239  goto done;
240  }
241 
242  num = cost/coin->clone.value;
243  /* so long as nrof is 32 bit, this is true.
244  * If it takes more coins than a person can possibly carry, this
245  * is basically true.
246  */
247  if ((cost/coin->clone.value) > UINT32_MAX) {
248  stringbuffer_append_string(buf, "an unimaginable sum of money");
249  goto done;
250  }
251 
252  cost -= (uint64_t)num*(uint64_t)coin->clone.value;
253  if (num == 1)
254  stringbuffer_append_printf(buf, "1 %s", coin->clone.name);
255  else
256  stringbuffer_append_printf(buf, "%u %ss", num, coin->clone.name);
257 
258  next_coin = find_next_coin(cost, &cointype);
259  if (next_coin == NULL)
260  goto done;
261 
262  do {
263  coin = next_coin;
264  num = cost/coin->clone.value;
265  cost -= (uint64_t)num*(uint64_t)coin->clone.value;
266 
267  if (cost == 0)
268  next_coin = NULL;
269  else
270  next_coin = find_next_coin(cost, &cointype);
271 
272  if (next_coin) {
273  /* There will be at least one more string to add to the list,
274  * use a comma.
275  */
277  } else {
279  }
280  if (num == 1)
281  stringbuffer_append_printf(buf, "1 %s", coin->clone.name);
282  else
283  stringbuffer_append_printf(buf, "%u %ss", num, coin->clone.name);
284  } while (next_coin);
285 
286 done:
287  return stringbuffer_finish(buf);
288 }
289 
300 static StringBuffer *real_money_value(const object *coin, StringBuffer *buf) {
301  assert(coin->type == MONEY);
302  assert(buf);
303 
304  stringbuffer_append_printf(buf, "%ld %s", (long)coin->nrof, coin->nrof == 1 ? coin->name : coin->name_pl);
305  return buf;
306 }
307 
308 char *cost_str(uint64_t cost) {
310 }
311 
312 char *cost_approx_str(const object *tmp, object *who) {
313  uint64_t approx_val = price_approx(tmp, who);
314  int idskill1 = 0;
315  int idskill2 = 0;
316  const typedata *tmptype;
317 
319 
320  /* money it's pretty hard to not give the exact price, so skip all logic and just return the real value. */
321  if (tmp->type == MONEY) {
323  }
324 
325  tmptype = get_typedata(tmp->type);
326  if (tmptype) {
327  idskill1 = tmptype->identifyskill;
328  idskill2 = tmptype->identifyskill2;
329  }
330 
331  /* we show an approximate price if
332  * 1) we are approximating
333  * 2) there either is no id skill(s) for the item, or we don't have them
334  * 3) we don't have bargaining skill either
335  */
336  if (!idskill1 || !find_skill_by_number(who, idskill1)) {
337  if (!idskill2 || !find_skill_by_number(who, idskill2)) {
338  if (!find_skill_by_number(who, SK_BARGAINING)) {
339  int num;
340  int cointype = LARGEST_COIN_GIVEN;
341  archetype *coin = find_next_coin(approx_val, &cointype);
342 
343  if (coin == NULL) {
344  stringbuffer_append_string(buf, "nothing");
345  return stringbuffer_finish(buf);
346  }
347 
348  num = approx_val/coin->clone.value;
349  if (num == 1)
350  stringbuffer_append_printf(buf, "about one %s", coin->clone.name);
351  else if (num < 5)
352  stringbuffer_append_printf(buf, "a few %s", coin->clone.name_pl);
353  else if (num < 10)
354  stringbuffer_append_printf(buf, "several %s", coin->clone.name_pl);
355  else if (num < 25)
356  stringbuffer_append_printf(buf, "a moderate amount of %s", coin->clone.name_pl);
357  else if (num < 100)
358  stringbuffer_append_printf(buf, "lots of %s", coin->clone.name_pl);
359  else if (num < 1000)
360  stringbuffer_append_printf(buf, "a great many %s", coin->clone.name_pl);
361  else
362  stringbuffer_append_printf(buf, "a vast quantity of %s", coin->clone.name_pl);
363  return stringbuffer_finish(buf);
364  }
365  }
366  }
367 
368  // If we get here, return the price we guessed.
370  return cost_str(approx_val);
371 }
372 
373 uint64_t query_money(const object *op) {
374  uint64_t total = 0;
375 
376  if (op->type != PLAYER && op->type != CONTAINER) {
377  LOG(llevError, "Query money called with non player/container\n");
378  return 0;
379  }
380  FOR_INV_PREPARE(op, tmp) {
381  if (tmp->type == MONEY) {
382  total += (uint64_t)tmp->nrof*(uint64_t)tmp->value;
383  } else if (tmp->type == CONTAINER
384  && QUERY_FLAG(tmp, FLAG_APPLIED)
385  && (tmp->race == NULL || strstr(tmp->race, "gold"))) {
386  total += query_money(tmp);
387  }
388  } FOR_INV_FINISH();
389  return total;
390 }
391 
404 int pay_for_amount(uint64_t to_pay, object *pl) {
405  if (to_pay == 0)
406  return 1;
407  if (to_pay > query_money(pl))
408  return 0;
409 
410  to_pay = pay_from_container(pl, pl, to_pay);
411 
412  FOR_INV_PREPARE(pl, pouch) {
413  if (to_pay <= 0)
414  break;
415  if (pouch->type == CONTAINER
416  && QUERY_FLAG(pouch, FLAG_APPLIED)
417  && (pouch->race == NULL || strstr(pouch->race, "gold"))) {
418  to_pay = pay_from_container(pl, pouch, to_pay);
419  }
420  } FOR_INV_FINISH();
421  if (to_pay > 0) {
422  LOG(llevError, "pay_for_amount: Cannot remove enough money -- %" FMT64U " remains\n", to_pay);
423  }
424 
425  fix_object(pl);
426  return 1;
427 }
428 
444 int pay_for_item(object *op, object *pl, uint64_t reduction) {
445  uint64_t to_pay = shop_price_buy(op, pl);
446  assert(to_pay >= reduction);
447  to_pay -= reduction;
448 
449  if (to_pay == 0)
450  return 1;
451  if (to_pay > query_money(pl))
452  return 0;
453 
454  to_pay = pay_from_container(pl, pl, to_pay);
455 
456  FOR_INV_PREPARE(pl, pouch) {
457  if (to_pay <= 0)
458  break;
459  if (pouch->type == CONTAINER
460  && QUERY_FLAG(pouch, FLAG_APPLIED)
461  && (pouch->race == NULL || strstr(pouch->race, "gold"))) {
462  to_pay = pay_from_container(pl, pouch, to_pay);
463  }
464  } FOR_INV_FINISH();
465  if (to_pay > 0) {
466  LOG(llevError, "pay_for_item: Cannot remove enough money -- %" FMT64U " remains\n", to_pay);
467  }
469  SET_FLAG(op, FLAG_WAS_WIZ);
470  fix_object(pl);
471  return 1;
472 }
473 
485 static int64_t remove_value(object *coin_objs[], int64_t remain) {
486  int i;
487 
488  for (i = 0; i < NUM_COINS; i++) {
489  int count;
490  int64_t num_coins;
491 
492  if ((int64_t)coin_objs[i]->nrof * coin_objs[i]->value > remain) {
493  num_coins = remain/coin_objs[i]->value;
494  if ((uint64_t)num_coins*(uint64_t)coin_objs[i]->value < (uint64_t) remain) {
495  num_coins++;
496  }
497  } else {
498  num_coins = coin_objs[i]->nrof;
499  }
500  remain -= (int64_t)num_coins*(int64_t)coin_objs[i]->value;
501  coin_objs[i]->nrof -= num_coins;
502  /* Now start making change. Start at the coin value
503  * below the one we just did, and work down to
504  * the lowest value.
505  */
506  count = i-1;
507  while (remain < 0 && count >= 0) {
508  num_coins = -remain/coin_objs[count]->value;
509  coin_objs[count]->nrof += num_coins;
510  remain += num_coins*coin_objs[count]->value;
511  count--;
512  }
513  }
514 
515  return remain;
516 }
517 
526 static void add_value(object *coin_objs[], int64_t value) {
527  int i;
528 
529  for (i = NUM_COINS-LARGEST_COIN_GIVEN-1; i >= 0; i--) {
530  uint32_t nrof;
531 
532  nrof = (uint32_t)(value/coin_objs[i]->value);
533  value -= nrof*coin_objs[i]->value;
534  coin_objs[i]->nrof += nrof;
535  }
536 }
537 
550 static void insert_objects(object *pl, object *container, object *objects[], int objects_len) {
551  int i, one = 0;
552 
553  for (i = 0; i < objects_len; i++) {
554  if (objects[i]->nrof > 0) {
555  object_insert_in_ob(objects[i], container);
556  one = 1;
557  } else {
559  }
560  }
561  if (one)
562  esrv_update_item(UPD_WEIGHT, pl, container);
563 }
564 
578 static uint64_t pay_from_container(object *pl, object *pouch, uint64_t to_pay) {
579  size_t i;
580  int64_t remain;
581  object *coin_objs[NUM_COINS];
582  object *other_money[16]; /* collects MONEY objects not matching coins[] */
583  size_t other_money_len; /* number of allocated entries in other_money[] */
584  archetype *at;
585 
586  if (pouch->type != PLAYER && pouch->type != CONTAINER)
587  return to_pay;
588 
589  remain = to_pay;
590  for (i = 0; i < NUM_COINS; i++)
591  coin_objs[i] = NULL;
592 
593  /* This hunk should remove all the money objects from the player/container */
594  other_money_len = 0;
595  FOR_INV_PREPARE(pouch, tmp) {
596  if (tmp->type == MONEY) {
597  for (i = 0; i < NUM_COINS; i++) {
598  if (!strcmp(coins[NUM_COINS-1-i], tmp->arch->name)
599  && (tmp->value == tmp->arch->clone.value)) {
600  /* This should not happen, but if it does, just
601  * merge the two.
602  */
603  if (coin_objs[i] != NULL) {
604  LOG(llevError, "%s has two money entries of (%s)\n", pouch->name, coins[NUM_COINS-1-i]);
605  object_remove(tmp);
606  coin_objs[i]->nrof += tmp->nrof;
608  } else {
609  object_remove(tmp);
610  coin_objs[i] = tmp;
611  }
612  break;
613  }
614  }
615  if (i == NUM_COINS) {
616  if (other_money_len >= sizeof(other_money)/sizeof(*other_money)) {
617  LOG(llevError, "pay_for_item: Cannot store non-standard money object %s\n", tmp->arch->name);
618  } else {
619  object_remove(tmp);
620  other_money[other_money_len++] = tmp;
621  }
622  }
623  }
624  } FOR_INV_FINISH();
625 
626  /* Fill in any gaps in the coin_objs array - needed to make change. */
627  /* Note that the coin_objs array goes from least value to greatest value */
628  for (i = 0; i < NUM_COINS; i++)
629  if (coin_objs[i] == NULL) {
630  at = find_archetype(coins[NUM_COINS-1-i]);
631  if (at == NULL) {
632  continue;
633  }
634  coin_objs[i] = object_new();
635  object_copy(&at->clone, coin_objs[i]);
636  coin_objs[i]->nrof = 0;
637  }
638 
639  /* Try to pay from standard coins first. */
640  remain = remove_value(coin_objs, remain);
641 
642  /* Now pay from non-standard coins until all is paid. */
643  for (i = 0; i < other_money_len && remain > 0; i++) {
644  uint32_t nrof;
645  object *coin;
646 
647  coin = other_money[i];
648 
649  /* Find the minimal number of coins to use. This prevents converting
650  * excess non-standard coins to standard money.
651  */
652  nrof = (remain+coin->value-1)/coin->value;
653  if (nrof > coin->nrof) {
654  nrof = coin->nrof;
655  }
656  coin->nrof -= nrof;
657  add_value(coin_objs, nrof*coin->value);
658 
659  remain = remove_value(coin_objs, remain);
660  }
661 
662  /* re-insert remaining coins into player */
663  insert_objects(pl, pouch, coin_objs, NUM_COINS);
664  insert_objects(pl, pouch, other_money, other_money_len);
665 
666  return(remain);
667 }
668 
669 uint64_t add_with_overflow(uint64_t a, uint64_t b) {
670  if (a == UINT64_MAX) {
671  return a;
672  }
673 
674  if (UINT64_MAX - a < b) {
675  // Overflow
676  return UINT64_MAX;
677  } else {
678  return a + b;
679  }
680 }
681 
682 struct unpaid_count {
683  object *pl;
684  int count;
685  uint64_t price;
686 };
687 
695 static void unpaid_iter(object *item, void (*callback)(object *item, void *data), void *data) {
697  if (QUERY_FLAG(item, FLAG_UNPAID)) {
698  callback(item, data);
699  }
700  if (item->inv) {
701  unpaid_iter(item->inv, callback, data);
702  }
704 }
705 
706 static void count_unpaid_callback(object *item, void *data) {
707  struct unpaid_count *args = (struct unpaid_count *)data;
708  args->count++;
709  args->price = add_with_overflow(args->price, shop_price_buy(item, args->pl));
710 }
711 
724 static void count_unpaid(object *pl, object *item, int *unpaid_count, uint64_t *unpaid_price) {
725  struct unpaid_count args = {pl, 0, 0};
726  unpaid_iter(item, count_unpaid_callback, &args);
727  *unpaid_count = args.count;
728  *unpaid_price = args.price;
729 }
730 
738 static void count_coins(object *item, uint32_t *coincount) {
740  /* Merely converting the player's monetary wealth won't do.
741  * If we did that, we could print the wrong numbers for the
742  * coins, so we count the money instead.
743  */
744  for (int i = 0; i < NUM_COINS; i++) {
745  if (!strcmp(coins[i], item->arch->name)) {
746  coincount[i] += item->nrof;
747  break;
748  }
749  }
750  if (item->inv) {
751  count_coins(item->inv, coincount);
752  }
754 }
755 
764 static uint64_t compute_price_variation_with_bargaining(object *pl, uint64_t price, float max_variation) {
766  if (skill && skill->level > 0) {
767  return rndm(0, price * (max_variation * skill->level / settings.max_level));
768  }
769  return 0;
770 }
771 
784 int can_pay(object *pl) {
785  int unpaid_count = 0, i;
786  uint64_t unpaid_price = 0;
787  uint32_t coincount[NUM_COINS];
788 
789  if (!pl || pl->type != PLAYER) {
790  LOG(llevError, "can_pay(): called against something that isn't a player\n");
791  return 0;
792  }
793  uint64_t player_wealth = query_money(pl);
794 
795  for (i = 0; i < NUM_COINS; i++)
796  coincount[i] = 0;
797 
798  count_unpaid(pl, pl->inv, &unpaid_count, &unpaid_price);
799  count_coins(pl->inv, coincount);
800 
801  if (unpaid_price > player_wealth) {
802  char buf[MAX_BUF], coinbuf[MAX_BUF];
803  int denominations = 0;
804  char *value = cost_str(unpaid_price);
805 
806  snprintf(buf, sizeof(buf), "You have %d unpaid items that would cost you %s, ", unpaid_count, value);
807  free(value);
808  for (i = 0; i < NUM_COINS; i++) {
809  if (coincount[i] > 0 && coins[i]) {
810  if (denominations == 0)
811  snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "but you only have");
812  denominations++;
813  archetype *arch = find_archetype(coins[i]);
814  if (arch != NULL)
815  {
816  snprintf(coinbuf, sizeof(coinbuf), " %u %s,", coincount[i], arch->clone.name_pl);
817  snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s", coinbuf);
818  }
819  }
820  }
821  if (denominations == 0)
822  snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "but you don't have any money.");
823  else if (denominations > 1)
827  return 0;
828  } else
829  return 1;
830 }
831 
832 static void shop_pay_unpaid_callback(object *op, void *data) {
833  object *pl = (object *)data;
834  char name_op[MAX_BUF];
835  uint64_t price = shop_price_buy(op, pl);
836  uint64_t reduction = 0;
837  if (!object_value_set(op, "price")) {
838  // only items without a player-set price can be bargained for
840  }
841  if (!pay_for_item(op, pl, reduction)) {
842  uint64_t i = price - query_money(pl);
843  char *missing = cost_str(i);
844 
845  CLEAR_FLAG(op, FLAG_UNPAID);
846  query_name(op, name_op, MAX_BUF);
849  "You lack %s to buy %s.",
850  missing, name_op);
851  free(missing);
852  SET_FLAG(op, FLAG_UNPAID);
853  return;
854  } else {
855  // TODO: Figure out how to pass in the shop owner for player shops.
856  if (events_execute_object_event(op, EVENT_BOUGHT, pl, NULL, NULL, SCRIPT_FIX_ALL) != 0)
857  return;
858 
859  object *tmp;
860  char *value = cost_str(price - reduction);
861 
862  CLEAR_FLAG(op, FLAG_UNPAID);
865  query_name(op, name_op, MAX_BUF);
866 
867  if (reduction > 0) {
868  char *reduction_str = cost_str(reduction);
871  "You paid %s for %s after bargaining a reduction of %s.",
872  value, name_op, reduction_str);
873  change_exp(pl, reduction, "bargaining", SK_EXP_NONE);
874  free(reduction_str);
875  } else {
878  "You paid %s for %s.",
879  value, name_op);
880  }
881  free(value);
882  tmp = object_merge(op, NULL);
883  if (pl->type == PLAYER && !tmp) {
884  /* If item wasn't merged we update it. If merged, object_merge() handled everything for us. */
886  }
887  }
888 }
889 
896 int shop_pay_unpaid(object *pl, object *op) {
897  if (!op) {
898  return 1;
899  }
901  return 1;
902 }
903 
915 void sell_item(object *op, object *pl) {
916  object *tmp;
917  archetype *at;
918  char obj_name[MAX_BUF];
919 
920  query_name(op, obj_name, MAX_BUF);
921 
922  if (pl == NULL || pl->type != PLAYER) {
923  LOG(llevDebug, "Object other than player tried to sell something.\n");
924  return;
925  }
926 
927  if (events_execute_object_event(op, EVENT_SELLING, pl, NULL, NULL, SCRIPT_FIX_ALL) != 0)
928  return;
929 
930  object_set_value(op, CUSTOM_NAME_FIELD, NULL, 0);
931 
932  uint64_t price = shop_price_sell(op, pl);
933  if (price == 0) {
936  "We're not interested in %s.",
937  obj_name);
938  return;
939  }
941 
943  char *value_str = cost_str(price + extra_gain);
944 
945  if (extra_gain > 0) {
946  change_exp(pl, extra_gain, "bargaining", SK_EXP_NONE);
947  char *extra_str = cost_str(extra_gain);
949  "You receive %s for %s, after bargaining for %s more than proposed.", value_str, obj_name, extra_str);
950  free(extra_str);
951  price += extra_gain;
952  } else {
954  "You receive %s for %s.", value_str, obj_name);
955  }
956  free(value_str);
957 
958  for (int count = LARGEST_COIN_GIVEN; coins[count] != NULL; count++) {
959  at = find_archetype(coins[count]);
960  if (at == NULL)
961  LOG(llevError, "Could not find %s archetype\n", coins[count]);
962  else if ((price/at->clone.value) > 0) {
963  FOR_INV_PREPARE(pl, pouch) {
964  if (pouch->type == CONTAINER
965  && QUERY_FLAG(pouch, FLAG_APPLIED)
966  && pouch->race
967  && strstr(pouch->race, "gold")) {
968  int w = at->clone.weight*(100-pouch->stats.Str)/100;
969  int n = price/at->clone.value;
970 
971  if (w == 0)
972  w = 1; /* Prevent divide by zero */
973  if (n > 0
974  && (!pouch->weight_limit || pouch->carrying+w <= pouch->weight_limit)) {
975  if (pouch->weight_limit
976  && (pouch->weight_limit-pouch->carrying)/w < n)
977  n = (pouch->weight_limit-pouch->carrying)/w;
978 
979  tmp = object_new();
980  object_copy(&at->clone, tmp);
981  tmp->nrof = n;
982  price -= (uint64_t)tmp->nrof*(uint64_t)tmp->value;
983  tmp = object_insert_in_ob(tmp, pouch);
985  }
986  }
987  } FOR_INV_FINISH();
988  if (price/at->clone.value > 0) {
989  tmp = object_new();
990  object_copy(&at->clone, tmp);
991  tmp->nrof = price/tmp->value;
992  price -= (uint64_t)tmp->nrof*(uint64_t)tmp->value;
993  tmp = object_insert_in_ob(tmp, pl);
995  }
996  }
997  }
998 
999  if (price != 0) {
1000  LOG(llevError, "Warning - payment not zero: %" PRIo64 "\n", price);
1001  }
1002 
1003  SET_FLAG(op, FLAG_UNPAID);
1004  identify(op);
1005 }
1006 
1022 static double shop_specialisation_ratio(const object *item, const mapstruct *map) {
1023  shopitems *items = map->shopitems;
1024  double ratio = SPECIALISATION_EFFECT, likedness = 0.001;
1025  int i;
1026 
1027  if (item == NULL) {
1028  LOG(llevError, "shop_specialisation_ratio: passed a NULL item for map %s\n", map->path);
1029  return 0;
1030  }
1031  if (item->type == (uint8_t)-1) {
1032  LOG(llevError, "shop_specialisation_ratio: passed an item with an invalid type\n");
1033  /*
1034  * I'm not really sure what the /right/ thing to do here is,
1035  * these types of item shouldn't exist anyway, but returning
1036  * the ratio is probably the best bet.."
1037  */
1038  return ratio;
1039  }
1040  if (map->shopitems) {
1041  for (i = 0; i < items[0].index; i++)
1042  if (items[i].typenum == item->type || (items[i].typenum == -1 && likedness == 0.001))
1043  likedness = items[i].strength/100.0;
1044  }
1045  if (likedness > 1.0) { /* someone has been rather silly with the map headers. */
1046  LOG(llevDebug, "shop_specialisation ratio: item type %d on map %s is above 100%%\n", item->type, map->path);
1047  likedness = 1.0;
1048  }
1049  if (likedness < -1.0) {
1050  LOG(llevDebug, "shop_specialisation ratio: item type %d on map %s is below -100%%\n", item->type, map->path);
1051  likedness = -1.0;
1052  }
1053  ratio = ratio+(1.0-ratio)*likedness;
1054  if (ratio <= 0.1)
1055  ratio = 0.1; /* if the ratio were much lower than this, we would get silly prices */
1056  return ratio;
1057 }
1058 
1073 static double shop_greed(const mapstruct *map) {
1074  float greed = map->shopgreed;
1075  if (greed == 0) {
1076  greed = 1;
1077  }
1078  return tanh(-greed+2.0)/2 + 0.5;
1079 }
1080 
1081 double shop_approval(const mapstruct *map, const object *player) {
1082  double approval = 1.0;
1083  if (map->shoprace) {
1084  approval = NEUTRAL_RATIO;
1085  if (player->race && !strcmp(player->race, map->shoprace))
1086  approval = 1.0;
1087  }
1088  return approval;
1089 }
1090 
1110 static uint64_t value_limit(uint64_t val, int quantity, const object *who, int isshop) {
1111  uint64_t newval, unit_price;
1112  mapstruct *map;
1113 
1114  unit_price = val/quantity;
1115  if (!isshop || !who) {
1116  if (unit_price > 10000)
1117  newval = 8000+isqrt(unit_price)*20;
1118  else
1119  newval = unit_price;
1120  } else {
1121  if (!who->map) {
1122  LOG(llevError, "value_limit: asked shop price for ob %s on NULL map\n", who->name);
1123  return val;
1124  }
1125  map = who->map;
1126  if (map->shopmin && unit_price < map->shopmin)
1127  return 0;
1128  else if (unit_price > map->shopmax/2)
1129  newval = MIN((map->shopmax/2)+isqrt(unit_price-map->shopmax/2), map->shopmax);
1130  else if (unit_price > 10000)
1131  newval = 8000+isqrt(unit_price)*20;
1132  else
1133  newval = unit_price;
1134  }
1135  newval *= quantity;
1136  return newval;
1137 }
1138 
1144 int shop_describe(const object *op) {
1145  mapstruct *map = op->map;
1146  /*shopitems *items=map->shopitems;*/
1147  int pos = 0, i;
1148  double opinion = 0;
1149  char tmp[MAX_BUF] = "\0", *value;
1150 
1151  if (op->type != PLAYER)
1152  return 0;
1153 
1154  /*check if there is a shop specified for this map */
1155  if (map->shopitems
1156  || map->shopgreed
1157  || map->shoprace
1158  || map->shopmin
1159  || map->shopmax) {
1161  "From looking at the nearby shop you determine that it trades in:");
1162 
1163  if (map->shopitems) {
1164  for (i = 0; i < map->shopitems[0].index; i++) {
1165  if (map->shopitems[i].name && map->shopitems[i].strength > 10) {
1166  snprintf(tmp+pos, sizeof(tmp)-pos, "%s, ", map->shopitems[i].name_pl);
1167  pos += strlen(tmp+pos);
1168  }
1169  }
1170  }
1171  if (!pos)
1172  strcpy(tmp, "a little of everything.");
1173 
1174  /* format the string into a list */
1175  make_list_like(tmp);
1176  draw_ext_info(NDI_UNIQUE, 0, op,
1178 
1179  if (map->shopmax) {
1180  value = cost_str(map->shopmax);
1183  "It won't trade for items above %s.",
1184  value);
1185  free(value);
1186  }
1187 
1188  if (map->shopmin) {
1189  value = cost_str(map->shopmin);
1192  "It won't trade in items worth less than %s.",
1193  value);
1194  free(value);
1195  }
1196 
1197  if (map->shopgreed) {
1198  if (map->shopgreed > 2.0)
1199  draw_ext_info(NDI_UNIQUE, 0, op,
1201  "It tends to overcharge massively.");
1202  else if (map->shopgreed > 1.5)
1203  draw_ext_info(NDI_UNIQUE, 0, op,
1205  "It tends to overcharge substantially.");
1206  else if (map->shopgreed > 1.1)
1207  draw_ext_info(NDI_UNIQUE, 0, op,
1209  "It tends to overcharge slightly.");
1210  else if (map->shopgreed < 0.9)
1211  draw_ext_info(NDI_UNIQUE, 0, op,
1213  "It tends to undercharge.");
1214  }
1215  if (map->shoprace) {
1216  opinion = shop_approval(map, op);
1217  if (opinion > 0.8)
1218  draw_ext_info(NDI_UNIQUE, 0, op,
1220  "You think the shopkeeper likes you.");
1221  else if (opinion > 0.5)
1222  draw_ext_info(NDI_UNIQUE, 0, op,
1224  "The shopkeeper seems unconcerned by you.");
1225  else
1226  draw_ext_info(NDI_UNIQUE, 0, op,
1228  "The shopkeeper seems to have taken a dislike to you.");
1229  }
1231  "There is no shop nearby.");
1232 
1233  return 1;
1234 }
mapstruct::shopgreed
double shopgreed
How much our shopkeeper overcharges.
Definition: map.h:348
object_value_set
bool object_value_set(const object *op, const char *const key)
Determine if an extra value is set.
Definition: object.cpp:4361
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:312
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:1081
PLAYER
@ PLAYER
Definition: object.h:112
EVENT_GBOUGHT
#define EVENT_GBOUGHT
Player bought object in shop, but global.
Definition: events.h:70
global.h
sell_item
void sell_item(object *op, object *pl)
Player is selling an item.
Definition: shop.cpp:915
settings
struct Settings settings
Global settings.
Definition: init.cpp:139
shop_cha_modifier
static float shop_cha_modifier(int charisma)
Calculate the buy price multiplier based on a player's charisma.
Definition: shop.cpp:111
Settings::max_level
int16_t max_level
This is read out of exp_table.
Definition: global.h:303
unpaid_count::price
uint64_t price
Definition: shop.cpp:685
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
unpaid_count::count
int count
Definition: shop.cpp:684
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:764
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:695
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:2036
cost_str
char * cost_str(uint64_t cost)
Definition: shop.cpp:308
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:188
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:526
c
static event_registration c
Definition: citylife.cpp:424
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
UPD_WEIGHT
#define UPD_WEIGHT
Definition: newclient.h:320
if
if(!(yy_init))
Definition: loader.cpp:36435
EVENT_BOUGHT
#define EVENT_BOUGHT
Object is being bought by player.
Definition: events.h:31
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:71
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:550
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:1177
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
shop_pay_unpaid_callback
static void shop_pay_unpaid_callback(object *op, void *data)
Definition: shop.cpp:832
MSG_TYPE_SHOP_PAYMENT
#define MSG_TYPE_SHOP_PAYMENT
Messages about payment, lack of funds.
Definition: newclient.h:514
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
MSG_TYPE_SHOP_MISC
#define MSG_TYPE_SHOP_MISC
Random messages.
Definition: newclient.h:517
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:309
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:2842
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:444
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:300
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
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:1545
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:328
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:154
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:594
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:896
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:373
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:1022
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
price_base
uint64_t price_base(const object *obj)
Price an item based on its value or archetype value, type, identification/BUC status,...
Definition: item.cpp:1510
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:682
CONTAINER
@ CONTAINER
Definition: object.h:236
done
int done
Definition: readable.cpp:1566
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:380
object::value
int32_t value
How much money it is worth (or contains)
Definition: object.h:360
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:220
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
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:319
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
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:669
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:407
EVENT_SELLING
#define EVENT_SELLING
Object is being sold by another one.
Definition: events.h:38
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:1144
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:1258
shopitems::typenum
int typenum
Itemtype number we need to match, -1 if it is the default price.
Definition: map.h:298
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
EVENT_GSOLD
#define EVENT_GSOLD
Player sold object in shop, but global.
Definition: events.h:71
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:1110
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:738
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:128
UINT32_MAX
#define UINT32_MAX
Definition: loader.cpp:84
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:266
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:516
shopitems::name
const char * name
Name of the item in question, null if it is the default item.
Definition: map.h:296
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:485
mapstruct
This is a game-map.
Definition: map.h:315
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:266
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:683
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
object_get_value
sstring object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4331
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:122
MSG_TYPE_SHOP_LISTING
#define MSG_TYPE_SHOP_LISTING
Shop listings - inventory, what it deals in.
Definition: newclient.h:512
shop_greed
static double shop_greed(const mapstruct *map)
Gets a shop's greed.
Definition: shop.cpp:1073
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:322
count_unpaid_callback
static void count_unpaid_callback(object *item, void *data)
Definition: shop.cpp:706
Settings::real_wiz
uint8_t real_wiz
Use mud-like wizards.
Definition: global.h:272
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:1818
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_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:4484
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:784
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:404
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:724
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:578
identify
object * identify(object *op)
Identifies an item.
Definition: item.cpp:1449