Skip to content

Commit

Permalink
Damage symbols/colors/levels/etc now have 5 stages
Browse files Browse the repository at this point in the history
  • Loading branch information
irwiss committed Mar 28, 2023
1 parent 02a4cb8 commit ae1c1e6
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 111 deletions.
6 changes: 1 addition & 5 deletions src/activity_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2475,11 +2475,7 @@ void activity_handlers::mend_item_finish( player_activity *act, Character *you )
const std::string start_durability = target->durability_indicator( true );
item &fix = *target.get_item();
for( int i = 0; i < method->heal_stages.value_or( 0 ); i++ ) {
int dmg = fix.damage() + 1;
for( const int lvl = fix.damage_level(); lvl == fix.damage_level() && dmg != fix.damage(); ) {
dmg = fix.damage(); // break loop if clamped by degradation or no more repair needed
fix.mod_damage( -1 ); // scan for next damage indicator breakpoint, repairing that much damage
}
fix.mod_damage( -itype::damage_scale );
}

//get skill list from mending method, iterate through and give xp
Expand Down
45 changes: 17 additions & 28 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -828,16 +828,9 @@ void item::rand_degradation()
set_degradation( rng( 0, damage() ) * 50.0f / type->degrade_increments() );
}

int item::damage_level( int dmg ) const
int item::damage_level() const
{
dmg = dmg == INT_MIN ? damage_ : dmg;
if( dmg == 0 ) {
return 0;
} else if( max_damage() <= 1 ) {
return dmg > 0 ? 4 : dmg;
} else {
return 3 * ( dmg - 1 ) / ( max_damage() - 1 ) + 1;
}
return type->damage_level( damage_ );
}

void item::set_damage( int qty )
Expand Down Expand Up @@ -8640,7 +8633,7 @@ bool item::inc_damage()

