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

NPCs keep track of total sales #51388

Merged
merged 1 commit into from
Sep 5, 2021
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
1 change: 1 addition & 0 deletions doc/NPCs.md
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,7 @@ Example | Description
`"u_val": "allies"` | Number of allies the character has. Only supported for the player character. Can be read but not written to.
`"u_val": "cash"` | Ammount of money the character has. Only supported for the player character. Can be read but not written to.
`"u_val": "owed"` | Owed money to the NPC you're talking to.
`"u_val": "sold"` | Amount sold to the NPC you're talking to.
`"u_val": "skill_level"` | Level in given skill. `"skill"` must also be specified.
`"u_val": "pos_x"` | Player character x coordinate. "pos_y" and "pos_z" also works as expected.
`"u_val": "pain"` | Pain level.
Expand Down
8 changes: 8 additions & 0 deletions src/condition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,14 @@ std::function<int( const T & )> conditional_t<T>::get_get_int( const JsonObject
return d.actor( true )->debt();
};
}
} else if( checked_value == "sold" ) {
if( is_npc ) {
jo.throw_error( "owed ammount not supported for NPCs. In " + jo.str() );
} else {
return []( const T & d ) {
return d.actor( true )->sold();
};
}
} else if( checked_value == "skill_level" ) {
const skill_id skill( jo.get_string( "skill" ) );
return [is_npc, skill]( const T & d ) {
Expand Down
16 changes: 12 additions & 4 deletions src/debug_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1169,19 +1169,21 @@ void character_edit_menu()
data << string_format( _( "Trust: %d" ), np->op_of_u.trust ) << " "
<< string_format( _( "Fear: %d" ), np->op_of_u.fear ) << " "
<< string_format( _( "Value: %d" ), np->op_of_u.value ) << " "
<< string_format( _( "Anger: %d" ), np->op_of_u.anger ) << " "
<< string_format( _( "Owed: %d" ), np->op_of_u.owed ) << std::endl;
<< string_format( _( "Anger: %d" ), np->op_of_u.anger ) << std::endl;
data << string_format( _( "Owed: %d" ), np->op_of_u.owed ) << " "
<< string_format( _( "Sold: %d" ), np->op_of_u.sold ) << std::endl;

data << string_format( _( "Aggression: %d" ),
static_cast<int>( np->personality.aggression ) ) << " "
<< string_format( _( "Bravery: %d" ), static_cast<int>( np->personality.bravery ) ) << " "
<< string_format( _( "Collector: %d" ), static_cast<int>( np->personality.collector ) ) << " "
<< string_format( _( "Altruism: %d" ), static_cast<int>( np->personality.altruism ) ) << std::endl;

data << _( "Needs:" ) << std::endl;
data << _( "Needs:" );
for( const auto &need : np->needs ) {
data << need << std::endl;
data << " " << npc::get_need_str_id( need );
}
data << std::endl;
data << string_format( _( "Total morale: %d" ), np->get_morale_level() ) << std::endl;

nmenu.text = data.str();
Expand Down Expand Up @@ -1397,6 +1399,7 @@ void character_edit_menu()
smenu.addentry( 2, true, 't', "%s: %d", _( "value" ), np->op_of_u.value );
smenu.addentry( 3, true, 'f', "%s: %d", _( "anger" ), np->op_of_u.anger );
smenu.addentry( 4, true, 'd', "%s: %d", _( "owed" ), np->op_of_u.owed );
smenu.addentry( 5, true, 'd', "%s: %d", _( "sold" ), np->op_of_u.sold );

smenu.query();
int value;
Expand Down Expand Up @@ -1429,6 +1432,11 @@ void character_edit_menu()
np->op_of_u.owed = value;
}
break;
case 5:
if( query_int( value, _( "Set sold to? Currently: %d" ), np->op_of_u.sold ) ) {
np->op_of_u.sold = value;
}
break;
}
}
break;
Expand Down
6 changes: 1 addition & 5 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2521,11 +2521,7 @@ void game::reset_npc_dispositions()
npc_to_add->chatbin.clear_all();
npc_to_add->mission = NPC_MISSION_NULL;
npc_to_add->set_attitude( NPCATT_NULL );
npc_to_add->op_of_u.anger = 0;
npc_to_add->op_of_u.fear = 0;
npc_to_add->op_of_u.trust = 0;
npc_to_add->op_of_u.value = 0;
npc_to_add->op_of_u.owed = 0;
npc_to_add->op_of_u = npc_opinion();
npc_to_add->set_fac( faction_id( "no_faction" ) );
npc_to_add->add_new_mission( mission::reserve_random( ORIGIN_ANY_NPC,
npc_to_add->global_omt_location(),
Expand Down
7 changes: 3 additions & 4 deletions src/npc.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,17 +255,15 @@ struct npc_opinion {
int value;
int anger;
int owed; // Positive when the npc owes the player. Negative if player owes them.
int sold; // Total value of goods sold/donated by player to the npc. Cannot be negative.

npc_opinion() {
trust = 0;
fear = 0;
value = 0;
anger = 0;
owed = 0;
}

npc_opinion( int T, int F, int V, int A, int O ) :
trust( T ), fear( F ), value( V ), anger( A ), owed( O ) {
sold = 0;
}

npc_opinion &operator+=( const npc_opinion &rhs ) {
Expand All @@ -274,6 +272,7 @@ struct npc_opinion {
value += rhs.value;
anger += rhs.anger;
owed += rhs.owed;
sold += rhs.sold;
return *this;
}

Expand Down
28 changes: 18 additions & 10 deletions src/npctalk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2530,12 +2530,20 @@ std::function<void( const dialogue &, int )> talk_effect_fun_t::get_set_int( con
jo.throw_error( "altering cash this way is currently not supported. In " + jo.str() );
} else if( checked_value == "owed" ) {
if( is_npc ) {
jo.throw_error( "owed ammount not supported for NPCs. In " + jo.str() );
jo.throw_error( "owed amount not supported for NPCs. In " + jo.str() );
} else {
return []( const dialogue & d, int input ) {
d.actor( true )->add_debt( input - d.actor( true )->debt() );
};
}
} else if( checked_value == "sold" ) {
if( is_npc ) {
jo.throw_error( "sold amount not supported for NPCs. In " + jo.str() );
} else {
return []( const dialogue & d, int input ) {
d.actor( true )->add_sold( input - d.actor( true )->sold() );
};
}
} else if( checked_value == "skill_level" ) {
const skill_id skill( jo.get_string( "skill" ) );
return [is_npc, skill]( const dialogue & d, int input ) {
Expand Down Expand Up @@ -2939,20 +2947,20 @@ talk_topic talk_effect_t::apply( dialogue &d ) const
{
if( d.has_beta ) {
// Need to get a reference to the mission before effects are applied, because effects can remove the mission
mission *miss = d.actor( true )->selected_mission();
const mission *miss = d.actor( true )->selected_mission();
for( const talk_effect_fun_t &effect : effects ) {
effect( d );
}
d.actor( true )->add_opinion( opinion.trust, opinion.fear, opinion.value, opinion.anger,
opinion.owed );
d.actor( true )->add_opinion( opinion );
if( miss && ( mission_opinion.trust || mission_opinion.fear ||
mission_opinion.value || mission_opinion.anger ) ) {
int m_value = d.actor( true )->cash_to_favor( miss->get_value() );
d.actor( true )->add_opinion( mission_opinion.trust ? m_value / mission_opinion.trust : 0,
mission_opinion.fear ? m_value / mission_opinion.fear : 0,
mission_opinion.value ? m_value / mission_opinion.value : 0,
mission_opinion.anger ? m_value / mission_opinion.anger : 0,
0 );
const int m_value = d.actor( true )->cash_to_favor( miss->get_value() );
npc_opinion op;
op.trust = mission_opinion.trust ? m_value / mission_opinion.trust : 0;
op.fear = mission_opinion.fear ? m_value / mission_opinion.fear : 0;
op.value = mission_opinion.value ? m_value / mission_opinion.value : 0;
op.anger = mission_opinion.anger ? m_value / mission_opinion.anger : 0;
d.actor( true )->add_opinion( op );
}
if( d.actor( true )->turned_hostile() ) {
d.actor( true )->make_angry();
Expand Down
13 changes: 9 additions & 4 deletions src/npctalk_funcs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,10 @@ void talk_function::mission_success( npc &p )
}

int miss_val = npc_trading::cash_to_favor( p, miss->get_value() );
npc_opinion tmp( 0, 0, 1 + miss_val / 5, -1, 0 );
p.op_of_u += tmp;
npc_opinion op;
op.value = 1 + miss_val / 5;
op.anger = -1;
p.op_of_u += op;
faction *p_fac = p.get_faction();
if( p_fac != nullptr ) {
int fac_val = std::min( 1 + miss_val / 10, 10 );
Expand All @@ -142,8 +144,11 @@ void talk_function::mission_failure( npc &p )
debugmsg( "mission_failure: mission_selected == nullptr" );
return;
}
npc_opinion tmp( -1, 0, -1, 1, 0 );
p.op_of_u += tmp;
npc_opinion op;
op.trust = -1;
op.value = -1;
op.anger = 1;
p.op_of_u += op;
miss->fail();
}

Expand Down
4 changes: 4 additions & 0 deletions src/npctrade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,9 @@ bool trading_window::perform_trade( npc &np, const std::string &deal )
int delta_price = ip.price * change_amount;
if( !np.will_exchange_items_freely() ) {
your_balance -= delta_price;
if( ip.selected != focus_them ) {
your_sale_value -= delta_price;
}
}
if( ip.loc.where() == item_location::type::character ) {
volume_left += ip.vol * change_amount;
Expand Down Expand Up @@ -702,6 +705,7 @@ int trading_window::calc_npc_owes_you( const npc &np ) const
void trading_window::update_npc_owed( npc &np )
{
np.op_of_u.owed = calc_npc_owes_you( np );
np.op_of_u.sold += your_sale_value;
}

// Oh my aching head
Expand Down
1 change: 1 addition & 0 deletions src/npctrade.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class trading_window
trading_window() = default;
std::vector<item_pricing> theirs;
std::vector<item_pricing> yours;
int your_sale_value = 0;
int your_balance = 0;

void setup_trade( int cost, npc &np );
Expand Down
2 changes: 2 additions & 0 deletions src/savegame_json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1672,6 +1672,7 @@ void npc_opinion::deserialize( JsonIn &jsin )
data.read( "value", value );
data.read( "anger", anger );
data.read( "owed", owed );
data.read( "sold", sold );
}

void npc_opinion::serialize( JsonOut &json ) const
Expand All @@ -1682,6 +1683,7 @@ void npc_opinion::serialize( JsonOut &json ) const
json.member( "value", value );
json.member( "anger", anger );
json.member( "owed", owed );
json.member( "sold", sold );
json.end_object();
}

Expand Down
8 changes: 6 additions & 2 deletions src/talker.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class item_location;
class mission;
class monster;
class npc;
struct npc_opinion;
class Character;
class recipe;
struct tripoint;
Expand Down Expand Up @@ -252,6 +253,10 @@ class talker
return 0;
}
virtual void add_debt( int ) {}
virtual int sold() const {
return 0;
}
virtual void add_sold( int ) {}
virtual std::vector<item *> items_with( const std::function<bool( const item & )> & ) const {
return {};
}
Expand Down Expand Up @@ -373,8 +378,7 @@ class talker
virtual std::string opinion_text() const {
return "";
}
virtual void add_opinion( int /*trust*/, int /*fear*/, int /*value*/, int /*anger*/,
int /*debt*/ ) {}
virtual void add_opinion( const npc_opinion & ) {}
virtual void set_first_topic( const std::string & ) {}
virtual bool is_safe() const {
return true;
Expand Down
15 changes: 12 additions & 3 deletions src/talker_npc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,16 @@ void talker_npc::add_debt( const int cost )
me_npc->op_of_u.owed += cost;
}

int talker_npc::sold() const
{
return me_npc->op_of_u.sold;
}

void talker_npc::add_sold( const int value )
{
me_npc->op_of_u.sold += value;
}

int talker_npc::cash_to_favor( const int value ) const
{
return npc_trading::cash_to_favor( *me_npc, value );
Expand Down Expand Up @@ -879,10 +889,9 @@ std::string talker_npc::opinion_text() const
return me_npc->opinion_text();
}

void talker_npc::add_opinion( const int trust, const int fear, const int value,
const int anger, const int debt )
void talker_npc::add_opinion( const npc_opinion &op )
{
me_npc->op_of_u += npc_opinion( trust, fear, value, anger, debt );
me_npc->op_of_u += op;
}

bool talker_npc::enslave_mind()
Expand Down
6 changes: 4 additions & 2 deletions src/talker_npc.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ class talker_npc : public talker_character
const spell_id &c_spell, const proficiency_id &c_proficiency ) override;

// inventory, buying, and selling
void add_debt( int cost ) override;
int debt() const override;
void add_debt( int cost ) override;
int sold() const override;
void add_sold( int value ) override;
int cash_to_favor( int value ) const override;
std::string give_item_to( bool to_use ) override;
bool buy_from( int amount ) override;
Expand Down Expand Up @@ -100,7 +102,7 @@ class talker_npc : public talker_character

// miscellaneous
std::string opinion_text() const override;
void add_opinion( int trust, int fear, int value, int anger, int debt ) override;
void add_opinion( const npc_opinion &op ) override;
bool enslave_mind() override;
void set_first_topic( const std::string &chat_topic ) override;
bool is_safe() const override;
Expand Down