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

Prevent copy-from from discarding armour values #54801

Merged
merged 3 commits into from
Jan 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions data/mods/TEST_DATA/items.json
Original file line number Diff line number Diff line change
Expand Up @@ -2706,5 +2706,108 @@
"unfold_msg": "You painstakingly unfold the bicycle and make it ready to ride.",
"moves": 500
}
},
{
"id": "test_armor_chitin",
"type": "ARMOR",
"category": "armor",
"name": { "str": "chitinous armor" },
"description": "Leg and body armor made from the exoskeletons of insects.",
"weight": "2632 g",
"volume": "17500 ml",
"price": 120000,
"price_postapoc": 3000,
"to_hit": -5,
"bashing": 2,
"material": [ "chitin" ],
"symbol": "[",
"looks_like": "armor_larmor",
"color": "green",
"warmth": 10,
"longest_side": "60 cm",
"material_thickness": 4,
"environmental_protection": 6,
"environmental_protection_with_filter": 10,
"flags": [ "STURDY", "OUTER" ],
"armor": [ { "encumbrance": 10, "coverage": 90, "covers": [ "torso", "leg_l", "leg_r" ] } ]
},
{
"id": "test_armor_chitin_copy",
"type": "ARMOR",
"name": { "str": "XL chitinous armor" },
"copy-from": "test_armor_chitin",
"proportional": { "weight": 1.125, "volume": 1.13, "price": 1.25 },
"extend": { "flags": [ "OVERSIZE" ] }
},
{
"id": "test_armor_chitin_copy_w_armor",
"type": "ARMOR",
"name": { "str": "XL chitinous armor" },
"copy-from": "test_armor_chitin",
"proportional": { "weight": 1.125, "volume": 1.13, "price": 1.25 },
"extend": { "flags": [ "OVERSIZE" ] },
"armor": [ { "encumbrance": 10, "coverage": 90, "covers": [ "torso", "leg_l", "leg_r" ] } ]
},
{
"id": "test_armor_chitin_copy_prop",
"type": "ARMOR",
"name": { "str": "XL chitinous armor" },
"copy-from": "test_armor_chitin",
"proportional": {
"weight": 1.125,
"volume": 1.13,
"price": 1.25,
"material_thickness": 1.2,
"environmental_protection": 1.2,
"environmental_protection_with_filter": 1.2
},
"extend": { "flags": [ "OVERSIZE" ] }
},
{
"id": "test_armor_chitin_copy_w_armor_prop",
"type": "ARMOR",
"name": { "str": "XL chitinous armor" },
"copy-from": "test_armor_chitin",
"proportional": {
"weight": 1.125,
"volume": 1.13,
"price": 1.25,
"material_thickness": 1.2,
"environmental_protection": 1.2,
"environmental_protection_with_filter": 1.2
},
"extend": { "flags": [ "OVERSIZE" ] },
"armor": [ { "encumbrance": 10, "coverage": 90, "covers": [ "torso", "leg_l", "leg_r" ] } ]
},
{
"id": "test_armor_chitin_copy_rel",
"type": "ARMOR",
"name": { "str": "XL chitinous armor" },
"copy-from": "test_armor_chitin",
"relative": {
"weight": 200,
"volume": 1000,
"price": 100,
"material_thickness": 2,
"environmental_protection": 2,
"environmental_protection_with_filter": 2
},
"extend": { "flags": [ "OVERSIZE" ] }
},
{
"id": "test_armor_chitin_copy_w_armor_rel",
"type": "ARMOR",
"name": { "str": "XL chitinous armor" },
"copy-from": "test_armor_chitin",
"relative": {
"weight": 200,
"volume": 1000,
"price": 100,
"material_thickness": 2,
"environmental_protection": 2,
"environmental_protection_with_filter": 2
},
"extend": { "flags": [ "OVERSIZE" ] },
"armor": [ { "encumbrance": 10, "coverage": 90, "covers": [ "torso", "leg_l", "leg_r" ] } ]
}
]
61 changes: 52 additions & 9 deletions src/item_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2479,24 +2479,67 @@ static void apply_optional( T &value, const cata::optional<T> &applied )
}
}

// Gets around the issue that cata::optional doesn't support
// the *= and += operators required for "proportional" and "relative".
template<typename T>
static void get_optional( const JsonObject &jo, bool was_loaded, const std::string &member,
cata::optional<T> &value )
{
T tmp;
if( value ) {
tmp = *value;
}
optional( jo, was_loaded, member, tmp );
if( jo.has_member( member ) ) {
value = tmp;
}
}

template<typename T>
static void get_relative( const JsonObject &jo, const std::string &member, cata::optional<T> &value,
T default_val )
{
if( jo.has_member( member ) ) {
value = value.value_or( default_val ) + jo.get_float( member );
}
}

template<typename T>
static void get_proportional( const JsonObject &jo, const std::string &member,
cata::optional<T> &value, T default_val )
{
if( jo.has_member( member ) ) {
value = value.value_or( default_val ) * jo.get_float( member );
}
}

