diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 0a3441b356e0..80ef07a576b7 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -4423,7 +4423,7 @@ void activity_handlers::robot_control_finish( player_activity *act, player *p ) z->name() ); z->friendly = -1; if( z->has_flag( MF_RIDEABLE_MECH ) ) { - z->add_effect( effect_pet, 1_turns, num_bp ); + z->add_effect( effect_pet, 1_turns ); } } else if( success >= -2 ) { //A near success diff --git a/src/armor_layers.cpp b/src/armor_layers.cpp index 3e34692b7a04..c8958336ab25 100644 --- a/src/armor_layers.cpp +++ b/src/armor_layers.cpp @@ -78,7 +78,7 @@ item_penalties get_item_penalties( const location_vector::const_iterator & std::vector> lists_of_bad_items_within; for( const bodypart_id &bp : c.get_all_body_parts() ) { - if( _bp->token && _bp != body_part_appendix ) { + if( _bp->token && _bp.id().is_null() ) { continue; } if( !worn_item->covers( bp ) ) { @@ -288,9 +288,9 @@ std::vector clothing_properties( props.reserve( 5 ); const std::string space = " "; - const int coverage = bp == body_part_appendix ? worn_item.get_avg_coverage() : + const int coverage = bp.id().is_null() ? worn_item.get_avg_coverage() : worn_item.get_coverage( bp ); - const int encumbrance = bp == body_part_appendix ? worn_item.get_avg_encumber( + const int encumbrance = bp.id().is_null() ? worn_item.get_avg_encumber( c ) : worn_item.get_encumber( c, bp ); props.push_back( string_format( "[%s]", _( "Properties" ) ) ); props.push_back( name_and_value( space + _( "Coverage:" ), @@ -436,7 +436,7 @@ void show_armor_layers_ui( Character &who ) * + 3 - horizontal lines; * + 1 - caption line; * + 2 - innermost/outermost string lines; - * + num_bp - sub-categories (torso, head, eyes, etc.); + * + num_of_parts - sub-categories (torso, head, eyes, etc.); * + 1 - gap; * number of lines required for displaying all items is calculated dynamically, * because some items can have multiple entries (i.e. cover a few parts of body). @@ -452,7 +452,7 @@ void show_armor_layers_ui( Character &who ) for( const bodypart_id &it : all_parts ) { armor_cat.insert( it ); } - armor_cat.insert( body_part_appendix ); + armor_cat.insert( bodypart_str_id::NULL_ID().id() ); int req_right_h = 3 + 1 + 2 + num_of_parts + 1; for( const bodypart_id &cover : armor_cat ) { @@ -468,9 +468,9 @@ void show_armor_layers_ui( Character &who ) * + 1 - caption line; * + 8 - general properties * + 13 - ASSUMPTION: max possible number of flags @ item - * + num_bp+1 - warmth & enc block + * + num_of_parts+1 - warmth & enc block */ - const int req_mid_h = 3 + 1 + 8 + 13 + num_bp + 1; + const int req_mid_h = 3 + 1 + 8 + 13 + num_of_parts + 1; int win_h = 0; int win_w = 0; @@ -542,7 +542,6 @@ void show_armor_layers_ui( Character &who ) ctxt.register_action( "NEXT_TAB" ); ctxt.register_action( "MOVE_ARMOR" ); ctxt.register_action( "CHANGE_SIDE" ); - ctxt.register_action( "TOGGLE_CLOTH" ); ctxt.register_action( "ASSIGN_INVLETS" ); ctxt.register_action( "SORT_ARMOR" ); ctxt.register_action( "EQUIP_ARMOR" ); @@ -574,7 +573,7 @@ void show_armor_layers_ui( Character &who ) // top bar wprintz( w_sort_cat, c_white, _( "Sort Armor" ) ); - const auto name = bp != body_part_appendix ? body_part_name_as_heading( bp, 1 ) : _( "All" ); + const auto name = bp.id() ? body_part_name_as_heading( bp, 1 ) : _( "All" ); wprintz( w_sort_cat, c_yellow, " << %s >>", name ); right_print( w_sort_cat, 0, 0, c_white, string_format( _( "[%s] Hide sprite. " @@ -678,7 +677,7 @@ void show_armor_layers_ui( Character &who ) } int pos = 1, curr = 0; for( const bodypart_id cover : rl ) { - if( cover == body_part_appendix ) { + if( cover.id().is_null() ) { continue; } if( curr >= rightListOffset && pos <= rightListLines ) { @@ -743,7 +742,7 @@ void show_armor_layers_ui( Character &who ) // Create ptr list of items to display tmp_worn.clear(); const bodypart_id &bp = armor_cat[ tabindex ]; - if( bp == body_part_appendix ) { + if( bp.id().is_null() ) { // All int i = 0; for( auto it = who.worn.begin(); it != who.worn.end(); ++it ) { @@ -874,7 +873,7 @@ void show_armor_layers_ui( Character &who ) bool equipped = who.as_player()->wear_possessed( *loc ); if( equipped ) { const bodypart_id &bp = armor_cat[tabindex]; - if( tabindex == num_bp || loc->covers( bp ) ) { + if( tabindex == num_of_parts || loc->covers( bp ) ) { // Set ourselves up to be pointing at the new item // TODO: This doesn't work yet because we don't save our // state through other activities, but that's a thing @@ -886,7 +885,7 @@ void show_armor_layers_ui( Character &who ) if( i == loc ) { found = true; } - return !found && ( tabindex == num_bp || i->covers( bp ) ); + return !found && ( tabindex == num_of_parts || i->covers( bp ) ); } ); } } else if( who.is_npc() ) { diff --git a/src/bionics_ui.cpp b/src/bionics_ui.cpp index a287dd6824f9..c4e8ef20e9ae 100644 --- a/src/bionics_ui.cpp +++ b/src/bionics_ui.cpp @@ -370,7 +370,8 @@ static void draw_bionics_tabs( const catacurses::window &win, const size_t activ wnoutrefresh( win ); } -static void draw_description( const catacurses::window &win, const bionic &bio ) +static void draw_description( const catacurses::window &win, const bionic &bio, + const Character &who ) { werase( win ); const int width = getmaxx( win ); @@ -384,7 +385,8 @@ static void draw_description( const catacurses::window &win, const bionic &bio ) // TODO: Unhide when enforcing limits if( get_option < bool >( "CBM_SLOTS_ENABLED" ) ) { - const bool each_bp_on_new_line = ypos + static_cast( num_bp ) + 1 < getmaxy( win ); + int body_part_count = who.get_all_body_parts().size(); + const bool each_bp_on_new_line = ypos + body_part_count + 1 < getmaxy( win ); fold_and_print( win, point( 0, ypos ), width, c_light_gray, list_occupied_bps( bio.id, _( "This bionic occupies the following body parts:" ), each_bp_on_new_line ) ); } @@ -707,7 +709,7 @@ void show_bionics_ui( Character &who ) draw_bionics_titlebar( w_title, &who, menu_mode ); if( menu_mode == EXAMINING && !current_bionic_list->empty() ) { - draw_description( w_description, *( *current_bionic_list )[cursor] ); + draw_description( w_description, *( *current_bionic_list )[cursor], who ); } } ); diff --git a/src/character.cpp b/src/character.cpp index 8be7ec3b6f10..b5707f15be09 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -1330,7 +1330,7 @@ void Character::forced_dismount() } const int dodge = get_dodge(); const int damage = std::max( 0, rng( 1, 20 ) - rng( dodge, dodge * 2 ) ); - bodypart_id hit( "num_bp" ); + bodypart_id hit = bodypart_str_id::NULL_ID().id(); switch( rng( 1, 10 ) ) { case 1: if( one_in( 2 ) ) { @@ -3175,25 +3175,23 @@ ret_val Character::can_wear( const item &it, bool with_equip_change ) cons } if( it.has_flag( flag_POWERARMOR_MOD ) ) { int max_layer = 2; - std::vector< std::pair< body_part, int > > mod_parts; - std::vector< std::pair< body_part, bool > > attachments; - body_part bp = num_bp; - bodypart_str_id bpid; + std::vector< std::pair< bodypart_str_id, int > > mod_parts; + std::vector< std::pair< bodypart_str_id, bool > > attachments; bool lhs = false; bool rhs = false; - for( std::size_t i = 0; i < static_cast< body_part >( num_bp ); ++i ) { - bp = static_cast< body_part >( i ); - if( it.get_covered_body_parts().test( convert_bp( bp ) ) ) { + const auto &all_bps = get_all_body_parts(); + for( const bodypart_id &bp : all_bps ) { + if( it.get_covered_body_parts().test( bp.id() ) ) { mod_parts.emplace_back( bp, 0 ); attachments.emplace_back( bp, false ); } } for( auto &elem : worn ) { // To check if there's an external/exoskeleton for the mod to attach to. - for( std::pair< body_part, bool > &attachment : attachments ) { - if( elem->get_covered_body_parts().test( convert_bp( attachment.first ) ) && + for( std::pair< bodypart_str_id, bool > &attachment : attachments ) { + if( elem->get_covered_body_parts().test( attachment.first ) && ( elem->has_flag( flag_POWERARMOR_EXO ) || elem->has_flag( flag_POWERARMOR_EXTERNAL ) ) ) { - if( elem->is_sided() && elem->get_side() == bpid->part_side ) { + if( elem->is_sided() && elem->get_side() == attachment.first->part_side ) { attachment.second = true; } else { attachment.second = true; @@ -3201,11 +3199,10 @@ ret_val Character::can_wear( const item &it, bool with_equip_change ) cons } } // To check how many mods are on a given part. - for( std::pair< body_part, int > &mod_part : mod_parts ) { - bpid = convert_bp( mod_part.first ); - if( elem->get_covered_body_parts().test( bpid ) && + for( std::pair< bodypart_str_id, int > &mod_part : mod_parts ) { + if( elem->get_covered_body_parts().test( mod_part.first ) && elem->has_flag( flag_POWERARMOR_MOD ) ) { - if( elem->is_sided() && elem->get_side() == bpid->part_side ) { + if( elem->is_sided() && elem->get_side() == mod_part.first->part_side ) { mod_part.second++; } else { mod_part.second++; @@ -3213,21 +3210,20 @@ ret_val Character::can_wear( const item &it, bool with_equip_change ) cons } } } - for( std::pair< body_part, bool > &attachment : attachments ) { + for( std::pair< bodypart_str_id, bool > &attachment : attachments ) { if( !attachment.second ) { return ret_val::make_failure( _( "Nothing to attach the mod to!" ) ); } } - for( std::pair< body_part, int > &mod_part : mod_parts ) { - bpid = convert_bp( mod_part.first ); - if( static_cast< body_part >( mod_part.first ) == bp_torso ) { + for( std::pair< bodypart_str_id, int > &mod_part : mod_parts ) { + if( mod_part.first == body_part_torso ) { max_layer = 3; } if( mod_part.second >= max_layer ) { - if( !it.is_sided() || bpid->part_side == side::BOTH ) { + if( !it.is_sided() || mod_part.first->part_side == side::BOTH ) { return ret_val::make_failure( _( "Can't wear any more mods on that body part!" ) ); } else { - if( bpid->part_side == side::LEFT ) { + if( mod_part.first->part_side == side::LEFT ) { lhs = true; } else { rhs = true; @@ -3483,27 +3479,23 @@ ret_val Character::can_swap( const item &it ) const { if( it.has_flag( flag_POWERARMOR_MOD ) ) { int max_layer = 2; - std::vector< std::pair< body_part, int > > mod_parts; - body_part bp = num_bp; - bodypart_str_id bpid; - for( std::size_t i = 0; i < static_cast< body_part >( num_bp ); ++i ) { - bp = static_cast< body_part >( i ); - bpid = convert_bp( bp ); - if( it.get_covered_body_parts().test( bpid ) && bpid->part_side != side::BOTH ) { + std::vector< std::pair< bodypart_str_id, int > > mod_parts; + const auto &all_bps = get_all_body_parts(); + for( const bodypart_id &bp : all_bps ) { + if( it.get_covered_body_parts().test( bp.id() ) && bp->part_side != side::BOTH ) { mod_parts.emplace_back( bp, 0 ); } } for( auto &elem : worn ) { - for( std::pair< body_part, int > &mod_part : mod_parts ) { - bpid = convert_bp( mod_part.first ); + for( std::pair< bodypart_str_id, int > &mod_part : mod_parts ) { + bodypart_str_id bpid = mod_part.first; if( elem->get_covered_body_parts().test( bpid->opposite_part ) && elem->has_flag( flag_POWERARMOR_MOD ) ) { mod_part.second++; } } } - for( std::pair< body_part, int > &mod_part : mod_parts ) { - bpid = convert_bp( mod_part.first ); + for( std::pair< bodypart_str_id, int > &mod_part : mod_parts ) { if( mod_part.second >= max_layer ) { return ret_val::make_failure( _( "There is no space on the opposite side!" ) ); } @@ -4033,6 +4025,10 @@ char_encumbrance_data Character::calc_encumbrance( const item &new_item ) const { char_encumbrance_data enc; + // Make sure we have all body parts here, so that we can use ::at + for( const bodypart_id &bp : get_all_body_parts() ) { + enc.elems[bp.id()]; + } item_encumb( enc, new_item ); mut_cbm_encumb( enc ); @@ -4066,9 +4062,14 @@ char_encumbrance_data Character::get_encumbrance( const item &new_item ) const return calc_encumbrance( new_item ); } -int Character::extraEncumbrance( const layer_level level, const int bp ) const +int Character::extra_encumbrance( layer_level level, const bodypart_str_id &bp ) const { - return encumbrance_cache->elems[bp].layer_penalty_details[static_cast( level )].total; + auto iter = encumbrance_cache->elems.find( bp ); + if( iter != encumbrance_cache->elems.end() ) { + return iter->second.layer_penalty_details[static_cast( level )].total; + } + + return 0; } bool Character::change_side( item &it, bool interactive ) @@ -4119,7 +4120,7 @@ bool Character::change_side( item *it, bool interactive ) static void layer_item( char_encumbrance_data &vals, const item &it, - std::array &highest_layer_so_far, + std::map &highest_layer_so_far, const Character &c ) { body_part_set covered_parts = it.get_covered_body_parts(); @@ -4146,17 +4147,17 @@ static void layer_item( char_encumbrance_data &vals, layering_encumbrance = 0; } - highest_layer_so_far[bp->token] = - std::max( highest_layer_so_far[bp->token], item_layer ); + highest_layer_so_far[bp.id()] = + std::max( highest_layer_so_far[bp.id()], item_layer ); // Apply layering penalty to this layer, as well as any layer worn // within it that would normally be worn outside of it. for( layer_level penalty_layer = item_layer; - penalty_layer <= highest_layer_so_far[bp->token]; ++penalty_layer ) { - vals.elems[bp->token].layer( penalty_layer, layering_encumbrance ); + penalty_layer <= highest_layer_so_far[bp.id()]; ++penalty_layer ) { + vals.elems[bp.id()].layer( penalty_layer, layering_encumbrance ); } - vals.elems[bp->token].armor_encumbrance += encumber_val; + vals.elems[bp.id()].armor_encumbrance += encumber_val; } } @@ -4353,9 +4354,12 @@ void Character::item_encumb( char_encumbrance_data &vals, const item &new_item ) // Track highest layer observed so far so we can penalize out-of-order // items - std::array highest_layer_so_far; - std::fill( highest_layer_so_far.begin(), highest_layer_so_far.end(), - PERSONAL_LAYER ); + std::map highest_layer_so_far; + const auto &all_bps = get_all_body_parts(); + + for( const bodypart_id &bp : all_bps ) { + highest_layer_so_far[bp.id()] = PERSONAL_LAYER; + } for( auto w_it = worn.begin(); w_it != worn.end(); ++w_it ) { if( w_it == new_item_position ) { @@ -4369,19 +4373,25 @@ void Character::item_encumb( char_encumbrance_data &vals, const item &new_item ) } // make sure values are sane - for( const body_part bp : all_body_parts ) { - encumbrance_data &elem = vals.elems[bp]; + for( const bodypart_id &bp : all_bps ) { + encumbrance_data &elem = vals.elems[bp.id()]; elem.armor_encumbrance = std::max( 0, elem.armor_encumbrance ); // Add armor and layering penalties for the final values elem.encumbrance += elem.armor_encumbrance + elem.layer_penalty; } + // @todo Debugmsg if there are bps not on our body list } int Character::encumb( const bodypart_str_id &bp ) const { - return encumbrance_cache->elems[bp->token].encumbrance; + const auto iter = encumbrance_cache->elems.find( bp ); + if( iter != encumbrance_cache->elems.end() ) { + // @todo Debugmsg? + return iter->second.encumbrance; + } + return 0; } static void apply_mut_encumbrance( char_encumbrance_data &vals, @@ -4389,12 +4399,12 @@ static void apply_mut_encumbrance( char_encumbrance_data &vals, const body_part_set &oversize ) { for( const std::pair &enc : mut->encumbrance_always ) { - vals.elems[enc.first].encumbrance += enc.second; + vals.elems[convert_bp( enc.first )].encumbrance += enc.second; } for( const std::pair &enc : mut->encumbrance_covered ) { if( !oversize.test( convert_bp( enc.first ) ) ) { - vals.elems[enc.first].encumbrance += enc.second; + vals.elems[convert_bp( enc.first )].encumbrance += enc.second; } } } @@ -4404,15 +4414,15 @@ void Character::mut_cbm_encumb( char_encumbrance_data &vals ) const for( const bionic_id &bid : get_bionics() ) { for( const std::pair &element : bid->encumbrance ) { - vals.elems[element.first->token].encumbrance += element.second; + vals.elems[element.first].encumbrance += element.second; } } if( has_active_bionic( bio_shock_absorber ) ) { for( auto &val : vals.elems ) { - val.encumbrance += 3; // Slight encumbrance to all parts except eyes + val.second.encumbrance += 3; // Slight encumbrance to all parts except eyes } - vals.elems[bp_eyes].encumbrance -= 3; + vals.elems[body_part_eyes].encumbrance -= 3; } // Lower penalty for bps covered only by XL armor @@ -5675,13 +5685,13 @@ void Character::update_bodytemp( const map &m, const weather_manager &weather ) temp_equalizer( *this, body_part_leg_l, body_part_foot_l ); temp_equalizer( *this, body_part_leg_r, body_part_foot_r ); + const auto &all_bps = get_all_body_parts(); for( const item * const &it : worn ) { // TODO: Port body part set id changes const body_part_set &covered = it->get_covered_body_parts(); - for( size_t i = 0; i < num_bp; i++ ) { - body_part token = static_cast( i ); - if( covered.test( convert_bp( token ) ) ) { - clothing_map[convert_bp( token )].emplace_back( it ); + for( const bodypart_id &bp : all_bps ) { + if( covered.test( bp.id() ) ) { + clothing_map[bp.id()].emplace_back( it ); } if( it->has_flag( flag_HOOD ) ) { bonus_clothing_map[body_part_head].emplace_back( it ); @@ -6154,10 +6164,10 @@ bodypart_str_id Character::body_window( const std::string &menu_header, const int current_hp = get_part_hp_cur( bp ); // This will c_light_gray if the part does not have any effects cured by the item/effect // (e.g. it cures only bites, but the part does not have a bite effect) - const nc_color state_col = limb_color( bp, bleed > 0.0f, bite > 0.0f, infect > 0.0f ); + const nc_color state_col = limb_color( bp.id(), bleed > 0.0f, bite > 0.0f, infect > 0.0f ); const bool has_curable_effect = state_col != c_light_gray; // The same as in the main UI sidebar. Independent of the capability of the healing item/effect! - const nc_color all_state_col = limb_color( bp, true, true, true ); + const nc_color all_state_col = limb_color( bp.id(), true, true, true ); // Broken means no HP can be restored, it requires surgical attention. const bool limb_is_broken = is_limb_broken( bp ); @@ -6313,21 +6323,21 @@ bodypart_str_id Character::body_window( const std::string &menu_header, } } -nc_color Character::limb_color( const bodypart_id &bp, bool bleed, bool bite, bool infect ) const +nc_color Character::limb_color( const bodypart_str_id &bp, bool bleed, bool bite, + bool infect ) const { - if( bp == bodypart_id( "num_bp" ) ) { + if( !bp ) { return c_light_gray; } - const bodypart_str_id &bp_str = bp.id(); int color_bit = 0; nc_color i_color = c_light_gray; - if( bleed && has_effect( effect_bleed, bp_str ) ) { + if( bleed && has_effect( effect_bleed, bp ) ) { color_bit += 1; } - if( bite && has_effect( effect_bite, bp_str ) ) { + if( bite && has_effect( effect_bite, bp ) ) { color_bit += 10; } - if( infect && has_effect( effect_infected, bp_str ) ) { + if( infect && has_effect( effect_infected, bp ) ) { color_bit += 100; } switch( color_bit ) { @@ -6838,13 +6848,9 @@ std::string Character::extended_description() const // This is a stripped-down version of the body_window function // This should be extracted into a separate function later on for( const bodypart_id &bp : bps ) { - // Hide appendix from the player - if( bp->id.str() == "num_bp" ) { - continue; - } const std::string &bp_heading = body_part_name_as_heading( bp->token, 1 ); - const nc_color state_col = limb_color( bp, true, true, true ); + const nc_color state_col = limb_color( bp.id(), true, true, true ); nc_color name_color = state_col; std::pair hp_bar = get_hp_bar( get_part_hp_cur( bp ), get_part_hp_max( bp ), false ); @@ -8750,7 +8756,7 @@ void Character::apply_damage( Creature *source, item *source_weapon, item *sourc return; } - if( hurt == bodypart_id( "num_bp" ) ) { + if( hurt.id().is_null() ) { debugmsg( "Wacky body part hurt!" ); hurt = bodypart_id( "torso" ); } @@ -8822,8 +8828,7 @@ dealt_damage_instance Character::deal_damage( Creature *source, bodypart_id bp, return dealt_damage_instance(); } - const body_part bp_token = bp->token; - if( bp_token == num_bp ) { + if( bp.id().is_null() ) { debugmsg( "Wacky bodypart hit!" ); return dealt_damage_instance(); } diff --git a/src/character.h b/src/character.h index 84514a24ee84..357dadac41d6 100644 --- a/src/character.h +++ b/src/character.h @@ -499,7 +499,7 @@ class Character : public Creature, public location_visitable /** Get encumbrance for all body parts as if `new_item` was also worn. */ char_encumbrance_data get_encumbrance( const item &new_item ) const; /** Get encumbrance penalty per layer & body part */ - int extraEncumbrance( layer_level level, int bp ) const; + int extra_encumbrance( layer_level level, const bodypart_str_id &bp ) const; /** Returns true if the character is wearing power armor */ bool is_wearing_power_armor( bool *hasHelmet = nullptr ) const; @@ -798,7 +798,7 @@ class Character : public Creature, public location_visitable float bleed, float bite, float infect, float bandage_power, float disinfectant_power ) const; // Returns color which this limb would have in healing menus - nc_color limb_color( const bodypart_id &bp, bool bleed, bool bite, bool infect ) const; + nc_color limb_color( const bodypart_str_id &bp, bool bleed, bool bite, bool infect ) const; static const std::vector fleshy; bool made_of( const material_id &m ) const override; diff --git a/src/character_display.cpp b/src/character_display.cpp index 10fb99b3e5aa..9b31390152b0 100644 --- a/src/character_display.cpp +++ b/src/character_display.cpp @@ -64,11 +64,6 @@ static int get_temp_conv( const Character &c, const bodypart_str_id &bp ) return iter->second.get_temp_conv(); } -static int get_temp_conv( const Character &c, body_part bp ) -{ - return get_temp_conv( c, convert_bp( bp ) ); -} - nc_color warmth::bodytemp_color( const Character &c, const bodypart_str_id &bp ) { if( bp == body_part_eyes ) { @@ -100,39 +95,35 @@ static int temperature_print_rescaling( int temp ) return ( temp / 100.0 ) * 2 - 100; } -static body_part other_part( body_part bp ) -{ - return static_cast( bp_aiOther[bp] ); -} - -static bool should_combine_bps( const Character &ch, body_part l, body_part r, +static bool should_combine_bps( const Character &ch, + const bodypart_str_id &l, const bodypart_str_id &r, const item *selected_clothing ) { const char_encumbrance_data enc_data = ch.get_encumbrance(); return l != r && // are different parts - l == other_part( r ) && r == other_part( l ) && // are complementary parts + l == r->opposite_part && r == l->opposite_part && // are complementary parts // same encumberance & temperature - enc_data.elems[l] == enc_data.elems[r] && + // @todo Is ::at safe here? + enc_data.elems.at( l ) == enc_data.elems.at( r ) && temperature_print_rescaling( get_temp_conv( ch, l ) ) == temperature_print_rescaling( get_temp_conv( ch, r ) ) && // selected_clothing covers both or neither parts ( !selected_clothing || - ( selected_clothing->covers( convert_bp( l ).id() ) == selected_clothing->covers( convert_bp( - r ).id() ) ) ); + ( selected_clothing->covers( l.id() ) == selected_clothing->covers( r.id() ) ) ); } -static std::vector> list_and_combine_bps( const Character &ch, +static std::vector> list_and_combine_bps( const Character &ch, const item *selected_clothing ) { // bool represents whether the part has been combined with its other half - std::vector> bps; - for( auto bp : all_body_parts ) { + std::vector> bps; + for( auto bp : ch.get_all_body_parts() ) { // assuming that a body part has at most one other half - if( other_part( other_part( bp ) ) != bp ) { - debugmsg( "Bodypart %d has more than one other half!", bp ); + if( bp->opposite_part->opposite_part != bp.id() ) { + debugmsg( "Bodypart %s has more than one other half!", bp.id().c_str() ); } - if( should_combine_bps( ch, bp, other_part( bp ), selected_clothing ) ) { - if( bp < other_part( bp ) ) { + if( should_combine_bps( ch, bp.id(), bp->opposite_part, selected_clothing ) ) { + if( bp.to_i() < bp->opposite_part.id().to_i() ) { // only add the earlier one bps.emplace_back( bp, true ); } @@ -168,7 +159,8 @@ void character_display::print_encumbrance( ui_adaptor &ui, const catacurses::win const int line, const item *selected_clothing ) { // bool represents whether the part has been combined with its other half - const std::vector> bps = list_and_combine_bps( ch, selected_clothing ); + const std::vector> bps = list_and_combine_bps( ch, + selected_clothing ); // width/height excluding title & scrollbar const int height = getmaxy( win ) - 1; @@ -191,11 +183,10 @@ void character_display::print_encumbrance( ui_adaptor &ui, const catacurses::win if( static_cast( thisline ) >= bps.size() ) { break; } - const body_part bp = bps[thisline].first; + const bodypart_str_id &bp = bps[thisline].first; const bool combine = bps[thisline].second; - const encumbrance_data &e = enc_data.elems[bp]; - const bool highlighted = selected_clothing ? selected_clothing->covers( convert_bp( - bp ).id() ) : false; + const encumbrance_data &e = enc_data.elems.at( bp ); + const bool highlighted = selected_clothing ? selected_clothing->covers( bp.id() ) : false; std::string out = body_part_name_as_heading( bp, combine ? 2 : 1 ); if( utf8_width( out ) > 7 ) { out = utf8_truncate( out, 7 ); @@ -221,7 +212,7 @@ void character_display::print_encumbrance( ui_adaptor &ui, const catacurses::win mvwprintz( win, point( 12, y_pos ), encumb_color( e.encumbrance ), "%-3d", e.layer_penalty ); // print warmth, tethered to right hand side of the window - mvwprintz( win, point( width - 6, y_pos ), warmth::bodytemp_color( ch, convert_bp( bp ) ), "(% 3d)", + mvwprintz( win, point( width - 6, y_pos ), warmth::bodytemp_color( ch, bp ), "(% 3d)", temperature_print_rescaling( get_temp_conv( ch, bp ) ) ); } @@ -276,13 +267,14 @@ static int get_encumbrance( const Character &p, body_part bp, bool combine ) return p.encumb( convert_bp( bp ) ) * ( ( combine && combines_with_other ) ? 2 : 1 ); } -static std::string get_encumbrance_description( const Character &p, body_part bp, bool combine ) +static std::string get_encumbrance_description( const Character &p, const bodypart_str_id &bp, + bool combine ) { std::string s; - const int eff_encumbrance = get_encumbrance( p, bp, combine ); + const int eff_encumbrance = get_encumbrance( p, bp->token, combine ); - switch( bp ) { + switch( bp->token ) { case bp_torso: { const int melee_roll_pen = std::max( -eff_encumbrance, -80 ); s += string_format( _( "Melee attack rolls: %+d%%\n" ), melee_roll_pen ); @@ -554,10 +546,10 @@ static void draw_encumbrance_tab( ui_adaptor &ui, const catacurses::window &w_en static void draw_encumbrance_info( const catacurses::window &w_info, const Character &you, const unsigned line ) { - const std::vector> bps = list_and_combine_bps( you, nullptr ); + const std::vector> bps = list_and_combine_bps( you, nullptr ); werase( w_info ); - body_part bp = num_bp; + bodypart_str_id bp; bool combined_here = false; if( line < bps.size() ) { bp = bps[line].first; @@ -1118,7 +1110,7 @@ static bool handle_player_display_action( Character &you, unsigned int &line, line_end = 6; break; case player_display_tab::encumbrance: { - const std::vector> bps = list_and_combine_bps( you, nullptr ); + const std::vector> bps = list_and_combine_bps( you, nullptr ); line_end = bps.size(); break; } diff --git a/src/character_encumbrance.h b/src/character_encumbrance.h index aa610d635a10..d4416445cccb 100644 --- a/src/character_encumbrance.h +++ b/src/character_encumbrance.h @@ -49,7 +49,7 @@ struct encumbrance_data { }; struct char_encumbrance_data { - std::array elems; + std::map elems; }; #endif // CATA_SRC_CHARACTER_ENCUMBRANCE_H diff --git a/src/character_functions.cpp b/src/character_functions.cpp index db417baaeead..770919d05bc4 100644 --- a/src/character_functions.cpp +++ b/src/character_functions.cpp @@ -474,12 +474,12 @@ std::string fmt_wielded_weapon( const Character &who ) } } -void add_pain_msg( const Character &who, int val, body_part bp ) +void add_pain_msg( const Character &who, int val, const bodypart_str_id &bp ) { if( who.has_trait( trait_NOPAIN ) ) { return; } - if( bp == num_bp ) { + if( !bp ) { if( val > 20 ) { who.add_msg_if_player( _( "Your body is wracked with excruciating pain!" ) ); } else if( val > 10 ) { @@ -494,19 +494,19 @@ void add_pain_msg( const Character &who, int val, body_part bp ) } else { if( val > 20 ) { who.add_msg_if_player( _( "Your %s is wracked with excruciating pain!" ), - body_part_name_accusative( bp ) ); + body_part_name_accusative( bp.id() ) ); } else if( val > 10 ) { who.add_msg_if_player( _( "Your %s is wracked with terrible pain!" ), - body_part_name_accusative( bp ) ); + body_part_name_accusative( bp.id() ) ); } else if( val > 5 ) { who.add_msg_if_player( _( "Your %s is wracked with pain!" ), - body_part_name_accusative( bp ) ); + body_part_name_accusative( bp.id() ) ); } else if( val > 1 ) { who.add_msg_if_player( _( "Your %s pains you!" ), - body_part_name_accusative( bp ) ); + body_part_name_accusative( bp.id() ) ); } else { who.add_msg_if_player( _( "Your %s aches." ), - body_part_name_accusative( bp ) ); + body_part_name_accusative( bp.id() ) ); } } } diff --git a/src/character_functions.h b/src/character_functions.h index 3a073c2edbbc..cb9422ee8b4b 100644 --- a/src/character_functions.h +++ b/src/character_functions.h @@ -118,9 +118,9 @@ std::string fmt_wielded_weapon( const Character &who ); * Add message describing how character feels pain. * @param who Character that feels the pain * @param val Amount of pain - * @param bp Target body part, use num_bp if no specific body part. + * @param bp Target body part, use bodypart_str_id::NULL_ID() if no specific body part. @todo Consider std::optional? */ -void add_pain_msg( const Character &who, int val, body_part bp ); +void add_pain_msg( const Character &who, int val, const bodypart_str_id &bp ); /** Reset Character's weapon and body state (limb hp, stamina, active martial art) */ void normalize( Character &who ); diff --git a/src/character_turn.cpp b/src/character_turn.cpp index 086a3ce4a18d..90c9589b28ca 100644 --- a/src/character_turn.cpp +++ b/src/character_turn.cpp @@ -339,7 +339,7 @@ void Character::process_one_effect( effect &it, bool is_new ) { bool reduced = resists_effect( it ); double mod = 1; - body_part bp = it.get_bp()->token; + bodypart_str_id bp = it.get_bp(); int val = 0; // Still hardcoded stuff, do this first since some modify their other traits @@ -489,7 +489,7 @@ void Character::process_one_effect( effect &it, bool is_new ) } } if( is_new || it.activated( calendar::turn, "HURT", val, reduced, mod ) ) { - if( bp == num_bp ) { + if( !bp ) { if( val > 5 ) { add_msg_if_player( _( "Your %s HURTS!" ), body_part_name_accusative( bp_torso ) ); } else { @@ -502,7 +502,7 @@ void Character::process_one_effect( effect &it, bool is_new ) } else { add_msg_if_player( _( "Your %s hurts!" ), body_part_name_accusative( bp ) ); } - apply_damage( nullptr, convert_bp( bp ).id(), val, true ); + apply_damage( nullptr, bp.id(), val, true ); } } } diff --git a/src/creature.cpp b/src/creature.cpp index 2623c073312a..3a8a73247231 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -589,7 +589,7 @@ void Creature::deal_melee_hit( Creature *source, item *source_weapon, int hit_sp const damage_instance &dam, dealt_damage_instance &dealt_dam ) { if( source == nullptr || source->is_hallucination() ) { - dealt_dam.bp_hit = anatomy_id( "human_anatomy" )->random_body_part()->token; + dealt_dam.bp_hit = anatomy_id( "human_anatomy" )->random_body_part().id(); return; } // If carrying a rider, there is a chance the hits may hit rider instead. @@ -607,12 +607,11 @@ void Creature::deal_melee_hit( Creature *source, item *source_weapon, int hit_sp } damage_instance d = dam; // copy, since we will mutate in block_hit bodypart_id bp_hit = select_body_part( source, hit_spread ).id(); - const body_part bp_token = bp_hit->token; block_hit( source, bp_hit, d ); on_hit( source, bp_hit ); // trigger on-gethit events dealt_dam = deal_damage( source, bp_hit, d, source_weapon ); - dealt_dam.bp_hit = bp_token; + dealt_dam.bp_hit = bp_hit.id(); } void Creature::deal_melee_hit( Creature *source, int hit_spread, bool critical_hit, const damage_instance &dam, dealt_damage_instance &dealt_dam ) @@ -647,11 +646,11 @@ void print_dmg_msg( Creature &target, Creature *source, const dealt_damage_insta if( dealt_dam.total_damage() == 0 ) { //~ 1$ - monster name, 2$ - character's bodypart or monster's skin/armor add_msg( _( "The shot reflects off %1$s %2$s!" ), target.disp_name( true ), - ( target.is_monster() || dealt_dam.bp_hit == num_bp ) ? + ( target.is_monster() || !dealt_dam.bp_hit ) ? target.skin_name() : - body_part_name_accusative( dealt_dam.bp_hit ) ); + dealt_dam.bp_hit->accusative.translated() ); } else if( target.is_player() ) { - if( dealt_dam.bp_hit != bodypart_str_id::NULL_ID()->token ) { + if( dealt_dam.bp_hit ) { //monster hits player ranged //~ Hit message. 1$s is bodypart name in accusative. 2$d is damage value. target.add_msg_if_player( m_bad, _( "You were hit in the %1$s for %2$d damage." ), @@ -861,7 +860,7 @@ void Creature::deal_projectile_attack( Creature *source, item *source_weapon, block_ranged_hit( source, bp_hit, impact ); // If the projectile survives, both it and the launcher get credit for the kill. dealt_dam = deal_damage( source, bp_hit, impact, source_weapon, attack.proj.get_drop() ); - dealt_dam.bp_hit = bp_hit->token; + dealt_dam.bp_hit = bp_hit.id(); // Apply ammo effects to target. if( proj.has_effect( ammo_effect_TANGLE ) ) { @@ -872,7 +871,7 @@ void Creature::deal_projectile_attack( Creature *source, item *source_weapon, if( z ) { detached_ptr drop_item = proj.unset_drop(); if( drop_item ) { - z->add_effect( effect_tied, 1_turns, num_bp ); + z->add_effect( effect_tied, 1_turns ); z->set_tied_item( std::move( drop_item ) ); } else { add_msg( m_debug, "projectile with TANGLE effect, but no drop item specified" ); @@ -1264,7 +1263,7 @@ bool Creature::remove_effect( const efftype_id &eff_id, const bodypart_str_id &b g->events().send( ch->getID(), eff_id ); } - // num_bp means remove all of a given effect id + // null bp means remove all of a given effect id if( !bp ) { for( auto &it : ( *effects )[eff_id] ) { auto &e = it.second; @@ -1291,7 +1290,7 @@ bool Creature::has_effect( const efftype_id &eff_id ) const } bool Creature::has_effect( const efftype_id &eff_id, const bodypart_str_id &bp ) const { - // num_bp means anything targeted or not + // null bp means anything, non-null means only that bp if( !bp ) { auto got = effects->find( eff_id ); return got != effects->end() && !got->second.begin()->second.is_removed(); @@ -1840,7 +1839,7 @@ std::vector Creature::get_all_body_parts( bool only_main ) const int Creature::get_hp( const bodypart_id &bp ) const { - if( bp != bodypart_id( "num_bp" ) ) { + if( bp ) { return get_part_hp_cur( bp ); } int hp_total = 0; @@ -1852,12 +1851,12 @@ int Creature::get_hp( const bodypart_id &bp ) const int Creature::get_hp() const { - return get_hp( bodypart_id( "num_bp" ) ); + return get_hp( bodypart_str_id::NULL_ID().id() ); } int Creature::get_hp_max( const bodypart_id &bp ) const { - if( bp != bodypart_id( "num_bp" ) ) { + if( bp ) { return get_part_hp_max( bp ); } int hp_total = 0; @@ -1869,7 +1868,7 @@ int Creature::get_hp_max( const bodypart_id &bp ) const int Creature::get_hp_max() const { - return get_hp_max( bodypart_id( "num_bp" ) ); + return get_hp_max( bodypart_str_id::NULL_ID().id() ); } int Creature::get_speed_base() const diff --git a/src/damage.h b/src/damage.h index aafa70fc3218..5227c702b2bb 100644 --- a/src/damage.h +++ b/src/damage.h @@ -108,7 +108,7 @@ struct damage_instance { struct dealt_damage_instance { std::array dealt_dams; - body_part bp_hit; + bodypart_str_id bp_hit; dealt_damage_instance(); void set_damage( damage_type dt, int amount ); diff --git a/src/effect.cpp b/src/effect.cpp index 2ed80b6e8dfe..b9bd65cade6c 100644 --- a/src/effect.cpp +++ b/src/effect.cpp @@ -600,7 +600,7 @@ std::string effect::disp_name() const } } } - if( bp != num_bp ) { + if( bp ) { ret += string_format( " (%s)", body_part_name( bp ) ); } @@ -850,7 +850,7 @@ time_point effect::get_start_time() const const bodypart_str_id &effect::get_bp() const { - return convert_bp( bp ); + return bp; } bool effect::is_permanent() const @@ -1456,7 +1456,7 @@ void effect::serialize( JsonOut &json ) const json.start_object(); json.member( "eff_type", eff_type != nullptr ? eff_type->id.str() : "" ); json.member( "duration", duration ); - json.member( "bp", static_cast( bp ) ); + json.member( "bp", bp ); json.member( "intensity", intensity ); json.member( "start_turn", start_time ); // Legacy @@ -1471,7 +1471,13 @@ void effect::deserialize( JsonIn &jsin ) const efftype_id id( jo.get_string( "eff_type" ) ); eff_type = &id.obj(); jo.read( "duration", duration ); - bp = static_cast( jo.get_int( "bp" ) ); + // @todo Remove after stable + if( jo.has_int( "bp" ) ) { + bp = convert_bp( static_cast( jo.get_int( "bp" ) ) ); + } else { + bp = bodypart_str_id( jo.get_string( "bp" ) ); + + } intensity = jo.get_int( "intensity" ); start_time = calendar::turn_zero; jo.read( "start_turn", start_time ); @@ -1584,7 +1590,7 @@ std::vector effect::create_child_effects( bool decay ) const const effect_type *new_effect_type = &*new_effect.type; time_duration dur = new_effect.inherit_duration ? this->duration : new_effect.duration; int intensity = new_effect.inherit_intensity ? this->intensity : new_effect.intensity; - bodypart_str_id bp = new_effect.inherit_body_part ? convert_bp( this->bp ) : new_effect.bp; + bodypart_str_id bp = new_effect.inherit_body_part ? this->bp : new_effect.bp; effect e = effect( new_effect_type, dur, bp, intensity, calendar::turn ); ret.emplace_back( e ); } diff --git a/src/effect.h b/src/effect.h index 127445ca72d1..d639b5219b98 100644 --- a/src/effect.h +++ b/src/effect.h @@ -218,13 +218,13 @@ class effect_type class effect { public: - effect() : eff_type( nullptr ), duration( 0_turns ), bp( num_bp ), + effect() : eff_type( nullptr ), duration( 0_turns ), bp(), intensity( 1 ), start_time( calendar::turn_zero ), removed( true ) { } effect( const effect_type *peff_type, const time_duration &dur, const bodypart_str_id &part, int nintensity, const time_point &nstart_time ) : - eff_type( peff_type ), duration( dur ), bp( part->token ), + eff_type( peff_type ), duration( dur ), bp( part ), intensity( nintensity ), start_time( nstart_time ), removed( false ) { } @@ -378,7 +378,7 @@ class effect protected: const effect_type *eff_type; time_duration duration; - body_part bp; + bodypart_str_id bp; int intensity; time_point start_time; bool removed; diff --git a/src/game.cpp b/src/game.cpp index 460c6f458566..d03f8170f588 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -740,7 +740,7 @@ bool game::start_game() for( const mtype_id &elem : u.starting_pets ) { if( monster *const mon = place_critter_around( elem, u.pos(), 5 ) ) { mon->friendly = -1; - mon->add_effect( effect_pet, 1_turns, num_bp ); + mon->add_effect( effect_pet, 1_turns ); } else { add_msg( m_debug, "cannot place starting pet, no space!" ); } @@ -4893,14 +4893,14 @@ bool game::revive_corpse( const tripoint &p, item &it ) } critter.no_extra_death_drops = true; - critter.add_effect( effect_downed, 5_turns, num_bp ); + critter.add_effect( effect_downed, 5_turns ); for( detached_ptr &component : it.remove_components() ) { critter.add_corpse_component( std::move( component ) ); } if( it.get_var( "zlave" ) == "zlave" ) { - critter.add_effect( effect_pacified, 1_turns, num_bp ); - critter.add_effect( effect_pet, 1_turns, num_bp ); + critter.add_effect( effect_pacified, 1_turns ); + critter.add_effect( effect_pet, 1_turns ); } if( it.get_var( "no_ammo" ) == "no_ammo" ) { diff --git a/src/item.cpp b/src/item.cpp index 2a61c50f788b..e91f88c5351c 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -4502,23 +4502,21 @@ void item::on_wear( Character &p ) } } else if( has_flag( flag_POWERARMOR_MOD ) ) { // for power armor mods, wear on side with least mods - std::vector< std::pair< body_part, int > > mod_parts; - body_part bp = num_bp; - bodypart_str_id bpid; + std::vector< std::pair< bodypart_str_id, int > > mod_parts; int lhs = 0; int rhs = 0; - for( std::size_t i = 0; i < static_cast< body_part >( num_bp ) ; ++i ) { - bp = static_cast< body_part >( i ); - if( get_covered_body_parts().test( convert_bp( bp ) ) ) { + const auto &all_bps = p.get_all_body_parts(); + for( const bodypart_id &bp : all_bps ) { + if( get_covered_body_parts().test( bp.id() ) ) { mod_parts.emplace_back( bp, 0 ); } } for( auto &elem : p.worn ) { - for( std::pair< body_part, int > &mod_part : mod_parts ) { - bpid = convert_bp( mod_part.first ); - if( elem->get_covered_body_parts().test( bpid ) && + for( std::pair< bodypart_str_id, int > &mod_part : mod_parts ) { + const bodypart_str_id &bp = mod_part.first; + if( elem->get_covered_body_parts().test( bp ) && elem->has_flag( flag_POWERARMOR_MOD ) ) { - if( elem->is_sided() && elem->get_side() == bpid->part_side ) { + if( elem->is_sided() && elem->get_side() == bp->part_side ) { mod_part.second++; continue; } @@ -4526,31 +4524,30 @@ void item::on_wear( Character &p ) } } } - for( std::pair< body_part, int > &mod_part : mod_parts ) { - bpid = convert_bp( mod_part.first ); - if( bpid->part_side == side::LEFT && mod_part.second > lhs ) { - add_msg( _( "left" ) ); + for( std::pair< bodypart_str_id, int > &mod_part : mod_parts ) { + const bodypart_str_id &bp = mod_part.first; + if( bp->part_side == side::LEFT && mod_part.second > lhs ) { lhs = mod_part.second; - } else if( bpid->part_side == side::RIGHT && mod_part.second > rhs ) { - add_msg( _( "right" ) ); + } else if( bp->part_side == side::RIGHT && mod_part.second > rhs ) { rhs = mod_part.second; } } set_side( ( lhs > rhs ) ? side::RIGHT : side::LEFT ); } else { // for sided items wear the item on the side which results in least encumbrance + const auto &all_bps = p.get_all_body_parts(); int lhs = 0; int rhs = 0; set_side( side::LEFT ); const char_encumbrance_data left_enc = p.get_encumbrance( *this ); - for( const body_part bp : all_body_parts ) { - lhs += left_enc.elems[bp].encumbrance; + for( const bodypart_id &bp : all_bps ) { + lhs += left_enc.elems.at( bp.id() ).encumbrance; } set_side( side::RIGHT ); const char_encumbrance_data right_enc = p.get_encumbrance( *this ); - for( const body_part bp : all_body_parts ) { - rhs += right_enc.elems[bp].encumbrance; + for( const bodypart_id &bp : all_bps ) { + rhs += right_enc.elems.at( bp.id() ).encumbrance; } set_side( lhs <= rhs ? side::LEFT : side::RIGHT ); diff --git a/src/iteminfo_armor.cpp b/src/iteminfo_armor.cpp index 42708c26df4b..2ad6b4d2415e 100644 --- a/src/iteminfo_armor.cpp +++ b/src/iteminfo_armor.cpp @@ -339,7 +339,7 @@ void item::armor_info( std::vector &info, const iteminfo_query *parts, continue; } for( const bodypart_str_id &covering_id : piece.covers ) { - if( covering_id != bodypart_str_id( "num_bp" ) ) { + if( covering_id ) { const int encumbrance_when_full = get_encumber_when_containing( you, get_total_capacity(), covering_id.id() ); to_display_data[covering_id] = { covering_id.obj().name_as_heading, { diff --git a/src/iuse.cpp b/src/iuse.cpp index 6f87d4fbadd9..c52298cf0412 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -4306,7 +4306,7 @@ int iuse::dog_whistle( player *p, item *it, bool, const tripoint & ) if( u_see ) { p->add_msg_if_player( _( "Your %s goes docile." ), critter.name() ); } - critter.add_effect( effect_docile, 1_turns, num_bp ); + critter.add_effect( effect_docile, 1_turns ); } } } @@ -4979,7 +4979,7 @@ int iuse::artifact( player *p, item *it, bool, const tripoint & ) for( int j = 0; j < num; j++ ) { if( monster *const b = g->place_critter_around( bug, p->pos(), 1 ) ) { b->friendly = -1; - b->add_effect( effect_pet, 1_turns, num_bp ); + b->add_effect( effect_pet, 1_turns ); } } } @@ -5757,7 +5757,7 @@ int iuse::robotcontrol( player *p, item *it, bool, const tripoint & ) if( critter.friendly != 0 && critter.type->in_species( ROBOT ) ) { p->add_msg_if_player( _( "A following %s goes into passive mode." ), critter.name() ); - critter.add_effect( effect_docile, 1_turns, num_bp ); + critter.add_effect( effect_docile, 1_turns ); f = 1; } } @@ -8004,7 +8004,7 @@ static bool multicooker_hallu( player &p ) add_msg( m_warning, _( "The multi-cooker runs away!" ) ); if( monster *const m = g->place_critter_around( mon_hallu_multicooker, p.pos(), 1 ) ) { m->hallucination = true; - m->add_effect( effect_run, 100_turns, num_bp ); + m->add_effect( effect_run, 100_turns ); } } else { p.add_msg_if_player( m_info, _( "You're surrounded by aggressive multi-cookers!" ) ); diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index 3cebfd5cd9d2..abed5e974ee4 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -1125,7 +1125,7 @@ int place_monster_iuse::use( player &p, item &it, bool, const tripoint &pos ) co } newmon.friendly = -1; if( is_pet ) { - newmon.add_effect( effect_pet, 1_turns, num_bp ); + newmon.add_effect( effect_pet, 1_turns ); } } // Transfer label from the item to monster nickname diff --git a/src/magic_spell_effect.cpp b/src/magic_spell_effect.cpp index 260d437766d2..ef23c27e1536 100644 --- a/src/magic_spell_effect.cpp +++ b/src/magic_spell_effect.cpp @@ -151,7 +151,7 @@ void spell_effect::pain_split( const spell &sp, Creature &caster, const tripoint int total_hp = 0; // total hp among limbs for( const std::pair &elem : p->get_body() ) { - if( elem.first == bodypart_str_id( "num_bp" ) ) { + if( !elem.first ) { continue; } num_limbs++; diff --git a/src/map_field.cpp b/src/map_field.cpp index b119b506dc36..35192c81bd90 100644 --- a/src/map_field.cpp +++ b/src/map_field.cpp @@ -1377,12 +1377,9 @@ void map::player_in_field( player &u ) } else { // Lying in the fire is BAAAD news, hits every body part. msg_num = 3; - const std::vector &all_parts = u.get_all_body_parts(); - // HACK: Skip num_bp part - for( auto bp : all_parts ) { - if( bp->token != num_bp ) { - parts_burned.push_back( bp ); - } + const auto &all_bps = u.get_all_body_parts( true ); + for( const auto &bp : all_bps ) { + parts_burned.emplace_back( bp ); } } @@ -1656,7 +1653,7 @@ void map::monster_in_field( monster &z ) const field_type_id cur_field_type = cur.get_field_type(); if( cur_field_type == fd_web ) { if( !z.has_flag( MF_WEBWALK ) ) { - z.add_effect( effect_webbed, 1_turns, num_bp, cur.get_field_intensity() ); + z.add_effect( effect_webbed, 1_turns, bodypart_str_id::NULL_ID(), cur.get_field_intensity() ); cur.set_field_intensity( 0 ); } } diff --git a/src/mattack_actors.cpp b/src/mattack_actors.cpp index a70f031bba4f..9234b133e15e 100644 --- a/src/mattack_actors.cpp +++ b/src/mattack_actors.cpp @@ -325,7 +325,7 @@ bool melee_actor::call( monster &z ) const target->on_hit( &z, bp_hit.id() ); dealt_damage_instance dealt_damage = target->deal_damage( &z, bp_hit.id(), damage ); - dealt_damage.bp_hit = bp_hit->token; + dealt_damage.bp_hit = bp_hit; int damage_total = dealt_damage.total_damage(); add_msg( m_debug, "%s's melee_attack did %d damage", z.name(), damage_total ); @@ -351,13 +351,13 @@ void melee_actor::on_damage( monster &z, Creature &target, dealt_damage_instance sfx::do_player_death_hurt( dynamic_cast( target ), false ); } auto msg_type = target.attitude_to( g->u ) == Attitude::A_FRIENDLY ? m_bad : m_neutral; - const body_part bp = dealt.bp_hit; + const bodypart_str_id bp = dealt.bp_hit; target.add_msg_player_or_npc( msg_type, hit_dmg_u, hit_dmg_npc, z.name(), body_part_name_accusative( bp ) ); for( const auto &eff : effects ) { if( x_in_y( eff.chance, 100 ) ) { - const bodypart_str_id &affected_bp = convert_bp( eff.affect_hit_bp ? bp : eff.bp ); + const bodypart_str_id &affected_bp = eff.affect_hit_bp ? bp : convert_bp( eff.bp ); target.add_effect( eff.id, time_duration::from_turns( eff.duration ), affected_bp ); if( eff.permanent ) { target.get_effect( eff.id, affected_bp ).set_permanent(); @@ -383,7 +383,7 @@ void bite_actor::on_damage( monster &z, Creature &target, dealt_damage_instance { melee_actor::on_damage( z, target, dealt ); if( target.has_effect( effect_grabbed ) && one_in( no_infection_chance - dealt.total_damage() ) ) { - const bodypart_str_id hit = convert_bp( dealt.bp_hit ); + const bodypart_str_id &hit = dealt.bp_hit; if( target.has_effect( effect_bite, hit ) ) { target.add_effect( effect_bite, 40_minutes, hit ); } else if( target.has_effect( effect_infected, hit ) ) { diff --git a/src/melee.cpp b/src/melee.cpp index b89cac9d93ec..bbb975fe29c0 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -653,7 +653,7 @@ void Character::melee_attack( Creature &t, bool allow_special, const matec_id *f check_dead_state(); if( t.as_character() ) { dealt_projectile_attack dp = dealt_projectile_attack(); - t.as_character()->on_hit( this, bodypart_id( "num_bp" ), &dp ); + t.as_character()->on_hit( this, bodypart_str_id::NULL_ID().id(), &dp ); } return; } diff --git a/src/monattack.cpp b/src/monattack.cpp index daa542060ba2..761a323b2393 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -1421,21 +1421,21 @@ bool mattack::science( monster *const z ) // I said SCIENCE again! return true; } -static body_part body_part_hit_by_plant() +static bodypart_str_id body_part_hit_by_plant() { - body_part hit = num_bp; + bodypart_str_id hit; if( one_in( 2 ) ) { - hit = bp_leg_l; + hit = body_part_leg_l; } else { - hit = bp_leg_r; + hit = body_part_leg_r; } if( one_in( 4 ) ) { - hit = bp_torso; + hit = body_part_torso; } else if( one_in( 2 ) ) { if( one_in( 2 ) ) { - hit = bp_foot_l; + hit = body_part_foot_l; } else { - hit = bp_foot_r; + hit = body_part_foot_r; } } return hit; @@ -1483,14 +1483,14 @@ bool mattack::growplants( monster *z ) continue; } - const body_part hit = body_part_hit_by_plant(); + const bodypart_str_id hit = body_part_hit_by_plant(); critter->add_msg_player_or_npc( m_bad, //~ %s is bodypart name in accusative. _( "A tree bursts forth from the earth and pierces your %s!" ), //~ %s is bodypart name in accusative. _( "A tree bursts forth from the earth and pierces 's %s!" ), body_part_name_accusative( hit ) ); - critter->deal_damage( z, convert_bp( hit ).id(), damage_instance( DT_STAB, rng( 10, 30 ) ) ); + critter->deal_damage( z, hit.id(), damage_instance( DT_STAB, rng( 10, 30 ) ) ); } // 1 in 5 chance of making existing vegetation grow larger @@ -1518,14 +1518,14 @@ bool mattack::growplants( monster *z ) // Underbrush => young tree g->m.ter_set( p, t_tree_young ); if( critter != nullptr && !critter->uncanny_dodge() ) { - const body_part hit = body_part_hit_by_plant(); + const bodypart_str_id hit = body_part_hit_by_plant(); critter->add_msg_player_or_npc( m_bad, //~ %s is bodypart name in accusative. _( "The underbrush beneath your feet grows and pierces your %s!" ), //~ %s is bodypart name in accusative. _( "Underbrush grows into a tree, and it pierces 's %s!" ), body_part_name_accusative( hit ) ); - critter->deal_damage( z, convert_bp( hit ).id(), damage_instance( DT_STAB, rng( 10, 30 ) ) ); + critter->deal_damage( z, hit.id(), damage_instance( DT_STAB, rng( 10, 30 ) ) ); } } } @@ -2088,11 +2088,11 @@ bool mattack::fungus_fortify( monster *z ) // Aimed at the player, too? Sure! const tripoint hit_pos = target->pos() + point( rng( -1, 1 ), rng( -1, 1 ) ); if( hit_pos == target->pos() && !target->uncanny_dodge() ) { - const body_part hit = body_part_hit_by_plant(); + const bodypart_str_id hit = body_part_hit_by_plant(); //~ %s is bodypart name in accusative. add_msg( m_bad, _( "A fungal tendril bursts forth from the earth and pierces your %s!" ), body_part_name_accusative( hit ) ); - g->u.deal_damage( z, convert_bp( hit ).id(), damage_instance( DT_CUT, rng( 5, 11 ) ) ); + g->u.deal_damage( z, hit.id(), damage_instance( DT_CUT, rng( 5, 11 ) ) ); g->u.check_dead_state(); // Probably doesn't have spores available *just* yet. Let's be nice. } else if( monster *const tendril = g->place_critter_at( mon_fungal_tendril, hit_pos ) ) { @@ -2501,7 +2501,7 @@ bool mattack::callblobs( monster *z ) } ( *ally )->set_dest( post ); if( !( *ally )->has_effect( effect_ai_controlled ) ) { - ( *ally )->add_effect( effect_ai_controlled, 1_turns, num_bp ); + ( *ally )->add_effect( effect_ai_controlled, 1_turns ); } } // This is telepathy, doesn't take any moves. @@ -2537,7 +2537,7 @@ bool mattack::jackson( monster *z ) } ( *ally )->set_dest( post ); if( !( *ally )->has_effect( effect_ai_controlled ) ) { - ( *ally )->add_effect( effect_ai_controlled, 1_turns, num_bp ); + ( *ally )->add_effect( effect_ai_controlled, 1_turns ); } } // Did we convert anybody? @@ -3185,7 +3185,7 @@ bool mattack::nurse_operate( monster *z ) // Check if we successfully grabbed the target if( target->has_effect( effect_grabbed ) ) { z->dragged_foe_id = target->getID(); - z->add_effect( effect_dragging, 1_turns, num_bp ); + z->add_effect( effect_dragging, 1_turns ); return true; } } @@ -5386,11 +5386,11 @@ bool mattack::bio_op_takedown( monster *z ) return true; } // Yes, it has the CQC bionic. - bodypart_id hit( "num_bp" ); + bodypart_str_id hit; if( one_in( 2 ) ) { - hit = bodypart_id( "leg_l" ); + hit = body_part_leg_l; } else { - hit = bodypart_id( "leg_r" ); + hit = body_part_leg_r; } // Weak kick to start with, knocks you off your footing @@ -5403,17 +5403,17 @@ bool mattack::bio_op_takedown( monster *z ) if( !foe->is_throw_immune() ) { if( !target->is_immune_effect( effect_downed ) ) { if( one_in( 4 ) ) { - hit = bodypart_id( "head" ); + hit = body_part_head; // 50% damage buff for the headshot. dam = rng( 9, 21 ); target->add_msg_if_player( m_bad, _( "and slams you, face first, to the ground for %d damage!" ), dam ); - foe->deal_damage( z, bodypart_id( "head" ), damage_instance( DT_BASH, dam ) ); + foe->deal_damage( z, body_part_head.id(), damage_instance( DT_BASH, dam ) ); } else { - hit = bodypart_id( "torso" ); + hit = body_part_torso; dam = rng( 6, 18 ); target->add_msg_if_player( m_bad, _( "and slams you to the ground for %d damage!" ), dam ); - foe->deal_damage( z, bodypart_id( "torso" ), damage_instance( DT_BASH, dam ) ); + foe->deal_damage( z, body_part_torso.id(), damage_instance( DT_BASH, dam ) ); } foe->add_effect( effect_downed, 3_turns ); } @@ -5421,12 +5421,12 @@ bool mattack::bio_op_takedown( monster *z ) foe->martial_arts_data->selected_has_weapon( foe->primary_weapon().typeId() ) ) && !thrown_by_judo( z ) ) { // Saved by the tentacle-bracing! :) - hit = bodypart_id( "torso" ); + hit = body_part_torso; dam = rng( 3, 9 ); target->add_msg_if_player( m_bad, _( "and slams you for %d damage!" ), dam ); foe->deal_damage( z, bodypart_id( "torso" ), damage_instance( DT_BASH, dam ) ); } - target->on_hit( z, hit ); + target->on_hit( z, hit.id() ); foe->check_dead_state(); return true; @@ -5982,7 +5982,7 @@ bool mattack::zombie_fuse( monster *z ) z->name() ); } z->moves -= 200; - z->add_effect( effect_grown_of_fuse, 10_days, num_bp, + z->add_effect( effect_grown_of_fuse, 10_days, bodypart_str_id::NULL_ID(), critter->get_hp_max() + z->get_effect( effect_grown_of_fuse ).get_intensity() ); z->heal( critter->get_hp(), true ); critter->death_drops = false; diff --git a/src/mondeath.cpp b/src/mondeath.cpp index 954c5e87f385..245803edddb6 100644 --- a/src/mondeath.cpp +++ b/src/mondeath.cpp @@ -864,7 +864,7 @@ void mdeath::detonate( monster &z ) } } // HACK, used to stop them from having ammo on respawn - z.add_effect( effect_no_ammo, 1_turns, num_bp ); + z.add_effect( effect_no_ammo, 1_turns ); // First die normally mdeath::normal( z ); diff --git a/src/monexamine.cpp b/src/monexamine.cpp index 016959764076..a40583a84367 100644 --- a/src/monexamine.cpp +++ b/src/monexamine.cpp @@ -454,7 +454,7 @@ bool monexamine::mech_hack( monster &z ) if( query_yn( _( "Swipe your %s into the %s's security port?" ), item::nname( card_type ), z.get_name() ) ) { you.mod_moves( -100 ); - z.add_effect( effect_pet, 1_turns, num_bp ); + z.add_effect( effect_pet, 1_turns ); z.friendly = -1; if( z.has_flag( MF_RIDEABLE_MECH ) ) { add_msg( m_good, _( "The %s whirs into life and opens its restraints to accept a pilot." ), @@ -513,7 +513,7 @@ bool monexamine::pay_bot( monster &z ) time_duration time_bought = time_duration::from_minutes( amount ); you.use_charges( itype_cash_card, amount * 10 ); z.add_effect( effect_pet, time_bought ); - z.add_effect( effect_paid, time_bought, num_bp ); + z.add_effect( effect_paid, time_bought ); z.friendly = -1; popup( _( "Your friendship grows stronger!\n This %s will follow you for %s." ), z.get_name(), to_string( z.get_effect_dur( effect_pet ) ) ); @@ -599,7 +599,7 @@ void monexamine::attach_or_remove_saddle( monster &z ) add_msg( _( "Never mind." ) ); return; } - z.add_effect( effect_saddled, 1_turns, num_bp ); + z.add_effect( effect_saddled, 1_turns ); z.set_tack_item( loc->detach() ); } } @@ -669,7 +669,7 @@ void monexamine::attach_bag_to( monster &z ) item &it = *loc; z.set_storage_item( it.detach( ) ); add_msg( _( "You mount the %1$s on your %2$s." ), it.display_name(), pet_name ); - z.add_effect( effect_has_bag, 1_turns, num_bp ); + z.add_effect( effect_has_bag, 1_turns ); // Update encumbrance in case we were wearing it you.flag_encumbrance(); you.moves -= 200; @@ -798,7 +798,7 @@ bool monexamine::add_armor( monster &z ) z.set_armor_item( loc->detach() ); add_msg( pgettext( "pet armor", "You put the %1$s on your %2$s." ), armor.display_name(), pet_name ); - z.add_effect( effect_monster_armor, 1_turns, num_bp ); + z.add_effect( effect_monster_armor, 1_turns ); // TODO: armoring a horse takes a lot longer than 2 seconds. This should be a long action. get_avatar().moves -= 200; return true; @@ -1001,7 +1001,7 @@ void monexamine::milk_source( monster &source_mon ) // pin the cow in place if it isn't already bool temp_tie = !source_mon.has_effect( effect_tied ); if( temp_tie ) { - source_mon.add_effect( effect_tied, 1_turns, num_bp ); + source_mon.add_effect( effect_tied, 1_turns ); you.activity->str_values.emplace_back( "temp_tie" ); } add_msg( _( "You milk the %s." ), source_mon.get_name() ); diff --git a/src/monmove.cpp b/src/monmove.cpp index 7d46668a13d6..b526d5c79d98 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -1713,13 +1713,13 @@ bool monster::move_to( const tripoint &p, bool force, bool step_on_critter, } if( g->m.has_flag( "UNSTABLE", destination ) && on_ground ) { - add_effect( effect_bouldering, 1_turns, num_bp ); + add_effect( effect_bouldering, 1_turns ); } else if( has_effect( effect_bouldering ) ) { remove_effect( effect_bouldering ); } if( g->m.has_flag_ter_or_furn( TFLAG_NO_SIGHT, destination ) && on_ground ) { - add_effect( effect_no_sight, 1_turns, num_bp ); + add_effect( effect_no_sight, 1_turns ); } else if( has_effect( effect_no_sight ) ) { remove_effect( effect_no_sight ); } diff --git a/src/monster.cpp b/src/monster.cpp index 1b7abba0880e..fb98bf9bcce0 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -1747,7 +1747,7 @@ void monster::melee_attack( Creature &target, float accuracy ) if( hitspread >= 0 ) { target.deal_melee_hit( this, hitspread, false, damage, dealt_dam ); } - body_part bp_hit = dealt_dam.bp_hit; + const bodypart_str_id bp_hit = dealt_dam.bp_hit; const int total_dealt = dealt_dam.total_damage(); if( hitspread < 0 ) { @@ -1774,7 +1774,7 @@ void monster::melee_attack( Creature &target, float accuracy ) sfx::do_player_death_hurt( dynamic_cast( target ), false ); //~ 1$s is attacker name, 2$s is bodypart name in accusative. add_msg( m_bad, _( "%1$s hits your %2$s." ), disp_name( false, true ), - body_part_name_accusative( bp_hit ) ); + bp_hit->accusative.translated() ); } else if( target.is_npc() ) { if( has_effect( effect_ridden ) && has_flag( MF_RIDEABLE_MECH ) && pos() == g->u.pos() ) { //~ %1$s: name of your mount, %2$s: target NPC name, %3$d: damage value @@ -1784,7 +1784,7 @@ void monster::melee_attack( Creature &target, float accuracy ) //~ %1$s: attacker name, %2$s: target NPC name, %3$s: bodypart name in accusative add_msg( _( "%1$s hits %2$s %3$s." ), disp_name( false, true ), target.disp_name( true ), - body_part_name_accusative( bp_hit ) ); + bp_hit->accusative.translated() ); } } else { if( has_effect( effect_ridden ) && has_flag( MF_RIDEABLE_MECH ) && pos() == g->u.pos() ) { @@ -1799,7 +1799,7 @@ void monster::melee_attack( Creature &target, float accuracy ) } else if( target.is_player() ) { //~ %s is bodypart name in accusative. add_msg( m_bad, _( "Something hits your %s." ), - body_part_name_accusative( bp_hit ) ); + bp_hit->accusative.translated() ); } } else { // No damage dealt @@ -1807,14 +1807,14 @@ void monster::melee_attack( Creature &target, float accuracy ) if( target.is_player() ) { //~ 1$s is attacker name, 2$s is bodypart name in accusative, 3$s is armor name add_msg( _( "%1$s hits your %2$s, but your %3$s protects you." ), disp_name( false, true ), - body_part_name_accusative( bp_hit ), target.skin_name() ); + bp_hit->accusative.translated(), target.skin_name() ); } else if( target.is_npc() ) { //~ $1s is monster name, %2$s is that monster target name, //~ $3s is target bodypart name in accusative, $4s is the monster target name, //~ 5$s is target armor name. add_msg( _( "%1$s hits %2$s %3$s but is stopped by %4$s %5$s." ), disp_name( false, true ), target.disp_name( true ), - body_part_name_accusative( bp_hit ), + bp_hit->accusative.translated(), target.disp_name( true ), target.skin_name() ); } else { @@ -1828,7 +1828,7 @@ void monster::melee_attack( Creature &target, float accuracy ) } else if( target.is_player() ) { //~ 1$s is bodypart name in accusative, 2$s is armor name. add_msg( _( "Something hits your %1$s, but your %2$s protects you." ), - body_part_name_accusative( bp_hit ), target.skin_name() ); + bp_hit->accusative.translated(), target.skin_name() ); } } @@ -1848,10 +1848,10 @@ void monster::melee_attack( Creature &target, float accuracy ) // Add any on damage effects for( const auto &eff : type->atk_effs ) { if( x_in_y( eff.chance, 100 ) ) { - const body_part affected_bp = eff.affect_hit_bp ? bp_hit : eff.bp; - target.add_effect( eff.id, time_duration::from_turns( eff.duration ), convert_bp( affected_bp ) ); + const bodypart_str_id &affected_bp = eff.affect_hit_bp ? bp_hit : convert_bp( eff.bp ); + target.add_effect( eff.id, time_duration::from_turns( eff.duration ), affected_bp ); if( eff.permanent ) { - target.get_effect( eff.id, convert_bp( affected_bp ) ).set_permanent(); + target.get_effect( eff.id, affected_bp ).set_permanent(); } } } @@ -1876,7 +1876,7 @@ void monster::melee_attack( Creature &target, float accuracy ) if( total_dealt > 6 && stab_cut > 0 && has_flag( MF_BLEED ) ) { // Maybe should only be if DT_CUT > 6... Balance question - target.add_effect( effect_bleed, 6_minutes, convert_bp( bp_hit ) ); + target.add_effect( effect_bleed, 6_minutes, bp_hit ); } } @@ -2119,16 +2119,13 @@ bool monster::move_effects( bool ) return true; } -void monster::add_effect( const efftype_id &eff_id, const time_duration &dur, - const bodypart_str_id &, - int intensity, bool force, bool deferred ) +void monster::add_effect( const efftype_id &eff_id, const time_duration &dur ) { - // Effects are not applied to specific monster body part - Creature::add_effect( eff_id, dur, bodypart_str_id::NULL_ID(), intensity, force, deferred ); + Creature::add_effect( eff_id, dur, bodypart_str_id::NULL_ID() ); } void monster::add_effect( const efftype_id &eff_id, const time_duration &dur, - body_part, + const bodypart_str_id &, int intensity, bool force, bool deferred ) { // Effects are not applied to specific monster body part @@ -2979,7 +2976,7 @@ void monster::make_pet() { friendly = -1; g->critter_tracker->update_faction( *this ); - add_effect( effect_pet, 1_turns, num_bp ); + add_effect( effect_pet, 1_turns ); } bool monster::is_pet() const diff --git a/src/monster.h b/src/monster.h index ff7831893a13..18d6cb72e161 100644 --- a/src/monster.h +++ b/src/monster.h @@ -370,8 +370,10 @@ class monster : public Creature, public location_visitable /** Performs any monster-specific modifications to the arguments before passing to Creature::add_effect(). */ void add_effect( const efftype_id &eff_id, const time_duration &dur, const bodypart_str_id &bp, int intensity = 0, bool force = false, bool deferred = false ) override; - void add_effect( const efftype_id &eff_id, const time_duration &dur, body_part bp = num_bp, - int intensity = 0, bool force = false, bool deferred = false ); + void add_effect( const efftype_id &eff_id, const time_duration &dur ); + // Use the bodypart_str_id variant instead + void add_effect( const efftype_id &eff_id, const time_duration &dur, body_part bp, + int intensity = 0, bool force = false, bool deferred = false ) = delete; /** Returns a std::string containing effects for descriptions */ std::string get_effect_status() const; diff --git a/src/panels.cpp b/src/panels.cpp index 4f9dec354a40..e26cd1023cfc 100644 --- a/src/panels.cpp +++ b/src/panels.cpp @@ -826,7 +826,7 @@ static void draw_limb2( avatar &u, const catacurses::window &w ) } else { wmove( w, point( 11, i / 2 ) ); } - wprintz( w, u.limb_color( bp, true, true, true ), str ); + wprintz( w, u.limb_color( bp.id(), true, true, true ), str ); if( i % 2 == 0 ) { wmove( w, point( 5, i / 2 ) ); } else { @@ -1140,7 +1140,7 @@ static void draw_limb_narrow( avatar &u, const catacurses::window &w ) std::string str = body_part_hp_bar_ui_text( bp ); wmove( w, point( nx, ny ) ); str = left_justify( str, 5 ); - wprintz( w, u.limb_color( bp, true, true, true ), str + ":" ); + wprintz( w, u.limb_color( bp.id(), true, true, true ), str + ":" ); } wnoutrefresh( w ); } @@ -1576,7 +1576,7 @@ static void draw_health_classic( avatar &u, const catacurses::window &w ) for( const bodypart_id &bp : u.get_all_body_parts( true ) ) { const std::string str = body_part_hp_bar_ui_text( part[i] ); wmove( w, point( 8, i ) ); - wprintz( w, u.limb_color( part[i], true, true, true ), str ); + wprintz( w, u.limb_color( part[i].id(), true, true, true ), str ); wmove( w, point( 14, i ) ); draw_limb_health( u, w, bp.id() ); i++; diff --git a/src/suffer.cpp b/src/suffer.cpp index 92e2574b92c3..6db2b391bf64 100644 --- a/src/suffer.cpp +++ b/src/suffer.cpp @@ -893,7 +893,7 @@ std::map Character::bodypart_exposure() // What body parts does this item cover? body_part_set covered = it->get_covered_body_parts(); for( const bodypart_id &bp : all_body_parts ) { - if( bp->token != num_bp && !covered.test( bp.id() ) ) { + if( bp.id() && !covered.test( bp.id() ) ) { continue; } // How much exposure does this item leave on this part? (1.0 == naked) diff --git a/src/trapfunc.cpp b/src/trapfunc.cpp index 6f63e9103544..c7e985fd8b6c 100644 --- a/src/trapfunc.cpp +++ b/src/trapfunc.cpp @@ -336,22 +336,22 @@ bool trapfunc::crossbow( const tripoint &p, Creature *c, item * ) if( n != nullptr ) { ///\EFFECT_DODGE reduces chance of being hit by crossbow trap if( !one_in( 4 ) && rng( 8, 20 ) > n->get_dodge() ) { - bodypart_id hit = bodypart_id( " num_bp" ); + bodypart_str_id hit; switch( rng( 1, 10 ) ) { case 1: if( one_in( 2 ) ) { - hit = bodypart_id( "foot_l" ); + hit = body_part_foot_l; } else { - hit = bodypart_id( "foot_r" ); + hit = body_part_foot_r; } break; case 2: case 3: case 4: if( one_in( 2 ) ) { - hit = bodypart_id( "leg_l" ); + hit = body_part_leg_l; } else { - hit = bodypart_id( "leg_r" ); + hit = body_part_leg_r; } break; case 5: @@ -359,10 +359,10 @@ bool trapfunc::crossbow( const tripoint &p, Creature *c, item * ) case 7: case 8: case 9: - hit = bodypart_id( "torso" ); + hit = body_part_torso; break; case 10: - hit = bodypart_id( "head" ); + hit = body_part_head; break; } //~ %s is bodypart @@ -400,7 +400,7 @@ bool trapfunc::crossbow( const tripoint &p, Creature *c, item * ) if( seen ) { add_msg( m_bad, _( "A bolt shoots out and hits the %s!" ), z->name() ); } - z->deal_damage( nullptr, bodypart_id( "torso" ), damage_instance( DT_STAB, rng( 30, 45 ) ) ); + z->deal_damage( nullptr, body_part_torso.id(), damage_instance( DT_STAB, rng( 30, 45 ) ) ); add_bolt = !one_in( 10 ); } else if( seen ) { add_msg( m_neutral, _( "A bolt shoots out, but misses the %s." ), z->name() ); @@ -432,22 +432,22 @@ bool trapfunc::shotgun( const tripoint &p, Creature *c, item * ) if( n != nullptr ) { ///\EFFECT_DODGE reduces chance of being hit by shotgun trap if( rng( 5, 50 ) > n->get_dodge() ) { - bodypart_id hit = bodypart_id( "num_bp" ); + bodypart_str_id hit; switch( rng( 1, 10 ) ) { case 1: if( one_in( 2 ) ) { - hit = bodypart_id( "foot_l" ); + hit = body_part_foot_l; } else { - hit = bodypart_id( "foot_r" ); + hit = body_part_foot_r; } break; case 2: case 3: case 4: if( one_in( 2 ) ) { - hit = bodypart_id( "leg_l" ); + hit = body_part_leg_l; } else { - hit = bodypart_id( "leg_r" ); + hit = body_part_leg_r; } break; case 5: @@ -455,10 +455,10 @@ bool trapfunc::shotgun( const tripoint &p, Creature *c, item * ) case 7: case 8: case 9: - hit = bodypart_id( "torso" ); + hit = body_part_torso; break; case 10: - hit = bodypart_id( "head" ); + hit = body_part_head; break; } //~ %s is bodypart @@ -478,10 +478,10 @@ bool trapfunc::shotgun( const tripoint &p, Creature *c, item * ) add_msg( m_bad, _( "A shotgun fires and hits the %s!" ), z->name() ); } if( shots > 1 ) { - z->deal_damage( nullptr, bodypart_id( "torso" ), damage_instance( DT_BULLET, rng( 60, + z->deal_damage( nullptr, body_part_torso.id(), damage_instance( DT_BULLET, rng( 60, 80 ), 0, 1.5f ) ); } - z->deal_damage( nullptr, bodypart_id( "torso" ), damage_instance( DT_BULLET, rng( 60, + z->deal_damage( nullptr, body_part_torso.id(), damage_instance( DT_BULLET, rng( 60, 80 ), 0, 1.5f ) ); } c->check_dead_state(); @@ -823,19 +823,19 @@ bool trapfunc::pit_spikes( const tripoint &p, Creature *c, item * ) } else if( 0 == damage || rng( 5, 30 ) < dodge ) { n->add_msg_if_player( _( "You avoid the spikes within." ) ); } else { - bodypart_id hit( "num_bp" ); + bodypart_str_id hit; switch( rng( 1, 10 ) ) { case 1: - hit = bodypart_id( "leg_l" ); + hit = body_part_leg_l; break; case 2: - hit = bodypart_id( "leg_r" ); + hit = body_part_leg_r; break; case 3: - hit = bodypart_id( "arm_l" ); + hit = body_part_arm_l; break; case 4: - hit = bodypart_id( "arm_r" ); + hit = body_part_arm_r; break; case 5: case 6: @@ -843,7 +843,7 @@ bool trapfunc::pit_spikes( const tripoint &p, Creature *c, item * ) case 8: case 9: case 10: - hit = bodypart_id( "torso" ); + hit = body_part_torso; break; } n->add_msg_if_player( m_bad, _( "The spikes impale your %s!" ), @@ -855,7 +855,7 @@ bool trapfunc::pit_spikes( const tripoint &p, Creature *c, item * ) add_msg( m_bad, _( "Your %s falls into a pit!" ), z->get_name() ); g->u.forced_dismount(); } - z->deal_damage( nullptr, bodypart_id( "torso" ), damage_instance( DT_CUT, rng( 20, 50 ) ) ); + z->deal_damage( nullptr, body_part_torso.id(), damage_instance( DT_CUT, rng( 20, 50 ) ) ); } c->check_dead_state(); if( one_in( 4 ) ) { @@ -904,31 +904,31 @@ bool trapfunc::pit_glass( const tripoint &p, Creature *c, item * ) } else if( 0 == damage || rng( 5, 30 ) < dodge ) { n->add_msg_if_player( _( "You avoid the glass shards within." ) ); } else { - bodypart_id hit( " num_bp" ); + bodypart_str_id hit; switch( rng( 1, 10 ) ) { case 1: - hit = bodypart_id( "leg_l" ); + hit = body_part_leg_l; break; case 2: - hit = bodypart_id( "leg_r" ); + hit = body_part_leg_r; break; case 3: - hit = bodypart_id( "arm_l" ); + hit = body_part_arm_l; break; case 4: - hit = bodypart_id( "arm_r" ); + hit = body_part_arm_r; break; case 5: - hit = bodypart_id( "foot_l" ); + hit = body_part_foot_l; break; case 6: - hit = bodypart_id( "foot_r" ); + hit = body_part_foot_r; break; case 7: case 8: case 9: case 10: - hit = bodypart_id( "torso" ); + hit = body_part_torso; break; } n->add_msg_if_player( m_bad, _( "The glass shards slash your %s!" ), @@ -940,7 +940,7 @@ bool trapfunc::pit_glass( const tripoint &p, Creature *c, item * ) add_msg( m_bad, _( "Your %s falls into a pit!" ), z->get_name() ); g->u.forced_dismount(); } - z->deal_damage( nullptr, bodypart_id( "torso" ), damage_instance( DT_CUT, rng( 20, 50 ) ) ); + z->deal_damage( nullptr, body_part_torso.id(), damage_instance( DT_CUT, rng( 20, 50 ) ) ); } c->check_dead_state(); if( one_in( 5 ) ) { diff --git a/src/weather.cpp b/src/weather.cpp index 080f073403c2..2d6735fd8cd7 100644 --- a/src/weather.cpp +++ b/src/weather.cpp @@ -389,16 +389,16 @@ void weather_effect::wet_player( int amount ) return; } std::map> clothing_map; - for( const bodypart_id &bp : target.get_all_body_parts() ) { + const auto &all_bps = target.get_all_body_parts(); + for( const bodypart_id &bp : all_bps ) { clothing_map.emplace( bp, std::vector() ); } for( const item * const &it : target.worn ) { // TODO: Port body part set id changes const body_part_set &covered = it->get_covered_body_parts(); - for( size_t i = 0; i < num_bp; i++ ) { - body_part token = static_cast( i ); - if( covered.test( convert_bp( token ) ) ) { - clothing_map[convert_bp( token )].emplace_back( it ); + for( const bodypart_id &bp : all_bps ) { + if( covered.test( bp.id() ) ) { + clothing_map[bp.id()].emplace_back( it ); } } } diff --git a/tests/encumbrance_test.cpp b/tests/encumbrance_test.cpp index 24465ea93e8d..a7fb84ef128e 100644 --- a/tests/encumbrance_test.cpp +++ b/tests/encumbrance_test.cpp @@ -22,7 +22,7 @@ static void test_encumbrance_on( player &p, std::vector> &clothing, - const std::string &body_part, + const bodypart_str_id &body_part, int expected_encumbrance, const std::function &tweak_player = {} ) @@ -38,13 +38,13 @@ static void test_encumbrance_on( p.worn.push_back( std::move( i ) ); } p.reset_encumbrance(); - encumbrance_data enc = p.get_encumbrance().elems[ get_body_part_token( body_part ) ]; + encumbrance_data enc = p.get_encumbrance().elems[ body_part ]; CHECK( enc.encumbrance == expected_encumbrance ); } static void test_encumbrance_items( std::vector> &clothing, - const std::string &body_part, + const bodypart_str_id &body_part, const int expected_encumbrance, const std::function &tweak_player = {} ) @@ -62,7 +62,7 @@ static void test_encumbrance_items( static void test_encumbrance( const std::vector &clothing_types, - const std::string &body_part, + const bodypart_str_id &body_part, const int expected_encumbrance ) { @@ -92,21 +92,21 @@ static constexpr int greatcoat_e = 23; TEST_CASE( "regular_clothing_encumbrance", "[encumbrance]" ) { clear_all_state(); - test_encumbrance( { "karate_gi" }, "TORSO", karate_gi_e ); - test_encumbrance( { "vest" }, "TORSO", vest_e ); - test_encumbrance( { "greatcoat" }, "TORSO", greatcoat_e ); + test_encumbrance( { "karate_gi" }, body_part_torso, karate_gi_e ); + test_encumbrance( { "vest" }, body_part_torso, vest_e ); + test_encumbrance( { "greatcoat" }, body_part_torso, greatcoat_e ); } TEST_CASE( "separate_layer_encumbrance", "[encumbrance]" ) { clear_all_state(); - test_encumbrance( { "vest", "greatcoat" }, "TORSO", vest_e + greatcoat_e ); + test_encumbrance( { "vest", "greatcoat" }, body_part_torso, vest_e + greatcoat_e ); } TEST_CASE( "out_of_order_encumbrance", "[encumbrance]" ) { clear_all_state(); - test_encumbrance( { "greatcoat", "vest" }, "TORSO", vest_e * 2 + greatcoat_e ); + test_encumbrance( { "greatcoat", "vest" }, body_part_torso, vest_e * 2 + greatcoat_e ); } TEST_CASE( "same_layer_encumbrance", "[encumbrance]" ) @@ -114,11 +114,11 @@ TEST_CASE( "same_layer_encumbrance", "[encumbrance]" ) clear_all_state(); // When stacking within a layer, encumbrance for additional items is // counted twice - test_encumbrance( { "vest", "vest" }, "TORSO", vest_e * 2 + vest_e ); + test_encumbrance( { "vest", "vest" }, body_part_torso, vest_e * 2 + vest_e ); // ... with a minimum of 2 - test_encumbrance( { "karate_gi", "karate_gi" }, "TORSO", karate_gi_e * 2 + 2 ); + test_encumbrance( { "karate_gi", "karate_gi" }, body_part_torso, karate_gi_e * 2 + 2 ); // ... and a maximum of 10 - test_encumbrance( { "greatcoat", "greatcoat" }, "TORSO", greatcoat_e * 2 + 10 ); + test_encumbrance( { "greatcoat", "greatcoat" }, body_part_torso, greatcoat_e * 2 + 10 ); } TEST_CASE( "tiny_clothing", "[encumbrance]" ) @@ -128,7 +128,7 @@ TEST_CASE( "tiny_clothing", "[encumbrance]" ) i->set_flag( flag_id( "UNDERSIZE" ) ); std::vector> items; items.push_back( std::move( i ) ); - test_encumbrance_items( items, "TORSO", + test_encumbrance_items( items, body_part_torso, vest_e * 3 ); } @@ -140,13 +140,13 @@ TEST_CASE( "tiny_character", "[encumbrance]" ) std::vector> items; items.push_back( std::move( i ) ); SECTION( "regular shirt" ) { - test_encumbrance_items( items, "TORSO", + test_encumbrance_items( items, body_part_torso, vest_e * 2, add_trait( "SMALL2" ) ); } SECTION( "undersize shrt" ) { obj.set_flag( flag_id( "UNDERSIZE" ) ); - test_encumbrance_items( items, "TORSO", vest_e, + test_encumbrance_items( items, body_part_torso, vest_e, add_trait( "SMALL2" ) ); } }