Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(port): Bionics can require another bionic #5484

Merged
merged 11 commits into from
Oct 2, 2024
3 changes: 2 additions & 1 deletion data/json/bionics.json
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,8 @@
"flags": [ "BIONIC_TOGGLED", "BIONIC_NPC_USABLE" ],
"act_cost": "10 kJ",
"react_cost": "10 kJ",
"time": 1
"time": 1,
"required_bionic": "bio_weight"
},
{
"id": "bio_infolink",
Expand Down
87 changes: 50 additions & 37 deletions doc/src/content/docs/en/mod/json/reference/json_info.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,43 +188,56 @@ the appropriate JSON file.

### Bionics

| Identifier | Description |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | (_mandatory_) Unique ID. Must be one continuous word, use underscores if necessary. |
| name | (_mandatory_) In-game name displayed. |
| description | (_mandatory_) In-game description. |
| flags | (_optional_) A list of flags. See JSON_FLAGS.md for supported values. |
| act_cost | (_optional_) How many kJ it costs to activate the bionic. Strings can be used "1 kJ"/"1000 J"/"1000000 mJ" (default: `0`) |
| deact_cost | (_optional_) How many kJ it costs to deactivate the bionic. Strings can be used "1 kJ"/"1000 J"/"1000000 mJ" (default: `0`) |
| react_cost | (_optional_) How many kJ it costs over time to keep this bionic active, does nothing without a non-zero "time". Strings can be used "1 kJ"/"1000 J"/"1000000 mJ" (default: `0`) |
| time | (_optional_) How long, when activated, between drawing cost. If 0, it draws power once. (default: `0`) |
| upgraded_bionic | (_optional_) Bionic that can be upgraded by installing this one. |
| available_upgrades | (_optional_) Upgrades available for this bionic, i.e. the list of bionics having this one referenced by `upgraded_bionic`. |
| encumbrance | (_optional_) A list of body parts and how much this bionic encumber them. |
| weight_capacity_bonus | (_optional_) Bonus to weight carrying capacity in grams, can be negative. Strings can be used - "5000 g" or "5 kg" (default: `0`) |
| weight_capacity_modifier | (_optional_) Factor modifying base weight carrying capacity. (default: `1`) |
| canceled_mutations | (_optional_) A list of mutations/traits that are removed when this bionic is installed (e.g. because it replaces the fault biological part). |
| included_bionics | (_optional_) Additional bionics that are installed automatically when this bionic is installed. This can be used to install several bionics from one CBM item, which is useful as each of those can be activated independently. |
| included | (_optional_) Whether this bionic is included with another. If true this bionic does not require a CBM item to be defined. (default: `false`) |
| env_protec | (_optional_) How much environmental protection does this bionic provide on the specified body parts. |
| bash_protec | (_optional_) How much bash protection does this bionic provide on the specified body parts. |
| cut_protec | (_optional_) How much cut protection does this bionic provide on the specified body parts. |
| bullet_protect | (_optional_) How much bullet protect does this bionic provide on the specified body parts. |
| occupied_bodyparts | (_optional_) A list of body parts occupied by this bionic, and the number of bionic slots it take on those parts. |
| capacity | (_optional_) Amount of power storage added by this bionic. Strings can be used "1 kJ"/"1000 J"/"1000000 mJ" (default: `0`) |
| fuel_options | (_optional_) A list of fuel that this bionic can use to produce bionic power. |
| is_remote_fueled | (_optional_) If true this bionic allows you to plug your power banks to an external power source (solar backpack, UPS, vehicle etc) via a cable. (default: `false`) |
| fuel_capacity | (_optional_) Volume of fuel this bionic can store. |
| fuel_efficiency | (_optional_) Fraction of fuel energy converted into power. (default: `0`) |
| fuel_multiplier | (_optional_) Multiplies the amount of fuel when loading into the bionic (default: `1`) |
| passive_fuel_efficiency | (_optional_) Fraction of fuel energy passively converted into power. Useful for CBM using PERPETUAL fuel like `muscle`, `wind` or `sun_light`. (default: `0`) |
| exothermic_power_gen | (_optional_) If true this bionic emits heat when producing power. (default: `false`) |
| coverage_power_gen_penalty | (_optional_) Fraction of coverage diminishing fuel_efficiency. Float between 0.0 and 1.0. (default: `nullopt`) |
| power_gen_emission | (_optional_) `emit_id` of the field emitted by this bionic when it produces energy. Emit_ids are defined in `emit.json`. |
| stat_bonus | (_optional_) List of passive stat bonus. Stat are designated as follow: "DEX", "INT", "STR", "PER". |
| enchantments | (_optional_) List of enchantments applied by this CBM (see MAGIC.md for instructions on enchantment. NB: enchantments are not necessarily magic.) |
| learned_spells | (_optional_) List of spells (with levels) you gain when installing this CBM, and lose when you uninstall this CBM. Spell classes are automatically gained. |
| fake_item | (_optional_) ID of fake item used by this bionic. Mandatory for gun and weapon bionics. |
| Identifier | Description |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | (_mandatory_) Unique ID. Must be one continuous word, use underscores if necessary. |
| name | (_mandatory_) In-game name displayed. |
| description | (_mandatory_) In-game description. |
| flags | (_optional_) A list of flags. See JSON_FLAGS.md for supported values. |
| act_cost | (_optional_) How many kJ it costs to activate the bionic. Strings can be used "1 kJ"/"1000 J"/"1000000 mJ" (default: `0`) |
| deact_cost | (_optional_) How many kJ it costs to deactivate the bionic. Strings can be used "1 kJ"/"1000 J"/"1000000 mJ" (default: `0`) |
| react_cost | (_optional_) How many kJ it costs over time to keep this bionic active, does nothing without a non-zero "time". Strings can be used "1 kJ"/"1000 J"/"1000000 mJ" (default: `0`) |
| time | (_optional_) How long, when activated, between drawing cost. If 0, it draws power once. (default: `0`) |
| upgraded_bionic | (_optional_) Bionic that can be upgraded by installing this one. |
| required_bionic | (_optional_) Bionic which is required to install this bionic, and which cannot be uninstalled if this bionic is installed |

scarf005 marked this conversation as resolved.
Show resolved Hide resolved
| available_upgrades | (_optional_) Upgrades available for this bionic, i.e. the list of bionics
having this one referenced by `upgraded_bionic`. | | encumbrance | (_optional_) A list of body parts
and how much this bionic encumber them. | | weight_capacity_bonus | (_optional_) Bonus to weight
carrying capacity in grams, can be negative. Strings can be used - "5000 g" or "5 kg" (default: `0`)
| | weight_capacity_modifier | (_optional_) Factor modifying base weight carrying capacity.
(default: `1`) | | canceled_mutations | (_optional_) A list of mutations/traits that are removed
when this bionic is installed (e.g. because it replaces the fault biological part). | |
included_bionics | (_optional_) Additional bionics that are installed automatically when this bionic
is installed. This can be used to install several bionics from one CBM item, which is useful as each
of those can be activated independently. | | included | (_optional_) Whether this bionic is included
with another. If true this bionic does not require a CBM item to be defined. (default: `false`) | |
env_protec | (_optional_) How much environmental protection does this bionic provide on the
specified body parts. | | bash_protec | (_optional_) How much bash protection does this bionic
provide on the specified body parts. | | cut_protec | (_optional_) How much cut protection does this
bionic provide on the specified body parts. | | bullet_protect | (_optional_) How much bullet
protect does this bionic provide on the specified body parts. | | occupied_bodyparts | (_optional_)
A list of body parts occupied by this bionic, and the number of bionic slots it take on those parts.
| | capacity | (_optional_) Amount of power storage added by this bionic. Strings can be used "1
kJ"/"1000 J"/"1000000 mJ" (default: `0`) | | fuel_options | (_optional_) A list of fuel that this
bionic can use to produce bionic power. | | is_remote_fueled | (_optional_) If true this bionic
allows you to plug your power banks to an external power source (solar backpack, UPS, vehicle etc)
via a cable. (default: `false`) | | fuel_capacity | (_optional_) Volume of fuel this bionic can
store. | | fuel_efficiency | (_optional_) Fraction of fuel energy converted into power. (default:
`0`) | | fuel_multiplier | (_optional_) Multiplies the amount of fuel when loading into the bionic
(default: `1`) | | passive_fuel_efficiency | (_optional_) Fraction of fuel energy passively
converted into power. Useful for CBM using PERPETUAL fuel like `muscle`, `wind` or `sun_light`.
(default: `0`) | | exothermic_power_gen | (_optional_) If true this bionic emits heat when producing
power. (default: `false`) | | coverage_power_gen_penalty | (_optional_) Fraction of coverage
diminishing fuel_efficiency. Float between 0.0 and 1.0. (default: `nullopt`) | | power_gen_emission
| (_optional_) `emit_id` of the field emitted by this bionic when it produces energy. Emit_ids are
defined in `emit.json`. | | stat_bonus | (_optional_) List of passive stat bonus. Stat are
designated as follow: "DEX", "INT", "STR", "PER". | | enchantments | (_optional_) List of
enchantments applied by this CBM (see MAGIC.md for instructions on enchantment. NB: enchantments are
not necessarily magic.) | | learned_spells | (_optional_) List of spells (with levels) you gain when
installing this CBM, and lose when you uninstall this CBM. Spell classes are automatically gained. |
| fake_item | (_optional_) ID of fake item used by this bionic. Mandatory for gun and weapon
bionics. |

```json
{
Expand Down
22 changes: 22 additions & 0 deletions src/bionics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ void bionic_data::load( const JsonObject &jsobj, const std::string &src )
assign( jsobj, "enchantments", enchantments, strict );
assign_map_from_array( jsobj, "learned_spells", learned_spells, strict );
assign( jsobj, "included_bionics", included_bionics, strict );
assign( jsobj, "required_bionic", required_bionic, strict );
assign( jsobj, "upgraded_bionic", upgraded_bionic, strict );
assign( jsobj, "available_upgrades", available_upgrades, strict );
assign( jsobj, "flags", flags, strict );
Expand Down Expand Up @@ -410,6 +411,14 @@ void bionic_data::check() const
rep.warn( "upgrades undefined bionic \"%s\"", upgraded_bionic.str() );
}
}
if( required_bionic ) {
if( required_bionic == id ) {
rep.warn( "The CBM %s requires itself as a prerequisite for installation", required_bionic.str() );
} else if( !required_bionic.is_valid() ) {
rep.warn( "The CBM %s requires undefined bionic %s", id.str(), required_bionic.str() );
}
}

for( const bionic_id &it : available_upgrades ) {
if( !it.is_valid() ) {
rep.warn( "specifies unknown upgrade \"%s\"", it.str() );
Expand Down Expand Up @@ -2036,6 +2045,14 @@ bool Character::can_uninstall_bionic( const bionic_id &b_id, player &installer,
}
}

for( const bionic_id &bid : get_bionics() ) {
if( bid->required_bionic == b_id ) {
popup( _( "%s cannot be removed because installed bionic %s requires it." ),
b_id->name, bid->name );
return false;
}
}

if( b_id == bio_eye_optic ) {
popup( _( "The Telescopic Lenses are part of %s eyes now. Removing them would leave %s blind." ),
disp_name( true ), disp_name() );
Expand Down Expand Up @@ -2279,6 +2296,11 @@ bool Character::can_install_bionics( const itype &type, player &installer, bool
}
int chance_of_success = bionic_manip_cos( adjusted_skill, difficult );

if( bioid->required_bionic && !has_bionic( bioid->required_bionic ) ) {
popup( _( "CBM requires prior installation of %s." ), bioid->required_bionic.obj().name );
return false;
}

std::vector<std::string> conflicting_muts;
for( const trait_id &mid : bioid->canceled_mutations ) {
if( has_trait( mid ) ) {
Expand Down
5 changes: 5 additions & 0 deletions src/bionics.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ struct bionic_data {
* Upgrades available for this bionic (opposite to @ref upgraded_bionic).
*/
std::set<bionic_id> available_upgrades;
/**
* 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;

std::set<flag_id> flags;
bool has_flag( const flag_id &flag ) const;
Expand Down
7 changes: 7 additions & 0 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3382,6 +3382,13 @@ void item::bionic_info( std::vector<iteminfo> &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 );

if( !bid->encumbrance.empty() ) {
info.emplace_back( "DESCRIPTION", _( "<bold>Encumbrance</bold>: " ),
iteminfo::no_newline );
Expand Down
Loading