From da07b2aa8c97b9a2fd2737afcfdab9f6f549de49 Mon Sep 17 00:00:00 2001 From: osuphobia <78858975+osuphobia@users.noreply.github.com> Date: Sun, 28 Apr 2024 06:06:06 +0800 Subject: [PATCH] Bow reload time fix (#73305) * Fix RAS weapon reload time and stamina drain. * fix typo * clang-tidy --- src/activity_actor.cpp | 59 +++++----------- src/activity_actor_definitions.h | 3 +- src/character.h | 2 +- src/npcmove.cpp | 2 +- src/ranged.cpp | 111 ++++++++++++++++++++++++++----- src/turret.cpp | 2 +- tests/eoc_test.cpp | 4 +- tests/ranged_balance_test.cpp | 2 +- tests/reload_time_test.cpp | 36 ++++++---- 9 files changed, 140 insertions(+), 81 deletions(-) diff --git a/src/activity_actor.cpp b/src/activity_actor.cpp index 284f1d1ac9a01..e2a2c3b4ce5e3 100644 --- a/src/activity_actor.cpp +++ b/src/activity_actor.cpp @@ -332,11 +332,12 @@ void aim_activity_actor::do_turn( player_activity &act, Character &who ) gun_mode gun = weapon->gun_current_mode(); // We need to make sure RAS weapon is loaded/reloaded in case the aim activity was temp. suspended // therefore the order of evaluation matters here - if( gun->has_flag( flag_RELOAD_AND_SHOOT ) && !gun->ammo_remaining() && !load_RAS_weapon() && - first_turn ) { - aborted = true; - act.moves_left = 0; - return; + if( gun->has_flag( flag_RELOAD_AND_SHOOT ) && !gun->ammo_remaining() && !reload_loc ) { + if( !load_RAS_weapon() ) { + aborted = true; + act.moves_left = 0; + return; + } } if( gun->has_flag( json_flag_ALWAYS_AIMED ) ) { @@ -354,10 +355,6 @@ void aim_activity_actor::do_turn( player_activity &act, Character &who ) fin_trajectory = trajectory; act.moves_left = 0; } - // If aborting on the first turn, keep 'first_turn' as 'true'. - // This allows refunding moves spent on unloading RELOAD_AND_SHOOT weapons - // to simulate avatar not loading them in the first place - first_turn = false; // Allow interrupting activity only during 'aim and fire'. // Prevents '.' key for 'aim for 10 turns' from conflicting with '.' key for 'interrupt activity' @@ -387,14 +384,7 @@ void aim_activity_actor::finish( player_activity &act, Character &who ) } gun_mode gun = weapon->gun_current_mode(); - who.fire_gun( fin_trajectory.back(), gun.qty, *gun ); - - if( weapon && weapon->gun_current_mode()->has_flag( flag_RELOAD_AND_SHOOT ) ) { - // RAS weapons are currently bugged, this is a workaround so bug impact - // isn't amplified, once #54997 and #50571 are fixed this can be removed. - restore_view(); - return; - } + who.fire_gun( fin_trajectory.back(), gun.qty, *gun, reload_loc ); if( !get_option( "AIM_AFTER_FIRING" ) ) { restore_view(); @@ -427,12 +417,12 @@ void aim_activity_actor::serialize( JsonOut &jsout ) const jsout.member( "fake_weapon", fake_weapon ); jsout.member( "fin_trajectory", fin_trajectory ); - jsout.member( "first_turn", first_turn ); jsout.member( "action", action ); jsout.member( "aif_duration", aif_duration ); jsout.member( "aiming_at_critter", aiming_at_critter ); jsout.member( "snap_to_target", snap_to_target ); jsout.member( "loaded_RAS_weapon", loaded_RAS_weapon ); + jsout.member( "reload_loc", reload_loc ); jsout.member( "shifting_view", shifting_view ); jsout.member( "initial_view_offset", initial_view_offset ); jsout.member( "aborted", aborted ); @@ -450,12 +440,12 @@ std::unique_ptr aim_activity_actor::deserialize( JsonValue &jsin data.read( "fake_weapon", actor.fake_weapon ); data.read( "fin_trajectory", actor.fin_trajectory ); - data.read( "first_turn", actor.first_turn ); data.read( "action", actor.action ); data.read( "aif_duration", actor.aif_duration ); data.read( "aiming_at_critter", actor.aiming_at_critter ); data.read( "snap_to_target", actor.snap_to_target ); data.read( "loaded_RAS_weapon", actor.loaded_RAS_weapon ); + data.read( "reload_loc", actor.reload_loc ); data.read( "shifting_view", actor.shifting_view ); data.read( "initial_view_offset", actor.initial_view_offset ); data.read( "aborted", actor.aborted ); @@ -518,48 +508,33 @@ bool aim_activity_actor::load_RAS_weapon() // Menu canceled return false; } - int reload_time = 0; - reload_time += opt.moves(); - if( !gun->reload( you, std::move( opt.ammo ), 1 ) ) { - // Reload not allowed - return false; - } // Burn 0.6% max base stamina without cardio/BMI factored in x the strength required to fire. - you.burn_energy_arms( gun->get_min_str() * static_cast( 0.006f * + // Stamina cost of RAS weapon is also calculated in ranged.cpp mod_stamina_archery, need to + // confirm if this formula should be removed. + you.burn_energy_arms( - gun->get_min_str() * static_cast( 0.006f * get_option( "PLAYER_MAX_STAMINA_BASE" ) ) ); - // At low stamina levels, firing starts getting slow. - int sta_percent = ( 100 * you.get_stamina() ) / you.get_stamina_max(); - reload_time += ( sta_percent < 25 ) ? ( ( 25 - sta_percent ) * 2 ) : 0; - you.mod_moves( -reload_time ); + reload_loc = opt.ammo; loaded_RAS_weapon = true; return true; } void aim_activity_actor::unload_RAS_weapon() { - // Unload reload-and-shoot weapons to avoid leaving bows pre-loaded with arrows avatar &you = get_avatar(); item_location weapon = get_weapon(); if( !weapon || !loaded_RAS_weapon ) { return; } + // Refund stamina cost. gun_mode gun = weapon->gun_current_mode(); if( gun->has_flag( flag_RELOAD_AND_SHOOT ) ) { - int moves_before_unload = you.get_moves(); - - // Note: this code works only for avatar - item_location loc = item_location( you, gun.target ); - you.unload( loc, true ); - - // Give back time for unloading as essentially nothing has been done. - if( first_turn ) { - you.set_moves( moves_before_unload ); - } + you.burn_energy_arms( gun->get_min_str() * static_cast( 0.006f * + get_option( "PLAYER_MAX_STAMINA_BASE" ) ) ); + loaded_RAS_weapon = false; } - loaded_RAS_weapon = false; } void autodrive_activity_actor::update_player_vehicle( Character &who ) diff --git a/src/activity_actor_definitions.h b/src/activity_actor_definitions.h index b0b4dcf0b7fcb..a7c933be52cdf 100644 --- a/src/activity_actor_definitions.h +++ b/src/activity_actor_definitions.h @@ -48,13 +48,14 @@ class aim_activity_actor : public activity_actor std::vector fin_trajectory; public: - bool first_turn = true; std::string action; int aif_duration = 0; // Counts aim-and-fire duration bool aiming_at_critter = false; // Whether aiming at critter or a tile bool snap_to_target = false; /** Not to try to unload RELOAD_AND_SHOOT weapon if it is not loaded */ bool loaded_RAS_weapon = false; + /* Item location for RAS weapon reload */ + item_location reload_loc = item_location(); bool shifting_view = false; tripoint initial_view_offset; /** Target UI requested to abort aiming */ diff --git a/src/character.h b/src/character.h index 648f71dda523e..304fb1a349327 100644 --- a/src/character.h +++ b/src/character.h @@ -3129,7 +3129,7 @@ class Character : public Creature, public visitable * @param gun item to fire (which does not necessary have to be in the players possession) * @return number of shots actually fired */ - int fire_gun( const tripoint &target, int shots, item &gun ); + int fire_gun( const tripoint &target, int shots, item &gun, item_location ammo = item_location() ); /** Execute a throw */ dealt_projectile_attack throw_item( const tripoint &target, const item &to_throw, const std::optional &blind_throw_from_pos = std::nullopt ); diff --git a/src/npcmove.cpp b/src/npcmove.cpp index 381f4bc999253..1de7c8cb454d9 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -1730,7 +1730,7 @@ void npc::execute_action( npc_action action ) if( is_hallucination() ) { pretend_fire( this, mode.qty, *mode ); } else { - fire_gun( tar, mode.qty, *mode ); + fire_gun( tar, mode.qty, *mode, item_location() ); // "discard" the fake bio weapon after shooting it if( is_using_bionic_weapon() ) { discharge_cbm_weapon(); diff --git a/src/ranged.cpp b/src/ranged.cpp index 5606a15c808e3..0a339a14cb413 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -155,7 +155,8 @@ static const std::set ferric = { material_iron, material_steel, mat static constexpr int AIF_DURATION_LIMIT = 10; static projectile make_gun_projectile( const item &gun ); -static int time_to_attack( const Character &p, const itype &firing ); +static int NPC_time_to_attack( const Character &p, const itype &firing ); +static int time_to_attack( const Character &p, const item &firing, const item_location &loc ); /** * Handle spent ammo casings and linkages. * @param weap Weapon. @@ -368,6 +369,9 @@ class target_ui // Relevant for TargetMode::Fire void apply_aim_turning_penalty() const; + // Update range & ammo from current gun mode + void update_ammo_range_from_gun_mode(); + // Switch firing mode. bool action_switch_mode(); @@ -861,10 +865,10 @@ int Character::fire_gun( const tripoint &target, int shots ) debugmsg( "%s doesn't have a gun to fire", get_name() ); return 0; } - return fire_gun( target, shots, *gun ); + return fire_gun( target, shots, *gun, item_location() ); } -int Character::fire_gun( const tripoint &target, int shots, item &gun ) +int Character::fire_gun( const tripoint &target, int shots, item &gun, item_location ammo ) { if( !gun.is_gun() ) { debugmsg( "%s tried to fire non-gun (%s).", get_name(), gun.tname() ); @@ -874,6 +878,10 @@ int Character::fire_gun( const tripoint &target, int shots, item &gun ) add_msg_if_player( _( "A shotgun equipped with choke cannot fire slugs." ) ); return 0; } + if( gun.ammo_required() > 0 && !gun.ammo_remaining() && !ammo ) { + debugmsg( "%s's gun %s is empty and has no ammo for reloading.", gun.tname() ); + return 0; + } bool is_mech_weapon = false; if( is_mounted() && mounted_creature->has_flag( mon_flag_RIDEABLE_MECH ) ) { @@ -881,15 +889,17 @@ int Character::fire_gun( const tripoint &target, int shots, item &gun ) } // cap our maximum burst size by ammo and energy - if( !gun.has_flag( flag_VEHICLE ) ) { + if( !gun.has_flag( flag_VEHICLE ) && !ammo ) { shots = std::min( shots, gun.shots_remaining( this ) ); } else if( gun.ammo_required() ) { // This checks ammo only. Vehicle turret energy drain is handled elsewhere. - shots = std::min( shots, static_cast( gun.ammo_remaining() / gun.ammo_required() ) ); + const int ammo_left = ammo ? ammo.get_item()->count() : gun.ammo_remaining(); + shots = std::min( shots, ammo_left / gun.ammo_required() ); } if( shots <= 0 ) { debugmsg( "Attempted to fire zero or negative shots using %s", gun.tname() ); + return 0; } map &here = get_map(); @@ -910,6 +920,7 @@ int Character::fire_gun( const tripoint &target, int shots, item &gun ) static_cast( MAX_SKILL ) ) / static_cast( MAX_SKILL * 2 ); itype_id gun_id = gun.typeId(); + int attack_moves = time_to_attack( *this, gun, ammo ); skill_id gun_skill = gun.gun_skill(); add_msg_debug( debugmode::DF_RANGED, "Gun skill (%s) %g", gun_skill.c_str(), get_skill_level( gun_skill ) ) ; @@ -918,6 +929,9 @@ int Character::fire_gun( const tripoint &target, int shots, item &gun ) int hits = 0; // total shots on target int delay = 0; // delayed recoil that has yet to be applied while( curshot != shots ) { + if( !!ammo && !gun.ammo_remaining() ) { + gun.reload( get_avatar(), ammo, 1 ); + } if( gun.faults.count( fault_gun_chamber_spent ) && curshot == 0 ) { mod_moves( -get_speed() * 0.5 ); gun.faults.erase( fault_gun_chamber_spent ); @@ -1054,7 +1068,7 @@ int Character::fire_gun( const tripoint &target, int shots, item &gun ) } } // Use different amounts of time depending on the type of gun and our skill - mod_moves( -time_to_attack( *this, *gun_id ) ); + mod_moves( -attack_moves ); const islot_gun &firing = *gun.type->gun; for( const std::pair &hurt_part : firing.hurt_part_when_fired ) { @@ -1690,7 +1704,7 @@ static std::vector calculate_ranged_chances( const target_ui &ui, const Character &you, target_ui::TargetMode mode, const input_context &ctxt, const item &weapon, const dispersion_sources &dispersion, const std::vector &confidence_ratings, - const Target_attributes &target, const tripoint &pos ) + const Target_attributes &target, const tripoint &pos, const item_location &load_loc ) { std::vector aim_types { get_default_aim_type() }; std::vector aim_outputs; @@ -1721,7 +1735,8 @@ static std::vector calculate_ranged_chances( prediction.moves = throw_moves; } else { prediction.moves = predict_recoil( you, weapon, target, ui.get_sight_dispersion(), aim_type, - you.recoil ).moves + time_to_attack( you, *weapon.type ); + you.recoil ).moves + time_to_attack( you, weapon, + load_loc ); } // if the default method is "behind" the selected; e.g. you are in immediate @@ -1936,7 +1951,8 @@ static bool pl_sees( const Creature &cr ) } static int print_aim( const target_ui &ui, Character &you, const catacurses::window &w, - int line_number, input_context &ctxt, const item &weapon, const tripoint &pos ) + int line_number, input_context &ctxt, const item &weapon, const tripoint &pos, + item_location &load_loc ) { // This is absolute accuracy for the player. // TODO: push the calculations duplicated from Creature::deal_projectile_attack() and @@ -1956,7 +1972,7 @@ static int print_aim( const target_ui &ui, Character &you, const catacurses::win const std::vector aim_chances = calculate_ranged_chances( ui, you, target_ui::TargetMode::Fire, ctxt, weapon, dispersion, confidence_config, - Target_attributes( you.pos(), pos ), pos ); + Target_attributes( you.pos(), pos ), pos, load_loc ); return print_ranged_chance( w, line_number, aim_chances ); } @@ -1995,7 +2011,8 @@ static void draw_throw_aim( const target_ui &ui, const Character &you, const cat you.sees( target_pos ) ); const std::vector aim_chances = calculate_ranged_chances( ui, you, - throwing_target_mode, ctxt, weapon, dispersion, confidence_config, attributes, target_pos ); + throwing_target_mode, ctxt, weapon, dispersion, confidence_config, attributes, target_pos, + item_location() ); text_y = print_ranged_chance( w, text_y, aim_chances ); } @@ -2097,7 +2114,7 @@ static projectile make_gun_projectile( const item &gun ) return proj; } -int time_to_attack( const Character &p, const itype &firing ) +int NPC_time_to_attack( const Character &p, const itype &firing ) { const skill_id &skill_used = firing.gun->skill_used; const time_info_t &info = skill_used->time_to_attack(); @@ -2106,6 +2123,26 @@ int time_to_attack( const Character &p, const itype &firing ) skill_used ) ) ) ); } +int time_to_attack( const Character &p, const item &firing, const item_location &loc ) +{ + const skill_id &skill_used = firing.type->gun->skill_used; + const time_info_t &info = skill_used->time_to_attack(); + int RAS_time = 0; + if( !loc ) { + RAS_time = 0; + } else { + // At low stamina levels, firing starts getting slow. + const item_location gun = p.get_wielded_item(); + int sta_percent = ( 100 * p.get_stamina() ) / p.get_stamina_max(); + RAS_time += ( sta_percent < 25 ) ? ( ( 25 - sta_percent ) * 2 ) : 0; + item::reload_option opt = item::reload_option( &p, gun, loc ); + RAS_time += opt.moves(); + } + return std::max( info.min_time, + static_cast( round( info.base_time - info.time_reduction_per_level * p.get_skill_level( + skill_used ) ) ) + RAS_time ); +} + static void cycle_action( item &weap, const itype_id &ammo, const tripoint &pos ) { map &here = get_map(); @@ -2375,7 +2412,7 @@ double Character::gun_value( const item &weap, int ammo ) const damage_factor += 0.5f * gun_damage.damage_units.front().res_pen; } - int move_cost = time_to_attack( *this, *weap.type ); + int move_cost = NPC_time_to_attack( *this, *weap.type ); if( gun.clip != 0 && gun.clip < 10 ) { // TODO: RELOAD_ONE should get a penalty here int reload_cost = gun.reload_time + encumb( bodypart_id( "hand_l" ) ) + encumb( @@ -2459,6 +2496,7 @@ target_handler::trajectory target_ui::run() you->add_msg_if_player( m_bad, _( "You don't have enough %s to cast this spell" ), casting->energy_string() ); } else if( mode == TargetMode::Fire ) { + update_ammo_range_from_gun_mode(); sight_dispersion = you->most_accurate_aiming_method_limit( *relevant ); } @@ -2498,7 +2536,7 @@ target_handler::trajectory target_ui::run() bool attack_was_confirmed = false; bool reentered = false; bool resume_critter = false; - if( mode == TargetMode::Fire && !activity->first_turn ) { + if( mode == TargetMode::Fire && !activity->action.empty() ) { // We were in this UI during previous turn... reentered = true; std::string act_data = activity->action; @@ -2552,7 +2590,7 @@ target_handler::trajectory target_ui::run() action.clear(); attack_was_confirmed = false; } - if( !activity->first_turn && !action.empty() && !prompt_friendlies_in_lof() ) { + if( !action.empty() && !prompt_friendlies_in_lof() ) { // A friendly creature moved into line of fire during aim-and-shoot, // and player decided to stop aiming action.clear(); @@ -3294,6 +3332,34 @@ void target_ui::apply_aim_turning_penalty() const you->recoil = predicted_recoil; } +void target_ui::update_ammo_range_from_gun_mode() +{ + if( mode == TargetMode::TurretManual ) { + itype_id ammo_current = turret->ammo_current(); + if( ammo_current.is_null() ) { + ammo = nullptr; + range = 0; + } else { + ammo = item::find_type( ammo_current ); + range = turret->range(); + } + } else { + if( relevant->gun_current_mode().melee() ) { + range = relevant->current_reach_range( *you ); + } else { + ammo = activity->reload_loc ? activity->reload_loc.get_item()->type : + relevant->gun_current_mode().target->ammo_data(); + if( activity->reload_loc ) { + item temp_weapon = *relevant; + temp_weapon.ammo_set( ammo->get_id() ); + range = temp_weapon.gun_current_mode().target->gun_range( you ); + } else { + range = relevant->gun_current_mode().target->gun_range( you ); + } + } + } +} + bool target_ui::action_switch_mode() { uilist menu; @@ -3382,8 +3448,15 @@ bool target_ui::action_switch_mode() refresh = true; range = relevant->current_reach_range( *you ); } else { - range = relevant->gun_current_mode().target->gun_range( you ); - ammo = relevant->gun_current_mode().target->ammo_data(); + ammo = activity->reload_loc ? activity->reload_loc.get_item()->type : + relevant->gun_current_mode().target->ammo_data(); + if( activity->reload_loc ) { + item temp_weapon = *relevant; + temp_weapon.ammo_set( ammo->get_id() ); + range = temp_weapon.gun_current_mode().target->gun_range( you ); + } else { + range = relevant->gun_current_mode().target->gun_range( you ); + } } } @@ -3579,7 +3652,9 @@ void target_ui::draw_ui_window() } else if( status == Status::Good ) { // TODO: these are old, consider refactoring if( mode == TargetMode::Fire ) { - text_y = print_aim( *this, *you, w_target, text_y, ctxt, *relevant->gun_current_mode(), dst ); + item_location load_loc = activity->reload_loc; + text_y = print_aim( *this, *you, w_target, text_y, ctxt, *relevant->gun_current_mode(), dst, + load_loc ); } else if( mode == TargetMode::Throw || mode == TargetMode::ThrowBlind ) { bool blind = mode == TargetMode::ThrowBlind; draw_throw_aim( *this, *you, w_target, text_y, ctxt, *relevant, dst, blind ); diff --git a/src/turret.cpp b/src/turret.cpp index e7fdbdcada106..bdd9431f3d128 100644 --- a/src/turret.cpp +++ b/src/turret.cpp @@ -317,7 +317,7 @@ int turret_data::fire( Character &c, const tripoint &target ) gun_mode mode = base()->gun_current_mode(); prepare_fire( c ); - shots = c.fire_gun( target, mode.qty, *mode ); + shots = c.fire_gun( target, mode.qty, *mode, item_location() ); post_fire( c, shots ); return shots; } diff --git a/tests/eoc_test.cpp b/tests/eoc_test.cpp index fce034c121eb5..012ab86d055de 100644 --- a/tests/eoc_test.cpp +++ b/tests/eoc_test.cpp @@ -1174,7 +1174,7 @@ TEST_CASE( "EOC_combat_event_test", "[eoc]" ) get_avatar().set_body(); arm_shooter( get_avatar(), "shotgun_s" ); get_avatar().recoil = 0; - get_avatar().fire_gun( target_pos, 1, *get_avatar().get_wielded_item() ); + get_avatar().fire_gun( target_pos, 1, *get_avatar().get_wielded_item(), item_location() ); if( !npc_dst_ranged.get_value( "npctalk_var_test_event_last_event" ).empty() ) { break; } @@ -1194,7 +1194,7 @@ TEST_CASE( "EOC_combat_event_test", "[eoc]" ) get_avatar().set_body(); arm_shooter( get_avatar(), "shotgun_s" ); get_avatar().recoil = 0; - get_avatar().fire_gun( mon_dst_ranged.pos(), 1, *get_avatar().get_wielded_item() ); + get_avatar().fire_gun( mon_dst_ranged.pos(), 1, *get_avatar().get_wielded_item(), item_location() ); if( !mon_dst_ranged.get_value( "npctalk_var_test_event_last_event" ).empty() ) { break; } diff --git a/tests/ranged_balance_test.cpp b/tests/ranged_balance_test.cpp index 6afc3f84ca172..70f40f02ea6b9 100644 --- a/tests/ranged_balance_test.cpp +++ b/tests/ranged_balance_test.cpp @@ -459,7 +459,7 @@ static void shoot_monster( const std::string &gun_type, const std::vectorrecoil = 0; monster &mon = spawn_test_monster( monster_type, monster_pos, false ); const int prev_HP = mon.get_hp(); - shooter->fire_gun( monster_pos, 1, *shooter->get_wielded_item() ); + shooter->fire_gun( monster_pos, 1, *shooter->get_wielded_item(), item_location() ); damage.add( prev_HP - mon.get_hp() ); if( damage.margin_of_error() < 0.05 && damage.n() > 100 ) { break; diff --git a/tests/reload_time_test.cpp b/tests/reload_time_test.cpp index 8284a7c584ac9..c115f0b526a89 100644 --- a/tests/reload_time_test.cpp +++ b/tests/reload_time_test.cpp @@ -3,18 +3,26 @@ #include "activity_actor_definitions.h" #include "avatar.h" #include "calendar.h" +#include "creature_tracker.h" +#include #include "item.h" #include "map.h" #include "player_helpers.h" #include "point.h" #include +#include "map_helpers.h" + +static const mtype_id pseudo_debug_mon( "pseudo_debug_mon" ); static void check_reload_time( const std::string &weapon, const std::string &ammo, const std::string &container, int expected_moves ) { const tripoint test_origin( 60, 60, 0 ); + const tripoint spot( 61, 60, 0 ); + clear_map(); avatar &shooter = get_avatar(); + g->place_critter_at( pseudo_debug_mon, spot ); shooter.setpos( test_origin ); shooter.set_wielded_item( item( weapon, calendar::turn_zero, 0 ) ); if( container.empty() ) { @@ -37,7 +45,7 @@ static void check_reload_time( const std::string &weapon, const std::string &amm CAPTURE( shooter.used_weapon()->get_reload_time() ); aim_activity_actor act = aim_activity_actor::use_wielded(); int moves_before = shooter.get_moves(); - REQUIRE( act.load_RAS_weapon() ); + REQUIRE( shooter.fire_gun( spot, 1, *shooter.used_weapon(), shooter.ammo_location ) ); int moves_after = shooter.get_moves(); int spent_moves = moves_before - moves_after; int expected_upper = expected_moves * 1.05; @@ -52,47 +60,47 @@ TEST_CASE( "reload_from_inventory_times", "[reload],[inventory],[balance]" ) clear_avatar(); SECTION( "reloading a slingshot" ) { SECTION( "from a backpack" ) { - check_reload_time( "slingshot", "pebble", "backpack", 350 ); + check_reload_time( "slingshot", "pebble", "backpack", 400 ); } SECTION( "from an ammo pouch" ) { - check_reload_time( "slingshot", "pebble", "ammo_pouch", 87 ); + check_reload_time( "slingshot", "pebble", "ammo_pouch", 137 ); } SECTION( "from a tool belt" ) { - check_reload_time( "slingshot", "pebble", "tool_belt", 150 ); + check_reload_time( "slingshot", "pebble", "tool_belt", 200 ); } SECTION( "from a pocket" ) { - check_reload_time( "slingshot", "pebble", "pants", 150 ); + check_reload_time( "slingshot", "pebble", "pants", 200 ); } SECTION( "from the ground" ) { - check_reload_time( "slingshot", "pebble", "", 130 ); + check_reload_time( "slingshot", "pebble", "", 180 ); } } SECTION( "reloading a staff sling" ) { SECTION( "from a backpack" ) { - check_reload_time( "staff_sling", "rock", "backpack", 375 ); + check_reload_time( "staff_sling", "rock", "backpack", 595 ); } SECTION( "from a stone pouch" ) { - check_reload_time( "staff_sling", "rock", "stone_pouch", 95 ); + check_reload_time( "staff_sling", "rock", "stone_pouch", 315 ); } SECTION( "from a tool belt" ) { - check_reload_time( "staff_sling", "rock", "tool_belt", 160 ); + check_reload_time( "staff_sling", "rock", "tool_belt", 380 ); } SECTION( "from a pocket" ) { - check_reload_time( "staff_sling", "rock", "pants", 175 ); + check_reload_time( "staff_sling", "rock", "pants", 395 ); } SECTION( "from the ground" ) { - check_reload_time( "staff_sling", "rock", "", 150 ); + check_reload_time( "staff_sling", "rock", "", 370 ); } } SECTION( "reloading a bow" ) { SECTION( "from a duffel bag" ) { - check_reload_time( "longbow", "arrow_wood", "long_duffelbag", 360 ); + check_reload_time( "longbow", "arrow_wood", "long_duffelbag", 410 ); } SECTION( "from a quiver" ) { - check_reload_time( "longbow", "arrow_wood", "quiver", 80 ); + check_reload_time( "longbow", "arrow_wood", "quiver", 130 ); } SECTION( "from the ground" ) { - check_reload_time( "longbow", "arrow_wood", "", 140 ); + check_reload_time( "longbow", "arrow_wood", "", 190 ); } } }