diff --git a/src/npctrade.cpp b/src/npctrade.cpp index bcad16ef1f068..8a09fedc036d0 100644 --- a/src/npctrade.cpp +++ b/src/npctrade.cpp @@ -1,43 +1,27 @@ #include "npctrade.h" #include -#include -#include +#include #include #include #include -#include #include -#include -#include #include #include "avatar.h" -#include "catacharset.h" -#include "color.h" -#include "cursesdef.h" +#include "character.h" #include "debug.h" -#include "enums.h" #include "faction.h" -#include "game_constants.h" -#include "input.h" #include "item.h" #include "item_category.h" // IWYU pragma: keep -#include "map_selector.h" +#include "item_location.h" +#include "item_pocket.h" #include "npc.h" -#include "output.h" -#include "point.h" +#include "ret_val.h" #include "skill.h" -#include "string_formatter.h" -#include "string_input_popup.h" #include "trade_ui.h" -#include "translations.h" #include "type_id.h" -#include "ui_manager.h" #include "units.h" -#include "units_utility.h" -#include "vehicle_selector.h" -#include "visitable.h" static const skill_id skill_speech( "speech" ); @@ -138,16 +122,6 @@ double npc_trading::net_price_adjustment( const Character &buyer, const Characte return ( std::max( adjust, 1.0 ) ); } -template -void buy_helper( T &src, Callback cb ) -{ - src.visit_items( [&src, &cb]( item * node, item * ) { - cb( std::move( item_location( src, node ) ), 1 ); - - return VisitResponse::SKIP; - } ); -} - int npc_trading::adjusted_price( Character const &buyer, Character const &seller, trade_selector::entry_t it ) { @@ -170,94 +144,6 @@ int npc_trading::adjusted_price( Character const &buyer, Character const &seller return price; } -std::vector npc_trading::init_buying( Character &buyer, Character &seller, - bool is_npc ) -{ - std::vector result; - npc *np_p = dynamic_cast( &buyer ); - if( is_npc ) { - np_p = dynamic_cast( &seller ); - } - npc &np = *np_p; - faction *fac = np.get_faction(); - - double adjust = net_price_adjustment( buyer, seller ); - - const auto check_item = [fac, adjust, is_npc, &np, &result, &seller]( item_location - loc, int count = 1 ) { - if( !loc ) { - return; - } - item &it = *loc; - - // Only solids allowed. All others should be transfered in a container. - if( !it.made_of( phase_id::SOLID ) ) { - return; - } - - // Don't sell items we don't own. - if( !it.is_owned_by( seller ) ) { - return; - } - - if( it.count() <= 0 ) { - debugmsg( "item %s has zero or negative charges", it.typeId().str() ); - return; - } - - // Hide contents of any containers that are not worn. - if( loc.has_parent() && !( loc.parent_item().where() == item_location::type::character ) ) { - return; - } - - // Worn containers have most contents visible so they show price for the container only, - // except hidden contents such as liquids. - const int market_price = loc.where() == item_location::type::character ? - it.price_no_contents( true ) : - it.price( true ); - int val = np.value( it, market_price ); - if( ( is_npc && np.wants_to_sell( it, val, market_price ) ) || - ( !is_npc && np.wants_to_buy( it, val, market_price ) ) ) { - result.emplace_back( std::move( loc ), val, count ); - result.back().adjust_values( adjust, fac ); - } - }; - - for( item_location loc : seller.all_items_loc() ) { - if( seller.is_wielding( *loc ) && loc->has_flag( json_flag_NO_UNWIELD ) ) { - continue; - } - check_item( loc, loc->count() ); - } - - //nearby items owned by the NPC will only show up in - //the trade window if the NPC is also a shopkeeper - if( np.mission == NPC_MISSION_SHOPKEEP ) { - for( map_cursor &cursor : map_selector( seller.pos(), PICKUP_RANGE ) ) { - buy_helper( cursor, check_item ); - } - } - - // Allow direct trade from vehicles, but *not* with allies, as that ends up - // with the same item on both sides of the trade panel, and so much clutter. - if( ! np.will_exchange_items_freely() ) { - for( vehicle_cursor &cursor : vehicle_selector( seller.pos(), 1 ) ) { - buy_helper( cursor, check_item ); - } - } - - const auto cmp = []( const item_pricing & a, const item_pricing & b ) { - // Sort items by category first, then name. - return localized_compare( - std::make_pair( a.loc->get_category_of_contents(), a.loc->display_name() ), - std::make_pair( b.loc->get_category_of_contents(), b.loc->display_name() ) ); - }; - - std::sort( result.begin(), result.end(), cmp ); - - return result; -} - void item_pricing::set_values( int ip_count ) { const item *i_p = loc.get_item(); @@ -278,490 +164,6 @@ void item_pricing::set_values( int ip_count ) } } -// Adjusts the pricing of an item, *unless* it is the currency of the -// faction we're trading with, as that should always be worth face value. -void item_pricing::adjust_values( const double adjust, const faction *fac ) -{ - if( !fac || fac->currency != loc.get_item()->typeId() ) { - price *= adjust; - } -} - -void trading_window::setup_win( ui_adaptor &ui ) -{ - const int win_they_w = TERMX / 2; - entries_per_page = std::min( TERMY - 7, 2 + ( 'z' - 'a' ) + ( 'Z' - 'A' ) ); - w_head = catacurses::newwin( 4, TERMX, point_zero ); - w_them = catacurses::newwin( TERMY - 4, win_they_w, point( 0, 4 ) ); - w_you = catacurses::newwin( TERMY - 4, TERMX - win_they_w, point( win_they_w, 4 ) ); - ui.position( point_zero, point( TERMX, TERMY ) ); -} - -// 'cost' is the cost of a service the NPC may be rendering, if any. -void trading_window::setup_trade( int cost, npc &np ) -{ - avatar &player_character = get_avatar(); - // Populate the list of what the NPC is willing to buy, and the prices they pay - // Note that the NPC's social skill is factored into these prices. - // TODO: Recalc item values every time a new item is selected - // Trading is not linear - starving NPC may pay $100 for 3 jerky, but not $100000 for 300 jerky - theirs = npc_trading::init_buying( player_character, np, true ); - yours = npc_trading::init_buying( np, player_character, false ); - - if( np.will_exchange_items_freely() ) { - your_balance = 0; - } else { - your_balance = np.op_of_u.owed - cost; - } -} - -void trading_window::update_win( npc &np, const std::string &deal ) -{ - // Draw borders, one of which is highlighted - werase( w_them ); - werase( w_you ); - - std::set without; - std::vector added; - - for( item_pricing &pricing : yours ) { - if( pricing.selected ) { - added.push_back( pricing.loc.get_item() ); - } - } - - for( item_pricing &pricing : theirs ) { - if( pricing.selected ) { - without.insert( pricing.loc.get_item() ); - } - } - - bool npc_out_of_space = volume_left < 0_ml || weight_left < 0_gram; - - // Colors for hinting if the trade will be accepted or not. - const nc_color trade_color = npc_will_accept_trade( np ) ? c_green : c_red; - - input_context ctxt( "NPC_TRADE" ); - const hotkey_queue &hotkeys = hotkey_queue::alphabets(); - - werase( w_head ); - fold_and_print( w_head, point_zero, getmaxx( w_head ), c_white, - _( "Trading with %s.\n" - "%s to switch lists, letters to pick items, " - "%s to finalize, %s to quit, " - "%s to get information on an item, " - "%s to mark selected items as favorite" ), - np.disp_name(), - ctxt.get_desc( "SWITCH_LISTS" ), - ctxt.get_desc( "CONFIRM" ), - ctxt.get_desc( "QUIT" ), - ctxt.get_desc( "EXAMINE" ), - ctxt.get_desc( "TOGGLE_FAVORITE" ) ); - - // Set up line drawings - for( int i = 0; i < TERMX; i++ ) { - mvwputch( w_head, point( i, 3 ), c_white, LINE_OXOX ); - } - // End of line drawings - - mvwprintz( w_head, point( 2, 3 ), npc_out_of_space ? c_red : c_green, - _( "Volume: %s %s, Weight: %.1f %s" ), - format_volume( volume_left ), volume_units_abbr(), - convert_weight( weight_left ), weight_units() ); - - std::string cost_str = _( "Exchange" ); - if( !np.will_exchange_items_freely() ) { - cost_str = string_format( your_balance >= 0 ? _( "Credit %s" ) : _( "Debt %s" ), - format_money( std::abs( your_balance ) ) ); - } - - mvwprintz( w_head, point( TERMX / 2 + ( TERMX / 2 - utf8_width( cost_str ) ) / 2, 3 ), - trade_color, cost_str ); - - if( !deal.empty() ) { - const nc_color trade_color_light = npc_will_accept_trade( np ) ? c_light_green : c_light_red; - mvwprintz( w_head, point( ( TERMX - utf8_width( deal ) ) / 2, 3 ), - trade_color_light, deal ); - } - draw_border( w_them, ( focus_them ? c_yellow : BORDER_COLOR ) ); - draw_border( w_you, ( !focus_them ? c_yellow : BORDER_COLOR ) ); - - mvwprintz( w_them, point( 2, 0 ), trade_color, np.get_name() ); - mvwprintz( w_you, point( 2, 0 ), trade_color, _( "You" ) ); - avatar &player_character = get_avatar(); - // Draw lists of items, starting from offset - for( size_t whose = 0; whose <= 1; whose++ ) { - const bool they = whose == 0; - const std::vector &list = they ? theirs : yours; - const size_t &offset = they ? them_off : you_off; - const Character &person = they ? *np.as_character() : *player_character.as_character(); - catacurses::window &w_whose = they ? w_them : w_you; - int win_w = getmaxx( w_whose ); - // Borders - win_w -= 2; - - input_event hotkey = ctxt.first_unassigned_hotkey( hotkeys ); - for( size_t i = offset; i < list.size() && i < entries_per_page + offset; i++ ) { - const item_pricing &ip = list[i]; - const item *it = ip.loc.get_item(); - nc_color color = it == &person.get_wielded_item() ? c_yellow : c_light_gray; - const int &owner_sells = they ? ip.u_has : ip.npc_has; - const int &owner_sells_charge = they ? ip.u_charges : ip.npc_charges; - std::string itname = it->display_name(); - - if( np.will_exchange_items_freely() && ip.loc.where() != item_location::type::character ) { - itname += " (" + ip.loc.describe( &player_character ) + ")"; - color = c_light_blue; - } - - if( ip.charges > 0 && owner_sells_charge > 0 ) { - itname += string_format( _( ": trading %d" ), owner_sells_charge ); - } else { - if( ip.count > 1 ) { - itname += string_format( _( " (%d)" ), ip.count ); - } - if( owner_sells ) { - itname += string_format( _( ": trading %d" ), owner_sells ); - } - } - - if( ip.selected ) { - color = c_white; - } - - trim_and_print( w_whose, point( 1, i - offset + 1 ), win_w, color, "%s %c %s", - right_justify( hotkey.short_description(), 2 ), - ip.selected ? '+' : '-', itname ); -#if defined(__ANDROID__) - ctxt.register_manual_key( hotkey.get_first_input(), itname ); -#endif - hotkey = ctxt.next_unassigned_hotkey( hotkeys, hotkey ); - - std::string price_str = format_money( ip.price ); - nc_color price_color = np.will_exchange_items_freely() - ? c_dark_gray - : ( ip.selected ? c_white : c_light_gray ); - mvwprintz( w_whose, point( win_w - utf8_width( price_str ), i - offset + 1 ), - price_color, price_str ); - } - if( offset > 0 ) { - mvwprintw( w_whose, point( 1, entries_per_page + 2 ), _( "< Back" ) ); - } - if( offset + entries_per_page < list.size() ) { - mvwprintw( w_whose, point( 9, entries_per_page + 2 ), _( "More >" ) ); - } - } - wnoutrefresh( w_head ); - wnoutrefresh( w_them ); - wnoutrefresh( w_you ); -} - -void trading_window::show_item_data( size_t offset, - std::vector &target_list ) -{ - catacurses::window w_tmp; - ui_adaptor ui; - ui.on_screen_resize( [&]( ui_adaptor & ui ) { - w_tmp = catacurses::newwin( 3, 21, - point( 30 + ( TERMX - FULL_SCREEN_WIDTH ) / 2, - 1 + ( TERMY - FULL_SCREEN_HEIGHT ) / 2 ) ); - ui.position_from_window( w_tmp ); - } ); - ui.mark_resize(); - - ui.on_redraw( [&]( const ui_adaptor & ) { - werase( w_tmp ); - // NOLINTNEXTLINE(cata-use-named-point-constants) - mvwprintz( w_tmp, point( 1, 1 ), c_red, _( "Examine which item?" ) ); - draw_border( w_tmp ); - wnoutrefresh( w_tmp ); - } ); - - input_context ctxt( "NPC_TRADE" ); - ctxt.register_action( "QUIT" ); - ctxt.register_action( "ANY_INPUT" ); - ctxt.register_action( "HELP_KEYBINDINGS" ); - - bool exit = false; - while( !exit ) { - ui_manager::redraw(); - const std::string action = ctxt.handle_input(); - if( action == "QUIT" ) { - exit = true; - } else if( action == "ANY_INPUT" ) { - const input_event evt = ctxt.get_raw_input(); - if( evt.sequence.empty() ) { - continue; - } - size_t help = 0; - const hotkey_queue &hotkeys = hotkey_queue::alphabets(); - input_event hotkey = ctxt.first_unassigned_hotkey( hotkeys ); - while( hotkey != input_event() && hotkey != evt ) { - hotkey = ctxt.next_unassigned_hotkey( hotkeys, hotkey ); - ++help; - } - - if( hotkey == input_event() ) { - continue; - } - - help += offset; - if( help < target_list.size() ) { - std::vector info; - const item &itm = *target_list[help].loc.get_item(); - itm.info( true, info ); - item_info_data data( itm.tname(), - itm.type_name(), - info, {} ); - data.handle_scrolling = true; - data.any_input = false; - draw_item_info( []() -> catacurses::window { - const int width = std::min( TERMX, FULL_SCREEN_WIDTH ); - const int height = std::min( TERMY, FULL_SCREEN_HEIGHT ); - return catacurses::newwin( height, width, point( ( TERMX - width ) / 2, ( TERMY - height ) / 2 ) ); - }, data ); - exit = true; - } - } - } -} - -int trading_window::get_var_trade( const item &it, int total_count ) -{ - string_input_popup popup_input; - int how_many = total_count; - - const std::string title = string_format( _( "Trade how many %s [MAX: %d]: " ), it.tname( how_many ), - total_count ); - popup_input.title( title ).edit( how_many ); - if( popup_input.canceled() || how_many <= 0 ) { - return -1; - } - return std::min( total_count, how_many ); -} - -void trading_window::item_selection( npc &np, std::vector &target_list, - item_pricing &ip, bool max ) -{ - int change_amount = 1; - int &owner_sells = focus_them ? ip.u_has : ip.npc_has; - int &owner_sells_charge = focus_them ? ip.u_charges : ip.npc_charges; - - if( ip.selected ) { - if( owner_sells_charge > 0 ) { - change_amount = owner_sells_charge; - owner_sells_charge = 0; - } else if( owner_sells > 0 ) { - change_amount = owner_sells; - owner_sells = 0; - // Deselect all contents when deselecting a container. - if( ip.is_container ) { - for( item *it : ip.loc.get_item()->get_contents().all_items_top() ) { - for( item_pricing &ipp : target_list ) { - if( it == ipp.loc.get_item() && ipp.selected ) { - item_selection( np, target_list, ipp ); - break; - } - } - } - } - } - } else if( ip.charges > 0 ) { - change_amount = max ? ip.charges : get_var_trade( *ip.loc.get_item(), ip.charges ); - - if( change_amount < 1 ) { - return; - } - owner_sells_charge = change_amount; - } else { - if( ip.count > 1 ) { - change_amount = max ? ip.count : get_var_trade( *ip.loc.get_item(), ip.count ); - - if( change_amount < 1 ) { - return; - } - } - owner_sells = change_amount; - // Select all contents when selecting a container. - if( ip.is_container ) { - for( item *it : ip.loc.get_item()->get_contents().all_items_top() ) { - for( item_pricing &ipp : target_list ) { - if( it == ipp.loc.get_item() && !ipp.selected ) { - item_selection( np, target_list, ipp, true ); - break; - } - } - } - } - } - ip.selected = !ip.selected; - if( ip.selected != focus_them ) { - change_amount *= -1; - } - 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_recursive() == item_location::type::character ) { - volume_left += ip.vol * change_amount; - weight_left += ip.weight * change_amount; - } -} - -bool trading_window::perform_trade( npc &np, const std::string &deal ) -{ - weight_left = np.weight_capacity() - np.weight_carried(); - - // Shopkeeps are happy to have large inventories. - if( np.mission == NPC_MISSION_SHOPKEEP ) { - volume_left = 5'000_liter; - weight_left = 5'000_kilogram; - } else { - volume_left = np.volume_capacity() - np.volume_carried(); - weight_left = np.weight_capacity() - np.weight_carried(); - } - - input_context ctxt( "NPC_TRADE" ); - ctxt.register_action( "SWITCH_LISTS" ); - ctxt.register_action( "PAGE_UP" ); - ctxt.register_action( "PAGE_DOWN" ); - ctxt.register_action( "EXAMINE" ); - ctxt.register_action( "CONFIRM" ); - ctxt.register_action( "QUIT" ); - ctxt.register_action( "HELP_KEYBINDINGS" ); - // action to mark item(s) as favorite for the npc so they never drop it - ctxt.register_action( "TOGGLE_FAVORITE" ); - ctxt.register_action( "ANY_INPUT" ); - - ui_adaptor ui; - ui.on_screen_resize( [this]( ui_adaptor & ui ) { - setup_win( ui ); - } ); - ui.mark_resize(); - - ui.on_redraw( [&]( const ui_adaptor & ) { - update_win( np, deal ); - } ); - - bool confirm = false; - bool exit = false; - while( !exit ) { - ui_manager::redraw(); - - std::vector &target_list = focus_them ? theirs : yours; - size_t &offset = focus_them ? them_off : you_off; - const std::string action = ctxt.handle_input(); - if( action == "SWITCH_LISTS" ) { - focus_them = !focus_them; - } else if( action == "PAGE_UP" ) { - if( offset > entries_per_page ) { - offset -= entries_per_page; - } else { - offset = 0; - } - } else if( action == "PAGE_DOWN" ) { - if( offset + entries_per_page < target_list.size() ) { - offset += entries_per_page; - } - } else if( action == "EXAMINE" ) { - show_item_data( offset, target_list ); - } else if( action == "CONFIRM" ) { - if( !npc_will_accept_trade( np ) ) { - if( np.max_credit_extended() == 0 ) { - popup( _( "You'll need to offer me more than that." ) ); - } else { - popup( - _( "Sorry, I'm only willing to extend you %s in credit." ), - format_money( np.max_credit_extended() ) - ); - } - } else if( volume_left < 0_ml || weight_left < 0_gram ) { - // Make sure NPC doesn't go over allowed volume - popup( _( "%s can't carry all that." ), np.get_name() ); - } else if( np.mission != NPC_MISSION_SHOPKEEP && !npc_can_fit_items( np ) ) { - popup( _( "%s doesn't have the appropriate pockets to accept that." ), np.get_name() ); - } else if( calc_npc_owes_you( np ) < your_balance ) { - // NPC is happy with the trade, but isn't willing to remember the whole debt. - const bool trade_ok = query_yn( - _( - "I'm never going to be able to pay you back for all that. The most I'm willing to owe you is %s.\n\nContinue with trade?" ), - format_money( np.max_willing_to_owe() ) - ); - - if( trade_ok ) { - exit = true; - confirm = true; - } - } else { - if( query_yn( _( "Looks like a deal! Accept this trade?" ) ) ) { - exit = true; - confirm = true; - } - } - } else if( action == "QUIT" ) { - exit = true; - confirm = false; - } else if( action == "TOGGLE_FAVORITE" ) { - // toggle the favorite status for each item that is selected currently - for( item_pricing &list_item : target_list ) { - if( list_item.selected ) { - item_location &item = list_item.loc; - item->set_favorite( !item->is_favorite ); - } - } - } else if( action == "ANY_INPUT" ) { - const input_event evt = ctxt.get_raw_input(); - if( evt.sequence.empty() ) { - continue; - } - size_t ch = 0; - const hotkey_queue &hotkeys = hotkey_queue::alphabets(); - input_event hotkey = ctxt.first_unassigned_hotkey( hotkeys ); - while( hotkey != input_event() && hotkey != evt ) { - hotkey = ctxt.next_unassigned_hotkey( hotkeys, hotkey ); - ++ch; - } - if( hotkey == input_event() ) { - continue; - } - - ch += offset; - if( ch < target_list.size() ) { - item_pricing &ipr = target_list[ch]; - item_selection( np, target_list, ipr ); - } - } - } - - return confirm; -} - -// Returns how much the NPC will owe you after this transaction. -// You must also check if they will accept the trade. -int trading_window::calc_npc_owes_you( const npc &np ) const -{ - // Friends don't hold debts against friends. - if( np.will_exchange_items_freely() ) { - return 0; - } - - // If they're going to owe you more than before, and it's more than they're willing - // to owe, then cap the amount owed at the present level or their willingness to owe - // (whichever is bigger). - // - // When could they owe you more than max_willing_to_owe? It could be from quest rewards, - // when they were less angry, or from when you were better friends. - if( your_balance > np.op_of_u.owed && your_balance > np.max_willing_to_owe() ) { - return std::max( np.op_of_u.owed, np.max_willing_to_owe() ); - } - - // Fair's fair. NPC will remember this debt (or credit they've extended) - return your_balance; -} - int npc_trading::calc_npc_owes_you( const npc &np, int your_balance ) { // Friends don't hold debts against friends. @@ -782,13 +184,6 @@ int npc_trading::calc_npc_owes_you( const npc &np, int your_balance ) // Fair's fair. NPC will remember this debt (or credit they've extended) return your_balance; } - -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; -} - void npc_trading::update_npc_owed( npc &np, int your_balance, int your_sale_value ) { np.op_of_u.owed = calc_npc_owes_you( np, your_balance ); @@ -854,50 +249,10 @@ bool npc_trading::trade( npc &np, int cost, const std::string &deal ) } // Will the NPC accept the trade that's currently on offer? -bool trading_window::npc_will_accept_trade( const npc &np ) const -{ - return np.will_exchange_items_freely() || your_balance + np.max_credit_extended() >= 0; -} - bool npc_trading::npc_will_accept_trade( npc const &np, int your_balance ) { return np.will_exchange_items_freely() || your_balance + np.max_credit_extended() >= 0; } - -bool trading_window::npc_can_fit_items( const npc &np ) const -{ - std::vector to_store; - std::vector avail_pockets; - for( const item_pricing &ip : yours ) { - if( ip.selected ) { - to_store.push_back( *ip.loc ); - } - } - for( const item &it : np.worn ) { - if( it.is_container() || it.is_holster() ) { - avail_pockets.push_back( it ); - } - } - if( avail_pockets.empty() ) { - return false; - } - for( item &i : to_store ) { - bool item_stored = false; - for( item &pkt : avail_pockets ) { - const units::volume pvol = pkt.max_containable_volume(); - if( pkt.can_holster( i ) || ( pkt.can_contain( i ).success() && pvol > i.volume() ) ) { - pkt.put_in( i, item_pocket::pocket_type::CONTAINER ); - item_stored = true; - break; - } - } - if( !item_stored ) { - return false; - } - } - return true; -} - bool npc_trading::npc_can_fit_items( npc const &np, trade_selector::select_t const &to_trade ) { std::vector avail_pockets; diff --git a/src/npctrade.h b/src/npctrade.h index 826e6ece73ae4..a44976a418784 100644 --- a/src/npctrade.h +++ b/src/npctrade.h @@ -2,24 +2,15 @@ #ifndef CATA_SRC_NPCTRADE_H #define CATA_SRC_NPCTRADE_H -#include -#include #include -#include -#include +#include -#include "cursesdef.h" -#include "inventory.h" -#include "item_location.h" #include "trade_ui.h" -#include "units.h" class Character; -class faction; class item; +class item_location; class npc; -class ui_adaptor; - class item_pricing { public: @@ -31,7 +22,6 @@ class item_pricing set_values( count ); } void set_values( int ip_count ); - void adjust_values( double adjust, const faction *fac ); item_location loc; int price = 0; @@ -47,47 +37,8 @@ class item_pricing units::mass weight = 0_gram; units::volume vol = 0_ml; }; - -class trading_window -{ - public: - trading_window() = default; - std::vector theirs; - std::vector yours; - int your_sale_value = 0; - int your_balance = 0; - - void setup_trade( int cost, npc &np ); - bool perform_trade( npc &np, const std::string &deal ); - void update_npc_owed( npc &np ); - - private: - void setup_win( ui_adaptor &ui ); - void update_win( npc &np, const std::string &deal ); - void show_item_data( size_t offset, std::vector &target_list ); - - catacurses::window w_head; - catacurses::window w_them; - catacurses::window w_you; - size_t entries_per_page = 0; - bool focus_them = true; // Is the focus on them? - size_t them_off = 0, you_off = 0; // Offset from the start of the list - - inventory temp; - units::volume volume_left; - units::mass weight_left; - - void item_selection( npc &np, std::vector &target_list, - item_pricing &ip, bool max = false ); - int get_var_trade( const item &it, int total_count ); - bool npc_will_accept_trade( const npc &np ) const; - bool npc_can_fit_items( const npc &np ) const; - int calc_npc_owes_you( const npc &np ) const; -}; - namespace npc_trading { - bool pay_npc( npc &np, int cost ); int adjusted_price( Character const &buyer, Character const &seller, trade_selector::entry_t it ); @@ -103,7 +54,6 @@ std::list transfer_items( trade_selector::select_t &stuff, Character &give double net_price_adjustment( const Character &buyer, const Character &seller ); bool trade( npc &p, int cost, const std::string &deal ); std::vector init_selling( npc &p ); -std::vector init_buying( Character &buyer, Character &seller, bool is_npc ); } // namespace npc_trading #endif // CATA_SRC_NPCTRADE_H