Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reworked how crafting skill requirement display is generated. #36089

Merged
2 changes: 1 addition & 1 deletion src/basecamp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ std::string basecamp::om_upgrade_description( const std::string &bldg, bool trun
comp = comp + elem + "\n";
}
comp = string_format( _( "Notes:\n%s\n\nSkills used: %s\n%s\n" ),
making.description, making.required_skills_string(), comp );
making.description, making.required_all_skills_string(), comp );
if( !trunc ) {
time_duration base_time = making.batch_duration();
comp += string_format( _( "Risk: None\nTime: %s\n" ),
Expand Down
15 changes: 3 additions & 12 deletions src/crafting_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,23 +488,14 @@ const recipe *select_crafting_recipe( int &batch_size )
const int xpos = 30;

if( display_mode == 0 ) {
auto player_skill = g->u.get_skill_level( current[line]->skill_used );
std::string difficulty_color =
current[line]->difficulty > player_skill ? "yellow" : "green";
std::string primary_skill_level = string_format( "(%s/%s)", player_skill,
current[line]->difficulty );
print_colored_text(
w_data, point( xpos, ypos++ ), col, col,
string_format( _( "Primary skill: <color_cyan>%s</color> <color_%s>%s</color>" ),
( !current[line]->skill_used ? _( "N/A" ) :
current[line]->skill_used.obj().name() ),
difficulty_color,
( !current[line]->skill_used ? "" : primary_skill_level )
) );
string_format( _( "Primary skill: %s" ),
current[line]->primary_skill_string( &g->u, false ) ) );

ypos += fold_and_print( w_data, point( xpos, ypos ), pane, col,
_( "Other skills: %s" ),
current[line]->required_skills_string( &g->u ) );
current[line]->required_skills_string( &g->u, false, false ) );

const int expected_turns = g->u.expected_time_to_craft( *current[line],
count ) / to_moves<int>( 1_turns );
Expand Down
91 changes: 62 additions & 29 deletions src/recipe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,22 +471,18 @@ bool recipe::has_byproducts() const
return !byproducts.empty();
}

