diff --git a/plugins/manipulator.cpp b/plugins/manipulator.cpp index 434ba08c8..9ebf093f1 100644 --- a/plugins/manipulator.cpp +++ b/plugins/manipulator.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "df/world.h" @@ -41,36 +42,36 @@ DFHACK_PLUGIN("manipulator"); struct SkillLevel { - const char *name; - int points; - char abbrev; + const char *name; + int points; + char abbrev; }; -#define NUM_SKILL_LEVELS (sizeof(skill_levels) / sizeof(SkillLevel)) +#define NUM_SKILL_LEVELS (sizeof(skill_levels) / sizeof(SkillLevel)) // The various skill rankings. Zero skill is hardcoded to "Not" and '-'. const SkillLevel skill_levels[] = { - {"Dabbling", 500, '0'}, - {"Novice", 600, '1'}, - {"Adequate", 700, '2'}, - {"Competent", 800, '3'}, - {"Skilled", 900, '4'}, - {"Proficient", 1000, '5'}, - {"Talented", 1100, '6'}, - {"Adept", 1200, '7'}, - {"Expert", 1300, '8'}, - {"Professional",1400, '9'}, - {"Accomplished",1500, 'A'}, - {"Great", 1600, 'B'}, - {"Master", 1700, 'C'}, - {"High Master", 1800, 'D'}, - {"Grand Master",1900, 'E'}, - {"Legendary", 2000, 'U'}, - {"Legendary+1", 2100, 'V'}, - {"Legendary+2", 2200, 'W'}, - {"Legendary+3", 2300, 'X'}, - {"Legendary+4", 2400, 'Y'}, - {"Legendary+5", 0, 'Z'} + {"Dabbling", 500, '0'}, + {"Novice", 600, '1'}, + {"Adequate", 700, '2'}, + {"Competent", 800, '3'}, + {"Skilled", 900, '4'}, + {"Proficient", 1000, '5'}, + {"Talented", 1100, '6'}, + {"Adept", 1200, '7'}, + {"Expert", 1300, '8'}, + {"Professional",1400, '9'}, + {"Accomplished",1500, 'A'}, + {"Great", 1600, 'B'}, + {"Master", 1700, 'C'}, + {"High Master", 1800, 'D'}, + {"Grand Master",1900, 'E'}, + {"Legendary", 2000, 'U'}, + {"Legendary+1", 2100, 'V'}, + {"Legendary+2", 2200, 'W'}, + {"Legendary+3", 2300, 'X'}, + {"Legendary+4", 2400, 'Y'}, + {"Legendary+5", 0, 'Z'} }; struct SkillColumn @@ -82,7 +83,7 @@ struct SkillColumn bool special; // specified labor is mutually exclusive with all other special labors }; -#define NUM_COLUMNS (sizeof(columns) / sizeof(SkillColumn)) +#define NUM_COLUMNS (sizeof(columns) / sizeof(SkillColumn)) // All of the skill/labor columns we want to display. Includes profession (for color), labor, skill, and 2 character label const SkillColumn columns[] = { @@ -247,17 +248,69 @@ struct UnitInfo int8_t color; }; -#define FILTER_NONWORKERS 0x0001 -#define FILTER_NONDWARVES 0x0002 -#define FILTER_NONCIV 0x0004 -#define FILTER_ANIMALS 0x0008 -#define FILTER_LIVING 0x0010 -#define FILTER_DEAD 0x0020 +enum altsort_mode { + ALTSORT_NAME, + ALTSORT_PROFESSION, + ALTSORT_MAX +}; + +bool descending; +df::job_skill sort_skill; +df::unit_labor sort_labor; + +bool sortByName (const UnitInfo *d1, const UnitInfo *d2) +{ + if (descending) + return (d1->name > d2->name); + else + return (d1->name < d2->name); +} + +bool sortByProfession (const UnitInfo *d1, const UnitInfo *d2) +{ + if (descending) + return (d1->profession > d2->profession); + else + return (d1->profession < d2->profession); +} + +bool sortBySkill (const UnitInfo *d1, const UnitInfo *d2) +{ + if (sort_skill != job_skill::NONE) + { + df::unit_skill *s1 = binsearch_in_vector>(d1->unit->status.current_soul->skills, &df::unit_skill::id, sort_skill); + df::unit_skill *s2 = binsearch_in_vector>(d1->unit->status.current_soul->skills, &df::unit_skill::id, sort_skill); + int l1 = s1 ? s1->rating : 0; + int l2 = s2 ? s2->rating : 0; + int e1 = s1 ? s1->experience : 0; + int e2 = s2 ? s2->experience : 0; + if (descending) + { + if (l1 != l2) + return l1 > l2; + if (e1 != e2) + return e1 > e2; + } + else + { + if (l1 != l2) + return l1 < l2; + if (e1 != e2) + return e1 < e2; + } + } + if (sort_labor != unit_labor::NONE) + { + if (descending) + return d1->unit->status.labors[sort_labor] > d2->unit->status.labors[sort_labor]; + else + return d1->unit->status.labors[sort_labor] < d2->unit->status.labors[sort_labor]; + } + return sortByName(d1, d2); +} class viewscreen_unitlaborsst : public dfhack_viewscreen { public: - static viewscreen_unitlaborsst *create (char pushtype, df::viewscreen *scr = NULL); - void feed(set *events); void render(); @@ -267,86 +320,41 @@ public: std::string getFocusString() { return "unitlabors"; } - viewscreen_unitlaborsst(); + viewscreen_unitlaborsst(vector &src); ~viewscreen_unitlaborsst() { }; protected: vector units; - int filter; + altsort_mode altsort; int first_row, sel_row; int first_column, sel_column; int height, name_width, prof_width, labors_width; -// bool descending; -// int sort_skill; -// int sort_labor; - - void readUnits (); void calcSize (); }; -viewscreen_unitlaborsst::viewscreen_unitlaborsst() -{ - filter = FILTER_LIVING; - first_row = sel_row = 0; - first_column = sel_column = 0; - calcSize(); - readUnits(); -} - -void viewscreen_unitlaborsst::readUnits () +viewscreen_unitlaborsst::viewscreen_unitlaborsst(vector &src) { - for (size_t i = 0; i < units.size(); i++) - delete units[i]; - units.clear(); - - UnitInfo *cur = new UnitInfo; - for (size_t i = 0; i < world->units.active.size(); i++) + for (size_t i = 0; i < src.size(); i++) { - df::unit *unit = world->units.active[i]; + UnitInfo *cur = new UnitInfo; + df::unit *unit = src[i]; cur->unit = unit; cur->allowEdit = true; if (unit->race != ui->race_id) - { cur->allowEdit = false; - if (!(filter & FILTER_NONDWARVES)) - continue; - } if (unit->civ_id != ui->civ_id) - { cur->allowEdit = false; - if (!(filter & FILTER_NONCIV)) - continue; - } if (unit->flags1.bits.dead) - { cur->allowEdit = false; - if (!(filter & FILTER_DEAD)) - continue; - } - else - { - if (!(filter & FILTER_LIVING)) - continue; - } if (!ENUM_ATTR(profession, can_assign_labor, unit->profession)) - { cur->allowEdit = false; - if (!(filter & FILTER_NONWORKERS)) - continue; - } - - if (!unit->name.first_name.length()) - { - if (!(filter & FILTER_ANIMALS)) - continue; - } cur->name = Translation::TranslateName(&unit->name, false); cur->transname = Translation::TranslateName(&unit->name, true); @@ -354,9 +362,13 @@ void viewscreen_unitlaborsst::readUnits () cur->color = Units::getProfessionColor(unit); units.push_back(cur); - cur = new UnitInfo; } - delete cur; + std::sort(units.begin(), units.end(), sortByName); + + altsort = ALTSORT_NAME; + first_row = sel_row = 0; + first_column = sel_column = 0; + calcSize(); } void viewscreen_unitlaborsst::calcSize() @@ -421,8 +433,6 @@ void viewscreen_unitlaborsst::feed(set *events) return; } - // TODO - allow modifying filters - if (!units.size()) return; @@ -501,9 +511,46 @@ void viewscreen_unitlaborsst::feed(set *events) unit->status.labors[col.labor] = !unit->status.labors[col.labor]; } - // TODO: add sorting + if (events->count(interface_key::SECONDSCROLL_UP) || events->count(interface_key::SECONDSCROLL_DOWN)) + { + descending = events->count(interface_key::SECONDSCROLL_UP); + sort_skill = columns[sel_column].skill; + sort_labor = columns[sel_column].labor; + std::sort(units.begin(), units.end(), sortBySkill); + } + + if (events->count(interface_key::SECONDSCROLL_PAGEUP) || events->count(interface_key::SECONDSCROLL_PAGEDOWN)) + { + descending = events->count(interface_key::SECONDSCROLL_PAGEUP); + switch (altsort) + { + case ALTSORT_NAME: + std::sort(units.begin(), units.end(), sortByName); + break; + case ALTSORT_PROFESSION: + std::sort(units.begin(), units.end(), sortByProfession); + break; + } + } + if (events->count(interface_key::CHANGETAB)) + { + switch (altsort) + { + case ALTSORT_NAME: + altsort = ALTSORT_PROFESSION; + break; + case ALTSORT_PROFESSION: + altsort = ALTSORT_NAME; + break; + } + } } +void OutputString(int8_t color, int &x, int y, const std::string &text) +{ + Screen::paintString(Screen::Pen(' ', color, 0), x, y, text); + x += text.length(); +} void viewscreen_unitlaborsst::render() { if (Screen::isDismissed(this)) @@ -528,6 +575,7 @@ void viewscreen_unitlaborsst::render() fg = 0; bg = 7; } + Screen::paintTile(Screen::Pen(columns[col_offset].label[0], fg, bg), 1 + name_width + 1 + prof_width + 1 + col, 1); Screen::paintTile(Screen::Pen(columns[col_offset].label[1], fg, bg), 1 + name_width + 1 + prof_width + 1 + col, 2); } @@ -537,6 +585,7 @@ void viewscreen_unitlaborsst::render() int row_offset = row + first_row; if (row_offset >= units.size()) break; + UnitInfo *cur = units[row_offset]; df::unit *unit = cur->unit; int8_t fg = 15, bg = 0; @@ -554,7 +603,8 @@ void viewscreen_unitlaborsst::render() profession.resize(prof_width); fg = cur->color; bg = 0; - Screen::paintString(Screen::Pen(' ', fg, bg), 1 + prof_width + 1, 3 + row, profession); + + Screen::paintString(Screen::Pen(' ', fg, bg), 1 + name_width + 1, 3 + row, profession); // Print unit's skills and labor assignments for (int col = 0; col < labors_width; col++) @@ -586,15 +636,21 @@ void viewscreen_unitlaborsst::render() if (cur != NULL) { df::unit *unit = cur->unit; - string str = cur->transname; - if (str.length()) - str += ", "; - str += cur->profession; - str += ":"; + int x = 1; + Screen::paintString(Screen::Pen(' ', 15, 0), x, 3 + height + 2, cur->transname); + x += cur->transname.length(); - Screen::paintString(Screen::Pen(' ', 15, 0), 1, 3 + height + 2, str); - int y = 1 + str.length() + 1; + if (cur->transname.length()) + { + Screen::paintString(Screen::Pen(' ', 15, 0), x, 3 + height + 2, ", "); + x += 2; + } + Screen::paintString(Screen::Pen(' ', 15, 0), x, 3 + height + 2, cur->profession); + x += cur->profession.length(); + Screen::paintString(Screen::Pen(' ', 15, 0), x, 3 + height + 2, ": "); + x += 2; + string str; if (columns[sel_column].skill == job_skill::NONE) { str = ENUM_ATTR_STR(unit_labor, caption, columns[sel_column].labor); @@ -602,7 +658,6 @@ void viewscreen_unitlaborsst::render() str += " Enabled"; else str += " Not Enabled"; - Screen::paintString(Screen::Pen(' ', 9, 0), y, 3 + height + 2, str); } else { @@ -618,11 +673,41 @@ void viewscreen_unitlaborsst::render() } else str = stl_sprintf("Not %s (0/500)", ENUM_ATTR_STR(job_skill, caption_noun, columns[sel_column].skill)); - Screen::paintString(Screen::Pen(' ', 9, 0), y, 3 + height + 2, str); } + Screen::paintString(Screen::Pen(' ', 9, 0), x, 3 + height + 2, str); } - // TODO - print command help info + int x = 1; + OutputString( 2, x, gps->dimy - 3, "Enter"); // SELECT key + OutputString(15, x, gps->dimy - 3, ": Toggle labor"); + x += 2; + + OutputString( 2, x, gps->dimy - 3, "Esc"); // LEAVESCREEN key + OutputString(15, x, gps->dimy - 3, ": Done"); + + x = 1; + OutputString( 2, x, gps->dimy - 2, "+"); // SECONDSCROLL_DOWN key + OutputString( 2, x, gps->dimy - 2, "-"); // SECONDSCROLL_UP key + OutputString(15, x, gps->dimy - 2, ": Sort by Skill"); + x += 2; + + OutputString( 2, x, gps->dimy - 2, "*"); // SECONDSCROLL_PAGEDOWN key + OutputString( 2, x, gps->dimy - 2, "/"); // SECONDSCROLL_PAGEUP key + OutputString(15, x, gps->dimy - 2, ": Sort by ("); + OutputString( 2, x, gps->dimy - 2, "Tab"); // CHANGETAB key + OutputString(15, x, gps->dimy - 2, ") "); + switch (altsort) + { + case ALTSORT_NAME: + OutputString(15, x, gps->dimy - 2, "Name"); + break; + case ALTSORT_PROFESSION: + OutputString(15, x, gps->dimy - 2, "Profession"); + break; + default: + OutputString(15, x, gps->dimy - 2, "Unknown"); + break; + } } struct unitlist_hook : df::viewscreen_unitlistst @@ -633,9 +718,11 @@ struct unitlist_hook : df::viewscreen_unitlistst { if (input->count(interface_key::UNITVIEW_PRF_PROF)) { - Screen::dismiss(this); - Screen::show(new viewscreen_unitlaborsst()); - return; + if (units[page].size()) + { + Screen::show(new viewscreen_unitlaborsst(units[page])); + return; + } } INTERPOSE_NEXT(feed)(input); }