From 15f2ff3ff0f57aa64390ba63f89e020edf71d0ee Mon Sep 17 00:00:00 2001 From: Paul Harvey <2677507+prharvey@users.noreply.github.com> Date: Sun, 5 Nov 2023 09:01:14 -0700 Subject: [PATCH] Allow techniques on reach attacks. (#69103) * Let techniques trigger on reach attacks according to the newly added flags "reach_ok" and "reach_teq". * Remove the skill_stabbing constant since it was no longer being used. * Update the documentation. --- data/json/martialarts.json | 2 +- data/json/techniques.json | 20 ++++++++++++++++++++ doc/MARTIALART_JSON.md | 2 ++ src/martialarts.cpp | 9 +++++++++ src/martialarts.h | 2 ++ src/melee.cpp | 29 ++++++++++++++++++++--------- 6 files changed, 54 insertions(+), 10 deletions(-) diff --git a/data/json/martialarts.json b/data/json/martialarts.json index a6f4ee5e65ff4..d989554f6897d 100644 --- a/data/json/martialarts.json +++ b/data/json/martialarts.json @@ -1313,7 +1313,7 @@ ] } ], - "techniques": [ "tec_sojutsu_feint", "tec_sojutsu_shove", "tec_sojutsu_trip" ], + "techniques": [ "tec_sojutsu_feint", "tec_sojutsu_shove", "tec_sojutsu_trip", "tec_sojutsu_jab" ], "weapon_category": [ "POLEARMS" ] }, { diff --git a/data/json/techniques.json b/data/json/techniques.json index 589fbd0fcde70..37b04fd8cce5e 100644 --- a/data/json/techniques.json +++ b/data/json/techniques.json @@ -1351,6 +1351,7 @@ "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, "forbidden_buffs_all": [ "buff_medievalpole_onmove" ], + "reach_ok": true, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.1 }, { "stat": "damage", "type": "cut", "scale": 1.1 }, @@ -1388,6 +1389,7 @@ "melee_allowed": true, "required_buffs_all": "buff_medievalpole_onmiss", "crit_ok": true, + "reach_ok": true, "weighting": 2, "condition": { "and": [ @@ -1417,6 +1419,7 @@ "condition": { "npc_has_effect": "downed" }, "condition_desc": "* Only works on a downed target", "crit_tec": true, + "reach_ok": true, "weighting": 2, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 }, @@ -2796,6 +2799,7 @@ "messages": [ "You deftly trip %s!", " deftly trips %s!" ], "skill_requirements": [ { "name": "melee", "level": 3 } ], "melee_allowed": true, + "reach_ok": true, "condition": { "and": [ { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, @@ -2813,6 +2817,22 @@ ], "attack_vectors": [ "WEAPON" ] }, + { + "type": "technique", + "id": "tec_sojutsu_jab", + "name": "Jab", + "messages": [ "You quickly strike %s!", " quickly strikes %s!" ], + "skill_requirements": [ { "name": "melee", "level": 2 } ], + "melee_allowed": true, + "reach_tec": true, + "mult_bonuses": [ + { "stat": "movecost", "scale": 0.5 }, + { "stat": "damage", "type": "bash", "scale": 0.66 }, + { "stat": "damage", "type": "cut", "scale": 0.66 }, + { "stat": "damage", "type": "stab", "scale": 0.66 } + ], + "attack_vectors": [ "WEAPON" ] + }, { "type": "technique", "id": "tec_sojutsu_feint", diff --git a/doc/MARTIALART_JSON.md b/doc/MARTIALART_JSON.md index 3d8e01b5e6027..e44208f6aef14 100644 --- a/doc/MARTIALART_JSON.md +++ b/doc/MARTIALART_JSON.md @@ -89,6 +89,8 @@ "needs_ammo": true, // Technique works only if weapon is loaded; Consume 1 charge per attack "crit_tec": true, // This technique only works on a critical hit "crit_ok": true, // This technique works on both normal and critical hits + "reach_tec": true, // This technique only works on a reach attack hit + "reach_ok": true, // This technique works on both normal and reach attack hits "attack_override": false, // This technique replaces the base attack it triggered on, nulling damage and movecost (instead using the tech's flat_bonuses), and counts as unarmed for the purposes of skill training and special melee effects "condition": "u_is_outside",// Optional (array of) dialog conditions the attack requires to trigger. Failing these will disqualify the tech from being selected "condition_desc": "Needs X",// Description string describing the conditions of this attack (since dialog conditions can't be automatically evaluated) diff --git a/src/martialarts.cpp b/src/martialarts.cpp index 8f8ba7b278a3f..fc79b7c8616ee 100644 --- a/src/martialarts.cpp +++ b/src/martialarts.cpp @@ -221,6 +221,8 @@ void ma_technique::load( const JsonObject &jo, const std::string &src ) optional( jo, was_loaded, "crit_ok", crit_ok, false ); optional( jo, was_loaded, "attack_override", attack_override, false ); optional( jo, was_loaded, "wall_adjacent", wall_adjacent, false ); + optional( jo, was_loaded, "reach_tec", reach_tec, false ); + optional( jo, was_loaded, "reach_ok", reach_ok, false ); optional( jo, was_loaded, "needs_ammo", needs_ammo, false ); @@ -1866,6 +1868,13 @@ std::string ma_technique::get_description() const dump += _( "* Will only activate on a crit" ) + std::string( "\n" ); } + if( reach_ok ) { + dump += _( "* Can activate on a normal or a reach attack hit" ) + + std::string( "\n" ); + } else if( reach_tec ) { + dump += _( "* Will only activate on a reach attack" ) + std::string( "\n" ); + } + if( side_switch ) { dump += _( "* Moves target behind you" ) + std::string( "\n" ); } diff --git a/src/martialarts.h b/src/martialarts.h index b7984c3fce935..4cb609a5d2b68 100644 --- a/src/martialarts.h +++ b/src/martialarts.h @@ -150,6 +150,8 @@ class ma_technique bool dummy = false; bool crit_tec = false; bool crit_ok = false; + bool reach_tec = false; // only possible to use during a reach attack + bool reach_ok = false; // possible to use during a reach attack bool attack_override = false; // The attack replaces the one it triggered off of ma_requirements reqs; diff --git a/src/melee.cpp b/src/melee.cpp index 844ae1508de6d..2fbe7eca32a59 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -142,7 +142,6 @@ static const move_mode_id move_mode_prone( "prone" ); static const skill_id skill_melee( "melee" ); static const skill_id skill_spellcraft( "spellcraft" ); -static const skill_id skill_stabbing( "stabbing" ); static const skill_id skill_unarmed( "unarmed" ); static const trait_id trait_ARM_TENTACLES( "ARM_TENTACLES" ); @@ -725,10 +724,10 @@ bool Character::melee_attack_abstract( Creature &t, bool allow_special, // Pick one or more special attacks matec_id technique_id; - if( allow_special && !has_force_technique ) { - technique_id = pick_technique( t, cur_weapon, critical_hit, false, false ); - } else if( has_force_technique ) { + if( has_force_technique ) { technique_id = force_technique; + } else if( allow_special ) { + technique_id = pick_technique( t, cur_weapon, critical_hit, false, false ); } else { technique_id = tec_none; } @@ -957,7 +956,8 @@ int Character::get_total_melee_stamina_cost( const item *weap ) const void Character::reach_attack( const tripoint &p, int forced_movecost ) { - matec_id force_technique = tec_none; + static const matec_id no_technique_id( "" ); + matec_id force_technique = no_technique_id; /** @EFFECT_MELEE >5 allows WHIP_DISARM technique */ if( weapon.has_flag( flag_WHIP ) && ( get_skill_level( skill_melee ) > 5 ) && one_in( 3 ) ) { force_technique = WHIP_DISARM; @@ -979,7 +979,7 @@ void Character::reach_attack( const tripoint &p, int forced_movecost ) // 1 / mult because mult is the percent penalty, in the form 1.0 == 100% const float weary_mult = 1.0f / exertion_adjusted_move_multiplier( EXTRA_EXERCISE ); int move_cost = attack_speed( weapon ) * weary_mult; - float skill = std::min( 10.0f, get_skill_level( skill_stabbing ) ); + float skill = std::min( 10.0f, get_skill_level( skill_melee ) ); int t = 0; map &here = get_map(); std::vector path = line_to( pos(), p, t, 0 ); @@ -987,7 +987,7 @@ void Character::reach_attack( const tripoint &p, int forced_movecost ) for( const tripoint &path_point : path ) { // Possibly hit some unintended target instead Creature *inter = creatures.creature_at( path_point ); - /** @EFFECT_STABBING decreases chance of hitting intervening target on reach attack */ + /** @EFFECT_MELEE decreases chance of hitting intervening target on reach attack */ if( inter != nullptr && !x_in_y( ( target_size * target_size + 1 ) * skill, ( inter->get_size() * inter->get_size() + 1 ) * 10 ) ) { @@ -1003,7 +1003,6 @@ void Character::reach_attack( const tripoint &p, int forced_movecost ) } critter = inter; break; - /** @EFFECT_STABBING increases ability to reach attack through fences */ } else if( here.impassable( path_point ) && // Fences etc. Spears can stab through those !( weapon.has_flag( flag_SPEAR ) && @@ -1031,7 +1030,7 @@ void Character::reach_attack( const tripoint &p, int forced_movecost ) } reach_attacking = true; - melee_attack_abstract( *critter, false, force_technique, false, forced_movecost ); + melee_attack_abstract( *critter, true, force_technique, false, forced_movecost ); reach_attacking = false; } @@ -1527,6 +1526,18 @@ std::vector Character::evaluate_techniques( Creature &t, const item_lo continue; } + // skip non reach ok techniques if reach attacking + if( !( tec.reach_ok || tec.reach_tec ) && reach_attacking ) { + add_msg_debug( debugmode::DF_MELEE, "Not usable with reach attack, attack discarded" ); + continue; + } + + // skip reach techniques if not reach attacking + if( tec.reach_tec && !reach_attacking ) { + add_msg_debug( debugmode::DF_MELEE, "Only usable with reach attack, attack discarded" ); + continue; + } + // skip dodge counter techniques if it's not a dodge count, and vice versa if( dodge_counter != tec.dodge_counter ) { add_msg_debug( debugmode::DF_MELEE, "Not a dodge counter, attack discarded" );