int item::repairable_levels() const
{
const int levels = damage_level( damage_ ) - damage_level( degradation_ );
const int levels = type->damage_level( damage_ ) - type->damage_level( degradation_ );

return levels > 0
? levels // full integer levels of damage
Expand Down Expand Up @@ -8724,19 +8717,17 @@ nc_color item::damage_color() const
{
switch( damage_level() ) {
case 0:
return c_light_green;
return c_green;
case 1:
return c_yellow;
return c_light_green;
case 2:
return c_light_red;
return c_yellow;
case 3:
return c_magenta;
return c_light_red;
case 4:
if( damage() >= max_damage() ) {
return c_dark_gray;
} else {
return c_red;
}
return c_red;
case 5:
return c_dark_gray;
default:
debugmsg( "damage_level returned unexpected value %d", damage_level() );
return c_dark_gray;
Expand All @@ -8747,19 +8738,17 @@ std::string item::damage_symbol() const
{
switch( damage_level() ) {
case 0:
return _( R"(||)" );
return _( R"(++)" );
case 1:
return _( R"(|\)" );
return _( R"(||)" );
case 2:
return _( R"(|.)" );
return _( R"(|\)" );
case 3:
return _( R"(\.)" );
return _( R"(|.)" );
case 4:
if( damage() >= max_damage() ) {
return _( R"(XX)" );
} else {
return _( R"(..)" );
}
return _( R"(\.)" );
case 5:
return _( R"(XX)" );
default:
debugmsg( "damage_level returned unexpected value %d", damage_level() );
return _( R"(??)" ); // negative damage is invalid
Expand Down
34 changes: 8 additions & 26 deletions src/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -1304,41 +1304,23 @@ class item : public visitable
/** How much degradation has the item accumulated? */
int degradation() const;

/** Used when spawning the item. Sets a random degradation within [0, damage]. */
// Sets a random degradation within [0, damage), used when spawning the item
void rand_degradation();

/**
* Scale item damage to the given number of levels. This function is
* here mostly for back-compatibility. It should not be used when
* doing continuous math with the damage value: use damage() instead.
*
* For example, for min_damage = 0, max_damage = 4000
* damage level
* 0 0
* 1 ~ 1333 1
* 1334 ~ 2666 2
* 2667 ~ 3999 3
* 4000 4
*
* @param dmg If specified, get the damage level of "dmg" instead of
* this item's current damage.
*/
int damage_level( int dmg = INT_MIN ) const;
// @see itype::damage_level()
int damage_level() const;

/** Maximum amount of damage to an item (state before destroyed) */
// @return 0 if item is count_by_charges() or 4000 ( value of itype::damage_max_ )
int max_damage() const;

/**
* Returns how many damage levels can be repaired on this item rounded up
* Example: item with 100 damage returns 1 ( 100 -> 0 )
* Example: item with 2000 damage returns 2 ( 2000 -> 1333 -> 0 )
* Returns how many damage levels can be repaired on this item
* Example: item with 100 damage returns 1 ( 100 -> 0 )
* Example: item with 2100 damage returns 3 ( 2100 -> 1100 -> 100 -> 0 )
*/
int repairable_levels() const;

/**
* Relative item health.
* Returns 1 for undamaged items, values in the range (0, 1) for damaged items
*/
// @return 1 for undamaged items or remaining hp divided by max hp in range [0, 1)
float get_relative_health() const;

/**
Expand Down
11 changes: 11 additions & 0 deletions src/itype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ std::string itype::nname( unsigned int quantity ) const
return name.translated( quantity );
}

int itype::damage_level( int damage ) const
{
if( damage == 0 ) {
return 0;
}
if( count_by_charges() ) {
return 5;
}
return std::clamp( 1 + 4 * damage / damage_max(), 0, 5 );
}

bool itype::has_any_quality( const std::string &quality ) const
{
return std::any_of( qualities.begin(),
Expand Down
13 changes: 12 additions & 1 deletion src/itype.h
Original file line number Diff line number Diff line change
Expand Up @@ -1317,7 +1317,7 @@ struct itype {

private:
/** maximum amount of damage to a non- count_by_charges item */
static constexpr int damage_max_ = +4000;
static constexpr int damage_max_ = 4000;
int degrade_increments_ = 50;

public:
Expand Down Expand Up @@ -1354,6 +1354,17 @@ struct itype {
return count_by_charges() ? 0 : degrade_increments_;
}

/**
* Quantizes item damage numbers into levels (for example for display).
* item damage [ 0 - 0 ] returns 0
* item damage [ 1 - 999 ] returns 1
* item damage [ 1000 - 1999 ] returns 2
* item damage [ 2000 - 2999 ] returns 3
* item damage [ 3000 - 3999 ] returns 4
* item damage [ 4000 - 4000 ] returns 5
*/
int damage_level( int damage ) const;

std::string get_item_type_string() const;

// Returns the name of the item type in the correct language and with respect to its grammatical number,
Expand Down
6 changes: 1 addition & 5 deletions src/iuse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5527,11 +5527,7 @@ std::optional<int> gun_repair( Character *p, item *, item_location &loc )
p->practice( skill_mechanics, 10 );
p->moves -= to_moves<int>( 20_seconds );

int dmg = fix.damage() + 1;
for( const int lvl = fix.damage_level(); lvl == fix.damage_level() && dmg != fix.damage(); ) {
dmg = fix.damage(); // break loop if clamped by degradation or no more repair needed
fix.mod_damage( -1 ); // scan for next damage indicator breakpoint, repairing that much damage
}
fix.mod_damage( -itype::damage_scale );

const std::string msg = fix.damage_level() == 0
? _( "You repair your %s completely! ( %s-> %s)" )
Expand Down
38 changes: 20 additions & 18 deletions tests/degradation_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ TEST_CASE( "Degradation on spawned items", "[item][degradation]" )
float doub = get_avg_degradation( itype_test_baseball_x2_degradation, max_iters, 3000 );
CHECK( norm == Approx( 1500.0 ).epsilon( 0.1 ) );
CHECK( half == Approx( 750.0 ).epsilon( 0.1 ) );
CHECK( doub == Approx( 3000.0 ).epsilon( 0.1 ) );
// not 3000.0 as expected - as degradation calculation gets clamped to max 4000
CHECK( doub == Approx( 2750.0 ).epsilon( 0.1 ) );
}
}

Expand All @@ -108,18 +109,18 @@ TEST_CASE( "Items that get damaged gain degradation", "[item][degradation]" )

WHEN( "Item loses 10 damage levels" ) {
add_x_dmg_levels( it, 10 );
THEN( "Item gains 10 percent as degradation, 0 damage level" ) {
THEN( "Item gains 10 percent as degradation, 2 damage level" ) {
CHECK( it.degradation() == 1040 );
CHECK( it.damage_level() == 1 );
CHECK( it.damage_level() == 2 );
CHECK( it.damage() == it.degradation() );
}
}

WHEN( "Item loses 20 damage levels" ) {
add_x_dmg_levels( it, 20 );
THEN( "Item gains 10 percent as degradation, 1 damage level" ) {
THEN( "Item gains 10 percent as degradation, 3 damage level" ) {
CHECK( it.degradation() == 2000 );
CHECK( it.damage_level() == 2 );
CHECK( it.damage_level() == 3 );
CHECK( it.damage() == it.degradation() );
}
}
Expand All @@ -135,7 +136,7 @@ TEST_CASE( "Items that get damaged gain degradation", "[item][degradation]" )

WHEN( "Item loses 20 damage levels" ) {
add_x_dmg_levels( it, 20 );
THEN( "Item gains 5 percent as degradation, 0 damage level" ) {
THEN( "Item gains 5 percent as degradation, 1 damage level" ) {
CHECK( it.degradation() == 960 );
CHECK( it.damage_level() == 1 );
CHECK( it.damage() == it.degradation() );
Expand All @@ -152,18 +153,18 @@ TEST_CASE( "Items that get damaged gain degradation", "[item][degradation]" )

WHEN( "Item loses 10 damage levels" ) {
add_x_dmg_levels( it, 10 );
THEN( "Item gains 20 percent as degradation, 1 damage level" ) {
THEN( "Item gains 20 percent as degradation, 3 damage level" ) {
CHECK( it.degradation() == 2080 );
CHECK( it.damage_level() == 2 );
CHECK( it.damage_level() == 3 );
CHECK( it.damage() == it.degradation() );
}
}

WHEN( "Item loses 20 damage levels" ) {
add_x_dmg_levels( it, 20 );
THEN( "Item gains 20 percent as degradation, 3 damage level" ) {
THEN( "Item gains 20 percent as degradation, 4 damage level" ) {
CHECK( it.degradation() == 3040 );
CHECK( it.damage_level() == 3 );
CHECK( it.damage_level() == 4 );
CHECK( it.damage() == it.degradation() );
}
}
Expand Down Expand Up @@ -420,11 +421,11 @@ TEST_CASE( "Gun repair with degradation", "[item][degradation]" )
gun.set_degradation( 0 );
REQUIRE( gun.damage() == 4000 );
REQUIRE( gun.degradation() == 0 );
THEN( "Repaired to 3999 damage" ) {
THEN( "Repaired to 3000 damage" ) {
u.wield( gun );
item_location gun_loc( u, &gun );
::gun_repair( &u, &gun, gun_loc );
CHECK( gun.damage() == 3999 );
CHECK( gun.damage() == 3000 );
}
}

Expand Down Expand Up @@ -459,11 +460,11 @@ TEST_CASE( "Gun repair with degradation", "[item][degradation]" )
gun.set_degradation( 1000 );
REQUIRE( gun.damage() == 4000 );
REQUIRE( gun.degradation() == 1000 );
THEN( "Repaired to 3999 damage" ) {
THEN( "Repaired to 3000 damage" ) {
u.wield( gun );
item_location gun_loc( u, &gun );
::gun_repair( &u, &gun, gun_loc );
CHECK( gun.damage() == 3999 );
CHECK( gun.damage() == 3000 );
}
}

Expand Down Expand Up @@ -498,11 +499,12 @@ TEST_CASE( "Gun repair with degradation", "[item][degradation]" )
gun.set_degradation( 2000 );
REQUIRE( gun.damage() == 4000 );
REQUIRE( gun.degradation() == 2000 );
THEN( "Repaired to 3999 damage" ) {
THEN( "Repaired to 2000 damage" ) {
u.wield( gun );
item_location gun_loc( u, &gun );
::gun_repair( &u, &gun, gun_loc );
CHECK( gun.damage() == 3999 );
::gun_repair( &u, &gun, gun_loc );
CHECK( gun.damage() == 2000 );
}
}

Expand Down Expand Up @@ -537,11 +539,11 @@ TEST_CASE( "Gun repair with degradation", "[item][degradation]" )
gun.set_degradation( 3000 );
REQUIRE( gun.damage() == 4000 );
REQUIRE( gun.degradation() == 3000 );
THEN( "Repaired to 3999 damage" ) {
THEN( "Repaired to 3000 damage" ) {
u.wield( gun );
item_location gun_loc( u, &gun );
::gun_repair( &u, &gun, gun_loc );
CHECK( gun.damage() == 3999 );
CHECK( gun.damage() == 3000 );
}
}

Expand Down
Loading

0 comments on commit ae1c1e6

Please sign in to comment.