void islot_armor::load( const JsonObject &jo )
{
optional( jo, was_loaded, "armor", sub_data );

cata::optional<float> thickness;
cata::optional<int> env_resist;
cata::optional<int> env_resist_w_filter;
cata::optional<body_part_set> covers;

assign_coverage_from_json( jo, "covers", covers );
optional( jo, false, "material_thickness", thickness, cata::nullopt );
optional( jo, false, "environmental_protection", env_resist, cata::nullopt );
optional( jo, false, "environmental_protection_with_filter", env_resist_w_filter, cata::nullopt );
get_optional( jo, was_loaded, "material_thickness", _material_thickness );
get_optional( jo, was_loaded, "environmental_protection", _env_resist );
get_optional( jo, was_loaded, "environmental_protection_with_filter", _env_resist_w_filter );

JsonObject relative = jo.get_object( "relative" );
relative.allow_omitted_members();
get_relative( relative, "material_thickness", _material_thickness, 0.f );
get_relative( relative, "environmental_protection", _env_resist, 0 );
get_relative( relative, "environmental_protection_with_filter", _env_resist_w_filter, 0 );

JsonObject proportional = jo.get_object( "proportional" );
proportional.allow_omitted_members();
get_proportional( proportional, "material_thickness", _material_thickness, 0.f );
get_proportional( proportional, "environmental_protection", _env_resist, 0 );
get_proportional( proportional, "environmental_protection_with_filter", _env_resist_w_filter, 0 );

for( armor_portion_data &armor : sub_data ) {
apply_optional( armor.avg_thickness, thickness );
apply_optional( armor.env_resist, env_resist );
apply_optional( armor.env_resist_w_filter, env_resist_w_filter );
apply_optional( armor.avg_thickness, _material_thickness );
apply_optional( armor.env_resist, _env_resist );
apply_optional( armor.env_resist_w_filter, _env_resist_w_filter );
if( covers ) {
armor.covers = covers;
}
Expand Down
135 changes: 71 additions & 64 deletions src/itype.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,77 +309,84 @@ struct armor_portion_data {
};

struct islot_armor {
/**
* Whether this item can be worn on either side of the body
*/
bool sided = false;
/**
* The Non-Functional variant of this item. Currently only applies to ablative plates
*/
itype_id non_functional;
/**
* How much warmth this item provides.
*/
int warmth = 0;
/**
* Factor modifying weight capacity
*/
float weight_capacity_modifier = 1.0f;
/**
* Bonus to weight capacity
*/
units::mass weight_capacity_bonus = 0_gram;
/**
* Whether this is a power armor item.
*/
bool power_armor = false;
/**
* Whether this item has ablative pockets
*/
bool ablative = false;
/**
* Whether this item has pockets that generate additional encumbrance
*/
bool additional_pocket_enc = false;
/**
* Whether this item has pockets that can be ripped off
*/
bool ripoff_chance = false;
/**
* Whether this item has pockets that are noisy
*/
bool noisy = false;
/**
* Whitelisted clothing mods.
* Restricted clothing mods must be listed here by id to be compatible.
*/
std::vector<std::string> valid_mods;
public:
/**
* Whether this item can be worn on either side of the body
*/
bool sided = false;
/**
* The Non-Functional variant of this item. Currently only applies to ablative plates
*/
itype_id non_functional;
/**
* How much warmth this item provides.
*/
int warmth = 0;
/**
* Factor modifying weight capacity
*/
float weight_capacity_modifier = 1.0f;
/**
* Bonus to weight capacity
*/
units::mass weight_capacity_bonus = 0_gram;
/**
* Whether this is a power armor item.
*/
bool power_armor = false;
/**
* Whether this item has ablative pockets
*/
bool ablative = false;
/**
* Whether this item has pockets that generate additional encumbrance
*/
bool additional_pocket_enc = false;
/**
* Whether this item has pockets that can be ripped off
*/
bool ripoff_chance = false;
/**
* Whether this item has pockets that are noisy
*/
bool noisy = false;
/**
* Whitelisted clothing mods.
* Restricted clothing mods must be listed here by id to be compatible.
*/
std::vector<std::string> valid_mods;

/**
* If the item in question has any sub coverage when testing for encumberance
*/
bool has_sub_coverage = false;
/**
* If the item in question has any sub coverage when testing for encumberance
*/
bool has_sub_coverage = false;

// Layer, encumbrance and coverage information for each body part.
// This isn't directly loaded in but is instead generated from the loaded in
// sub_data vector
std::vector<armor_portion_data> data;
// Layer, encumbrance and coverage information for each body part.
// This isn't directly loaded in but is instead generated from the loaded in
// sub_data vector
std::vector<armor_portion_data> data;

// Layer, encumbrance and coverage information for each sub body part.
// This vector can have duplicates for body parts themselves.
std::vector<armor_portion_data> sub_data;
// Layer, encumbrance and coverage information for each sub body part.
// This vector can have duplicates for body parts themselves.
std::vector<armor_portion_data> sub_data;

// all of the layers this item is involved in
std::vector<layer_level> all_layers;
// all of the layers this item is involved in
std::vector<layer_level> all_layers;

bool was_loaded = false;
bool was_loaded = false;

int avg_env_resist() const;
int avg_env_resist_w_filter() const;
float avg_thickness() const;
int avg_env_resist() const;
int avg_env_resist_w_filter() const;
float avg_thickness() const;

void load( const JsonObject &jo );
void deserialize( const JsonObject &jo );
void load( const JsonObject &jo );
void deserialize( const JsonObject &jo );

private:
// Base material thickness, used to derive thickness in sub_data
cata::optional<float> _material_thickness = 0.0f;
cata::optional<int> _env_resist = 0;
cata::optional<int> _env_resist_w_filter = 0;
};

struct islot_pet_armor {
Expand Down
Loading