Skip to content

Commit

Permalink
Sort Character Creation skills in menus (#1784)
Browse files Browse the repository at this point in the history
* Sort skills in character creation (#53052)

* Rework the display completely

* Profession Menu update

* Indent the Skills tab levels

Might be an issue if an added skill is longer than 16 characters.

* Make scrollbars work with this system.

It's a bit hacky.

* Added an enum class for ScrollDirection

* Remove get_next

* Standardizing list movement

Uses Modulo to cut down on required code

* Update the Modulo function

Pray things don't break.

* Fix Scrollbar & Non-Centred scrolling

* Change name of variable

Co-authored-by: Saicchi <47158232+Saicchi@users.noreply.github.com>
  • Loading branch information
KheirFerrum and Saicchi authored Sep 3, 2022
1 parent 3f2dd6e commit 3a112fc
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 43 deletions.
2 changes: 1 addition & 1 deletion src/cata_utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ int modulo( int v, int m )
// but this is supposed to be mathematical modulo: 0 <= v%m < m,
const int r = v % m;
// Adding m in that (and only that) case.
return r >= 0 ? r : r + m;
return r >= 0 ? r : r + ( m * ( 1 - r / m ) );
}

bool isBetween( int test, int down, int up )
Expand Down
122 changes: 80 additions & 42 deletions src/newcharacter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1506,14 +1506,25 @@ tab_direction set_profession( avatar &u, points_left &points,
}

// Profession skills
const auto prof_skills = sorted_profs[cur_id]->skills();
std::vector<std::pair<skill_id, int>> prof_skills = sorted_profs[cur_id]->skills();
std::stable_sort( prof_skills.begin(), prof_skills.end(),
[]( const std::pair<skill_id, int> &a, const std::pair<skill_id, int> &b ) {
return localized_compare( std::make_pair( a.first->display_category(), a.first->name() ),
std::make_pair( b.first->display_category(), b.first->name() ) );
} );
buffer += colorize( _( "Profession skills:" ), c_light_blue ) + "\n";
if( prof_skills.empty() ) {
buffer += pgettext( "set_profession_skill", "None" ) + std::string( "\n" );
} else {
skill_displayType_id cur_category = skill_displayType_id::NULL_ID();
for( const auto &sl : prof_skills ) {
if( cur_category != sl.first->display_category() ) {
cur_category = sl.first->display_category();
buffer += colorize( string_format( sl.first->display_category()->display_string() ),
c_yellow ) + "\n";
}
const auto format = pgettext( "set_profession_skill", "%1$s (%2$d)" );
buffer += string_format( format, sl.first.obj().name(), sl.second ) + "\n";
buffer += " " + string_format( format, sl.first.obj().name(), sl.second ) + "\n";
}
}

Expand Down Expand Up @@ -1745,13 +1756,27 @@ tab_direction set_skills( avatar &u, points_left &points )
ui.on_screen_resize( init_windows );

auto sorted_skills = Skill::get_skills_sorted_by( []( const Skill & a, const Skill & b ) {
return localized_compare( a.name(), b.name() );
return localized_compare( std::make_pair( a.display_category(), a.name() ),
std::make_pair( b.display_category(), b.name() ) );
} );

const int num_skills = sorted_skills.size();
skill_displayType_id current_category = skill_displayType_id::NULL_ID();
// Actual line that the skill takes up.
int display_line = 0;
std::vector<std::pair<const Skill *, int>> skill_list;
for( const Skill *skl : sorted_skills ) {
if( current_category != skl->display_category() ) {
current_category = skl->display_category();
display_line++;
}
skill_list.emplace_back( skl, display_line );
display_line++;
}

const int num_skills = skill_list.size();
int cur_offset = 0;
int cur_pos = 0;
const Skill *currentSkill = sorted_skills[cur_pos];
const Skill *currentSkill = skill_list[cur_pos].first;
int selected = 0;

input_context ctxt( "NEW_CHAR_SKILLS" );
Expand Down Expand Up @@ -1868,21 +1893,36 @@ tab_direction set_skills( avatar &u, points_left &points )
draw_scrollbar( w, selected, iContentHeight, iLines,
point( getmaxx( w ) - 1, 5 ), BORDER_COLOR, true );

calcStartPos( cur_offset, cur_pos, iContentHeight, num_skills );
for( int i = cur_offset; i < num_skills && i - cur_offset < iContentHeight; ++i ) {
const int y = 5 + i - cur_offset;
const Skill *thisSkill = sorted_skills[i];
// Clear the line
mvwprintz( w, point( 2, y ), c_light_gray, std::string( getmaxx( w ) - 3, ' ' ) );
if( u.get_skill_level( thisSkill->ident() ) == 0 ) {
mvwprintz( w, point( 2, y ),
( i == cur_pos ? h_light_gray : c_light_gray ), thisSkill->name() );
} else {
mvwprintz( w, point( 2, y ),
( i == cur_pos ? hilite( COL_SKILL_USED ) : COL_SKILL_USED ),
thisSkill->name() );
wprintz( w, ( i == cur_pos ? hilite( COL_SKILL_USED ) : COL_SKILL_USED ),
" ( %d )", u.get_skill_level( thisSkill->ident() ) );
calcStartPos( cur_offset, skill_list[cur_pos].second - 1, iContentHeight - 1, display_line - 1 );
current_category = skill_displayType_id::NULL_ID();
for( int i = 0; i < num_skills && skill_list[i].second - cur_offset - 1 < iContentHeight; ++i ) {
const int y = 5 + skill_list[i].second - cur_offset;
// Necessary because cur_offset doesn't indicate the first object to read. A bit hacky.
if( y < 5 ) {
continue;
}
const skill_displayType_id &display_type = skill_list[i].first->display_category();
const Skill *thisSkill = skill_list[i].first;
if( current_category != display_type && y - 1 >= 5 ) {
// Clear the line
mvwprintz( w, point( 2, y - 1 ), c_light_gray, std::string( getmaxx( w ) - 3, ' ' ) );
mvwprintz( w, point( 2, y - 1 ), c_yellow, display_type->display_string() );
current_category = display_type;
}
if( y < iContentHeight + 5 ) {
// Clear the line. 2 for x-coord because category names will be scrolled over.
mvwprintz( w, point( 2, y ), c_light_gray, std::string( getmaxx( w ) - 3, ' ' ) );
if( u.get_skill_level( thisSkill->ident() ) == 0 ) {
mvwprintz( w, point( 4, y ),
( i == cur_pos ? h_light_gray : c_light_gray ), thisSkill->name() );
} else {
mvwprintz( w, point( 4, y ),
( i == cur_pos ? hilite( COL_SKILL_USED ) : COL_SKILL_USED ),
thisSkill->name() );
mvwprintz( w, point( 20, y ),
( i == cur_pos ? hilite( COL_SKILL_USED ) : COL_SKILL_USED ),
" (%d)", u.get_skill_level( thisSkill->ident() ) );
}
}
for( auto &prof_skill : u.prof->skills() ) {
if( prof_skill.first == thisSkill->ident() ) {
Expand All @@ -1893,7 +1933,8 @@ tab_direction set_skills( avatar &u, points_left &points )
}
}

draw_scrollbar( w, cur_pos, iContentHeight, num_skills, point( 0, 5 ) );
draw_scrollbar( w, skill_list[cur_pos].second - 1, iContentHeight - 1, display_line - 1, point( 0,
5 ) );

wnoutrefresh( w );
wnoutrefresh( w_description );
Expand All @@ -1903,17 +1944,11 @@ tab_direction set_skills( avatar &u, points_left &points )
ui_manager::redraw();
const std::string action = ctxt.handle_input();
if( action == "DOWN" ) {
cur_pos++;
if( cur_pos >= num_skills ) {
cur_pos = 0;
}
currentSkill = sorted_skills[cur_pos];
cur_pos = modulo( cur_pos + 1, num_skills );
currentSkill = skill_list[cur_pos].first;
} else if( action == "UP" ) {
cur_pos--;
if( cur_pos < 0 ) {
cur_pos = num_skills - 1;
}
currentSkill = sorted_skills[cur_pos];
cur_pos = modulo( cur_pos - 1, num_skills );
currentSkill = skill_list[cur_pos].first;
} else if( action == "LEFT" ) {
const int level = u.get_skill_level( currentSkill->ident() );
if( level > 0 ) {
Expand Down Expand Up @@ -2489,33 +2524,36 @@ tab_direction set_description( avatar &you, const bool allow_reroll,
mvwprintz( w_skills, point_zero, COL_HEADER, _( "Skills:" ) );

auto skillslist = Skill::get_skills_sorted_by( [&]( const Skill & a, const Skill & b ) {
const int level_a = you.get_skill_level_object( a.ident() ).exercised_level();
const int level_b = you.get_skill_level_object( b.ident() ).exercised_level();
return localized_compare( std::make_pair( -level_a, a.name() ),
std::make_pair( -level_b, b.name() ) );
return localized_compare( std::make_pair( a.display_category(), a.name() ),
std::make_pair( b.display_category(), b.name() ) );
} );

int line = 1;
bool has_skills = false;
profession::StartingSkillList list_skills = you.prof->skills();
skill_displayType_id last_category = skill_displayType_id::NULL_ID();
for( auto &elem : skillslist ) {
int level = you.get_skill_level( elem->ident() );

if( points.limit != points_left::TRANSFER ) {
profession::StartingSkillList::iterator i = list_skills.begin();
while( i != list_skills.end() ) {
if( i->first == ( elem )->ident() ) {
level += i->second;
for( auto &prof_skill : you.prof->skills() ) {
if( prof_skill.first == elem->ident() ) {
level += static_cast<int>( prof_skill.second );
break;
}
++i;
}
}

if( level > 0 ) {
mvwprintz( w_skills, point( 0, line ), c_light_gray,
if( last_category != elem->display_category() ) {
last_category = elem->display_category();
mvwprintz( w_skills, point( 0, line ), c_yellow, elem->display_category()->display_string() );
line++;
}
mvwprintz( w_skills, point( 2, line ), c_light_gray,
elem->name() + ":" );
mvwprintz( w_skills, point( 23, line ), c_light_gray, "%-2d", static_cast<int>( level ) );
mvwprintz( w_skills, point( 25, line ), c_light_gray, "%-2d",
static_cast<int>( level ) );
line++;
has_skills = true;
}
Expand Down
13 changes: 13 additions & 0 deletions src/skill.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,19 @@ SkillDisplayType::SkillDisplayType( const skill_displayType_id &ident,
{
}

/** @relates string_id */
template<>
const SkillDisplayType &skill_displayType_id::obj() const
{
for( const SkillDisplayType &skill : SkillDisplayType::skillTypes ) {
if( skill.ident() == *this ) {
return skill;
}
}

return invalid_skill_type;
}

void SkillDisplayType::load( const JsonObject &jsobj )
{
// TEMPORARY until 0.G: Remove "ident" support
Expand Down

0 comments on commit 3a112fc

Please sign in to comment.