Skip to content

Commit

Permalink
WIP attack vector
Browse files Browse the repository at this point in the history
  • Loading branch information
Venera3 committed Apr 17, 2024
1 parent 0853a71 commit 6487bc4
Show file tree
Hide file tree
Showing 9 changed files with 203 additions and 4 deletions.
17 changes: 13 additions & 4 deletions data/json/mutations/mutation_techs.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
"unarmed_allowed": true,
"melee_allowed": true,
"attack_override": true,
"weighting": -2,
"weighting": 200,
"crit_ok": true,
"required_char_flags": [ "SEESLEEP" ],
"forbidden_char_flags": [ "EYE_MEMBRANE" ],
"repeat_min": 1,
"repeat_max": 5,
"mult_bonuses": [ { "stat": "damage", "type": "bullet", "scale": 15 } ],
Expand All @@ -30,6 +28,17 @@
"message": "You bleed the %s dry!"
},
{ "id": "downed", "chance": 50, "duration": 2, "message": "You bonk the %s real good", "req_flag": "DREAMY" }
]
],
"wip_attack_vectors": [ "test_test" ],
"attack_vectors": [ "HAND" ]
},
{
"type": "attack_vector",
"id": "test_test",
"limbs": [ "debug_tail" ],
"limb_types": [ "sensor" ],
"sub_limbs": [ "sub_limb_debug_tail"],
"encumbrance_limit": 33,
"bp_hp_limit": 75
}
]
5 changes: 5 additions & 0 deletions src/bodypart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,11 @@ float body_part_type::unarmed_damage( const damage_type_id &dt ) const
return damage.type_damage( dt );
}

float body_part_type::total_unarmed_damage() const
{
return damage.total_damage();
}

float body_part_type::unarmed_arpen( const damage_type_id &dt ) const
{
return damage.type_arpen( dt );
Expand Down
2 changes: 2 additions & 0 deletions src/bodypart.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,8 @@ struct body_part_type {
}

float unarmed_damage( const damage_type_id &dt ) const;
// return the total amount of unarmed damage this limb would do
float total_unarmed_damage() const;
float unarmed_arpen( const damage_type_id &dt ) const;

float damage_resistance( const damage_type_id &dt ) const;
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 @@ -80,6 +80,8 @@ class character_martial_arts
/** Fires all kill-triggered martial arts events */
void ma_onkill_effects( Character &owner );

// Selects a valid attack vector
attack_vector_id choose_attack_vector( const Character &user, const matec_id &tech ) const;
/** Returns an attack vector that the player can use */
std::string get_valid_attack_vector( const Character &user,
const std::vector<std::string> &attack_vectors ) const;
Expand Down
1 change: 1 addition & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ void DynamicDataLoader::initialize()
add( "weapon_category", &weapon_category::load_weapon_categories );
add( "martial_art", &load_martial_art );
add( "climbing_aid", &climbing_aid::load_climbing_aid );
add( "attack_vector", &wip_attack_vector::load_attack_vectors );
add( "effect_type", &load_effect_type );
add( "oter_id_migration", &overmap::load_oter_id_migration );
add( "overmap_terrain", &overmap_terrains::load );
Expand Down
148 changes: 148 additions & 0 deletions src/martialarts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
#include "translations.h"
#include "ui_manager.h"
#include "value_ptr.h"
#include "weighted_list.h"

static const attack_vector_id attack_vector_null( "null" );

Check failure on line 39 in src/martialarts.cpp

View workflow job for this annotation

GitHub Actions / build (src)

Variable 'attack_vector_null' declared but not used. [cata-unused-statics,-warnings-as-errors]

Check failure on line 39 in src/martialarts.cpp

View workflow job for this annotation

GitHub Actions / build (src)

Declaration of string_id 'attack_vector_null' should be named 'wip_attack_vector_null'. [cata-static-string_id-constants,-warnings-as-errors]

static const bionic_id bio_armor_arms( "bio_armor_arms" );
static const bionic_id bio_armor_legs( "bio_armor_legs" );
Expand All @@ -50,14 +53,51 @@ static const skill_id skill_unarmed( "unarmed" );

static const weapon_category_id weapon_category_OTHER_INVALID_WEAP_CAT( "OTHER_INVALID_WEAP_CAT" );


namespace
{
generic_factory<weapon_category> weapon_category_factory( "weapon category" );
generic_factory<ma_technique> ma_techniques( "martial art technique" );
generic_factory<martialart> martialarts( "martial art style" );
generic_factory<ma_buff> ma_buffs( "martial art buff" );
generic_factory<wip_attack_vector> attack_vector_factory( "attack vector" );
} // namespace

/** @relates string_id */
template<>
const wip_attack_vector &string_id<wip_attack_vector>::obj() const
{
return attack_vector_factory.obj( *this );
}

template<>
bool attack_vector_id::is_valid() const
{
return attack_vector_factory.is_valid( *this );
}

void wip_attack_vector::load_attack_vectors( const JsonObject &jo, const std::string &src )
{
attack_vector_factory.load( jo, src );
}

void wip_attack_vector::reset()
{
attack_vector_factory.reset();
}

void wip_attack_vector::load( const JsonObject &jo, const std::string_view )
{
mandatory( jo, was_loaded, "id", id );
optional( jo, was_loaded, "weapon", weapon, false );
optional( jo, was_loaded, "limbs", limbs );
optional( jo, was_loaded, "sub_limbs", sub_limbs );
optional( jo, was_loaded, "limb_types", limb_types );
optional( jo, was_loaded, "encumbrance_limit", encumbrance_limit );
optional( jo, was_loaded, "bp_hp_limit", bp_hp_limit );

}

template<>
const weapon_category &weapon_category_id::obj() const
{
Expand Down Expand Up @@ -278,6 +318,9 @@ void ma_technique::load( const JsonObject &jo, const std::string &src )
has_condition = true;
}

if( jo.has_array( "wip_attack_vectors" ) ) {
optional( jo, was_loaded, "wip_attack_vectors", wip_attack_vectors );
}
reqs.load( jo, src );
bonuses.load( jo );
}
Expand Down Expand Up @@ -1393,6 +1436,111 @@ std::string character_martial_arts::get_valid_attack_vector( const Character &us
return "NONE";
}

