diff --git a/doc/MAGIC.md b/doc/MAGIC.md index e7486a851b94c..06ca89ec98476 100644 --- a/doc/MAGIC.md +++ b/doc/MAGIC.md @@ -878,6 +878,7 @@ Character status value | Description `POWER_TRICKLE` | Generates this amount of millijoules each second. Default value is zero, so better to use `add` `RANGE` | Modifies your characters range with firearms `RANGED_DAMAGE` | Adds damage to ranged attacks. +`RANGE_DODGE` | Chance to dodge projectile attack, no matter of it's speed; Consumes dodges similarly to melee dodges, and fails, if character has no dodges left. `add` and `multiply` behave equally. `add: 0.5` would result in 50% chance to avoid projectile `READING_EXP` | Changes the minimum you learn from each reading increment. `READING_SPEED_MULTIPLIER` | Changes how fast you can read books; Lesser value means faster book reading, with cap of 1 second. `RECOIL_MODIFIER` | Affects recoil when shooting a gun. Positive value increase the dispersion, negative decrease one. diff --git a/src/creature.cpp b/src/creature.cpp index 440b023756b80..cfdcc1770c099 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -1203,6 +1203,25 @@ void Creature::messaging_projectile_attack( const Creature *source, } } +void Creature::print_proj_avoid_msg( Creature *source, viewer &player_view ) const +{ + // "Avoid" rather than "dodge", because it includes removing self from the line of fire + // rather than just Matrix-style bullet dodging + if( source != nullptr && player_view.sees( *source ) ) { + add_msg_player_or_npc( + m_warning, + _( "You avoid %s projectile!" ), + get_option( "LOG_MONSTER_ATTACK_MONSTER" ) ? _( " avoids %s projectile." ) : "", + source->disp_name( true ) ); + } else { + add_msg_player_or_npc( + m_warning, + _( "You avoid an incoming projectile!" ), + get_option( "LOG_MONSTER_ATTACK_MONSTER" ) ? _( " avoids an incoming projectile." ) : + "" ); + } +} + /** * Attempts to harm a creature with a projectile. * @@ -1243,26 +1262,23 @@ void Creature::deal_projectile_attack( Creature *source, dealt_projectile_attack on_try_dodge(); // There's a dodge roll in accuracy_projectile_attack() } + Character *guy = as_character(); + if( guy ) { + double range_dodge_chance = guy->enchantment_cache->modify_value( enchant_vals::mod::RANGE_DODGE, + 1.0f ) - 1.0f; + if( x_in_y( range_dodge_chance, 1.0f ) ) { + on_try_dodge(); + print_proj_avoid_msg( source, player_view ); + return; + } + } + if( goodhit >= 1.0 && !magic ) { attack.missed_by = 1.0; // Arbitrary value if( !print_messages ) { return; } - // "Avoid" rather than "dodge", because it includes removing self from the line of fire - // rather than just Matrix-style bullet dodging - if( source != nullptr && player_view.sees( *source ) ) { - add_msg_player_or_npc( - m_warning, - _( "You avoid %s projectile!" ), - get_option( "LOG_MONSTER_ATTACK_MONSTER" ) ? _( " avoids %s projectile." ) : "", - source->disp_name( true ) ); - } else { - add_msg_player_or_npc( - m_warning, - _( "You avoid an incoming projectile!" ), - get_option( "LOG_MONSTER_ATTACK_MONSTER" ) ? _( " avoids an incoming projectile." ) : - "" ); - } + print_proj_avoid_msg( source, player_view ); return; } diff --git a/src/creature.h b/src/creature.h index de1f3678db319..13d89c261cb95 100644 --- a/src/creature.h +++ b/src/creature.h @@ -1343,6 +1343,7 @@ class Creature : public viewer // do messaging and SCT for projectile hit void messaging_projectile_attack( const Creature *source, const projectile_attack_results &hit_selection, int total_damage ) const; + void print_proj_avoid_msg( Creature *source, viewer &player_view ) const; }; std::unique_ptr get_talker_for( Creature &me ); std::unique_ptr get_talker_for( const Creature &me ); diff --git a/src/magic_enchantment.cpp b/src/magic_enchantment.cpp index 5baf8e186c28f..0b13714a8279a 100644 --- a/src/magic_enchantment.cpp +++ b/src/magic_enchantment.cpp @@ -76,6 +76,7 @@ namespace io case enchant_vals::mod::REGEN_HP: return "REGEN_HP"; case enchant_vals::mod::REGEN_HP_AWAKE: return "REGEN_HP_AWAKE"; case enchant_vals::mod::MUT_INSTABILITY_MOD: return "MUT_INSTABILITY_MOD"; + case enchant_vals::mod::RANGE_DODGE: return "RANGE_DODGE"; case enchant_vals::mod::HUNGER: return "HUNGER"; case enchant_vals::mod::THIRST: return "THIRST"; case enchant_vals::mod::SLEEPINESS: return "SLEEPINESS"; diff --git a/src/magic_enchantment.h b/src/magic_enchantment.h index bf6bd747e3dda..a9cb95f5d88af 100644 --- a/src/magic_enchantment.h +++ b/src/magic_enchantment.h @@ -49,6 +49,7 @@ enum class mod : int { FAT_TO_MAX_HP, CARDIO_MULTIPLIER, MUT_INSTABILITY_MOD, + RANGE_DODGE, MAX_HP, // for all limbs! use with caution REGEN_HP, REGEN_HP_AWAKE,