1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
|
#include "avatar.h"
#include "cata_catch.h"
#include "itype.h"
#include "player_helpers.h"
#include "type_id.h"
static const quality_id qual_BOIL( "BOIL" );
static const quality_id qual_DRILL( "DRILL" );
static const quality_id qual_LOCKPICK( "LOCKPICK" );
static const quality_id qual_PRY( "PRY" );
static const quality_id qual_SCREW( "SCREW" );
static const quality_id qual_SCREW_FINE( "SCREW_FINE" );
static const quality_id qual_WRENCH( "WRENCH" );
// item::get_quality
//
// Returns the best quality level provided by:
//
// - inherent qualities from the "qualities" field
// - charged qualities from the "charged_qualities" field (only if item has sufficient charge)
// - inherent or charged qualities of any items contained within this item
//
// The BOIL quality requires the item (container) to be empty, unless strict_boiling = false.
//
TEST_CASE( "get_quality", "[tool][quality]" )
{
SECTION( "get_quality returns numeric level of given quality" ) {
item sonic( "test_sonic_screwdriver" );
CHECK( sonic.get_quality( qual_LOCKPICK ) == 30 );
CHECK( sonic.get_quality( qual_PRY ) == 2 );
CHECK( sonic.get_quality( qual_SCREW ) == 2 );
CHECK( sonic.get_quality( qual_SCREW_FINE ) == 1 );
CHECK( sonic.get_quality( qual_WRENCH ) == 1 );
}
SECTION( "charged_qualities" ) {
// Without charges, the cordless drill cannot drill, but with charges, it can drill
SECTION( "with 0 charge, get_quality returns 0" ) {
CHECK( tool_with_ammo( "test_cordless_drill", 0 ).get_quality( qual_DRILL ) == 0 );
}
SECTION( "with sufficient charge, get_quality returns quality level" ) {
CHECK( tool_with_ammo( "test_cordless_drill", 20 ).get_quality( qual_DRILL ) == 3 );
}
}
SECTION( "BOIL quality" ) {
// Tools that can BOIL and have a CONTAINER pocket have BOIL quality only when empty
item tin_can( "test_can_food" );
SECTION( "get_quality returns BOIL quality if container is empty" ) {
REQUIRE( tin_can.empty_container() );
CHECK( tin_can.get_quality( qual_BOIL ) == 1 );
}
SECTION( "get_quality returns INT_MIN for BOIL quality if container is not empty" ) {
item broth( "test_liquid" );
tin_can.put_in( broth, pocket_type::CONTAINER );
REQUIRE_FALSE( tin_can.empty_container() );
CHECK( tin_can.get_quality( qual_BOIL ) == INT_MIN );
// Passing strict_boiling = false to get_quality ignores the emptiness rule
CHECK( tin_can.get_quality( qual_BOIL, false ) == 1 );
}
}
}
// Tools that run on battery power (or are otherwise "charged") may have "charged_qualities"
// that are only available when the item is charged with at least "charges_per_use" charges.
TEST_CASE( "battery-powered_tool_qualities", "[tool][battery][quality]" )
{
item drill( "test_cordless_drill" );
item battery( "medium_battery_cell" );
// This cordless drill is a battery-powered tool needing some charges for each use
REQUIRE( drill.is_tool() );
REQUIRE( drill.type->charges_to_use() > 0 );
// It has one "inherent" quality, SCREW 1, that always works regardless of charges
REQUIRE( drill.type->qualities.size() == 1 );
// and it has one "charged" quality, DRILL 3, that only works with enough charges
REQUIRE( drill.type->charged_qualities.size() == 1 );
// the idea being that the screwdriver bit can be used to awkwardly turn screws, even without
// powered assistance, while drilling holes with an unpowered drill bit is nigh impossible.
// TODO: Eventually, battery power should also give a significant advantage to the speed or
// effort of screw-turning, compared with manual wrist-twisting.
WHEN( "tool has no battery" ) {
REQUIRE_FALSE( drill.magazine_current() );
// Screwing should work, but drilling should not
THEN( "inherent qualities can be used" ) {
CHECK( drill.has_quality( qual_SCREW, 1, 1 ) );
}
THEN( "charged tool qualities cannot be used" ) {
CHECK_FALSE( drill.has_quality( qual_DRILL, 3, 1 ) );
}
}
WHEN( "tool has a battery with zero charge" ) {
// Get a dead battery
battery.ammo_set( battery.ammo_default(), 0 );
REQUIRE( battery.ammo_remaining() == 0 );
// Install the battery in the drill
drill.put_in( battery, pocket_type::MAGAZINE_WELL );
REQUIRE( drill.magazine_current() );
REQUIRE( drill.ammo_remaining() == 0 );
// Screwing should work, but drilling should not
THEN( "inherent qualities can be used" ) {
CHECK( drill.has_quality( qual_SCREW, 1, 1 ) );
}
THEN( "charged tool qualities cannot be used" ) {
CHECK_FALSE( drill.has_quality( qual_DRILL, 3, 1 ) );
}
}
WHEN( "tool has a battery with enough charge for one use, equal to charges_per_use" ) {
// Get a battery with exactly enough charge for one use
int bat_charges = drill.type->charges_to_use();
battery.ammo_set( battery.ammo_default(), bat_charges );
REQUIRE( battery.ammo_remaining() == bat_charges );
// Install the battery in the drill
drill.put_in( battery, pocket_type::MAGAZINE_WELL );
REQUIRE( drill.magazine_current() );
REQUIRE( drill.ammo_remaining() == bat_charges );
// Ensure there is enough charge
REQUIRE( drill.type->charges_to_use() <= bat_charges );
// Both screwing and drilling should work
THEN( "both inherent and charged tool qualities can be used" ) {
CHECK( drill.has_quality( qual_SCREW, 1, 1 ) );
CHECK( drill.has_quality( qual_DRILL, 3, 1 ) );
}
}
WHEN( "tool has a battery with insufficient charge, less than charges_per_use" ) {
// Get a battery with too few charges by 1
int bat_charges = drill.type->charges_to_use() - 1;
battery.ammo_set( battery.ammo_default(), bat_charges );
REQUIRE( battery.ammo_remaining() == bat_charges );
// Install the battery in the drill
drill.put_in( battery, pocket_type::MAGAZINE_WELL );
REQUIRE( drill.magazine_current() );
REQUIRE( drill.ammo_remaining() == bat_charges );
// Ensure there is not enough charge
REQUIRE( drill.type->charges_to_use() > bat_charges );
// Screwing should still work, but drilling should not
THEN( "inherent qualities can be used" ) {
CHECK( drill.has_quality( qual_SCREW, 1, 1 ) );
}
THEN( "charged tool qualities cannot be used" ) {
CHECK_FALSE( drill.has_quality( qual_DRILL, 3, 1 ) );
}
}
SECTION( "charged tool qualities with UPS conversion mod" ) {
// Need avatar as "carrier" for the UPS
Character &they = get_player_character();
clear_character( they );
they.worn.wear_item( they, item( "debug_backpack" ), false, false );
// Use i_add to place everything in the avatar's inventory (backpack)
// so the UPS power will be available to the cordless drill after modding
item_location drill = they.i_add( item( "test_cordless_drill" ) );
item_location bat_cell = they.i_add( item( "heavy_battery_cell" ) );
item_location ups_mod = they.i_add( item( "battery_ups" ) );
item_location ups = they.i_add( item( "UPS_ON" ) );
GIVEN( "UPS has battery with enough charge, equal to drill's charges_per_use" ) {
// Charge the battery
int bat_charges = drill->type->charges_to_use();
REQUIRE( bat_charges > 0 );
bat_cell->ammo_set( bat_cell->ammo_default(), bat_charges );
REQUIRE( bat_cell->ammo_remaining() == bat_charges );
// Install heavy battery into UPS
REQUIRE( ups->put_in( *bat_cell, pocket_type::MAGAZINE_WELL ).success() );
REQUIRE( ups->ammo_remaining( &they ) == bat_charges );
WHEN( "UPS battery mod is installed into the drill" ) {
// Ensure drill currently has no mods
REQUIRE( drill->toolmods().empty() );
REQUIRE( drill->tname() == "test cordless drill" );
// Install the UPS mod and ensure it worked
drill->put_in( *ups_mod, pocket_type::MOD );
REQUIRE_FALSE( drill->toolmods().empty() );
REQUIRE( drill->tname() == "test cordless drill+1 (UPS)" );
// Ensure avatar actually has the drill and UPS in possession
CHECK( they.has_item( *drill ) );
CHECK( they.has_item( *ups ) );
THEN( "the drill has the same charge as the UPS" ) {
CHECK( drill->ammo_remaining( &they ) == bat_charges );
}
THEN( "inherent qualities of the drill can be used" ) {
CHECK( drill->has_quality( qual_SCREW, 1, 1 ) );
}
// Regression test for #54471
THEN( "charged qualities of the drill can be used" ) {
CHECK( drill->has_quality( qual_DRILL, 3, 1 ) );
}
}
}
}
}
|