attack_vector_id character_martial_arts::choose_attack_vector( const Character &user,
const matec_id &tech ) const
{
// Handle choosing the attack vector
// Deal with hard filters - DONE
// Consider expected damage?
// Weighted list based on damage? Hard priority?
// Return explicit bodypart id for unarmed stuff?
//
const std::vector<bodypart_id> anat = user.get_all_body_parts();
weighted_float_list<attack_vector_id> list;
for( const attack_vector_id &vec : tech.obj().wip_attack_vectors ) {
wip_attack_vector tmp = vec.obj();
bool found = false;
float weight = 0.0f;
// Early break for armed vectors
if( tmp.weapon && user.is_armed() ) {
item *weapon = user.get_wielded_item().get_item();
weight = weapon->average_dps( user );
if( tmp.primary ) {
return vec;
} else {
list.add_or_replace( vec, weight );
}
add_msg_debug( debugmode::DF_MELEE, "Weapon %s eligable for attack vector %s with weight %.1f",
weapon->display_name(),
vec.c_str(), weight );
found = true;

Check failure on line 1466 in src/martialarts.cpp

View workflow job for this annotation

GitHub Actions / build (src)

Value stored to 'found' is never read [clang-analyzer-deadcode.DeadStores,-warnings-as-errors]
break;
}
if( found ) {
continue;
}
// If we defined explicit bodyparts
for( const bodypart_id &bp : vec.obj().limbs ) {

Check failure on line 1473 in src/martialarts.cpp

View workflow job for this annotation

GitHub Actions / build (src)

the type of the loop variable 'bp' is different from the one returned by the iterator and generates an implicit conversion; you can either change the type to the matching one ('const string_id<body_part_type> &' but 'const auto&' is always a valid option) or remove the reference to make it explicit that you are creating a new value [performance-implicit-conversion-in-loop,-warnings-as-errors]

Check failure on line 1473 in src/martialarts.cpp

View workflow job for this annotation

GitHub Actions / build (src)

loop variable 'bp' of type 'const bodypart_id &' (aka 'const int_id<body_part_type> &') binds to a temporary constructed from type 'reference' (aka 'const string_id<body_part_type> &') [clang-diagnostic-range-loop-construct,-warnings-as-errors]
if( std::find( anat.begin(), anat.end(), bp ) != anat.end() ) {
const bodypart &part = *user.get_part( bp );
if( ( 100 * part.get_hp_cur() / part.get_hp_max() ) > tmp.bp_hp_limit &&
part.get_encumbrance_data().encumbrance < tmp.encumbrance_limit ) {
// Use the BP unarmed damage as the weight
weight = bp.obj().total_unarmed_damage();
if( tmp.primary ) {
return vec;
} else {
list.add_or_replace( vec, weight );
}
add_msg_debug( debugmode::DF_MELEE, "Bodypart %s eligable for attack vector %s with weight %.1f",
bp.id().c_str(),
vec.c_str(), weight );
found = true;
break;
}
}
}
if( found ) {
continue;
}
// Sublimb check
for( const sub_bodypart_str_id &sbp : tmp.sub_limbs ) {
for( const bodypart_id &bp : anat ) {
if( std::find( bp.obj().sub_parts.begin(), bp.obj().sub_parts.end(),
sbp ) != bp.obj().sub_parts.end() ) {
list.add_or_replace( vec, weight );
add_msg_debug( debugmode::DF_MELEE,
"Sub-bodypart %s eligable for attack vector %s with weight %.1f", sbp.c_str(),
vec.c_str(), weight );
found = true;
break;
}
}
if( found ) {
break;
}
}
if( found ) {
continue;
}
// More flexible search for limb types
for( const body_part_type::type &type : tmp.limb_types ) {
std::vector<bodypart_id> limbs = user.get_all_body_parts_of_type( type );
for( const bodypart_id &bp : limbs ) {
const bodypart &part = *user.get_part( bp );
if( ( 100 * part.get_hp_cur() / part.get_hp_max() ) > tmp.bp_hp_limit &&
part.get_encumbrance_data().encumbrance < tmp.encumbrance_limit ) {
list.add_or_replace( vec, weight );
add_msg_debug( debugmode::DF_MELEE,
"Bodypart %s eligable for attack vector %s (limb type filter) with weight %.1f",
bp.id().c_str(),
vec.c_str(), weight );
found = true;
break;

}
}
if( found ) {
break;
}
}
if( found ) {
continue;
}
}
return *list.pick();
}

