Skip to content

Commit

Permalink
First Version Of Encumbrance By Sentence (CleverRaven#57243)
Browse files Browse the repository at this point in the history
  • Loading branch information
bombasticSlacks authored Apr 30, 2022
1 parent 4974cb9 commit a26d6be
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 5 deletions.
11 changes: 10 additions & 1 deletion data/json/body_parts.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,16 @@
"smash_efficiency": 0.25,
"bionic_slots": 18,
"flags": [ "LIMB_UPPER" ],
"sub_parts": [ "head_forehead", "head_crown", "head_nape", "head_throat", "head_ear_r", "head_ear_l" ]
"sub_parts": [ "head_forehead", "head_crown", "head_nape", "head_throat", "head_ear_r", "head_ear_l" ],
"encumbrance_per_weight": [
{ "weight": "1 g", "encumbrance": 1 },
{ "weight": "300 g", "encumbrance": 4 },
{ "weight": "800 g", "encumbrance": 8 },
{ "weight": "1300 g", "encumbrance": 20 },
{ "weight": "1600 g", "encumbrance": 30 },
{ "weight": "2200 g", "encumbrance": 50 },
{ "weight": "5600 g", "encumbrance": 80 }
]
},
{
"id": "eyes",
Expand Down
4 changes: 2 additions & 2 deletions data/json/items/armor/helmets.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"material_thickness": 9,
"techniques": [ "WBLOCK_1" ],
"flags": [ "VARSIZE", "WATERPROOF", "STURDY", "PADDED" ],
"armor": [ { "encumbrance": 20, "coverage": 85, "covers": [ "head" ] } ]
"armor": [ { "encumbrance_modifiers": [ "WELL_SUPPORTED" ], "coverage": 85, "covers": [ "head" ] } ]
},
{
"id": "tac_fullhelmet",
Expand Down Expand Up @@ -554,7 +554,7 @@
],
"covers": [ "head" ],
"coverage": 100,
"encumbrance": 25
"encumbrance_modifiers": [ "RESTRICTS_NECK", "WELL_SUPPORTED" ]
},
{
"material": [
Expand Down
3 changes: 3 additions & 0 deletions doc/JSON_INFO.md
Original file line number Diff line number Diff line change
Expand Up @@ -2936,6 +2936,9 @@ Encumbrance and coverage can be defined on a piece of armor as such:
The value of this field (or, if it is an array, the first value in the array) is the base encumbrance (unfitted) of this item.
When specified as an array, the second value is the max encumbrance - when the pockets of this armor are completely full of items, the encumbrance of a non-rigid item will be set to this. Otherwise it'll be between the first value and the second value following this the equation: first value + (second value - first value) * non-rigid volume / non-rigid capacity. By default, the max encumbrance is the encumbrance + (non-rigid volume / 250ml).

##### Encumbrance_modifiers
Experimental feature for having an items encumbrance be generated by weight instead of a fixed number. Takes an array of "DESCRIPTORS" described in the code. If you don't need any descriptors put "NONE". This overrides encumbrance putting it as well will make it be ignored. Currently only works for head armor.

##### Coverage
(integer)
What percentage of time this piece of armor will be hit (and thus used as armor) when an attack hits the body parts in `covers`.
Expand Down
13 changes: 13 additions & 0 deletions src/bodypart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,19 @@ void body_part_type::load( const JsonObject &jo, const std::string & )
mandatory( jo, was_loaded, "side", part_side );

optional( jo, was_loaded, "sub_parts", sub_parts );

if( jo.has_array( "encumbrance_per_weight" ) ) {
const JsonArray &jarr = jo.get_array( "encumbrance_per_weight" );
for( const JsonObject jval : jarr ) {
units::mass weight = 0_gram;
int encumbrance = 0;

assign( jval, "weight", weight, true );
mandatory( jval, was_loaded, "encumbrance", encumbrance );

encumbrance_per_weight.insert( std::pair<units::mass, int>( weight, encumbrance ) );
}
}
}

void body_part_type::reset()
Expand Down
2 changes: 2 additions & 0 deletions src/bodypart.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ struct body_part_type {
*/
std::vector<sub_bodypart_str_id> sub_parts;

std::map<units::mass, int> encumbrance_per_weight;

cata::flat_set<json_character_flag> flags;
cata::flat_set<json_character_flag> conditional_flags;

Expand Down
54 changes: 53 additions & 1 deletion src/item_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,10 @@ void Item_factory::finalize_post( itype &obj )
it.encumber += sub_armor.encumber;
it.max_encumber += sub_armor.max_encumber;

for( const encumbrance_modifier &en : sub_armor.encumber_modifiers ) {
it.encumber_modifiers.push_back( en );
}

// get the amount of the limb that is covered with sublocations
// for overall coverage we need to scale coverage by that
float scale = sub_armor.max_coverage( bp ) / 100.0;
Expand Down Expand Up @@ -834,6 +838,30 @@ void Item_factory::finalize_post( itype &obj )

}

// calculate encumbrance data per limb if done by description
for( armor_portion_data &data : obj.armor->data ) {
if( !data.encumber_modifiers.empty() ) {
// we know that the data entry covers a single bp
data.encumber = data.calc_encumbrance( obj.weight, *data.covers.value().begin() );

// need to account for varsize stuff here and double encumbrance if so
if( obj.has_flag( flag_VARSIZE ) ) {
data.encumber *= 2;
}

// Recalc max encumber as well
units::volume total_nonrigid_volume = 0_ml;
for( const pocket_data &pocket : obj.pockets ) {
if( !pocket.rigid ) {
// include the modifier for each individual pocket
total_nonrigid_volume += pocket.max_contains_volume() * pocket.volume_encumber_modifier;
}
}
data.max_encumber = data.encumber + total_nonrigid_volume * data.volume_encumber_modifier /
data.volume_per_encumbrance;
}
}

// need to scale amalgamized portion data based on total coverage.
// 3% of 48% needs to be scaled to 6% of 100%
for( armor_portion_data &it : obj.armor->data ) {
Expand Down Expand Up @@ -2657,7 +2685,10 @@ void armor_portion_data::deserialize( const JsonObject &jo )

optional( jo, false, "rigid_layer_only", rigid_layer_only, false );

if( jo.has_array( "encumbrance" ) ) {
if( jo.has_array( "encumbrance_modifiers" ) ) {
// instead of reading encumbrance calculate it by weight
optional( jo, false, "encumbrance_modifiers", encumber_modifiers );
} else if( jo.has_array( "encumbrance" ) ) {
encumber = jo.get_array( "encumbrance" ).get_int( 0 );
max_encumber = jo.get_array( "encumbrance" ).get_int( 1 );
} else {
Expand Down Expand Up @@ -3533,6 +3564,27 @@ struct enum_traits<balance_val> {
static constexpr balance_val last = balance_val::LAST;
};

namespace io
{
template<>
std::string enum_to_string<encumbrance_modifier>( encumbrance_modifier data )
{
switch( data ) {
case encumbrance_modifier::IMBALANCED:
return "IMBALANCED";
case encumbrance_modifier::RESTRICTS_NECK:
return "RESTRICTS_NECK";
case encumbrance_modifier::WELL_SUPPORTED:
return "WELL_SUPPORTED";
case encumbrance_modifier::NONE:
return "NONE";
case encumbrance_modifier::last:
break;
}
cata_fatal( "Invalid encumbrance descriptor" );
}
} // namespace io

namespace io
{
// *INDENT-OFF*
Expand Down
53 changes: 53 additions & 0 deletions src/itype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,56 @@ int armor_portion_data::max_coverage( bodypart_str_id bp ) const
// return the max of primary or hanging sublocations (this only matters for hanging items on chest)
return std::max( primary_max_coverage, secondary_max_coverage );
}

int armor_portion_data::calc_encumbrance( units::mass weight, bodypart_id bp ) const
{
// this function takes some fixed points for mass to encumbrance and interpolates them to get results for head encumbrance
// TODO: Generalize this for other body parts (either with a modifier or seperated point graphs)
// TODO: Handle distributed weight

int encumbrance = 0;

std::map<units::mass, int> mass_to_encumbrance = bp->encumbrance_per_weight;

std::map<units::mass, int>::iterator itt = mass_to_encumbrance.lower_bound( weight );

if( itt == mass_to_encumbrance.end() ) {
debugmsg( "Can't find a notable point to match this with" );
return 100;
}

std::map<units::mass, int>::iterator next_itt = std::next( itt );

// between itt and next_itt need to figure out how much and scale values
float scale = static_cast<float>( weight.value() - itt->first.value() ) / static_cast<float>
( next_itt->first.value() - itt->first.value() );

// encumbrance is scaled by range between the two values
encumbrance = itt->second + std::roundf( static_cast<float>( next_itt->second - itt->second ) *
scale );

// then add some modifiers

for( const encumbrance_modifier &em : encumber_modifiers ) {
encumbrance += armor_portion_data::convert_descriptor_to_int( em );
}

return encumbrance;
}

int armor_portion_data::convert_descriptor_to_int( encumbrance_modifier em )
{
// this is where the values for each of these exist
switch( em ) {
case encumbrance_modifier::IMBALANCED:
case encumbrance_modifier::RESTRICTS_NECK:
return 10;
case encumbrance_modifier::WELL_SUPPORTED:
return -10;
case encumbrance_modifier::NONE:
return 0;
case encumbrance_modifier::last:
break;
}
return 0;
}
25 changes: 24 additions & 1 deletion src/itype.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,28 @@ struct part_material {
void deserialize( const JsonObject &jo );
};

// values for attributes related to encumbrance
enum class encumbrance_modifier : int {
IMBALANCED = 0,
RESTRICTS_NECK,
WELL_SUPPORTED,
NONE,
last
};

template<>
struct enum_traits<encumbrance_modifier> {
static constexpr encumbrance_modifier last = encumbrance_modifier::last;
};

struct armor_portion_data {

// The base volume for an item
const units::volume volume_per_encumbrance = 250_ml; // NOLINT(cata-serialize)

// descriptors used to infer encumbrance
std::vector<encumbrance_modifier> encumber_modifiers;

// How much this piece encumbers the player.
int encumber = 0;

Expand Down Expand Up @@ -320,6 +337,12 @@ struct armor_portion_data {
*/
int max_coverage( bodypart_str_id bp ) const;

// helper function to return encumbrance value by descriptor and weight
int calc_encumbrance( units::mass weight, bodypart_id bp ) const;

// converts a specific encumbrance modifier to an actual encumbrance value
static int convert_descriptor_to_int( encumbrance_modifier em );

void deserialize( const JsonObject &jo );
};

Expand Down Expand Up @@ -387,7 +410,7 @@ struct islot_armor {
std::vector<std::string> valid_mods;

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

Expand Down

0 comments on commit a26d6be

Please sign in to comment.