Skip to content

Commit

Permalink
feat: Allow martial arts to require mutations (#5973)
Browse files Browse the repository at this point in the history
* Handle martialarts.cpp except style callback

* stylin'

* style(autofix.ci): automated formatting

* Implement the style-wide restrictions

* Documentationing

* style(autofix.ci): automated formatting

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
RobbieNeko and autofix-ci[bot] authored Jan 25, 2025
1 parent 2c5a2e4 commit a795c95
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,20 @@ title: Martial arts & techniques
"id" : "debug_elem_resist",
"heat_arm_per" : 1.0
],
"ondodge_buffs" : [] // List of buffs that are automatically applied on successful dodge
"onattack_buffs" : [] // List of buffs that are automatically applied after any attack, hit or miss
"onhit_buffs" : [] // List of buffs that are automatically applied on successful hit
"onmove_buffs" : [] // List of buffs that are automatically applied on movement
"onmiss_buffs" : [] // List of buffs that are automatically applied on a miss
"oncrit_buffs" : [] // List of buffs that are automatically applied on a crit
"onkill_buffs" : [] // List of buffs that are automatically applied upon killing an enemy
"ondodge_buffs" : [], // List of buffs that are automatically applied on successful dodge
"onattack_buffs" : [], // List of buffs that are automatically applied after any attack, hit or miss
"onhit_buffs" : [], // List of buffs that are automatically applied on successful hit
"onmove_buffs" : [], // List of buffs that are automatically applied on movement
"onmiss_buffs" : [], // List of buffs that are automatically applied on a miss
"oncrit_buffs" : [], // List of buffs that are automatically applied on a crit
"onkill_buffs" : [], // List of buffs that are automatically applied upon killing an enemy
"techniques" : [ // List of techniques available when this martial art is used
"tec_debug_slow",
"tec_debug_arpen"
]
"weapons": [ "tonfa" ] // List of weapons usable with this art
],
"weapons": [ "tonfa" ], // List of weapons usable with this art
"weapon_category": [ "WEAPON_CAT1" ], // Weapons that have one of the categories in here are usable with this art.
"mutation": [ "UNSTYLISH" ] // A list of mutations, at least 1 of which is needed to use this art
```

### Techniques
Expand Down Expand Up @@ -72,7 +73,8 @@ title: Martial arts & techniques
"You phase-strike %s",
"<npcname> phase-strikes %s"
]
"movecost_mult" : 0.3 // Any bonuses, as described below
"movecost_mult" : 0.3, // Any bonuses, as described below
"mutations_required": [ "MASOCHIST" ] // List of mutations, at least 1 of which is required to use the technique
```

### Buffs
Expand Down
5 changes: 5 additions & 0 deletions src/character_martial_arts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ bool character_martial_arts::selected_strictly_melee() const
return style_selected->strictly_melee;
}

std::set<trait_id> character_martial_arts::selected_mutations() const
{
return style_selected->mutation;
}

bool character_martial_arts::selected_has_weapon( const itype_id &weap ) const
{
return style_selected->has_weapon( weap );
Expand Down
2 changes: 2 additions & 0 deletions src/character_martial_arts.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class character_martial_arts

bool knows_selected_style() const;
bool selected_strictly_melee() const;
std::set<trait_id> selected_mutations()
const; // returns a list of the selected style's required mutations
bool selected_allow_melee() const;
bool selected_has_weapon( const itype_id &weap ) const;
bool selected_force_unarmed() const;
Expand Down
58 changes: 58 additions & 0 deletions src/martialarts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <algorithm>
#include <cstdlib>
#include <generic_readers.h>
#include <iterator>
#include <map>
#include <memory>
Expand All @@ -26,6 +27,7 @@
#include "json.h"
#include "map.h"
#include "messages.h"
#include "mutation.h"
#include "output.h"
#include "pimpl.h"
#include "player.h"
Expand Down Expand Up @@ -179,6 +181,7 @@ void ma_requirements::load( const JsonObject &jo, const std::string & )
optional( jo, was_loaded, "weapon_damage_requirements", min_damage, ma_weapon_damage_reader {} );
optional( jo, was_loaded, "weapon_categories_allowed", weapon_categories_allowed,
auto_flags_reader<weapon_category_id> {} );
optional( jo, was_loaded, "mutations_required", mutations_required, auto_flags_reader<trait_id> {} );
}

void ma_technique::load( const JsonObject &jo, const std::string &src )
Expand Down Expand Up @@ -326,6 +329,7 @@ void martialart::load( const JsonObject &jo, const std::string & )
optional( jo, was_loaded, "techniques", techniques, auto_flags_reader<matec_id> {} );
optional( jo, was_loaded, "weapons", weapons, auto_flags_reader<itype_id> {} );
optional( jo, was_loaded, "weapon_category", weapon_category, auto_flags_reader<weapon_category_id> {} );
optional( jo, was_loaded, "mutation", mutation, auto_flags_reader<trait_id> {} );

