Skip to content

Commit

Permalink
Bow reload time fix (CleverRaven#73305)
Browse files Browse the repository at this point in the history
* Fix RAS weapon reload time and stamina drain.

* fix typo

* clang-tidy
  • Loading branch information
osuphobia authored Apr 27, 2024
1 parent d45a4b3 commit da07b2a
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 81 deletions.
59 changes: 17 additions & 42 deletions src/activity_actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) ) {
Expand All @@ -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'
Expand Down Expand Up @@ -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<bool>( "AIM_AFTER_FIRING" ) ) {
restore_view();
Expand Down Expand Up @@ -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 );
Expand All @@ -450,12 +440,12 @@ std::unique_ptr<activity_actor> 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 );
Expand Down Expand Up @@ -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<int>( 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<int>( 0.006f *
get_option<int>( "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<int>( 0.006f *
get_option<int>( "PLAYER_MAX_STAMINA_BASE" ) ) );
loaded_RAS_weapon = false;
}
loaded_RAS_weapon = false;
}

void autodrive_activity_actor::update_player_vehicle( Character &who )
Expand Down
3 changes: 2 additions & 1 deletion src/activity_actor_definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,14 @@ class aim_activity_actor : public activity_actor
std::vector<tripoint> 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 */
Expand Down
2 changes: 1 addition & 1 deletion src/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<tripoint> &blind_throw_from_pos = std::nullopt );
Expand Down
2 changes: 1 addition & 1 deletion src/npcmove.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Loading

0 comments on commit da07b2a

Please sign in to comment.