diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 05fb0bf363f12..0e75dee1dec38 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -1090,6 +1090,7 @@ mod = min( max, ( limb_score / denominator ) - subtract ); | `social_modifiers` | (_optional_) Json object with optional members: persuade, lie, and intimidate which add or subtract that amount from those types of social checks | `dispersion_mod` | (_optional_) Modifier to change firearm dispersion. | `activated_on_install` | (_optional_) Auto-activates this bionic when installed. +| `required_bionic` | (_optional_) Bionic which is required to install this bionic, and which cannot be uninstalled if this bionic is installed ```JSON { @@ -1123,7 +1124,19 @@ mod = min( max, ( limb_score / denominator ) - subtract ); [ "hand_r", { "bash": 3, "cut": 3, "bullet": 3 } ] ], "flags": [ "BIONIC_NPC_USABLE" ] -} +}, + { + "id": "bio_hydraulics", + "type": "bionic", + "name": { "str": "Hydraulic Muscles" }, + "description": "While activated, your muscles will be greatly enhanced, increasing your strength by 20.", + "occupied_bodyparts": [ [ "torso", 10 ], [ "arm_l", 8 ], [ "arm_r", 8 ], [ "leg_l", 10 ], [ "leg_r", 10 ] ], + "flags": [ "BIONIC_TOGGLED", "BIONIC_NPC_USABLE" ], + "act_cost": "10 kJ", + "react_cost": "10 kJ", + "time": "1 s", + "required_bionic": "bio_weight" + } ``` Bionics effects are defined in the code and new effects cannot be created through JSON alone. diff --git a/src/bionics.cpp b/src/bionics.cpp index 1dd6e94f1d746..156d9654f4d62 100644 --- a/src/bionics.cpp +++ b/src/bionics.cpp @@ -364,6 +364,7 @@ void bionic_data::load( const JsonObject &jsobj, const std::string &src ) optional( jsobj, was_loaded, "included_bionics", included_bionics ); optional( jsobj, was_loaded, "included", included ); optional( jsobj, was_loaded, "upgraded_bionic", upgraded_bionic ); + optional( jsobj, was_loaded, "required_bionic", required_bionic ); optional( jsobj, was_loaded, "fuel_options", fuel_opts ); optional( jsobj, was_loaded, "activated_on_install", activated_on_install, false ); @@ -568,6 +569,14 @@ void bionic_data::check_bionic_consistency() bio.id.c_str(), bio.upgraded_bionic.c_str() ); } } + if( bio.required_bionic ) { + if( bio.required_bionic == bio.id ) { + debugmsg( "Bionic %s requires itself as a prerequisite for installation", bio.id.c_str() ); + } else if( !bio.required_bionic.is_valid() ) { + debugmsg( "Bionic %s requires undefined bionic %s", + bio.id.c_str(), bio.required_bionic.c_str() ); + } + } if( !item::type_is_defined( bio.itype() ) && !bio.included ) { debugmsg( "Bionic %s has no defined item version", bio.id.c_str() ); } @@ -2113,6 +2122,14 @@ bool Character::can_uninstall_bionic( const bionic &bio, Character &installer, b return false; } + for( const bionic_id &bid : get_bionics() ) { + if( bid->required_bionic && bid->required_bionic == bio.id ) { + popup( _( "%s cannot be removed because installed bionic %s requires it." ), bio.id->name, + bid->name ); + return false; + } + } + if( bio.id->cant_remove_reason.has_value() ) { popup( string_format( bio.id->cant_remove_reason.value(), disp_name( true ), disp_name() ) ); return false; @@ -2331,6 +2348,10 @@ ret_val Character::is_installable( const item *it, const bool by_autodoc ) !has_bionic( bid->upgraded_bionic ) && it->is_upgrade() ) { return ret_val::make_failure( _( "No base version installed." ) ); + } else if( bid->required_bionic && + !has_bionic( bid->required_bionic ) ) { + return ret_val::make_failure( _( "CBM requires prior installation of %s." ), + bid->required_bionic.obj().name ); } else if( std::any_of( bid->available_upgrades.begin(), bid->available_upgrades.end(), [this]( const bionic_id & b ) { diff --git a/src/bionics.h b/src/bionics.h index 029059b2a6d5c..a81c6811b58ec 100644 --- a/src/bionics.h +++ b/src/bionics.h @@ -167,7 +167,13 @@ struct bionic_data { */ std::set available_upgrades; - /**Requirement to bionic installation*/ + /** + * Id of another bionic which this bionic needs to have installed to be installed. + * Also prevents that bionic from being removed while this bionic is installed. + */ + bionic_id required_bionic; + + /**Requirement to bionic installation - this is a crafting requirement such as soldering_standard or surface_heat*/ requirement_id installation_requirement; cata::flat_set flags; diff --git a/src/item.cpp b/src/item.cpp index e50a513156736..3fa49dd55c409 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -5112,6 +5112,12 @@ void item::bionic_info( std::vector &info, const iteminfo_query *parts insert_separation_line( info ); + if( bid->required_bionic ) { + info.emplace_back( "CBM", string_format( "* This CBM requires another CBM to also be installed: %s", + bid->required_bionic->name ) ); + } + insert_separation_line( info ); + // TODO refactor these almost identical blocks if( !bid->encumbrance.empty() ) { info.emplace_back( "DESCRIPTION", _( "Encumbrance:" ),