diff --git a/src/veh_interact.cpp b/src/veh_interact.cpp index 8015932a29e8b..714cf7ff5e4c2 100644 --- a/src/veh_interact.cpp +++ b/src/veh_interact.cpp @@ -873,6 +873,14 @@ bool veh_interact::update_part_requirements() } nmsg += res.second; + ret_val can_mount = veh->can_mount( + veh->part( cpart ).mount, sel_vpart_info->get_id() ); + if( !can_mount.success() ) { + ok = false; + nmsg += _( "Cannot install due to:\n> " ) + colorize( can_mount.str(), + c_red ) + "\n"; + } + sel_vpart_info->format_description( nmsg, c_light_gray, getmaxx( w_msg ) - 4 ); msg = colorize( nmsg, c_light_gray ); @@ -2363,7 +2371,7 @@ void veh_interact::move_cursor( const point &d, int dstart_at ) if( has_critter && vp.has_flag( VPFLAG_OBSTACLE ) ) { continue; } - if( veh->can_mount( vd, vp.get_id() ) ) { + if( veh->can_mount( vd, vp.get_id() ).success() ) { if( vp.has_flag( VPFLAG_APPLIANCE ) ) { // exclude "appliances" from vehicle part list continue; @@ -2377,6 +2385,8 @@ void veh_interact::move_cursor( const point &d, int dstart_at ) } else { req_missing.push_back( &vp ); } + } else { + req_missing.push_back( &vp ); } } auto vpart_localized_sort = []( const vpart_info * a, const vpart_info * b ) { diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 769a4d5de12f3..dcf9c751847e5 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1120,17 +1120,18 @@ bool vehicle::is_structural_part_removed() const * @param id The id of the part to install. * @return true if the part can be mounted, false if not. */ -bool vehicle::can_mount( const point &dp, const vpart_id &id ) const +ret_val vehicle::can_mount( const point &dp, const vpart_id &id ) const { //The part has to actually exist. if( !id.is_valid() ) { - return false; + return ret_val::make_failure( + _( "Invalid part ID! This should never appear." ) ); } //It also has to be a real part, not the null part const vpart_info &part = id.obj(); if( part.has_flag( "NOINSTALL" ) ) { - return false; + return ret_val::make_failure( _( "Part cannot be installed." ) ); } const std::vector parts_in_square = parts_at_relative( dp, false, false ); @@ -1138,15 +1139,17 @@ bool vehicle::can_mount( const point &dp, const vpart_id &id ) const //First part in an empty square MUST be a structural part or be an appliance if( parts_in_square.empty() && part.location != part_location_structure && !part.has_flag( flag_APPLIANCE ) ) { - return false; + return ret_val::make_failure( _( "There's no structure to support it." ) ); } // If its a part that harnesses animals that don't allow placing on it. if( !parts_in_square.empty() && part_info( parts_in_square[0] ).has_flag( "ANIMAL_CTRL" ) ) { - return false; + return ret_val::make_failure( + _( "There's an animal harness in the way." ) ); } //No other part can be placed on a protrusion if( !parts_in_square.empty() && part_info( parts_in_square[0] ).has_flag( "PROTRUSION" ) ) { - return false; + return ret_val::make_failure( + _( "An existing vehicle part is protruding." ) ); } //No part type can stack with itself, or any other part in the same slot @@ -1156,12 +1159,16 @@ bool vehicle::can_mount( const point &dp, const vpart_id &id ) const //Parts with no location can stack with each other (but not themselves) if( part.get_id() == other_part.get_id() || ( !part.location.empty() && part.location == other_part.location ) ) { - return false; + return ret_val::make_failure( + _( "The installed %1$s part shares the %2$s location." ), other_part.name(), + other_part.location ); } // Until we have an interface for handling multiple components with CARGO space, // exclude them from being mounted in the same tile. if( part.has_flag( "CARGO" ) && other_part.has_flag( "CARGO" ) ) { - return false; + return ret_val::make_failure( + _( "There can't be two cargo parts on the same tile. Part conflicts with existing %1$s." ), + other_part.name() ); } } @@ -1175,14 +1182,16 @@ bool vehicle::can_mount( const point &dp, const vpart_id &id ) const !has_structural_part( dp + point_south ) && !has_structural_part( dp + point_west ) && !has_structural_part( dp + point_north ) ) { - return false; + return ret_val::make_failure( + _( "Part needs to be adjacent to or on existing structure." ) ); } } // only one exclusive engine allowed std::string empty; if( has_engine_conflict( &part, empty ) ) { - return false; + return ret_val::make_failure( + _( "Only one exclusive engine is allowed." ) ); } // Check all the flags of the part to see if they require other flags @@ -1196,7 +1205,8 @@ bool vehicle::can_mount( const point &dp, const vpart_id &id ) const } } if( !anchor_found ) { - return false; + return ret_val::make_failure( + _( "Part requires flag from another part." ) ); } } } @@ -1205,7 +1215,8 @@ bool vehicle::can_mount( const point &dp, const vpart_id &id ) const if( part.has_flag( "VISION" ) && !part.has_flag( "CAMERA" ) ) { for( const int &elem : parts_in_square ) { if( part_info( elem ).has_flag( "OPAQUE" ) ) { - return false; + return ret_val::make_failure( + _( "Mirrors cannot be mounted on opaque parts." ) ); } } } @@ -1214,7 +1225,8 @@ bool vehicle::can_mount( const point &dp, const vpart_id &id ) const for( const int &elem : parts_in_square ) { if( part_info( elem ).has_flag( "VISION" ) && !part_info( elem ).has_flag( "CAMERA" ) ) { - return false; + return ret_val::make_failure( + _( "Opaque parts cannot be mounted on mirror parts." ) ); } } } @@ -1223,13 +1235,14 @@ bool vehicle::can_mount( const point &dp, const vpart_id &id ) const if( part.has_flag( "TURRET_MOUNT" ) ) { for( const int &elem : parts_in_square ) { if( part_info( elem ).has_flag( "TURRET_MOUNT" ) ) { - return false; + return ret_val::make_failure( + _( "You can't install a turret on a turret." ) ); } } } //Anything not explicitly denied is permitted - return true; + return ret_val::make_success(); } bool vehicle::can_unmount( const int p ) const @@ -1401,7 +1414,7 @@ bool vehicle::is_appliance() const int vehicle::install_part( const point &dp, const vpart_id &id, const std::string &variant_id, bool force ) { - if( !( force || can_mount( dp, id ) ) ) { + if( !( force || can_mount( dp, id ).success() ) ) { return -1; } return install_part( dp, vehicle_part( id, variant_id, dp, item( id.obj().base_item ) ) ); @@ -1410,7 +1423,7 @@ int vehicle::install_part( const point &dp, const vpart_id &id, const std::strin int vehicle::install_part( const point &dp, const vpart_id &id, item &&obj, const std::string &variant_id, bool force ) { - if( !( force || can_mount( dp, id ) ) ) { + if( !( force || can_mount( dp, id ).success() ) ) { return -1; } return install_part( dp, vehicle_part( id, variant_id, dp, std::move( obj ) ) ); diff --git a/src/vehicle.h b/src/vehicle.h index 5021034b6dc38..6def34f2acedc 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -960,7 +960,7 @@ class vehicle const vpart_info &part_info( int index, bool include_removed = false ) const; // check if certain part can be mounted at certain position (not accounting frame direction) - bool can_mount( const point &dp, const vpart_id &id ) const; + ret_val can_mount( const point &dp, const vpart_id &id ) const; // check if certain part can be unmounted bool can_unmount( int p ) const;