diff --git a/plugins/autolabor.cpp b/plugins/autolabor.cpp index cfd9419db..73f8e7c27 100644 --- a/plugins/autolabor.cpp +++ b/plugins/autolabor.cpp @@ -23,6 +23,15 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include + +#include using std::string; using std::endl; @@ -446,21 +455,44 @@ static const struct labor_default default_labor_infos[] = { /* WAX_WORKING */ {AUTOMATIC, false, 1, 200, 0}, }; -static const df::job_skill noble_skills[] = { - df::enums::job_skill::APPRAISAL, - df::enums::job_skill::ORGANIZATION, - df::enums::job_skill::RECORD_KEEPING, +static const int responsibility_penalties[] = { + 0, /* LAW_MAKING */ + 0, /* LAW_ENFORCEMENT */ + 3000, /* RECEIVE_DIPLOMATS */ + 0, /* MEET_WORKERS */ + 1000, /* MANAGE_PRODUCTION */ + 3000, /* TRADE */ + 1000, /* ACCOUNTING */ + 0, /* ESTABLISH_COLONY_TRADE_AGREEMENTS */ + 0, /* MAKE_INTRODUCTIONS */ + 0, /* MAKE_PEACE_AGREEMENTS */ + 0, /* MAKE_TOPIC_AGREEMENTS */ + 0, /* COLLECT_TAXES */ + 0, /* ESCORT_TAX_COLLECTOR */ + 0, /* EXECUTIONS */ + 0, /* TAME_EXOTICS */ + 0, /* RELIGION */ + 0, /* ATTACK_ENEMIES */ + 0, /* PATROL_TERRITORY */ + 0, /* MILITARY_GOALS */ + 0, /* MILITARY_STRATEGY */ + 0, /* UPGRADE_SQUAD_EQUIPMENT */ + 0, /* EQUIPMENT_MANIFESTS */ + 0, /* SORT_AMMUNITION */ + 0, /* BUILD_MORALE */ + 5000 /* HEALTH_MANAGEMENT */ }; struct dwarf_info_t { int highest_skill; int total_skill; - bool is_best_noble; int mastery_penalty; int assigned_jobs; dwarf_state state; bool has_exclusive_labor; + int noble_penalty; // penalty for assignment due to noble status + bool medical; // this dwarf has medical responsibility }; static bool isOptionEnabled(unsigned flag) @@ -714,15 +746,45 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) std::vector dwarf_info(n_dwarfs); - std::vector best_noble(ARRAY_COUNT(noble_skills)); - std::vector highest_noble_skill(ARRAY_COUNT(noble_skills)); - std::vector highest_noble_experience(ARRAY_COUNT(noble_skills)); - // Find total skill and highest skill for each dwarf. More skilled dwarves shouldn't be used for minor tasks. for (int dwarf = 0; dwarf < n_dwarfs; dwarf++) { - assert(dwarfs[dwarf]->status.souls.size() > 0); +// assert(dwarfs[dwarf]->status.souls.size() > 0); +// assert fails can cause DF to crash, so don't do that + + if (dwarfs[dwarf]->status.souls.size() <= 0) + continue; + + // compute noble penalty + + int noble_penalty = 0; + + df::historical_figure* hf = df::historical_figure::find(dwarfs[dwarf]->hist_figure_id); + for (int i = 0; i < hf->entity_links.size(); i++) { + df::histfig_entity_link* hfelink = hf->entity_links.at(i); + if (hfelink->getType() == df::histfig_entity_link_type::POSITION) { + df::histfig_entity_link_positionst *epos = + (df::histfig_entity_link_positionst*) hfelink; + df::historical_entity* entity = df::historical_entity::find(epos->entity_id); + if (!entity) + continue; + df::entity_position_assignment* assignment = binsearch_in_vector(entity->positions.assignments, epos->assignment_id); + if (!assignment) + continue; + df::entity_position* position = binsearch_in_vector(entity->positions.own, assignment->position_id); + if (!position) + continue; + + for (int n = 0; n < 25; n++) + if (position->responsibilities[n]) + noble_penalty += responsibility_penalties[n]; + + if (position->responsibilities[df::entity_position_responsibility::HEALTH_MANAGEMENT]) + dwarf_info[dwarf].medical = true; + + } + } for (auto s = dwarfs[dwarf]->status.souls[0]->skills.begin(); s != dwarfs[dwarf]->status.souls[0]->skills.end(); s++) { @@ -733,30 +795,6 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) int skill_level = (*s)->rating; int skill_experience = (*s)->experience; - // Track the dwarfs with the best Appraisal, Organization, and Record Keeping skills. - // They are likely to have appointed noble positions, so should be kept free where possible. - - int noble_skill_id = -1; - for (int i = 0; i < ARRAY_COUNT(noble_skills); i++) - { - if (skill == noble_skills[i]) - noble_skill_id = i; - } - - if (noble_skill_id >= 0) - { - assert(noble_skill_id < ARRAY_COUNT(noble_skills)); - - if (highest_noble_skill[noble_skill_id] < skill_level || - (highest_noble_skill[noble_skill_id] == skill_level && - highest_noble_experience[noble_skill_id] < skill_experience)) - { - highest_noble_skill[noble_skill_id] = skill_level; - highest_noble_experience[noble_skill_id] = skill_experience; - best_noble[noble_skill_id] = dwarf; - } - } - // Track total & highest skill among normal/medical skills. (We don't care about personal or social skills.) if (skill_class != df::enums::job_skill_class::Normal && skill_class != df::enums::job_skill_class::Medical) @@ -768,24 +806,13 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) } } - // Mark the best nobles, so we try to keep them non-busy. (It would be better to find the actual assigned nobles.) - - for (int i = 0; i < ARRAY_COUNT(noble_skills); i++) - { - assert(best_noble[i] >= 0); - assert(best_noble[i] < n_dwarfs); - - dwarf_info[best_noble[i]].is_best_noble = true; - } - // Calculate a base penalty for using each dwarf for a task he isn't good at. for (int dwarf = 0; dwarf < n_dwarfs; dwarf++) { dwarf_info[dwarf].mastery_penalty -= 40 * dwarf_info[dwarf].highest_skill; dwarf_info[dwarf].mastery_penalty -= 10 * dwarf_info[dwarf].total_skill; - if (dwarf_info[dwarf].is_best_noble) - dwarf_info[dwarf].mastery_penalty -= 250; + dwarf_info[dwarf].mastery_penalty -= dwarf_info[dwarf].noble_penalty; for (int labor = ENUM_FIRST_ITEM(unit_labor); labor <= ENUM_LAST_ITEM(unit_labor); labor++) { @@ -1032,6 +1059,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) * Note that only idle and busy dwarfs count towards the number of dwarfs. "Other" dwarfs * (sleeping, eating, on break, etc.) will have labors assigned, but will not be counted. * Military and children/nobles will not have labors assigned. + * Dwarfs with the "health management" responsibility are always assigned DIAGNOSIS. */ for (int i = 0; i < candidates.size() && labor_infos[labor].active_dwarfs < max_dwarfs; i++) { @@ -1040,6 +1068,8 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) assert(dwarf >= 0); assert(dwarf < n_dwarfs); + + bool preferred_dwarf = false; if (want_idle_dwarf && dwarf_info[dwarf].state == IDLE) preferred_dwarf = true; @@ -1047,6 +1077,8 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) preferred_dwarf = true; if (previously_enabled[dwarf] && labor_infos[labor].is_exclusive) preferred_dwarf = true; + if (dwarf_info[dwarf].medical && labor == df::unit_labor::DIAGNOSE) + preferred_dwarf = true; if (labor_infos[labor].active_dwarfs >= min_dwarfs && !preferred_dwarf) continue;