Merge pull request #1386 from billw2012/lm-disable-labor

labormanager: add option to disable the management of a labor.
develop
Lethosor 2018-12-27 16:49:01 -05:00 committed by GitHub
commit 58fd98cb12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 134 additions and 75 deletions

@ -100,6 +100,11 @@ enum ConfigFlags {
CF_ALLOW_HUNTING = 4, CF_ALLOW_HUNTING = 4,
}; };
// Value of 0 for max dwarfs means uncapped.
const int MAX_DWARFS_NONE = 0;
// Value < 0 for max dwarfs means don't manager the labor.
const int MAX_DWARFS_UNMANAGED = -1;
// Here go all the command declarations... // Here go all the command declarations...
// mostly to allow having the mandatory stuff on top of the file and commands on the bottom // mostly to allow having the mandatory stuff on top of the file and commands on the bottom
@ -390,16 +395,18 @@ struct labor_info
int idle_dwarfs; int idle_dwarfs;
int busy_dwarfs; int busy_dwarfs;
int priority() { return config.ival(1); } int priority() const { return config.ival(1); }
void set_priority(int priority) { config.ival(1) = priority; } void set_priority(int priority) { config.ival(1) = priority; }
int maximum_dwarfs() { return config.ival(2); } bool is_unmanaged() const { return maximum_dwarfs() == MAX_DWARFS_UNMANAGED; }
int maximum_dwarfs() const { return config.ival(2); }
void set_maximum_dwarfs(int maximum_dwarfs) { config.ival(2) = maximum_dwarfs; } void set_maximum_dwarfs(int maximum_dwarfs) { config.ival(2) = maximum_dwarfs; }
int time_since_last_assigned() int time_since_last_assigned() const
{ {
return (*df::global::cur_year - config.ival(3)) * 403200 + *df::global::cur_year_tick - config.ival(4); return (*df::global::cur_year - config.ival(3)) * 403200 + *df::global::cur_year_tick - config.ival(4);
} }
void mark_assigned() { void mark_assigned() {
config.ival(3) = (*df::global::cur_year); config.ival(3) = (*df::global::cur_year);
config.ival(4) = (*df::global::cur_year_tick); config.ival(4) = (*df::global::cur_year_tick);
@ -412,7 +419,6 @@ enum tools_enum {
TOOLS_MAX TOOLS_MAX
}; };
struct labor_default struct labor_default
{ {
int priority; int priority;
@ -524,10 +530,12 @@ struct dwarf_info_t
bool has_children; bool has_children;
bool armed; bool armed;
int unmanaged_labors_assigned;
df::unit_labor using_labor; df::unit_labor using_labor;
dwarf_info_t(df::unit* dw) : dwarf(dw), state(OTHER), dwarf_info_t(df::unit* dw) : dwarf(dw), state(OTHER),
clear_all(false), high_skill(0), has_children(false), armed(false), using_labor(df::unit_labor::NONE) clear_all(false), high_skill(0), has_children(false), armed(false), using_labor(df::unit_labor::NONE), unmanaged_labors_assigned(0)
{ {
for (int e = TOOL_NONE; e < TOOLS_MAX; e++) for (int e = TOOL_NONE; e < TOOLS_MAX; e++)
has_tool[e] = false; has_tool[e] = false;
@ -841,6 +849,11 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector <Plugin
" Enables or disables the plugin.\n" " Enables or disables the plugin.\n"
" labormanager max <labor> <maximum>\n" " labormanager max <labor> <maximum>\n"
" Set max number of dwarves assigned to a labor.\n" " Set max number of dwarves assigned to a labor.\n"
" labormanager max <labor> unmanaged\n"
" labormanager max <labor> disable\n"
" Don't attempt to manage this labor.\n"
" Any dwarves with unmanaged labors assigned will be less\n"
" likely to have managed labors assigned to them.\n"
" labormanager max <labor> none\n" " labormanager max <labor> none\n"
" Unrestrict the number of dwarves assigned to a labor.\n" " Unrestrict the number of dwarves assigned to a labor.\n"
" labormanager priority <labor> <priority>\n" " labormanager priority <labor> <priority>\n"
@ -857,8 +870,8 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector <Plugin
" When enabled, labormanager periodically checks your dwarves and enables or\n" " When enabled, labormanager periodically checks your dwarves and enables or\n"
" disables labors. Generally, each dwarf will be assigned exactly one labor.\n" " disables labors. Generally, each dwarf will be assigned exactly one labor.\n"
" Warning: labormanager will override any manual changes you make to labors\n" " Warning: labormanager will override any manual changes you make to labors\n"
" while it is enabled. Do not try to run both autolabor and labormanager at\n" " while it is enabled, except where the labor is marked as unmanaged.\n"
" the same time.\n" " Do not try to run both autolabor and labormanager at the same time.\n"
)); ));
generate_labor_to_skill_map(); generate_labor_to_skill_map();
@ -944,7 +957,7 @@ private:
private: private:
void set_labor(dwarf_info_t* dwarf, df::unit_labor labor, bool value) void set_labor(dwarf_info_t* dwarf, df::unit_labor labor, bool value)
{ {
if (labor >= 0 && labor <= ENUM_LAST_ITEM(unit_labor)) if (labor >= 0 && labor <= ENUM_LAST_ITEM(unit_labor) && !labor_infos[labor].is_unmanaged())
{ {
if (!Units::isValidLabor(dwarf->dwarf, labor)) if (!Units::isValidLabor(dwarf->dwarf, labor))
{ {
@ -954,7 +967,6 @@ private:
ENUM_KEY_STR(unit_labor, labor).c_str()); ENUM_KEY_STR(unit_labor, labor).c_str());
return; return;
} }
bool old = dwarf->dwarf->status.labors[labor]; bool old = dwarf->dwarf->status.labors[labor];
dwarf->dwarf->status.labors[labor] = value; dwarf->dwarf->status.labors[labor] = value;
if (old != value) if (old != value)
@ -1009,7 +1021,7 @@ private:
df::unit_labor labor = labor_mapper->find_job_labor(j); df::unit_labor labor = labor_mapper->find_job_labor(j);
if (labor != df::unit_labor::NONE) if (labor != df::unit_labor::NONE && !labor_infos[labor].is_unmanaged())
{ {
labor_needed[labor]++; labor_needed[labor]++;
if (worker == -1) if (worker == -1)
@ -1136,7 +1148,7 @@ private:
{ {
df::item* item = *i; df::item* item = *i;
if (item->flags.bits.dump) if (item->flags.bits.dump && !labor_infos[df::unit_labor::HAUL_REFUSE].is_unmanaged())
labor_needed[df::unit_labor::HAUL_REFUSE]++; labor_needed[df::unit_labor::HAUL_REFUSE]++;
if (item->flags.whole & bad_flags.whole) if (item->flags.whole & bad_flags.whole)
@ -1382,6 +1394,8 @@ private:
dwarf->state = state; dwarf->state = state;
dwarf->unmanaged_labors_assigned = 0;
FOR_ENUM_ITEMS(unit_labor, l) FOR_ENUM_ITEMS(unit_labor, l)
{ {
if (l == df::unit_labor::NONE) if (l == df::unit_labor::NONE)
@ -1389,6 +1403,8 @@ private:
if (dwarf->dwarf->status.labors[l]) if (dwarf->dwarf->status.labors[l])
if (state == IDLE) if (state == IDLE)
labor_infos[l].idle_dwarfs++; labor_infos[l].idle_dwarfs++;
if (labor_infos[l].is_unmanaged())
dwarf->unmanaged_labors_assigned++;
} }
@ -1436,7 +1452,7 @@ private:
FOR_ENUM_ITEMS(unit_labor, labor) FOR_ENUM_ITEMS(unit_labor, labor)
{ {
if (labor == df::unit_labor::NONE) if (labor == df::unit_labor::NONE || labor_infos[labor].is_unmanaged())
continue; continue;
df::job_skill skill = labor_to_skill[labor]; df::job_skill skill = labor_to_skill[labor];
@ -1456,7 +1472,7 @@ private:
{ {
FOR_ENUM_ITEMS(unit_labor, labor) FOR_ENUM_ITEMS(unit_labor, labor)
{ {
if (labor == unit_labor::NONE) if (labor == unit_labor::NONE || labor_infos[labor].is_unmanaged())
continue; continue;
if (Units::isValidLabor(dwarf->dwarf, labor)) if (Units::isValidLabor(dwarf->dwarf, labor))
set_labor(dwarf, labor, false); set_labor(dwarf, labor, false);
@ -1572,6 +1588,9 @@ private:
score -= Units::computeMovementSpeed(d->dwarf); score -= Units::computeMovementSpeed(d->dwarf);
// significantly disfavor dwarves who have unmanaged labors assigned
score -= 1000 * d->unmanaged_labors_assigned;
return score; return score;
} }
@ -1700,67 +1719,79 @@ public:
if (l == df::unit_labor::NONE) if (l == df::unit_labor::NONE)
continue; continue;
int before = labor_needed[l]; if (!labor_infos[l].is_unmanaged())
{
labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]); int before = labor_needed[l];
if (default_labor_infos[l].tool != TOOL_NONE) labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]);
labor_needed[l] = std::min(labor_needed[l], tool_count[default_labor_infos[l].tool] - tool_in_use[default_labor_infos[l].tool]);
if (print_debug && before != labor_needed[l]) if (default_labor_infos[l].tool != TOOL_NONE)
out.print("labor %s reduced from %d to %d\n", ENUM_KEY_STR(unit_labor, l).c_str(), before, labor_needed[l]); labor_needed[l] = std::min(labor_needed[l], tool_count[default_labor_infos[l].tool] - tool_in_use[default_labor_infos[l].tool]);
if (print_debug && before != labor_needed[l])
out.print("labor %s reduced from %d to %d\n", ENUM_KEY_STR(unit_labor, l).c_str(), before, labor_needed[l]);
}
else
{
labor_needed[l] = 0;
}
} }
/* assign food haulers for rotting food items */ /* assign food haulers for rotting food items */
if (!labor_infos[df::unit_labor::HAUL_FOOD].is_unmanaged())
if (priority_food > 0 && labor_infos[df::unit_labor::HAUL_FOOD].idle_dwarfs > 0)
priority_food = 1;
if (print_debug)
out.print("priority food count = %d\n", priority_food);
while (!available_dwarfs.empty() && priority_food > 0)
{ {
std::list<dwarf_info_t*>::iterator bestdwarf = available_dwarfs.begin(); if (priority_food > 0 && labor_infos[df::unit_labor::HAUL_FOOD].idle_dwarfs > 0)
priority_food = 1;
int best_score = INT_MIN; if (print_debug)
out.print("priority food count = %d\n", priority_food);
for (std::list<dwarf_info_t*>::iterator k = available_dwarfs.begin(); k != available_dwarfs.end(); k++) while (!available_dwarfs.empty() && priority_food > 0)
{ {
dwarf_info_t* d = (*k); std::list<dwarf_info_t*>::iterator bestdwarf = available_dwarfs.begin();
int best_score = INT_MIN;
if (Units::isValidLabor(d->dwarf, df::unit_labor::HAUL_FOOD)) for (std::list<dwarf_info_t*>::iterator k = available_dwarfs.begin(); k != available_dwarfs.end(); k++)
{ {
int score = score_labor(d, df::unit_labor::HAUL_FOOD); dwarf_info_t* d = (*k);
if (score > best_score) if (Units::isValidLabor(d->dwarf, df::unit_labor::HAUL_FOOD))
{ {
bestdwarf = k; int score = score_labor(d, df::unit_labor::HAUL_FOOD);
best_score = score;
if (score > best_score)
{
bestdwarf = k;
best_score = score;
}
} }
} }
}
if (best_score > INT_MIN)
{
if (print_debug)
out.print("LABORMANAGER: assign \"%s\" labor %s score=%d (priority food)\n", (*bestdwarf)->dwarf->name.first_name.c_str(), ENUM_KEY_STR(unit_labor, df::unit_labor::HAUL_FOOD).c_str(), best_score);
FOR_ENUM_ITEMS(unit_labor, l) if (best_score > INT_MIN)
{ {
if (l == df::unit_labor::NONE) if (print_debug)
continue; out.print("LABORMANAGER: assign \"%s\" labor %s score=%d (priority food)\n", (*bestdwarf)->dwarf->name.first_name.c_str(), ENUM_KEY_STR(unit_labor, df::unit_labor::HAUL_FOOD).c_str(), best_score);
if (Units::isValidLabor((*bestdwarf)->dwarf, l))
set_labor(*bestdwarf, l, l == df::unit_labor::HAUL_FOOD); FOR_ENUM_ITEMS(unit_labor, l)
{
if (l == df::unit_labor::NONE)
continue;
if (Units::isValidLabor((*bestdwarf)->dwarf, l))
set_labor(*bestdwarf, l, l == df::unit_labor::HAUL_FOOD);
}
available_dwarfs.erase(bestdwarf);
priority_food--;
} }
else
break;
available_dwarfs.erase(bestdwarf);
priority_food--;
} }
else }
break; else
{
priority_food = 0;
} }
if (print_debug) if (print_debug)
@ -1779,12 +1810,15 @@ public:
for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) for (auto i = labor_needed.begin(); i != labor_needed.end(); i++)
{ {
df::unit_labor l = i->first; df::unit_labor l = i->first;
if (l == df::unit_labor::NONE) if (l == df::unit_labor::NONE || labor_infos[l].is_unmanaged())
continue; continue;
if (labor_infos[l].maximum_dwarfs() > 0 && const int user_specified_max_dwarfs = labor_infos[l].maximum_dwarfs();
i->second > labor_infos[l].maximum_dwarfs())
i->second = labor_infos[l].maximum_dwarfs(); if (user_specified_max_dwarfs != MAX_DWARFS_NONE && i->second > user_specified_max_dwarfs)
{
i->second = user_specified_max_dwarfs;
}
int priority = labor_infos[l].priority(); int priority = labor_infos[l].priority();
@ -1945,7 +1979,7 @@ public:
FOR_ENUM_ITEMS(unit_labor, l) FOR_ENUM_ITEMS(unit_labor, l)
{ {
if (l == df::unit_labor::NONE) if (l == df::unit_labor::NONE || labor_infos[l].is_unmanaged())
continue; continue;
if (l == (*d)->using_labor) if (l == (*d)->using_labor)
continue; continue;
@ -2002,12 +2036,17 @@ public:
set_labor(canary_dwarf, df::unit_labor::CLEAN, true); set_labor(canary_dwarf, df::unit_labor::CLEAN, true);
/* Also set the canary to remove constructions, because we have no way yet to tell if there are constructions needing removal */ /* Also set the canary to remove constructions, because we have no way yet to tell if there are constructions needing removal */
if (!labor_infos[df::unit_labor::REMOVE_CONSTRUCTION].is_unmanaged())
set_labor(canary_dwarf, df::unit_labor::REMOVE_CONSTRUCTION, true); {
set_labor(canary_dwarf, df::unit_labor::REMOVE_CONSTRUCTION, true);
}
/* Set HAUL_WATER so we can detect ponds that need to be filled ponds. */ /* Set HAUL_WATER so we can detect ponds that need to be filled ponds. */
set_labor(canary_dwarf, df::unit_labor::HAUL_WATER, true); if (!labor_infos[df::unit_labor::HAUL_WATER].is_unmanaged())
{
set_labor(canary_dwarf, df::unit_labor::HAUL_WATER, true);
}
if (print_debug) if (print_debug)
out.print("Setting %s as the hauling canary\n", canary_dwarf->dwarf->name.first_name.c_str()); out.print("Setting %s as the hauling canary\n", canary_dwarf->dwarf->name.first_name.c_str());
@ -2027,7 +2066,7 @@ public:
{ {
FOR_ENUM_ITEMS(unit_labor, l) FOR_ENUM_ITEMS(unit_labor, l)
{ {
if (l == df::unit_labor::NONE) if (l == df::unit_labor::NONE || labor_infos[l].is_unmanaged())
continue; continue;
if (Units::isValidLabor((*d)->dwarf, l)) if (Units::isValidLabor((*d)->dwarf, l))
@ -2059,13 +2098,16 @@ public:
} }
} }
set_labor(*d, df::unit_labor::PULL_LEVER, true); if (!labor_infos[df::unit_labor::PULL_LEVER].is_unmanaged())
{
set_labor(*d, df::unit_labor::PULL_LEVER, true);
}
if (any) continue; if (any) continue;
FOR_ENUM_ITEMS(unit_labor, l) FOR_ENUM_ITEMS(unit_labor, l)
{ {
if (l == df::unit_labor::NONE) if (l == df::unit_labor::NONE || labor_infos[l].is_unmanaged())
continue; continue;
if (to_assign[l] > 0 || l == df::unit_labor::CLEAN) if (to_assign[l] > 0 || l == df::unit_labor::CLEAN)
@ -2086,7 +2128,7 @@ public:
FOR_ENUM_ITEMS(unit_labor, l) FOR_ENUM_ITEMS(unit_labor, l)
{ {
if (l == df::unit_labor::NONE) if (l == df::unit_labor::NONE || labor_infos[l].is_unmanaged())
continue; continue;
tools_enum t = default_labor_infos[l].tool; tools_enum t = default_labor_infos[l].tool;
@ -2183,25 +2225,40 @@ void print_labor(df::unit_labor labor, color_ostream &out)
out << labor_name << ": "; out << labor_name << ": ";
for (int i = 0; i < 20 - (int)labor_name.length(); i++) for (int i = 0; i < 20 - (int)labor_name.length(); i++)
out << ' '; out << ' ';
out << "priority " << labor_infos[labor].priority() const auto& labor_info = labor_infos[labor];
<< ", maximum " << labor_infos[labor].maximum_dwarfs() if (labor_info.is_unmanaged())
<< ", currently " << labor_infos[labor].active_dwarfs << " dwarfs (" {
<< labor_infos[labor].busy_dwarfs << " busy, " out << "UNMANAGED";
<< labor_infos[labor].idle_dwarfs << " idle)" }
else
{
out << "priority " << labor_info.priority();
if (labor_info.maximum_dwarfs() == MAX_DWARFS_NONE)
out << ", no maximum";
else
out << ", maximum " << labor_info.maximum_dwarfs();
}
out << ", currently " << labor_info.active_dwarfs << " dwarfs ("
<< labor_info.busy_dwarfs << " busy, "
<< labor_info.idle_dwarfs << " idle)"
<< endl; << endl;
} }
df::unit_labor lookup_labor_by_name(std::string& name) df::unit_labor lookup_labor_by_name(std::string name)
{ {
df::unit_labor labor = df::unit_labor::NONE; // We should accept incorrect casing, there is no ambiguity.
std::transform(name.begin(), name.end(), name.begin(), ::toupper);
FOR_ENUM_ITEMS(unit_labor, test_labor) FOR_ENUM_ITEMS(unit_labor, test_labor)
{ {
if (name == ENUM_KEY_STR(unit_labor, test_labor)) if (name == ENUM_KEY_STR(unit_labor, test_labor))
labor = test_labor; {
return test_labor;
}
} }
return labor; return df::unit_labor::NONE;
} }
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) DFhackCExport command_result plugin_enable(color_ostream &out, bool enable)
@ -2261,7 +2318,9 @@ command_result labormanager(color_ostream &out, std::vector <std::string> & para
int v; int v;
if (parameters[2] == "none") if (parameters[2] == "none")
v = 0; v = MAX_DWARFS_NONE;
else if (parameters[2] == "disable" || parameters[2] == "unmanaged")
v = MAX_DWARFS_UNMANAGED;
else else
v = atoi(parameters[2].c_str()); v = atoi(parameters[2].c_str());