diff --git a/data/json/skills.json b/data/json/skills.json index f5d27e437ec6..8aabc2d44376 100644 --- a/data/json/skills.json +++ b/data/json/skills.json @@ -269,7 +269,7 @@ "type": "skill", "id": "unarmed", "name": { "str": "unarmed combat" }, - "description": "Your skill in hand-to-hand fighting. For the unskilled, it's a good way to get hurt, but those with enough practice can perform special blows and techniques to quickly dispatch enemies.", + "description": "Your skill in hand-to-hand fighting, with unarmed weapons or empty-handed. Skill increases attack accuracy and unlocks techniques in many martial arts, while also providing a bonus to bare-handed damage.", "tags": [ "combat_skill", "weapon_skill" ], "companion_combat_rank_factor": 1, "companion_survival_rank_factor": 1, diff --git a/src/character_display.cpp b/src/character_display.cpp index 1daa346ae8e6..e0cf450ddbc4 100644 --- a/src/character_display.cpp +++ b/src/character_display.cpp @@ -36,6 +36,7 @@ #include "weather.h" static const skill_id skill_swimming( "swimming" ); +static const skill_id skill_unarmed( "unarmed" ); static const std::string title_STATS = translate_marker( "STATS" ); static const std::string title_ENCUMB = translate_marker( "ENCUMBRANCE AND WARMTH" ); @@ -45,6 +46,9 @@ static const std::string title_SKILLS = translate_marker( "SKILLS" ); static const std::string title_BIONICS = translate_marker( "BIONICS" ); static const std::string title_TRAITS = translate_marker( "TRAITS" ); +static const trait_flag_str_id trait_flag_NEED_ACTIVE_TO_MELEE( "NEED_ACTIVE_TO_MELEE" ); +static const trait_flag_str_id trait_flag_UNARMED_BONUS( "UNARMED_BONUS" ); + // use this instead of having to type out 26 spaces like before static const std::string header_spaces( 26, ' ' ); @@ -642,6 +646,57 @@ struct HeaderSkill { } }; +int character_display::display_empty_handed_base_damage( const Character &you ) +{ + int empty_hand_base_damage = you.get_skill_level( skill_unarmed ) * 2; + const bool left_empty = !you.natural_attack_restricted_on( bodypart_id( "hand_l" ) ); + const bool right_empty = !you.natural_attack_restricted_on( bodypart_id( "hand_r" ) ); + + if( !left_empty && !right_empty ) { + // Mutation and bionic bonuses don't matter so just print unarmed bonus + return empty_hand_base_damage; + } else { + + // Mutation and bionic bonuses double if both hands are free + int per_hand = 0; + if( you.has_bionic( bionic_id( "bio_razors" ) ) ) { + per_hand += 4; + } + for( const trait_id &mut : you.get_mutations() ) { + if( mut->flags.count( trait_flag_NEED_ACTIVE_TO_MELEE ) > 0 && + !you.has_active_mutation( mut ) ) { + continue; + } + // Fixed bonuses are nice and simple + per_hand += mut->bash_dmg_bonus + mut->cut_dmg_bonus + mut->pierce_dmg_bonus; + + // Random bonuses are more fiddly, since we want baseline numbers let's just report the minimum + const std::pair rand_bash = mut->rand_bash_bonus; + const std::pair rand_cut = mut->rand_cut_bonus; + per_hand += rand_bash.first + rand_cut.first; + + // Extra skill bonus is also fairly simple, but each type of fixed bonus can trigger it separately + if( mut->flags.count( trait_flag_UNARMED_BONUS ) > 0 ) { + if( mut->bash_dmg_bonus > 0 ) { + per_hand += std::min( you.get_skill_level( skill_unarmed ) / 2, 4 ); + } + if( mut->cut_dmg_bonus > 0 ) { + per_hand += std::min( you.get_skill_level( skill_unarmed ) / 2, 4 ); + } + if( mut->pierce_dmg_bonus > 0 ) { + per_hand += std::min( you.get_skill_level( skill_unarmed ) / 2, 4 ); + } + } + } + empty_hand_base_damage += per_hand; // First hand + if( left_empty && right_empty ) { + // Second hand + empty_hand_base_damage += per_hand; + } + return empty_hand_base_damage; + } +} + static void draw_skills_tab( const catacurses::window &w_skills, Character &you, unsigned int line, const player_display_tab curtab, std::vector &skillslist, @@ -723,6 +778,11 @@ static void draw_skills_tab( const catacurses::window &w_skills, if( aSkill->ident() == skill_id( "dodge" ) ) { mvwprintz( w_skills, point( 14, y_pos ), cstatus, "%4.1f/%-2d(%2d%%)", you.get_dodge(), level_num, exercise < 0 ? 0 : exercise ); + } + if( aSkill->ident() == skill_id( "unarmed" ) ) { + mvwprintz( w_skills, point( 15, y_pos ), cstatus, "%3d/%-2d(%2d%%)", + character_display::display_empty_handed_base_damage( you ), level_num, + exercise < 0 ? 0 : exercise ); } else { mvwprintz( w_skills, point( 19, y_pos ), cstatus, "%-2d(%2d%%)", level_num, diff --git a/src/character_display.h b/src/character_display.h index 021a7063d676..3d45dadb7335 100644 --- a/src/character_display.h +++ b/src/character_display.h @@ -35,6 +35,10 @@ void disp_info( Character &ch ); */ void upgrade_stat_prompt( avatar &you, const character_stat &stat ); +/** Gets the minimum combined bare-handed damage from skill, bionics, and mutations for display functions */ +int display_empty_handed_base_damage( const Character &you ); + } // namespace character_display + #endif // CATA_SRC_CHARACTER_DISPLAY_H diff --git a/src/player.cpp b/src/player.cpp index 414fe83ab35c..12b14cb9fa7a 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -18,6 +18,7 @@ #include "bionics.h" #include "cata_utility.h" #include "catacharset.h" +#include "character_display.h" #include "character_functions.h" #include "character_effects.h" #include "character_martial_arts.h" @@ -222,8 +223,11 @@ bool character_martial_arts::pick_style( const avatar &you ) // Style selecti "\n" "STR: %d, DEX: %d, " "PER: %d, INT: %d\n" + "Base empty-handed damage: %3d\n" + "Effective dodge rating: %4.1f\n" "Press [%s] for more info.\n" ), you.get_str(), you.get_dex(), you.get_per(), you.get_int(), + character_display::display_empty_handed_base_damage( you ), you.get_dodge(), ctxt.get_desc( "SHOW_DESCRIPTION" ) ); ma_style_callback callback( static_cast( STYLE_OFFSET ), selectable_styles ); kmenu.callback = &callback;