Go to the documentation of this file.
39 #define SPECIALISATION_EFFECT 0.5
42 #define DISAPPROVAL_RATIO 0.2
45 #define NEUTRAL_RATIO 0.8
48 #define MAX_BUY_REDUCTION 0.1f
50 #define MAX_SELL_EXTRA 0.1f
59 #define LARGEST_COIN_GIVEN 2
62 static const char *const coins[] = {
79 uint64_t val = (uint64_t)
obj->value * number;
84 float ratio = atof(
key);
94 if (!identified &&
obj->arch) {
95 val =
obj->arch->clone.value * number;
113 if (
obj->arch != NULL && identified) {
114 int diff =
obj->magic -
obj->arch->clone.magic;
115 val *= pow(1.15, diff);
120 val *=
obj->stats.food / 50.0;
147 int lev_identify = 0;
161 LOG(
llevError,
"Query_cost: item %s hasn't got a valid type\n",
tmp->name);
163 val += val * (sin(
tmp->count) / sqrt(lev_identify * 3 + 1.0));
174 return tanh((charisma+15.0)/20);
199 const float adj_val = val * adj / E;
200 if (getenv(
"CF_DEBUG_SHOP")) {
201 LOG(
llevDebug,
"price_buy %s %lu*adj(%.2f)/E(%.2f) = %.2f\n",
202 tmp->arch->name, val, adj, E, adj_val);
204 if (std::isfinite(adj_val)) {
221 const uint64_t adj_val = val * adj * spec * E;
227 if (getenv(
"CF_DEBUG_SHOP")) {
228 LOG(
llevDebug,
"price_sell %s %lu*adj(%.2f)*s(%.2f)*E(%.2f) = %lu limited to %lu\n",
229 tmp->arch->name, val, adj, spec, E, adj_val, limval);
288 if (
cost == UINT64_MAX) {
316 if (next_coin == NULL)
434 LOG(
llevError,
"Query money called with non player/container\n");
442 && (
tmp->race == NULL || strstr(
tmp->race,
"gold"))) {
474 && (pouch->race == NULL || strstr(pouch->race,
"gold"))) {
479 LOG(
llevError,
"pay_for_amount: Cannot remove enough money -- %" FMT64U " remains\n", to_pay);
503 assert(to_pay >= reduction);
518 && (pouch->race == NULL || strstr(pouch->race,
"gold"))) {
523 LOG(
llevError,
"pay_for_item: Cannot remove enough money -- %" FMT64U " remains\n", to_pay);
549 if ((int64_t)coin_objs[i]->nrof * coin_objs[i]->
value > remain) {
550 num_coins = remain/coin_objs[i]->
value;
551 if ((uint64_t)num_coins*(uint64_t)coin_objs[i]->
value < (uint64_t) remain) {
555 num_coins = coin_objs[i]->
nrof;
557 remain -= (int64_t)num_coins*(int64_t)coin_objs[i]->
value;
558 coin_objs[i]->
nrof -= num_coins;
564 while (remain < 0 && count >= 0) {
591 coin_objs[i]->
nrof += nrof;
610 for (i = 0; i < objects_len; i++) {
639 object *other_money[16];
640 size_t other_money_len;
656 && (
tmp->value ==
tmp->arch->clone.value)) {
660 if (coin_objs[i] != NULL) {
663 coin_objs[i]->
nrof +=
tmp->nrof;
673 if (other_money_len >=
sizeof(other_money)/
sizeof(*other_money)) {
674 LOG(
llevError,
"pay_for_item: Cannot store non-standard money object %s\n",
tmp->arch->name);
677 other_money[other_money_len++] =
tmp;
686 if (coin_objs[i] == NULL) {
693 coin_objs[i]->
nrof = 0;
700 for (i = 0; i < other_money_len && remain > 0; i++) {
704 coin = other_money[i];
727 if (
a == UINT64_MAX) {
731 if (UINT64_MAX -
a <
b) {
785 *unpaid_price =
args.price;
802 if (!strcmp(
coins[i],
item->arch->name)) {
803 coincount[i] +=
item->nrof;
823 if (skill && skill->
level > 0) {
843 uint64_t unpaid_price = 0;
847 LOG(
llevError,
"can_pay(): called against something that isn't a player\n");
858 if (unpaid_price > player_wealth) {
860 int denominations = 0;
866 if (coincount[i] > 0 &&
coins[i]) {
867 if (denominations == 0)
868 snprintf(
buf+strlen(
buf),
sizeof(
buf)-strlen(
buf),
"but you only have");
873 snprintf(coinbuf,
sizeof(coinbuf),
" %u %s,", coincount[i],
arch->clone.name_pl);
874 snprintf(
buf+strlen(
buf),
sizeof(
buf)-strlen(
buf),
"%s", coinbuf);
878 if (denominations == 0)
879 snprintf(
buf+strlen(
buf),
sizeof(
buf)-strlen(
buf),
"but you don't have any money.");
880 else if (denominations > 1)
890 object *
pl = (
object *)
data;
902 "You lack %s to buy %s.",
919 char *reduction_str =
cost_str(reduction);
922 "You paid %s for %s after bargaining a reduction of %s.",
923 value, name_op, reduction_str);
929 "You paid %s for %s.",
974 LOG(
llevDebug,
"Object other than player tried to sell something.\n");
987 "We're not interested in %s.",
995 if (extra_gain > 0) {
997 char *extra_str =
cost_str(extra_gain);
999 "You receive %s for %s, after bargaining for %s more than proposed.", value_str, obj_name, extra_str);
1001 price += extra_gain;
1004 "You receive %s for %s.", value_str, obj_name);
1017 && strstr(pouch->race,
"gold")) {
1018 int w = at->
clone.
weight*(100-pouch->stats.Str)/100;
1024 && (!pouch->weight_limit || pouch->carrying+w <= pouch->weight_limit)) {
1025 if (pouch->weight_limit
1026 && (pouch->weight_limit-pouch->carrying)/w < n)
1027 n = (pouch->weight_limit-pouch->carrying)/w;
1032 price -= (uint64_t)
tmp->nrof*(uint64_t)
tmp->value;
1042 price -= (uint64_t)
tmp->nrof*(uint64_t)
tmp->value;
1078 LOG(
llevError,
"shop_specialisation_ratio: passed a NULL item for map %s\n",
map->path);
1081 if (
item->type == (uint8_t)-1) {
1082 LOG(
llevError,
"shop_specialisation_ratio: passed an item with an invalid type\n");
1090 if (
map->shopitems) {
1091 for (i = 0; i < items[0].
index; i++)
1092 if (items[i].typenum ==
item->type || (items[i].
typenum == -1 && likedness == 0.001))
1093 likedness = items[i].
strength/100.0;
1095 if (likedness > 1.0) {
1096 LOG(
llevDebug,
"shop_specialisation ratio: item type %d on map %s is above 100%%\n",
item->type,
map->path);
1099 if (likedness < -1.0) {
1100 LOG(
llevDebug,
"shop_specialisation ratio: item type %d on map %s is below -100%%\n",
item->type,
map->path);
1103 ratio = ratio+(1.0-ratio)*likedness;
1124 float greed =
map->shopgreed;
1128 return tanh(-greed+2.0)/2 + 0.5;
1132 double approval = 1.0;
1133 if (
map->shoprace) {
1161 uint64_t newval, unit_price;
1165 if (!isshop || !
who) {
1166 if (unit_price > 10000)
1167 newval = 8000+
isqrt(unit_price)*20;
1169 newval = unit_price;
1172 LOG(
llevError,
"value_limit: asked shop price for ob %s on NULL map\n",
who->name);
1176 if (
map->shopmin && unit_price < map->shopmin)
1178 else if (
map->shopmax && unit_price >
map->shopmax/2)
1180 else if (unit_price > 10000)
1181 newval = 8000+
isqrt(unit_price)*20;
1183 newval = unit_price;
1211 "From looking at the nearby shop you determine that it trades in:");
1213 if (
map->shopitems) {
1214 for (i = 0; i <
map->shopitems[0].index; i++) {
1215 if (
map->shopitems[i].name &&
map->shopitems[i].strength > 10) {
1216 snprintf(
tmp+pos,
sizeof(
tmp)-pos,
"%s, ",
map->shopitems[i].name_pl);
1217 pos += strlen(
tmp+pos);
1222 strcpy(
tmp,
"a little of everything.");
1233 "It won't trade for items above %s.",
1242 "It won't trade in items worth less than %s.",
1247 if (
map->shopgreed) {
1248 if (
map->shopgreed > 2.0)
1251 "It tends to overcharge massively.");
1252 else if (
map->shopgreed > 1.5)
1255 "It tends to overcharge substantially.");
1256 else if (
map->shopgreed > 1.1)
1259 "It tends to overcharge slightly.");
1260 else if (
map->shopgreed < 0.9)
1263 "It tends to undercharge.");
1265 if (
map->shoprace) {
1270 "You think the shopkeeper likes you.");
1271 else if (opinion > 0.5)
1274 "The shopkeeper seems unconcerned by you.");
1278 "The shopkeeper seems to have taken a dislike to you.");
1281 "There is no shop nearby.");
1297 if (!
ob->map)
return 0;
char * cost_approx_str(const object *tmp, object *who)
double shop_approval(const mapstruct *map, const object *player)
void sell_item(object *op, object *pl)
static float shop_cha_modifier(int charisma)
object * find_skill_by_number(object *who, int skillno)
void LOG(LogLevel logLevel, const char *format,...)
#define LARGEST_COIN_GIVEN
#define QUERY_FLAG(xyz, p)
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
static uint64_t compute_price_variation_with_bargaining(object *pl, uint64_t price, float max_variation)
static void unpaid_iter(object *item, void(*callback)(object *item, void *data), void *data)
object * object_merge(object *op, object *top)
char * cost_str(uint64_t cost)
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
static archetype * find_next_coin(uint64_t c, int *cointype)
static void add_value(object *coin_objs[], int64_t value)
static event_registration c
#define SPECIALISATION_EFFECT
StringBuffer * stringbuffer_new(void)
static bool coords_in_shop(mapstruct *map, int x, int y)
uint64_t price_approx(const object *tmp, object *who)
static void insert_objects(object *pl, object *container, object *objects[], int objects_len)
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
void object_copy(const object *src_ob, object *dest_ob)
void fix_object(object *op)
static void shop_pay_unpaid_callback(object *op, void *data)
#define MSG_TYPE_SHOP_PAYMENT
static const char *const coins[]
int rndm(int min, int max)
const char * object_get_value(const object *op, const char *const key)
#define MSG_TYPE_SHOP_MISC
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
object * object_insert_in_ob(object *op, object *where)
int pay_for_item(object *op, object *pl, uint64_t reduction)
static StringBuffer * real_money_value(const object *coin, StringBuffer *buf)
char * stringbuffer_finish(StringBuffer *sb)
void object_free_drop_inventory(object *ob)
static uint32_t NROF(const object *const ob)
const typedata * get_typedata(int itemtype)
uint64_t shop_price_sell(const object *tmp, object *who)
void query_name(const object *op, char *buf, size_t size)
int shop_pay_unpaid(object *pl, object *op)
uint64_t query_money(const object *op)
static double shop_specialisation_ratio(const object *item, const mapstruct *map)
#define FOR_OB_AND_BELOW_FINISH()
int is_identified(const object *op)
char * cost_string_from_value(uint64_t cost, int largest_coin)
#define MAX_BUY_REDUCTION
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
uint64_t add_with_overflow(uint64_t a, uint64_t b)
void stringbuffer_append_string(StringBuffer *sb, const char *str)
#define FOR_OB_AND_BELOW_PREPARE(op_)
int shop_describe(const object *op)
object * object_new(void)
static uint64_t value_limit(uint64_t val, int quantity, const object *who, int isshop)
static void count_coins(object *item, uint32_t *coincount)
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
uint64_t shop_price_buy(const object *tmp, object *who)
#define MSG_TYPE_SHOP_SELL
bool shop_contains(object *ob)
void stringbuffer_delete(StringBuffer *sb)
static int64_t remove_value(object *coin_objs[], int64_t remain)
uint64_t price_base(const object *obj)
archetype * find_archetype(const char *name)
void esrv_update_item(int flags, object *pl, object *op)
void make_list_like(char *input)
#define CLEAR_FLAG(xyz, p)
float shop_efficiency(const object *player)
#define MSG_TYPE_SHOP_LISTING
static double shop_greed(const mapstruct *map)
static void count_unpaid_callback(object *item, void *data)
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
void object_remove(object *op)
int object_set_value(object *op, const char *key, const char *value, int add_key)
int pay_for_amount(uint64_t to_pay, object *pl)
#define CUSTOM_NAME_FIELD
static void count_unpaid(object *pl, object *item, int *unpaid_count, uint64_t *unpaid_price)
#define FOR_INV_PREPARE(op_, it_)
static uint64_t pay_from_container(object *pl, object *pouch, uint64_t to_pay)
object * identify(object *op)