diff --git a/data/json/bionics.json b/data/json/bionics.json index 9da4ff744c0f..e6008da202e5 100644 --- a/data/json/bionics.json +++ b/data/json/bionics.json @@ -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", diff --git a/data/json/items/ammo.json b/data/json/items/ammo.json index faf3de62768b..438e7538a974 100644 --- a/data/json/items/ammo.json +++ b/data/json/items/ammo.json @@ -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 }, diff --git a/data/json/items/melee/spears_and_polearms.json b/data/json/items/melee/spears_and_polearms.json index 1a986fcacebe..12a27e47c291 100644 --- a/data/json/items/melee/spears_and_polearms.json +++ b/data/json/items/melee/spears_and_polearms.json @@ -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" ], diff --git a/src/character.cpp b/src/character.cpp index 819aa71a7580..b40512571529 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -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( str_cur * 15 ) ) { + if( ( tmp.weight() / 100_gram ) > static_cast( str_cur * 15 ) ) { return 0; } // Increases as weight decreases until 150 g, then decreases again @@ -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( - tmp.weight() / 15_gram ) ); + const int divisor = tmp.weight() >= 150_gram + ? tmp.weight() / 100_gram + : 10 - static_cast( tmp.weight() / 15_gram ); + int ret = ( str_override * 10 ) / divisor; ret -= tmp.volume() / 1_liter; static const std::set affected_materials = { material_id( "iron" ), material_id( "steel" ) }; if( has_active_bionic( bio_railgun ) && tmp.made_of_any( affected_materials ) ) { @@ -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 Character::fleshy = { material_id( "flesh" ), material_id( "hflesh" ) }; diff --git a/src/ranged.cpp b/src/ranged.cpp index 0c8292575c86..9b9a4ac8300c 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -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 @@ -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 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 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( 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( damage ) ); if( thrown.has_flag( flag_ACT_ON_RANGED_HIT ) ) { proj.add_effect( ammo_effect_ACT_ON_RANGED_HIT ); diff --git a/tests/throwing_test.cpp b/tests/throwing_test.cpp index 6287b874cdcb..848ac27ab3c2 100644 --- a/tests/throwing_test.cpp +++ b/tests/throwing_test.cpp @@ -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 } ); @@ -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 } ); } } @@ -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 } ); } }