From b0aee968eb4affeeca803ff0d58623cf7198c099 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Mon, 10 Feb 2020 18:18:09 -0700 Subject: [PATCH 01/51] Standardize unformatted colon after headings Existing headings were about half and half between these two styles: Heading: Heading: This commit standardizes on the latter, for all item info. --- src/item.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 90784a6201ac1..2b1ab6ab8dd98 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1241,7 +1241,7 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, req.push_back( string_format( "%s %d", skill_id( sk.first )->name(), sk.second ) ); } if( !req.empty() ) { - info.emplace_back( "BASE", _( "Minimum requirements:" ) ); + info.emplace_back( "BASE", _( "Minimum requirements:" ) ); info.emplace_back( "BASE", enumerate_as_string( req ) ); insert_separation_line( info ); } @@ -1660,7 +1660,7 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf const std::string fmt = string_format( ngettext( " round of %s", " rounds of %s", mod->ammo_capacity() ), at->name() ); - info.emplace_back( "GUN", _( "Capacity: " ), fmt, iteminfo::no_flags, + info.emplace_back( "GUN", _( "Capacity: " ), fmt, iteminfo::no_flags, mod->ammo_capacity() ); } } @@ -1866,7 +1866,7 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf } if( !fm.empty() ) { insert_separation_line( info ); - info.emplace_back( "GUN", _( "Fire modes: " ) + + info.emplace_back( "GUN", _( "Fire modes: " ) + enumerate_as_string( fm ) ); } } @@ -1874,7 +1874,7 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf if( !magazine_integral() && parts->test( iteminfo_parts::GUN_ALLOWED_MAGAZINES ) ) { insert_separation_line( info ); const std::set compat = magazine_compatible(); - info.emplace_back( "DESCRIPTION", _( "Compatible magazines: " ) + + info.emplace_back( "DESCRIPTION", _( "Compatible magazines: " ) + enumerate_as_string( compat.begin(), compat.end(), []( const itype_id & id ) { return item::nname( id ); } ) ); @@ -1883,7 +1883,7 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf if( !gun.valid_mod_locations.empty() && parts->test( iteminfo_parts::DESCRIPTION_GUN_MODS ) ) { insert_separation_line( info ); - std::string mod_str = _( "Mods: " ); + std::string mod_str = _( "Mods: " ); std::map mod_locations = get_mod_locations(); @@ -2472,13 +2472,13 @@ void item::battery_info( std::vector &info, const iteminfo_query * /*p std::string info_string; if( type->battery->max_capacity < 1_J ) { - info_string = string_format( _( "Capacity: %dmJ" ), + info_string = string_format( _( "Capacity: %dmJ" ), to_millijoule( type->battery->max_capacity ) ); } else if( type->battery->max_capacity < 1_kJ ) { - info_string = string_format( _( "Capacity: %dJ" ), + info_string = string_format( _( "Capacity: %dJ" ), to_joule( type->battery->max_capacity ) ); } else if( type->battery->max_capacity >= 1_kJ ) { - info_string = string_format( _( "Capacity: %dkJ" ), + info_string = string_format( _( "Capacity: %dkJ" ), to_kilojoule( type->battery->max_capacity ) ); } insert_separation_line( info ); @@ -2507,7 +2507,7 @@ void item::tool_info( std::vector &info, const iteminfo_query *parts, if( parts->test( iteminfo_parts::TOOL_MAGAZINE_COMPATIBLE ) ) { insert_separation_line( info ); const std::set compat = magazine_compatible(); - info.emplace_back( "TOOL", _( "Compatible magazines: " ), + info.emplace_back( "TOOL", _( "Compatible magazines: " ), enumerate_as_string( compat.begin(), compat.end(), []( const itype_id & id ) { return item::nname( id ); } ) ); @@ -2637,7 +2637,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, insert_separation_line( info ); info.push_back( iteminfo( "DESCRIPTION", _( "Techniques when wielded: " ) + enumerate_as_string( all_techniques.begin(), all_techniques.end(), []( const matec_id & tid ) { - return string_format( "%s: %s", _( tid.obj().name ), + return string_format( "%s: %s", _( tid.obj().name ), _( tid.obj().description ) ); } ) ) ); } @@ -2668,7 +2668,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, int attack_cost = g->u.attack_speed( *this ); insert_separation_line( info ); if( parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG ) ) { - info.push_back( iteminfo( "DESCRIPTION", _( "Average melee damage:" ) ) ); + info.push_back( iteminfo( "DESCRIPTION", _( "Average melee damage:" ) ) ); } if( parts->test( iteminfo_parts::DESCRIPTION_MELEEDMG_CRIT ) ) { info.push_back( iteminfo( "DESCRIPTION", @@ -3019,7 +3019,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, insert_separation_line( info ); if( bid->capacity > 0_mJ ) { - info.push_back( iteminfo( "CBM", _( "Power Capacity:" ), _( " mJ" ), + info.push_back( iteminfo( "CBM", _( "Power Capacity:" ), _( " mJ" ), iteminfo::no_newline, units::to_millijoule( bid->capacity ) ) ); } @@ -3027,7 +3027,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, insert_separation_line( info ); if( !bid->encumbrance.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", _( "Encumbrance: " ), + info.push_back( iteminfo( "DESCRIPTION", _( "Encumbrance: " ), iteminfo::no_newline ) ); for( const auto &element : bid->encumbrance ) { info.push_back( iteminfo( "CBM", body_part_name_as_heading( element.first, 1 ), @@ -3037,7 +3037,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, if( !bid->env_protec.empty() ) { info.push_back( iteminfo( "DESCRIPTION", - _( "Environmental Protection: " ), + _( "Environmental Protection: " ), iteminfo::no_newline ) ); for( const std::pair< body_part, size_t > &element : bid->env_protec ) { info.push_back( iteminfo( "CBM", body_part_name_as_heading( element.first, 1 ), @@ -3047,7 +3047,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, if( !bid->bash_protec.empty() ) { info.push_back( iteminfo( "DESCRIPTION", - _( "Bash Protection: " ), + _( "Bash Protection: " ), iteminfo::no_newline ) ); for( const std::pair< body_part, size_t > &element : bid->bash_protec ) { info.push_back( iteminfo( "CBM", body_part_name_as_heading( element.first, 1 ), @@ -3056,7 +3056,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } if( !bid->cut_protec.empty() ) { info.push_back( iteminfo( "DESCRIPTION", - _( "Cut Protection: " ), + _( "Cut Protection: " ), iteminfo::no_newline ) ); for( const std::pair< body_part, size_t > &element : bid->cut_protec ) { info.push_back( iteminfo( "CBM", body_part_name_as_heading( element.first, 1 ), @@ -3065,7 +3065,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } if( !bid->stat_bonus.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", _( "Stat Bonus: " ), + info.push_back( iteminfo( "DESCRIPTION", _( "Stat Bonus: " ), iteminfo::no_newline ) ); for( const auto &element : bid->stat_bonus ) { info.push_back( iteminfo( "CBM", get_stat_name( element.first ), " ", @@ -3185,7 +3185,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, if( !holsters.empty() && parts->test( iteminfo_parts::DESCRIPTION_HOLSTERS ) ) { insert_separation_line( info ); - info.emplace_back( "DESCRIPTION", _( "Can be stored in: " ) + + info.emplace_back( "DESCRIPTION", _( "Can be stored in: " ) + enumerate_as_string( holsters.begin(), holsters.end(), []( const itype * e ) { return e->nname( 1 ); From ada77975895970535b698b17f379a48cbce8e012 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Mon, 10 Feb 2020 19:56:10 -0700 Subject: [PATCH 02/51] Add item::armor_protection_info, item::armor_fit_info Factoring out armor-related info to (mostly) one place, via two new functions: - `armor_protection_info` (formerly duplicated at the end of both `armor_info` and `animal_armor_info`), showing bash/cut/acid/fire/env protection for the armor - `armor_fit_info` (formerly embedded in `final_info`) showing how well/poorly the armor fits, and reszability options Does not change display functionality at all; verified by `cata_test`. --- src/item.cpp | 413 +++++++++++++++++++++++++-------------------------- src/item.h | 4 + 2 files changed, 208 insertions(+), 209 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 2b1ab6ab8dd98..9e00d08146565 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2032,8 +2032,50 @@ void item::gunmod_info( std::vector &info, const iteminfo_query *parts } } -void item::armor_info( std::vector &info, const iteminfo_query *parts, int /* batch */, - bool /* debug */ ) const +void item::armor_protection_info( std::vector &info, const iteminfo_query *parts, + int /*batch*/, + bool /*debug*/ ) const +{ + if( !is_armor() && !is_pet_armor() ) { + return; + } + + const std::string space = " "; + + if( parts->test( iteminfo_parts::ARMOR_PROTECTION ) ) { + info.push_back( iteminfo( "ARMOR", _( "Protection: Bash: " ), "", + iteminfo::no_newline, bash_resist() ) ); + info.push_back( iteminfo( "ARMOR", space + _( "Cut: " ), cut_resist() ) ); + info.push_back( iteminfo( "ARMOR", space + _( "Acid: " ), "", + iteminfo::no_newline, acid_resist() ) ); + info.push_back( iteminfo( "ARMOR", space + _( "Fire: " ), "", + iteminfo::no_newline, fire_resist() ) ); + info.push_back( iteminfo( "ARMOR", space + _( "Environmental: " ), + get_base_env_resist( *this ) ) ); + if( type->can_use( "GASMASK" ) || type->can_use( "DIVE_TANK" ) ) { + info.push_back( iteminfo( "ARMOR", + _( "Protection when active: " ) ) ); + info.push_back( iteminfo( "ARMOR", space + _( "Acid: " ), "", + iteminfo::no_newline, + acid_resist( false, get_base_env_resist_w_filter() ) ) ); + info.push_back( iteminfo( "ARMOR", space + _( "Fire: " ), "", + iteminfo::no_newline, + fire_resist( false, get_base_env_resist_w_filter() ) ) ); + info.push_back( iteminfo( "ARMOR", space + _( "Environmental: " ), + get_env_resist( get_base_env_resist_w_filter() ) ) ); + } + + if( damage() > 0 ) { + info.push_back( iteminfo( "ARMOR", + _( "Protection values are reduced by damage and " + "you may be able to improve them by repairing this " + "item." ) ) ); + } + } +} + +void item::armor_info( std::vector &info, const iteminfo_query *parts, int batch, + bool debug ) const { if( !is_armor() ) { return; @@ -2183,36 +2225,10 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, // Whatever the last entry was, we want a newline at this point info.back().bNewLine = true; - if( parts->test( iteminfo_parts::ARMOR_PROTECTION ) && covers_anything ) { - info.push_back( iteminfo( "ARMOR", _( "Protection: Bash: " ), "", - iteminfo::no_newline, bash_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Cut: " ), cut_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Acid: " ), "", - iteminfo::no_newline, acid_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Fire: " ), "", - iteminfo::no_newline, fire_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Environmental: " ), - get_base_env_resist( *this ) ) ); - if( type->can_use( "GASMASK" ) || type->can_use( "DIVE_TANK" ) ) { - info.push_back( iteminfo( "ARMOR", - _( "Protection when active: " ) ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Acid: " ), "", - iteminfo::no_newline, - acid_resist( false, get_base_env_resist_w_filter() ) ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Fire: " ), "", - iteminfo::no_newline, - fire_resist( false, get_base_env_resist_w_filter() ) ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Environmental: " ), - get_env_resist( get_base_env_resist_w_filter() ) ) ); - } - - if( damage() > 0 ) { - info.push_back( iteminfo( "ARMOR", - _( "Protection values are reduced by damage and " - "you may be able to improve them by repairing this " - "item." ) ) ); - } + if( covers_anything ) { + armor_protection_info( info, parts, batch, debug ); } + const units::mass weight_bonus = get_weight_capacity_bonus(); const float weight_modif = get_weight_capacity_modifier(); if( weight_modif != 1 ) { @@ -2239,9 +2255,8 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, } } -void item::animal_armor_info( std::vector &info, const iteminfo_query *parts, - int /* batch */, - bool /* debug */ ) const +void item::animal_armor_info( std::vector &info, const iteminfo_query *parts, int batch, + bool debug ) const { if( !is_pet_armor() ) { return; @@ -2262,36 +2277,163 @@ void item::animal_armor_info( std::vector &info, const iteminfo_query // Whatever the last entry was, we want a newline at this point info.back().bNewLine = true; - if( parts->test( iteminfo_parts::ARMOR_PROTECTION ) ) { - info.push_back( iteminfo( "ARMOR", _( "Protection: Bash: " ), "", - iteminfo::no_newline, bash_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Cut: " ), cut_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Acid: " ), "", - iteminfo::no_newline, acid_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Fire: " ), "", - iteminfo::no_newline, fire_resist() ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Environmental: " ), - get_base_env_resist( *this ) ) ); - if( type->can_use( "GASMASK" ) || type->can_use( "DIVE_TANK" ) ) { - info.push_back( iteminfo( "ARMOR", - _( "Protection when active: " ) ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Acid: " ), "", - iteminfo::no_newline, - acid_resist( false, get_base_env_resist_w_filter() ) ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Fire: " ), "", - iteminfo::no_newline, - fire_resist( false, get_base_env_resist_w_filter() ) ) ); - info.push_back( iteminfo( "ARMOR", space + _( "Environmental: " ), - get_env_resist( get_base_env_resist_w_filter() ) ) ); + armor_protection_info( info, parts, batch, debug ); +} + +void item::armor_fit_info( std::vector &info, const iteminfo_query *parts, int /*batch*/, + bool /*debug*/ ) const +{ + if( !is_armor() ) { + return; + } + + int encumbrance = get_encumber( g->u ); + const sizing sizing_level = get_sizing( g->u, encumbrance != 0 ); + + if( has_flag( "HELMET_COMPAT" ) && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_HELMETCOMPAT ) ) { + info.push_back( iteminfo( "DESCRIPTION", + _( "* This item can be worn with a " + "helmet." ) ) ); + } + + if( parts->test( iteminfo_parts::DESCRIPTION_FLAGS_FITS ) ) { + switch( sizing_level ) { + case sizing::human_sized_human_char: + if( has_flag( "FIT" ) ) { + info.emplace_back( "DESCRIPTION", + _( "* This clothing fits you perfectly." ) ); + } + break; + case sizing::big_sized_big_char: + if( has_flag( "FIT" ) ) { + info.emplace_back( "DESCRIPTION", _( "* This clothing fits " + "your large frame perfectly." ) ); + } + break; + case sizing::small_sized_small_char: + if( has_flag( "FIT" ) ) { + info.emplace_back( "DESCRIPTION", _( "* This clothing fits " + "your small frame perfectly." ) ); + } + break; + case sizing::big_sized_human_char: + info.emplace_back( "DESCRIPTION", _( "* This clothing is oversized " + "and does not fit you." ) ); + break; + case sizing::big_sized_small_char: + info.emplace_back( "DESCRIPTION", + _( "* This clothing is hilariously oversized " + "and does not fit your abnormally " + "small mutated anatomy." ) ); + break; + case sizing::human_sized_big_char: + info.emplace_back( "DESCRIPTION", + _( "* This clothing is normal sized and does " + "not fit your abnormally large " + "mutated anatomy." ) ); + break; + case sizing::human_sized_small_char: + info.emplace_back( "DESCRIPTION", + _( "* This clothing is normal sized and does " + "not fit your abnormally small " + "mutated anatomy." ) ); + break; + case sizing::small_sized_big_char: + info.emplace_back( "DESCRIPTION", + _( "* This clothing is hilariously undersized " + "and does not fit your abnormally " + "large mutated anatomy." ) ); + break; + case sizing::small_sized_human_char: + info.emplace_back( "DESCRIPTION", _( "* This clothing is undersized " + "and does not fit you." ) ); + break; + default: + break; } + } - if( damage() > 0 ) { - info.push_back( iteminfo( "ARMOR", - _( "Protection values are reduced by damage and " - "you may be able to improve them by repairing this " - "item." ) ) ); + if( parts->test( iteminfo_parts::DESCRIPTION_FLAGS_VARSIZE ) ) { + if( has_flag( "VARSIZE" ) ) { + std::string resize_str; + if( has_flag( "FIT" ) ) { + switch( sizing_level ) { + case sizing::small_sized_human_char: + resize_str = _( "can be upsized" ); + break; + case sizing::human_sized_small_char: + resize_str = _( "can be downsized" ); + break; + case sizing::big_sized_human_char: + case sizing::big_sized_small_char: + resize_str = _( "can not be downsized" ); + break; + case sizing::small_sized_big_char: + case sizing::human_sized_big_char: + resize_str = _( "can not be upsized" ); + break; + default: + break; + } + if( !resize_str.empty() ) { + std::string info_str = string_format( _( "* This clothing %s." ), resize_str ); + info.push_back( iteminfo( "DESCRIPTION", info_str ) ); + } + } else { + switch( sizing_level ) { + case sizing::small_sized_human_char: + resize_str = _( " and upsized" ); + break; + case sizing::human_sized_small_char: + resize_str = _( " and downsized" ); + break; + case sizing::big_sized_human_char: + case sizing::big_sized_small_char: + resize_str = _( " but not downsized" ); + break; + case sizing::small_sized_big_char: + case sizing::human_sized_big_char: + resize_str = _( " but not upsized" ); + break; + default: + break; + } + std::string info_str = string_format( _( "* This clothing can be " + "refitted%s." ), resize_str ); + info.push_back( iteminfo( "DESCRIPTION", info_str ) ); + } + } else { + info.emplace_back( "DESCRIPTION", _( "* This clothing can not be refitted, " + "upsized, or downsized." ) ); + } + } + + if( is_sided() && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_SIDED ) ) { + info.push_back( iteminfo( "DESCRIPTION", + _( "* This item can be worn on either side of " + "the body." ) ) ); + } + if( is_power_armor() && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_POWERARMOR ) ) { + info.push_back( iteminfo( "DESCRIPTION", + _( "* This gear is a part of power armor." ) ) ); + if( parts->test( iteminfo_parts::DESCRIPTION_FLAGS_POWERARMOR_RADIATIONHINT ) ) { + if( covers( bp_head ) ) { + info.push_back( iteminfo( "DESCRIPTION", + _( "* When worn with a power armor suit, it will " + "fully protect you from " + "radiation." ) ) ); + } else { + info.push_back( iteminfo( "DESCRIPTION", + _( "* When worn with a power armor helmet, it will " + "fully protect you from " "radiation." ) ) ); + } } } + if( typeId() == "rad_badge" && parts->test( iteminfo_parts::DESCRIPTION_IRRADIATION ) ) { + info.push_back( iteminfo( "DESCRIPTION", + string_format( _( "* The film strip on the badge is %s." ), + rad_badge_color( irradiation ) ) ) ); + } } void item::book_info( std::vector &info, const iteminfo_query *parts, int /* batch */, @@ -2621,14 +2763,12 @@ void item::qualities_info( std::vector &info, const iteminfo_query *pa } void item::final_info( std::vector &info, const iteminfo_query *parts, int batch, - bool /*debug*/ ) const + bool debug ) const { if( is_null() ) { return; } - int encumbrance = get_encumber( g->u ); - const sizing sizing_level = get_sizing( g->u, encumbrance != 0 ); const std::string space = " "; std::set all_techniques = type->techniques; @@ -2781,152 +2921,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } } - if( is_armor() ) { - if( has_flag( "HELMET_COMPAT" ) && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_HELMETCOMPAT ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be worn with a " - "helmet." ) ) ); - } - - if( parts->test( iteminfo_parts::DESCRIPTION_FLAGS_FITS ) ) { - switch( sizing_level ) { - case sizing::human_sized_human_char: - if( has_flag( "FIT" ) ) { - info.emplace_back( "DESCRIPTION", - _( "* This clothing fits you perfectly." ) ); - } - break; - case sizing::big_sized_big_char: - if( has_flag( "FIT" ) ) { - info.emplace_back( "DESCRIPTION", _( "* This clothing fits " - "your large frame perfectly." ) ); - } - break; - case sizing::small_sized_small_char: - if( has_flag( "FIT" ) ) { - info.emplace_back( "DESCRIPTION", _( "* This clothing fits " - "your small frame perfectly." ) ); - } - break; - case sizing::big_sized_human_char: - info.emplace_back( "DESCRIPTION", _( "* This clothing is oversized " - "and does not fit you." ) ); - break; - case sizing::big_sized_small_char: - info.emplace_back( "DESCRIPTION", - _( "* This clothing is hilariously oversized " - "and does not fit your abnormally " - "small mutated anatomy." ) ); - break; - case sizing::human_sized_big_char: - info.emplace_back( "DESCRIPTION", - _( "* This clothing is normal sized and does " - "not fit your abnormally large " - "mutated anatomy." ) ); - break; - case sizing::human_sized_small_char: - info.emplace_back( "DESCRIPTION", - _( "* This clothing is normal sized and does " - "not fit your abnormally small " - "mutated anatomy." ) ); - break; - case sizing::small_sized_big_char: - info.emplace_back( "DESCRIPTION", - _( "* This clothing is hilariously undersized " - "and does not fit your abnormally " - "large mutated anatomy." ) ); - break; - case sizing::small_sized_human_char: - info.emplace_back( "DESCRIPTION", _( "* This clothing is undersized " - "and does not fit you." ) ); - break; - default: - break; - } - } - - if( parts->test( iteminfo_parts::DESCRIPTION_FLAGS_VARSIZE ) ) { - if( has_flag( "VARSIZE" ) ) { - std::string resize_str; - if( has_flag( "FIT" ) ) { - switch( sizing_level ) { - case sizing::small_sized_human_char: - resize_str = _( "can be upsized" ); - break; - case sizing::human_sized_small_char: - resize_str = _( "can be downsized" ); - break; - case sizing::big_sized_human_char: - case sizing::big_sized_small_char: - resize_str = _( "can not be downsized" ); - break; - case sizing::small_sized_big_char: - case sizing::human_sized_big_char: - resize_str = _( "can not be upsized" ); - break; - default: - break; - } - if( !resize_str.empty() ) { - std::string info_str = string_format( _( "* This clothing %s." ), resize_str ); - info.push_back( iteminfo( "DESCRIPTION", info_str ) ); - } - } else { - switch( sizing_level ) { - case sizing::small_sized_human_char: - resize_str = _( " and upsized" ); - break; - case sizing::human_sized_small_char: - resize_str = _( " and downsized" ); - break; - case sizing::big_sized_human_char: - case sizing::big_sized_small_char: - resize_str = _( " but not downsized" ); - break; - case sizing::small_sized_big_char: - case sizing::human_sized_big_char: - resize_str = _( " but not upsized" ); - break; - default: - break; - } - std::string info_str = string_format( _( "* This clothing can be " - "refitted%s." ), resize_str ); - info.push_back( iteminfo( "DESCRIPTION", info_str ) ); - } - } else { - info.emplace_back( "DESCRIPTION", _( "* This clothing can not be refitted, " - "upsized, or downsized." ) ); - } - } - - if( is_sided() && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_SIDED ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be worn on either side of " - "the body." ) ) ); - } - if( is_power_armor() && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_POWERARMOR ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This gear is a part of power armor." ) ) ); - if( parts->test( iteminfo_parts::DESCRIPTION_FLAGS_POWERARMOR_RADIATIONHINT ) ) { - if( covers( bp_head ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* When worn with a power armor suit, it will " - "fully protect you from " - "radiation." ) ) ); - } else { - info.push_back( iteminfo( "DESCRIPTION", - _( "* When worn with a power armor helmet, it will " - "fully protect you from " "radiation." ) ) ); - } - } - } - if( typeId() == "rad_badge" && parts->test( iteminfo_parts::DESCRIPTION_IRRADIATION ) ) { - info.push_back( iteminfo( "DESCRIPTION", - string_format( _( "* The film strip on the badge is %s." ), - rad_badge_color( irradiation ) ) ) ); - } - } + armor_fit_info( info, parts, batch, debug ); if( is_tool() ) { if( has_flag( "USE_UPS" ) && parts->test( iteminfo_parts::DESCRIPTION_RECHARGE_UPSMODDED ) ) { diff --git a/src/item.h b/src/item.h index fa349b8b2d05c..6c4e3701eb016 100644 --- a/src/item.h +++ b/src/item.h @@ -403,10 +403,14 @@ class item : public visitable bool debug ) const; void gunmod_info( std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const; + void armor_protection_info( std::vector &info, const iteminfo_query *parts, int batch, + bool debug ) const; void armor_info( std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const; void animal_armor_info( std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const; + void armor_fit_info( std::vector &info, const iteminfo_query *parts, int batch, + bool debug ) const; void book_info( std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const; void battery_info( std::vector &info, const iteminfo_query *parts, int batch, From 6ed87aee0696485b7cdf93ca27ab8e6a4ae9f90f Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Mon, 10 Feb 2020 20:18:54 -0700 Subject: [PATCH 03/51] Factor out `item::bionic_info` Readability --- src/item.cpp | 230 +++++++++++++++++++++++++++------------------------ src/item.h | 2 + 2 files changed, 122 insertions(+), 110 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 9e00d08146565..ce5ecde73286f 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2762,6 +2762,125 @@ void item::qualities_info( std::vector &info, const iteminfo_query *pa } } +void item::bionic_info( std::vector &info, const iteminfo_query *parts, int /*batch*/, + bool /*debug*/ ) const +{ + if( !is_bionic() ) { + return; + } + + // TODO: Unhide when enforcing limits + if( get_option < bool >( "CBM_SLOTS_ENABLED" ) + && parts->test( iteminfo_parts::DESCRIPTION_CBM_SLOTS ) ) { + info.push_back( iteminfo( "DESCRIPTION", list_occupied_bps( type->bionic->id, + _( "This bionic is installed in the following body " + "part(s):" ) ) ) ); + } + insert_separation_line( info ); + + if( is_bionic() && has_flag( "NO_STERILE" ) ) { + info.push_back( iteminfo( "DESCRIPTION", + _( "* This bionic is not sterile, use an autoclave and an autoclave pouch to sterilize it. " ) ) ); + } + insert_separation_line( info ); + + const bionic_id bid = type->bionic->id; + const std::vector &fuels = bid->fuel_opts; + if( !fuels.empty() ) { + const int &fuel_numb = fuels.size(); + + info.push_back( iteminfo( "DESCRIPTION", + ngettext( "* This bionic can produce power from the following fuel: ", + "* This bionic can produce power from the following fuels: ", + fuel_numb ) + enumerate_as_string( fuels.begin(), + fuels.end(), []( const itype_id & id ) -> std::string { return "" + item_controller->find_template( id )->nname( 1 ) + ""; } ) ) ); + } + + insert_separation_line( info ); + + if( bid->capacity > 0_mJ ) { + info.push_back( iteminfo( "CBM", _( "Power Capacity:" ), _( " mJ" ), + iteminfo::no_newline, + units::to_millijoule( bid->capacity ) ) ); + } + + insert_separation_line( info ); + + if( !bid->encumbrance.empty() ) { + info.push_back( iteminfo( "DESCRIPTION", _( "Encumbrance: " ), + iteminfo::no_newline ) ); + for( const auto &element : bid->encumbrance ) { + info.push_back( iteminfo( "CBM", body_part_name_as_heading( element.first, 1 ), + " ", iteminfo::no_newline, element.second ) ); + } + } + + if( !bid->env_protec.empty() ) { + info.push_back( iteminfo( "DESCRIPTION", + _( "Environmental Protection: " ), + iteminfo::no_newline ) ); + for( const std::pair< body_part, size_t > &element : bid->env_protec ) { + info.push_back( iteminfo( "CBM", body_part_name_as_heading( element.first, 1 ), + " ", iteminfo::no_newline, element.second ) ); + } + } + + if( !bid->bash_protec.empty() ) { + info.push_back( iteminfo( "DESCRIPTION", + _( "Bash Protection: " ), + iteminfo::no_newline ) ); + for( const std::pair< body_part, size_t > &element : bid->bash_protec ) { + info.push_back( iteminfo( "CBM", body_part_name_as_heading( element.first, 1 ), + " ", iteminfo::no_newline, element.second ) ); + } + } + + if( !bid->cut_protec.empty() ) { + info.push_back( iteminfo( "DESCRIPTION", + _( "Cut Protection: " ), + iteminfo::no_newline ) ); + for( const std::pair< body_part, size_t > &element : bid->cut_protec ) { + info.push_back( iteminfo( "CBM", body_part_name_as_heading( element.first, 1 ), + " ", iteminfo::no_newline, element.second ) ); + } + } + + if( !bid->stat_bonus.empty() ) { + info.push_back( iteminfo( "DESCRIPTION", _( "Stat Bonus: " ), + iteminfo::no_newline ) ); + for( const auto &element : bid->stat_bonus ) { + info.push_back( iteminfo( "CBM", get_stat_name( element.first ), " ", + iteminfo::no_newline, element.second ) ); + } + } + + const units::mass weight_bonus = bid->weight_capacity_bonus; + const float weight_modif = bid->weight_capacity_modifier; + if( weight_modif != 1 ) { + std::string modifier; + if( weight_modif < 1 ) { + modifier = "x"; + } else { + modifier = "x"; + } + info.push_back( iteminfo( "CBM", + _( "Weight capacity modifier: " ), modifier, + iteminfo::no_newline | iteminfo::is_decimal, + weight_modif ) ); + } + if( weight_bonus != 0_gram ) { + std::string bonus; + if( weight_bonus < 0_gram ) { + bonus = string_format( " %s", weight_units() ); + } else { + bonus = string_format( " %s", weight_units() ); + } + info.push_back( iteminfo( "CBM", _( "Weight capacity bonus: " ), bonus, + iteminfo::no_newline | iteminfo::is_decimal, + convert_weight( weight_bonus ) ) ); + } +} + void item::final_info( std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const { @@ -2983,117 +3102,8 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } } - // TODO: Unhide when enforcing limits - if( is_bionic() ) { - if( get_option < bool >( "CBM_SLOTS_ENABLED" ) - && parts->test( iteminfo_parts::DESCRIPTION_CBM_SLOTS ) ) { - info.push_back( iteminfo( "DESCRIPTION", list_occupied_bps( type->bionic->id, - _( "This bionic is installed in the following body " - "part(s):" ) ) ) ); - } - insert_separation_line( info ); + bionic_info( info, parts, batch, debug ); - if( is_bionic() && has_flag( "NO_STERILE" ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This bionic is not sterile, use an autoclave and an autoclave pouch to sterilize it. " ) ) ); - } - insert_separation_line( info ); - - const bionic_id bid = type->bionic->id; - const std::vector &fuels = bid->fuel_opts; - if( !fuels.empty() ) { - const int &fuel_numb = fuels.size(); - - info.push_back( iteminfo( "DESCRIPTION", - ngettext( "* This bionic can produce power from the following fuel: ", - "* This bionic can produce power from the following fuels: ", - fuel_numb ) + enumerate_as_string( fuels.begin(), - fuels.end(), []( const itype_id & id ) -> std::string { return "" + item_controller->find_template( id )->nname( 1 ) + ""; } ) ) ); - } - - insert_separation_line( info ); - - if( bid->capacity > 0_mJ ) { - info.push_back( iteminfo( "CBM", _( "Power Capacity:" ), _( " mJ" ), - iteminfo::no_newline, - units::to_millijoule( bid->capacity ) ) ); - } - - insert_separation_line( info ); - - if( !bid->encumbrance.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", _( "Encumbrance: " ), - iteminfo::no_newline ) ); - for( const auto &element : bid->encumbrance ) { - info.push_back( iteminfo( "CBM", body_part_name_as_heading( element.first, 1 ), - " ", iteminfo::no_newline, element.second ) ); - } - } - - if( !bid->env_protec.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "Environmental Protection: " ), - iteminfo::no_newline ) ); - for( const std::pair< body_part, size_t > &element : bid->env_protec ) { - info.push_back( iteminfo( "CBM", body_part_name_as_heading( element.first, 1 ), - " ", iteminfo::no_newline, element.second ) ); - } - } - - if( !bid->bash_protec.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "Bash Protection: " ), - iteminfo::no_newline ) ); - for( const std::pair< body_part, size_t > &element : bid->bash_protec ) { - info.push_back( iteminfo( "CBM", body_part_name_as_heading( element.first, 1 ), - " ", iteminfo::no_newline, element.second ) ); - } - } - if( !bid->cut_protec.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "Cut Protection: " ), - iteminfo::no_newline ) ); - for( const std::pair< body_part, size_t > &element : bid->cut_protec ) { - info.push_back( iteminfo( "CBM", body_part_name_as_heading( element.first, 1 ), - " ", iteminfo::no_newline, element.second ) ); - } - } - - if( !bid->stat_bonus.empty() ) { - info.push_back( iteminfo( "DESCRIPTION", _( "Stat Bonus: " ), - iteminfo::no_newline ) ); - for( const auto &element : bid->stat_bonus ) { - info.push_back( iteminfo( "CBM", get_stat_name( element.first ), " ", - iteminfo::no_newline, element.second ) ); - } - } - - const units::mass weight_bonus = bid->weight_capacity_bonus; - const float weight_modif = bid->weight_capacity_modifier; - if( weight_modif != 1 ) { - std::string modifier; - if( weight_modif < 1 ) { - modifier = "x"; - } else { - modifier = "x"; - } - info.push_back( iteminfo( "CBM", - _( "Weight capacity modifier: " ), modifier, - iteminfo::no_newline | iteminfo::is_decimal, - weight_modif ) ); - } - if( weight_bonus != 0_gram ) { - std::string bonus; - if( weight_bonus < 0_gram ) { - bonus = string_format( " %s", weight_units() ); - } else { - bonus = string_format( " %s", weight_units() ); - } - info.push_back( iteminfo( "CBM", _( "Weight capacity bonus: " ), bonus, - iteminfo::no_newline | iteminfo::is_decimal, - convert_weight( weight_bonus ) ) ); - } - } if( is_gun() && has_flag( "FIRE_TWOHAND" ) && parts->test( iteminfo_parts::DESCRIPTION_TWOHANDED ) ) { diff --git a/src/item.h b/src/item.h index 6c4e3701eb016..95055a8897463 100644 --- a/src/item.h +++ b/src/item.h @@ -425,6 +425,8 @@ class item : public visitable bool debug ) const; void qualities_info( std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const; + void bionic_info( std::vector &info, const iteminfo_query *parts, int batch, + bool debug ) const; void final_info( std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const; From 0385b06ea7a1cdcbc425721484e30622368cdc0d Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Mon, 10 Feb 2020 20:24:10 -0700 Subject: [PATCH 04/51] Fix spelling of INCENDIARY --- src/item.cpp | 3 +-- src/iteminfo_query.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index ce5ecde73286f..91a8af34b2302 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1624,7 +1624,7 @@ void item::ammo_info( std::vector &info, const iteminfo_query *parts, fx.emplace_back( _( "This ammo never misfires." ) ); } if( ammo.ammo_effects.count( "INCENDIARY" ) && - parts->test( iteminfo_parts::AMMO_FX_INDENDIARY ) ) { + parts->test( iteminfo_parts::AMMO_FX_INCENDIARY ) ) { fx.emplace_back( _( "This ammo starts fires." ) ); } if( !fx.empty() ) { @@ -3104,7 +3104,6 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, bionic_info( info, parts, batch, debug ); - if( is_gun() && has_flag( "FIRE_TWOHAND" ) && parts->test( iteminfo_parts::DESCRIPTION_TWOHANDED ) ) { info.push_back( iteminfo( "DESCRIPTION", diff --git a/src/iteminfo_query.h b/src/iteminfo_query.h index 29c27d3d2c987..d7f89184cd4ab 100644 --- a/src/iteminfo_query.h +++ b/src/iteminfo_query.h @@ -54,7 +54,7 @@ enum class iteminfo_parts : size_t { AMMO_FX_RECYCLED, AMMO_FX_BLACKPOWDER, AMMO_FX_CANTMISSFIRE, - AMMO_FX_INDENDIARY, + AMMO_FX_INCENDIARY, DESCRIPTION_AUX_GUNMOD_HEADER, From a5ec129a8a7a31a309481570bfdbbe7e5998f1fa Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Wed, 12 Feb 2020 20:51:51 -0700 Subject: [PATCH 05/51] Adjust iteminfo tests to put colon after heading --- tests/iteminfo_test.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 832badc57868c..e723f2aa4dc10 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -60,9 +60,9 @@ TEST_CASE( "techniques when wielded", "[item][iteminfo]" ) item( "halligan" ), q, "--\n" "Techniques when wielded:" - " Brutal Strike: Stun 1 turn, knockback 1 tile, crit only," - " Sweep Attack: Down 2 turns, and" - " Block: Medium blocking ability\n" ); + " Brutal Strike: Stun 1 turn, knockback 1 tile, crit only," + " Sweep Attack: Down 2 turns, and" + " Block: Medium blocking ability\n" ); } @@ -103,7 +103,7 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo]" ) iteminfo_test( item( "compbow" ), q, "--\n" - "Capacity: 1 round of arrows\n" ); + "Capacity: 1 round of arrows\n" ); } SECTION( "default ammo when unloaded" ) { @@ -138,7 +138,7 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo]" ) iteminfo_test( item( "compbow" ), q, "--\n" - "Fire modes: manual (1)\n" ); + "Fire modes: manual (1)\n" ); } SECTION( "weapon mods" ) { @@ -146,7 +146,7 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo]" ) iteminfo_test( item( "compbow" ), q, "--\n" - "Mods: 0/2 accessories;" + "Mods: 0/2 accessories;" " 0/1 dampening; 0/1 sights;" " 0/1 stabilizer; 0/1 underbarrel.\n" ); } From b0c1822279fcd300d03c9cbb4ec7824dd98ff1df Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Wed, 12 Feb 2020 21:17:15 -0700 Subject: [PATCH 06/51] Factor out item::repair_info For modularity and symmetry with disassembly_info --- src/item.cpp | 40 +++++++++++++++++++++++----------------- src/item.h | 2 ++ 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 91a8af34b2302..b21d328a1853d 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2691,6 +2691,28 @@ void item::component_info( std::vector &info, const iteminfo_query *pa } } +void item::repair_info( std::vector &info, const iteminfo_query *parts, + int /*batch*/, bool /*debug*/ ) const +{ + if( parts->test( iteminfo_parts::DESCRIPTION_REPAIREDWITH ) ) { + return; + } + insert_separation_line( info ); + const std::set &rep = repaired_with(); + if( !rep.empty() ) { + info.emplace_back( "DESCRIPTION", _( "Repaired with: " ) + + enumerate_as_string( rep.begin(), rep.end(), []( const itype_id & e ) { + return nname( e ); + }, enumeration_conjunction::or_ ) ); + if( reinforceable() ) { + info.emplace_back( "DESCRIPTION", _( "* This item can be " + "reinforced." ) ); + } + } else { + info.emplace_back( "DESCRIPTION", _( "* This item is not repairable." ) ); + } +} + void item::disassembly_info( std::vector &info, const iteminfo_query *parts, int /*batch*/, bool /*debug*/ ) const { @@ -2981,23 +3003,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } } - if( parts->test( iteminfo_parts::DESCRIPTION_REPAIREDWITH ) ) { - insert_separation_line( info ); - const std::set &rep = repaired_with(); - if( !rep.empty() ) { - info.emplace_back( "DESCRIPTION", _( "Repaired with: " ) + - enumerate_as_string( rep.begin(), rep.end(), []( const itype_id & e ) { - return nname( e ); - }, enumeration_conjunction::or_ ) ); - insert_separation_line( info ); - if( reinforceable() ) { - info.emplace_back( "DESCRIPTION", _( "* This item can be " - "reinforced." ) ); - } - } else { - info.emplace_back( "DESCRIPTION", _( "* This item is not repairable." ) ); - } - } + repair_info( info, parts, batch, debug ); if( parts->test( iteminfo_parts::DESCRIPTION_CONDUCTIVITY ) ) { if( !conductive() ) { diff --git a/src/item.h b/src/item.h index 95055a8897463..ff11f0bcef76b 100644 --- a/src/item.h +++ b/src/item.h @@ -421,6 +421,8 @@ class item : public visitable bool debug ) const; void component_info( std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const; + void repair_info( std::vector &info, const iteminfo_query *parts, int batch, + bool debug ) const; void disassembly_info( std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const; void qualities_info( std::vector &info, const iteminfo_query *parts, int batch, From b6d8aeb4b07581e1620369bc11d38fcd5bfb91d0 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Thu, 13 Feb 2020 16:02:41 -0700 Subject: [PATCH 07/51] Fix repair_info backwards logic The repair_info function was incorrectly returning only IF the item is repairable. It should be the opposite. --- src/item.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/item.cpp b/src/item.cpp index b21d328a1853d..8e289438f58a2 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2694,7 +2694,7 @@ void item::component_info( std::vector &info, const iteminfo_query *pa void item::repair_info( std::vector &info, const iteminfo_query *parts, int /*batch*/, bool /*debug*/ ) const { - if( parts->test( iteminfo_parts::DESCRIPTION_REPAIREDWITH ) ) { + if( !parts->test( iteminfo_parts::DESCRIPTION_REPAIREDWITH ) ) { return; } insert_separation_line( info ); From 1b7be85278f976578dd32f66e3b594ab73c26ee9 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Fri, 14 Feb 2020 16:06:31 -0700 Subject: [PATCH 08/51] Regroup qualities, repair, and diassembly Qualities are somewhat more important than repair or disassembly; this moves item qualities above both of them. Repair and disassembly attributes were sometimes widely separated; they are conceptually similar and belong together. Their headings are now similarly formatted as well, changing this: Repaired with: ... Disassembling this item takes ... and might yield ... to this: Repair: using ... Disassembly: takes ... and might yield ... Finally, adds some tags to the iteminfo tests for more granular control over which tests run. --- src/item.cpp | 17 ++++++------ tests/iteminfo_test.cpp | 58 +++++++++++++++++++++++++++++++++-------- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 8e289438f58a2..8ec3d71d17c60 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2700,7 +2700,7 @@ void item::repair_info( std::vector &info, const iteminfo_query *parts insert_separation_line( info ); const std::set &rep = repaired_with(); if( !rep.empty() ) { - info.emplace_back( "DESCRIPTION", _( "Repaired with: " ) + + info.emplace_back( "DESCRIPTION", _( "Repair: using " ) + enumerate_as_string( rep.begin(), rep.end(), []( const itype_id & e ) { return nname( e ); }, enumeration_conjunction::or_ ) ); @@ -2719,19 +2719,21 @@ void item::disassembly_info( std::vector &info, const iteminfo_query * if( !components.empty() && parts->test( iteminfo_parts::DESCRIPTION_COMPONENTS_MADEFROM ) ) { return; } + if( !parts->test( iteminfo_parts::DESCRIPTION_COMPONENTS_DISASSEMBLE ) ) { + return; + } + const recipe &dis = recipe_dictionary::get_uncraft( typeId() ); const requirement_data &req = dis.disassembly_requirements(); - if( !req.is_empty() && - parts->test( iteminfo_parts::DESCRIPTION_COMPONENTS_DISASSEMBLE ) ) { + if( !req.is_empty() ) { const requirement_data::alter_item_comp_vector &components = req.get_components(); const std::string components_list = enumerate_as_string( components.begin(), components.end(), []( const std::vector &comps ) { return comps.front().to_string(); } ); - insert_separation_line( info ); info.push_back( iteminfo( "DESCRIPTION", - string_format( _( "Disassembling this item takes %s and " + string_format( _( "Disassembly: takes %s and " "might yield: %s." ), to_string_approx( time_duration::from_turns( dis.time / 100 ) ), components_list ) ) ); @@ -3003,8 +3005,6 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } } - repair_info( info, parts, batch, debug ); - if( parts->test( iteminfo_parts::DESCRIPTION_CONDUCTIVITY ) ) { if( !conductive() ) { info.push_back( iteminfo( "BASE", _( "* This item does not " @@ -3406,8 +3406,9 @@ std::string item::info( std::vector &info, const iteminfo_query *parts battery_info( info, parts, batch, debug ); tool_info( info, parts, batch, debug ); component_info( info, parts, batch, debug ); - disassembly_info( info, parts, batch, debug ); qualities_info( info, parts, batch, debug ); + repair_info( info, parts, batch, debug ); + disassembly_info( info, parts, batch, debug ); final_info( info, parts, batch, debug ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index e723f2aa4dc10..99df46c978e20 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -37,7 +37,7 @@ TEST_CASE( "item description and physical attributes", "[item][iteminfo]" ) } -TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo]" ) +TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) { iteminfo_query q( { iteminfo_parts::BASE_DAMAGE, iteminfo_parts::BASE_TOHIT, iteminfo_parts::BASE_MOVES @@ -52,7 +52,7 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo]" ) } -TEST_CASE( "techniques when wielded", "[item][iteminfo]" ) +TEST_CASE( "techniques when wielded", "[item][iteminfo][weapon]" ) { iteminfo_query q( { iteminfo_parts::DESCRIPTION_TECHNIQUES } ); @@ -66,7 +66,7 @@ TEST_CASE( "techniques when wielded", "[item][iteminfo]" ) } -TEST_CASE( "armor coverage and protection values", "[item][iteminfo]" ) +TEST_CASE( "armor coverage and protection values", "[item][iteminfo][armor]" ) { iteminfo_query q( { iteminfo_parts::ARMOR_BODYPARTS, iteminfo_parts::ARMOR_LAYER, iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH, @@ -96,7 +96,7 @@ TEST_CASE( "armor coverage and protection values", "[item][iteminfo]" ) } } -TEST_CASE( "ranged weapon attributes", "[item][iteminfo]" ) +TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged]" ) { SECTION( "ammo capacity" ) { iteminfo_query q( { iteminfo_parts::GUN_CAPACITY } ); @@ -153,7 +153,7 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo]" ) } -TEST_CASE( "nutrients in food", "[item][iteminfo]" ) +TEST_CASE( "nutrients in food", "[item][iteminfo][food]" ) { iteminfo_query q( { iteminfo_parts::FOOD_NUTRITION, iteminfo_parts::FOOD_VITAMINS, iteminfo_parts::FOOD_QUENCH @@ -182,7 +182,7 @@ TEST_CASE( "nutrients in food", "[item][iteminfo]" ) } } -TEST_CASE( "food freshness and lifetime", "[item][iteminfo]" ) +TEST_CASE( "food freshness and lifetime", "[item][iteminfo][food]" ) { iteminfo_query q( { iteminfo_parts::FOOD_ROT } ); @@ -213,7 +213,7 @@ TEST_CASE( "food freshness and lifetime", "[item][iteminfo]" ) } -TEST_CASE( "item conductivity", "[item][iteminfo]" ) +TEST_CASE( "item conductivity", "[item][iteminfo][conductivity]" ) { iteminfo_query q( { iteminfo_parts::DESCRIPTION_CONDUCTIVITY } ); @@ -240,7 +240,7 @@ TEST_CASE( "item conductivity", "[item][iteminfo]" ) } } -TEST_CASE( "list of item qualities", "[item][iteminfo]" ) +TEST_CASE( "list of item qualities", "[item][iteminfo][quality]" ) { iteminfo_query q( { iteminfo_parts::QUALITIES } ); @@ -269,24 +269,60 @@ TEST_CASE( "list of item qualities", "[item][iteminfo]" ) } } -TEST_CASE( "repairable and with what tools", "[item][iteminfo]" ) +TEST_CASE( "repairable and with what tools", "[item][iteminfo][repair]" ) { iteminfo_query q( { iteminfo_parts::DESCRIPTION_REPAIREDWITH } ); iteminfo_test( item( "halligan" ), q, "--\n" - "Repaired with: extended toolset, arc welder, or makeshift arc welder\n" ); + "Repair: using extended toolset, arc welder, or makeshift arc welder\n" ); iteminfo_test( item( "hazmat_suit" ), q, "--\n" - "Repaired with: soldering iron or extended toolset\n" ); + "Repair: using soldering iron or extended toolset\n" ); iteminfo_test( item( "rock" ), q, "--\n" "* This item is not repairable.\n" ); + + /* + iteminfo_test( + item( "socks" ), q, + "--\n" + "* This item can be reinforced.\n" ); + */ +} + +TEST_CASE( "disassembly time and yield", "[item][iteminfo][disassembly]" ) +{ + iteminfo_query q( { iteminfo_parts::DESCRIPTION_COMPONENTS_DISASSEMBLE } ); + + // long string + iteminfo_test( + item( "string_36" ), q, + "--\n" + "Disassembly: takes about 5 minutes and might yield: 6 short strings.\n" ); + + // short string + iteminfo_test( + item( "string_6" ), q, + "--\n" + "Disassembly: takes about 5 minutes and might yield: thread (50).\n" ); + + iteminfo_test( + item( "sheet_metal" ), q, + "--\n" + "Disassembly: takes about 2 minutes and might yield: small metal sheet (24).\n" ); + + iteminfo_test( + item( "soldering_iron" ), q, + "--\n" + "Disassembly: takes about 20 minutes and might yield:" + " 2 electronic scraps, copper (1), scrap metal (1), and copper wire (5).\n" ); + } TEST_CASE( "item description flags", "[item][iteminfo]" ) From 8aba39675011ae1421f16988cd1e450c52610f3e Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Fri, 14 Feb 2020 17:10:47 -0700 Subject: [PATCH 09/51] Move separator above conductivity To keep conductivity (and wool allergy while we're at it) in the same section with the other flags --- src/item.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 8ec3d71d17c60..0f033f0bc380e 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -3005,6 +3005,8 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } } + insert_separation_line( info ); + if( parts->test( iteminfo_parts::DESCRIPTION_CONDUCTIVITY ) ) { if( !conductive() ) { info.push_back( iteminfo( "BASE", _( "* This item does not " @@ -3018,11 +3020,6 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } } - bool anyFlags = ( *parts & iteminfo_query::anyflags ).any(); - if( anyFlags ) { - insert_separation_line( info ); - } - if( is_armor() && g->u.has_trait( trait_id( "WOOLALLERGY" ) ) && ( made_of( material_id( "wool" ) ) || item_tags.count( "wooled" ) ) ) { info.push_back( iteminfo( "DESCRIPTION", From 7c603a30720b12812bc9aab60af13deea51786d9 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Fri, 14 Feb 2020 17:13:56 -0700 Subject: [PATCH 10/51] Un-bold 'Volume' in item description Volume is not more important than other labels in this section and doesn't need to be bold. --- src/item.cpp | 2 +- tests/iteminfo_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 0f033f0bc380e..53ac9d929d992 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1174,7 +1174,7 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, if( converted_volume_scale != 0 ) { f |= iteminfo::is_three_decimal; } - info.push_back( iteminfo( "BASE", _( "Volume: " ), + info.push_back( iteminfo( "BASE", _( "Volume: " ), string_format( " %s", volume_units_abbr() ), f, converted_volume ) ); } diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 99df46c978e20..99f038a84539c 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -30,7 +30,7 @@ TEST_CASE( "item description and physical attributes", "[item][iteminfo]" ) "A standard plastic jug used for milk and household cleaning chemicals.\n" "--\n" "Category: CONTAINERS Price: $0.00\n" - "Volume: 3.750 L" + "Volume: 3.750 L" " Weight: 0.42 lbs\n" "--\n" "Material: Plastic\n" ); From 8acd907141bf2e2cd4b459e74e0285599ceb7a8d Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Fri, 14 Feb 2020 17:14:55 -0700 Subject: [PATCH 11/51] Add quality test for scissor jack Jacking quality is handled separately from other qualities; good to include a test case for it. --- tests/iteminfo_test.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 99f038a84539c..42cc3f4a4dc86 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -267,6 +267,13 @@ TEST_CASE( "list of item qualities", "[item][iteminfo][quality]" ) "Has level 2 hammering quality.\n" "Has level 4 prying quality.\n" ); } + + SECTION( "bottle jack" ) { + iteminfo_test( + item( "jack_small" ), q, + "--\n" + "Has level 4 jacking quality and is rated at 4409 lbs\n" ); + } } TEST_CASE( "repairable and with what tools", "[item][iteminfo][repair]" ) From aa5c368938d7e0b6469291b49e8d2a931ecfd349 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Fri, 14 Feb 2020 17:25:44 -0700 Subject: [PATCH 12/51] Move Material under Volume/Weight/Rigidity Looks better having material with other physical attributes instead of with offensive combat ratings. --- src/item.cpp | 26 ++++++++++++++------------ tests/iteminfo_test.cpp | 4 +--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 53ac9d929d992..35b2cdc02c85c 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1166,10 +1166,10 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, static_cast( price_postapoc ) / 100 ) ); } - int converted_volume_scale = 0; - const double converted_volume = round_up( convert_volume( volume().value(), - &converted_volume_scale ) * batch, 3 ); if( parts->test( iteminfo_parts::BASE_VOLUME ) ) { + int converted_volume_scale = 0; + const double converted_volume = round_up( convert_volume( volume().value(), + &converted_volume_scale ) * batch, 3 ); iteminfo::flags f = iteminfo::lower_is_better | iteminfo::no_newline; if( converted_volume_scale != 0 ) { f |= iteminfo::is_three_decimal; @@ -1184,11 +1184,21 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, iteminfo::lower_is_better | iteminfo::is_decimal, convert_weight( weight() ) * batch ) ); } - if( !type->rigid && parts->test( iteminfo_parts::BASE_RIGIDITY ) ) { info.emplace_back( "BASE", _( "Rigid: " ), _( "No (contents increase volume)" ) ); } + if( parts->test( iteminfo_parts::BASE_MATERIAL ) ) { + const std::vector mat_types = made_of_types(); + if( !mat_types.empty() ) { + const std::string material_list = enumerate_as_string( mat_types.begin(), mat_types.end(), + []( const material_type * material ) { + return string_format( "%s", _( material->name() ) ); + }, enumeration_conjunction::none ); + info.push_back( iteminfo( "BASE", string_format( _( "Material: %s" ), material_list ) ) ); + } + } + int dmg_bash = damage_melee( DT_BASH ); int dmg_cut = damage_melee( DT_CUT ); @@ -1247,14 +1257,6 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, } } - const std::vector mat_types = made_of_types(); - if( !mat_types.empty() && parts->test( iteminfo_parts::BASE_MATERIAL ) ) { - const std::string material_list = enumerate_as_string( mat_types.begin(), mat_types.end(), - []( const material_type * material ) { - return string_format( "%s", _( material->name() ) ); - }, enumeration_conjunction::none ); - info.push_back( iteminfo( "BASE", string_format( _( "Material: %s" ), material_list ) ) ); - } if( !owner.is_null() ) { info.push_back( iteminfo( "BASE", string_format( _( "Owner: %s" ), _( get_owner_name() ) ) ) ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 42cc3f4a4dc86..c6fad9be37d7e 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -30,9 +30,7 @@ TEST_CASE( "item description and physical attributes", "[item][iteminfo]" ) "A standard plastic jug used for milk and household cleaning chemicals.\n" "--\n" "Category: CONTAINERS Price: $0.00\n" - "Volume: 3.750 L" - " Weight: 0.42 lbs\n" - "--\n" + "Volume: 3.750 L Weight: 0.42 lbs\n" "Material: Plastic\n" ); } From 4d09927cb220f4ed60cdeb23cb974d5246703fbb Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Fri, 14 Feb 2020 18:50:41 -0700 Subject: [PATCH 13/51] Include rigidity for rigid items; rephrase & test A big bold "Rigid" heading was displayed always and only for NON-rigid items, which seemed a little counterintuitive. Removed the boldness, and added a message for rigid items too, along with an explanation for both, e.g. Rigid: Volume and encumbrance are constant. Not rigid: Volume and encumbrance increase when filled. Added test cases (rigid briefcase, non-rigid backpack). --- src/item.cpp | 13 ++++++++----- tests/iteminfo_test.cpp | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 35b2cdc02c85c..632a76c389957 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1184,10 +1184,6 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, iteminfo::lower_is_better | iteminfo::is_decimal, convert_weight( weight() ) * batch ) ); } - if( !type->rigid && parts->test( iteminfo_parts::BASE_RIGIDITY ) ) { - info.emplace_back( "BASE", _( "Rigid: " ), - _( "No (contents increase volume)" ) ); - } if( parts->test( iteminfo_parts::BASE_MATERIAL ) ) { const std::vector mat_types = made_of_types(); if( !mat_types.empty() ) { @@ -1198,7 +1194,14 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, info.push_back( iteminfo( "BASE", string_format( _( "Material: %s" ), material_list ) ) ); } } - + if( parts->test( iteminfo_parts::BASE_RIGIDITY ) ) { + if( type->rigid ) { + info.emplace_back( "BASE", _( "Rigid: Volume and encumbrance are constant." ) ); + } else { + info.emplace_back( "BASE", + _( "Not rigid: Volume and encumbrance increase when filled." ) ); + } + } int dmg_bash = damage_melee( DT_BASH ); int dmg_cut = damage_melee( DT_CUT ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index c6fad9be37d7e..104d81ef739df 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -35,6 +35,23 @@ TEST_CASE( "item description and physical attributes", "[item][iteminfo]" ) } +TEST_CASE( "item rigidity", "[item][iteminfo][rigidity]" ) +{ + iteminfo_query q( { iteminfo_parts::BASE_RIGIDITY } ); + + SECTION( "rigid items indicate constant volume/encumbrance" ) { + iteminfo_test( + item( "briefcase" ), q, + "Rigid: Volume and encumbrance are constant.\n" ); + } + + SECTION( "non-rigid items indicate flexible volume/encumbrance" ) { + iteminfo_test( + item( "backpack" ), q, + "Not rigid: Volume and encumbrance increase when filled.\n" ); + } +} + TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) { iteminfo_query q( { iteminfo_parts::BASE_DAMAGE, iteminfo_parts::BASE_TOHIT, From 27cd5fe0793f5f0fd0db95b51fdee0c0521ee8aa Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Fri, 14 Feb 2020 19:04:07 -0700 Subject: [PATCH 14/51] Do NOT indicate rigidity for rigid items On second thought, this looks rather silly. Remove the rigidity indicator for the 99% of items that are rigid; leave it for non-rigid items, but do not make it bold. --- src/item.cpp | 4 +--- tests/iteminfo_test.cpp | 7 +++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 632a76c389957..f7d0209d1a464 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1195,9 +1195,7 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, } } if( parts->test( iteminfo_parts::BASE_RIGIDITY ) ) { - if( type->rigid ) { - info.emplace_back( "BASE", _( "Rigid: Volume and encumbrance are constant." ) ); - } else { + if( !type->rigid ) { info.emplace_back( "BASE", _( "Not rigid: Volume and encumbrance increase when filled." ) ); } diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 104d81ef739df..265fbe2ac4db8 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -39,13 +39,12 @@ TEST_CASE( "item rigidity", "[item][iteminfo][rigidity]" ) { iteminfo_query q( { iteminfo_parts::BASE_RIGIDITY } ); - SECTION( "rigid items indicate constant volume/encumbrance" ) { + SECTION( "rigid items do not indicate they are rigid, since almost all items are" ) { iteminfo_test( - item( "briefcase" ), q, - "Rigid: Volume and encumbrance are constant.\n" ); + item( "briefcase" ), q, "" ); } - SECTION( "non-rigid items indicate flexible volume/encumbrance" ) { + SECTION( "non-rigid items indicate their flexible volume/encumbrance" ) { iteminfo_test( item( "backpack" ), q, "Not rigid: Volume and encumbrance increase when filled.\n" ); From b34cf1a9ad96a84afaa0105a12f83feb6cfd2e7a Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Fri, 14 Feb 2020 19:06:01 -0700 Subject: [PATCH 15/51] Un-bold repair/disassembly headings; cleanup These sections don't need to draw the eye so much. Also do a little bit of code refactoring to avoid unnecessary math. --- src/item.cpp | 37 ++++++++++++++++++++----------------- tests/iteminfo_test.cpp | 13 +++++++------ 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index f7d0209d1a464..e9c9b288000ce 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1205,6 +1205,7 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, int dmg_cut = damage_melee( DT_CUT ); int dmg_stab = damage_melee( DT_STAB ); if( parts->test( iteminfo_parts::BASE_DAMAGE ) ) { + insert_separation_line( info ); std::string sep; if( dmg_bash ) { info.emplace_back( "BASE", _( "Bash: " ), "", iteminfo::no_newline, dmg_bash ); @@ -2703,13 +2704,12 @@ void item::repair_info( std::vector &info, const iteminfo_query *parts insert_separation_line( info ); const std::set &rep = repaired_with(); if( !rep.empty() ) { - info.emplace_back( "DESCRIPTION", _( "Repair: using " ) + + info.emplace_back( "DESCRIPTION", _( "Repair using " ) + enumerate_as_string( rep.begin(), rep.end(), []( const itype_id & e ) { return nname( e ); - }, enumeration_conjunction::or_ ) ); + }, enumeration_conjunction::or_ ) + "." ); if( reinforceable() ) { - info.emplace_back( "DESCRIPTION", _( "* This item can be " - "reinforced." ) ); + info.emplace_back( "DESCRIPTION", _( "* This item can be reinforced." ) ); } } else { info.emplace_back( "DESCRIPTION", _( "* This item is not repairable." ) ); @@ -2736,7 +2736,7 @@ void item::disassembly_info( std::vector &info, const iteminfo_query * } ); insert_separation_line( info ); info.push_back( iteminfo( "DESCRIPTION", - string_format( _( "Disassembly: takes %s and " + string_format( _( "Disassembly takes %s and " "might yield: %s." ), to_string_approx( time_duration::from_turns( dis.time / 100 ) ), components_list ) ) ); @@ -2917,15 +2917,18 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, const std::string space = " "; - std::set all_techniques = type->techniques; - all_techniques.insert( techniques.begin(), techniques.end() ); - if( !all_techniques.empty() && parts->test( iteminfo_parts::DESCRIPTION_TECHNIQUES ) ) { - insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", _( "Techniques when wielded: " ) + - enumerate_as_string( all_techniques.begin(), all_techniques.end(), []( const matec_id & tid ) { - return string_format( "%s: %s", _( tid.obj().name ), - _( tid.obj().description ) ); - } ) ) ); + if( parts->test( iteminfo_parts::DESCRIPTION_TECHNIQUES ) ) { + std::set all_techniques = type->techniques; + all_techniques.insert( techniques.begin(), techniques.end() ); + + if( !all_techniques.empty() ) { + insert_separation_line( info ); + info.push_back( iteminfo( "DESCRIPTION", _( "Techniques when wielded: " ) + + enumerate_as_string( all_techniques.begin(), all_techniques.end(), []( const matec_id & tid ) { + return string_format( "%s: %s", _( tid.obj().name ), + _( tid.obj().description ) ); + } ) ) ); + } } if( !is_gunmod() && has_flag( "REACH_ATTACK" ) && @@ -2943,10 +2946,9 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } ///\EFFECT_MELEE >2 allows seeing melee damage stats on weapons - if( debug_mode || - ( g->u.get_skill_level( skill_melee ) > 2 && + if( ( g->u.get_skill_level( skill_melee ) > 2 && ( damage_melee( DT_BASH ) > 0 || damage_melee( DT_CUT ) > 0 || - damage_melee( DT_STAB ) > 0 || type->m_to_hit > 0 ) ) ) { + damage_melee( DT_STAB ) > 0 || type->m_to_hit > 0 ) ) || debug_mode ) { damage_instance non_crit; g->u.roll_all_damage( false, non_crit, true, *this ); damage_instance crit; @@ -3001,6 +3003,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } } + if( parts->test( iteminfo_parts::DESCRIPTION_USE_METHODS ) ) { for( const std::pair &method : type->use_methods ) { insert_separation_line( info ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 265fbe2ac4db8..2194320aad78b 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -59,6 +59,7 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) iteminfo_test( item( "halligan" ), q, + "--\n" "Bash: 20" " Cut: 5" " To-hit bonus: +2\n" @@ -297,12 +298,12 @@ TEST_CASE( "repairable and with what tools", "[item][iteminfo][repair]" ) iteminfo_test( item( "halligan" ), q, "--\n" - "Repair: using extended toolset, arc welder, or makeshift arc welder\n" ); + "Repair using extended toolset, arc welder, or makeshift arc welder.\n" ); iteminfo_test( item( "hazmat_suit" ), q, "--\n" - "Repair: using soldering iron or extended toolset\n" ); + "Repair using soldering iron or extended toolset.\n" ); iteminfo_test( item( "rock" ), q, @@ -325,23 +326,23 @@ TEST_CASE( "disassembly time and yield", "[item][iteminfo][disassembly]" ) iteminfo_test( item( "string_36" ), q, "--\n" - "Disassembly: takes about 5 minutes and might yield: 6 short strings.\n" ); + "Disassembly takes about 5 minutes and might yield: 6 short strings.\n" ); // short string iteminfo_test( item( "string_6" ), q, "--\n" - "Disassembly: takes about 5 minutes and might yield: thread (50).\n" ); + "Disassembly takes about 5 minutes and might yield: thread (50).\n" ); iteminfo_test( item( "sheet_metal" ), q, "--\n" - "Disassembly: takes about 2 minutes and might yield: small metal sheet (24).\n" ); + "Disassembly takes about 2 minutes and might yield: small metal sheet (24).\n" ); iteminfo_test( item( "soldering_iron" ), q, "--\n" - "Disassembly: takes about 20 minutes and might yield:" + "Disassembly takes about 20 minutes and might yield:" " 2 electronic scraps, copper (1), scrap metal (1), and copper wire (5).\n" ); } From daf2a84b485ca1b87aa4faef0b75092aecd2dba8 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 10:29:56 -0700 Subject: [PATCH 16/51] Improve translation for repair indicators Avoid double-translation of material name, and make the "Repair using ..." string more amenable to translation, as suggested by @Qrox --- src/item.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index e9c9b288000ce..61aa39115d4a7 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1189,7 +1189,7 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, if( !mat_types.empty() ) { const std::string material_list = enumerate_as_string( mat_types.begin(), mat_types.end(), []( const material_type * material ) { - return string_format( "%s", _( material->name() ) ); + return string_format( "%s", material->name() ); }, enumeration_conjunction::none ); info.push_back( iteminfo( "BASE", string_format( _( "Material: %s" ), material_list ) ) ); } @@ -2704,10 +2704,10 @@ void item::repair_info( std::vector &info, const iteminfo_query *parts insert_separation_line( info ); const std::set &rep = repaired_with(); if( !rep.empty() ) { - info.emplace_back( "DESCRIPTION", _( "Repair using " ) + + info.emplace_back( "DESCRIPTION", string_format( _( "Repair using %s." ), enumerate_as_string( rep.begin(), rep.end(), []( const itype_id & e ) { return nname( e ); - }, enumeration_conjunction::or_ ) + "." ); + }, enumeration_conjunction::or_ ) ) ); if( reinforceable() ) { info.emplace_back( "DESCRIPTION", _( "* This item can be reinforced." ) ); } From 4765b6747a226b86ac0e8dd699ba480c2cf132b9 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 10:55:21 -0700 Subject: [PATCH 17/51] Move item description below more basic info To avoid player needing to scan or scroll past arbitrarily long descriptions to locate the more important volume/weight info --- src/item.cpp | 56 ++++++++++++++++++++--------------------- tests/iteminfo_test.cpp | 6 ++--- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 61aa39115d4a7..ff0de0c1af083 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1119,34 +1119,6 @@ static void insert_separation_line( std::vector &info ) void item::basic_info( std::vector &info, const iteminfo_query *parts, int batch, bool debug /* debug */ ) const { - if( parts->test( iteminfo_parts::DESCRIPTION ) ) { - const std::map::const_iterator idescription = - item_vars.find( "description" ); - const cata::optional snippet = SNIPPET.get_snippet_by_id( snip_id ); - if( snippet.has_value() ) { - // Just use the dynamic description - info.push_back( iteminfo( "DESCRIPTION", snippet.value().translated() ) ); - } else if( idescription != item_vars.end() ) { - info.push_back( iteminfo( "DESCRIPTION", idescription->second ) ); - } else { - if( has_flag( "MAGIC_FOCUS" ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "This item is a magical focus. " - "You can cast spells with it in your hand." ) ) ); - } - if( is_craft() ) { - const std::string desc = _( "This is an in progress %s. " - "It is %d percent complete." ); - const int percent_progress = item_counter / 100000; - info.push_back( iteminfo( "DESCRIPTION", string_format( desc, - craft_data_->making->result_name(), - percent_progress ) ) ); - } else { - info.push_back( iteminfo( "DESCRIPTION", type->description.translated() ) ); - } - } - insert_separation_line( info ); - } const std::string space = " "; if( parts->test( iteminfo_parts::BASE_CATEGORY ) ) { info.push_back( iteminfo( "BASE", _( "Category: " ), @@ -1200,6 +1172,34 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, _( "Not rigid: Volume and encumbrance increase when filled." ) ); } } + if( parts->test( iteminfo_parts::DESCRIPTION ) ) { + insert_separation_line( info ); + const std::map::const_iterator idescription = + item_vars.find( "description" ); + const cata::optional snippet = SNIPPET.get_snippet_by_id( snip_id ); + if( snippet.has_value() ) { + // Just use the dynamic description + info.push_back( iteminfo( "DESCRIPTION", snippet.value().translated() ) ); + } else if( idescription != item_vars.end() ) { + info.push_back( iteminfo( "DESCRIPTION", idescription->second ) ); + } else { + if( has_flag( "MAGIC_FOCUS" ) ) { + info.push_back( iteminfo( "DESCRIPTION", + _( "This item is a magical focus. " + "You can cast spells with it in your hand." ) ) ); + } + if( is_craft() ) { + const std::string desc = _( "This is an in progress %s. " + "It is %d percent complete." ); + const int percent_progress = item_counter / 100000; + info.push_back( iteminfo( "DESCRIPTION", string_format( desc, + craft_data_->making->result_name(), + percent_progress ) ) ); + } else { + info.push_back( iteminfo( "DESCRIPTION", type->description.translated() ) ); + } + } + } int dmg_bash = damage_melee( DT_BASH ); int dmg_cut = damage_melee( DT_CUT ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 2194320aad78b..300db2feb8779 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -27,11 +27,11 @@ TEST_CASE( "item description and physical attributes", "[item][iteminfo]" ) } ); iteminfo_test( item( "jug_plastic" ), q, - "A standard plastic jug used for milk and household cleaning chemicals.\n" - "--\n" "Category: CONTAINERS Price: $0.00\n" "Volume: 3.750 L Weight: 0.42 lbs\n" - "Material: Plastic\n" ); + "Material: Plastic\n" + "--\n" + "A standard plastic jug used for milk and household cleaning chemicals.\n" ); } From 566ee2892c50ac97dad557adc8953a0d3452b6a9 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 11:43:15 -0700 Subject: [PATCH 18/51] Group Owner/Price/Barter value Item price and barter value post-apocalypse are not relevant enough to get such high prominence in the info display. They conceptually belong with Owner; this commit puts them together. Minimal test case for Price extracted from the existing one; will need more coverage here. --- src/item.cpp | 56 ++++++++++++++++++++--------------------- tests/iteminfo_test.cpp | 36 +++++++++++++++++--------- 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index ff0de0c1af083..d1af0edabf240 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1122,22 +1122,18 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, const std::string space = " "; if( parts->test( iteminfo_parts::BASE_CATEGORY ) ) { info.push_back( iteminfo( "BASE", _( "Category: " ), - "
" + get_category().name() + "
", - iteminfo::no_newline ) ); - } - const int price_preapoc = price( false ) * batch; - const int price_postapoc = price( true ) * batch; - if( parts->test( iteminfo_parts::BASE_PRICE ) ) { - info.push_back( iteminfo( "BASE", space + _( "Price: " ), _( "$" ), - iteminfo::is_decimal | iteminfo::lower_is_better, - static_cast( price_preapoc ) / 100 ) ); + "
" + get_category().name() + "
" ) ); } - if( price_preapoc != price_postapoc && parts->test( iteminfo_parts::BASE_BARTER ) ) { - info.push_back( iteminfo( "BASE", _( "Barter value: " ), _( "$" ), - iteminfo::is_decimal | iteminfo::lower_is_better, - static_cast( price_postapoc ) / 100 ) ); + if( parts->test( iteminfo_parts::BASE_MATERIAL ) ) { + const std::vector mat_types = made_of_types(); + if( !mat_types.empty() ) { + const std::string material_list = enumerate_as_string( mat_types.begin(), mat_types.end(), + []( const material_type * material ) { + return string_format( "%s", material->name() ); + }, enumeration_conjunction::none ); + info.push_back( iteminfo( "BASE", string_format( _( "Material: %s" ), material_list ) ) ); + } } - if( parts->test( iteminfo_parts::BASE_VOLUME ) ) { int converted_volume_scale = 0; const double converted_volume = round_up( convert_volume( volume().value(), @@ -1156,16 +1152,6 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, iteminfo::lower_is_better | iteminfo::is_decimal, convert_weight( weight() ) * batch ) ); } - if( parts->test( iteminfo_parts::BASE_MATERIAL ) ) { - const std::vector mat_types = made_of_types(); - if( !mat_types.empty() ) { - const std::string material_list = enumerate_as_string( mat_types.begin(), mat_types.end(), - []( const material_type * material ) { - return string_format( "%s", material->name() ); - }, enumeration_conjunction::none ); - info.push_back( iteminfo( "BASE", string_format( _( "Material: %s" ), material_list ) ) ); - } - } if( parts->test( iteminfo_parts::BASE_RIGIDITY ) ) { if( !type->rigid ) { info.emplace_back( "BASE", @@ -1199,6 +1185,24 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, info.push_back( iteminfo( "DESCRIPTION", type->description.translated() ) ); } } + insert_separation_line( info ); + } + + if( !owner.is_null() ) { + info.push_back( iteminfo( "BASE", string_format( _( "Owner: %s" ), + _( get_owner_name() ) ) ) ); + } + const int price_preapoc = price( false ) * batch; + const int price_postapoc = price( true ) * batch; + if( parts->test( iteminfo_parts::BASE_PRICE ) ) { + info.push_back( iteminfo( "BASE", _( "Price: " ), _( "$" ), + iteminfo::is_decimal | iteminfo::lower_is_better, + static_cast( price_preapoc ) / 100 ) ); + } + if( price_preapoc != price_postapoc && parts->test( iteminfo_parts::BASE_BARTER ) ) { + info.push_back( iteminfo( "BASE", _( "Barter value: " ), _( "$" ), + iteminfo::is_decimal | iteminfo::lower_is_better, + static_cast( price_postapoc ) / 100 ) ); } int dmg_bash = damage_melee( DT_BASH ); @@ -1259,10 +1263,6 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, } } - if( !owner.is_null() ) { - info.push_back( iteminfo( "BASE", string_format( _( "Owner: %s" ), - _( get_owner_name() ) ) ) ); - } if( has_var( "contained_name" ) && parts->test( iteminfo_parts::BASE_CONTENTS ) ) { info.push_back( iteminfo( "BASE", string_format( _( "Contains: %s" ), get_var( "contained_name" ) ) ) ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 300db2feb8779..d570e1f487ee0 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -19,20 +19,32 @@ static void iteminfo_test( const item &i, const iteminfo_query &q, const std::st CHECK( info == reference ); } -TEST_CASE( "item description and physical attributes", "[item][iteminfo]" ) +TEST_CASE( "item description and physical attributes", "[item][iteminfo][primary]" ) { - iteminfo_query q( { iteminfo_parts::DESCRIPTION, iteminfo_parts::BASE_CATEGORY, - iteminfo_parts::BASE_PRICE, iteminfo_parts::BASE_VOLUME, - iteminfo_parts::BASE_WEIGHT, iteminfo_parts::BASE_MATERIAL - } ); - iteminfo_test( - item( "jug_plastic" ), q, - "Category: CONTAINERS Price: $0.00\n" - "Volume: 3.750 L Weight: 0.42 lbs\n" - "Material: Plastic\n" - "--\n" - "A standard plastic jug used for milk and household cleaning chemicals.\n" ); + iteminfo_query q( { iteminfo_parts::BASE_CATEGORY, iteminfo_parts::BASE_MATERIAL, + iteminfo_parts::BASE_VOLUME, iteminfo_parts::BASE_WEIGHT, + iteminfo_parts::DESCRIPTION } ); + + SECTION( "category, material, volume, weight, description" ) { + iteminfo_test( + item( "jug_plastic" ), q, + "Category: CONTAINERS\n" + "Material: Plastic\n" + "Volume: 3.750 L Weight: 0.42 lbs\n" + "--\n" + "A standard plastic jug used for milk and household cleaning chemicals.\n" ); + } +} + +TEST_CASE( "item owner, price, and barter value", "[item][iteminfo][price]" ) +{ + iteminfo_query q( { iteminfo_parts::BASE_PRICE, iteminfo_parts::BASE_BARTER } ); + SECTION( "price and owner" ) { + iteminfo_test( + item( "jug_plastic" ), q, + "Price: $0.00\n" ); + } } TEST_CASE( "item rigidity", "[item][iteminfo][rigidity]" ) From 98224e56d115e276c39eb3e6f3729cec1b7647b4 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 11:52:03 -0700 Subject: [PATCH 19/51] Embolden Repair and Disassembly keywords Highlighting the 'Repair' and 'Disassembly' keywords makes these sections easier to find quickly (thanks @Hirmuolio) --- src/item.cpp | 4 ++-- tests/iteminfo_test.cpp | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index d1af0edabf240..182a4715989a1 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2704,7 +2704,7 @@ void item::repair_info( std::vector &info, const iteminfo_query *parts insert_separation_line( info ); const std::set &rep = repaired_with(); if( !rep.empty() ) { - info.emplace_back( "DESCRIPTION", string_format( _( "Repair using %s." ), + info.emplace_back( "DESCRIPTION", string_format( _( "Repair using %s." ), enumerate_as_string( rep.begin(), rep.end(), []( const itype_id & e ) { return nname( e ); }, enumeration_conjunction::or_ ) ) ); @@ -2736,7 +2736,7 @@ void item::disassembly_info( std::vector &info, const iteminfo_query * } ); insert_separation_line( info ); info.push_back( iteminfo( "DESCRIPTION", - string_format( _( "Disassembly takes %s and " + string_format( _( "Disassembly takes %s and " "might yield: %s." ), to_string_approx( time_duration::from_turns( dis.time / 100 ) ), components_list ) ) ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index d570e1f487ee0..4b4dab163bc84 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -310,12 +310,12 @@ TEST_CASE( "repairable and with what tools", "[item][iteminfo][repair]" ) iteminfo_test( item( "halligan" ), q, "--\n" - "Repair using extended toolset, arc welder, or makeshift arc welder.\n" ); + "Repair using extended toolset, arc welder, or makeshift arc welder.\n" ); iteminfo_test( item( "hazmat_suit" ), q, "--\n" - "Repair using soldering iron or extended toolset.\n" ); + "Repair using soldering iron or extended toolset.\n" ); iteminfo_test( item( "rock" ), q, @@ -338,23 +338,23 @@ TEST_CASE( "disassembly time and yield", "[item][iteminfo][disassembly]" ) iteminfo_test( item( "string_36" ), q, "--\n" - "Disassembly takes about 5 minutes and might yield: 6 short strings.\n" ); + "Disassembly takes about 5 minutes and might yield: 6 short strings.\n" ); // short string iteminfo_test( item( "string_6" ), q, "--\n" - "Disassembly takes about 5 minutes and might yield: thread (50).\n" ); + "Disassembly takes about 5 minutes and might yield: thread (50).\n" ); iteminfo_test( item( "sheet_metal" ), q, "--\n" - "Disassembly takes about 2 minutes and might yield: small metal sheet (24).\n" ); + "Disassembly takes about 2 minutes and might yield: small metal sheet (24).\n" ); iteminfo_test( item( "soldering_iron" ), q, "--\n" - "Disassembly takes about 20 minutes and might yield:" + "Disassembly takes about 20 minutes and might yield:" " 2 electronic scraps, copper (1), scrap metal (1), and copper wire (5).\n" ); } From 149ee9c04d939f50ae1dd0d1f2c78d0837d80476 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 12:50:23 -0700 Subject: [PATCH 20/51] Factor out item::combat_info Moves weapon techniques, martial arts, reach attacks, and detailed melee damage into the same section with other attack/offensive info, as a new function `item::combat_info`. This is to keep logically related information in the same section and make it easier to find. --- src/item.cpp | 96 ++++++++++++++++++++++++++++------------------------ src/item.h | 2 ++ 2 files changed, 53 insertions(+), 45 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 182a4715989a1..51da3bb9b6b42 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1205,37 +1205,6 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, static_cast( price_postapoc ) / 100 ) ); } - int dmg_bash = damage_melee( DT_BASH ); - int dmg_cut = damage_melee( DT_CUT ); - int dmg_stab = damage_melee( DT_STAB ); - if( parts->test( iteminfo_parts::BASE_DAMAGE ) ) { - insert_separation_line( info ); - std::string sep; - if( dmg_bash ) { - info.emplace_back( "BASE", _( "Bash: " ), "", iteminfo::no_newline, dmg_bash ); - sep = space; - } - if( dmg_cut ) { - info.emplace_back( "BASE", sep + _( "Cut: " ), "", iteminfo::no_newline, dmg_cut ); - sep = space; - } - if( dmg_stab ) { - info.emplace_back( "BASE", sep + _( "Pierce: " ), "", iteminfo::no_newline, dmg_stab ); - } - } - - if( dmg_bash || dmg_cut || dmg_stab ) { - if( parts->test( iteminfo_parts::BASE_TOHIT ) ) { - info.push_back( iteminfo( "BASE", space + _( "To-hit bonus: " ), "", - iteminfo::show_plus, type->m_to_hit ) ); - } - - if( parts->test( iteminfo_parts::BASE_MOVES ) ) { - info.push_back( iteminfo( "BASE", _( "Moves per attack: " ), "", - iteminfo::lower_is_better, attack_time() ) ); - } - } - insert_separation_line( info ); if( parts->test( iteminfo_parts::BASE_REQUIREMENTS ) ) { @@ -2908,14 +2877,41 @@ void item::bionic_info( std::vector &info, const iteminfo_query *parts } } -void item::final_info( std::vector &info, const iteminfo_query *parts, int batch, - bool debug ) const +void item::combat_info( std::vector &info, const iteminfo_query *parts, int /*batch*/, + bool /*debug*/ ) const { - if( is_null() ) { - return; + const std::string space = " "; + + int dmg_bash = damage_melee( DT_BASH ); + int dmg_cut = damage_melee( DT_CUT ); + int dmg_stab = damage_melee( DT_STAB ); + if( parts->test( iteminfo_parts::BASE_DAMAGE ) ) { + insert_separation_line( info ); + std::string sep; + if( dmg_bash ) { + info.emplace_back( "BASE", _( "Bash: " ), "", iteminfo::no_newline, dmg_bash ); + sep = space; + } + if( dmg_cut ) { + info.emplace_back( "BASE", sep + _( "Cut: " ), "", iteminfo::no_newline, dmg_cut ); + sep = space; + } + if( dmg_stab ) { + info.emplace_back( "BASE", sep + _( "Pierce: " ), "", iteminfo::no_newline, dmg_stab ); + } } - const std::string space = " "; + if( dmg_bash || dmg_cut || dmg_stab ) { + if( parts->test( iteminfo_parts::BASE_TOHIT ) ) { + info.push_back( iteminfo( "BASE", space + _( "To-hit bonus: " ), "", + iteminfo::show_plus, type->m_to_hit ) ); + } + + if( parts->test( iteminfo_parts::BASE_MOVES ) ) { + info.push_back( iteminfo( "BASE", _( "Moves per attack: " ), "", + iteminfo::lower_is_better, attack_time() ) ); + } + } if( parts->test( iteminfo_parts::DESCRIPTION_TECHNIQUES ) ) { std::set all_techniques = type->techniques; @@ -2931,6 +2927,17 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } } + // display which martial arts styles character can use with this weapon + if( parts->test( iteminfo_parts::DESCRIPTION_APPLICABLEMARTIALARTS ) ) { + const std::string valid_styles = g->u.martial_arts_data.enumerate_known_styles( typeId() ); + if( !valid_styles.empty() ) { + insert_separation_line( info ); + info.push_back( iteminfo( "DESCRIPTION", + _( "You know how to use this with these martial arts " + "styles: " ) + valid_styles ) ); + } + } + if( !is_gunmod() && has_flag( "REACH_ATTACK" ) && parts->test( iteminfo_parts::DESCRIPTION_GUNMOD_ADDREACHATTACK ) ) { insert_separation_line( info ); @@ -2991,18 +2998,16 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, string_format( _( "%d moves per attack" ), attack_cost ) ) ); } } +} - //lets display which martial arts styles character can use with this weapon - if( parts->test( iteminfo_parts::DESCRIPTION_APPLICABLEMARTIALARTS ) ) { - const std::string valid_styles = g->u.martial_arts_data.enumerate_known_styles( typeId() ); - if( !valid_styles.empty() ) { - insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", - _( "You know how to use this with these martial arts " - "styles: " ) + valid_styles ) ); - } +void item::final_info( std::vector &info, const iteminfo_query *parts, int batch, + bool debug ) const +{ + if( is_null() ) { + return; } + const std::string space = " "; if( parts->test( iteminfo_parts::DESCRIPTION_USE_METHODS ) ) { for( const std::pair &method : type->use_methods ) { @@ -3365,6 +3370,7 @@ std::string item::info( std::vector &info, const iteminfo_query *parts if( !is_null() ) { basic_info( info, parts, batch, debug ); + combat_info( info, parts, batch, debug ); } const item *med_item = nullptr; diff --git a/src/item.h b/src/item.h index ff11f0bcef76b..bbe4785e01375 100644 --- a/src/item.h +++ b/src/item.h @@ -429,6 +429,8 @@ class item : public visitable bool debug ) const; void bionic_info( std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const; + void combat_info( std::vector &info, const iteminfo_query *parts, int batch, + bool debug ) const; void final_info( std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const; From 303dbae2238a41cf6758e78f47bbd0e9ad810bab Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 13:33:39 -0700 Subject: [PATCH 21/51] Add Damage heading to items with melee damage Make this section easier to find visually --- src/item.cpp | 9 ++++++--- tests/iteminfo_test.cpp | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 51da3bb9b6b42..80c7ae9c0f909 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2888,16 +2888,19 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts if( parts->test( iteminfo_parts::BASE_DAMAGE ) ) { insert_separation_line( info ); std::string sep; + if( dmg_bash || dmg_cut || dmg_stab ) { + info.push_back( iteminfo( "BASE", _( "Damage: " ), "", iteminfo::no_newline ) ); + } if( dmg_bash ) { - info.emplace_back( "BASE", _( "Bash: " ), "", iteminfo::no_newline, dmg_bash ); + info.push_back( iteminfo( "BASE", _( "Bash: " ), "", iteminfo::no_newline, dmg_bash ) ); sep = space; } if( dmg_cut ) { - info.emplace_back( "BASE", sep + _( "Cut: " ), "", iteminfo::no_newline, dmg_cut ); + info.push_back( iteminfo( "BASE", sep + _( "Cut: " ), "", iteminfo::no_newline, dmg_cut ) ); sep = space; } if( dmg_stab ) { - info.emplace_back( "BASE", sep + _( "Pierce: " ), "", iteminfo::no_newline, dmg_stab ); + info.push_back( iteminfo( "BASE", sep + _( "Pierce: " ), "", iteminfo::no_newline, dmg_stab ) ); } } diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 4b4dab163bc84..13e1880b2c1ab 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -72,7 +72,7 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) iteminfo_test( item( "halligan" ), q, "--\n" - "Bash: 20" + "Damage: Bash: 20" " Cut: 5" " To-hit bonus: +2\n" "Moves per attack: 145\n" ); From f720e306220bec86977e37ccaf1cebea70b6c7c0 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 14:03:13 -0700 Subject: [PATCH 22/51] Add tests for item damage section Tests the new "Damage:" heading before bash/cut/pierce/to-hit/moves --- tests/iteminfo_test.cpp | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 13e1880b2c1ab..5bd0ac40101a7 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -69,13 +69,38 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) iteminfo_parts::BASE_MOVES } ); - iteminfo_test( - item( "halligan" ), q, - "--\n" - "Damage: Bash: 20" - " Cut: 5" - " To-hit bonus: +2\n" - "Moves per attack: 145\n" ); + SECTION( "bash damage" ) { + iteminfo_test( + item( "rock" ), q, + "--\n" + "Damage: Bash: 7" + " To-hit bonus: -2\n" + "Moves per attack: 79\n" ); + } + + SECTION( "bash and cut damage" ) { + iteminfo_test( + item( "halligan" ), q, + "--\n" + "Damage: Bash: 20" + " Cut: 5" + " To-hit bonus: +2\n" + "Moves per attack: 145\n" ); + } + + SECTION( "bash and pierce damage" ) { + iteminfo_test( + item( "pointy_stick" ), q, + "--\n" + "Damage: Bash: 4" + " Pierce: 8" + " To-hit bonus: +1\n" + "Moves per attack: 100\n" ); + } + + SECTION( "no damage" ) { + iteminfo_test( item( "rag" ), q, "" ); + } } From 500cb26dc753eb495fd706fbdbacd8033e427ba9 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 14:27:33 -0700 Subject: [PATCH 23/51] Shorten and standardize item flag indicators To avoid many redundant appearances of the phrase "this item" in the item description, this commit: - Replaces "This piece of clothing" with "This clothing" - Replaces applicable "This item" with "This tool" or "This clothing" - Replaces generic "This item" phrases with "It" to save screen space --- data/json/flags.json | 52 ++++++++++++++++++++--------------------- src/item.cpp | 29 +++++++++++------------ tests/iteminfo_test.cpp | 16 ++++++------- 3 files changed, 47 insertions(+), 50 deletions(-) diff --git a/data/json/flags.json b/data/json/flags.json index 5bab06c0acbd7..3d77e216ac93b 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -26,7 +26,7 @@ "id": "ALLOWS_REMOTE_USE", "type": "json_flag", "context": [ "TOOL" ], - "info": "This item can be activated or reloaded from adjacent tile without picking it up." + "info": "This tool can be activated or reloaded from adjacent tile without picking it up." }, { "id": "AURA", @@ -46,7 +46,7 @@ "id": "BELT_CLIP", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "info": "This item can be clipped on to a belt loop of the appropriate size." + "info": "This tool can be clipped on to a belt loop of the appropriate size." }, { "id": "BELTED", @@ -78,25 +78,25 @@ "id": "BLOCK_WHILE_WORN", "type": "json_flag", "context": [ "ARMOR", "TOOL_ARMOR" ], - "info": "This item can be used to block attacks when worn." + "info": "This clothing can be used to block attacks when worn." }, { "id": "CBM", "type": "json_flag", "context": [ "BIONIC_ITEM" ], - "info": "This item is a Compact Bionic Module. You'll need to use specialized machinery or ask a surgeon to install it into your body." + "info": "This is a Compact Bionic Module. You'll need to use specialized machinery or ask a surgeon to install it into your body." }, { "id": "CLIMATE_CONTROL", "type": "json_flag", "context": [ "ARMOR", "TOOL_ARMOR" ], - "info": "This piece of clothing has built-in or attached climate control, keeping you at a comfortable temperature." + "info": "This clothing has built-in or attached climate control, keeping you at a comfortable temperature." }, { "id": "COLLAR", "type": "json_flag", "context": [ "ARMOR", "TOOL_ARMOR" ], - "info": "This piece of clothing has a wide collar that can keep your mouth warm if it is unencumbered." + "info": "This clothing has a wide collar that can keep your mouth warm if it is unencumbered." }, { "id": "DEAF", @@ -109,7 +109,7 @@ "id": "DIAMOND", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "info": "This item has a diamond coating improving its cutting or piercing damage.", + "info": "This tool has a diamond coating improving its cutting or piercing damage.", "inherit": false }, { @@ -147,7 +147,7 @@ "id": "ETHEREAL_ITEM", "type": "json_flag", "context": [ ], - "info": "This item disappears as soon as its timer runs out whether it is food or not." + "info": "It disappears as soon as its timer runs out whether it is food or not." }, { "id": "ONLY_ONE", @@ -160,26 +160,26 @@ "type": "json_flag", "context": [ "ARMOR", "TOOL_ARMOR" ], "//": "Wearing this clothing gives a morale bonus if the player has the Stylish trait.", - "info": "This piece of clothing is fancy.", + "info": "This clothing is fancy.", "conflicts": [ "SUPER_FANCY" ] }, { "id": "FIRE", "type": "json_flag", "context": [ "GENERIC", "TOOL", "TOOL_ARMOR" ], - "info": "This item counts as fire for crafting purposes." + "info": "It counts as fire for crafting purposes." }, { "id": "FIRESTARTER", "type": "json_flag", "context": [ "GENERIC", "TOOL", "TOOL_ARMOR" ], - "info": "This item can start fire." + "info": "It can start fire." }, { "id": "FIREWOOD", "type": "json_flag", "context": [ "GENERIC" ], - "info": "This item can serve as a firewood." + "info": "It can serve as a firewood." }, { "id": "FIX_FARSIGHT", @@ -199,7 +199,7 @@ "context": [ "ARMOR", "TOOL_ARMOR" ], "//": "Zombie-dropped clothing giving various penalties if Filthy mod is active. Also CBMs harvested from zombies.", "craft_inherit": true, - "info": "This item is filthy." + "info": "It is filthy." }, { "id": "FLASH_PROTECTION", @@ -237,7 +237,7 @@ "id": "HOOD", "type": "json_flag", "context": [ "ARMOR", "TOOL_ARMOR" ], - "info": "This piece of clothing has a hood to keep your head warm if your head is unencumbered." + "info": "This clothing has a hood to keep your head warm if your head is unencumbered." }, { "id": "HYGROMETER", @@ -249,7 +249,7 @@ "id": "IRREMOVABLE", "type": "json_flag", "context": [ "GUNMOD" ], - "info": "This item is a component of the gun it is attached to. It can't be removed without destroying it.", + "info": "It is a component of the gun it is attached to. It can't be removed without destroying it.", "inherit": false }, { @@ -308,7 +308,7 @@ "id": "UNDERSIZE", "type": "json_flag", "context": [ "ARMOR", "TOOL_ARMOR" ], - "//": "Can be worn comfortably by mutants with Tiny or Unassuming. Too small for anyone else." + "//": "This clothing can be worn comfortably by mutants with Tiny or Unassuming, but is too small for anyone else." }, { "id": "PARTIAL_DEAF", @@ -369,14 +369,14 @@ "id": "TWO_WAY_RADIO", "type": "json_flag", "context": [ "GENERIC", "TOOL_ARMOR", "TOOL" ], - "info": "This item can be used to communicate with radio waves." + "info": "It can be used to communicate with radio waves." }, { "id": "RAINPROOF", "type": "json_flag", "context": [ "ARMOR", "TOOL_ARMOR" ], "//": "Prevents the covered body-part(s) from getting wet in the rain.", - "info": "This piece of clothing is designed to keep you dry in the rain." + "info": "This clothing is designed to keep you dry in the rain." }, { "id": "RESTRICT_HANDS", @@ -395,31 +395,31 @@ "id": "SHEATH_AXE", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "//": "This item can be stored in a sheath of the appropriate size." + "//": "This tool can be stored in a sheath of the appropriate size." }, { "id": "SHEATH_KNIFE", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "//": "This item can be stored in a sheath of the appropriate size." + "//": "This tool can be stored in a sheath of the appropriate size." }, { "id": "SHEATH_SWORD", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "//": "This item can be stored in a scabbard of the appropriate size." + "//": "This tool can be stored in a scabbard of the appropriate size." }, { "id": "SHEATH_SPEAR", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "//": "This item can be stored in a sling of the appropriate size." + "//": "This tool can be stored in a sling of the appropriate size." }, { "id": "SHEATH_GOLF", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "//": "This item can be stored in a bag of the appropriate size." + "//": "This tool can be stored in a bag of the appropriate size." }, { "id": "SKINTIGHT", @@ -480,7 +480,7 @@ "id": "VARSIZE", "type": "json_flag", "context": [ "ARMOR", "TOOL_ARMOR" ], - "//": "Can be made to fit via tailoring." + "//": "This clothing aan be made to fit via tailoring." }, { "id": "WAIST", @@ -516,7 +516,7 @@ "type": "json_flag", "context": [ "ARMOR", "TOOL_ARMOR" ], "//": "Allows power armor to be worn with compatible armors like ear plugs and mouthpieces.", - "info": "This item can be worn simultaneously with power armor." + "info": "This clothing can be worn simultaneously with power armor." }, { "id": "furred", @@ -559,7 +559,7 @@ "id": "NANOFAB_TEMPLATE", "type": "json_flag", "context": [ "generic", "TOOL" ], - "info": "This item contains a nanofabricator recipe." + "info": "It contains a nanofabricator recipe." }, { "id": "BIONIC_FAULTY", diff --git a/src/item.cpp b/src/item.cpp index 80c7ae9c0f909..81b25e0f64cb7 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1171,7 +1171,7 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, } else { if( has_flag( "MAGIC_FOCUS" ) ) { info.push_back( iteminfo( "DESCRIPTION", - _( "This item is a magical focus. " + _( "It is a magical focus. " "You can cast spells with it in your hand." ) ) ); } if( is_craft() ) { @@ -2265,8 +2265,7 @@ void item::armor_fit_info( std::vector &info, const iteminfo_query *pa if( has_flag( "HELMET_COMPAT" ) && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_HELMETCOMPAT ) ) { info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be worn with a " - "helmet." ) ) ); + _( "* It can be worn with a helmet." ) ) ); } if( parts->test( iteminfo_parts::DESCRIPTION_FLAGS_FITS ) ) { @@ -2383,8 +2382,7 @@ void item::armor_fit_info( std::vector &info, const iteminfo_query *pa if( is_sided() && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_SIDED ) ) { info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be worn on either side of " - "the body." ) ) ); + _( "* It can be worn on either side of the body." ) ) ); } if( is_power_armor() && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_POWERARMOR ) ) { info.push_back( iteminfo( "DESCRIPTION", @@ -2678,10 +2676,10 @@ void item::repair_info( std::vector &info, const iteminfo_query *parts return nname( e ); }, enumeration_conjunction::or_ ) ) ); if( reinforceable() ) { - info.emplace_back( "DESCRIPTION", _( "* This item can be reinforced." ) ); + info.emplace_back( "DESCRIPTION", _( "* It can be reinforced." ) ); } } else { - info.emplace_back( "DESCRIPTION", _( "* This item is not repairable." ) ); + info.emplace_back( "DESCRIPTION", _( "* It is not repairable." ) ); } } @@ -2946,11 +2944,11 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts insert_separation_line( info ); if( has_flag( "REACH3" ) ) { info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be used to make long reach " + _( "* It can be used to make long reach " "attacks." ) ) ); } else { info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be used to make reach " + _( "* It can be used to make reach " "attacks." ) ) ); } } @@ -3023,14 +3021,13 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, if( parts->test( iteminfo_parts::DESCRIPTION_CONDUCTIVITY ) ) { if( !conductive() ) { - info.push_back( iteminfo( "BASE", _( "* This item does not " - "conduct electricity." ) ) ); + info.push_back( iteminfo( "BASE", _( "* It does not conduct electricity." ) ) ); } else if( has_flag( "CONDUCTIVE" ) ) { info.push_back( iteminfo( "BASE", - _( "* This item effectively conducts " + _( "* It effectively conducts " "electricity, as it has no guard." ) ) ); } else { - info.push_back( iteminfo( "BASE", _( "* This item conducts electricity." ) ) ); + info.push_back( iteminfo( "BASE", _( "* It conducts electricity." ) ) ); } } @@ -3089,11 +3086,11 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, parts->test( iteminfo_parts::DESCRIPTION_RADIO_ACTIVATION ) ) { if( has_flag( "RADIO_MOD" ) ) { info.emplace_back( "DESCRIPTION", - _( "* This item has been modified to listen to radio " + _( "* It has been modified to listen to radio " "signals. It can still be activated manually." ) ); } else { info.emplace_back( "DESCRIPTION", - _( "* This item can only be activated by a radio " + _( "* It can only be activated by a radio " "signal." ) ); } @@ -3309,7 +3306,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, } if( this->get_var( "die_num_sides", 0 ) != 0 ) { info.emplace_back( "DESCRIPTION", - string_format( _( "* This item can be used as a die, " + string_format( _( "* It can be used as a die, " "and has %d sides." ), static_cast( this->get_var( "die_num_sides", 0 ) ) ) ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 5bd0ac40101a7..1a6f27fc743d8 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -273,22 +273,22 @@ TEST_CASE( "item conductivity", "[item][iteminfo][conductivity]" ) iteminfo_test( item( "2x4" ), q, "--\n" - "* This item does not conduct electricity.\n" ); + "* It does not conduct electricity.\n" ); iteminfo_test( item( "fire_ax" ), q, "--\n" - "* This item does not conduct electricity.\n" ); + "* It does not conduct electricity.\n" ); } SECTION( "conductive items" ) { iteminfo_test( item( "pipe" ), q, "--\n" - "* This item conducts electricity.\n" ); + "* It conducts electricity.\n" ); iteminfo_test( item( "halligan" ), q, "--\n" - "* This item conducts electricity.\n" ); + "* It conducts electricity.\n" ); } } @@ -345,13 +345,13 @@ TEST_CASE( "repairable and with what tools", "[item][iteminfo][repair]" ) iteminfo_test( item( "rock" ), q, "--\n" - "* This item is not repairable.\n" ); + "* It is not repairable.\n" ); /* iteminfo_test( item( "socks" ), q, "--\n" - "* This item can be reinforced.\n" ); + "* It can be reinforced.\n" ); */ } @@ -391,7 +391,7 @@ TEST_CASE( "item description flags", "[item][iteminfo]" ) iteminfo_test( item( "halligan" ), q, "--\n" - "* This item can be clipped on to a belt loop of the appropriate size.\n" + "* This tool can be clipped on to a belt loop of the appropriate size.\n" "* As a weapon, this item is well-made and will" " withstand the punishment of combat.\n" ); @@ -405,7 +405,7 @@ TEST_CASE( "item description flags", "[item][iteminfo]" ) "* This gear is generally worn over clothing.\n" "* This clothing completely protects you from" " radiation.\n" - "* This piece of clothing is designed to keep you dry in the rain.\n" + "* This clothing is designed to keep you dry in the rain.\n" "* This clothing won't let water through." " Unless you jump in the river or something like that.\n" ); } From 7edb69813e0d917f4f7c3c7bf76127e430bf6457 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 14:32:12 -0700 Subject: [PATCH 24/51] Replace a few more 'this item' with 'it' --- data/json/flags.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/json/flags.json b/data/json/flags.json index 3d77e216ac93b..51b8e8e8c40f8 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -116,13 +116,13 @@ "id": "DIG_TOOL", "type": "json_flag", "context": [ "TOOL", "TOOL_ARMOR" ], - "info": "While wielded, this item allows you to mine through rocks and other hard obstacles by moving into tiles with them. Note that automatic mining option should be set to true for this to work." + "info": "While wielded, it allows you to mine through rocks and other hard obstacles by moving into tiles with them. Note that automatic mining option should be set to true for this to work." }, { "id": "DURABLE_MELEE", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "info": "As a weapon, this item is well-made and will withstand the punishment of combat.", + "info": "As a weapon, it is well-made and will withstand the punishment of combat.", "conflicts": [ "FRAGILE_MELEE" ] }, { @@ -224,7 +224,7 @@ "id": "FRAGILE_MELEE", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "info": "As a weapon, this item is flimsy and won't last long in combat before breaking apart.", + "info": "As a weapon, it is flimsy and won't last long in combat before breaking apart.", "conflicts": [ "DURABLE_MELEE" ] }, { From acf644cef6d57368416035afbead280af958791b Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 15:16:28 -0700 Subject: [PATCH 25/51] Factor out item::contents_info To make it easier to reposition later --- src/item.cpp | 111 ++++++++++++++++++++++++++++----------------------- src/item.h | 2 + 2 files changed, 62 insertions(+), 51 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 81b25e0f64cb7..dbd759f12d037 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -3001,6 +3001,65 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts } } + +void item::contents_info( std::vector &info, const iteminfo_query *parts, int batch, + bool /*debug*/ ) const +{ + if( contents.empty() || !parts->test( iteminfo_parts::DESCRIPTION_CONTENTS ) ) { + return; + } + const std::string space = " "; + for( const item *mod : is_gun() ? gunmods() : toolmods() ) { + std::string mod_str; + if( mod->type->gunmod ) { + if( mod->is_irremovable() ) { + mod_str = _( "Integrated mod: " ); + } else { + mod_str = _( "Mod: " ); + } + mod_str += string_format( "%s (%s) ", mod->tname(), + mod->type->gunmod->location.name() ); + } + insert_separation_line( info ); + info.emplace_back( "DESCRIPTION", mod_str ); + info.emplace_back( "DESCRIPTION", mod->type->description.translated() ); + } + bool contents_header = false; + for( const item &contents_item : contents ) { + if( !contents_item.type->mod ) { + if( !contents_header ) { + insert_separation_line( info ); + info.emplace_back( "DESCRIPTION", _( "Contents:" ) ); + contents_header = true; + } else { + // Separate items with a blank line + info.emplace_back( "DESCRIPTION", space ); + } + + const translation &description = contents_item.type->description; + + if( contents_item.made_of_from_type( LIQUID ) ) { + units::volume contents_volume = contents_item.volume() * batch; + int converted_volume_scale = 0; + const double converted_volume = + round_up( convert_volume( contents_volume.value(), + &converted_volume_scale ), 2 ); + info.emplace_back( "DESCRIPTION", contents_item.display_name() ); + iteminfo::flags f = iteminfo::no_newline; + if( converted_volume_scale != 0 ) { + f |= iteminfo::is_decimal; + } + info.emplace_back( "CONTAINER", description + space, + string_format( " %s", volume_units_abbr() ), f, + converted_volume ); + } else { + info.emplace_back( "DESCRIPTION", contents_item.display_name() ); + info.emplace_back( "DESCRIPTION", description.translated() ); + } + } + } +} + void item::final_info( std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const { @@ -3252,58 +3311,8 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, info.push_back( iteminfo( "DESCRIPTION", ntext ) ); } - // describe contents - if( !contents.empty() && parts->test( iteminfo_parts::DESCRIPTION_CONTENTS ) ) { - for( const item *mod : is_gun() ? gunmods() : toolmods() ) { - std::string mod_str; - if( mod->type->gunmod ) { - if( mod->is_irremovable() ) { - mod_str = _( "Integrated mod: " ); - } else { - mod_str = _( "Mod: " ); - } - mod_str += string_format( "%s (%s) ", mod->tname(), - mod->type->gunmod->location.name() ); - } - insert_separation_line( info ); - info.emplace_back( "DESCRIPTION", mod_str ); - info.emplace_back( "DESCRIPTION", mod->type->description.translated() ); - } - bool contents_header = false; - for( const item &contents_item : contents ) { - if( !contents_item.type->mod ) { - if( !contents_header ) { - insert_separation_line( info ); - info.emplace_back( "DESCRIPTION", _( "Contents of this item:" ) ); - contents_header = true; - } else { - // Separate items with a blank line - info.emplace_back( "DESCRIPTION", space ); - } + contents_info( info, parts, batch, debug ); - const translation &description = contents_item.type->description; - - if( contents_item.made_of_from_type( LIQUID ) ) { - units::volume contents_volume = contents_item.volume() * batch; - int converted_volume_scale = 0; - const double converted_volume = - round_up( convert_volume( contents_volume.value(), - &converted_volume_scale ), 2 ); - info.emplace_back( "DESCRIPTION", contents_item.display_name() ); - iteminfo::flags f = iteminfo::no_newline; - if( converted_volume_scale != 0 ) { - f |= iteminfo::is_decimal; - } - info.emplace_back( "CONTAINER", description + space, - string_format( " %s", volume_units_abbr() ), f, - converted_volume ); - } else { - info.emplace_back( "DESCRIPTION", contents_item.display_name() ); - info.emplace_back( "DESCRIPTION", description.translated() ); - } - } - } - } if( this->get_var( "die_num_sides", 0 ) != 0 ) { info.emplace_back( "DESCRIPTION", string_format( _( "* It can be used as a die, " diff --git a/src/item.h b/src/item.h index bbe4785e01375..bc3135435fa54 100644 --- a/src/item.h +++ b/src/item.h @@ -431,6 +431,8 @@ class item : public visitable bool debug ) const; void combat_info( std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const; + void contents_info( std::vector &info, const iteminfo_query *parts, int batch, + bool debug ) const; void final_info( std::vector &info, const iteminfo_query *parts, int batch, bool debug ) const; From c6cca50da0437cca06920ef665d616a0b18b9f0e Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 15:17:16 -0700 Subject: [PATCH 26/51] Re-use variables declared earlier --- src/item.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index dbd759f12d037..be79ebccad426 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2955,8 +2955,7 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts ///\EFFECT_MELEE >2 allows seeing melee damage stats on weapons if( ( g->u.get_skill_level( skill_melee ) > 2 && - ( damage_melee( DT_BASH ) > 0 || damage_melee( DT_CUT ) > 0 || - damage_melee( DT_STAB ) > 0 || type->m_to_hit > 0 ) ) || debug_mode ) { + ( dmg_bash || dmg_cut || dmg_stab || type->m_to_hit > 0 ) ) || debug_mode ) { damage_instance non_crit; g->u.roll_all_damage( false, non_crit, true, *this ); damage_instance crit; From 05d2f145dda7551f9df0848f427468fdd4260be7 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 15:17:46 -0700 Subject: [PATCH 27/51] Move techniques to end of combat info --- src/item.cpp | 78 ++++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index be79ebccad426..e4dbbeb4e0ade 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2914,45 +2914,6 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts } } - if( parts->test( iteminfo_parts::DESCRIPTION_TECHNIQUES ) ) { - std::set all_techniques = type->techniques; - all_techniques.insert( techniques.begin(), techniques.end() ); - - if( !all_techniques.empty() ) { - insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", _( "Techniques when wielded: " ) + - enumerate_as_string( all_techniques.begin(), all_techniques.end(), []( const matec_id & tid ) { - return string_format( "%s: %s", _( tid.obj().name ), - _( tid.obj().description ) ); - } ) ) ); - } - } - - // display which martial arts styles character can use with this weapon - if( parts->test( iteminfo_parts::DESCRIPTION_APPLICABLEMARTIALARTS ) ) { - const std::string valid_styles = g->u.martial_arts_data.enumerate_known_styles( typeId() ); - if( !valid_styles.empty() ) { - insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", - _( "You know how to use this with these martial arts " - "styles: " ) + valid_styles ) ); - } - } - - if( !is_gunmod() && has_flag( "REACH_ATTACK" ) && - parts->test( iteminfo_parts::DESCRIPTION_GUNMOD_ADDREACHATTACK ) ) { - insert_separation_line( info ); - if( has_flag( "REACH3" ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* It can be used to make long reach " - "attacks." ) ) ); - } else { - info.push_back( iteminfo( "DESCRIPTION", - _( "* It can be used to make reach " - "attacks." ) ) ); - } - } - ///\EFFECT_MELEE >2 allows seeing melee damage stats on weapons if( ( g->u.get_skill_level( skill_melee ) > 2 && ( dmg_bash || dmg_cut || dmg_stab || type->m_to_hit > 0 ) ) || debug_mode ) { @@ -2998,6 +2959,45 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts string_format( _( "%d moves per attack" ), attack_cost ) ) ); } } + + if( parts->test( iteminfo_parts::DESCRIPTION_TECHNIQUES ) ) { + std::set all_techniques = type->techniques; + all_techniques.insert( techniques.begin(), techniques.end() ); + + if( !all_techniques.empty() ) { + insert_separation_line( info ); + info.push_back( iteminfo( "DESCRIPTION", _( "Techniques when wielded: " ) + + enumerate_as_string( all_techniques.begin(), all_techniques.end(), []( const matec_id & tid ) { + return string_format( "%s: %s", _( tid.obj().name ), + _( tid.obj().description ) ); + } ) ) ); + } + } + + // display which martial arts styles character can use with this weapon + if( parts->test( iteminfo_parts::DESCRIPTION_APPLICABLEMARTIALARTS ) ) { + const std::string valid_styles = g->u.martial_arts_data.enumerate_known_styles( typeId() ); + if( !valid_styles.empty() ) { + insert_separation_line( info ); + info.push_back( iteminfo( "DESCRIPTION", + _( "You know how to use this with these martial arts " + "styles: " ) + valid_styles ) ); + } + } + + if( !is_gunmod() && has_flag( "REACH_ATTACK" ) && + parts->test( iteminfo_parts::DESCRIPTION_GUNMOD_ADDREACHATTACK ) ) { + insert_separation_line( info ); + if( has_flag( "REACH3" ) ) { + info.push_back( iteminfo( "DESCRIPTION", + _( "* It can be used to make long reach " + "attacks." ) ) ); + } else { + info.push_back( iteminfo( "DESCRIPTION", + _( "* It can be used to make reach " + "attacks." ) ) ); + } + } } From b384915685eeb8b0b4b6d85c21eadafc32862b90 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 15:22:12 -0700 Subject: [PATCH 28/51] Fix test case (this item -> it) --- tests/iteminfo_test.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 1a6f27fc743d8..70443d14c5275 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -264,7 +264,6 @@ TEST_CASE( "food freshness and lifetime", "[item][iteminfo][food]" ) } - TEST_CASE( "item conductivity", "[item][iteminfo][conductivity]" ) { iteminfo_query q( { iteminfo_parts::DESCRIPTION_CONDUCTIVITY } ); @@ -392,7 +391,7 @@ TEST_CASE( "item description flags", "[item][iteminfo]" ) item( "halligan" ), q, "--\n" "* This tool can be clipped on to a belt loop of the appropriate size.\n" - "* As a weapon, this item is well-made and will" + "* As a weapon, it is well-made and will" " withstand the punishment of combat.\n" ); iteminfo_test( From dabcf41cffd16b3fe7c33b1c9460360769c18f9b Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 15:54:47 -0700 Subject: [PATCH 29/51] Move container_info near contents_info --- src/item.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index e4dbbeb4e0ade..d2edbb3ce4d16 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -3310,8 +3310,6 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, info.push_back( iteminfo( "DESCRIPTION", ntext ) ); } - contents_info( info, parts, batch, debug ); - if( this->get_var( "die_num_sides", 0 ) != 0 ) { info.emplace_back( "DESCRIPTION", string_format( _( "* It can be used as a die, " @@ -3378,6 +3376,8 @@ std::string item::info( std::vector &info, const iteminfo_query *parts if( !is_null() ) { basic_info( info, parts, batch, debug ); + container_info( info, parts, batch, debug ); + contents_info( info, parts, batch, debug ); combat_info( info, parts, batch, debug ); } @@ -3419,7 +3419,6 @@ std::string item::info( std::vector &info, const iteminfo_query *parts armor_info( info, parts, batch, debug ); animal_armor_info( info, parts, batch, debug ); book_info( info, parts, batch, debug ); - container_info( info, parts, batch, debug ); battery_info( info, parts, batch, debug ); tool_info( info, parts, batch, debug ); component_info( info, parts, batch, debug ); From d4dfedef63242e2e991e626d33823146f3506fa7 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 15:55:24 -0700 Subject: [PATCH 30/51] Ammunition/ammunition type heading The bold-faced "Damage" heading in this section was ambiguious (especially for items with both a melee and ammunition damage, like rocks). Bold the word "Ammunition", and replace "Type" with "Ammunition type"; make other labels in the ammo section unbolded. --- src/item.cpp | 13 +++++++------ tests/iteminfo_test.cpp | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index d2edbb3ce4d16..e40c3150c99ce 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1543,26 +1543,27 @@ void item::ammo_info( std::vector &info, const iteminfo_query *parts, const std::string space = " "; if( ammo_remaining() > 0 ) { - info.emplace_back( "AMMO", _( "Ammunition: " ), ammo_data()->nname( ammo_remaining() ) ); + info.emplace_back( "AMMO", _( "Ammunition: " ), + ammo_data()->nname( ammo_remaining() ) ); } else if( is_ammo() ) { - info.emplace_back( "AMMO", _( "Type: " ), ammo_type()->name() ); + info.emplace_back( "AMMO", _( "Ammunition type: " ), ammo_type()->name() ); } const islot_ammo &ammo = *ammo_data()->ammo; if( !ammo.damage.empty() || ammo.prop_damage || ammo.force_stat_display ) { if( !ammo.damage.empty() ) { if( parts->test( iteminfo_parts::AMMO_DAMAGE_VALUE ) ) { - info.emplace_back( "AMMO", _( "Damage: " ), "", + info.emplace_back( "AMMO", _( "Damage: " ), "", iteminfo::no_newline, ammo.damage.total_damage() ); } } else if( ammo.prop_damage ) { if( parts->test( iteminfo_parts::AMMO_DAMAGE_PROPORTIONAL ) ) { - info.emplace_back( "AMMO", _( "Damage multiplier: " ), "", + info.emplace_back( "AMMO", _( "Damage multiplier: " ), "", iteminfo::no_newline | iteminfo::is_decimal, *ammo.prop_damage ); } } else { - info.emplace_back( "AMMO", _( "Damage multiplier: " ), "", + info.emplace_back( "AMMO", _( "Damage multiplier: " ), "", iteminfo::no_newline | iteminfo::is_decimal, 1.0 ); } if( parts->test( iteminfo_parts::AMMO_DAMAGE_AP ) ) { @@ -2958,6 +2959,7 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts info.push_back( iteminfo( "DESCRIPTION", string_format( _( "%d moves per attack" ), attack_cost ) ) ); } + insert_separation_line( info ); } if( parts->test( iteminfo_parts::DESCRIPTION_TECHNIQUES ) ) { @@ -3000,7 +3002,6 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts } } - void item::contents_info( std::vector &info, const iteminfo_query *parts, int batch, bool /*debug*/ ) const { diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 70443d14c5275..ede4355d7e03b 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -205,6 +205,24 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged]" ) } +TEST_CASE( "ammunition", "[item][iteminfo][ammo]" ) +{ + iteminfo_query q( { iteminfo_parts::AMMO_REMAINING_OR_TYPES, iteminfo_parts::AMMO_DAMAGE_VALUE, + iteminfo_parts::AMMO_DAMAGE_PROPORTIONAL, iteminfo_parts::AMMO_DAMAGE_AP, + iteminfo_parts::AMMO_DAMAGE_RANGE, iteminfo_parts::AMMO_DAMAGE_DISPERSION, + iteminfo_parts::AMMO_DAMAGE_RECOIL } ); + + SECTION( "simple item with ammo damage" ) { + iteminfo_test( + item( "rock" ), q, + "--\n" + "Ammunition type: rocks\n" + "Damage: 7 Armor-pierce: 0\n" + "Range: 10 Dispersion: 14\n" + "Recoil: 0\n" ); + } +} + TEST_CASE( "nutrients in food", "[item][iteminfo][food]" ) { iteminfo_query q( { iteminfo_parts::FOOD_NUTRITION, iteminfo_parts::FOOD_VITAMINS, From 17ed7c89565c3bb7fd2d491ae3304efb14f9d947 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sat, 15 Feb 2020 18:28:56 -0700 Subject: [PATCH 31/51] Move Owner/Price/Barter value to bottom of info This information is among the least-important attributes about items in the cataclysm. Change my mind. --- src/item.cpp | 40 ++++++++++++++++++++++------------------ tests/iteminfo_test.cpp | 28 +++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index e40c3150c99ce..d428b9d57b617 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1188,23 +1188,6 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, insert_separation_line( info ); } - if( !owner.is_null() ) { - info.push_back( iteminfo( "BASE", string_format( _( "Owner: %s" ), - _( get_owner_name() ) ) ) ); - } - const int price_preapoc = price( false ) * batch; - const int price_postapoc = price( true ) * batch; - if( parts->test( iteminfo_parts::BASE_PRICE ) ) { - info.push_back( iteminfo( "BASE", _( "Price: " ), _( "$" ), - iteminfo::is_decimal | iteminfo::lower_is_better, - static_cast( price_preapoc ) / 100 ) ); - } - if( price_preapoc != price_postapoc && parts->test( iteminfo_parts::BASE_BARTER ) ) { - info.push_back( iteminfo( "BASE", _( "Barter value: " ), _( "$" ), - iteminfo::is_decimal | iteminfo::lower_is_better, - static_cast( price_postapoc ) / 100 ) ); - } - insert_separation_line( info ); if( parts->test( iteminfo_parts::BASE_REQUIREMENTS ) ) { @@ -3319,7 +3302,28 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, 0 ) ) ) ); } - // list recipes you could use it in + // Owner, price, and barter value + if( !owner.is_null() || parts->test( iteminfo_parts::BASE_PRICE ) ) { + insert_separation_line( info ); + } + if( !owner.is_null() ) { + info.push_back( iteminfo( "BASE", string_format( _( "Owner: %s" ), + _( get_owner_name() ) ) ) ); + } + const int price_preapoc = price( false ) * batch; + const int price_postapoc = price( true ) * batch; + if( parts->test( iteminfo_parts::BASE_PRICE ) ) { + info.push_back( iteminfo( "BASE", _( "Price: " ), _( "$" ), + iteminfo::is_decimal | iteminfo::lower_is_better | iteminfo::no_newline, + static_cast( price_preapoc ) / 100 ) ); + } + if( price_preapoc != price_postapoc && parts->test( iteminfo_parts::BASE_BARTER ) ) { + info.push_back( iteminfo( "BASE", space + _( "Barter value: " ), _( "$" ), + iteminfo::is_decimal | iteminfo::lower_is_better, + static_cast( price_postapoc ) / 100 ) ); + } + + // Recipes using this item as an ingredient if( parts->test( iteminfo_parts::DESCRIPTION_APPLICABLE_RECIPES ) ) { itype_id tid = contents.empty() ? typeId() : contents.front().typeId(); const inventory &crafting_inv = g->u.crafting_inventory(); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index ede4355d7e03b..2141cfe4fa0fc 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -40,11 +40,33 @@ TEST_CASE( "item owner, price, and barter value", "[item][iteminfo][price]" ) { iteminfo_query q( { iteminfo_parts::BASE_PRICE, iteminfo_parts::BASE_BARTER } ); - SECTION( "price and owner" ) { + SECTION( "owner and price" ) { + item my_rock( "rock" ); + my_rock.set_owner( g->u ); iteminfo_test( - item( "jug_plastic" ), q, - "Price: $0.00\n" ); + my_rock, q, + "--\n" + "Owner: Your Followers\n" + "Price: $0.00" ); + } + + SECTION( "owner, price and barter value" ) { + item my_necklace( "gold_necklace" ); + my_necklace.set_owner( g->u ); + iteminfo_test( + my_necklace, q, + "--\n" + "Owner: Your Followers\n" + "Price: $400.00 Barter value: $50.00\n" ); } + + SECTION( "zero price item with no owner" ) { + iteminfo_test( + item( "rock" ), q, + "--\n" + "Price: $0.00" ); + } + } TEST_CASE( "item rigidity", "[item][iteminfo][rigidity]" ) From 5397f390df143e808473303fcf3e9a7344dcc501 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sun, 16 Feb 2020 06:59:30 -0700 Subject: [PATCH 32/51] Revert 'this item' changes made in earlier commits Reverts changes made by commits 500cb26dc7 and 7edb69813e @Night-Pryanik pointed out that these rephrasing changes would make additional work for translators without much benefit. This commit restores most of them to their previous phrasing. --- data/json/flags.json | 48 ++++++++++++++++++++--------------------- src/item.cpp | 29 ++++++++++++++----------- tests/iteminfo_test.cpp | 16 +++++++------- 3 files changed, 48 insertions(+), 45 deletions(-) diff --git a/data/json/flags.json b/data/json/flags.json index 51b8e8e8c40f8..13c09c2c4ba13 100644 --- a/data/json/flags.json +++ b/data/json/flags.json @@ -26,7 +26,7 @@ "id": "ALLOWS_REMOTE_USE", "type": "json_flag", "context": [ "TOOL" ], - "info": "This tool can be activated or reloaded from adjacent tile without picking it up." + "info": "This item can be activated or reloaded from adjacent tile without picking it up." }, { "id": "AURA", @@ -46,7 +46,7 @@ "id": "BELT_CLIP", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "info": "This tool can be clipped on to a belt loop of the appropriate size." + "info": "This item can be clipped on to a belt loop of the appropriate size." }, { "id": "BELTED", @@ -78,13 +78,13 @@ "id": "BLOCK_WHILE_WORN", "type": "json_flag", "context": [ "ARMOR", "TOOL_ARMOR" ], - "info": "This clothing can be used to block attacks when worn." + "info": "This item can be used to block attacks when worn." }, { "id": "CBM", "type": "json_flag", "context": [ "BIONIC_ITEM" ], - "info": "This is a Compact Bionic Module. You'll need to use specialized machinery or ask a surgeon to install it into your body." + "info": "This item is a Compact Bionic Module. You'll need to use specialized machinery or ask a surgeon to install it into your body." }, { "id": "CLIMATE_CONTROL", @@ -109,20 +109,20 @@ "id": "DIAMOND", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "info": "This tool has a diamond coating improving its cutting or piercing damage.", + "info": "This item has a diamond coating improving its cutting or piercing damage.", "inherit": false }, { "id": "DIG_TOOL", "type": "json_flag", "context": [ "TOOL", "TOOL_ARMOR" ], - "info": "While wielded, it allows you to mine through rocks and other hard obstacles by moving into tiles with them. Note that automatic mining option should be set to true for this to work." + "info": "While wielded, this item allows you to mine through rocks and other hard obstacles by moving into tiles with them. Note that automatic mining option should be set to true for this to work." }, { "id": "DURABLE_MELEE", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "info": "As a weapon, it is well-made and will withstand the punishment of combat.", + "info": "As a weapon, this item is well-made and will withstand the punishment of combat.", "conflicts": [ "FRAGILE_MELEE" ] }, { @@ -147,7 +147,7 @@ "id": "ETHEREAL_ITEM", "type": "json_flag", "context": [ ], - "info": "It disappears as soon as its timer runs out whether it is food or not." + "info": "This item disappears as soon as its timer runs out whether it is food or not." }, { "id": "ONLY_ONE", @@ -167,19 +167,19 @@ "id": "FIRE", "type": "json_flag", "context": [ "GENERIC", "TOOL", "TOOL_ARMOR" ], - "info": "It counts as fire for crafting purposes." + "info": "This item counts as fire for crafting purposes." }, { "id": "FIRESTARTER", "type": "json_flag", "context": [ "GENERIC", "TOOL", "TOOL_ARMOR" ], - "info": "It can start fire." + "info": "This item can start fire." }, { "id": "FIREWOOD", "type": "json_flag", "context": [ "GENERIC" ], - "info": "It can serve as a firewood." + "info": "This item can serve as a firewood." }, { "id": "FIX_FARSIGHT", @@ -199,7 +199,7 @@ "context": [ "ARMOR", "TOOL_ARMOR" ], "//": "Zombie-dropped clothing giving various penalties if Filthy mod is active. Also CBMs harvested from zombies.", "craft_inherit": true, - "info": "It is filthy." + "info": "This item is filthy." }, { "id": "FLASH_PROTECTION", @@ -224,7 +224,7 @@ "id": "FRAGILE_MELEE", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "info": "As a weapon, it is flimsy and won't last long in combat before breaking apart.", + "info": "As a weapon, this item is flimsy and won't last long in combat before breaking apart.", "conflicts": [ "DURABLE_MELEE" ] }, { @@ -249,7 +249,7 @@ "id": "IRREMOVABLE", "type": "json_flag", "context": [ "GUNMOD" ], - "info": "It is a component of the gun it is attached to. It can't be removed without destroying it.", + "info": "This item is a component of the gun it is attached to. It can't be removed without destroying it.", "inherit": false }, { @@ -308,7 +308,7 @@ "id": "UNDERSIZE", "type": "json_flag", "context": [ "ARMOR", "TOOL_ARMOR" ], - "//": "This clothing can be worn comfortably by mutants with Tiny or Unassuming, but is too small for anyone else." + "//": "This clothing can be worn comfortably by mutants with Tiny or Unassuming. Too small for anyone else." }, { "id": "PARTIAL_DEAF", @@ -369,7 +369,7 @@ "id": "TWO_WAY_RADIO", "type": "json_flag", "context": [ "GENERIC", "TOOL_ARMOR", "TOOL" ], - "info": "It can be used to communicate with radio waves." + "info": "This item can be used to communicate with radio waves." }, { "id": "RAINPROOF", @@ -395,31 +395,31 @@ "id": "SHEATH_AXE", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "//": "This tool can be stored in a sheath of the appropriate size." + "//": "This item can be stored in a sheath of the appropriate size." }, { "id": "SHEATH_KNIFE", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "//": "This tool can be stored in a sheath of the appropriate size." + "//": "This item can be stored in a sheath of the appropriate size." }, { "id": "SHEATH_SWORD", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "//": "This tool can be stored in a scabbard of the appropriate size." + "//": "This item can be stored in a scabbard of the appropriate size." }, { "id": "SHEATH_SPEAR", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "//": "This tool can be stored in a sling of the appropriate size." + "//": "This item can be stored in a sling of the appropriate size." }, { "id": "SHEATH_GOLF", "type": "json_flag", "context": [ "GENERIC", "TOOL" ], - "//": "This tool can be stored in a bag of the appropriate size." + "//": "This item can be stored in a bag of the appropriate size." }, { "id": "SKINTIGHT", @@ -480,7 +480,7 @@ "id": "VARSIZE", "type": "json_flag", "context": [ "ARMOR", "TOOL_ARMOR" ], - "//": "This clothing aan be made to fit via tailoring." + "//": "Can be made to fit via tailoring." }, { "id": "WAIST", @@ -516,7 +516,7 @@ "type": "json_flag", "context": [ "ARMOR", "TOOL_ARMOR" ], "//": "Allows power armor to be worn with compatible armors like ear plugs and mouthpieces.", - "info": "This clothing can be worn simultaneously with power armor." + "info": "This item can be worn simultaneously with power armor." }, { "id": "furred", @@ -559,7 +559,7 @@ "id": "NANOFAB_TEMPLATE", "type": "json_flag", "context": [ "generic", "TOOL" ], - "info": "It contains a nanofabricator recipe." + "info": "This item contains a nanofabricator recipe." }, { "id": "BIONIC_FAULTY", diff --git a/src/item.cpp b/src/item.cpp index d428b9d57b617..bee018f41ab88 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1171,7 +1171,7 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, } else { if( has_flag( "MAGIC_FOCUS" ) ) { info.push_back( iteminfo( "DESCRIPTION", - _( "It is a magical focus. " + _( "This item is a magical focus. " "You can cast spells with it in your hand." ) ) ); } if( is_craft() ) { @@ -2249,7 +2249,8 @@ void item::armor_fit_info( std::vector &info, const iteminfo_query *pa if( has_flag( "HELMET_COMPAT" ) && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_HELMETCOMPAT ) ) { info.push_back( iteminfo( "DESCRIPTION", - _( "* It can be worn with a helmet." ) ) ); + _( "* This item can be worn with a " + "helmet." ) ) ); } if( parts->test( iteminfo_parts::DESCRIPTION_FLAGS_FITS ) ) { @@ -2366,7 +2367,8 @@ void item::armor_fit_info( std::vector &info, const iteminfo_query *pa if( is_sided() && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_SIDED ) ) { info.push_back( iteminfo( "DESCRIPTION", - _( "* It can be worn on either side of the body." ) ) ); + _( "* This item can be worn on either side of " + "the body." ) ) ); } if( is_power_armor() && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_POWERARMOR ) ) { info.push_back( iteminfo( "DESCRIPTION", @@ -2660,10 +2662,10 @@ void item::repair_info( std::vector &info, const iteminfo_query *parts return nname( e ); }, enumeration_conjunction::or_ ) ) ); if( reinforceable() ) { - info.emplace_back( "DESCRIPTION", _( "* It can be reinforced." ) ); + info.emplace_back( "DESCRIPTION", _( "* This item can be reinforced." ) ); } } else { - info.emplace_back( "DESCRIPTION", _( "* It is not repairable." ) ); + info.emplace_back( "DESCRIPTION", _( "* This item is not repairable." ) ); } } @@ -2975,11 +2977,11 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts insert_separation_line( info ); if( has_flag( "REACH3" ) ) { info.push_back( iteminfo( "DESCRIPTION", - _( "* It can be used to make long reach " + _( "* This item can be used to make long reach " "attacks." ) ) ); } else { info.push_back( iteminfo( "DESCRIPTION", - _( "* It can be used to make reach " + _( "* This item can be used to make reach " "attacks." ) ) ); } } @@ -3063,13 +3065,14 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, if( parts->test( iteminfo_parts::DESCRIPTION_CONDUCTIVITY ) ) { if( !conductive() ) { - info.push_back( iteminfo( "BASE", _( "* It does not conduct electricity." ) ) ); + info.push_back( iteminfo( "BASE", _( "* This item does not " + "conduct electricity." ) ) ); } else if( has_flag( "CONDUCTIVE" ) ) { info.push_back( iteminfo( "BASE", - _( "* It effectively conducts " + _( "* This item effectively conducts " "electricity, as it has no guard." ) ) ); } else { - info.push_back( iteminfo( "BASE", _( "* It conducts electricity." ) ) ); + info.push_back( iteminfo( "BASE", _( "* This item conducts electricity." ) ) ); } } @@ -3128,11 +3131,11 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, parts->test( iteminfo_parts::DESCRIPTION_RADIO_ACTIVATION ) ) { if( has_flag( "RADIO_MOD" ) ) { info.emplace_back( "DESCRIPTION", - _( "* It has been modified to listen to radio " + _( "* This item has been modified to listen to radio " "signals. It can still be activated manually." ) ); } else { info.emplace_back( "DESCRIPTION", - _( "* It can only be activated by a radio " + _( "* This item can only be activated by a radio " "signal." ) ); } @@ -3296,7 +3299,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, if( this->get_var( "die_num_sides", 0 ) != 0 ) { info.emplace_back( "DESCRIPTION", - string_format( _( "* It can be used as a die, " + string_format( _( "* This item can be used as a die, " "and has %d sides." ), static_cast( this->get_var( "die_num_sides", 0 ) ) ) ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 2141cfe4fa0fc..5e76709c7a915 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -312,22 +312,22 @@ TEST_CASE( "item conductivity", "[item][iteminfo][conductivity]" ) iteminfo_test( item( "2x4" ), q, "--\n" - "* It does not conduct electricity.\n" ); + "* This item does not conduct electricity.\n" ); iteminfo_test( item( "fire_ax" ), q, "--\n" - "* It does not conduct electricity.\n" ); + "* This item does not conduct electricity.\n" ); } SECTION( "conductive items" ) { iteminfo_test( item( "pipe" ), q, "--\n" - "* It conducts electricity.\n" ); + "* This item conducts electricity.\n" ); iteminfo_test( item( "halligan" ), q, "--\n" - "* It conducts electricity.\n" ); + "* This item conducts electricity.\n" ); } } @@ -384,13 +384,13 @@ TEST_CASE( "repairable and with what tools", "[item][iteminfo][repair]" ) iteminfo_test( item( "rock" ), q, "--\n" - "* It is not repairable.\n" ); + "* This item is not repairable.\n" ); /* iteminfo_test( item( "socks" ), q, "--\n" - "* It can be reinforced.\n" ); + "* This item can be reinforced.\n" ); */ } @@ -430,8 +430,8 @@ TEST_CASE( "item description flags", "[item][iteminfo]" ) iteminfo_test( item( "halligan" ), q, "--\n" - "* This tool can be clipped on to a belt loop of the appropriate size.\n" - "* As a weapon, it is well-made and will" + "* This item can be clipped on to a belt loop of the appropriate size.\n" + "* As a weapon, this item is well-made and will" " withstand the punishment of combat.\n" ); iteminfo_test( From e1aa79d270a9bf17612bad67c80bf137d46d9ca7 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sun, 16 Feb 2020 07:09:37 -0700 Subject: [PATCH 33/51] Minor gun info cleanup Also move container/contents/combat info back below med_info and food_info, at the same level as the others (it's not clear why only `basic_info` had the `is_null` check, but I'll leave it more or less how it was for now). --- src/item.cpp | 12 ++++++------ tests/iteminfo_test.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index bee018f41ab88..2e4360e20b4aa 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1617,7 +1617,7 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf const std::string fmt = string_format( ngettext( " round of %s", " rounds of %s", mod->ammo_capacity() ), at->name() ); - info.emplace_back( "GUN", _( "Capacity: " ), fmt, iteminfo::no_flags, + info.emplace_back( "GUN", _( "Capacity: " ), fmt, iteminfo::no_flags, mod->ammo_capacity() ); } } @@ -2604,9 +2604,8 @@ void item::tool_info( std::vector &info, const iteminfo_query *parts, } if( parts->test( iteminfo_parts::TOOL_MAGAZINE_COMPATIBLE ) ) { - insert_separation_line( info ); const std::set compat = magazine_compatible(); - info.emplace_back( "TOOL", _( "Compatible magazines: " ), + info.emplace_back( "TOOL", _( "Compatible magazines: " ), enumerate_as_string( compat.begin(), compat.end(), []( const itype_id & id ) { return item::nname( id ); } ) ); @@ -3384,9 +3383,6 @@ std::string item::info( std::vector &info, const iteminfo_query *parts if( !is_null() ) { basic_info( info, parts, batch, debug ); - container_info( info, parts, batch, debug ); - contents_info( info, parts, batch, debug ); - combat_info( info, parts, batch, debug ); } const item *med_item = nullptr; @@ -3403,6 +3399,10 @@ std::string item::info( std::vector &info, const iteminfo_query *parts food_info( food_item, info, parts, batch, debug ); } + container_info( info, parts, batch, debug ); + contents_info( info, parts, batch, debug ); + combat_info( info, parts, batch, debug ); + magazine_info( info, parts, batch, debug ); ammo_info( info, parts, batch, debug ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 5e76709c7a915..7e8a77d997ef2 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -177,7 +177,7 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged]" ) iteminfo_test( item( "compbow" ), q, "--\n" - "Capacity: 1 round of arrows\n" ); + "Capacity: 1 round of arrows\n" ); } SECTION( "default ammo when unloaded" ) { From 7a98a040ce60ebb5a0b18cd5998d746a2f5cb747 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sun, 16 Feb 2020 15:06:17 -0700 Subject: [PATCH 34/51] Add data/json/TEST with jsons for iteminfo tests This commit shifts some of the test items in `tests/iteminfo_test.cpp` into JSON data loaded from `data/json/TEST`. These items are copy/pasted from existing in-game items, with new IDs (ex. `test_halligan`) and distinctive names (`TEST Halligan bar`). One test item is purely fictional (`test_sonic_screwdriver`). There is not much precedent for this kind of thing in CDDA yet, and I have some uncertainty about these test items possibly appearing in-game. For example, when I tried adding a `test_soldering_iron` to the world item data, repairable items showed "Repairable with: TEST soldering iron", probably based on the tool's attributes alone. So the possibility of polluting the game with test items is my big concern with this approach. A cleaner alternative would be to give the TEST jsons their own standalone directory, but I haven't figured out how to do that, so I hope this commit is good enough for a first step. --- data/json/TEST/README.md | 9 +++ data/json/TEST/items.json | 150 ++++++++++++++++++++++++++++++++++++ data/json/TEST/uncraft.json | 11 +++ tests/iteminfo_test.cpp | 69 +++++++---------- 4 files changed, 199 insertions(+), 40 deletions(-) create mode 100644 data/json/TEST/README.md create mode 100644 data/json/TEST/items.json create mode 100644 data/json/TEST/uncraft.json diff --git a/data/json/TEST/README.md b/data/json/TEST/README.md new file mode 100644 index 0000000000000..d940f58111f0a --- /dev/null +++ b/data/json/TEST/README.md @@ -0,0 +1,9 @@ +# Test JSON Data # + +JSON files placed within `data/json/TEST` should only contain data for testing. +None of the items, recipes, or other content here should appear in-game except +through debug-spawning. + +Use a lowercase `test_` prefix for all `id` strings, and an all-caps `TEST` prefix +in the `name` field, to clearly distinguish them from "real" (live in-game) data. + diff --git a/data/json/TEST/items.json b/data/json/TEST/items.json new file mode 100644 index 0000000000000..06506fd28d488 --- /dev/null +++ b/data/json/TEST/items.json @@ -0,0 +1,150 @@ +[ + { + "type": "AMMO", + "id": "test_rock", + "symbol": "*", + "color": "light_gray", + "name": "TEST rock", + "description": "A rock the size of a baseball. Makes a decent melee weapon, and is also good for throwing at enemies.", + "category": "spare_parts", + "material": "stone", + "ammo_type": "rock", + "flags": "TRADER_AVOID", + "weight": "657 g", + "volume": "250 ml", + "bashing": 7, + "damage": 7, + "range": 10, + "dispersion": 14, + "loudness": 0, + "to_hit": -2, + "effects": [ "NEVER_MISFIRES", "NON-FOULING", "RECOVER_80" ], + "qualities": [ [ "HAMMER", 1 ] ] + }, + { + "type": "GENERIC", + "id": "test_sheet_metal", + "name": "TEST sheet metal", + "description": "A thin sheet of metal.", + "//": "Roughly in the 70cm×70cm×1.5mm to 1m×1m×0.75mm range. Has to be folded / rolled up when in inventory, so 75% density compared to solid block.", + "weight": "6000 g", + "to_hit": -2, + "color": "light_cyan", + "symbol": "]", + "material": [ "steel" ], + "volume": "1 L", + "bashing": 5, + "category": "spare_parts", + "price": 6000, + "qualities": [ [ "COOK", 1 ] ] + }, + { + "id": "test_sheet_metal_small", + "type": "AMMO", + "category": "spare_parts", + "name": "TEST small metal sheet", + "description": "A small sheet of metal.", + "looks_like": "test_sheet_metal", + "weight": "250 g", + "volume": "250 ml", + "price": 2000, + "bashing": 5, + "to_hit": -3, + "stack_size": 8, + "//": "Roughly in the 15cm×15cm to 20cm×20cm range. Compact and stacks well, so equally dense as a solid block.", + "material": "steel", + "symbol": "]", + "color": "light_cyan", + "ammo_type": "components" + }, + { + "id": "test_halligan", + "type": "TOOL", + "name": "TEST Halligan bar", + "description": "This is a heavy multiple-use tool commonly carried by firefighters, law enforcement, and military rescue units. Use it to open locked doors without destroying them or to lift manhole covers. You could also wield it to bash some heads in.", + "weight": "3600 g", + "volume": "1250 ml", + "price": 7500, + "to_hit": 2, + "bashing": 20, + "cutting": 5, + "material": "steel", + "symbol": ";", + "color": "dark_gray", + "techniques": [ "WBLOCK_1", "BRUTAL", "SWEEP" ], + "qualities": [ [ "PRY", 4 ], [ "HAMMER", 2 ], [ "DIG", 1 ] ], + "use_action": [ "HAMMER", "CROWBAR" ], + "flags": [ "DURABLE_MELEE", "BELT_CLIP" ] + }, + { + "id": "test_screwdriver", + "type": "TOOL", + "name": "TEST screwdriver", + "description": "This is a Philips-head screwdriver. It is important for almost all electronics crafting, most mechanics crafting, and has many more uses.", + "weight": "170 g", + "volume": "250 ml", + "price": 450, + "to_hit": -1, + "bashing": 2, + "cutting": 6, + "material": [ "steel", "plastic" ], + "symbol": ";", + "color": "yellow", + "qualities": [ [ "SCREW", 1 ] ], + "flags": [ "SPEAR", "BELT_CLIP" ] + }, + { + "id": "test_sonic_screwdriver", + "type": "TOOL", + "name": "TEST sonic screwdriver", + "description": "This is a sonic screwdriver. Like a normal screwdriver, but sonic.", + "weight": "170 g", + "volume": "250 ml", + "price": 450, + "to_hit": -1, + "bashing": 2, + "cutting": 6, + "material": [ "steel", "plastic" ], + "symbol": ";", + "color": "yellow", + "qualities": [ [ "SCREW", 2 ], [ "SCREW_FINE", 1 ], [ "WRENCH", 1 ], [ "PRY", 2 ] ], + "use_action": { "type": "picklock", "pick_quality": 30 }, + "flags": [ "SPEAR", "BELT_CLIP" ] + }, + { + "id": "test_jack_small", + "type": "TOOL", + "name": "TEST scissor jack", + "description": "A compact scissor jack used for lifting vehicles.", + "material": "steel", + "symbol": ";", + "color": "light_gray", + "weight": "3000 g", + "volume": "750 ml", + "price": 5000, + "bashing": 4, + "to_hit": -2, + "qualities": [ [ "JACK", 4 ] ] + }, + { + "id": "test_hazmat_suit", + "repairs_like": "aep_suit", + "type": "ARMOR", + "name": "TEST hazmat suit", + "description": "An impermeable whole-body garment worn as protection against hazardous materials. Though very restrictive and fragile, wearing it will provide complete protection against ambient radiation. It requires a separate gas mask for full protection.", + "weight": "5000 g", + "volume": "17 L", + "price": 117500, + "material": [ "plastic" ], + "symbol": "[", + "looks_like": "beekeeping_suit", + "color": "yellow", + "covers": [ "HEAD", "TORSO", "ARMS", "HANDS", "LEGS", "FEET" ], + "coverage": 100, + "encumbrance": 37, + "warmth": 40, + "material_thickness": 2, + "environmental_protection": 20, + "flags": [ "VARSIZE", "WATERPROOF", "RAINPROOF", "GAS_PROOF", "RAD_PROOF", "ELECTRIC_IMMUNE", "OUTER" ] + } +] diff --git a/data/json/TEST/uncraft.json b/data/json/TEST/uncraft.json new file mode 100644 index 0000000000000..eb45166312399 --- /dev/null +++ b/data/json/TEST/uncraft.json @@ -0,0 +1,11 @@ +[ + { + "result": "test_sheet_metal", + "type": "uncraft", + "skill_used": "fabrication", + "difficulty": 1, + "time": "150 s", + "qualities": [ { "id": "SAW_M", "level": 2 } ], + "components": [ [ [ "test_sheet_metal_small", 24 ] ] ] + } +] diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 7e8a77d997ef2..da8bf69b4bba3 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -41,7 +41,7 @@ TEST_CASE( "item owner, price, and barter value", "[item][iteminfo][price]" ) iteminfo_query q( { iteminfo_parts::BASE_PRICE, iteminfo_parts::BASE_BARTER } ); SECTION( "owner and price" ) { - item my_rock( "rock" ); + item my_rock( "test_rock" ); my_rock.set_owner( g->u ); iteminfo_test( my_rock, q, @@ -62,7 +62,7 @@ TEST_CASE( "item owner, price, and barter value", "[item][iteminfo][price]" ) SECTION( "zero price item with no owner" ) { iteminfo_test( - item( "rock" ), q, + item( "test_rock" ), q, "--\n" "Price: $0.00" ); } @@ -93,7 +93,7 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) SECTION( "bash damage" ) { iteminfo_test( - item( "rock" ), q, + item( "test_rock" ), q, "--\n" "Damage: Bash: 7" " To-hit bonus: -2\n" @@ -102,7 +102,7 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) SECTION( "bash and cut damage" ) { iteminfo_test( - item( "halligan" ), q, + item( "test_halligan" ), q, "--\n" "Damage: Bash: 20" " Cut: 5" @@ -131,7 +131,7 @@ TEST_CASE( "techniques when wielded", "[item][iteminfo][weapon]" ) iteminfo_query q( { iteminfo_parts::DESCRIPTION_TECHNIQUES } ); iteminfo_test( - item( "halligan" ), q, + item( "test_halligan" ), q, "--\n" "Techniques when wielded:" " Brutal Strike: Stun 1 turn, knockback 1 tile, crit only," @@ -236,7 +236,7 @@ TEST_CASE( "ammunition", "[item][iteminfo][ammo]" ) SECTION( "simple item with ammo damage" ) { iteminfo_test( - item( "rock" ), q, + item( "test_rock" ), q, "--\n" "Ammunition type: rocks\n" "Damage: 7 Armor-pierce: 0\n" @@ -325,7 +325,7 @@ TEST_CASE( "item conductivity", "[item][iteminfo][conductivity]" ) "--\n" "* This item conducts electricity.\n" ); iteminfo_test( - item( "halligan" ), q, + item( "test_halligan" ), q, "--\n" "* This item conducts electricity.\n" ); } @@ -335,24 +335,9 @@ TEST_CASE( "list of item qualities", "[item][iteminfo][quality]" ) { iteminfo_query q( { iteminfo_parts::QUALITIES } ); - SECTION( "screwdriver" ) { - iteminfo_test( - item( "screwdriver" ), q, - "--\n" - "Has level 1 screw driving quality.\n" ); - } - - SECTION( "screwdriver set" ) { - iteminfo_test( - item( "screwdriver_set" ), q, - "--\n" - "Has level 1 screw driving quality.\n" - "Has level 1 fine screw driving quality.\n" ); - } - SECTION( "Halligan bar" ) { iteminfo_test( - item( "halligan" ), q, + item( "test_halligan" ), q, "--\n" "Has level 1 digging quality.\n" "Has level 2 hammering quality.\n" @@ -361,10 +346,21 @@ TEST_CASE( "list of item qualities", "[item][iteminfo][quality]" ) SECTION( "bottle jack" ) { iteminfo_test( - item( "jack_small" ), q, + item( "test_jack_small" ), q, "--\n" "Has level 4 jacking quality and is rated at 4409 lbs\n" ); } + + SECTION( "sonic screwdriver" ) { + iteminfo_test( + item( "test_sonic_screwdriver" ), q, + "--\n" + "Has level 2 prying quality.\n" + "Has level 2 screw driving quality.\n" + "Has level 1 fine screw driving quality.\n" + "Has level 1 bolt turning quality.\n" ); + } + } TEST_CASE( "repairable and with what tools", "[item][iteminfo][repair]" ) @@ -372,17 +368,17 @@ TEST_CASE( "repairable and with what tools", "[item][iteminfo][repair]" ) iteminfo_query q( { iteminfo_parts::DESCRIPTION_REPAIREDWITH } ); iteminfo_test( - item( "halligan" ), q, + item( "test_halligan" ), q, "--\n" "Repair using extended toolset, arc welder, or makeshift arc welder.\n" ); iteminfo_test( - item( "hazmat_suit" ), q, + item( "test_hazmat_suit" ), q, "--\n" "Repair using soldering iron or extended toolset.\n" ); iteminfo_test( - item( "rock" ), q, + item( "test_rock" ), q, "--\n" "* This item is not repairable.\n" ); @@ -398,29 +394,22 @@ TEST_CASE( "disassembly time and yield", "[item][iteminfo][disassembly]" ) { iteminfo_query q( { iteminfo_parts::DESCRIPTION_COMPONENTS_DISASSEMBLE } ); - // long string - iteminfo_test( - item( "string_36" ), q, - "--\n" - "Disassembly takes about 5 minutes and might yield: 6 short strings.\n" ); - // short string iteminfo_test( item( "string_6" ), q, "--\n" "Disassembly takes about 5 minutes and might yield: thread (50).\n" ); - iteminfo_test( - item( "sheet_metal" ), q, - "--\n" - "Disassembly takes about 2 minutes and might yield: small metal sheet (24).\n" ); - iteminfo_test( item( "soldering_iron" ), q, "--\n" "Disassembly takes about 20 minutes and might yield:" " 2 electronic scraps, copper (1), scrap metal (1), and copper wire (5).\n" ); + iteminfo_test( + item( "test_sheet_metal" ), q, + "--\n" + "Disassembly takes about 2 minutes and might yield: TEST small metal sheet (24).\n" ); } TEST_CASE( "item description flags", "[item][iteminfo]" ) @@ -428,14 +417,14 @@ TEST_CASE( "item description flags", "[item][iteminfo]" ) iteminfo_query q( { iteminfo_parts::DESCRIPTION_FLAGS } ); iteminfo_test( - item( "halligan" ), q, + item( "test_halligan" ), q, "--\n" "* This item can be clipped on to a belt loop of the appropriate size.\n" "* As a weapon, this item is well-made and will" " withstand the punishment of combat.\n" ); iteminfo_test( - item( "hazmat_suit" ), q, + item( "test_hazmat_suit" ), q, "--\n" "* This gear completely protects you from" " electric discharges.\n" From a22f442897e89aa3c20430f9aa36c57e06febd9c Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sun, 16 Feb 2020 20:56:16 -0700 Subject: [PATCH 35/51] Reduce boldness in uses info for consistency To make these `info` functions more consistent with the other highlighting style practices in the item info panel, the use of bold is reduced. For healing info, a single bold heading is included for all healing effects. --- src/iuse_actor.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index aa816181127b4..3677f32547698 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -459,11 +459,11 @@ void explosion_iuse::info( const item &, std::vector &dump ) const return; } - dump.emplace_back( "TOOL", _( "Power at epicenter: " ), explosion.power ); + dump.emplace_back( "TOOL", _( "Power at epicenter: " ), explosion.power ); const auto &sd = explosion.shrapnel; if( sd.casing_mass > 0 ) { - dump.emplace_back( "TOOL", _( "Casing mass: " ), sd.casing_mass ); - dump.emplace_back( "TOOL", _( "Fragment mass: " ), string_format( "%.2f", + dump.emplace_back( "TOOL", _( "Casing mass: " ), sd.casing_mass ); + dump.emplace_back( "TOOL", _( "Fragment mass: " ), string_format( "%.2f", sd.fragment_mass ) ); } } @@ -3816,13 +3816,18 @@ hp_part heal_actor::use_healing_item( player &healer, player &patient, item &it, void heal_actor::info( const item &, std::vector &dump ) const { + if( head_power > 0 || torso_power > 0 || limb_power > 0 || bandages_power > 0 || + disinfectant_power > 0 || bleed > 0.0f || bite > 0.0f || infect > 0.0f ) { + dump.emplace_back( "HEAL", _( "Healing effects " ) ); + } + if( head_power > 0 || torso_power > 0 || limb_power > 0 ) { - dump.emplace_back( "HEAL", _( "Base healing: " ) ); + dump.emplace_back( "HEAL", _( "Base healing: " ) ); dump.emplace_back( "HEAL_BASE", _( "Head: " ), "", iteminfo::no_newline, head_power ); dump.emplace_back( "HEAL_BASE", _( " Torso: " ), "", iteminfo::no_newline, torso_power ); dump.emplace_back( "HEAL_BASE", _( " Limbs: " ), limb_power ); if( g != nullptr ) { - dump.emplace_back( "HEAL", _( "Actual healing: " ) ); + dump.emplace_back( "HEAL", _( "Actual healing: " ) ); dump.emplace_back( "HEAL_ACT", _( "Head: " ), "", iteminfo::no_newline, get_heal_value( g->u, hp_head ) ); dump.emplace_back( "HEAL_ACT", _( " Torso: " ), "", iteminfo::no_newline, @@ -3832,25 +3837,25 @@ void heal_actor::info( const item &, std::vector &dump ) const } if( bandages_power > 0 ) { - dump.emplace_back( "HEAL", _( "Base bandaging quality: " ), + dump.emplace_back( "HEAL", _( "Base bandaging quality: " ), texitify_base_healing_power( static_cast( bandages_power ) ) ); if( g != nullptr ) { - dump.emplace_back( "HEAL", _( "Actual bandaging quality: " ), + dump.emplace_back( "HEAL", _( "Actual bandaging quality: " ), texitify_healing_power( get_bandaged_level( g->u ) ) ); } } if( disinfectant_power > 0 ) { - dump.emplace_back( "HEAL", _( "Base disinfecting quality: " ), + dump.emplace_back( "HEAL", _( "Base disinfecting quality: " ), texitify_base_healing_power( static_cast( disinfectant_power ) ) ); if( g != nullptr ) { - dump.emplace_back( "HEAL", _( "Actual disinfecting quality: " ), + dump.emplace_back( "HEAL", _( "Actual disinfecting quality: " ), texitify_healing_power( get_disinfected_level( g->u ) ) ); } } if( bleed > 0.0f || bite > 0.0f || infect > 0.0f ) { - dump.emplace_back( "HEAL", _( "Chance to heal (percent): " ) ); + dump.emplace_back( "HEAL", _( "Chance to heal (percent): " ) ); if( bleed > 0.0f ) { dump.emplace_back( "HEAL", _( "* Bleeding: " ), static_cast( bleed * 100 ) ); @@ -3865,7 +3870,7 @@ void heal_actor::info( const item &, std::vector &dump ) const } } - dump.emplace_back( "HEAL", _( "Moves to use: " ), move_cost ); + dump.emplace_back( "HEAL", _( "Moves to use: " ), move_cost ); } place_trap_actor::place_trap_actor( const std::string &type ) : From 35134e35b2e49d69a3e5b637878de8a08b85e364 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sun, 16 Feb 2020 21:00:35 -0700 Subject: [PATCH 36/51] Move item uses section above repair/disassembly This relocates the item description section that covers bandage and disinfectant healing qualities, what will fit into a holster, and what an item turns into (such as a grenade with a countdown timer). Those things are important enough to promote out of `final_info` (but not really big enough to promote into a standalone function); for now place them between qualities and repair/disassembly info. --- src/item.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 2e4360e20b4aa..88475ce51f6cc 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -3053,13 +3053,6 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, const std::string space = " "; - if( parts->test( iteminfo_parts::DESCRIPTION_USE_METHODS ) ) { - for( const std::pair &method : type->use_methods ) { - insert_separation_line( info ); - method.second.dump_info( *this, info ); - } - } - insert_separation_line( info ); if( parts->test( iteminfo_parts::DESCRIPTION_CONDUCTIVITY ) ) { @@ -3431,6 +3424,15 @@ std::string item::info( std::vector &info, const iteminfo_query *parts tool_info( info, parts, batch, debug ); component_info( info, parts, batch, debug ); qualities_info( info, parts, batch, debug ); + + // Uses for item (bandaging quality, holster capacity, grenade activation) + if( parts->test( iteminfo_parts::DESCRIPTION_USE_METHODS ) ) { + for( const std::pair &method : type->use_methods ) { + insert_separation_line( info ); + method.second.dump_info( *this, info ); + } + } + repair_info( info, parts, batch, debug ); disassembly_info( info, parts, batch, debug ); From ac6e1c89c23849d6adcec382f57f44468d83e1b0 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sun, 16 Feb 2020 21:03:54 -0700 Subject: [PATCH 37/51] Move techniques above average melee damage Average melee damage is kind of long; put it at the end of combat info. --- src/item.cpp | 80 +++++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 88475ce51f6cc..61fe94baa1b86 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1410,6 +1410,8 @@ void item::food_info( const item *food_item, std::vector &info, info.emplace_back( "FOOD", _( "Other contents: " ), effect_vits ); } + insert_separation_line( info ); + if( g->u.allergy_type( *food_item ) != morale_type( "morale_null" ) ) { info.emplace_back( "DESCRIPTION", _( "* This food will cause an allergic reaction." ) ); @@ -2899,6 +2901,45 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts } } + if( parts->test( iteminfo_parts::DESCRIPTION_TECHNIQUES ) ) { + std::set all_techniques = type->techniques; + all_techniques.insert( techniques.begin(), techniques.end() ); + + if( !all_techniques.empty() ) { + insert_separation_line( info ); + info.push_back( iteminfo( "DESCRIPTION", _( "Techniques when wielded: " ) + + enumerate_as_string( all_techniques.begin(), all_techniques.end(), []( const matec_id & tid ) { + return string_format( "%s: %s", _( tid.obj().name ), + _( tid.obj().description ) ); + } ) ) ); + } + } + + // display which martial arts styles character can use with this weapon + if( parts->test( iteminfo_parts::DESCRIPTION_APPLICABLEMARTIALARTS ) ) { + const std::string valid_styles = g->u.martial_arts_data.enumerate_known_styles( typeId() ); + if( !valid_styles.empty() ) { + insert_separation_line( info ); + info.push_back( iteminfo( "DESCRIPTION", + _( "You know how to use this with these martial arts " + "styles: " ) + valid_styles ) ); + } + } + + if( !is_gunmod() && has_flag( "REACH_ATTACK" ) && + parts->test( iteminfo_parts::DESCRIPTION_GUNMOD_ADDREACHATTACK ) ) { + insert_separation_line( info ); + if( has_flag( "REACH3" ) ) { + info.push_back( iteminfo( "DESCRIPTION", + _( "* This item can be used to make long reach " + "attacks." ) ) ); + } else { + info.push_back( iteminfo( "DESCRIPTION", + _( "* This item can be used to make reach " + "attacks." ) ) ); + } + } + ///\EFFECT_MELEE >2 allows seeing melee damage stats on weapons if( ( g->u.get_skill_level( skill_melee ) > 2 && ( dmg_bash || dmg_cut || dmg_stab || type->m_to_hit > 0 ) ) || debug_mode ) { @@ -2945,45 +2986,6 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts } insert_separation_line( info ); } - - if( parts->test( iteminfo_parts::DESCRIPTION_TECHNIQUES ) ) { - std::set all_techniques = type->techniques; - all_techniques.insert( techniques.begin(), techniques.end() ); - - if( !all_techniques.empty() ) { - insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", _( "Techniques when wielded: " ) + - enumerate_as_string( all_techniques.begin(), all_techniques.end(), []( const matec_id & tid ) { - return string_format( "%s: %s", _( tid.obj().name ), - _( tid.obj().description ) ); - } ) ) ); - } - } - - // display which martial arts styles character can use with this weapon - if( parts->test( iteminfo_parts::DESCRIPTION_APPLICABLEMARTIALARTS ) ) { - const std::string valid_styles = g->u.martial_arts_data.enumerate_known_styles( typeId() ); - if( !valid_styles.empty() ) { - insert_separation_line( info ); - info.push_back( iteminfo( "DESCRIPTION", - _( "You know how to use this with these martial arts " - "styles: " ) + valid_styles ) ); - } - } - - if( !is_gunmod() && has_flag( "REACH_ATTACK" ) && - parts->test( iteminfo_parts::DESCRIPTION_GUNMOD_ADDREACHATTACK ) ) { - insert_separation_line( info ); - if( has_flag( "REACH3" ) ) { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be used to make long reach " - "attacks." ) ) ); - } else { - info.push_back( iteminfo( "DESCRIPTION", - _( "* This item can be used to make reach " - "attacks." ) ) ); - } - } } void item::contents_info( std::vector &info, const iteminfo_query *parts, int batch, From eae8cdfc4751df2af7784e985767370333e02cb8 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sun, 16 Feb 2020 21:15:41 -0700 Subject: [PATCH 38/51] Bold 'Covers'; add separation before qualities --- src/item.cpp | 3 ++- tests/iteminfo_test.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 61fe94baa1b86..ad55cd08901a4 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2047,7 +2047,7 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, bool covers_anything = covered_parts.any(); if( parts->test( iteminfo_parts::ARMOR_BODYPARTS ) ) { - std::string coverage = _( "Covers: " ); + std::string coverage = _( "Covers: " ); if( covers( bp_head ) ) { coverage += _( "The head. " ); } @@ -2716,6 +2716,7 @@ void item::qualities_info( std::vector &info, const iteminfo_query *pa }; if( parts->test( iteminfo_parts::QUALITIES ) ) { + insert_separation_line( info ); for( const std::pair &q : type->qualities ) { name_quality( q ); } diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index da8bf69b4bba3..c4feb59ecba8c 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -152,7 +152,7 @@ TEST_CASE( "armor coverage and protection values", "[item][iteminfo][armor]" ) item( "longshirt" ), q, "--\n" // NOLINTNEXTLINE(cata-text-style) - "Covers: The torso. The arms. \n" + "Covers: The torso. The arms. \n" // NOLINTNEXTLINE(cata-text-style) "Layer: Normal. \n" "Coverage: 90% Warmth: 5\n" @@ -166,7 +166,7 @@ TEST_CASE( "armor coverage and protection values", "[item][iteminfo][armor]" ) iteminfo_test( item( "ear_plugs" ), q, "--\n" - "Covers: Nothing.\n" ); + "Covers: Nothing.\n" ); } } From 853601c3e10ddeaa36c7443fd88ae83c190095ef Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sun, 16 Feb 2020 22:12:41 -0700 Subject: [PATCH 39/51] Move data/json/TEST to data/mods/TEST_DATA Suggested by @ifreund, using a mod to load test data seems to work nicely, and should avoid any concerns of test data polluting a live game world. This commit creates a TEST_DATA mod, populated with a few json items and uncraft recipe as proof of concept, and forces the mod to be always loaded by `test_main.cpp`. --- data/json/TEST/README.md | 9 --------- data/mods/TEST_DATA/README.md | 4 ++++ data/{json/TEST => mods/TEST_DATA}/items.json | 0 data/mods/TEST_DATA/modinfo.json | 10 ++++++++++ data/{json/TEST => mods/TEST_DATA}/uncraft.json | 0 tests/test_main.cpp | 3 +++ 6 files changed, 17 insertions(+), 9 deletions(-) delete mode 100644 data/json/TEST/README.md create mode 100644 data/mods/TEST_DATA/README.md rename data/{json/TEST => mods/TEST_DATA}/items.json (100%) create mode 100644 data/mods/TEST_DATA/modinfo.json rename data/{json/TEST => mods/TEST_DATA}/uncraft.json (100%) diff --git a/data/json/TEST/README.md b/data/json/TEST/README.md deleted file mode 100644 index d940f58111f0a..0000000000000 --- a/data/json/TEST/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Test JSON Data # - -JSON files placed within `data/json/TEST` should only contain data for testing. -None of the items, recipes, or other content here should appear in-game except -through debug-spawning. - -Use a lowercase `test_` prefix for all `id` strings, and an all-caps `TEST` prefix -in the `name` field, to clearly distinguish them from "real" (live in-game) data. - diff --git a/data/mods/TEST_DATA/README.md b/data/mods/TEST_DATA/README.md new file mode 100644 index 0000000000000..696d350deb246 --- /dev/null +++ b/data/mods/TEST_DATA/README.md @@ -0,0 +1,4 @@ +# Test Data pseudo-mod # + +This mod is purely for loading data to be used by `tests/cata_test`. + diff --git a/data/json/TEST/items.json b/data/mods/TEST_DATA/items.json similarity index 100% rename from data/json/TEST/items.json rename to data/mods/TEST_DATA/items.json diff --git a/data/mods/TEST_DATA/modinfo.json b/data/mods/TEST_DATA/modinfo.json new file mode 100644 index 0000000000000..411f5836568f8 --- /dev/null +++ b/data/mods/TEST_DATA/modinfo.json @@ -0,0 +1,10 @@ +[ + { + "type": "MOD_INFO", + "ident": "test_data", + "name": "TESTING DATA", + "description": "Adds mockup items, recipes, and other content for use by automated tests.", + "category": "content", + "dependencies": [ "dda" ] + } +] diff --git a/data/json/TEST/uncraft.json b/data/mods/TEST_DATA/uncraft.json similarity index 100% rename from data/json/TEST/uncraft.json rename to data/mods/TEST_DATA/uncraft.json diff --git a/tests/test_main.cpp b/tests/test_main.cpp index dd6134cb879c3..8b2ef84b7be8d 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -78,6 +78,9 @@ static std::vector extract_mod_selection( std::vector &arg ret.emplace_back( mod_name ); } } + // Always load test data mod + ret.emplace_back( "test_data" ); + return ret; } From 463e31b578c9feb45fac5e692fdb6646e6abe878 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Sun, 16 Feb 2020 22:28:08 -0700 Subject: [PATCH 40/51] Mark TEST_DATA mod as obsolete (not really tho) --- data/mods/TEST_DATA/modinfo.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/mods/TEST_DATA/modinfo.json b/data/mods/TEST_DATA/modinfo.json index 411f5836568f8..30ee50eab60b8 100644 --- a/data/mods/TEST_DATA/modinfo.json +++ b/data/mods/TEST_DATA/modinfo.json @@ -5,6 +5,8 @@ "name": "TESTING DATA", "description": "Adds mockup items, recipes, and other content for use by automated tests.", "category": "content", + "//": "Not really obsolete! Marked as such to prevent it from showing in the main list", + "obsolete": true, "dependencies": [ "dda" ] } ] From 49f50d50b7360bfc1065864de5d5838839e3a44f Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Mon, 17 Feb 2020 09:04:41 -0700 Subject: [PATCH 41/51] Move most iteminfo test items to TEST_DATA Make tests more resilient against in-game item changes by using the TEST_DATA mod for most of them. A few more could be factored out too. This commit also splits the former `iteminfo_test` function into two, to allow a "contains" match as well: test_iteminfo_equals test_iteminfo_contains The only real use case for "contains" so far is the reinforcement test for socks, for which I don't care to verify the repairing tools list (since it may or may not contain the Magiclysm "enchanted tailor's kit"). Anyway it seems applicable for other situations too, and should make tests a little more flexible. --- data/mods/TEST_DATA/items.json | 239 +++++++++++++++++++++++++++++++ data/mods/TEST_DATA/recipes.json | 23 +++ tests/iteminfo_test.cpp | 158 ++++++++++---------- 3 files changed, 339 insertions(+), 81 deletions(-) create mode 100644 data/mods/TEST_DATA/recipes.json diff --git a/data/mods/TEST_DATA/items.json b/data/mods/TEST_DATA/items.json index 06506fd28d488..e2fc54cf09fae 100644 --- a/data/mods/TEST_DATA/items.json +++ b/data/mods/TEST_DATA/items.json @@ -21,6 +21,57 @@ "effects": [ "NEVER_MISFIRES", "NON-FOULING", "RECOVER_80" ], "qualities": [ [ "HAMMER", 1 ] ] }, + { + "id": "test_rag", + "type": "TOOL", + "category": "spare_parts", + "name": "TEST rag", + "description": "This is a largish piece of cloth, useful in crafting and possibly for staunching bleeding.", + "weight": "80 g", + "volume": "250 ml", + "price": 0, + "material": "cotton", + "symbol": ",", + "color": "white", + "use_action": [ { "type": "heal", "move_cost": 200, "used_up_item": "rag_bloody", "bleed": 0.5, "limb_power": 0 }, "WASH_HARD_ITEMS" ], + "flags": [ "NO_SALVAGE" ] + }, + { + "type": "GENERIC", + "id": "test_2x4", + "name": "TEST plank", + "description": "A narrow, thick plank of wood, like a 2 by 4 or similar piece of dimensional lumber. Makes a decent melee weapon, and can be used for all kinds construction.", + "category": "spare_parts", + "weight": "2200 g", + "to_hit": 1, + "color": "brown", + "symbol": "/", + "material": [ "wood" ], + "techniques": [ "WBLOCK_1" ], + "volume": "4400 ml", + "bashing": 10, + "price": 1000, + "price_postapoc": 0, + "flags": [ "FIREWOOD" ] + }, + { + "type": "GENERIC", + "id": "test_pipe", + "name": "TEST pipe", + "description": "A steel pipe, makes a good melee weapon. Useful in a few crafting recipes.", + "category": "spare_parts", + "weight": "1250 g", + "to_hit": 1, + "color": "dark_gray", + "symbol": "/", + "material": [ "steel" ], + "qualities": [ [ "HAMMER", 1 ] ], + "techniques": [ "WBLOCK_1" ], + "volume": "1 L", + "bashing": 12, + "price": 7500, + "price_postapoc": 300 + }, { "type": "GENERIC", "id": "test_sheet_metal", @@ -76,6 +127,25 @@ "use_action": [ "HAMMER", "CROWBAR" ], "flags": [ "DURABLE_MELEE", "BELT_CLIP" ] }, + { + "id": "test_fire_ax", + "type": "TOOL", + "name": "TEST fire axe", + "description": "This is a large, two-handed pickhead axe normally used by firefighters. It makes a powerful melee weapon, but is a bit slow to recover between swings.", + "weight": "2520 g", + "volume": "2 L", + "price": 20000, + "to_hit": 1, + "bashing": 20, + "cutting": 20, + "material": [ "steel", "wood" ], + "symbol": "/", + "color": "light_gray", + "techniques": [ "WBLOCK_1", "BRUTAL", "SWEEP" ], + "qualities": [ [ "AXE", 2 ], [ "PRY", 3 ], [ "BUTCHER", -30 ] ], + "flags": [ "DURABLE_MELEE", "NONCONDUCTIVE", "BELT_CLIP", "SHEATH_AXE" ], + "use_action": "CROWBAR" + }, { "id": "test_screwdriver", "type": "TOOL", @@ -111,6 +181,49 @@ "use_action": { "type": "picklock", "pick_quality": 30 }, "flags": [ "SPEAR", "BELT_CLIP" ] }, + { + "id": "test_soldering_iron", + "type": "TOOL", + "name": "TEST soldering iron", + "description": "This is a device with a metal tip that can get very hot. It is necessary for advanced electronics crafting. You could also use it to cauterize wounds, if you had to.", + "weight": "181 g", + "volume": "500 ml", + "price": 1000, + "bashing": 2, + "cutting": 6, + "material": "iron", + "symbol": ",", + "color": "light_gray", + "ammo": "battery", + "charges_per_use": 1, + "use_action": [ + { + "type": "repair_item", + "item_action_type": "repair_metal", + "materials": [ "plastic", "lead", "tin", "zinc" ], + "skill": "fabrication", + "cost_scaling": 0.1, + "move_cost": 1500 + }, + { "flame": false, "type": "cauterize" } + ], + "flags": [ "SPEAR", "BELT_CLIP", "ALLOWS_REMOTE_USE" ], + "magazines": [ + [ + "battery", + [ + "light_minus_battery_cell", + "light_battery_cell", + "light_plus_battery_cell", + "light_atomic_battery_cell", + "light_minus_atomic_battery_cell", + "light_minus_disposable_cell", + "light_disposable_cell" + ] + ] + ], + "magazine_well": 1 + }, { "id": "test_jack_small", "type": "TOOL", @@ -126,6 +239,58 @@ "to_hit": -2, "qualities": [ [ "JACK", 4 ] ] }, + { + "id": "test_socks", + "type": "ARMOR", + "name": { "str": "TEST pair of socks", "str_pl": "TEST pairs of socks" }, + "description": "Socks. Put 'em on your feet.", + "weight": "32 g", + "volume": "250 ml", + "price": 200, + "material": [ "cotton" ], + "symbol": "[", + "looks_like": "socks_wool", + "color": "white", + "covers": [ "FEET" ], + "coverage": 100, + "warmth": 5, + "material_thickness": 1, + "flags": [ "VARSIZE", "SKINTIGHT" ] + }, + { + "id": "test_longshirt", + "type": "ARMOR", + "name": "TEST long-sleeved shirt", + "description": "A long-sleeved cotton shirt.", + "weight": "146 g", + "volume": "750 ml", + "price": 2000, + "material": [ "cotton" ], + "symbol": "[", + "looks_like": "dress_shirt", + "color": "blue", + "covers": [ "TORSO", "ARMS" ], + "coverage": 90, + "encumbrance": 3, + "warmth": 5, + "material_thickness": 1, + "flags": [ "VARSIZE" ] + }, + { + "id": "test_ear_plugs", + "type": "ARMOR", + "name": { "str": "TEST pair of ear plugs", "str_pl": "TEST pairs of ear plugs" }, + "description": "Industrial grade ear plugs. They fit inside the ear.", + "weight": "10 g", + "volume": "10 ml", + "price": 10, + "material": [ "plastic" ], + "symbol": ";", + "color": "light_gray", + "coverage": 1, + "material_thickness": 1, + "flags": [ "DEAF", "OVERSIZE", "POWERARMOR_COMPATIBLE" ] + }, { "id": "test_hazmat_suit", "repairs_like": "aep_suit", @@ -146,5 +311,79 @@ "material_thickness": 2, "environmental_protection": 20, "flags": [ "VARSIZE", "WATERPROOF", "RAINPROOF", "GAS_PROOF", "RAD_PROOF", "ELECTRIC_IMMUNE", "OUTER" ] + }, + { + "id": "test_compbow", + "looks_like": "longbow", + "type": "GUN", + "symbol": "(", + "color": "yellow", + "name": "TEST compound bow", + "description": "A high-power bow with shaped cams and extra cables for high velocity shots that can be used effectively by fairly strong archers. Currently set to a medium weight.", + "price": 55000, + "material": [ "steel", "plastic" ], + "flags": [ "FIRE_TWOHAND", "RELOAD_AND_SHOOT", "PRIMITIVE_RANGED_WEAPON" ], + "skill": "archery", + "min_strength": 6, + "ammo": "arrow", + "weight": "907 g", + "volume": "1500 ml", + "bashing": 8, + "to_hit": 1, + "reload_noise_volume": 3, + "loudness": 10, + "ranged_damage": 18, + "range": 18, + "dispersion": 850, + "durability": 6, + "clip_size": 1, + "reload": 110, + "valid_mod_locations": [ [ "underbarrel", 1 ], [ "sights", 1 ], [ "accessories", 2 ], [ "stabilizer", 1 ], [ "dampening", 1 ] ], + "use_action": { + "menu_text": "Tighten Limbs", + "type": "transform", + "target": "compbow_high", + "qualities_needed": { "SCREW_FINE": 1 }, + "msg": "You tighten the limbs, increasing the strength of the bow." + } + }, + { + "type": "COMESTIBLE", + "id": "test_pine_nuts", + "name": { "str": "TEST pine nuts", "str_pl": "TEST pine nuts" }, + "weight": "30 g", + "color": "brown", + "spoils_in": 1080, + "container": "bag_plastic", + "comestible_type": "FOOD", + "symbol": "%", + "quench": -2, + "healthy": 1, + "calories": 202, + "description": "A handful of tasty crunchy nuts from a pinecone.", + "price": 136, + "material": "nut", + "volume": "250 ml", + "flags": [ "EDIBLE_FROZEN", "NUTRIENT_OVERRIDE" ], + "charges": 4, + "vitamins": [ [ "iron", 9 ] ], + "fun": 2 + }, + { + "id": "test_jug_plastic", + "type": "CONTAINER", + "category": "container", + "name": "TEST gallon jug", + "description": "A standard plastic jug used for milk and household cleaning chemicals.", + "weight": "190 g", + "volume": "3750 ml", + "price": 0, + "to_hit": 1, + "material": "plastic", + "symbol": ")", + "color": "light_cyan", + "contains": "3750 ml", + "seals": true, + "watertight": true } ] diff --git a/data/mods/TEST_DATA/recipes.json b/data/mods/TEST_DATA/recipes.json new file mode 100644 index 0000000000000..211e47d003795 --- /dev/null +++ b/data/mods/TEST_DATA/recipes.json @@ -0,0 +1,23 @@ +[ + { + "type": "recipe", + "result": "test_soldering_iron", + "category": "CC_ELECTRONIC", + "subcategory": "CSC_ELECTRONIC_TOOLS", + "skill_used": "electronics", + "difficulty": 1, + "time": "20 m", + "reversible": true, + "decomp_learn": 0, + "autolearn": [ [ "electronics", 2 ] ], + "book_learn": [ [ "manual_electronics", 1 ], [ "advanced_electronics", 2 ], [ "textbook_anarch", 2 ] ], + "qualities": [ { "id": "CUT", "level": 1 }, { "id": "SCREW", "level": 1 } ], + "components": [ + [ [ "e_scrap", 2 ], [ "glowplug", 1 ] ], + [ [ "copper", 1 ], [ "nail", 1 ], [ "wire", 1 ] ], + [ [ "scrap", 1 ] ], + [ [ "duct_tape", 10 ] ], + [ [ "cable", 5 ] ] + ] + } +] diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index c4feb59ecba8c..cc54ac7b6633e 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -11,7 +11,8 @@ #include "itype.h" #include "recipe_dictionary.h" -static void iteminfo_test( const item &i, const iteminfo_query &q, const std::string &reference ) +static void test_info_equals( const item &i, const iteminfo_query &q, + const std::string &reference ) { g->u.empty_traits(); std::vector info_v; @@ -19,6 +20,16 @@ static void iteminfo_test( const item &i, const iteminfo_query &q, const std::st CHECK( info == reference ); } +static void test_info_contains( const item &i, const iteminfo_query &q, + const std::string &reference ) +{ + g->u.empty_traits(); + std::vector info_v; + std::string info = i.info( info_v, &q, 1 ); + using Catch::Matchers::Contains; + REQUIRE_THAT( info, Contains( reference ) ); +} + TEST_CASE( "item description and physical attributes", "[item][iteminfo][primary]" ) { iteminfo_query q( { iteminfo_parts::BASE_CATEGORY, iteminfo_parts::BASE_MATERIAL, @@ -26,8 +37,8 @@ TEST_CASE( "item description and physical attributes", "[item][iteminfo][primary iteminfo_parts::DESCRIPTION } ); SECTION( "category, material, volume, weight, description" ) { - iteminfo_test( - item( "jug_plastic" ), q, + test_info_equals( + item( "test_jug_plastic" ), q, "Category: CONTAINERS\n" "Material: Plastic\n" "Volume: 3.750 L Weight: 0.42 lbs\n" @@ -43,7 +54,7 @@ TEST_CASE( "item owner, price, and barter value", "[item][iteminfo][price]" ) SECTION( "owner and price" ) { item my_rock( "test_rock" ); my_rock.set_owner( g->u ); - iteminfo_test( + test_info_equals( my_rock, q, "--\n" "Owner: Your Followers\n" @@ -51,17 +62,17 @@ TEST_CASE( "item owner, price, and barter value", "[item][iteminfo][price]" ) } SECTION( "owner, price and barter value" ) { - item my_necklace( "gold_necklace" ); - my_necklace.set_owner( g->u ); - iteminfo_test( - my_necklace, q, + item my_pipe( "test_pipe" ); + my_pipe.set_owner( g->u ); + test_info_equals( + my_pipe, q, "--\n" "Owner: Your Followers\n" - "Price: $400.00 Barter value: $50.00\n" ); + "Price: $75.00 Barter value: $3.00\n" ); } SECTION( "zero price item with no owner" ) { - iteminfo_test( + test_info_equals( item( "test_rock" ), q, "--\n" "Price: $0.00" ); @@ -74,12 +85,12 @@ TEST_CASE( "item rigidity", "[item][iteminfo][rigidity]" ) iteminfo_query q( { iteminfo_parts::BASE_RIGIDITY } ); SECTION( "rigid items do not indicate they are rigid, since almost all items are" ) { - iteminfo_test( + test_info_equals( item( "briefcase" ), q, "" ); } SECTION( "non-rigid items indicate their flexible volume/encumbrance" ) { - iteminfo_test( + test_info_equals( item( "backpack" ), q, "Not rigid: Volume and encumbrance increase when filled.\n" ); } @@ -92,7 +103,7 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) } ); SECTION( "bash damage" ) { - iteminfo_test( + test_info_equals( item( "test_rock" ), q, "--\n" "Damage: Bash: 7" @@ -101,7 +112,7 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) } SECTION( "bash and cut damage" ) { - iteminfo_test( + test_info_equals( item( "test_halligan" ), q, "--\n" "Damage: Bash: 20" @@ -111,7 +122,7 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) } SECTION( "bash and pierce damage" ) { - iteminfo_test( + test_info_equals( item( "pointy_stick" ), q, "--\n" "Damage: Bash: 4" @@ -121,7 +132,7 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) } SECTION( "no damage" ) { - iteminfo_test( item( "rag" ), q, "" ); + test_info_equals( item( "test_rag" ), q, "" ); } } @@ -130,7 +141,7 @@ TEST_CASE( "techniques when wielded", "[item][iteminfo][weapon]" ) { iteminfo_query q( { iteminfo_parts::DESCRIPTION_TECHNIQUES } ); - iteminfo_test( + test_info_equals( item( "test_halligan" ), q, "--\n" "Techniques when wielded:" @@ -148,8 +159,8 @@ TEST_CASE( "armor coverage and protection values", "[item][iteminfo][armor]" ) } ); SECTION( "shows coverage, encumbrance, and protection for armor with coverage" ) { - iteminfo_test( - item( "longshirt" ), q, + test_info_equals( + item( "test_longshirt" ), q, "--\n" // NOLINTNEXTLINE(cata-text-style) "Covers: The torso. The arms. \n" @@ -163,8 +174,8 @@ TEST_CASE( "armor coverage and protection values", "[item][iteminfo][armor]" ) } SECTION( "omits irrelevant info if it covers nothing" ) { - iteminfo_test( - item( "ear_plugs" ), q, + test_info_equals( + item( "test_ear_plugs" ), q, "--\n" "Covers: Nothing.\n" ); } @@ -174,16 +185,16 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged]" ) { SECTION( "ammo capacity" ) { iteminfo_query q( { iteminfo_parts::GUN_CAPACITY } ); - iteminfo_test( - item( "compbow" ), q, + test_info_equals( + item( "test_compbow" ), q, "--\n" "Capacity: 1 round of arrows\n" ); } SECTION( "default ammo when unloaded" ) { iteminfo_query q( { iteminfo_parts::GUN_DEFAULT_AMMO } ); - iteminfo_test( - item( "compbow" ), q, + test_info_equals( + item( "test_compbow" ), q, "--\n" "Gun is not loaded, so stats below assume the default ammo:" " wooden broadhead arrow\n" ); @@ -193,32 +204,32 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged]" ) iteminfo_query q( { iteminfo_parts::GUN_DAMAGE, iteminfo_parts::GUN_DAMAGE_AMMOPROP, iteminfo_parts::GUN_DAMAGE_TOTAL } ); - iteminfo_test( - item( "compbow" ), q, + test_info_equals( + item( "test_compbow" ), q, "--\n" "Damage: 18*1.25 = 22\n" ); } SECTION( "time to reload" ) { iteminfo_query q( { iteminfo_parts::GUN_RELOAD_TIME } ); - iteminfo_test( - item( "compbow" ), q, + test_info_equals( + item( "test_compbow" ), q, "--\n" "Reload time: 110 moves \n" ); // NOLINT(cata-text-style) } SECTION( "firing modes" ) { iteminfo_query q( { iteminfo_parts::GUN_FIRE_MODES } ); - iteminfo_test( - item( "compbow" ), q, + test_info_equals( + item( "test_compbow" ), q, "--\n" "Fire modes: manual (1)\n" ); } SECTION( "weapon mods" ) { iteminfo_query q( { iteminfo_parts::DESCRIPTION_GUN_MODS } ); - iteminfo_test( - item( "compbow" ), q, + test_info_equals( + item( "test_compbow" ), q, "--\n" "Mods: 0/2 accessories;" " 0/1 dampening; 0/1 sights;" @@ -235,7 +246,7 @@ TEST_CASE( "ammunition", "[item][iteminfo][ammo]" ) iteminfo_parts::AMMO_DAMAGE_RECOIL } ); SECTION( "simple item with ammo damage" ) { - iteminfo_test( + test_info_equals( item( "test_rock" ), q, "--\n" "Ammunition type: rocks\n" @@ -252,7 +263,7 @@ TEST_CASE( "nutrients in food", "[item][iteminfo][food]" ) } ); SECTION( "fixed nutrient values in regular item" ) { item i( "icecream" ); - iteminfo_test( + test_info_equals( i, q, "--\n" "Calories (kcal): 325 " @@ -263,7 +274,7 @@ TEST_CASE( "nutrients in food", "[item][iteminfo][food]" ) SECTION( "nutrient ranges for recipe exemplars", "[item][iteminfo]" ) { item i( "icecream" ); i.set_var( "recipe_exemplar", "icecream" ); - iteminfo_test( + test_info_equals( i, q, "--\n" "Nutrition will vary with chosen ingredients.\n" @@ -283,8 +294,8 @@ TEST_CASE( "food freshness and lifetime", "[item][iteminfo][food]" ) REQUIRE_FALSE( g->u.can_estimate_rot() ); SECTION( "food is fresh" ) { - iteminfo_test( - item( "pine_nuts" ), q, + test_info_equals( + item( "test_pine_nuts" ), q, "--\n" "* This food is perishable, and at room temperature has" " an estimated nominal shelf life of 6 weeks.\n" @@ -292,9 +303,9 @@ TEST_CASE( "food freshness and lifetime", "[item][iteminfo][food]" ) } SECTION( "food is old" ) { - item nuts( "pine_nuts" ); + item nuts( "test_pine_nuts" ); nuts.mod_rot( nuts.type->comestible->spoils ); - iteminfo_test( + test_info_equals( nuts, q, "--\n" "* This food is perishable, and at room temperature has" @@ -309,22 +320,22 @@ TEST_CASE( "item conductivity", "[item][iteminfo][conductivity]" ) iteminfo_query q( { iteminfo_parts::DESCRIPTION_CONDUCTIVITY } ); SECTION( "non-conductive items" ) { - iteminfo_test( - item( "2x4" ), q, + test_info_equals( + item( "test_2x4" ), q, "--\n" "* This item does not conduct electricity.\n" ); - iteminfo_test( - item( "fire_ax" ), q, + test_info_equals( + item( "test_fire_ax" ), q, "--\n" "* This item does not conduct electricity.\n" ); } SECTION( "conductive items" ) { - iteminfo_test( - item( "pipe" ), q, + test_info_equals( + item( "test_pipe" ), q, "--\n" "* This item conducts electricity.\n" ); - iteminfo_test( + test_info_equals( item( "test_halligan" ), q, "--\n" "* This item conducts electricity.\n" ); @@ -336,7 +347,7 @@ TEST_CASE( "list of item qualities", "[item][iteminfo][quality]" ) iteminfo_query q( { iteminfo_parts::QUALITIES } ); SECTION( "Halligan bar" ) { - iteminfo_test( + test_info_equals( item( "test_halligan" ), q, "--\n" "Has level 1 digging quality.\n" @@ -345,14 +356,14 @@ TEST_CASE( "list of item qualities", "[item][iteminfo][quality]" ) } SECTION( "bottle jack" ) { - iteminfo_test( + test_info_equals( item( "test_jack_small" ), q, "--\n" "Has level 4 jacking quality and is rated at 4409 lbs\n" ); } SECTION( "sonic screwdriver" ) { - iteminfo_test( + test_info_equals( item( "test_sonic_screwdriver" ), q, "--\n" "Has level 2 prying quality.\n" @@ -360,53 +371,38 @@ TEST_CASE( "list of item qualities", "[item][iteminfo][quality]" ) "Has level 1 fine screw driving quality.\n" "Has level 1 bolt turning quality.\n" ); } - } TEST_CASE( "repairable and with what tools", "[item][iteminfo][repair]" ) { iteminfo_query q( { iteminfo_parts::DESCRIPTION_REPAIREDWITH } ); - iteminfo_test( + test_info_contains( item( "test_halligan" ), q, - "--\n" "Repair using extended toolset, arc welder, or makeshift arc welder.\n" ); - iteminfo_test( + test_info_contains( item( "test_hazmat_suit" ), q, - "--\n" - "Repair using soldering iron or extended toolset.\n" ); + "Repair using soldering iron, TEST soldering iron, or extended toolset.\n" ); - iteminfo_test( - item( "test_rock" ), q, - "--\n" - "* This item is not repairable.\n" ); + test_info_contains( + item( "test_rock" ), q, "* This item is not repairable.\n" ); - /* - iteminfo_test( - item( "socks" ), q, - "--\n" - "* This item can be reinforced.\n" ); - */ + test_info_contains( + item( "test_socks" ), q, "* This item can be reinforced.\n" ); } TEST_CASE( "disassembly time and yield", "[item][iteminfo][disassembly]" ) { iteminfo_query q( { iteminfo_parts::DESCRIPTION_COMPONENTS_DISASSEMBLE } ); - // short string - iteminfo_test( - item( "string_6" ), q, - "--\n" - "Disassembly takes about 5 minutes and might yield: thread (50).\n" ); - - iteminfo_test( - item( "soldering_iron" ), q, + test_info_equals( + item( "test_soldering_iron" ), q, "--\n" "Disassembly takes about 20 minutes and might yield:" " 2 electronic scraps, copper (1), scrap metal (1), and copper wire (5).\n" ); - iteminfo_test( + test_info_equals( item( "test_sheet_metal" ), q, "--\n" "Disassembly takes about 2 minutes and might yield: TEST small metal sheet (24).\n" ); @@ -416,14 +412,14 @@ TEST_CASE( "item description flags", "[item][iteminfo]" ) { iteminfo_query q( { iteminfo_parts::DESCRIPTION_FLAGS } ); - iteminfo_test( + test_info_equals( item( "test_halligan" ), q, "--\n" "* This item can be clipped on to a belt loop of the appropriate size.\n" "* As a weapon, this item is well-made and will" " withstand the punishment of combat.\n" ); - iteminfo_test( + test_info_equals( item( "test_hazmat_suit" ), q, "--\n" "* This gear completely protects you from" @@ -449,7 +445,7 @@ TEST_CASE( "show available recipes with item as an ingredient", "[item][iteminfo g->u.empty_skills(); THEN( "nothing is craftable from it" ) { - iteminfo_test( + test_info_equals( iodine, q, "--\nYou know of nothing you could craft with it.\n" ); } @@ -459,7 +455,7 @@ TEST_CASE( "show available recipes with item as an ingredient", "[item][iteminfo REQUIRE( g->u.get_skill_level( purtab->skill_used ) == purtab->difficulty ); THEN( "still nothing is craftable from it" ) { - iteminfo_test( + test_info_equals( iodine, q, "--\nYou know of nothing you could craft with it.\n" ); } @@ -469,7 +465,7 @@ TEST_CASE( "show available recipes with item as an ingredient", "[item][iteminfo REQUIRE( g->u.knows_recipe( purtab ) ); THEN( "they can use potassium iodide tablets to craft it" ) { - iteminfo_test( + test_info_equals( iodine, q, "--\n" "You could use it to craft: " @@ -481,7 +477,7 @@ TEST_CASE( "show available recipes with item as an ingredient", "[item][iteminfo g->u.i_add( item( "textbook_chemistry" ) ); THEN( "they can use potassium iodide tablets to craft it" ) { - iteminfo_test( + test_info_equals( iodine, q, "--\n" "You could use it to craft: " From 9eb28959a2521aa6b28e98662cdd9569989a7c24 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Mon, 17 Feb 2020 12:24:42 -0700 Subject: [PATCH 42/51] Attempt workaround for apple compiler Travis CI for MacOS was reporting an ambiguous constructor error on this line (and only this line); seeing if a typecast will make it happy. --- tests/iteminfo_test.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index cc54ac7b6633e..678fe77d52671 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -49,7 +49,9 @@ TEST_CASE( "item description and physical attributes", "[item][iteminfo][primary TEST_CASE( "item owner, price, and barter value", "[item][iteminfo][price]" ) { - iteminfo_query q( { iteminfo_parts::BASE_PRICE, iteminfo_parts::BASE_BARTER } ); + // Explicit cast to std::vector to avoid ambiguous + // constructor error from MacOS / apple clang + iteminfo_query q( std::vector( { iteminfo_parts::BASE_PRICE, iteminfo_parts::BASE_BARTER } ) ); SECTION( "owner and price" ) { item my_rock( "test_rock" ); From c409d0d6fb38ddc856eeea759bbcfb26d34bf41a Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Mon, 17 Feb 2020 12:44:08 -0700 Subject: [PATCH 43/51] Flesh out test data mod readme Explain the reasoning for this mod a little better --- data/mods/TEST_DATA/README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/data/mods/TEST_DATA/README.md b/data/mods/TEST_DATA/README.md index 696d350deb246..451cc55e4d734 100644 --- a/data/mods/TEST_DATA/README.md +++ b/data/mods/TEST_DATA/README.md @@ -1,4 +1,11 @@ # Test Data pseudo-mod # -This mod is purely for loading data to be used by `tests/cata_test`. +This mod is purely for loading data to be used by `tests/cata_test`. It is +automatically loaded by `tests/test_main.cpp`, so any items, recipes, or other +content defined in the mod will be available to everything in `tests/`. + +The benefit of using this mod for test data is that it allows a clean +separation of tests from in-game content. Instead of testing with content in +the main `data/json` directory, functional tests can use `TEST_DATA` content +to ensure a more stable and controllable set of example data. From 691af7313796078b82f5211d418e7fcf7156fdcc Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Mon, 17 Feb 2020 15:12:31 -0700 Subject: [PATCH 44/51] Distinguish melee from ranged ramage; formatting Ranged weapons may have both melee and ranged damage, and both "Damage" headings may be bold; use separate "Melee damage" and "Ranged damage" headings for these sections to make it clear which is which. Also add a red "not loaded" indicator to make it stand out, and call it a "weapon" instead of a "gun" (since it could be a crossbow or such). --- src/item.cpp | 11 +++++++---- tests/iteminfo_test.cpp | 44 +++++++++++++++++++++++++++-------------- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index ad55cd08901a4..3a9c7a40ca7e8 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1654,8 +1654,9 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf tmp.ammo_set( mod->magazine_current() ? tmp.common_ammo_default() : tmp.ammo_default() ); loaded_mod = &tmp; if( parts->test( iteminfo_parts::GUN_DEFAULT_AMMO ) ) { + insert_separation_line( info ); info.emplace_back( "GUN", - _( "Gun is not loaded, so stats below assume the default ammo: " ), + _( "Weapon is not loaded, so stats below assume the default ammo: " ), string_format( "%s", loaded_mod->ammo_data()->nname( 1 ) ) ); } @@ -1692,7 +1693,8 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf } if( parts->test( iteminfo_parts::GUN_DAMAGE ) ) { - info.push_back( iteminfo( "GUN", _( "Damage: " ), "", iteminfo::no_newline, + insert_separation_line( info ); + info.push_back( iteminfo( "GUN", _( "Ranged damage: " ), "", iteminfo::no_newline, mod->gun_damage( false ).total_damage() ) ); } @@ -1719,11 +1721,12 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf loaded_mod->gun_damage( true ).total_damage() ) ); } } + info.back().bNewLine = true; // TODO: This doesn't cover multiple damage types if( parts->test( iteminfo_parts::GUN_ARMORPIERCE ) ) { - info.push_back( iteminfo( "GUN", space + _( "Armor-pierce: " ), "", + info.push_back( iteminfo( "GUN", _( "Armor-pierce: " ), "", iteminfo::no_newline, get_ranged_pierce( gun ) ) ); } if( mod->ammo_required() ) { @@ -2875,7 +2878,7 @@ void item::combat_info( std::vector &info, const iteminfo_query *parts insert_separation_line( info ); std::string sep; if( dmg_bash || dmg_cut || dmg_stab ) { - info.push_back( iteminfo( "BASE", _( "Damage: " ), "", iteminfo::no_newline ) ); + info.push_back( iteminfo( "BASE", _( "Melee damage: " ), "", iteminfo::no_newline ) ); } if( dmg_bash ) { info.push_back( iteminfo( "BASE", _( "Bash: " ), "", iteminfo::no_newline, dmg_bash ) ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 678fe77d52671..631b6b714d1b9 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -108,7 +108,7 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) test_info_equals( item( "test_rock" ), q, "--\n" - "Damage: Bash: 7" + "Melee damage: Bash: 7" " To-hit bonus: -2\n" "Moves per attack: 79\n" ); } @@ -117,7 +117,7 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) test_info_equals( item( "test_halligan" ), q, "--\n" - "Damage: Bash: 20" + "Melee damage: Bash: 20" " Cut: 5" " To-hit bonus: +2\n" "Moves per attack: 145\n" ); @@ -127,7 +127,7 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) test_info_equals( item( "pointy_stick" ), q, "--\n" - "Damage: Bash: 4" + "Melee damage: Bash: 4" " Pierce: 8" " To-hit bonus: +1\n" "Moves per attack: 100\n" ); @@ -136,7 +136,6 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) SECTION( "no damage" ) { test_info_equals( item( "test_rag" ), q, "" ); } - } TEST_CASE( "techniques when wielded", "[item][iteminfo][weapon]" ) @@ -150,7 +149,6 @@ TEST_CASE( "techniques when wielded", "[item][iteminfo][weapon]" ) " Brutal Strike: Stun 1 turn, knockback 1 tile, crit only," " Sweep Attack: Down 2 turns, and" " Block: Medium blocking ability\n" ); - } TEST_CASE( "armor coverage and protection values", "[item][iteminfo][armor]" ) @@ -183,9 +181,18 @@ TEST_CASE( "armor coverage and protection values", "[item][iteminfo][armor]" ) } } -TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged]" ) +TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged][gun]" ) { - SECTION( "ammo capacity" ) { + + SECTION( "skill used" ) { + iteminfo_query q( { iteminfo_parts::GUN_USEDSKILL } ); + test_info_equals( + item( "test_compbow" ), q, + "--\n" + "Skill used: archery\n" ); + } + + SECTION( "ammo capacity of weapon" ) { iteminfo_query q( { iteminfo_parts::GUN_CAPACITY } ); test_info_equals( item( "test_compbow" ), q, @@ -193,26 +200,27 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged]" ) "Capacity: 1 round of arrows\n" ); } - SECTION( "default ammo when unloaded" ) { + SECTION( "default ammo when weapon is unloaded" ) { iteminfo_query q( { iteminfo_parts::GUN_DEFAULT_AMMO } ); test_info_equals( item( "test_compbow" ), q, "--\n" - "Gun is not loaded, so stats below assume the default ammo:" + "Weapon is not loaded, so stats below assume the default ammo:" " wooden broadhead arrow\n" ); } - SECTION( "damage including floating-point multiplier" ) { + SECTION( "weapon damage including floating-point multiplier" ) { iteminfo_query q( { iteminfo_parts::GUN_DAMAGE, iteminfo_parts::GUN_DAMAGE_AMMOPROP, - iteminfo_parts::GUN_DAMAGE_TOTAL + iteminfo_parts::GUN_DAMAGE_TOTAL, iteminfo_parts::GUN_ARMORPIERCE } ); test_info_equals( item( "test_compbow" ), q, "--\n" - "Damage: 18*1.25 = 22\n" ); + "Ranged damage: 18*1.25 = 22\n" + "Armor-pierce: 0\n" ); } - SECTION( "time to reload" ) { + SECTION( "time to reload weapon" ) { iteminfo_query q( { iteminfo_parts::GUN_RELOAD_TIME } ); test_info_equals( item( "test_compbow" ), q, @@ -220,7 +228,7 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged]" ) "Reload time: 110 moves \n" ); // NOLINT(cata-text-style) } - SECTION( "firing modes" ) { + SECTION( "weapon firing modes" ) { iteminfo_query q( { iteminfo_parts::GUN_FIRE_MODES } ); test_info_equals( item( "test_compbow" ), q, @@ -238,6 +246,13 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged]" ) " 0/1 stabilizer; 0/1 underbarrel.\n" ); } + SECTION( "weapon dispersion" ) { + iteminfo_query q( { iteminfo_parts::GUN_DISPERSION } ); + test_info_equals( + item( "test_compbow" ), q, + "--\n" + "Dispersion: 850\n" ); + } } TEST_CASE( "ammunition", "[item][iteminfo][ammo]" ) @@ -314,7 +329,6 @@ TEST_CASE( "food freshness and lifetime", "[item][iteminfo][food]" ) " an estimated nominal shelf life of 6 weeks.\n" "* This food looks old. It's on the brink of becoming inedible.\n" ); } - } TEST_CASE( "item conductivity", "[item][iteminfo][conductivity]" ) From 53043e98239763946268a37bf843a8a7a1a4c17c Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Mon, 17 Feb 2020 15:15:40 -0700 Subject: [PATCH 45/51] Rearrange ranged weapon ratings; use color This promotes more important ranged weapon information (damage and armor-piercing calculations especially) to the top of the ranged weapon section, with less important info like move times for each kind of aiming moved toward the bottom. Also add a cyan highlight to the "Regular Aim", "Careful Aim", "Precise Aim" sections, so it's not just a big block of grey. --- src/item.cpp | 141 +++++++++++++++++++++++++-------------------------- 1 file changed, 69 insertions(+), 72 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 3a9c7a40ca7e8..b431805f6b1fd 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1598,53 +1598,9 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf int /* batch */, bool /* debug */ ) const { const std::string space = " "; - const islot_gun &gun = *mod->type->gun; - const Skill &skill = *mod->gun_skill(); - if( parts->test( iteminfo_parts::GUN_USEDSKILL ) ) { - info.push_back( iteminfo( "GUN", _( "Skill used: " ), - "" + skill.name() + "" ) ); - } - - if( mod->magazine_integral() || mod->magazine_current() ) { - if( mod->magazine_current() && parts->test( iteminfo_parts::GUN_MAGAZINE ) ) { - info.emplace_back( "GUN", _( "Magazine: " ), - string_format( "%s", - mod->magazine_current()->tname() ) ); - } - if( mod->ammo_capacity() && parts->test( iteminfo_parts::GUN_CAPACITY ) ) { - for( const ammotype &at : mod->ammo_types() ) { - const std::string fmt = string_format( ngettext( " round of %s", - " rounds of %s", - mod->ammo_capacity() ), at->name() ); - info.emplace_back( "GUN", _( "Capacity: " ), fmt, iteminfo::no_flags, - mod->ammo_capacity() ); - } - } - } else if( parts->test( iteminfo_parts::GUN_TYPE ) ) { - info.emplace_back( "GUN", _( "Type: " ), enumerate_as_string( mod->ammo_types().begin(), - mod->ammo_types().end(), []( const ammotype & at ) { - return at->name(); - }, enumeration_conjunction::none ) ); - } - - if( mod->ammo_data() && parts->test( iteminfo_parts::AMMO_REMAINING ) ) { - info.emplace_back( "AMMO", _( "Ammunition: " ), string_format( "%s", - mod->ammo_data()->nname( mod->ammo_remaining() ) ) ); - } - - if( mod->get_gun_ups_drain() && parts->test( iteminfo_parts::AMMO_UPSCOST ) ) { - info.emplace_back( "AMMO", - string_format( ngettext( "Uses %i charge of UPS per shot", - "Uses %i charges of UPS per shot", - mod->get_gun_ups_drain() ), - mod->get_gun_ups_drain() ) ); - } - - insert_separation_line( info ); - // many statistics are dependent upon loaded ammo // if item is unloaded (or is RELOAD_AND_SHOOT) shows approximate stats using default ammo const item *loaded_mod = mod; @@ -1664,34 +1620,6 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf const itype *curammo = loaded_mod->ammo_data(); - int max_gun_range = loaded_mod->gun_range( &g->u ); - if( max_gun_range > 0 && parts->test( iteminfo_parts::GUN_MAX_RANGE ) ) { - info.emplace_back( "GUN", _( "Maximum range: " ), "", iteminfo::no_flags, - max_gun_range ); - } - - if( parts->test( iteminfo_parts::GUN_AIMING_STATS ) ) { - info.emplace_back( "GUN", _( "Base aim speed: " ), "", iteminfo::no_flags, - g->u.aim_per_move( *mod, MAX_RECOIL ) ); - for( const aim_type &type : g->u.get_aim_types( *mod ) ) { - // Nameless aim levels don't get an entry. - if( type.name.empty() ) { - continue; - } - // For item comparison to work correctly each info object needs a - // distinct tag per aim type. - const std::string tag = "GUN_" + type.name; - info.emplace_back( tag, _( type.name ) ); - int max_dispersion = g->u.get_weapon_dispersion( *loaded_mod ).max(); - int range = range_with_even_chance_of_good_hit( max_dispersion + type.threshold ); - info.emplace_back( tag, _( "Even chance of good hit at range: " ), - _( "" ), iteminfo::no_flags, range ); - int aim_mv = g->u.gun_engagement_moves( *mod, type.threshold ); - info.emplace_back( tag, _( "Time to reach aim level: " ), _( " moves " ), - iteminfo::lower_is_better, aim_mv ); - } - } - if( parts->test( iteminfo_parts::GUN_DAMAGE ) ) { insert_separation_line( info ); info.push_back( iteminfo( "GUN", _( "Ranged damage: " ), "", iteminfo::no_newline, @@ -1819,6 +1747,74 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf iteminfo::lower_is_better, mod->get_reload_time() ); } + if( parts->test( iteminfo_parts::GUN_USEDSKILL ) ) { + info.push_back( iteminfo( "GUN", _( "Skill used: " ), + "" + skill.name() + "" ) ); + } + + if( mod->magazine_integral() || mod->magazine_current() ) { + if( mod->magazine_current() && parts->test( iteminfo_parts::GUN_MAGAZINE ) ) { + info.emplace_back( "GUN", _( "Magazine: " ), + string_format( "%s", + mod->magazine_current()->tname() ) ); + } + if( mod->ammo_capacity() && parts->test( iteminfo_parts::GUN_CAPACITY ) ) { + for( const ammotype &at : mod->ammo_types() ) { + const std::string fmt = string_format( ngettext( " round of %s", + " rounds of %s", + mod->ammo_capacity() ), at->name() ); + info.emplace_back( "GUN", _( "Capacity: " ), fmt, iteminfo::no_flags, + mod->ammo_capacity() ); + } + } + } else if( parts->test( iteminfo_parts::GUN_TYPE ) ) { + info.emplace_back( "GUN", _( "Type: " ), enumerate_as_string( mod->ammo_types().begin(), + mod->ammo_types().end(), []( const ammotype & at ) { + return at->name(); + }, enumeration_conjunction::none ) ); + } + + if( mod->ammo_data() && parts->test( iteminfo_parts::AMMO_REMAINING ) ) { + info.emplace_back( "AMMO", _( "Ammunition: " ), string_format( "%s", + mod->ammo_data()->nname( mod->ammo_remaining() ) ) ); + } + + if( mod->get_gun_ups_drain() && parts->test( iteminfo_parts::AMMO_UPSCOST ) ) { + info.emplace_back( "AMMO", + string_format( ngettext( "Uses %i charge of UPS per shot", + "Uses %i charges of UPS per shot", + mod->get_gun_ups_drain() ), + mod->get_gun_ups_drain() ) ); + } + + int max_gun_range = loaded_mod->gun_range( &g->u ); + if( max_gun_range > 0 && parts->test( iteminfo_parts::GUN_MAX_RANGE ) ) { + insert_separation_line( info ); + info.emplace_back( "GUN", _( "Maximum range: " ), "", iteminfo::no_flags, + max_gun_range ); + } + if( parts->test( iteminfo_parts::GUN_AIMING_STATS ) ) { + info.emplace_back( "GUN", _( "Base aim speed: " ), "", iteminfo::no_flags, + g->u.aim_per_move( *mod, MAX_RECOIL ) ); + for( const aim_type &type : g->u.get_aim_types( *mod ) ) { + // Nameless aim levels don't get an entry. + if( type.name.empty() ) { + continue; + } + // For item comparison to work correctly each info object needs a + // distinct tag per aim type. + const std::string tag = "GUN_" + type.name; + info.emplace_back( tag, string_format( "%s", type.name ) ); + int max_dispersion = g->u.get_weapon_dispersion( *loaded_mod ).max(); + int range = range_with_even_chance_of_good_hit( max_dispersion + type.threshold ); + info.emplace_back( tag, _( "Even chance of good hit at range: " ), + _( "" ), iteminfo::no_flags, range ); + int aim_mv = g->u.gun_engagement_moves( *mod, type.threshold ); + info.emplace_back( tag, _( "Time to reach aim level: " ), _( " moves " ), + iteminfo::lower_is_better, aim_mv ); + } + } + if( parts->test( iteminfo_parts::GUN_FIRE_MODES ) ) { std::vector fm; for( const std::pair &e : fire_modes ) { @@ -2050,6 +2046,7 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, bool covers_anything = covered_parts.any(); if( parts->test( iteminfo_parts::ARMOR_BODYPARTS ) ) { + insert_separation_line( info ); std::string coverage = _( "Covers: " ); if( covers( bp_head ) ) { coverage += _( "The head. " ); From 3ccd72afadd7c23bace444395c2cc15aa61a5232 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Mon, 17 Feb 2020 15:30:19 -0700 Subject: [PATCH 46/51] Move maximum range up (just below damage line) --- src/item.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index b431805f6b1fd..7c1465d07ad76 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1651,6 +1651,12 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf } info.back().bNewLine = true; + int max_gun_range = loaded_mod->gun_range( &g->u ); + if( max_gun_range > 0 && parts->test( iteminfo_parts::GUN_MAX_RANGE ) ) { + info.emplace_back( "GUN", _( "Maximum range: " ), "", iteminfo::no_flags, + max_gun_range ); + } + // TODO: This doesn't cover multiple damage types if( parts->test( iteminfo_parts::GUN_ARMORPIERCE ) ) { @@ -1787,14 +1793,9 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf mod->get_gun_ups_drain() ) ); } - int max_gun_range = loaded_mod->gun_range( &g->u ); - if( max_gun_range > 0 && parts->test( iteminfo_parts::GUN_MAX_RANGE ) ) { - insert_separation_line( info ); - info.emplace_back( "GUN", _( "Maximum range: " ), "", iteminfo::no_flags, - max_gun_range ); - } if( parts->test( iteminfo_parts::GUN_AIMING_STATS ) ) { - info.emplace_back( "GUN", _( "Base aim speed: " ), "", iteminfo::no_flags, + insert_separation_line( info ); + info.emplace_back( "GUN", _( "Base aim speed: " ), "", iteminfo::no_flags, g->u.aim_per_move( *mod, MAX_RECOIL ) ); for( const aim_type &type : g->u.get_aim_types( *mod ) ) { // Nameless aim levels don't get an entry. From 61465ab3d885b2a03838b5122edaac80b1d784f8 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Mon, 17 Feb 2020 18:02:17 -0700 Subject: [PATCH 47/51] Fix astyle check --- src/item.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/item.cpp b/src/item.cpp index 990de1ff0b11c..daf96241bf2d0 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -2227,7 +2227,8 @@ void item::armor_fit_info( std::vector &info, const iteminfo_query *pa int encumbrance = get_encumber( g->u ); const sizing sizing_level = get_sizing( g->u, encumbrance != 0 ); - if( has_flag( flag_HELMET_COMPAT ) && parts->test( iteminfo_parts::DESCRIPTION_FLAGS_HELMETCOMPAT ) ) { + if( has_flag( flag_HELMET_COMPAT ) && + parts->test( iteminfo_parts::DESCRIPTION_FLAGS_HELMETCOMPAT ) ) { info.push_back( iteminfo( "DESCRIPTION", _( "* This item can be worn with a " "helmet." ) ) ); From 06af1f348f4d72e177366615177e28e4b0e84567 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Tue, 18 Feb 2020 16:41:23 -0700 Subject: [PATCH 48/51] Rephrase/move "not rigid" indicator; add tests The rigidity indicator was kind of out of place at the top of the item info. This commit moves it alongside the other flags, e.g. * This item is not rigid. Its volume and encumbrance increase with contents. * This item does not conduct electricity. * ... Also adds test data and expands the test cases for rigidity to include: - waterskin, backpack (non-rigid containers) - briefcase (rigid container with encumbrance) - plastic jug (rigid container without encumbrance) - pipe, pine nuts (rigid non-container) --- data/mods/TEST_DATA/items.json | 66 ++++++++++++++++++++++++++++++++++ src/item.cpp | 14 ++++---- tests/iteminfo_test.cpp | 32 +++++++++++++---- 3 files changed, 100 insertions(+), 12 deletions(-) diff --git a/data/mods/TEST_DATA/items.json b/data/mods/TEST_DATA/items.json index e2fc54cf09fae..7c21f4d857e8d 100644 --- a/data/mods/TEST_DATA/items.json +++ b/data/mods/TEST_DATA/items.json @@ -385,5 +385,71 @@ "contains": "3750 ml", "seals": true, "watertight": true + }, + { + "id": "test_waterskin", + "type": "CONTAINER", + "category": "container", + "name": "TEST small waterskin", + "description": "A small watertight leather bag with a carrying strap, can hold 1.5 liters of water.", + "weight": "453 g", + "volume": "250 ml", + "price": 2000, + "to_hit": -1, + "bashing": 1, + "rigid": false, + "material": "leather", + "symbol": ")", + "color": "brown", + "contains": "1500 ml", + "seals": true, + "watertight": true, + "armor_data": { "covers": [ "LEG_EITHER" ], "coverage": 5, "material_thickness": 2 }, + "flags": [ "WAIST", "WATER_FRIENDLY" ] + }, + { + "id": "test_backpack", + "type": "ARMOR", + "name": "TEST backpack", + "description": "A small backpack. Good storage for a little encumbrance.", + "weight": "633 g", + "volume": "2 L", + "price": 3900, + "price_postapoc": 16000, + "rigid": false, + "material": [ "cotton" ], + "symbol": "[", + "looks_like": "ragpouch", + "color": "green", + "covers": [ "TORSO" ], + "coverage": 30, + "encumbrance": 2, + "max_encumbrance": 15, + "storage": "15 L", + "warmth": 6, + "material_thickness": 2, + "flags": [ "BELTED" ] + }, + { + "id": "test_briefcase", + "repairs_like": "backpack_hiking", + "type": "ARMOR", + "name": "TEST briefcase", + "description": "Useful for carrying money, documents, or smuggled goods.", + "weight": "1700 g", + "volume": "15 L", + "price": 24000, + "to_hit": -2, + "bashing": 5, + "material": [ "plastic" ], + "symbol": "[", + "looks_like": "plastic_shopping_bag", + "color": "light_gray", + "covers": [ "ARM_EITHER", "HAND_EITHER" ], + "coverage": 10, + "encumbrance": 30, + "storage": "15 L", + "material_thickness": 2, + "flags": [ "FANCY", "OVERSIZE", "BELTED", "RESTRICT_HANDS", "WATER_FRIENDLY" ] } ] diff --git a/src/item.cpp b/src/item.cpp index daf96241bf2d0..f14697e261d40 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1129,12 +1129,6 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, iteminfo::lower_is_better | iteminfo::is_decimal, convert_weight( weight() ) * batch ) ); } - if( parts->test( iteminfo_parts::BASE_RIGIDITY ) ) { - if( !type->rigid ) { - info.emplace_back( "BASE", - _( "Not rigid: Volume and encumbrance increase when filled." ) ); - } - } if( parts->test( iteminfo_parts::DESCRIPTION ) ) { insert_separation_line( info ); const std::map::const_iterator idescription = @@ -3037,6 +3031,14 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, insert_separation_line( info ); + if( parts->test( iteminfo_parts::BASE_RIGIDITY ) ) { + if( !type->rigid ) { + info.emplace_back( "BASE", + _( "* This item is not rigid. Its" + " volume and encumbrance increase with contents." ) ); + } + } + if( parts->test( iteminfo_parts::DESCRIPTION_CONDUCTIVITY ) ) { if( !conductive() ) { info.push_back( iteminfo( "BASE", _( "* This item does not " diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 631b6b714d1b9..fd2aefc29a9ed 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -84,17 +84,37 @@ TEST_CASE( "item owner, price, and barter value", "[item][iteminfo][price]" ) TEST_CASE( "item rigidity", "[item][iteminfo][rigidity]" ) { - iteminfo_query q( { iteminfo_parts::BASE_RIGIDITY } ); + iteminfo_query q( { iteminfo_parts::BASE_RIGIDITY, iteminfo_parts::ARMOR_ENCUMBRANCE } ); + + SECTION( "non-rigid items indicate their flexible volume/encumbrance" ) { + test_info_equals( + item( "test_waterskin" ), q, + "--\n" + "Encumbrance: 0" + " Encumbrance when full: 6\n" + "--\n" + "* This item is not rigid." + " Its volume and encumbrance increase with contents.\n" ); - SECTION( "rigid items do not indicate they are rigid, since almost all items are" ) { test_info_equals( - item( "briefcase" ), q, "" ); + item( "test_backpack" ), q, + "--\n" + "Encumbrance: 2" + " Encumbrance when full: 15\n" + "--\n" + "* This item is not rigid." + " Its volume and encumbrance increase with contents.\n" ); } - SECTION( "non-rigid items indicate their flexible volume/encumbrance" ) { + SECTION( "rigid items do not indicate they are rigid, since almost all items are" ) { test_info_equals( - item( "backpack" ), q, - "Not rigid: Volume and encumbrance increase when filled.\n" ); + item( "test_briefcase" ), q, + "--\n" + "Encumbrance: 30\n" ); + + test_info_equals( item( "test_jug_plastic" ), q, "" ); + test_info_equals( item( "test_pipe" ), q, "" ); + test_info_equals( item( "test_pine_nuts" ), q, "" ); } } From 6ea81961f71017037cb3b6bc88a9dd8f3858596a Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Tue, 18 Feb 2020 17:22:08 -0700 Subject: [PATCH 49/51] Material, Category, Volume, Weight, Owner After many revisions, I think this is my final ordering for the top lines of the item info: - Material and Category (same line) - Volume and Weight (same line) - Owner name Promoting Material to the top position in the info was done because it is a fundamental trait of the item (its raw component substance). I considered demoting Category further down in the info, but as it has always been the first thing displayed, and always in the distinctive magenta heading style, it didn't feel right to move it, especially since it fits neatly next to Material most of the time. Some items do not have a material (particularly multivitamin, potassium tablet and other drugs); in that case Category will have a line by itself. Price and Barter value remain near the bottom, since this info is already obtainable when it's relevant (while trading). --- src/item.cpp | 26 +++++++++++++------------- tests/iteminfo_test.cpp | 9 ++++----- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index f14697e261d40..1035b9a0731e7 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1097,10 +1097,6 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, bool debug /* debug */ ) const { const std::string space = " "; - if( parts->test( iteminfo_parts::BASE_CATEGORY ) ) { - info.push_back( iteminfo( "BASE", _( "Category: " ), - "
" + get_category().name() + "
" ) ); - } if( parts->test( iteminfo_parts::BASE_MATERIAL ) ) { const std::vector mat_types = made_of_types(); if( !mat_types.empty() ) { @@ -1108,9 +1104,15 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, []( const material_type * material ) { return string_format( "%s", material->name() ); }, enumeration_conjunction::none ); - info.push_back( iteminfo( "BASE", string_format( _( "Material: %s" ), material_list ) ) ); + info.push_back( iteminfo( "BASE", _( "Material: " ), + string_format( _( "%s " ), material_list ), + iteminfo::no_newline ) ); } } + if( parts->test( iteminfo_parts::BASE_CATEGORY ) ) { + info.push_back( iteminfo( "BASE", _( "Category: " ), + "
" + get_category().name() + "
" ) ); + } if( parts->test( iteminfo_parts::BASE_VOLUME ) ) { int converted_volume_scale = 0; const double converted_volume = round_up( convert_volume( volume().value(), @@ -1129,6 +1131,10 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, iteminfo::lower_is_better | iteminfo::is_decimal, convert_weight( weight() ) * batch ) ); } + if( !owner.is_null() ) { + info.push_back( iteminfo( "BASE", string_format( _( "Owner: %s" ), + _( get_owner_name() ) ) ) ); + } if( parts->test( iteminfo_parts::DESCRIPTION ) ) { insert_separation_line( info ); const std::map::const_iterator idescription = @@ -3281,17 +3287,11 @@ void item::final_info( std::vector &info, const iteminfo_query *parts, 0 ) ) ) ); } - // Owner, price, and barter value - if( !owner.is_null() || parts->test( iteminfo_parts::BASE_PRICE ) ) { - insert_separation_line( info ); - } - if( !owner.is_null() ) { - info.push_back( iteminfo( "BASE", string_format( _( "Owner: %s" ), - _( get_owner_name() ) ) ) ); - } + // Price and barter value const int price_preapoc = price( false ) * batch; const int price_postapoc = price( true ) * batch; if( parts->test( iteminfo_parts::BASE_PRICE ) ) { + insert_separation_line( info ); info.push_back( iteminfo( "BASE", _( "Price: " ), _( "$" ), iteminfo::is_decimal | iteminfo::lower_is_better | iteminfo::no_newline, static_cast( price_preapoc ) / 100 ) ); diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index fd2aefc29a9ed..2f120d380f4b7 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -36,11 +36,10 @@ TEST_CASE( "item description and physical attributes", "[item][iteminfo][primary iteminfo_parts::BASE_VOLUME, iteminfo_parts::BASE_WEIGHT, iteminfo_parts::DESCRIPTION } ); - SECTION( "category, material, volume, weight, description" ) { + SECTION( "volume, weight, category, material, description" ) { test_info_equals( item( "test_jug_plastic" ), q, - "Category: CONTAINERS\n" - "Material: Plastic\n" + "Material: Plastic Category: CONTAINERS\n" "Volume: 3.750 L Weight: 0.42 lbs\n" "--\n" "A standard plastic jug used for milk and household cleaning chemicals.\n" ); @@ -58,8 +57,8 @@ TEST_CASE( "item owner, price, and barter value", "[item][iteminfo][price]" ) my_rock.set_owner( g->u ); test_info_equals( my_rock, q, + "Owner: Your Followers\n" "--\n" - "Owner: Your Followers\n" "Price: $0.00" ); } @@ -68,8 +67,8 @@ TEST_CASE( "item owner, price, and barter value", "[item][iteminfo][price]" ) my_pipe.set_owner( g->u ); test_info_equals( my_pipe, q, + "Owner: Your Followers\n" "--\n" - "Owner: Your Followers\n" "Price: $75.00 Barter value: $3.00\n" ); } From 69849d48be792411769a13ba8403f37fa7f83bb6 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Tue, 18 Feb 2020 19:53:04 -0700 Subject: [PATCH 50/51] No, Material/Volume/Weight/Owner/Category That's my final answer --- src/item.cpp | 13 ++++++------- tests/iteminfo_test.cpp | 3 ++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index 1035b9a0731e7..023d00f9bd776 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1104,15 +1104,9 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, []( const material_type * material ) { return string_format( "%s", material->name() ); }, enumeration_conjunction::none ); - info.push_back( iteminfo( "BASE", _( "Material: " ), - string_format( _( "%s " ), material_list ), - iteminfo::no_newline ) ); + info.push_back( iteminfo( "BASE", string_format( _( "Material: %s" ), material_list ) ) ); } } - if( parts->test( iteminfo_parts::BASE_CATEGORY ) ) { - info.push_back( iteminfo( "BASE", _( "Category: " ), - "
" + get_category().name() + "
" ) ); - } if( parts->test( iteminfo_parts::BASE_VOLUME ) ) { int converted_volume_scale = 0; const double converted_volume = round_up( convert_volume( volume().value(), @@ -1135,6 +1129,11 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts, info.push_back( iteminfo( "BASE", string_format( _( "Owner: %s" ), _( get_owner_name() ) ) ) ); } + if( parts->test( iteminfo_parts::BASE_CATEGORY ) ) { + info.push_back( iteminfo( "BASE", _( "Category: " ), + "
" + get_category().name() + "
" ) ); + } + if( parts->test( iteminfo_parts::DESCRIPTION ) ) { insert_separation_line( info ); const std::map::const_iterator idescription = diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 2f120d380f4b7..a6b5c81846ea7 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -39,8 +39,9 @@ TEST_CASE( "item description and physical attributes", "[item][iteminfo][primary SECTION( "volume, weight, category, material, description" ) { test_info_equals( item( "test_jug_plastic" ), q, - "Material: Plastic Category: CONTAINERS\n" + "Material: Plastic\n" "Volume: 3.750 L Weight: 0.42 lbs\n" + "Category: CONTAINERS\n" "--\n" "A standard plastic jug used for milk and household cleaning chemicals.\n" ); } From bbc8909e203250e12e0fccf4e383623e829c5c74 Mon Sep 17 00:00:00 2001 From: Eric Pierce Date: Wed, 19 Feb 2020 18:12:31 -0700 Subject: [PATCH 51/51] Wrap iteminfo_query constructor To avoid MacOS compiler errors (I hope - no way to test but push and see what Travis CI says) --- tests/iteminfo_test.cpp | 90 +++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index a6b5c81846ea7..70029a57e6e70 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -30,11 +30,29 @@ static void test_info_contains( const item &i, const iteminfo_query &q, REQUIRE_THAT( info, Contains( reference ) ); } +/* + * Wrap the iteminfo_query() constructor to avoid MacOS clang compiler errors like this: + * + * iteminfo_test.cpp:NN: error: call to constructor of 'iteminfo_query' is ambiguous + * iteminfo_query q( { iteminfo_parts::BASE_RIGIDITY, iteminfo_parts::ARMOR_ENCUMBRANCE } ); + * ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * ../src/iteminfo_query.h:245:9: note: candidate constructor + * iteminfo_query( const std::string &bits ); + * ../src/iteminfo_query.h:246:9: note: candidate constructor + * iteminfo_query( const std::vector &setBits ); + * + * Using this wrapper should force it to use the vector constructor. + */ +static iteminfo_query q_vec( const std::vector &part_flags ) +{ + return iteminfo_query( part_flags ); +} + TEST_CASE( "item description and physical attributes", "[item][iteminfo][primary]" ) { - iteminfo_query q( { iteminfo_parts::BASE_CATEGORY, iteminfo_parts::BASE_MATERIAL, - iteminfo_parts::BASE_VOLUME, iteminfo_parts::BASE_WEIGHT, - iteminfo_parts::DESCRIPTION } ); + iteminfo_query q = q_vec( { iteminfo_parts::BASE_CATEGORY, iteminfo_parts::BASE_MATERIAL, + iteminfo_parts::BASE_VOLUME, iteminfo_parts::BASE_WEIGHT, + iteminfo_parts::DESCRIPTION } ); SECTION( "volume, weight, category, material, description" ) { test_info_equals( @@ -49,9 +67,7 @@ TEST_CASE( "item description and physical attributes", "[item][iteminfo][primary TEST_CASE( "item owner, price, and barter value", "[item][iteminfo][price]" ) { - // Explicit cast to std::vector to avoid ambiguous - // constructor error from MacOS / apple clang - iteminfo_query q( std::vector( { iteminfo_parts::BASE_PRICE, iteminfo_parts::BASE_BARTER } ) ); + iteminfo_query q = q_vec( std::vector( { iteminfo_parts::BASE_PRICE, iteminfo_parts::BASE_BARTER } ) ); SECTION( "owner and price" ) { item my_rock( "test_rock" ); @@ -84,7 +100,7 @@ TEST_CASE( "item owner, price, and barter value", "[item][iteminfo][price]" ) TEST_CASE( "item rigidity", "[item][iteminfo][rigidity]" ) { - iteminfo_query q( { iteminfo_parts::BASE_RIGIDITY, iteminfo_parts::ARMOR_ENCUMBRANCE } ); + iteminfo_query q = q_vec( { iteminfo_parts::BASE_RIGIDITY, iteminfo_parts::ARMOR_ENCUMBRANCE } ); SECTION( "non-rigid items indicate their flexible volume/encumbrance" ) { test_info_equals( @@ -120,9 +136,8 @@ TEST_CASE( "item rigidity", "[item][iteminfo][rigidity]" ) TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) { - iteminfo_query q( { iteminfo_parts::BASE_DAMAGE, iteminfo_parts::BASE_TOHIT, - iteminfo_parts::BASE_MOVES - } ); + iteminfo_query q = q_vec( { iteminfo_parts::BASE_DAMAGE, iteminfo_parts::BASE_TOHIT, + iteminfo_parts::BASE_MOVES } ); SECTION( "bash damage" ) { test_info_equals( @@ -160,7 +175,7 @@ TEST_CASE( "weapon attack ratings and moves", "[item][iteminfo][weapon]" ) TEST_CASE( "techniques when wielded", "[item][iteminfo][weapon]" ) { - iteminfo_query q( { iteminfo_parts::DESCRIPTION_TECHNIQUES } ); + iteminfo_query q = q_vec( { iteminfo_parts::DESCRIPTION_TECHNIQUES } ); test_info_equals( item( "test_halligan" ), q, @@ -173,10 +188,9 @@ TEST_CASE( "techniques when wielded", "[item][iteminfo][weapon]" ) TEST_CASE( "armor coverage and protection values", "[item][iteminfo][armor]" ) { - iteminfo_query q( { iteminfo_parts::ARMOR_BODYPARTS, iteminfo_parts::ARMOR_LAYER, - iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH, - iteminfo_parts::ARMOR_ENCUMBRANCE, iteminfo_parts::ARMOR_PROTECTION - } ); + iteminfo_query q = q_vec( { iteminfo_parts::ARMOR_BODYPARTS, iteminfo_parts::ARMOR_LAYER, + iteminfo_parts::ARMOR_COVERAGE, iteminfo_parts::ARMOR_WARMTH, + iteminfo_parts::ARMOR_ENCUMBRANCE, iteminfo_parts::ARMOR_PROTECTION } ); SECTION( "shows coverage, encumbrance, and protection for armor with coverage" ) { test_info_equals( @@ -205,7 +219,7 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged][gun]" ) { SECTION( "skill used" ) { - iteminfo_query q( { iteminfo_parts::GUN_USEDSKILL } ); + iteminfo_query q = q_vec( { iteminfo_parts::GUN_USEDSKILL } ); test_info_equals( item( "test_compbow" ), q, "--\n" @@ -213,7 +227,7 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged][gun]" ) } SECTION( "ammo capacity of weapon" ) { - iteminfo_query q( { iteminfo_parts::GUN_CAPACITY } ); + iteminfo_query q = q_vec( { iteminfo_parts::GUN_CAPACITY } ); test_info_equals( item( "test_compbow" ), q, "--\n" @@ -221,7 +235,7 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged][gun]" ) } SECTION( "default ammo when weapon is unloaded" ) { - iteminfo_query q( { iteminfo_parts::GUN_DEFAULT_AMMO } ); + iteminfo_query q = q_vec( { iteminfo_parts::GUN_DEFAULT_AMMO } ); test_info_equals( item( "test_compbow" ), q, "--\n" @@ -230,9 +244,8 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged][gun]" ) } SECTION( "weapon damage including floating-point multiplier" ) { - iteminfo_query q( { iteminfo_parts::GUN_DAMAGE, iteminfo_parts::GUN_DAMAGE_AMMOPROP, - iteminfo_parts::GUN_DAMAGE_TOTAL, iteminfo_parts::GUN_ARMORPIERCE - } ); + iteminfo_query q = q_vec( { iteminfo_parts::GUN_DAMAGE, iteminfo_parts::GUN_DAMAGE_AMMOPROP, + iteminfo_parts::GUN_DAMAGE_TOTAL, iteminfo_parts::GUN_ARMORPIERCE } ); test_info_equals( item( "test_compbow" ), q, "--\n" @@ -241,7 +254,7 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged][gun]" ) } SECTION( "time to reload weapon" ) { - iteminfo_query q( { iteminfo_parts::GUN_RELOAD_TIME } ); + iteminfo_query q = q_vec( { iteminfo_parts::GUN_RELOAD_TIME } ); test_info_equals( item( "test_compbow" ), q, "--\n" @@ -249,7 +262,7 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged][gun]" ) } SECTION( "weapon firing modes" ) { - iteminfo_query q( { iteminfo_parts::GUN_FIRE_MODES } ); + iteminfo_query q = q_vec( { iteminfo_parts::GUN_FIRE_MODES } ); test_info_equals( item( "test_compbow" ), q, "--\n" @@ -257,7 +270,7 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged][gun]" ) } SECTION( "weapon mods" ) { - iteminfo_query q( { iteminfo_parts::DESCRIPTION_GUN_MODS } ); + iteminfo_query q = q_vec( { iteminfo_parts::DESCRIPTION_GUN_MODS } ); test_info_equals( item( "test_compbow" ), q, "--\n" @@ -267,7 +280,7 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged][gun]" ) } SECTION( "weapon dispersion" ) { - iteminfo_query q( { iteminfo_parts::GUN_DISPERSION } ); + iteminfo_query q = q_vec( { iteminfo_parts::GUN_DISPERSION } ); test_info_equals( item( "test_compbow" ), q, "--\n" @@ -277,10 +290,10 @@ TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged][gun]" ) TEST_CASE( "ammunition", "[item][iteminfo][ammo]" ) { - iteminfo_query q( { iteminfo_parts::AMMO_REMAINING_OR_TYPES, iteminfo_parts::AMMO_DAMAGE_VALUE, - iteminfo_parts::AMMO_DAMAGE_PROPORTIONAL, iteminfo_parts::AMMO_DAMAGE_AP, - iteminfo_parts::AMMO_DAMAGE_RANGE, iteminfo_parts::AMMO_DAMAGE_DISPERSION, - iteminfo_parts::AMMO_DAMAGE_RECOIL } ); + iteminfo_query q = q_vec( { iteminfo_parts::AMMO_REMAINING_OR_TYPES, iteminfo_parts::AMMO_DAMAGE_VALUE, + iteminfo_parts::AMMO_DAMAGE_PROPORTIONAL, iteminfo_parts::AMMO_DAMAGE_AP, + iteminfo_parts::AMMO_DAMAGE_RANGE, iteminfo_parts::AMMO_DAMAGE_DISPERSION, + iteminfo_parts::AMMO_DAMAGE_RECOIL } ); SECTION( "simple item with ammo damage" ) { test_info_equals( @@ -295,9 +308,8 @@ TEST_CASE( "ammunition", "[item][iteminfo][ammo]" ) TEST_CASE( "nutrients in food", "[item][iteminfo][food]" ) { - iteminfo_query q( { iteminfo_parts::FOOD_NUTRITION, iteminfo_parts::FOOD_VITAMINS, - iteminfo_parts::FOOD_QUENCH - } ); + iteminfo_query q = q_vec( { iteminfo_parts::FOOD_NUTRITION, iteminfo_parts::FOOD_VITAMINS, + iteminfo_parts::FOOD_QUENCH } ); SECTION( "fixed nutrient values in regular item" ) { item i( "icecream" ); test_info_equals( @@ -324,7 +336,7 @@ TEST_CASE( "nutrients in food", "[item][iteminfo][food]" ) TEST_CASE( "food freshness and lifetime", "[item][iteminfo][food]" ) { - iteminfo_query q( { iteminfo_parts::FOOD_ROT } ); + iteminfo_query q = q_vec( { iteminfo_parts::FOOD_ROT } ); // Ensure test character has no skill estimating spoilage g->u.empty_skills(); @@ -353,7 +365,7 @@ TEST_CASE( "food freshness and lifetime", "[item][iteminfo][food]" ) TEST_CASE( "item conductivity", "[item][iteminfo][conductivity]" ) { - iteminfo_query q( { iteminfo_parts::DESCRIPTION_CONDUCTIVITY } ); + iteminfo_query q = q_vec( { iteminfo_parts::DESCRIPTION_CONDUCTIVITY } ); SECTION( "non-conductive items" ) { test_info_equals( @@ -380,7 +392,7 @@ TEST_CASE( "item conductivity", "[item][iteminfo][conductivity]" ) TEST_CASE( "list of item qualities", "[item][iteminfo][quality]" ) { - iteminfo_query q( { iteminfo_parts::QUALITIES } ); + iteminfo_query q = q_vec( { iteminfo_parts::QUALITIES } ); SECTION( "Halligan bar" ) { test_info_equals( @@ -411,7 +423,7 @@ TEST_CASE( "list of item qualities", "[item][iteminfo][quality]" ) TEST_CASE( "repairable and with what tools", "[item][iteminfo][repair]" ) { - iteminfo_query q( { iteminfo_parts::DESCRIPTION_REPAIREDWITH } ); + iteminfo_query q = q_vec( { iteminfo_parts::DESCRIPTION_REPAIREDWITH } ); test_info_contains( item( "test_halligan" ), q, @@ -430,7 +442,7 @@ TEST_CASE( "repairable and with what tools", "[item][iteminfo][repair]" ) TEST_CASE( "disassembly time and yield", "[item][iteminfo][disassembly]" ) { - iteminfo_query q( { iteminfo_parts::DESCRIPTION_COMPONENTS_DISASSEMBLE } ); + iteminfo_query q = q_vec( { iteminfo_parts::DESCRIPTION_COMPONENTS_DISASSEMBLE } ); test_info_equals( item( "test_soldering_iron" ), q, @@ -446,7 +458,7 @@ TEST_CASE( "disassembly time and yield", "[item][iteminfo][disassembly]" ) TEST_CASE( "item description flags", "[item][iteminfo]" ) { - iteminfo_query q( { iteminfo_parts::DESCRIPTION_FLAGS } ); + iteminfo_query q = q_vec( { iteminfo_parts::DESCRIPTION_FLAGS } ); test_info_equals( item( "test_halligan" ), q, @@ -472,7 +484,7 @@ TEST_CASE( "item description flags", "[item][iteminfo]" ) TEST_CASE( "show available recipes with item as an ingredient", "[item][iteminfo][recipes]" ) { - iteminfo_query q( { iteminfo_parts::DESCRIPTION_APPLICABLE_RECIPES } ); + iteminfo_query q = q_vec( { iteminfo_parts::DESCRIPTION_APPLICABLE_RECIPES } ); const recipe *purtab = &recipe_id( "pur_tablets" ).obj(); g->u.empty_traits();