Skip to content

Commit

Permalink
feat(balance): revamp throwing damage (#5088)
Browse files Browse the repository at this point in the history
* refactor: use const

* feat: revamp throwing damage

* refactor: use `std::min`

* feat(balance): double throwing range

also eradicate imperial units along the way

* feat(balance): round rock and javelin weight

* fix: reword bio railgun description

* test: update snapshot

* refactor: remove static cast to long

* fix: rollback range buff
  • Loading branch information
scarf005 authored Sep 28, 2024
1 parent 1eb383c commit db61eb6
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 45 deletions.
2 changes: 1 addition & 1 deletion data/json/bionics.json
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@
"id": "bio_railgun",
"type": "bionic",
"name": { "str": "Railgun" },
"description": "EM field generators in your arms double the range and damage of thrown iron and steel objects at a cost of 1 power per throw, causing them to leave a trail of electricity that can cause additional damage.",
"description": "EM field generators in your arms double the range and increase damage of thrown iron and steel objects at a cost of 1kJ per throw, causing them to leave a trail of electricity that can cause additional damage.",
"occupied_bodyparts": [ [ "arm_l", 5 ], [ "arm_r", 5 ], [ "hand_l", 1 ], [ "hand_r", 1 ] ],
"flags": [ "BIONIC_TOGGLED" ],
"act_cost": "1 kJ",
Expand Down
2 changes: 1 addition & 1 deletion data/json/items/ammo.json
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@
"material": "stone",
"ammo_type": "rock",
"flags": [ "TRADER_AVOID" ],
"weight": "657 g",
"weight": "500 g",
"volume": "250 ml",
"bashing": 7,
"damage": { "damage_type": "bash", "amount": 7 },
Expand Down
2 changes: 1 addition & 1 deletion data/json/items/melee/spears_and_polearms.json
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@
"copy-from": "javelin",
"name": { "str": "iron javelin" },
"description": "An iron-tipped wooden throwing spear. The grip area has been carved and covered for better grip.",
"weight": "960 g",
"weight": "1 kg",
"to_hit": -1,
"color": "light_gray",
"material": [ "wood", "iron" ],
Expand Down
16 changes: 6 additions & 10 deletions src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6713,7 +6713,7 @@ int Character::throw_range( const item &it ) const
}

/** @EFFECT_STR determines maximum weight that can be thrown */
if( ( tmp.weight() / 113_gram ) > static_cast<int>( str_cur * 15 ) ) {
if( ( tmp.weight() / 100_gram ) > static_cast<int>( str_cur * 15 ) ) {
return 0;
}
// Increases as weight decreases until 150 g, then decreases again
Expand All @@ -6723,9 +6723,10 @@ int Character::throw_range( const item &it ) const
auto mons = mounted_creature.get();
str_override = mons->mech_str_addition() != 0 ? mons->mech_str_addition() : str_cur;
}
int ret = ( str_override * 10 ) / ( tmp.weight() >= 150_gram ? tmp.weight() / 113_gram : 10 -
static_cast<int>(
tmp.weight() / 15_gram ) );
const int divisor = tmp.weight() >= 150_gram
? tmp.weight() / 100_gram
: 10 - static_cast<int>( tmp.weight() / 15_gram );
int ret = ( str_override * 10 ) / divisor;
ret -= tmp.volume() / 1_liter;
static const std::set<material_id> affected_materials = { material_id( "iron" ), material_id( "steel" ) };
if( has_active_bionic( bio_railgun ) && tmp.made_of_any( affected_materials ) ) {
Expand All @@ -6738,12 +6739,7 @@ int Character::throw_range( const item &it ) const
/** @EFFECT_STR caps throwing range */

/** @EFFECT_THROW caps throwing range */
if( ret > str_override * 3 + get_skill_level( skill_throw ) ) {
return str_override * 3 + get_skill_level( skill_throw );
}


return ret;
return std::min( ret, str_override * 3 + get_skill_level( skill_throw ) );
}