bool character_martial_arts::can_use_attack_vector( const Character &user,
const std::string &av ) const
{
Expand Down
27 changes: 27 additions & 0 deletions src/martialarts.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,32 @@ class weapon_category

matype_id martial_art_learned_from( const itype & );

struct wip_attack_vector {
attack_vector_id id;
translation name;
// Used with a weapon, precludes most other checks
bool weapon = false;
// If true the vector will always be preferentially used when eligable
bool primary = false;
// Explicit bodypart definitions
std::vector<bodypart_str_id> limbs;
// Flexible bodypart type definition
std::vector<body_part_type::type> limb_types;
// Explicit sublimb requirement
std::vector<sub_bodypart_str_id> sub_limbs;

// Encumbrance limit in absolute encumbrance
int encumbrance_limit = 100;
// Percent of bodypart HP required
int bp_hp_limit = 100;

bool was_loaded = false;

static void load_attack_vectors( const JsonObject &jo, const std::string &src );
static void reset();
void load( const JsonObject &jo, std::string_view );
};

struct ma_requirements {
bool was_loaded = false;

Expand Down Expand Up @@ -172,6 +198,7 @@ class ma_technique
// What way is the technique delivered to the target?
std::vector<std::string> attack_vectors; // by priority
std::vector<std::string> attack_vectors_random; // randomly
std::vector<attack_vector_id> wip_attack_vectors;

int repeat_min = 1; // Number of times the technique is repeated on a successful proc
int repeat_max = 1;
Expand Down
2 changes: 2 additions & 0 deletions src/melee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1657,6 +1657,8 @@ std::vector<matec_id> Character::evaluate_techniques( Creature &t, const item_lo
continue;
}

attack_vector_id wip = martial_arts_data->choose_attack_vector( *this, tec.id );

Check failure on line 1660 in src/melee.cpp

View workflow job for this annotation

GitHub Actions / build (src)

Value stored to 'wip' during its initialization is never read [clang-analyzer-deadcode.DeadStores,-warnings-as-errors]

Check failure on line 1660 in src/melee.cpp

View workflow job for this annotation

GitHub Actions / build (src)

unused variable 'wip' [clang-diagnostic-unused-variable,-warnings-as-errors]

// Does the player have a functional attack vector to deliver the technique?
std::vector<std::string> shuffled_attack_vectors = tec.attack_vectors_random;
std::shuffle( shuffled_attack_vectors.begin(), shuffled_attack_vectors.end(), rng_get_engine() );
Expand Down
3 changes: 3 additions & 0 deletions src/type_id.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ struct ammo_effect;
using ammo_effect_id = int_id<ammo_effect>;
using ammo_effect_str_id = string_id<ammo_effect>;

struct wip_attack_vector;
using attack_vector_id = string_id<wip_attack_vector>;

struct bionic_data;
using bionic_id = string_id<bionic_data>;

Expand Down

0 comments on commit 6487bc4

Please sign in to comment.