From 45564ca0cb82d512dad4c6aa0c6dbe18b63f207e Mon Sep 17 00:00:00 2001 From: Kelly Martin Date: Sat, 1 Dec 2012 23:12:41 -0600 Subject: [PATCH] Autolabor: generating haulers based on unstockpiled items (less than ideal). Fix wrong build labor for Farmer's workshop. Add build labor function for constructions (also works for furnaces and trade depots). Add architect detection. Use a different mechanism for selecting dwarfs for labors. --- plugins/autolabor.cpp | 148 +++++++++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 60 deletions(-) diff --git a/plugins/autolabor.cpp b/plugins/autolabor.cpp index 5d90610d9..846ca8e64 100644 --- a/plugins/autolabor.cpp +++ b/plugins/autolabor.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include @@ -529,7 +530,11 @@ struct dwarf_info_t bool has_pick; bool has_crossbow; - dwarf_info_t(df::unit* dw) : dwarf(dw), clear_all(0), has_axe(0), has_pick(0), has_crossbow(0), state(OTHER) {} + int high_skill; + + dwarf_info_t(df::unit* dw) : dwarf(dw), clear_all(0), has_axe(0), has_pick(0), has_crossbow(0), state(OTHER), high_skill(0) + { + } void set_labor(df::unit_labor labor) { @@ -647,7 +652,7 @@ static df::unit_labor hauling_labor_map[] = static df::unit_labor workshop_build_labor[] = { /* Carpenters */ df::unit_labor::CARPENTER, - /* Farmers */ df::unit_labor::HERBALIST, + /* Farmers */ df::unit_labor::PROCESS_PLANT, /* Masons */ df::unit_labor::MASON, /* Craftsdwarfs */ df::unit_labor::STONE_CRAFT, /* Jewelers */ df::unit_labor::CUT_GEM, @@ -687,6 +692,19 @@ static df::building* get_building_from_job(df::job* j) return 0; } +static df::unit_labor construction_build_labor (df::item* i) +{ + MaterialInfo matinfo; + if (matinfo.decode(i)) + { + if (matinfo.material->flags.is_set(df::material_flags::IS_METAL)) + return df::unit_labor::METAL_CRAFT; + if (matinfo.material->flags.is_set(df::material_flags::WOOD)) + return df::unit_labor::CARPENTER; + } + return df::unit_labor::MASON; +} + class JobLaborMapper { private: class jlfunc @@ -729,6 +747,8 @@ private: case df::building_type::Workshop: { df::building_workshopst* ws = (df::building_workshopst*) bld; + if (ws->design && !ws->design->flags.bits.designed) + return df::unit_labor::ARCHITECT; if (ws->type == df::workshop_type::Custom) { df::building_def* def = df::building_def::find(ws->custom_type); @@ -738,6 +758,16 @@ private: return workshop_build_labor[ws->type]; } break; + case df::building_type::Furnace: + case df::building_type::TradeDepot: + case df::building_type::Construction: + { + df::building_actual* b = (df::building_actual*) bld; + if (b->design && !b->design->flags.bits.designed) + return df::unit_labor::ARCHITECT; + return construction_build_labor(j->items[0]->item); + } + break; case df::building_type::FarmPlot: return df::unit_labor::PLANT; } @@ -1386,10 +1416,9 @@ private: int cnt_traction; int cnt_crutch; - std::map labor_needed; std::vector dwarf_info; - std::list idle_dwarfs; + std::list available_dwarfs; private: void scan_buildings() @@ -1486,6 +1515,9 @@ private: if (item->flags.whole & bad_flags.whole) continue; + if (!item->flags.bits.in_inventory && !item->isAssignedToStockpile()) + labor_needed[hauling_labor_map[item->getType()]]++; + if (!item->isWeapon()) continue; @@ -1504,6 +1536,8 @@ private: void collect_job_list() { + labor_needed.clear(); + for (df::job_list_link* jll = world->job_list.next; jll; jll = jll->next) { df::job* j = jll->item; @@ -1524,9 +1558,6 @@ private: bld = ((df::general_ref_building_holderst *)(j->general_refs[r]))->building_id; } - if (worker != -1) - continue; - if (bld != -1) { if (print_debug) @@ -1617,7 +1648,7 @@ private: } } - // Find the activity state for each dwarf-> + // Find the activity state for each dwarf bool is_on_break = false; dwarf_state state = OTHER; @@ -1689,6 +1720,17 @@ private: cnt_crutch++; } + // find dwarf's highest effective skill + + int high_skill = 0; + + FOR_ENUM_ITEMS (job_skill, skill) + { + int skill_level = Units::getEffectiveSkill(dwarf->dwarf, skill); + high_skill = std::max(high_skill, skill_level); + } + + dwarf->high_skill = high_skill; // check if dwarf has an axe, pick, or crossbow for (int j = 0; j < dwarf->dwarf->inventory.size(); j++) @@ -1733,17 +1775,17 @@ private: if (labor == unit_labor::NONE) continue; - dwarf->dwarf->status.labors[labor] = false; + dwarf->clear_labor(labor); } } - if (state == IDLE && !dwarf->clear_all) - idle_dwarfs.push_back(dwarf); + if ((state == IDLE || state == BUSY) && !dwarf->clear_all) + available_dwarfs.push_back(dwarf); } } - } + } public: void process() @@ -1760,14 +1802,14 @@ public: count_map_designations(); - // count number of picks and axes available for use - - count_tools(); - // collect current job list collect_job_list(); + // count number of picks and axes available for use + + count_tools(); + // collect list of dwarfs collect_dwarf_list(); @@ -1800,34 +1842,6 @@ public: } } - // match idle dwarfs to need list - if an idle dwarf is assigned to that labor, then yay, decrement the need count - // and remove the idle dwarf from the idle list - - if (print_debug) - out.print("idle count = %d, labor need count = %d\n", idle_dwarfs.size(), labor_needed.size()); - - for (auto d = idle_dwarfs.begin(); d != idle_dwarfs.end(); d++) - { - FOR_ENUM_ITEMS(unit_labor, l) - { - if (l == df::unit_labor::NONE) - continue; - - if ((*d)->dwarf->status.labors[l]) - if (labor_needed[l] > 0) - { - if (print_debug) - out.print("assign \"%s\" labor %s (carried through)\n", (*d)->dwarf->name.first_name.c_str(), ENUM_KEY_STR(unit_labor, l).c_str()); - labor_needed[l]--; - d = idle_dwarfs.erase(d); // remove from idle list - d--; // and go back one - break; - } else { - (*d)->clear_labor(l); - } - } - } - priority_queue> pq; for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) @@ -1837,9 +1851,9 @@ public: } if (print_debug) - out.print("idle count = %d, labor need count = %d\n", idle_dwarfs.size(), pq.size()); + out.print("idle count = %d, labor need count = %d\n", available_dwarfs.size(), pq.size()); - while (!idle_dwarfs.empty() && !pq.empty()) + while (!available_dwarfs.empty() && !pq.empty()) { df::unit_labor labor = pq.top().second; int priority = pq.top().first; @@ -1848,30 +1862,44 @@ public: if (print_debug) out.print("labor %s skill %s priority %d\n", ENUM_KEY_STR(unit_labor, labor).c_str(), ENUM_KEY_STR(job_skill, skill).c_str(), priority); - std::list::iterator bestdwarf = idle_dwarfs.begin(); + std::list::iterator bestdwarf = available_dwarfs.begin(); - if (skill != df::job_skill::NONE) - { - int best_skill_level = -1; + int best_score = -10000; - for (std::list::iterator k = idle_dwarfs.begin(); k != idle_dwarfs.end(); k++) + for (std::list::iterator k = available_dwarfs.begin(); k != available_dwarfs.end(); k++) + { + dwarf_info_t* d = (*k); + int skill_level = 0; + if (skill != df::job_skill::NONE) { - dwarf_info_t* d = (*k); int skill_level = Units::getEffectiveSkill(d->dwarf, skill); + } - if (skill_level > best_skill_level) - { - bestdwarf = k; - best_skill_level = skill_level; - } + int score = skill_level * 100 - (d->high_skill - skill) * 100; + if (d->dwarf->status.labors[labor]) + score += 300; + if ((labor == df::unit_labor::MINE && d->has_pick) || + (labor == df::unit_labor::CUTWOOD && d->has_axe) || + (labor == df::unit_labor::HUNT && d->has_crossbow)) + score += 300; + if (score > best_score) + { + bestdwarf = k; + best_score = score; } } if (print_debug) - out.print("assign \"%s\" labor %s\n", (*bestdwarf)->dwarf->name.first_name.c_str(), ENUM_KEY_STR(unit_labor, labor).c_str()); - (*bestdwarf)->set_labor(labor); + out.print("assign \"%s\" labor %s score=%d\n", (*bestdwarf)->dwarf->name.first_name.c_str(), ENUM_KEY_STR(unit_labor, labor).c_str(), best_score); + FOR_ENUM_ITEMS(unit_labor, l) + { + if (l == labor) + (*bestdwarf)->set_labor(l); + else + (*bestdwarf)->clear_labor(l); + } - idle_dwarfs.erase(bestdwarf); + available_dwarfs.erase(bestdwarf); pq.pop(); if (--labor_needed[labor] > 0) {