diff --git a/data/json/mutations/mutations.json b/data/json/mutations/mutations.json index 6fc4f126e3793..2da69b6758c03 100644 --- a/data/json/mutations/mutations.json +++ b/data/json/mutations/mutations.json @@ -2018,8 +2018,9 @@ "points": 2, "visibility": 6, "ugliness": 3, + "bash_dmg_bonus": 2, "mixed_effect": true, - "description": "You've grown a chitin exoskeleton, much like that of an insect. It provides considerable physical protection, but reduces your Dexterity by 1. Somewhat reduces wet effects.", + "description": "You've grown a chitin exoskeleton, much like that of an insect. It provides considerable physical protection, and make your punches hit a little harder but reduces your Dexterity by 1. Somewhat reduces wet effects.", "types": [ "SKIN" ], "prereqs": [ "CHITIN" ], "changes_to": [ "CHITIN3" ], @@ -2046,7 +2047,8 @@ "points": 2, "visibility": 8, "ugliness": 5, - "description": "You've grown a chitin exoskeleton made of thick, stiff plates. It provides excellent physical protection, but reduces your Dexterity by 1 and encumbers all body parts but your eyes and mouth. Greatly reduces wet effects.", + "bash_dmg_bonus": 3, + "description": "You've grown a chitin exoskeleton made of thick, stiff plates. It provides excellent physical protection, make your punches hit harder but reduces your Dexterity by 1 and encumbers all body parts but your eyes and mouth. Greatly reduces wet effects.", "types": [ "SKIN" ], "prereqs": [ "CHITIN2", "CHITIN_FUR2" ], "category": [ "SPIDER" ], @@ -2446,6 +2448,7 @@ "points": 2, "visibility": 3, "ugliness": 2, + "cut_dmg_bonus": 3, "description": "You have claws on the ends of your fingers. If you aren't wearing gloves, your unarmed attacks deal a minor amount of cutting damage.", "types": [ "CLAWS" ], "prereqs": [ "NAILS" ], @@ -2460,6 +2463,8 @@ "points": 3, "visibility": 3, "ugliness": 4, + "cut_dmg_bonus": 1, + "flags": [ "UNARMED_BONUS" ], "description": "Your claws have grown tougher and slightly gnarled.", "types": [ "CLAWS" ], "prereqs": [ "CLAWS" ], @@ -2476,6 +2481,8 @@ "ugliness": 5, "valid": false, "purifiable": false, + "cut_dmg_bonus": 1, + "flags": [ "UNARMED_BONUS" ], "description": "Your paws are bone, muscle, and claw with a thin layer of skin and fur. They might as well be made of stainless steel.", "types": [ "CLAWS" ], "prereqs": [ "CLAWS_RAT" ], @@ -2490,6 +2497,8 @@ "name": "Retractable Claws", "points": 2, "ugliness": 1, + "cut_dmg_bonus": 3, + "flags": [ "NEED_ACTIVE_TO_MELEE" ], "description": "You have claws on the ends of your fingers, and can extend or retract them as desired. Gloves will still get in the way, though.", "types": [ "CLAWS" ], "prereqs": [ "CLAWS" ], @@ -2519,6 +2528,8 @@ "points": 2, "visibility": 4, "ugliness": 3, + "cut_dmg_bonus": 3, + "flags": [ "UNARMED_BONUS" ], "mixed_effect": true, "restricts_gear": [ "HAND_L", "HAND_R" ], "destroys_gear": true, @@ -2685,6 +2696,7 @@ "points": 1, "visibility": 5, "ugliness": 4, + "rand_cut_bonus": { "min": 2, "max": 3 }, "description": "The skin on your hands is a mucous membrane and produces a thick, acrid slime. Attacks using your hand will cause minor acid damage. Slightly increases wet benefits.", "prereqs": [ "SLIMY" ], "category": [ "SLIME" ], diff --git a/doc/JSON_FLAGS.md b/doc/JSON_FLAGS.md index 312e9ebf765dc..c65d38e369b61 100644 --- a/doc/JSON_FLAGS.md +++ b/doc/JSON_FLAGS.md @@ -1081,6 +1081,11 @@ Also see `monster_attacks.json` for more special attacks, for example, impale an ## Mutations +#### Flags + +- ```UNARMED_BONUS``` You get a bonus to unarmed bash and cut damage equal to unarmed_skill/2 up to 4. +- ```NEED_ACTIVE_TO_MELEE``` This mutation gives bonus to unarmed melee only if it's active. + ### Categories These branches are also the valid entries for the categories of `dreams` in `dreams.json` diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index 4870c634a06d4..7e062ca18366f 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -940,6 +940,10 @@ Note that even though most statistics yield an integer, you should still use "points": 2, // Point cost of the trait. Positive values cost points and negative values give points "visibility": 0, // Visibility of the trait for purposes of NPC interaction (default: 0) "ugliness": 0, // Ugliness of the trait for purposes of NPC interaction (default: 0) +"cut_dmg_bonus": 3, // Bonus to unarmed cut damage (default: 0) +"bash_dmg_bonus": 3, // Bonus to unarmed bash damage (default: 0) +"rand_cut_bonus": { "min": 2, "max": 3 }, // Random bonus to unarmed cut damage between min and max. +"rand_bash_bonus": { "min": 2, "max": 3 }, // Random bonus to unarmed bash damage between min and max. "bodytemp_modifiers" : [100, 150], // Range of additional bodytemp units (these units are described in 'weather.h'. First value is used if the person is already overheated, second one if it's not. "bodytemp_sleep" : 50, // Additional units of bodytemp which are applied when sleeping "initial_ma_styles": [ "style_crane" ], // (optional) A list of ids of martial art styles of which the player can choose one when starting a game. diff --git a/src/melee.cpp b/src/melee.cpp index dd0ae50b89dc8..04491bbd019f2 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -498,17 +498,29 @@ void player::melee_attack( Creature &t, bool allow_special, const matec_id &forc perform_technique( technique, t, d, move_cost ); } - if( allow_special && !t.is_dead_state() ) { - perform_special_attacks( t ); - } - // Proceed with melee attack. if( !t.is_dead_state() ) { // Handles speed penalties to monster & us, etc std::string specialmsg = melee_special_effects( t, d, cur_weapon ); - dealt_damage_instance dealt_dam; // gets overwritten with the dealt damage values + // gets overwritten with the dealt damage values + dealt_damage_instance dealt_dam; + dealt_damage_instance dealt_special_dam; + if( allow_special ) { + perform_special_attacks( t, dealt_special_dam ); + } t.deal_melee_hit( this, hit_spread, critical_hit, d, dealt_dam ); + if( ( cur_weapon.is_null() && ( dealt_dam.type_damage( DT_CUT ) > 0 || + dealt_dam.type_damage( DT_STAB ) > 0 ) ) || ( dealt_special_dam.type_damage( DT_CUT ) > 0 || + dealt_special_dam.type_damage( DT_STAB ) > 0 ) ) { + if( has_trait( trait_POISONOUS ) ) { + add_msg_if_player( m_good, _( "You poison %s!" ), t.disp_name() ); + t.add_effect( effect_poison, 6_turns ); + } else if( has_trait( trait_POISONOUS2 ) ) { + add_msg_if_player( m_good, _( "You inject your venom into %s!" ), t.disp_name() ); + t.add_effect( effect_badpoison, 6_turns ); + } + } // Make a rather quiet sound, to alert any nearby monsters if( !is_quiet() ) { // check martial arts silence @@ -840,6 +852,35 @@ void player::roll_bash_damage( bool crit, damage_instance &di, bool average, bash_dam += average ? ( mindrunk + maxdrunk ) * 0.5f : rng( mindrunk, maxdrunk ); } + if( unarmed ) { + const bool left_empty = !natural_attack_restricted_on( bp_hand_l ); + const bool right_empty = !natural_attack_restricted_on( bp_hand_r ) && + weap.is_null(); + if( left_empty || right_empty ) { + float per_hand = 0.0f; + for( const std::pair< trait_id, trait_data > &mut : my_mutations ) { + if( mut.first->flags.count( "NEED_ACTIVE_TO_MELEE" ) > 0 && !has_active_mutation( mut.first ) ) { + continue; + } + float unarmed_bonus = 0.0f; + const int bash_bonus = mut.first->bash_dmg_bonus; + if( mut.first->flags.count( "UNARMED_BONUS" ) > 0 && bash_bonus > 0 ) { + unarmed_bonus += std::min( get_skill_level( skill_unarmed ) / 2, 4 ); + } + per_hand += bash_bonus + unarmed_bonus; + const std::pair rand_bash = mut.first->rand_bash_bonus; + per_hand += average ? ( rand_bash.first + rand_bash.second ) / 2.0f : rng( rand_bash.first, + rand_bash.second ); + } + bash_dam += per_hand; // First hand + if( left_empty && right_empty ) { + // Second hand + bash_dam += per_hand; + } + } + + } + /** @EFFECT_STR increases bashing damage */ float weap_dam = weap.damage_melee( DT_BASH ) + stat_bonus; /** @EFFECT_UNARMED caps bash damage with unarmed weapons */ @@ -886,7 +927,6 @@ void player::roll_cut_damage( bool crit, damage_instance &di, bool average, cons float cut_mul = 1.0f; int cutting_skill = get_skill_level( skill_cutting ); - int unarmed_skill = get_skill_level( skill_unarmed ); if( has_active_bionic( bio_cqb ) ) { cutting_skill = BIO_CQB_LEVEL; @@ -899,26 +939,24 @@ void player::roll_cut_damage( bool crit, damage_instance &di, bool average, cons weap.is_null(); if( left_empty || right_empty ) { float per_hand = 0.0f; - if( has_trait( trait_CLAWS ) || ( has_active_mutation( trait_CLAWS_RETRACT ) ) ) { - per_hand += 3; - } if( has_bionic( bionic_id( "bio_razors" ) ) ) { per_hand += 2; } - if( has_trait( trait_TALONS ) ) { - /** @EFFECT_UNARMED increases cutting damage with TALONS */ - per_hand += 3 + ( unarmed_skill > 8 ? 4 : unarmed_skill / 2 ); - } - // Stainless Steel Claws do stabbing damage, too. - if( has_trait( trait_CLAWS_RAT ) || has_trait( trait_CLAWS_ST ) ) { - /** @EFFECT_UNARMED increases cutting damage with CLAWS_RAT and CLAWS_ST */ - per_hand += 1 + ( unarmed_skill > 8 ? 4 : unarmed_skill / 2 ); + for( const std::pair< trait_id, trait_data > &mut : my_mutations ) { + if( mut.first->flags.count( "NEED_ACTIVE_TO_MELEE" ) > 0 && !has_active_mutation( mut.first ) ) { + continue; + } + float unarmed_bonus = 0.0f; + const int cut_bonus = mut.first->cut_dmg_bonus; + if( mut.first->flags.count( "UNARMED_BONUS" ) > 0 && cut_bonus > 0 ) { + unarmed_bonus += std::min( get_skill_level( skill_unarmed ) / 2, 4 ); + } + per_hand += cut_bonus + unarmed_bonus; + const std::pair rand_cut = mut.first->rand_cut_bonus; + per_hand += average ? ( rand_cut.first + rand_cut.second ) / 2.0f : rng( rand_cut.first, + rand_cut.second ); } // TODO: add acidproof check back to slime hands (probably move it elsewhere) - if( has_trait( trait_SLIME_HANDS ) ) { - /** @EFFECT_UNARMED increases cutting damage with SLIME_HANDS */ - per_hand += average ? 2.5f : rng( 2, 3 ); - } cut_dam += per_hand; // First hand if( left_empty && right_empty ) { @@ -1656,22 +1694,16 @@ bool player::block_hit( Creature *source, body_part &bp_hit, damage_instance &da return true; } -void player::perform_special_attacks( Creature &t ) +void player::perform_special_attacks( Creature &t, dealt_damage_instance &dealt_dam ) { - bool can_poison = false; - std::vector special_attacks = mutation_attacks( t ); - std::string target = t.disp_name(); - bool practiced = false; for( const auto &att : special_attacks ) { if( t.is_dead_state() ) { break; } - dealt_damage_instance dealt_dam; - // TODO: Make this hit roll use unarmed skill, not weapon skill + weapon to_hit int hit_spread = t.deal_melee_attack( this, hit_roll() * 0.8 ); if( hit_spread >= 0 ) { @@ -1686,20 +1718,6 @@ void player::perform_special_attacks( Creature &t ) if( dam > 0 ) { player_hit_message( this, att.text, t, dam ); } - - can_poison = can_poison || - dealt_dam.type_damage( DT_CUT ) > 0 || - dealt_dam.type_damage( DT_STAB ) > 0; - } - - if( can_poison && ( has_trait( trait_POISONOUS ) || has_trait( trait_POISONOUS2 ) ) ) { - if( has_trait( trait_POISONOUS ) ) { - add_msg_if_player( m_good, _( "You poison %s!" ), target ); - t.add_effect( effect_poison, 6_turns ); - } else if( has_trait( trait_POISONOUS2 ) ) { - add_msg_if_player( m_good, _( "You inject your venom into %s!" ), target ); - t.add_effect( effect_badpoison, 6_turns ); - } } } diff --git a/src/mutation.h b/src/mutation.h index b1a42c201ab32..053738d2c38cb 100644 --- a/src/mutation.h +++ b/src/mutation.h @@ -125,6 +125,11 @@ struct mutation_branch { float hp_adjustment = 0.0f; // Modify strength stat without changing HP float str_modifier = 0.0f; + //melee bonuses + int cut_dmg_bonus = 0; + std::pair rand_cut_bonus; + int bash_dmg_bonus = 0; + std::pair rand_bash_bonus; // Additional bonuses float dodge_modifier = 0.0f; float speed_modifier = 1.0f; diff --git a/src/mutation_data.cpp b/src/mutation_data.cpp index 8aaf3c4abac5c..c7bb5dbd88ab8 100644 --- a/src/mutation_data.cpp +++ b/src/mutation_data.cpp @@ -328,6 +328,8 @@ void mutation_branch::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "hp_adjustment", hp_adjustment, 0.0f ); optional( jo, was_loaded, "stealth_modifier", stealth_modifier, 0.0f ); optional( jo, was_loaded, "str_modifier", str_modifier, 0.0f ); + optional( jo, was_loaded, "cut_dmg_bonus", cut_dmg_bonus, 0 ); + optional( jo, was_loaded, "bash_dmg_bonus", bash_dmg_bonus, 0 ); optional( jo, was_loaded, "dodge_modifier", dodge_modifier, 0.0f ); optional( jo, was_loaded, "speed_modifier", speed_modifier, 1.0f ); optional( jo, was_loaded, "movecost_modifier", movecost_modifier, 1.0f ); @@ -367,6 +369,19 @@ void mutation_branch::load( const JsonObject &jo, const std::string & ) optional( jo, was_loaded, "mana_multiplier", mana_multiplier, 1.0f ); optional( jo, was_loaded, "mana_regen_multiplier", mana_regen_multiplier, 1.0f ); + if( jo.has_object( "rand_cut_bonus" ) ) { + JsonObject sm = jo.get_object( "rand_cut_bonus" ); + rand_cut_bonus.first = sm.get_int( "min" ); + rand_cut_bonus.second = sm.get_int( "max" ); + } + + if( jo.has_object( "rand_bash_bonus" ) ) { + JsonObject sm = jo.get_object( "rand_bash_bonus" ); + rand_bash_bonus.first = sm.get_int( "min" ); + rand_bash_bonus.second = sm.get_int( "max" ); + } + + if( jo.has_object( "social_modifiers" ) ) { JsonObject sm = jo.get_object( "social_modifiers" ); social_mods = load_mutation_social_mods( sm ); diff --git a/src/player.h b/src/player.h index ec2c0e7cdd07d..f00d97b9904d7 100644 --- a/src/player.h +++ b/src/player.h @@ -523,7 +523,7 @@ class player : public Character void perform_technique( const ma_technique &technique, Creature &t, damage_instance &di, int &move_cost ); /** Performs special attacks and their effects (poisonous, stinger, etc.) */ - void perform_special_attacks( Creature &t ); + void perform_special_attacks( Creature &t, dealt_damage_instance &dealt_dam ); /** Returns a vector of valid mutation attacks */ std::vector mutation_attacks( Creature &t ) const;