Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

npctrade: rework price adjustment formula #57706

Merged
merged 2 commits into from
May 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 7 additions & 27 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6352,31 +6352,7 @@ int item::price( bool practical ) const
int res = 0;

visit_items( [&res, practical]( const item * e, item * ) {
if( e->rotten() ) {
// TODO: Special case things that stay useful when rotten
return VisitResponse::NEXT;
}

int child = units::to_cent( practical ? e->type->price_post : e->type->price );
if( e->damage() > 0 ) {
// maximal damage level is 4, maximal reduction is 40% of the value.
child -= child * static_cast<double>( e->damage_level() ) / 10;
}

if( e->count_by_charges() || e->made_of( phase_id::LIQUID ) ) {
// price from json data is for default-sized stack
child *= e->charges / static_cast<double>( e->type->stack_size );

} else if( e->magazine_integral() && e->ammo_remaining() && e->ammo_data() ) {
// items with integral magazines may contain ammunition which can affect the price
child += item( e->ammo_data(), calendar::turn, e->ammo_remaining() ).price( practical );

} else if( e->is_tool() && e->type->tool->max_charges != 0 ) {
// if tool has no ammo (e.g. spray can) reduce price proportional to remaining charges
child *= e->ammo_remaining() / static_cast<double>( std::max( e->type->charges_default(), 1 ) );
}

res += child;
res += e->price_no_contents( practical );
return VisitResponse::NEXT;
} );

Expand All @@ -6390,8 +6366,12 @@ int item::price_no_contents( bool practical ) const
}
int price = units::to_cent( practical ? type->price_post : type->price );
if( damage() > 0 ) {
// maximal damage level is 4, maximal reduction is 40% of the value.
price -= price * static_cast< double >( damage_level() ) / 10;
// maximal damage level is 4, maximal reduction is 80% of the value.
price -= price * static_cast< double >( damage_level() ) / 5;
}

if( is_filthy() ) {
price *= 0.8;
}

if( count_by_charges() || made_of( phase_id::LIQUID ) ) {
Expand Down
7 changes: 5 additions & 2 deletions src/npc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#include "mtype.h"
#include "mutation.h"
#include "npc_class.h"
#include "npctrade.h"
#include "npctrade_utils.h"
#include "npctalk.h"
#include "options.h"
Expand Down Expand Up @@ -148,6 +149,7 @@ static const trait_id trait_MUTE( "MUTE" );
static const trait_id trait_PROF_DICEMASTER( "PROF_DICEMASTER" );
static const trait_id trait_PSYCHOPATH( "PSYCHOPATH" );
static const trait_id trait_SAPIOVORE( "SAPIOVORE" );
static const trait_id trait_SQUEAMISH( "SQUEAMISH" );
static const trait_id trait_TERRIFYING( "TERRIFYING" );

class monfaction;
Expand Down Expand Up @@ -1952,12 +1954,13 @@ bool npc::wants_to_buy( const item &it, int at_price, int /*market_price*/ ) con
return true;
}

if( it.has_flag( flag_TRADER_AVOID ) ) {
if( it.has_flag( flag_TRADER_AVOID ) or it.has_var( VAR_TRADE_IGNORE ) or
( my_fac == nullptr and has_trait( trait_SQUEAMISH ) and it.is_filthy() ) ) {
return false;
}

// TODO: Base on inventory
return at_price > 0;
return at_price >= 0;
}

// Will the NPC freely exchange items with the player?
Expand Down
7 changes: 3 additions & 4 deletions src/npctrade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ double npc_trading::net_price_adjustment( const Character &buyer, const Characte
double adjust = 0.05 * ( seller.int_cur - buyer.int_cur ) +
price_adjustment( seller.get_skill_level( skill_speech ) -
buyer.get_skill_level( skill_speech ) );
return std::max( adjust, 1.0 );
return seller.is_npc() ? adjust : -1 / adjust;
}

int npc_trading::bionic_install_price( Character &installer, Character &patient,
Expand All @@ -166,8 +166,7 @@ int npc_trading::adjusted_price( item const *it, int amount, Character const &bu

int price = it->price_no_contents( true );
if( it->count_by_charges() and amount >= 0 ) {
price /= it->charges;
price *= amount;
price *= static_cast<double>( amount ) / it->charges;
}
if( buyer.is_npc() ) {
price = buyer.as_npc()->value( *it, price );
Expand All @@ -176,7 +175,7 @@ int npc_trading::adjusted_price( item const *it, int amount, Character const &bu
}

if( fac == nullptr || fac->currency != it->typeId() ) {
return static_cast<int>( price * adjust );
return static_cast<int>( price * ( 1 + 0.25 * adjust ) );
}

return price;
Expand Down
22 changes: 3 additions & 19 deletions src/skill.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,23 +585,7 @@ bool SkillLevelMap::has_same_levels_as( const SkillLevelMap &other ) const
// Caps at 200% when you are 5 levels ahead, int comparison is handled in npctalk.cpp
double price_adjustment( int barter_skill )
{
if( barter_skill <= 0 ) {
return 1.0;
}
if( barter_skill >= 5 ) {
return 2.0;
}
switch( barter_skill ) {
case 1:
return 1.05;
case 2:
return 1.15;
case 3:
return 1.30;
case 4:
return 1.65;
default:
// Should never occur
return 1.0;
}
int const skill = std::min( 5, std::abs( barter_skill ) );
double const val = 0.045 * std::pow( skill, 2 ) - 0.025 * skill + 1;
return barter_skill >= 0 ? val : 1 / val;
}