const std::vector<material_id> Character::fleshy = { material_id( "flesh" ), material_id( "hflesh" ) };
Expand Down
35 changes: 15 additions & 20 deletions src/ranged.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1177,8 +1177,8 @@ dealt_projectile_attack throw_item( Character &who, const tripoint &target,
who.mod_moves( -move_cost );

const int throwing_skill = who.get_skill_level( skill_throw );
units::volume volume = thrown.volume();
units::mass weight = thrown.weight();
const units::volume volume = thrown.volume();
const units::mass weight = thrown.weight();

// Previously calculated as 2_gram * std::max( 1, str_cur )
// using 16_gram normalizes it to 8 str. Same effort expenditure
Expand Down Expand Up @@ -1208,29 +1208,24 @@ dealt_projectile_attack throw_item( Character &who, const tripoint &target,
if( who.has_effect( effect_downed ) ) {
skill_level = std::max( 0, skill_level - 5 );
}

static const std::set<material_id> ferric = { material_id( "iron" ), material_id( "steel" ) };
const bool do_railgun = who.has_active_bionic( bio_railgun ) && thrown.made_of_any( ferric ) &&
!throw_assist;
const int effective_strength =
throw_assist ? throw_assist_str : do_railgun ? who.get_str() * 2 : who.get_str();

// We'll be constructing a projectile
projectile proj;
proj.impact = thrown.base_damage_thrown();
proj.speed = 10 + skill_level;
proj.speed = std::log2( std::max( 1, skill_level ) )
+ std::log2( std::max( 1, effective_strength ) );
auto &impact = proj.impact;

static const std::set<material_id> ferric = { material_id( "iron" ), material_id( "steel" ) };

bool do_railgun = who.has_active_bionic( bio_railgun ) && thrown.made_of_any( ferric ) &&
!throw_assist;

// The damage dealt due to item's weight, player's strength, and skill level
// Up to str/2 or weight/100g (lower), so 10 str is 5 damage before multipliers
// Railgun doubles the effective strength
///\EFFECT_STR increases throwing damage
double stats_mod = do_railgun ? who.get_str() : ( who.get_str() / 2.0 );
stats_mod = throw_assist ? throw_assist_str / 2.0 : stats_mod;
// modify strength impact based on skill level, clamped to [0.15 - 1]
// mod = mod * [ ( ( skill / max_skill ) * 0.85 ) + 0.15 ]
stats_mod *= ( std::min( MAX_SKILL,
who.get_skill_level( skill_throw ) ) /
static_cast<double>( MAX_SKILL ) ) * 0.85 + 0.15;
impact.add_damage( DT_BASH, std::min( weight / 100.0_gram, stats_mod ) );
// calculate extra damage, proportional to 1/2mv^2
// @see https://www.desmos.com/calculator/ibo2jh9cqa
const float damage = 0.5 * ( weight / 1_gram / 1000.0 ) * std::pow( proj.speed, 2 );
impact.add_damage( DT_BASH, static_cast<int>( damage ) );

if( thrown.has_flag( flag_ACT_ON_RANGED_HIT ) ) {
proj.add_effect( ammo_effect_ACT_ON_RANGED_HIT );
Expand Down
24 changes: 12 additions & 12 deletions tests/throwing_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ TEST_CASE( "basic_throwing_sanity_tests", "[throwing],[balance]" )
}

SECTION( "test_player_vs_zombie_javelin_iron_basestats" ) {
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 1, lo_skill_base_stats, { 1.00, 0.10 }, { 28, 5 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 1, lo_skill_base_stats, { 1.00, 0.10 }, { 33, 5 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 5, lo_skill_base_stats, { 0.64, 0.10 }, { 13, 3 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 10, lo_skill_base_stats, { 0.20, 0.10 }, { 4, 2 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 15, lo_skill_base_stats, { 0.11, 0.10 }, { 1.29, 3 } );
Expand All @@ -204,13 +204,13 @@ TEST_CASE( "basic_throwing_sanity_tests", "[throwing],[balance]" )
}

SECTION( "test_player_vs_zombie_javelin_iron_athlete" ) {
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 1, hi_skill_athlete_stats, { 1.00, 0.10 }, { 34.00, 8 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 5, hi_skill_athlete_stats, { 1.00, 0.10 }, { 34.00, 8 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 10, hi_skill_athlete_stats, { 1.00, 0.10 }, { 34.16, 8 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 15, hi_skill_athlete_stats, { 0.97, 0.10 }, { 25.21, 6 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 20, hi_skill_athlete_stats, { 0.77, 0.10 }, { 18.90, 5 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 25, hi_skill_athlete_stats, { 0.58, 0.10 }, { 13.59, 5 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 30, hi_skill_athlete_stats, { 0.43, 0.10 }, { 10.00, 4 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 1, hi_skill_athlete_stats, { 1.00, 0.10 }, { 59.00, 8 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 5, hi_skill_athlete_stats, { 1.00, 0.10 }, { 50.55, 8 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 10, hi_skill_athlete_stats, { 1.00, 0.10 }, { 38.00, 8 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 15, hi_skill_athlete_stats, { 0.97, 0.10 }, { 36.71, 6 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 20, hi_skill_athlete_stats, { 0.77, 0.10 }, { 27.51, 5 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 25, hi_skill_athlete_stats, { 0.58, 0.10 }, { 20.42, 5 } );
test_throwing_player_versus( p, "mon_zombie", "javelin_iron", 30, hi_skill_athlete_stats, { 0.43, 0.10 }, { 15.31, 4 } );
}
}

Expand All @@ -223,14 +223,14 @@ TEST_CASE( "throwing_skill_impact_test", "[throwing],[balance]" )
// the throwing skill has while the sanity tests are more explicit.
SECTION( "mid_skill_basestats_rock" ) {
test_throwing_player_versus( p, "mon_zombie", "rock", 5, mid_skill_base_stats, { 1.00, 0.10 }, { 12, 6 } );
test_throwing_player_versus( p, "mon_zombie", "rock", 10, mid_skill_base_stats, { 0.92, 0.10 }, { 7, 4 } );
test_throwing_player_versus( p, "mon_zombie", "rock", 15, mid_skill_base_stats, { 0.62, 0.10 }, { 5, 2 } );
test_throwing_player_versus( p, "mon_zombie", "rock", 10, mid_skill_base_stats, { 0.92, 0.10 }, { 11.6, 4 } );
test_throwing_player_versus( p, "mon_zombie", "rock", 15, mid_skill_base_stats, { 0.62, 0.10 }, { 7, 2 } );
}

SECTION( "hi_skill_basestats_rock" ) {
test_throwing_player_versus( p, "mon_zombie", "rock", 5, hi_skill_base_stats, { 1.00, 0.10 }, { 18, 5 } );
test_throwing_player_versus( p, "mon_zombie", "rock", 10, hi_skill_base_stats, { 1.00, 0.10 }, { 14.7, 5 } );
test_throwing_player_versus( p, "mon_zombie", "rock", 15, hi_skill_base_stats, { 0.97, 0.10 }, { 10.5, 4 } );
test_throwing_player_versus( p, "mon_zombie", "rock", 10, hi_skill_base_stats, { 1.00, 0.10 }, { 16, 5 } );
test_throwing_player_versus( p, "mon_zombie", "rock", 15, hi_skill_base_stats, { 0.97, 0.10 }, { 15, 4 } );
}
}

Expand Down

0 comments on commit db61eb6

Please sign in to comment.