@@ -2556,6 +2556,7 @@ input_context get_default_mode_input_context()
25562556 ctxt.register_action ( " loot" );
25572557 ctxt.register_action ( " examine" );
25582558 ctxt.register_action ( " examine_and_pickup" );
2559+ ctxt.register_action ( " interact" , to_translation ( " Interact with tile" ) );
25592560 ctxt.register_action ( " advinv" );
25602561 ctxt.register_action ( " pickup" );
25612562 ctxt.register_action ( " pickup_all" );
@@ -5040,39 +5041,50 @@ void game::moving_vehicle_dismount( const tripoint_bub_ms &dest_loc )
50405041 }
50415042}
50425043
5043- void game::control_vehicle ()
5044+ void game::control_vehicle ( const std::optional<tripoint_bub_ms> &p )
50445045{
50455046 map &here = get_map ();
50465047
5047- if ( vehicle *remote_veh = remoteveh () ) { // remote controls have priority
5048- for ( const vpart_reference &vpr : remote_veh->get_avail_parts ( " REMOTE_CONTROLS" ) ) {
5049- remote_veh->interact_with ( &here, vpr.pos_bub ( here ) );
5050- return ;
5048+ if ( !p && !here.veh_at ( u.pos_bub () ) ) {
5049+ if ( vehicle *remote_veh = remoteveh () ) { // remote controls have priority
5050+ for ( const vpart_reference &vpr : remote_veh->get_avail_parts ( " REMOTE_CONTROLS" ) ) {
5051+ remote_veh->interact_with ( &here, vpr.pos_bub ( here ) );
5052+ return ;
5053+ }
50515054 }
50525055 }
5056+
50535057 vehicle *veh = nullptr ;
50545058 bool controls_ok = false ;
50555059 bool reins_ok = false ;
5056- if ( const optional_vpart_position vp = here.veh_at ( u.pos_bub () ) ) {
5060+ const tripoint_bub_ms player_pos = u.pos_bub ();
5061+ const tripoint_bub_ms target_pos = p.value_or ( player_pos );
5062+
5063+ if ( const optional_vpart_position vp = here.veh_at ( target_pos ) ) {
50575064 veh = &vp->vehicle ();
50585065 const int controls_idx = veh->avail_part_with_feature ( vp->mount_pos (), " CONTROLS" );
50595066 const int reins_idx = veh->avail_part_with_feature ( vp->mount_pos (), " CONTROL_ANIMAL" );
50605067 controls_ok = controls_idx >= 0 ; // controls available to "drive"
50615068 reins_ok = reins_idx >= 0 // reins + animal available to "drive"
50625069 && veh->has_engine_type ( fuel_type_animal, false )
50635070 && veh->get_harnessed_animal ( here );
5064- if ( veh->player_in_control ( here, u ) ) {
5065- // player already "driving" - offer ways to leave
5066- if ( controls_ok ) {
5067- veh->interact_with ( &here, u.pos_bub () );
5068- } else if ( reins_idx >= 0 ) {
5069- u.controlling_vehicle = false ;
5070- add_msg ( m_info, _ ( " You let go of the reins." ) );
5071- }
5072- } else if ( u.in_vehicle && ( controls_ok || reins_ok ) ) {
5073- // player not driving but has controls or reins on tile
5071+
5072+ if ( target_pos == player_pos ) {
5073+ if ( veh->player_in_control ( here, u ) ) {
5074+ // player already "driving" - offer ways to leave
5075+ if ( controls_ok ) {
5076+ veh->interact_with ( &here, u.pos_bub () );
5077+ } else if ( reins_idx >= 0 ) {
5078+ u.controlling_vehicle = false ;
5079+ add_msg ( m_info, _ ( " You let go of the reins." ) );
5080+ }
5081+ return ;
5082+ }
5083+ }
5084+
5085+ if ( controls_ok || reins_ok ) {
50745086 if ( veh->is_locked ) {
5075- veh->interact_with ( &here, u. pos_bub () );
5087+ veh->interact_with ( &here, target_pos );
50765088 return ; // interact_with offers to hotwire
50775089 }
50785090 if ( !veh->handle_potential_theft ( u ) ) {
@@ -5112,13 +5124,27 @@ void game::control_vehicle()
51125124 } else {
51135125 veh->start_engines ( here, &u, true );
51145126 }
5127+ // Success!
5128+ if ( u.controlling_vehicle ) {
5129+ for ( const tripoint_abs_ms &target : veh->get_points () ) {
5130+ u.memorize_clear_decoration ( target, " vp_" );
5131+ here.memory_cache_dec_set_dirty ( here.get_bub ( target ), true );
5132+ }
5133+ veh->is_following = false ;
5134+ veh->is_patrolling = false ;
5135+ veh->autopilot_on = false ;
5136+ veh->is_autodriving = false ;
5137+ }
5138+ return ;
51155139 }
51165140 }
5117- if ( !controls_ok && !reins_ok ) { // no controls or reins under player position, search nearby
5141+
5142+ if ( !p ) {
5143+ // Fallback search nearby if no target point provided and no controls at player position
51185144 int num_valid_controls = 0 ;
51195145 std::optional<tripoint_bub_ms> vehicle_position;
51205146 std::optional<vpart_reference> vehicle_controls;
5121- for ( const tripoint_bub_ms &elem : here.points_in_radius ( get_player_character () .pos_bub (), 1 ) ) {
5147+ for ( const tripoint_bub_ms &elem : here.points_in_radius ( u .pos_bub (), 1 ) ) {
51225148 if ( const optional_vpart_position vp = here.veh_at ( elem ) ) {
51235149 const std::optional<vpart_reference> controls = vp.value ().part_with_feature ( " CONTROLS" , true );
51245150 if ( controls ) {
@@ -5149,18 +5175,18 @@ void game::control_vehicle()
51495175 return ;
51505176 }
51515177 }
5152- // If we hit neither of those, there's only one set of vehicle controls, which should already have been found.
51535178 if ( vehicle_controls ) {
51545179 veh = &vehicle_controls->vehicle ();
51555180 if ( !veh->handle_potential_theft ( u ) ) {
51565181 return ;
51575182 }
51585183 veh->interact_with ( &here, *vehicle_position );
51595184 }
5185+ } else {
5186+ add_msg ( _ ( " No vehicle controls found there." ) );
51605187 }
5161- if ( u.controlling_vehicle ) {
5162- // If we reached here, we gained control of a vehicle.
5163- // Clear the map memory for the area covered by the vehicle to eliminate ghost vehicles.
5188+
5189+ if ( u.controlling_vehicle && veh ) {
51645190 for ( const tripoint_abs_ms &target : veh->get_points () ) {
51655191 u.memorize_clear_decoration ( target, " vp_" );
51665192 here.memory_cache_dec_set_dirty ( here.get_bub ( target ), true );
@@ -7605,9 +7631,13 @@ void game::insert_item()
76057631 game_menus::inv::insert_items ( item_loc );
76067632}
76077633
7608- void game::unload_container ()
7634+ void game::unload_container ( const std::optional<tripoint_bub_ms> &p )
76097635{
7610- if ( const std::optional<tripoint_bub_ms> pnt = choose_adjacent ( _ ( " Unload where?" ) ) ) {
7636+ std::optional<tripoint_bub_ms> pnt = p;
7637+ if ( !pnt ) {
7638+ pnt = choose_adjacent ( _ ( " Unload where?" ) );
7639+ }
7640+ if ( pnt ) {
76117641 u.drop ( game_menus::inv::unload_container (), *pnt );
76127642 }
76137643}
@@ -7723,7 +7753,7 @@ static void add_disassemblables( uilist &menu,
77237753 }
77247754}
77257755
7726- void game::butcher ()
7756+ void game::butcher ( const std::optional<tripoint_bub_ms> &p )
77277757{
77287758 map &here = get_map ();
77297759
@@ -7733,14 +7763,16 @@ void game::butcher()
77337763 return ;
77347764 }
77357765
7766+ const tripoint_bub_ms pos = p.value_or ( u.pos_bub () );
7767+
77367768 const int factor = u.max_quality ( qual_BUTCHER, PICKUP_RANGE );
77377769 const int factorD = u.max_quality ( qual_CUT_FINE, PICKUP_RANGE );
77387770 const std::string no_knife_msg = _ ( " You don't have a butchering tool." );
77397771 const std::string no_corpse_msg = _ ( " There are no corpses here to butcher." );
77407772
77417773 // You can't butcher on sealed terrain- you have to smash/shovel/etc it open first
7742- if ( here.has_flag ( ter_furn_flag::TFLAG_SEALED, u. pos_bub () ) ) {
7743- if ( here.sees_some_items ( u. pos_bub () , u ) ) {
7774+ if ( here.has_flag ( ter_furn_flag::TFLAG_SEALED, pos ) ) {
7775+ if ( here.sees_some_items ( pos , u ) ) {
77447776 add_msg ( m_info, _ ( " You can't access the items here." ) );
77457777 } else if ( factor > INT_MIN || factorD > INT_MIN ) {
77467778 add_msg ( m_info, no_corpse_msg );
@@ -7755,7 +7787,7 @@ void game::butcher()
77557787 std::vector<map_stack::iterator> corpses;
77567788 std::vector<map_stack::iterator> disassembles;
77577789 std::vector<map_stack::iterator> salvageables;
7758- map_stack items = here.i_at ( u. pos_bub () );
7790+ map_stack items = here.i_at ( pos );
77597791 const inventory &crafting_inv = u.crafting_inventory ();
77607792
77617793 // TODO: Properly handle different material whitelists
@@ -7962,7 +7994,7 @@ void game::butcher()
79627994 if ( bt.has_value () ) {
79637995 std::vector<butchery_data> bd;
79647996 for ( map_stack::iterator &it : corpses ) {
7965- item_location corpse_loc = item_location ( map_cursor ( u. pos_abs () ), &*it );
7997+ item_location corpse_loc = item_location ( map_cursor ( pos ), &*it );
79667998 bd.emplace_back ( corpse_loc, bt.value () );
79677999 }
79688000 u.assign_activity ( butchery_activity_actor ( bd ) );
@@ -7983,7 +8015,7 @@ void game::butcher()
79838015 case BUTCHER_CORPSE: {
79848016 const std::optional<butcher_type> bt = butcher_submenu ( corpses, indexer_index );
79858017 if ( bt.has_value () ) {
7986- item_location corpse_loc = item_location ( map_cursor ( u. pos_abs () ), &*corpses[indexer_index] );
8018+ item_location corpse_loc = item_location ( map_cursor ( pos ), &*corpses[indexer_index] );
79878019 butchery_data bd ( corpse_loc, bt.value () );
79888020 u.assign_activity ( butchery_activity_actor ( bd ) );
79898021 }
@@ -7992,7 +8024,7 @@ void game::butcher()
79928024 case BUTCHER_DISASSEMBLE: {
79938025 // Pick index of first item in the disassembly stack
79948026 item *const target = &*disassembly_stacks[indexer_index].first ;
7995- u.disassemble ( item_location ( map_cursor ( u. pos_abs () ), target ), true );
8027+ u.disassemble ( item_location ( map_cursor ( pos ), target ), true );
79968028 }
79978029 break ;
79988030 case BUTCHER_SALVAGE: {
@@ -8001,7 +8033,7 @@ void game::butcher()
80018033 } else {
80028034 // Pick index of first item in the salvage stack
80038035 item *const target = &*salvage_stacks[indexer_index].first ;
8004- item_location item_loc ( map_cursor ( u. pos_abs () ), target );
8036+ item_location item_loc ( map_cursor ( pos ), target );
80058037 salvage_iuse->try_to_cut_up ( u, *salvage_tool, item_loc );
80068038 }
80078039 }
0 commit comments