Crossfire Server, Trunk  R20513
shop.c
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 <math.h>
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 
47 static uint64_t pay_from_container(object *pl, object *pouch, uint64_t to_pay);
48 static uint64_t value_limit(uint64_t val, int quantity, const object *who, int isshop);
49 static double shop_specialisation_ratio(const object *item, const mapstruct *map);
50 static double shop_greed(const mapstruct *map);
51 
52 #define NUM_COINS 5
54 #define LARGEST_COIN_GIVEN 2
57 static const char *const coins[] = {
58  "ambercoin",
59  "jadecoin",
60  "platinacoin",
61  "goldcoin",
62  "silvercoin",
63  NULL
64 };
65 
66 uint64_t price_base(const object *tmp) {
67  // When there are zero objects, there is really one.
68  int number = (tmp->nrof == 0) ? 1 : tmp->nrof;
69  uint64_t val = (uint64_t)tmp->value * number;
70 
71  // Objects with price adjustments skip the rest of the calculations.
72  const char *key = object_get_value(tmp, "price_adjustment");
73  if (key != NULL) {
74  float ratio = atof(key);
75  return val * ratio;
76  }
77 
78  if (tmp->type == MONEY || tmp->type == GEM) {
79  return val;
80  }
81 
82  if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) {
83  val *= 0.8;
84  }
85 
86  // If an item has an archetype, compare its base enchantment.
87  if (tmp->arch != NULL) {
88  int diff = tmp->magic - tmp->arch->clone.magic;
89  val *= pow(1.15, diff);
90  }
91 
92  // FIXME: Is the 'baseline' 50 charges per wand?
93  if (tmp->type == WAND) {
94  val *= tmp->stats.food / 50.0;
95  }
96 
97  /* we need to multiply these by 4.0 to keep buy costs roughly the same
98  * (otherwise, you could buy a potion of charisma for around 400 pp.
99  * Arguable, the costs in the archetypes should be updated to better
100  * reflect values (potion charisma list for 1250 gold)
101  */
102  val *= 4;
103 
104  return val;
105 }
106 
107 uint64_t price_approx(const object *tmp, object *who) {
108  uint64_t val = price_base(tmp);
109 
110  /* If we are approximating, then the value returned should
111  * be allowed to be wrong however merely using a random number
112  * each time will not be sufficient, as then multiple examinations
113  * would give different answers, so we'll use the count instead.
114  * By taking the sine of the count, a value between -1 and 1 is
115  * generated, we then divide by the square root of the bargaining
116  * skill and the appropriate identification skills, so that higher
117  * level players get better estimates. (We need a +1 there to
118  * prevent dividing by zero.)
119  */
120  const typedata *tmptype = get_typedata(tmp->type);
121  int lev_identify = 0;
122 
123  if (tmptype) {
124  int idskill1 = tmptype->identifyskill;
125  if (idskill1) {
126  int idskill2 = tmptype->identifyskill2;
127  if (find_skill_by_number(who, idskill1)) {
128  lev_identify = find_skill_by_number(who, idskill1)->level;
129  }
130  if (idskill2 && find_skill_by_number(who, idskill2)) {
131  lev_identify += find_skill_by_number(who, idskill2)->level;
132  }
133  }
134  } else {
135  LOG(llevError, "Query_cost: item %s hasn't got a valid type\n", tmp->name);
136  }
137  val += val * (sin(tmp->count) / sqrt(lev_identify * 3 + 1.0));
138 
139  return val;
140 }
141 
148 static float shop_buy_multiplier(int charisma) {
149  float multiplier = 1 / (0.38 * pow(1.06, charisma));
150 
151  if (multiplier > 2) {
152  return 2;
153  } else if (multiplier < 0.5) {
154  return 0.5;
155  } else {
156  return multiplier;
157  }
158 }
159 
167 static float shop_bargain_multiplier(int lev_bargain) {
168  return 1 - 0.5 * lev_bargain / settings.max_level;
169 }
170 
171 uint64_t shop_price_buy(const object *tmp, object *who) {
172  assert(who != NULL && who->type == PLAYER);
173  uint64_t val = price_base(tmp);
174 
175  const char *key = object_get_value(tmp, "price_adjustment_buy");
176  if (key != NULL) {
177  float ratio = atof(key);
178  return val * ratio;
179  }
180 
181  if (tmp->type == GEM) {
182  return 1.03 * val;
183  }
184 
185  int bargain_level = 0;
187  bargain_level = find_skill_by_number(who, SK_BARGAINING)->level;
188  }
189 
190  float multiplier = shop_bargain_multiplier(bargain_level);
191  multiplier *= shop_buy_multiplier(who->stats.Cha);
192 
193  // Limit buy price multiplier to 0.5, no matter what.
194  val *= multiplier > 0.5 ? multiplier : 0.5;
195 
196  /*
197  * When buying, if the item was sold by another player, it is
198  * ok to let the item be sold cheaper, according to the
199  * specialisation of the shop. If a player sold an item here,
200  * then his sale price was multiplied by the specialisation
201  * ratio, to do the same to the buy price will not generate
202  * extra money. However, the same is not true of generated
203  * items, these have to /divide/ by the specialisation, so
204  * that the price is never less than what they could
205  * be sold for (otherwise players could camp map resets to
206  * make money).
207  * In game terms, a non-specialist shop might not recognise
208  * the true value of the items it sells (much like how people
209  * sometimes find antiques in a junk shop in real life).
210  */
211  if (QUERY_FLAG(tmp, FLAG_PLAYER_SOLD)) {
212  val = (int64_t)val*shop_greed(who->map)
213  *shop_specialisation_ratio(tmp, who->map)
214  /shop_approval(who->map, who);
215  } else {
216  val = (int64_t)val*shop_greed(who->map)
217  /(shop_specialisation_ratio(tmp, who->map)
218  *shop_approval(who->map, who));
219  }
220 
221  return val;
222 }
223 
224 uint64_t shop_price_sell(const object *tmp, object *who) {
225  assert(who != NULL && who->type == PLAYER);
226  uint64_t val = price_base(tmp);
227  bool identified = QUERY_FLAG(tmp, FLAG_IDENTIFIED) || !need_identify(tmp);
228 
229  const char *key = object_get_value(tmp, "price_adjustment_sell");
230  if (key != NULL) {
231  float ratio = atof(key);
232  return val * ratio;
233  }
234 
235  if (tmp->type == GEM) {
236  return 0.97 * val;
237  }
238 
239  // Shops value unidentified items less.
240  if (!identified) {
241  if (tmp->arch != NULL) {
242  // Unidentified standard objects are only worth a little less.
243  if (QUERY_FLAG(tmp, FLAG_BEEN_APPLIED)) {
244  val *= 0.85;
245  } else {
246  val *= 0.70;
247  }
248  } else {
249  // No archetype, so probably an artifact.
250  val /= 2;
251  }
252  }
253 
254  // Selling to shops yields roughly 50% of the base price.
255  val /= 2;
256 
257  /* Limit amount of money you can get for really great items. */
258  int number = (tmp->nrof == 0) ? 1 : tmp->nrof;
259  val = value_limit(val, number, who, 1);
260 
261  val = (int64_t)val*shop_specialisation_ratio(tmp, who->map)*
262  shop_approval(who->map, who)/shop_greed(who->map);
263  return val;
264 }
265 
277 static archetype *find_next_coin(uint64_t c, int *cointype) {
278  archetype *coin;
279 
280  do {
281  if (coins[*cointype] == NULL)
282  return NULL;
283  coin = find_archetype(coins[*cointype]);
284  if (coin == NULL)
285  return NULL;
286  *cointype += 1;
287  } while (coin->clone.value > (int64_t) c);
288 
289  return coin;
290 }
291 
311 char* cost_string_from_value(uint64_t cost, int largest_coin) {
312  archetype *coin, *next_coin;
313  uint32_t num;
314  int cointype = largest_coin;
315 
316  if (cointype < 0)
317  cointype = 0;
318  else if (cointype >= NUM_COINS)
319  cointype = NUM_COINS - 1;
320 
322  coin = find_next_coin(cost, &cointype);
323  if (coin == NULL) {
324  stringbuffer_append_string(buf, "nothing");
325  goto done;
326  }
327 
328  num = cost/coin->clone.value;
329  /* so long as nrof is 32 bit, this is true.
330  * If it takes more coins than a person can possibly carry, this
331  * is basically true.
332  */
333  if ((cost/coin->clone.value) > UINT32_MAX) {
334  stringbuffer_append_string(buf, "an unimaginable sum of money.");
335  goto done;
336  }
337 
338  cost -= (uint64_t)num*(uint64_t)coin->clone.value;
339  if (num == 1)
340  stringbuffer_append_printf(buf, "1 %s", coin->clone.name);
341  else
342  stringbuffer_append_printf(buf, "%u %ss", num, coin->clone.name);
343 
344  next_coin = find_next_coin(cost, &cointype);
345  if (next_coin == NULL)
346  goto done;
347 
348  do {
349  coin = next_coin;
350  num = cost/coin->clone.value;
351  cost -= (uint64_t)num*(uint64_t)coin->clone.value;
352 
353  if (cost == 0)
354  next_coin = NULL;
355  else
356  next_coin = find_next_coin(cost, &cointype);
357 
358  if (next_coin) {
359  /* There will be at least one more string to add to the list,
360  * use a comma.
361  */
362  stringbuffer_append_string(buf, ", ");
363  } else {
364  stringbuffer_append_string(buf, " and ");
365  }
366  if (num == 1)
367  stringbuffer_append_printf(buf, "1 %s", coin->clone.name);
368  else
369  stringbuffer_append_printf(buf, "%u %ss", num, coin->clone.name);
370  } while (next_coin);
371 
372 done:
373  return stringbuffer_finish(buf);
374 }
375 
386 static StringBuffer *real_money_value(const object *coin, StringBuffer *buf) {
387  assert(coin->type == MONEY);
388  assert(buf);
389 
390  stringbuffer_append_printf(buf, "%ld %s", (long)coin->nrof, coin->nrof == 1 ? coin->name : coin->name_pl);
391  return buf;
392 }
393 
394 char *cost_str(uint64_t cost) {
396 }
397 
398 char *cost_approx_str(const object *tmp, object *who) {
399  uint64_t approx_val = price_approx(tmp, who);
400  int idskill1 = 0;
401  int idskill2 = 0;
402  const typedata *tmptype;
403 
405 
406  /* money it's pretty hard to not give the exact price, so skip all logic and just return the real value. */
407  if (tmp->type == MONEY) {
408  return stringbuffer_finish(real_money_value(tmp, buf));
409  }
410 
411  tmptype = get_typedata(tmp->type);
412  if (tmptype) {
413  idskill1 = tmptype->identifyskill;
414  idskill2 = tmptype->identifyskill2;
415  }
416 
417  /* we show an approximate price if
418  * 1) we are approximating
419  * 2) there either is no id skill(s) for the item, or we don't have them
420  * 3) we don't have bargaining skill either
421  */
422  if (!idskill1 || !find_skill_by_number(who, idskill1)) {
423  if (!idskill2 || !find_skill_by_number(who, idskill2)) {
424  if (!find_skill_by_number(who, SK_BARGAINING)) {
425  int num;
426  int cointype = LARGEST_COIN_GIVEN;
427  archetype *coin = find_next_coin(approx_val, &cointype);
428 
429  if (coin == NULL) {
430  stringbuffer_append_string(buf, "nothing");
431  return stringbuffer_finish(buf);
432  }
433 
434  num = approx_val/coin->clone.value;
435  if (num == 1)
436  stringbuffer_append_printf(buf, "about one %s", coin->clone.name);
437  else if (num < 5)
438  stringbuffer_append_printf(buf, "a few %s", coin->clone.name_pl);
439  else if (num < 10)
440  stringbuffer_append_printf(buf, "several %s", coin->clone.name_pl);
441  else if (num < 25)
442  stringbuffer_append_printf(buf, "a moderate amount of %s", coin->clone.name_pl);
443  else if (num < 100)
444  stringbuffer_append_printf(buf, "lots of %s", coin->clone.name_pl);
445  else if (num < 1000)
446  stringbuffer_append_printf(buf, "a great many %s", coin->clone.name_pl);
447  else
448  stringbuffer_append_printf(buf, "a vast quantity of %s", coin->clone.name_pl);
449  return stringbuffer_finish(buf);
450  }
451  }
452  }
453 
454  // If we get here, return the price we guessed.
455  stringbuffer_delete(buf);
456  return cost_str(approx_val);
457 }
458 
459 uint64_t query_money(const object *op) {
460  uint64_t total = 0;
461 
462  if (op->type != PLAYER && op->type != CONTAINER) {
463  LOG(llevError, "Query money called with non player/container\n");
464  return 0;
465  }
466  FOR_INV_PREPARE(op, tmp) {
467  if (tmp->type == MONEY) {
468  total += (uint64_t)tmp->nrof*(uint64_t)tmp->value;
469  } else if (tmp->type == CONTAINER
470  && QUERY_FLAG(tmp, FLAG_APPLIED)
471  && (tmp->race == NULL || strstr(tmp->race, "gold"))) {
472  total += query_money(tmp);
473  }
474  } FOR_INV_FINISH();
475  return total;
476 }
477 
490 int pay_for_amount(uint64_t to_pay, object *pl) {
491  if (to_pay == 0)
492  return 1;
493  if (to_pay > query_money(pl))
494  return 0;
495 
496  to_pay = pay_from_container(pl, pl, to_pay);
497 
498  FOR_INV_PREPARE(pl, pouch) {
499  if (to_pay <= 0)
500  break;
501  if (pouch->type == CONTAINER
502  && QUERY_FLAG(pouch, FLAG_APPLIED)
503  && (pouch->race == NULL || strstr(pouch->race, "gold"))) {
504  to_pay = pay_from_container(pl, pouch, to_pay);
505  }
506  } FOR_INV_FINISH();
507  if (to_pay > 0) {
508  LOG(llevError, "pay_for_amount: Cannot remove enough money -- %"FMT64U" remains\n", to_pay);
509  }
510 
511  fix_object(pl);
512  return 1;
513 }
514 
529 int pay_for_item(object *op, object *pl) {
530  uint64_t to_pay = shop_price_buy(op, pl);
531 
532  if (to_pay == 0)
533  return 1;
534  if (to_pay > query_money(pl))
535  return 0;
536 
537  /* We compare the paid price with the one for a player
538  * without bargaining skill.
539  * This determins the amount of exp (if any) gained for bargaining.
540  */
541  int64_t saved_money = price_base(op) - to_pay;
542  if (saved_money > 0)
543  change_exp(pl, saved_money, "bargaining", SK_EXP_NONE);
544 
545  to_pay = pay_from_container(pl, pl, to_pay);
546 
547  FOR_INV_PREPARE(pl, pouch) {
548  if (to_pay <= 0)
549  break;
550  if (pouch->type == CONTAINER
551  && QUERY_FLAG(pouch, FLAG_APPLIED)
552  && (pouch->race == NULL || strstr(pouch->race, "gold"))) {
553  to_pay = pay_from_container(pl, pouch, to_pay);
554  }
555  } FOR_INV_FINISH();
556  if (to_pay > 0) {
557  LOG(llevError, "pay_for_item: Cannot remove enough money -- %"FMT64U" remains\n", to_pay);
558  }
560  SET_FLAG(op, FLAG_WAS_WIZ);
561  fix_object(pl);
562  return 1;
563 }
564 
576 static int64_t remove_value(object *coin_objs[], int64_t remain) {
577  int i;
578 
579  for (i = 0; i < NUM_COINS; i++) {
580  int count;
581  int64_t num_coins;
582 
583  if ((int64_t)coin_objs[i]->nrof * coin_objs[i]->value > remain) {
584  num_coins = remain/coin_objs[i]->value;
585  if ((uint64_t)num_coins*(uint64_t)coin_objs[i]->value < (uint64_t) remain) {
586  num_coins++;
587  }
588  } else {
589  num_coins = coin_objs[i]->nrof;
590  }
591  remain -= (int64_t)num_coins*(int64_t)coin_objs[i]->value;
592  coin_objs[i]->nrof -= num_coins;
593  /* Now start making change. Start at the coin value
594  * below the one we just did, and work down to
595  * the lowest value.
596  */
597  count = i-1;
598  while (remain < 0 && count >= 0) {
599  num_coins = -remain/coin_objs[count]->value;
600  coin_objs[count]->nrof += num_coins;
601  remain += num_coins*coin_objs[count]->value;
602  count--;
603  }
604  }
605 
606  return remain;
607 }
608 
617 static void add_value(object *coin_objs[], int64_t value) {
618  int i;
619 
620  for (i = NUM_COINS-LARGEST_COIN_GIVEN-1; i >= 0; i--) {
621  uint32_t nrof;
622 
623  nrof = (uint32_t)(value/coin_objs[i]->value);
624  value -= nrof*coin_objs[i]->value;
625  coin_objs[i]->nrof += nrof;
626  }
627 }
628 
641 static void insert_objects(object *pl, object *container, object *objects[], int objects_len) {
642  int i, one = 0;
643 
644  for (i = 0; i < objects_len; i++) {
645  if (objects[i]->nrof > 0) {
646  object_insert_in_ob(objects[i], container);
647  one = 1;
648  } else {
649  object_free_drop_inventory(objects[i]);
650  }
651  }
652  if (one)
653  esrv_update_item(UPD_WEIGHT, pl, container);
654 }
655 
672 static uint64_t pay_from_container(object *pl, object *pouch, uint64_t to_pay) {
673  size_t i;
674  int64_t remain;
675  object *coin_objs[NUM_COINS];
676  object *other_money[16]; /* collects MONEY objects not matching coins[] */
677  size_t other_money_len; /* number of allocated entries in other_money[] */
678  archetype *at;
679 
680  if (pouch->type != PLAYER && pouch->type != CONTAINER)
681  return to_pay;
682 
683  remain = to_pay;
684  for (i = 0; i < NUM_COINS; i++)
685  coin_objs[i] = NULL;
686 
687  /* This hunk should remove all the money objects from the player/container */
688  other_money_len = 0;
689  FOR_INV_PREPARE(pouch, tmp) {
690  if (tmp->type == MONEY) {
691  for (i = 0; i < NUM_COINS; i++) {
692  if (!strcmp(coins[NUM_COINS-1-i], tmp->arch->name)
693  && (tmp->value == tmp->arch->clone.value)) {
694  /* This should not happen, but if it does, just
695  * merge the two.
696  */
697  if (coin_objs[i] != NULL) {
698  LOG(llevError, "%s has two money entries of (%s)\n", pouch->name, coins[NUM_COINS-1-i]);
699  object_remove(tmp);
700  coin_objs[i]->nrof += tmp->nrof;
702  } else {
703  object_remove(tmp);
704  coin_objs[i] = tmp;
705  }
706  break;
707  }
708  }
709  if (i == NUM_COINS) {
710  if (other_money_len >= sizeof(other_money)/sizeof(*other_money)) {
711  LOG(llevError, "pay_for_item: Cannot store non-standard money object %s\n", tmp->arch->name);
712  } else {
713  object_remove(tmp);
714  other_money[other_money_len++] = tmp;
715  }
716  }
717  }
718  } FOR_INV_FINISH();
719 
720  /* Fill in any gaps in the coin_objs array - needed to make change. */
721  /* Note that the coin_objs array goes from least value to greatest value */
722  for (i = 0; i < NUM_COINS; i++)
723  if (coin_objs[i] == NULL) {
724  at = find_archetype(coins[NUM_COINS-1-i]);
725  if (at == NULL)
726  LOG(llevError, "Could not find %s archetype\n", coins[NUM_COINS-1-i]);
727  coin_objs[i] = object_new();
728  object_copy(&at->clone, coin_objs[i]);
729  coin_objs[i]->nrof = 0;
730  }
731 
732  /* Try to pay from standard coins first. */
733  remain = remove_value(coin_objs, remain);
734 
735  /* Now pay from non-standard coins until all is paid. */
736  for (i = 0; i < other_money_len && remain > 0; i++) {
737  uint32_t nrof;
738  object *coin;
739 
740  coin = other_money[i];
741 
742  /* Find the minimal number of coins to use. This prevents converting
743  * excess non-standard coins to standard money.
744  */
745  nrof = (remain+coin->value-1)/coin->value;
746  if (nrof > coin->nrof) {
747  nrof = coin->nrof;
748  }
749  coin->nrof -= nrof;
750  add_value(coin_objs, nrof*coin->value);
751 
752  remain = remove_value(coin_objs, remain);
753  }
754 
755  /* re-insert remaining coins into player */
756  insert_objects(pl, pouch, coin_objs, NUM_COINS);
757  insert_objects(pl, pouch, other_money, other_money_len);
758 
759  return(remain);
760 }
761 
778 static void count_unpaid(object *pl, object *item, int *unpaid_count, uint64_t *unpaid_price, uint32_t *coincount) {
779  int i;
780 
782  if (QUERY_FLAG(item, FLAG_UNPAID)) {
783  (*unpaid_count)++;
784  (*unpaid_price) += shop_price_buy(item, pl);
785  }
786  /* Merely converting the player's monetary wealth won't do.
787  * If we did that, we could print the wrong numbers for the
788  * coins, so we count the money instead.
789  */
790  for (i = 0; i < NUM_COINS; i++)
791  if (!strcmp(coins[i], item->arch->name)) {
792  coincount[i] += item->nrof;
793  break;
794  }
795  if (item->inv)
796  count_unpaid(pl, item->inv, unpaid_count, unpaid_price, coincount);
798 }
799 
812 int can_pay(object *pl) {
813  int unpaid_count = 0, i;
814  uint64_t unpaid_price = 0;
815  uint64_t player_wealth = query_money(pl);
816  uint32_t coincount[NUM_COINS];
817 
818  if (!pl || pl->type != PLAYER) {
819  LOG(llevError, "can_pay(): called against something that isn't a player\n");
820  return 0;
821  }
822 
823  for (i = 0; i < NUM_COINS; i++)
824  coincount[i] = 0;
825 
826  count_unpaid(pl, pl->inv, &unpaid_count, &unpaid_price, coincount);
827 
828  if (unpaid_price > player_wealth) {
829  char buf[MAX_BUF], coinbuf[MAX_BUF];
830  int denominations = 0;
831  char *value = cost_str(unpaid_price);
832 
833  snprintf(buf, sizeof(buf), "You have %d unpaid items that would cost you %s, ", unpaid_count, value);
834  free(value);
835  for (i = 0; i < NUM_COINS; i++) {
836  if (coincount[i] > 0 && coins[i]) {
837  if (denominations == 0)
838  snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "but you only have");
839  denominations++;
840  snprintf(coinbuf, sizeof(coinbuf), " %u %s,", coincount[i], find_archetype(coins[i])->clone.name_pl);
841  snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s", coinbuf);
842  }
843  }
844  if (denominations == 0)
845  snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "but you don't have any money.");
846  else if (denominations > 1)
847  make_list_like(buf);
849  MSG_TYPE_SHOP_PAYMENT, buf);
850  return 0;
851  } else
852  return 1;
853 }
854 
855 int shop_pay_unpaid(object *pl, object *op) {
856  char name_op[MAX_BUF];
857  int ret = 1;
858 
859  if (op != NULL && op->inv)
860  ret = shop_pay_unpaid(pl, op->inv);
861 
862  if (!ret)
863  return 0;
864 
865  if (op != NULL && op->below)
866  ret = shop_pay_unpaid(pl, op->below);
867 
868  if (!ret)
869  return 0;
870 
871  if (op != NULL && QUERY_FLAG(op, FLAG_UNPAID)) {
872  uint64_t price = shop_price_buy(op, pl);
873  if (!pay_for_item(op, pl)) {
874  uint64_t i = price - query_money(pl);
875  char *missing = cost_str(i);
876 
877  CLEAR_FLAG(op, FLAG_UNPAID);
878  query_name(op, name_op, MAX_BUF);
881  "You lack %s to buy %s.",
882  missing, name_op);
883  free(missing);
884  SET_FLAG(op, FLAG_UNPAID);
885  return 0;
886  } else {
887  object *tmp;
888  char *value = cost_str(price);
889 
890  CLEAR_FLAG(op, FLAG_UNPAID);
892  query_name(op, name_op, MAX_BUF);
895  "You paid %s for %s.",
896  value, name_op);
897  free(value);
898  tmp = object_merge(op, NULL);
899  if (pl->type == PLAYER && !tmp) {
900  /* If item wasn't merged we update it. If merged, object_merge() handled everything for us. */
902  }
903  }
904  }
905  return 1;
906 }
907 
921 void sell_item(object *op, object *pl) {
922  object *tmp;
923  archetype *at;
924  char obj_name[MAX_BUF];
925 
926  query_name(op, obj_name, MAX_BUF);
927 
928  if (pl == NULL || pl->type != PLAYER) {
929  LOG(llevDebug, "Object other than player tried to sell something.\n");
930  return;
931  }
932 
933  if (execute_event(op, EVENT_SELLING, pl, NULL, NULL, SCRIPT_FIX_ALL) != 0)
934  return;
935 
936  if (op->custom_name)
938 
939  uint64_t price = shop_price_sell(op, pl);
940  if (price == 0) {
943  "We're not interested in %s.",
944  obj_name);
945  return;
946  }
947 
948  /* We compare the price with the one for a player
949  * without bargaining skill.
950  * This determins the amount of exp (if any) gained for bargaining.
951  * exp/10 -> 1 for each gold coin
952  */
953  int64_t extra_gain = price - price_base(op);
954  if (extra_gain > 0) {
955  change_exp(pl, extra_gain/10, "bargaining", SK_EXP_NONE);
956  }
957 
958  char *value_str = cost_str(price);
960  "You receive %s for %s.", value_str, obj_name);
961  free(value_str);
962 
963  for (int count = LARGEST_COIN_GIVEN; coins[count] != NULL; count++) {
964  at = find_archetype(coins[count]);
965  if (at == NULL)
966  LOG(llevError, "Could not find %s archetype\n", coins[count]);
967  else if ((price/at->clone.value) > 0) {
968  FOR_INV_PREPARE(pl, pouch) {
969  if (pouch->type == CONTAINER
970  && QUERY_FLAG(pouch, FLAG_APPLIED)
971  && pouch->race
972  && strstr(pouch->race, "gold")) {
973  int w = at->clone.weight*(100-pouch->stats.Str)/100;
974  int n = price/at->clone.value;
975 
976  if (w == 0)
977  w = 1; /* Prevent divide by zero */
978  if (n > 0
979  && (!pouch->weight_limit || pouch->carrying+w <= pouch->weight_limit)) {
980  if (pouch->weight_limit
981  && (pouch->weight_limit-pouch->carrying)/w < n)
982  n = (pouch->weight_limit-pouch->carrying)/w;
983 
984  tmp = object_new();
985  object_copy(&at->clone, tmp);
986  tmp->nrof = n;
987  price -= (uint64_t)tmp->nrof*(uint64_t)tmp->value;
988  tmp = object_insert_in_ob(tmp, pouch);
989  esrv_update_item(UPD_WEIGHT, pl, pl);
990  }
991  }
992  } FOR_INV_FINISH();
993  if (price/at->clone.value > 0) {
994  tmp = object_new();
995  object_copy(&at->clone, tmp);
996  tmp->nrof = price/tmp->value;
997  price -= (uint64_t)tmp->nrof*(uint64_t)tmp->value;
998  tmp = object_insert_in_ob(tmp, pl);
999  esrv_update_item(UPD_WEIGHT, pl, pl);
1000  }
1001  }
1002  }
1003 
1004  if (price != 0) {
1005  LOG(llevError, "Warning - payment not zero: %" PRIo64 "\n", price);
1006  }
1007 
1008  SET_FLAG(op, FLAG_UNPAID);
1009  identify(op);
1010 }
1011 
1025 static double shop_specialisation_ratio(const object *item, const mapstruct *map) {
1026  shopitems *items = map->shopitems;
1027  double ratio = SPECIALISATION_EFFECT, likedness = 0.001;
1028  int i;
1029 
1030  if (item == NULL) {
1031  LOG(llevError, "shop_specialisation_ratio: passed a NULL item for map %s\n", map->path);
1032  return 0;
1033  }
1034  if (item->type == (uint8_t)-1) {
1035  LOG(llevError, "shop_specialisation_ratio: passed an item with an invalid type\n");
1036  /*
1037  * I'm not really sure what the /right/ thing to do here is,
1038  * these types of item shouldn't exist anyway, but returning
1039  * the ratio is probably the best bet.."
1040  */
1041  return ratio;
1042  }
1043  if (map->shopitems) {
1044  for (i = 0; i < items[0].index; i++)
1045  if (items[i].typenum == item->type || (items[i].typenum == -1 && likedness == 0.001))
1046  likedness = items[i].strength/100.0;
1047  }
1048  if (likedness > 1.0) { /* someone has been rather silly with the map headers. */
1049  LOG(llevDebug, "shop_specialisation ratio: item type %d on map %s is above 100%%\n", item->type, map->path);
1050  likedness = 1.0;
1051  }
1052  if (likedness < -1.0) {
1053  LOG(llevDebug, "shop_specialisation ratio: item type %d on map %s is below -100%%\n", item->type, map->path);
1054  likedness = -1.0;
1055  }
1056  ratio = ratio+(1.0-ratio)*likedness;
1057  if (ratio <= 0.1)
1058  ratio = 0.1; /* if the ratio were much lower than this, we would get silly prices */
1059  return ratio;
1060 }
1061 
1070 static double shop_greed(const mapstruct *map) {
1071  double greed = 1.0;
1072 
1073  if (map->shopgreed)
1074  return map->shopgreed;
1075  return greed;
1076 }
1077 
1078 double shop_approval(const mapstruct *map, const object *player) {
1079  double approval = 1.0;
1080 
1081  if (map->shoprace) {
1082  approval = NEUTRAL_RATIO;
1083  if (player->race && !strcmp(player->race, map->shoprace))
1084  approval = 1.0;
1085  }
1086  return approval;
1087 }
1088 
1108 static uint64_t value_limit(uint64_t val, int quantity, const object *who, int isshop) {
1109  uint64_t newval, unit_price;
1110  mapstruct *map;
1111 
1112  unit_price = val/quantity;
1113  if (!isshop || !who) {
1114  if (unit_price > 10000)
1115  newval = 8000+isqrt(unit_price)*20;
1116  else
1117  newval = unit_price;
1118  } else {
1119  if (!who->map) {
1120  LOG(llevError, "value_limit: asked shop price for ob %s on NULL map\n", who->name);
1121  return val;
1122  }
1123  map = who->map;
1124  if (map->shopmin && unit_price < map->shopmin)
1125  return 0;
1126  else if (map->shopmax && unit_price > map->shopmax/2)
1127  newval = MIN((map->shopmax/2)+isqrt(unit_price-map->shopmax/2), map->shopmax);
1128  else if (unit_price > 10000)
1129  newval = 8000+isqrt(unit_price)*20;
1130  else
1131  newval = unit_price;
1132  }
1133  newval *= quantity;
1134  return newval;
1135 }
1136 
1137 int shop_describe(const object *op) {
1138  mapstruct *map = op->map;
1139  /*shopitems *items=map->shopitems;*/
1140  int pos = 0, i;
1141  double opinion = 0;
1142  char tmp[MAX_BUF] = "\0", *value;
1143 
1144  if (op->type != PLAYER)
1145  return 0;
1146 
1147  /*check if there is a shop specified for this map */
1148  if (map->shopitems
1149  || map->shopgreed
1150  || map->shoprace
1151  || map->shopmin
1152  || map->shopmax) {
1154  "From looking at the nearby shop you determine that it trades in:");
1155 
1156  if (map->shopitems) {
1157  for (i = 0; i < map->shopitems[0].index; i++) {
1158  if (map->shopitems[i].name && map->shopitems[i].strength > 10) {
1159  snprintf(tmp+pos, sizeof(tmp)-pos, "%s, ", map->shopitems[i].name_pl);
1160  pos += strlen(tmp+pos);
1161  }
1162  }
1163  }
1164  if (!pos)
1165  strcpy(tmp, "a little of everything.");
1166 
1167  /* format the string into a list */
1168  make_list_like(tmp);
1169  draw_ext_info(NDI_UNIQUE, 0, op,
1171 
1172  if (map->shopmax) {
1173  value = cost_str(map->shopmax);
1176  "It won't trade for items above %s.",
1177  value);
1178  free(value);
1179  }
1180 
1181  if (map->shopmin) {
1182  value = cost_str(map->shopmin);
1185  "It won't trade in items worth less than %s.",
1186  value);
1187  free(value);
1188  }
1189 
1190  if (map->shopgreed) {
1191  if (map->shopgreed > 2.0)
1192  draw_ext_info(NDI_UNIQUE, 0, op,
1194  "It tends to overcharge massively.");
1195  else if (map->shopgreed > 1.5)
1196  draw_ext_info(NDI_UNIQUE, 0, op,
1198  "It tends to overcharge substantially.");
1199  else if (map->shopgreed > 1.1)
1200  draw_ext_info(NDI_UNIQUE, 0, op,
1202  "It tends to overcharge slightly.");
1203  else if (map->shopgreed < 0.9)
1204  draw_ext_info(NDI_UNIQUE, 0, op,
1206  "It tends to undercharge.");
1207  }
1208  if (map->shoprace) {
1209  opinion = shop_approval(map, op);
1210  if (opinion > 0.8)
1211  draw_ext_info(NDI_UNIQUE, 0, op,
1213  "You think the shopkeeper likes you.");
1214  else if (opinion > 0.5)
1215  draw_ext_info(NDI_UNIQUE, 0, op,
1217  "The shopkeeper seems unconcerned by you.");
1218  else
1219  draw_ext_info(NDI_UNIQUE, 0, op,
1221  "The shopkeeper seems to have taken a dislike to you.");
1222  }
1224  "There is no shop nearby.");
1225 
1226  return 1;
1227 }
1228 
1232 static bool coords_in_shop(mapstruct *map, int x, int y) {
1233  FOR_MAP_PREPARE(map, x, y, floor)
1234  if (floor->type == SHOP_FLOOR) return true;
1235  FOR_MAP_FINISH();
1236  return false;
1237 }
1238 
1239 bool shop_contains(object *ob) {
1240  if (!ob->map) return 0;
1241  return coords_in_shop(ob->map, ob->x, ob->y);
1242 }
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Sends message to player(s).
Definition: main.c:315
Error, serious thing.
Definition: logger.h:11
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:365
uint64_t price_base(const object *tmp)
Determine the base (intrinsic) value of an item.
Definition: shop.c:66
One player.
Definition: player.h:92
#define FLAG_PLAYER_SOLD
Object was sold to a shop by a player.
Definition: define.h:252
double shopgreed
How much our shopkeeper overcharges.
Definition: map.h:358
archetype * find_archetype(const char *name)
Finds, using the hashtable, which archetype matches the given name.
Definition: arch.c:695
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:318
#define FLAG_UNPAID
Object hasn&#39;t been paid for yet.
Definition: define.h:236
#define MSG_TYPE_SHOP_LISTING
Shop listings - inventory, what it deals in.
Definition: newclient.h:486
static archetype * find_next_coin(uint64_t c, int *cointype)
Find the coin type that is worth more than &#39;c&#39;.
Definition: shop.c:277
static const char *const coins[]
Coins to use for shopping.
Definition: shop.c:57
uint64_t query_money(const object *op)
Determine the amount of money the given object contains, including what is inside containers...
Definition: shop.c:459
static StringBuffer * real_money_value(const object *coin, StringBuffer *buf)
Returns a string representing the money&#39;s value, in plain coins.
Definition: shop.c:386
const char * race
Human, goblin, dragon, etc.
Definition: object.h:318
uint64_t shop_price_sell(const object *tmp, object *who)
Adjust the value of an item to be sold based on the player&#39;s bargaining skill and charisma...
Definition: shop.c:224
#define MSG_TYPE_SHOP_SELL
Messages about selling items.
Definition: newclient.h:492
#define SET_FLAG(xyz, p)
Definition: define.h:223
unsigned char uint8_t
Definition: win32.h:161
int identifyskill
Skill used to identify this object class.
Definition: define.h:93
#define NUM_COINS
Number of coin types.
Definition: shop.c:52
static bool coords_in_shop(mapstruct *map, int x, int y)
Check if the given map coordinates are in a shop.
Definition: shop.c:1232
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.c:57
int16_t max_level
This is read out of exp_table.
Definition: global.h:300
static double shop_specialisation_ratio(const object *item, const mapstruct *map)
returns a double that is the ratio of the price that a shop will offer for item based on the shops sp...
Definition: shop.c:1025
#define FMT64U
Definition: compat.h:13
#define MSG_TYPE_SHOP_PAYMENT
Messages about payment, lack of funds.
Definition: newclient.h:489
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.c:342
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.c:4246
See Money.
Definition: object.h:137
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.c:1108
double shop_approval(const mapstruct *map, const object *player)
Return the approval ratio for a shop for a given player.
Definition: shop.c:1078
uint64_t shop_price_buy(const object *tmp, object *who)
Adjust the value of an item to be bought based on the player&#39;s bargaining skill and charisma...
Definition: shop.c:171
object clone
An object from which to do object_copy()
Definition: object.h:470
bool shop_contains(object *ob)
Check if an object is in a shop.
Definition: shop.c:1239
int isqrt(int n)
Compute the square root.
Definition: utils.c:585
static void count_unpaid(object *pl, object *item, int *unpaid_count, uint64_t *unpaid_price, uint32_t *coincount)
Helper function for can_pay().
Definition: shop.c:778
const char * name
Name of the item in question, null if it is the default item.
Definition: map.h:306
static void insert_objects(object *pl, object *container, object *objects[], int objects_len)
Insert a list of objects into a player object.
Definition: shop.c:641
#define FALSE
Definition: compat.h:11
Global type definitions and header inclusions.
Link an object type with skill needed to identify, and general name.
Definition: define.h:89
#define SCRIPT_FIX_ALL
Definition: global.h:361
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.c:310
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:465
Bargaining.
Definition: skills.h:28
See Wand & Staff.
Definition: object.h:220
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:789
#define MIN(x, y)
Definition: compat.h:17
int typenum
Itemtype number we need to match, -1 if it is the default price.
Definition: map.h:308
int can_pay(object *pl)
Checks all unpaid items in op&#39;s inventory, adds up all the money they have, and checks that they can ...
Definition: shop.c:812
uint64_t price_approx(const object *tmp, object *who)
Adjust the value of the given item based on the player&#39;s skills.
Definition: shop.c:107
const typedata * get_typedata(int itemtype)
Definition: item.c:334
static void add_value(object *coin_objs[], int64_t value)
This function adds a given amount to a list of coins.
Definition: shop.c:617
void make_list_like(char *input)
Taking a string as an argument, mutate it into a string that looks like a list.
Definition: utils.c:394
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.c:1368
int16_t y
Position in the map for this object.
Definition: object.h:326
int pay_for_item(object *op, object *pl)
DAMN: This is now a wrapper for pay_from_container, which is called for the player, then for each active container that can hold money until op is paid for.
Definition: shop.c:529
static int64_t remove_value(object *coin_objs[], int64_t remain)
This function removes a given amount from a list of coins.
Definition: shop.c:576
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it...
Definition: object.c:1037
const char * name_pl
The plural name of the object.
Definition: object.h:315
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
Definition: stringbuffer.c:95
int index
Being the size of the shopitems array.
Definition: map.h:311
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.c:2690
char * cost_string_from_value(uint64_t cost, int largest_coin)
Converts a price to number of coins.
Definition: shop.c:311
int32_t weight
Attributes of the object.
Definition: object.h:365
int8_t strength
The degree of specialisation the shop has in this item, as a percentage from -100 to 100...
Definition: map.h:309
struct mapdef * map
Pointer to the map in which this object is present.
Definition: object.h:297
#define snprintf
Definition: win32.h:46
uint64_t shopmin
Minimum price a shop will trade for.
Definition: map.h:359
#define FLAG_IDENTIFIED
Player knows full info about item.
Definition: define.h:261
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:712
#define MSG_TYPE_SHOP_MISC
Random messages.
Definition: newclient.h:493
object * objects
Pointer to the list of used objects.
Definition: object.c:60
const char * name
The name of the object, obviously...
Definition: object.h:311
char * cost_approx_str(const object *tmp, object *who)
Return a textual cost approximation in a newly-allocated string.
Definition: shop.c:398
static double shop_greed(const mapstruct *map)
Gets shop&#39;s greed.
Definition: shop.c:1070
struct obj * below
Pointer to the object stacked below this one.
Definition: object.h:287
uint32_t nrof
How many of the objects.
Definition: object.h:333
int8_t Cha
Definition: living.h:35
#define UPD_FLAGS
Definition: newclient.h:290
uint8_t real_wiz
Use mud-like wizards.
Definition: global.h:269
#define EVENT_SELLING
Object is being sold by another one.
Definition: plugin.h:79
int pay_for_amount(uint64_t to_pay, object *pl)
Takes the amount of money from the the player inventory and from it&#39;s various pouches using the pay_f...
Definition: shop.c:490
#define FREE_AND_CLEAR_STR(xyz)
Release the shared string, and set it to NULL.
Definition: global.h:208
#define MSG_TYPE_SHOP
Definition: newclient.h:378
#define UPD_WEIGHT
Definition: newclient.h:291
unsigned __int64 uint64_t
Definition: win32.h:167
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Changes experience to a player/monster.
Definition: living.c:2076
#define FLAG_BEEN_APPLIED
The object has been applied.
Definition: define.h:324
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
int16_t x
Definition: object.h:326
int shop_pay_unpaid(object *pl, object *op)
Pay for each unpaid item carried by a player, including those inside containers.
Definition: shop.c:855
See Container.
Definition: object.h:231
signed __int64 int64_t
Definition: win32.h:168
int identifyskill2
Second skill used to identify this object class.
Definition: define.h:94
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:765
int need_identify(const object *op)
This function really should not exist - by default, any item not identified should need it...
Definition: item.c:1331
#define FLAG_CURSED
The object is cursed.
Definition: define.h:317
unsigned int uint32_t
Definition: win32.h:162
See Player.
Definition: object.h:107
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 player.
Definition: shop.c:672
static float shop_buy_multiplier(int charisma)
Calculate the buy price multiplier based on a player&#39;s charisma.
Definition: shop.c:148
const char * custom_name
Custom name assigned by player.
Definition: object.h:432
tag_t count
Unique object number for this object.
Definition: object.h:299
const char * name_pl
Plural name.
Definition: map.h:307
living stats
Str, Con, Dex, etc.
Definition: object.h:368
struct archt * arch
Pointer to archetype.
Definition: object.h:412
See Shop Floor.
Definition: object.h:183
Only for debugging purposes.
Definition: logger.h:13
#define LARGEST_COIN_GIVEN
Never give amber or jade, but accept them.
Definition: shop.c:54
void stringbuffer_delete(StringBuffer *sb)
Totally delete a string buffer.
Definition: stringbuffer.c:71
uint64_t shopmax
MMaximum price a shop will offer.
Definition: map.h:360
char * cost_str(uint64_t cost)
Definition: shop.c:394
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
struct Settings settings
Server settings.
Definition: init.c:40
#define SK_EXP_NONE
Player gets nothing.
Definition: skills.h:81
Shop-related information for a map.
Definition: map.h:305
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
void sell_item(object *op, object *pl)
Player is selling an item.
Definition: shop.c:921
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.c:1869
int execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: main.c:364
#define UPD_NAME
Definition: newclient.h:293
#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:785
#define SPECIALISATION_EFFECT
This is a measure of how effective store specialisation is.
Definition: shop.c:39
object * identify(object *op)
Identifies an item.
Definition: item.c:1437
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Append a formatted string to a string buffer instance.
Definition: stringbuffer.c:104
static float shop_bargain_multiplier(int lev_bargain)
Calculate the buy price multiplier based on a player&#39;s bargaining skill.
Definition: shop.c:167
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.c:838
struct obj * inv
Pointer to the first object in the inventory.
Definition: object.h:290
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:234
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:758
struct shopitem * shopitems
List of item-types the map&#39;s shop will trade in.
Definition: map.h:356
A buffer that will be expanded as content is added to it.
Definition: stringbuffer.c:25
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.c:625
char * shoprace
The preffered race of the local shopkeeper.
Definition: map.h:357
object * find_skill_by_number(object *who, int skillno)
This returns the skill pointer of the given name (the one that accumulates exp, has the level...
Definition: main.c:351
This is a game-map.
Definition: map.h:325
See Jewel.
Definition: object.h:167
#define NEUTRAL_RATIO
Price a shopkeeper will give someone they neither like nor dislike.
Definition: shop.c:45
int shop_describe(const object *op)
Give the player a description of the shop on their current map.
Definition: shop.c:1137
int16_t level
Level of creature or object.
Definition: object.h:351
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.c:1120
int32_t value
How much money it is worth (or contains)
Definition: object.h:350
int8_t magic
Any magical bonuses to this item.
Definition: object.h:348
const char * name
More definite name, like "generate_kobold".
Definition: object.h:466
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
Definition: stringbuffer.c:76
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:705
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.c:1654
int32_t food
How much food in stomach.
Definition: living.h:47