Skip to content

Commit

Permalink
NPCs keep track of sales value (#51388)
Browse files Browse the repository at this point in the history
Add `sold` to NPC `op_of_u`
Add dialog support for reading/writing this value through `"u_val":
"sold"`
  • Loading branch information
eltank authored Sep 5, 2021
1 parent 0138041 commit aae81f0
Show file tree
Hide file tree
Showing 13 changed files with 81 additions and 34 deletions.
1 change: 1 addition & 0 deletions doc/NPCs.md
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,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 @@ -1026,6 +1026,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 @@ -2592,11 +2592,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 @@ -2507,12 +2507,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 @@ -2923,20 +2931,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 @@ -1676,6 +1676,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 @@ -1686,6 +1687,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 @@ -377,8 +382,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

0 comments on commit aae81f0

Please sign in to comment.