From ea9cc6ef40853172eca7acc9a66b881a7e3dfea4 Mon Sep 17 00:00:00 2001 From: RenechCDDA <84619419+RenechCDDA@users.noreply.github.com> Date: Thu, 27 Apr 2023 05:58:52 -0400 Subject: [PATCH] Display why vehicle parts cannot be installed --- src/veh_interact.cpp | 10 +++++++- src/vehicle.cpp | 54 ++++++++++++++++++++++++++++++-------------- src/vehicle.h | 31 ++++++++++++++++++++++++- 3 files changed, 76 insertions(+), 19 deletions(-) diff --git a/src/veh_interact.cpp b/src/veh_interact.cpp index 8015932a29e8b..7210d1344b1f6 100644 --- a/src/veh_interact.cpp +++ b/src/veh_interact.cpp @@ -873,6 +873,12 @@ bool veh_interact::update_part_requirements() } nmsg += res.second; + if( !veh->can_mount( veh->part( cpart ).mount, sel_vpart_info->get_id() ).success() ) { + ok = false; + nmsg += _( "Cannot install due to:\n" ) + veh->can_mount( veh->part( + cpart ).mount, sel_vpart_info->get_id() ).str() + "\n"; + } + sel_vpart_info->format_description( nmsg, c_light_gray, getmaxx( w_msg ) - 4 ); msg = colorize( nmsg, c_light_gray ); @@ -2363,7 +2369,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 +2383,8 @@ void veh_interact::move_cursor( const point &d, int dstart_at ) } else { req_missing.push_back( &vp ); } + } else if( !veh->can_mount( vd, vp.get_id() ).success() ) { + 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..6432f620ee0c7 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1120,17 +1120,19 @@ 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( + install_code::ERR_INVALID, _( "Invalid 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( + install_code::ERR_NOINSTALL, _( "Part cannot be installed!" ) ); } const std::vector parts_in_square = parts_at_relative( dp, false, false ); @@ -1138,15 +1140,18 @@ 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( + install_code::ERR_FIRST_PART, _( "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( + install_code::ERR_ANIMAL_YOKE, _( "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( + install_code::ERR_PROTRUSION, _( "An existing vehicle part is protruding!" ) ); } //No part type can stack with itself, or any other part in the same slot @@ -1156,12 +1161,18 @@ 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( + install_code::ERR_LOCATION_TAKEN, + _( "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( + install_code::ERR_ONE_CARGO_LIMIT, + _( "Can't have two cargo parts on the same tile! Conflicts with %1$s!" ), + other_part.name() ); } } @@ -1175,14 +1186,17 @@ 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( + install_code::ERR_ADJACENT_STRUCTURE, + _( "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( + install_code::ERR_EXCLUSIVE_ENGINE, _( "Only one exclusive engine allowed!" ) ); } // Check all the flags of the part to see if they require other flags @@ -1196,7 +1210,8 @@ bool vehicle::can_mount( const point &dp, const vpart_id &id ) const } } if( !anchor_found ) { - return false; + return ret_val::make_failure( + install_code::ERR_FLAG, _( "Part requires flag from another part!" ) ); } } } @@ -1205,7 +1220,9 @@ 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( + install_code::ERR_EXISTING_OPAQUE, + _( "Mirrors cannot be mounted on opaque parts!" ) ); } } } @@ -1214,7 +1231,9 @@ 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( + install_code::ERR_EXISTING_MIRROR, + _( "Opaque parts cannot be mounted on mirror parts!" ) ); } } } @@ -1223,13 +1242,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( + install_code::ERR_TURRET, _( "You can't install a turret on a turret!" ) ); } } } //Anything not explicitly denied is permitted - return true; + return ret_val::make_success( install_code::SUCCESS ); } bool vehicle::can_unmount( const int p ) const @@ -1401,7 +1421,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 +1430,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..0df310da80327 100644 --- a/src/vehicle.h +++ b/src/vehicle.h @@ -843,6 +843,35 @@ class vehicle vehicle &operator=( const vehicle & ) = default; public: + enum class install_code : int { + SUCCESS, + // part doesn't exist + ERR_INVALID, + // part cannot be installed + ERR_NOINSTALL, + // first part must be structural + ERR_FIRST_PART, + // can't put parts on top of an animal harness + ERR_ANIMAL_YOKE, + // protruding part in the way + ERR_PROTRUSION, + // installing part's location is already occupied + ERR_LOCATION_TAKEN, + // only one part with CARGO flag allowed per tile + ERR_ONE_CARGO_LIMIT, + // part needs to be adjacent to structure + ERR_ADJACENT_STRUCTURE, + // only one exclusive engine allowed + ERR_EXCLUSIVE_ENGINE, + // part requires flag from another part + ERR_FLAG, + // Mirrors cannot be mounted on OPAQUE parts + ERR_EXISTING_OPAQUE, + // Opaque parts cannot be mounted on mirrors parts + ERR_EXISTING_MIRROR, + // can't install turret on top of turret + ERR_TURRET + }; /** Disable or enable refresh() ; used to speed up performance when creating a vehicle */ void suspend_refresh(); void enable_refresh(); @@ -960,7 +989,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;