std::string recipe::required_skills_string( const Character *c, bool print_skill_level ) const
// Format a std::pair<skill_id, int> for the crafting menu.
// skill colored green (or yellow if beyond characters skill)
// optionally with the skill level (player / difficulty)
template<typename Iter>
std::string required_skills_as_string( Iter first, Iter last, const Character *c,
const bool print_skill_level )
{
if( required_skills.empty() ) {
if( difficulty == 0 ) {
return _( "<color_cyan>none</color>" );
} else {
const int player_skill = c ? c->get_skill_level( skill_used ) : 0;
std::string difficulty_color = difficulty > player_skill ? "yellow" : "green";
std::string skill_level_string = print_skill_level ? "" :
( std::to_string( player_skill ) + "/" );
skill_level_string += std::to_string( difficulty );
return string_format( "<color_cyan>%s</color> <color_%s>(%s)</color>",
skill_used.obj().name(), difficulty_color, skill_level_string );
}
if( first == last ) {
return _( "<color_cyan>none</color>" );
}
return enumerate_as_string( required_skills.begin(), required_skills.end(),

return enumerate_as_string( first, last,
[&]( const std::pair<skill_id, int> &skill ) {
const int player_skill = c ? c->get_skill_level( skill.first ) : 0;
std::string difficulty_color = skill.second > player_skill ? "yellow" : "green";
Expand All @@ -497,28 +493,65 @@ std::string recipe::required_skills_string( const Character *c, bool print_skill
} );
}

std::string recipe::required_skills_string( const Character *c ) const
// Format a std::pair<skill_id, int> for the basecamp bulletin board.
// skill colored white with difficulty in parenthesis.
template<typename Iter>
std::string required_skills_as_string( Iter first, Iter last )
{
return required_skills_string( c, false );
}

std::string recipe::required_skills_string() const
{
if( required_skills.empty() ) {
if( difficulty == 0 ) {
return _( "<color_cyan>none</color>" );
} else {
return string_format( "<color_white>%s: %d</color>", skill_used.obj().name(),
difficulty );
}
if( first == last ) {
return _( "<color_cyan>none</color>" );
}
return enumerate_as_string( required_skills.begin(), required_skills.end(),

return enumerate_as_string( first, last,
[&]( const std::pair<skill_id, int> &skill ) {
return string_format( "<color_white>%s: %d</color>", skill.first.obj().name(),
return string_format( "<color_white>%s (%d)</color>", skill.first.obj().name(),
skill.second );
} );
}

std::string recipe::primary_skill_string( const Character *c, bool print_skill_level ) const
{
std::vector< std::pair<skill_id, int> > skillList;

if( !skill_used.is_null() ) {
skillList.push_back( std::pair<skill_id, int>( skill_used, difficulty ) );
}

return required_skills_as_string( skillList.begin(), skillList.end(), c, print_skill_level );
}

std::string recipe::required_skills_string( const Character *c, bool include_primary_skill,
bool print_skill_level ) const
{
// There is no primary skill used or it shouldn't be included then we can just use the required_skills directly.
if( skill_used.is_null() || !include_primary_skill ) {
return required_skills_as_string( required_skills.begin(), required_skills.end(), c,
print_skill_level );
}

std::vector< std::pair<skill_id, int> > skillList;
skillList.push_back( std::pair<skill_id, int>( skill_used, difficulty ) );
std::copy( required_skills.begin(), required_skills.end(),
std::back_inserter<std::vector<std::pair<skill_id, int> > >( skillList ) );

return required_skills_as_string( skillList.begin(), skillList.end(), c, print_skill_level );
}

std::string recipe::required_all_skills_string() const
{
// There is no primary skill used, we can just use the required_skills directly.
if( skill_used.is_null() ) {
return required_skills_as_string( required_skills.begin(), required_skills.end() );
}

std::vector< std::pair<skill_id, int> > skillList;
skillList.push_back( std::pair<skill_id, int>( skill_used, difficulty ) );
std::copy( required_skills.begin(), required_skills.end(),
std::back_inserter<std::vector<std::pair<skill_id, int> > >( skillList ) );

return required_skills_as_string( skillList.begin(), skillList.end() );
}

std::string recipe::batch_savings_string() const
{
return ( batch_rsize != 0 ) ?
Expand Down
16 changes: 13 additions & 3 deletions src/recipe.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,19 @@ class recipe
// Create a string list to describe the skill requirements for this recipe
// Format: skill_name(level/amount), skill_name(level/amount)
// Character object (if provided) used to color levels
std::string required_skills_string( const Character *, bool print_skill_level ) const;
std::string required_skills_string( const Character * ) const;
std::string required_skills_string() const;

// These are primarily used by the crafting menu.
// Format the primary skill string.
std::string primary_skill_string( const Character *c, bool print_skill_level ) const;

// Format the other skills string. This is also used for searching within the crafting
// menu which includes the primary skill.
std::string required_skills_string( const Character *, bool include_primary_skill,
bool print_skill_level ) const;

// This is used by the basecamp bulletin board.
std::string required_all_skills_string() const;


// Create a string to describe the time savings of batch-crafting, if any.
// Format: "N% at >M units" or "none"
Expand Down
3 changes: 1 addition & 2 deletions src/recipe_dictionary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,7 @@ std::vector<const recipe *> recipe_subset::search( const std::string &txt,
return lcmatch( r->result_name(), txt );

case search_type::skill:
return lcmatch( r->required_skills_string( nullptr ), txt ) ||
lcmatch( r->skill_used->name(), txt );
return lcmatch( r->required_skills_string( nullptr, true, false ), txt );

case search_type::primary_skill:
return lcmatch( r->skill_used->name(), txt );
Expand Down