optional( jo, was_loaded, "strictly_melee", strictly_melee, false );
optional( jo, was_loaded, "strictly_unarmed", strictly_unarmed, false );
Expand Down Expand Up @@ -406,6 +410,11 @@ void check_martialarts()
debugmsg( "Weapon category %s in style %s is invalid.", weap_cat.c_str(), ma.name );
}
}
for( const trait_id &mut : ma.mutation ) {
if( !mut.is_valid() ) {
debugmsg( "Mutation %s in style %s is invalid.", mut.c_str(), ma.name );
}
}
}
for( const auto &t : ma_techniques.get_all() ) {
::check( t.reqs, string_format( "technique %s", t.id.c_str() ) );
Expand Down Expand Up @@ -501,6 +510,7 @@ bool ma_requirements::is_valid_character( const Character &u ) const
bool weapon_ok = is_valid_weapon( u.primary_weapon() );
bool style_weapon = u.martial_arts_data->selected_has_weapon( u.primary_weapon().typeId() );
bool all_weapons = u.martial_arts_data->selected_allow_melee();
std::set<trait_id> style_muts = u.martial_arts_data->selected_mutations();

bool unarmed_ok = !is_armed || ( unarmed_weapon && unarmed_weapons_allowed );
bool melee_ok = melee_allowed && weapon_ok && ( style_weapon || all_weapons );
Expand All @@ -512,6 +522,18 @@ bool ma_requirements::is_valid_character( const Character &u ) const
return false;
}

if( !style_muts.empty() ) {
bool valid_mut = false;
for( const trait_id &mut : style_muts ) {
if( u.has_trait( mut ) ) {
valid_mut = true;
}
}
if( !valid_mut ) {
return false;
}
}

if( wall_adjacent && !get_map().is_wall_adjacent( u.pos() ) ) {
return false;
}
Expand All @@ -534,6 +556,18 @@ bool ma_requirements::is_valid_character( const Character &u ) const
}
}

if( !mutations_required.empty() ) {
bool valid_mut = false;
for( const trait_id &mut : mutations_required ) {
if( u.has_trait( mut ) ) {
valid_mut = true;
}
}
if( !valid_mut ) {
return false;
}
}

return true;
}

Expand Down Expand Up @@ -599,6 +633,18 @@ std::string ma_requirements::get_description( bool buff ) const
} ) + "\n";
}

if( !mutations_required.empty() ) {
dump += vgettext( "<bold>Mutation required: </bold>",
"<bold>Mutations required: </bold>", mutations_required.size() );
dump += enumerate_as_string( mutations_required.begin(),
mutations_required.end(), []( const trait_id & mut ) {
if( !mut.is_valid() ) {
return mut.str();
}
return mut->name();
} ) + "\n";
}

if( !req_buffs.empty() ) {
dump += _( "<bold>Requires:</bold> " );

Expand Down Expand Up @@ -1625,6 +1671,18 @@ bool ma_style_callback::key( const input_context &ctxt, const input_event &event
buffer += enumerate_as_string( weapons );
}
}
if( !ma.mutation.empty() ) {
Character &player = get_player_character();
buffer += _( "<bold>Mutations:</bold>" ) + std::string( "\n" );
std::vector<std::string> mutations;
for( const trait_id &mut : ma.mutation ) {
std::string mutname = player.has_trait( mut ) ? colorize( mut->name() + _( " [have]" ),
c_light_cyan ) : mut->name();
mutations.push_back( mutname );
}
std::sort( mutations.begin(), mutations.end(), localized_compare );
buffer += enumerate_as_string( mutations );
}

catacurses::window w;

Expand Down
5 changes: 5 additions & 0 deletions src/martialarts.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ struct ma_requirements {
/** Weapon categories compatible with this requirement. If empty, allow any weapon category. */
std::vector<weapon_category_id> weapon_categories_allowed;

// A list of mutations that are compatible with the technique (i.e. without them no technique usage for you)
std::vector<trait_id> mutations_required;

/** Minimum amount of given skill to trigger this bonus */
std::vector<std::pair<skill_id, int>> min_skill;

Expand Down Expand Up @@ -286,6 +289,8 @@ class martialart
std::set<matec_id> techniques; // all available techniques
std::set<itype_id> weapons; // all style weapons
std::set<weapon_category_id> weapon_category; // all style weapon categories
std::set<trait_id>
mutation; // style-based necessary mutations (if set, need at least 1 to use style)
bool strictly_unarmed = false; // Punch daggers etc.
bool strictly_melee = false; // Must have a weapon.
bool allow_melee = false; // Can use unarmed or with ANY weapon
Expand Down

0 comments on commit a795c95

Please sign in to comment.