summaryrefslogtreecommitdiff
path: root/plugins/autolabor.cpp
diff options
context:
space:
mode:
authorRossM2012-04-03 23:26:15 -0700
committerRossM2012-04-03 23:26:15 -0700
commita76de8b777d3f73ffc64387c6385a6196e7f704c (patch)
treee01c896d2ebadf2fe10441f1af0081705419da24 /plugins/autolabor.cpp
parent285afa2594822bd870ed289bdbf2d12d72741d22 (diff)
downloaddfhack-a76de8b777d3f73ffc64387c6385a6196e7f704c.tar.gz
dfhack-a76de8b777d3f73ffc64387c6385a6196e7f704c.tar.bz2
dfhack-a76de8b777d3f73ffc64387c6385a6196e7f704c.tar.xz
Fix detection of military dwarves. Add overview comments explaining why
autolabor works how it does.
Diffstat (limited to 'plugins/autolabor.cpp')
-rw-r--r--plugins/autolabor.cpp45
1 files changed, 42 insertions, 3 deletions
diff --git a/plugins/autolabor.cpp b/plugins/autolabor.cpp
index 5fb5216e..fedde8f3 100644
--- a/plugins/autolabor.cpp
+++ b/plugins/autolabor.cpp
@@ -31,6 +31,31 @@ using df::global::world;
#define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0]))
+/*
+ * Autolabor module for dfhack
+ *
+ * The idea behind this module is to constantly adjust labors so that the right dwarves
+ * are assigned to new tasks. The key is that, for almost all labors, once a dwarf begins
+ * a job it will finish that job even if the associated labor is removed. Thus the
+ * strategy is to frequently decide, for each labor, which dwarves should possibly take
+ * a new job for that labor if it comes in and which shouldn't, and then set the labors
+ * appropriately. The updating should happen as often as can be reasonably done without
+ * causing lag.
+ *
+ * The obvious thing to do is to just set each labor on a single idle dwarf who is best
+ * suited to doing new jobs of that labor. This works in a way, but it leads to a lot
+ * of idle dwarves since only one dwarf will be dispatched for each labor in an update
+ * cycle, and dwarves that finish tasks will wait for the next update before being
+ * dispatched. An improvement is to also set some labors on dwarves that are currently
+ * doing a job, so that they will immediately take a new job when they finish. The
+ * details of which dwarves should have labors set is mostly a heuristic.
+ *
+ * A complication to the above simple scheme is labors that have associated equipment.
+ * Enabling/disabling these labors causes dwarves to change equipment, and disabling
+ * them in the middle of a job may cause the job to be abandoned. Those labors
+ * (mining, hunting, and woodcutting) need to be handled carefully to minimize churn.
+ */
+
static int enable_autolabor = 0;
static bool print_debug = 0;
@@ -659,11 +684,11 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
{
dwarf_info[dwarf].state = CHILD;
}
+ else if (ENUM_ATTR(profession, military, dwarfs[dwarf]->profession))
+ dwarf_info[dwarf].state = MILITARY;
else if (dwarfs[dwarf]->job.current_job == NULL)
{
- if (ENUM_ATTR(profession, military, dwarfs[dwarf]->profession))
- dwarf_info[dwarf].state = MILITARY;
- else if (is_on_break)
+ if (is_on_break)
dwarf_info[dwarf].state = OTHER;
else if (dwarfs[dwarf]->meetings.size() > 0)
dwarf_info[dwarf].state = OTHER;
@@ -773,6 +798,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
auto mode = labor_infos[labor].mode;
+ // Find candidate dwarfs, and calculate a preference value for each dwarf
for (int dwarf = 0; dwarf < n_dwarfs; dwarf++)
{
if (dwarf_info[dwarf].state == CHILD)
@@ -827,9 +853,11 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
}
+ // Sort candidates by preference value
values_sorter ivs(values);
std::sort(candidates.begin(), candidates.end(), ivs);
+ // Disable the labor on everyone
for (int dwarf = 0; dwarf < n_dwarfs; dwarf++)
{
if (dwarf_info[dwarf].state == CHILD)
@@ -852,6 +880,17 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
if (state_count[IDLE] < 2)
want_idle_dwarf = false;
+ /*
+ * Assign dwarfs to this labor. We assign at least the minimum number of dwarfs, in
+ * order of preference, and then assign additional dwarfs that meet any of these conditions:
+ * - The dwarf is idle and there are no idle dwarves assigned to this labor
+ * - The dwarf has nonzero skill associated with the labor
+ * - The labor is mining, hunting, or woodcutting and the dwarf currently has it enabled.
+ * We stop assigning dwarfs when we reach the maximum allowed.
+ * 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.
+ */
for (int i = 0; i < candidates.size() && labor_infos[labor].active_dwarfs < max_dwarfs; i++)
{
int dwarf = candidates[i];