diff --git a/data/json/flags.json b/data/json/flags.json
index 5bab06c0acbd7..13c09c2c4ba13 100644
--- a/data/json/flags.json
+++ b/data/json/flags.json
@@ -90,13 +90,13 @@
"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",
@@ -160,7 +160,7 @@
"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" ]
},
{
@@ -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",
@@ -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. Too small for anyone else."
},
{
"id": "PARTIAL_DEAF",
@@ -376,7 +376,7 @@
"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",
diff --git a/data/mods/TEST_DATA/items.json b/data/mods/TEST_DATA/items.json
new file mode 100644
index 0000000000000..7c21f4d857e8d
--- /dev/null
+++ b/data/mods/TEST_DATA/items.json
@@ -0,0 +1,455 @@
+[
+ {
+ "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 ] ]
+ },
+ {
+ "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",
+ "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_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",
+ "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_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",
+ "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_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",
+ "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" ]
+ },
+ {
+ "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
+ },
+ {
+ "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/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/data/mods/TEST_DATA/uncraft.json b/data/mods/TEST_DATA/uncraft.json
new file mode 100644
index 0000000000000..eb45166312399
--- /dev/null
+++ b/data/mods/TEST_DATA/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/src/item.cpp b/src/item.cpp
index 41bd639d29d32..3e8d4f61b3aa4 100644
--- a/src/item.cpp
+++ b/src/item.cpp
@@ -1263,7 +1263,46 @@ 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
{
+ const std::string space = " ";
+ 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(),
+ &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;
+ }
+ info.push_back( iteminfo( "BASE", _( "Volume: " ),
+ string_format( " %s", volume_units_abbr() ),
+ f, converted_volume ) );
+ }
+ if( parts->test( iteminfo_parts::BASE_WEIGHT ) ) {
+ info.push_back( iteminfo( "BASE", space + _( "Weight: " ),
+ string_format( " %s", weight_units() ),
+ 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::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 =
item_vars.find( "description" );
const cata::optional snippet = SNIPPET.get_snippet_by_id( snip_id );
@@ -1291,86 +1330,6 @@ void item::basic_info( std::vector &info, const iteminfo_query *parts,
}
insert_separation_line( info );
}
- 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 ) );
- }
- 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 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 ) ) {
- iteminfo::flags f = iteminfo::lower_is_better | iteminfo::no_newline;
- if( converted_volume_scale != 0 ) {
- f |= iteminfo::is_three_decimal;
- }
- info.push_back( iteminfo( "BASE", _( "Volume: " ),
- string_format( " %s", volume_units_abbr() ),
- f, converted_volume ) );
- }
- if( parts->test( iteminfo_parts::BASE_WEIGHT ) ) {
- info.push_back( iteminfo( "BASE", space + _( "Weight: " ),
- string_format( " %s", weight_units() ),
- 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)" ) );
- }
-
- 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 ) ) {
- 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() ) );
- double dps = ( dmg_bash + dmg_cut + dmg_stab ) * to_moves( 1_seconds ) /
- static_cast( attack_time() );
- static const matec_id rapid_strike( "RAPID" );
- if( has_technique( rapid_strike ) ) {
- dps *= 100.0 / 66;
- }
- info.push_back( iteminfo( "BASE", _( "Damage per second: " ), "",
- iteminfo::is_decimal, dps ) );
- }
- }
insert_separation_line( info );
@@ -1393,24 +1352,12 @@ 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 );
}
}
- 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() ) ) ) );
- }
if( has_var( "contained_name" ) && parts->test( iteminfo_parts::BASE_CONTENTS ) ) {
info.push_back( iteminfo( "BASE", string_format( _( "Contains: %s" ),
get_var( "contained_name" ) ) ) );
@@ -1605,6 +1552,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." ) );
@@ -1721,26 +1670,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 ) ) {
@@ -1775,7 +1725,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() ) {
@@ -1790,53 +1740,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;
@@ -1846,8 +1752,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 ) ) );
}
@@ -1855,36 +1762,9 @@ 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 ) ) {
- 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() ) );
}
@@ -1911,11 +1791,18 @@ void item::gun_info( const item *mod, std::vector &info, const iteminf
loaded_mod->gun_damage( true ).total_damage() ) );
}
}
+ 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 ) ) {
- 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() ) {
@@ -2008,6 +1895,69 @@ 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() ) );
+ }
+
+ if( parts->test( iteminfo_parts::GUN_AIMING_STATS ) ) {
+ 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.
+ 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 ) {
@@ -2017,7 +1967,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 ) );
}
}
@@ -2025,7 +1975,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 );
} ) );
@@ -2034,7 +1984,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();
@@ -2183,32 +2133,75 @@ 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() ) {
+ if( !is_armor() && !is_pet_armor() ) {
return;
}
- int encumbrance = get_encumber( g->u );
- const sizing sizing_level = get_sizing( g->u, encumbrance != 0 );
const std::string space = " ";
- body_part_set covered_parts = get_covered_body_parts();
- bool covers_anything = covered_parts.any();
- if( parts->test( iteminfo_parts::ARMOR_BODYPARTS ) ) {
- std::string coverage = _( "Covers: " );
- if( covers( bp_head ) ) {
- coverage += _( "The head. " );
- }
- if( covers( bp_eyes ) ) {
- coverage += _( "The eyes. " );
- }
- if( covers( bp_mouth ) ) {
- coverage += _( "The mouth. " );
- }
- if( covers( bp_torso ) ) {
- coverage += _( "The torso. " );
+ 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;
+ }
+
+ int encumbrance = get_encumber( g->u );
+ const sizing sizing_level = get_sizing( g->u, encumbrance != 0 );
+ const std::string space = " ";
+ body_part_set covered_parts = get_covered_body_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. " );
+ }
+ if( covers( bp_eyes ) ) {
+ coverage += _( "The eyes. " );
+ }
+ if( covers( bp_mouth ) ) {
+ coverage += _( "The mouth. " );
+ }
+ if( covers( bp_torso ) ) {
+ coverage += _( "The torso. " );
}
if( is_sided() && ( covers( bp_arm_l ) || covers( bp_arm_r ) ) ) {
@@ -2334,36 +2327,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 ) {
@@ -2390,9 +2357,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;
@@ -2413,36 +2379,164 @@ 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( 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( flag_FIT ) ) {
+ info.emplace_back( "DESCRIPTION",
+ _( "* This clothing fits you perfectly." ) );
+ }
+ break;
+ case sizing::big_sized_big_char:
+ if( has_flag( flag_FIT ) ) {
+ info.emplace_back( "DESCRIPTION", _( "* This clothing fits "
+ "your large frame perfectly." ) );
+ }
+ break;
+ case sizing::small_sized_small_char:
+ if( has_flag( 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( flag_VARSIZE ) ) {
+ std::string resize_str;
+ if( has_flag( 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 */,
@@ -2623,13 +2717,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 );
@@ -2656,9 +2750,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 );
} ) );
@@ -2700,25 +2793,48 @@ 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", string_format( _( "Repair using %s." ),
+ 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
{
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 ) ) );
@@ -2744,6 +2860,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 );
}
@@ -2771,26 +2888,195 @@ 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
+void item::bionic_info( std::vector &info, const iteminfo_query *parts, int /*batch*/,
+ bool /*debug*/ ) const
{
- if( is_null() ) {
+ if( !is_bionic() ) {
return;
}
- int encumbrance = get_encumber( g->u );
- const sizing sizing_level = get_sizing( g->u, encumbrance != 0 );
+ // 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( 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::combat_info( std::vector &info, const iteminfo_query *parts, int /*batch*/,
+ bool /*debug*/ ) const
+{
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 ) ) {
+ 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 );
- 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 ) );
- } ) ) );
+ std::string sep;
+ if( dmg_bash || dmg_cut || dmg_stab ) {
+ info.push_back( iteminfo( "BASE", _( "Melee damage: " ), "", iteminfo::no_newline ) );
+ }
+ if( dmg_bash ) {
+ info.push_back( iteminfo( "BASE", _( "Bash: " ), "", iteminfo::no_newline, dmg_bash ) );
+ sep = space;
+ }
+ if( dmg_cut ) {
+ info.push_back( iteminfo( "BASE", sep + _( "Cut: " ), "", iteminfo::no_newline, dmg_cut ) );
+ sep = space;
+ }
+ if( dmg_stab ) {
+ info.push_back( iteminfo( "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() ) );
+ double dps = ( dmg_bash + dmg_cut + dmg_stab ) * to_moves( 1_seconds ) /
+ static_cast( attack_time() );
+ static const matec_id rapid_strike( "RAPID" );
+ if( has_technique( rapid_strike ) ) {
+ dps *= 100.0 / 66;
+ }
+ info.push_back( iteminfo( "BASE", _( "Damage per second: " ), "",
+ iteminfo::is_decimal, dps ) );
+ }
+ }
+
+ 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( flag_REACH_ATTACK ) &&
@@ -2808,10 +3094,8 @@ 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 &&
- ( damage_melee( DT_BASH ) > 0 || damage_melee( DT_CUT ) > 0 ||
- damage_melee( DT_STAB ) > 0 || type->m_to_hit > 0 ) ) ) {
+ if( ( g->u.get_skill_level( skill_melee ) > 2 &&
+ ( 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;
@@ -2819,7 +3103,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",
@@ -2853,41 +3137,84 @@ void item::final_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 );
}
+}
- //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::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() );
}
-
- 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 );
+ 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() );
+ }
}
}
+}
- 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." ) );
+void item::final_info( std::vector &info, const iteminfo_query *parts, int batch,
+ bool debug ) const
+{
+ if( is_null() ) {
+ return;
+ }
+
+ const std::string space = " ";
+
+ 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." ) );
}
}
@@ -2904,11 +3231,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_WOOLALLERGY ) &&
( made_of( material_id( "wool" ) ) || item_tags.count( "wooled" ) ) ) {
info.push_back( iteminfo( "DESCRIPTION",
@@ -2932,153 +3254,7 @@ void item::final_info( std::vector &info, const iteminfo_query *parts,
}
}
- if( is_armor() ) {
- 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." ) ) );
- }
-
- if( parts->test( iteminfo_parts::DESCRIPTION_FLAGS_FITS ) ) {
- switch( sizing_level ) {
- case sizing::human_sized_human_char:
- if( has_flag( flag_FIT ) ) {
- info.emplace_back( "DESCRIPTION",
- _( "* This clothing fits you perfectly." ) );
- }
- break;
- case sizing::big_sized_big_char:
- if( has_flag( flag_FIT ) ) {
- info.emplace_back( "DESCRIPTION", _( "* This clothing fits "
- "your large frame perfectly." ) );
- }
- break;
- case sizing::small_sized_small_char:
- if( has_flag( 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( flag_VARSIZE ) ) {
- std::string resize_str;
- if( has_flag( 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( flag_USE_UPS ) && parts->test( iteminfo_parts::DESCRIPTION_RECHARGE_UPSMODDED ) ) {
@@ -3140,117 +3316,7 @@ 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 );
-
- if( is_bionic() && has_flag( 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 ) ) );
- }
- }
+ bionic_info( info, parts, batch, debug );
if( is_gun() && has_flag( flag_FIRE_TWOHAND ) &&
parts->test( iteminfo_parts::DESCRIPTION_TWOHANDED ) ) {
@@ -3337,7 +3403,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 );
@@ -3386,58 +3452,6 @@ 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 );
- }
-
- 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( _( "* This item can be used as a die, "
@@ -3446,7 +3460,22 @@ void item::final_info( std::vector &info, const iteminfo_query *parts,
0 ) ) ) );
}
- // list recipes you could use it in
+ // 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 ) );
+ }
+ 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();
@@ -3520,6 +3549,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 );
@@ -3544,13 +3577,22 @@ 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 );
- disassembly_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 );
+
final_info( info, parts, batch, debug );
if( !info.empty() && info.back().sName == "--" ) {
diff --git a/src/item.h b/src/item.h
index 6e406cab5bfba..b8a8000639d1a 100644
--- a/src/item.h
+++ b/src/item.h
@@ -398,10 +398,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,
@@ -412,10 +416,18 @@ 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,
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 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;
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,
diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp
index 4d6f9021e738f..07aecebfafe8e 100644
--- a/src/iuse_actor.cpp
+++ b/src/iuse_actor.cpp
@@ -563,11 +563,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 ) );
}
}
@@ -3921,13 +3921,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,
@@ -3937,25 +3942,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 ) );
@@ -3970,7 +3975,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 ) :
diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp
index 1e8ff78b45ca0..c551f0a2b1a58 100644
--- a/tests/iteminfo_test.cpp
+++ b/tests/iteminfo_test.cpp
@@ -12,7 +12,8 @@
#include "options_helpers.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;
@@ -20,68 +21,187 @@ 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]" )
+static void test_info_contains( const item &i, const iteminfo_query &q,
+ const std::string &reference )
{
- 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
- } );
+ 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 ) );
+}
+
+/*
+ * 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 = q_vec( { iteminfo_parts::BASE_CATEGORY, iteminfo_parts::BASE_MATERIAL,
+ iteminfo_parts::BASE_VOLUME, iteminfo_parts::BASE_WEIGHT,
+ iteminfo_parts::DESCRIPTION } );
+
override_option opt( "USE_METRIC_WEIGHTS", "lbs" );
- 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"
- "--\n"
- "Material: Plastic\n" );
+ SECTION( "volume, weight, category, material, description" ) {
+ test_info_equals(
+ item( "test_jug_plastic" ), q,
+ "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" );
+ }
+}
+
+TEST_CASE( "item owner, price, and barter value", "[item][iteminfo][price]" )
+{
+ iteminfo_query q = q_vec( std::vector( { iteminfo_parts::BASE_PRICE, iteminfo_parts::BASE_BARTER } ) );
+
+ SECTION( "owner and price" ) {
+ item my_rock( "test_rock" );
+ my_rock.set_owner( g->u );
+ test_info_equals(
+ my_rock, q,
+ "Owner: Your Followers\n"
+ "--\n"
+ "Price: $0.00" );
+ }
+ SECTION( "owner, price and barter value" ) {
+ item my_pipe( "test_pipe" );
+ my_pipe.set_owner( g->u );
+ test_info_equals(
+ my_pipe, q,
+ "Owner: Your Followers\n"
+ "--\n"
+ "Price: $75.00 Barter value: $3.00\n" );
+ }
+
+ SECTION( "zero price item with no owner" ) {
+ test_info_equals(
+ item( "test_rock" ), q,
+ "--\n"
+ "Price: $0.00" );
+ }
+}
+
+TEST_CASE( "item rigidity", "[item][iteminfo][rigidity]" )
+{
+ 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(
+ 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" );
+
+ test_info_equals(
+ 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( "rigid items do not indicate they are rigid, since almost all items are" ) {
+ test_info_equals(
+ 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, "" );
+ }
}
-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
- } );
-
- iteminfo_test(
- item( "halligan" ), q,
- "Bash: 20"
- " Cut: 5"
- " To-hit bonus: +2\n"
- "Moves per attack: 145\n"
- "Damage per second: 17.24\n" );
+ iteminfo_query q = q_vec( { iteminfo_parts::BASE_DAMAGE, iteminfo_parts::BASE_TOHIT,
+ iteminfo_parts::BASE_MOVES } );
+ SECTION( "bash damage" ) {
+ test_info_equals(
+ item( "test_rock" ), q,
+ "--\n"
+ "Melee damage: Bash: 7"
+ " To-hit bonus: -2\n"
+ "Moves per attack: 79\n"
+ "Damage per second: 8.86\n" );
+ }
+
+ SECTION( "bash and cut damage" ) {
+ test_info_equals(
+ item( "test_halligan" ), q,
+ "--\n"
+ "Melee damage: Bash: 20"
+ " Cut: 5"
+ " To-hit bonus: +2\n"
+ "Moves per attack: 145\n"
+ "Damage per second: 17.24\n" );
+ }
+
+ SECTION( "bash and pierce damage" ) {
+ test_info_equals(
+ item( "pointy_stick" ), q,
+ "--\n"
+ "Melee damage: Bash: 4"
+ " Pierce: 8"
+ " To-hit bonus: +1\n"
+ "Moves per attack: 100\n"
+ "Damage per second: 12.00\n" );
+ }
+
+ SECTION( "no damage" ) {
+ test_info_equals( item( "test_rag" ), q, "" );
+ }
}
-TEST_CASE( "techniques when wielded", "[item][iteminfo]" )
+TEST_CASE( "techniques when wielded", "[item][iteminfo][weapon]" )
{
- iteminfo_query q( { iteminfo_parts::DESCRIPTION_TECHNIQUES } );
+ iteminfo_query q = q_vec( { iteminfo_parts::DESCRIPTION_TECHNIQUES } );
- iteminfo_test(
- item( "halligan" ), q,
+ test_info_equals(
+ item( "test_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" );
}
-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,
- 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" ) {
- iteminfo_test(
- item( "longshirt" ), q,
+ test_info_equals(
+ item( "test_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"
@@ -92,78 +212,112 @@ TEST_CASE( "armor coverage and protection values", "[item][iteminfo]" )
}
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" );
+ "Covers: Nothing.\n" );
}
}
-TEST_CASE( "ranged weapon attributes", "[item][iteminfo]" )
+TEST_CASE( "ranged weapon attributes", "[item][iteminfo][weapon][ranged][gun]" )
{
- SECTION( "ammo capacity" ) {
- iteminfo_query q( { iteminfo_parts::GUN_CAPACITY } );
- iteminfo_test(
- item( "compbow" ), q,
+
+ SECTION( "skill used" ) {
+ iteminfo_query q = q_vec( { iteminfo_parts::GUN_USEDSKILL } );
+ test_info_equals(
+ item( "test_compbow" ), q,
+ "--\n"
+ "Skill used: archery\n" );
+ }
+
+ SECTION( "ammo capacity of weapon" ) {
+ iteminfo_query q = q_vec( { iteminfo_parts::GUN_CAPACITY } );
+ test_info_equals(
+ item( "test_compbow" ), q,
"--\n"
- "Capacity: 1 round of arrows\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,
+ SECTION( "default ammo when weapon is unloaded" ) {
+ iteminfo_query q = q_vec( { 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" ) {
- iteminfo_query q( { iteminfo_parts::GUN_DAMAGE, iteminfo_parts::GUN_DAMAGE_AMMOPROP,
- iteminfo_parts::GUN_DAMAGE_TOTAL
- } );
- iteminfo_test(
- item( "compbow" ), q,
+ SECTION( "weapon damage including floating-point multiplier" ) {
+ 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"
- "Damage: 50*1.50 = 75\n" );
+ "Ranged damage:"
+ " 18*1.50 = 27\n"
+ "Armor-pierce: 0\n" );
}
- SECTION( "time to reload" ) {
- iteminfo_query q( { iteminfo_parts::GUN_RELOAD_TIME } );
- iteminfo_test(
- item( "compbow" ), q,
+ SECTION( "time to reload weapon" ) {
+ iteminfo_query q = q_vec( { iteminfo_parts::GUN_RELOAD_TIME } );
+ test_info_equals(
+ item( "test_compbow" ), q,
"--\n"
- "Reload time: 100 moves \n" ); // NOLINT(cata-text-style)
+ "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,
+ SECTION( "weapon firing modes" ) {
+ iteminfo_query q = q_vec( { iteminfo_parts::GUN_FIRE_MODES } );
+ test_info_equals(
+ item( "test_compbow" ), q,
"--\n"
- "Fire modes: manual (1)\n" );
+ "Fire modes: manual (1)\n" );
}
SECTION( "weapon mods" ) {
- iteminfo_query q( { iteminfo_parts::DESCRIPTION_GUN_MODS } );
- iteminfo_test(
- item( "compbow" ), q,
+ iteminfo_query q = q_vec( { iteminfo_parts::DESCRIPTION_GUN_MODS } );
+ test_info_equals(
+ item( "test_compbow" ), q,
"--\n"
- "Mods: 0/2 accessories;"
+ "Mods: 0/2 accessories;"
" 0/1 dampening; 0/1 sights;"
" 0/1 stabilizer; 0/1 underbarrel.\n" );
}
+ SECTION( "weapon dispersion" ) {
+ iteminfo_query q = q_vec( { iteminfo_parts::GUN_DISPERSION } );
+ test_info_equals(
+ item( "test_compbow" ), q,
+ "--\n"
+ "Dispersion: 850\n" );
+ }
+}
+
+TEST_CASE( "ammunition", "[item][iteminfo][ammo]" )
+{
+ 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(
+ item( "test_rock" ), q,
+ "--\n"
+ "Ammunition type: rocks\n"
+ "Damage: 7 Armor-pierce: 0\n"
+ "Range: 10 Dispersion: