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
|
/*
* Researching what seem to be generally agreed on values
* for bow power required for guaranteed game kills, these are some breakpoints.
* While many source use KE values, there is a broad consensus that momentum is related to damage.
* FPS ft-lbs slug-ft-s Game
* 136 19.01 0.28 Turkeys
* 153 24 0.315 Whitetails at close range
* 195 39 0.401 Whitetails
* 249 63.73 0.512 Elk
* 278 79.44 0.572 Moose
*
* The concept is to bracket these threshods with various bows using standard hunting loadouts.
*/
#include <iosfwd>
#include <memory>
#include <set>
#include <string>
#include "cata_catch.h"
#include "damage.h"
#include "game_constants.h"
#include "item.h"
#include "itype.h"
#include "map.h"
#include "mapdata.h"
#include "monster.h"
#include "point.h"
#include "projectile.h"
#include "type_id.h"
#include "value_ptr.h"
// In short, a bow should never destroy a wall, pretty simple.
static void test_projectile_hitting_wall( const std::string &target_type, bool smashable,
dealt_projectile_attack &attack, const std::string &weapon_type )
{
static const tripoint target_point{ 5, 5, 0 };
map &here = get_map();
for( int i = 0; i < 10; ++i ) {
projectile projectile_copy = attack.proj;
here.set( target_point, ter_id( target_type ), furn_id( "f_null" ) );
CAPTURE( projectile_copy.impact.total_damage() );
here.shoot( target_point, projectile_copy, false );
CAPTURE( target_type );
CAPTURE( weapon_type );
CAPTURE( ter_id( target_type ).obj().name() );
CAPTURE( here.ter( target_point ).obj().name() );
if( smashable ) {
CHECK( here.ter( target_point ) != ter_id( target_type ) );
} else {
CHECK( here.ter( target_point ) == ter_id( target_type ) );
}
}
}
static void test_projectile_attack( const std::string &target_type, bool killable,
dealt_projectile_attack &attack, const std::string &weapon_type )
{
for( int i = 0; i < 10; ++i ) {
monster target{ mtype_id( target_type ), tripoint_zero };
target.deal_projectile_attack( nullptr, attack, false );
CAPTURE( target_type );
CAPTURE( target.get_hp() );
CAPTURE( target.get_hp_max() );
CAPTURE( attack.proj.impact.total_damage() );
CAPTURE( weapon_type );
CHECK( target.is_dead() == killable );
}
}
static void test_archery_balance( const std::string &weapon_type, const std::string &ammo_type,
const std::string &killable, const std::string &unkillable )
{
item weapon( weapon_type );
// The standard modern hunting arrow, make this a parameter if we extend to crossbows.
weapon.ammo_set( itype_id( ammo_type ), 1 );
projectile test_projectile;
test_projectile.speed = 1000;
test_projectile.impact = weapon.gun_damage();
test_projectile.proj_effects = weapon.ammo_effects();
test_projectile.critical_multiplier = weapon.ammo_data()->ammo->critical_multiplier;
dealt_projectile_attack attack {
test_projectile, nullptr, dealt_damage_instance(), tripoint_zero, accuracy_critical - 0.05
};
if( !killable.empty() ) {
test_projectile_attack( killable, true, attack, weapon_type );
}
if( !unkillable.empty() ) {
test_projectile_attack( unkillable, false, attack, weapon_type );
}
test_projectile_hitting_wall( "t_wall", false, attack, weapon_type );
// Use "can't kill anything" as an indication that it can't break a window either.
if( !killable.empty() ) {
test_projectile_hitting_wall( "t_window", true, attack, weapon_type );
}
}
TEST_CASE( "archery_damage_thresholds", "[balance],[archery]" )
{
// Selfbow can't kill a turkey
test_archery_balance( "selfbow", "arrow_metal", "", "mon_turkey" );
test_archery_balance( "rep_crossbow", "bolt_steel", "", "mon_turkey" );
// Shortbow can kill turkeys, but not deer
test_archery_balance( "shortbow", "arrow_metal", "mon_turkey", "mon_deer" );
test_archery_balance( "hand_crossbow", "bolt_steel", "mon_turkey", "mon_deer" );
// Fiberglass recurve can kill deer, but not bear
test_archery_balance( "recurbow", "arrow_metal", "mon_deer", "mon_bear" );
test_archery_balance( "compositecrossbow", "bolt_steel", "mon_deer", "mon_bear" );
// Medium setting compound bow can kill Bear
test_archery_balance( "compbow", "arrow_metal", "mon_bear", "" );
// High setting modern compund bow can kill Moose
test_archery_balance( "compcrossbow", "bolt_steel", "mon_moose", "" );
test_archery_balance( "compbow_high", "arrow_metal", "mon_moose", "" );
}
|