labormanager: significant restructuring to use job posting list

Updated here to get potential jobs off the job posting lists, which is
apparently where certain map-designated live after being designated but
before they move to the actual job list. Also changes to how tools are
handled, and lever pulling is assigned by default to all idle dwarfs.
develop
Kelly Kinkade 2016-06-30 23:58:56 -05:00
parent 857058752b
commit d8f4d79b97
1 changed files with 169 additions and 104 deletions

@ -184,7 +184,7 @@ static const dwarf_state dwarf_states[] = {
OTHER /* GoShopping2 */, OTHER /* GoShopping2 */,
BUSY /* Clean */, BUSY /* Clean */,
OTHER /* Rest */, OTHER /* Rest */,
BUSY /* PickupEquipment */, OTHER /* PickupEquipment */,
BUSY /* DumpItem */, BUSY /* DumpItem */,
OTHER /* StrangeMoodCrafter */, OTHER /* StrangeMoodCrafter */,
OTHER /* StrangeMoodJeweller */, OTHER /* StrangeMoodJeweller */,
@ -414,7 +414,7 @@ struct labor_default
static std::vector<struct labor_info> labor_infos; static std::vector<struct labor_info> labor_infos;
static const struct labor_default default_labor_infos[] = { static const struct labor_default default_labor_infos[] = {
/* MINE */ {200, 0, TOOL_PICK}, /* MINEa */ {200, 0, TOOL_PICK},
/* HAUL_STONE */ {100, 0, TOOL_NONE}, /* HAUL_STONE */ {100, 0, TOOL_NONE},
/* HAUL_WOOD */ {100, 0, TOOL_NONE}, /* HAUL_WOOD */ {100, 0, TOOL_NONE},
/* HAUL_BODY */ {200, 0, TOOL_NONE}, /* HAUL_BODY */ {200, 0, TOOL_NONE},
@ -1607,7 +1607,7 @@ private:
bool labors_changed; bool labors_changed;
int tool_count[TOOLS_MAX]; int tool_count[TOOLS_MAX];
bool reequip_needed[TOOLS_MAX]; int tool_in_use[TOOLS_MAX];
int cnt_recover_wounded; int cnt_recover_wounded;
int cnt_diagnosis; int cnt_diagnosis;
@ -1639,7 +1639,69 @@ private:
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)
{
labors_changed = true; labors_changed = true;
tools_enum tool = default_labor_infos[labor].tool;
if (tool != TOOL_NONE)
tool_in_use[tool] += value ? 1 : -1;
}
}
}
void process_job (df::job* j)
{
if (j->flags.bits.suspend || j->flags.bits.item_lost)
return;
int worker = -1;
int bld = -1;
for (int r = 0; r < j->general_refs.size(); ++r)
{
if (j->general_refs[r]->getType() == df::general_ref_type::UNIT_WORKER)
worker = ((df::general_ref_unit_workerst *)(j->general_refs[r]))->unit_id;
if (j->general_refs[r]->getType() == df::general_ref_type::BUILDING_HOLDER)
bld = ((df::general_ref_building_holderst *)(j->general_refs[r]))->building_id;
}
if (bld != -1)
{
df::building* b = binsearch_in_vector(world->buildings.all, bld);
int fjid = -1;
for (int jn = 0; jn < b->jobs.size(); jn++)
{
if (b->jobs[jn]->flags.bits.suspend)
continue;
fjid = b->jobs[jn]->id;
break;
}
// check if this job is the first nonsuspended job on this building; if not, ignore it
// (except for farms and trade depots)
if (fjid != j->id &&
b->getType() != df::building_type::FarmPlot &&
b->getType() != df::building_type::TradeDepot)
return;
}
df::unit_labor labor = labor_mapper->find_job_labor (j);
if (labor != df::unit_labor::NONE)
{
labor_needed[labor]++;
if (worker == -1)
{
if (j->pos.isValid())
{
df::tile_designation* d = Maps::getTileDesignation(j->pos);
if (d->bits.outside)
labor_outside[labor] = true;
}
} else {
labor_infos[labor].mark_assigned();
labor_in_use[labor]++;
}
} }
} }
@ -1674,6 +1736,7 @@ private:
else else
out.print("Trade depot found but trader is not requested.\n"); out.print("Trade depot found but trader is not requested.\n");
} }
} }
} }
} }
@ -1729,7 +1792,10 @@ private:
void count_tools() void count_tools()
{ {
for (int e = TOOL_NONE; e < TOOLS_MAX; e++) for (int e = TOOL_NONE; e < TOOLS_MAX; e++)
{
tool_count[e] = 0; tool_count[e] = 0;
tool_in_use[e] = 0;
}
priority_food = 0; priority_food = 0;
@ -1776,66 +1842,20 @@ private:
void collect_job_list() void collect_job_list()
{ {
labor_needed.clear();
for (df::job_list_link* jll = world->job_list.next; jll; jll = jll->next) for (df::job_list_link* jll = world->job_list.next; jll; jll = jll->next)
{ {
df::job* j = jll->item; df::job* j = jll->item;
if (!j) if (!j)
continue; continue;
process_job(j);
if (j->flags.bits.suspend || j->flags.bits.item_lost)
continue;
int worker = -1;
int bld = -1;
for (int r = 0; r < j->general_refs.size(); ++r)
{
if (j->general_refs[r]->getType() == df::general_ref_type::UNIT_WORKER)
worker = ((df::general_ref_unit_workerst *)(j->general_refs[r]))->unit_id;
if (j->general_refs[r]->getType() == df::general_ref_type::BUILDING_HOLDER)
bld = ((df::general_ref_building_holderst *)(j->general_refs[r]))->building_id;
} }
if (bld != -1) for (auto jp = world->job_postings.begin(); jp != world->job_postings.end(); jp++)
{
df::building* b = binsearch_in_vector(world->buildings.all, bld);
int fjid = -1;
for (int jn = 0; jn < b->jobs.size(); jn++)
{ {
if (b->jobs[jn]->flags.bits.suspend) if ((*jp)->flags.bits.dead)
continue; continue;
fjid = b->jobs[jn]->id;
break;
}
// check if this job is the first nonsuspended job on this building; if not, ignore it
// (except for farms)
if (fjid != j->id && b->getType() != df::building_type::FarmPlot) {
continue;
}
}
df::unit_labor labor = labor_mapper->find_job_labor (j);
if (labor != df::unit_labor::NONE)
{
labor_needed[labor]++;
if (worker == -1)
{
if (j->pos.isValid())
{
df::tile_designation* d = Maps::getTileDesignation(j->pos);
if (d->bits.outside)
labor_outside[labor] = true;
}
} else {
labor_infos[labor].mark_assigned();
labor_in_use[labor]++;
}
} process_job((*jp)->job);
} }
} }
@ -1909,6 +1929,32 @@ private:
} }
} }
// check if dwarf has an axe, pick, or crossbow
for (int j = 0; j < dwarf->dwarf->inventory.size(); j++)
{
df::unit_inventory_item* ui = dwarf->dwarf->inventory[j];
if (ui->mode == df::unit_inventory_item::Weapon && ui->item->isWeapon())
{
dwarf->armed = true;
df::itemdef_weaponst* weapondef = ((df::item_weaponst*)(ui->item))->subtype;
df::job_skill weaponsk = (df::job_skill) weapondef->skill_melee;
df::job_skill rangesk = (df::job_skill) weapondef->skill_ranged;
if (weaponsk == df::job_skill::AXE)
{
dwarf->has_tool[TOOL_AXE] = true;
}
else if (weaponsk == df::job_skill::MINING)
{
dwarf->has_tool[TOOL_PICK] = true;
}
else if (rangesk == df::job_skill::CROSSBOW)
{
dwarf->has_tool[TOOL_CROSSBOW] = true;
}
}
}
// Find the activity state for each dwarf // Find the activity state for each dwarf
bool is_on_break = false; bool is_on_break = false;
@ -1972,12 +2018,9 @@ private:
if (labor != df::unit_labor::NONE) if (labor != df::unit_labor::NONE)
{ {
labor_infos[labor].busy_dwarfs++; labor_infos[labor].busy_dwarfs++;
if (default_labor_infos[labor].tool != TOOL_NONE)
if (!dwarf->dwarf->status.labors[labor])
{ {
out.print("LABORMANAGER: dwarf %s (id %d) is doing job %s(%d) but is not enabled for labor %s(%d).\n", tool_in_use[default_labor_infos[labor].tool]++;
dwarf->dwarf->name.first_name.c_str(), dwarf->dwarf->id,
ENUM_KEY_STR(job_type, job).c_str(), job, ENUM_KEY_STR(unit_labor, labor).c_str(), labor);
} }
} }
} }
@ -2044,37 +2087,7 @@ private:
} }
dwarf->high_skill = high_skill; dwarf->high_skill = high_skill;
// check if dwarf has an axe, pick, or crossbow
for (int j = 0; j < dwarf->dwarf->inventory.size(); j++)
{
df::unit_inventory_item* ui = dwarf->dwarf->inventory[j];
if (ui->mode == df::unit_inventory_item::Weapon && ui->item->isWeapon())
{
dwarf->armed = true;
df::itemdef_weaponst* weapondef = ((df::item_weaponst*)(ui->item))->subtype;
df::job_skill weaponsk = (df::job_skill) weapondef->skill_melee;
df::job_skill rangesk = (df::job_skill) weapondef->skill_ranged;
if (weaponsk == df::job_skill::AXE)
{
dwarf->has_tool[TOOL_AXE] = true;
if (state != IDLE)
tool_count[TOOL_AXE]--;
}
else if (weaponsk == df::job_skill::MINING)
{
dwarf->has_tool[TOOL_PICK] = 1;
if (state != IDLE)
tool_count[TOOL_PICK]--;
}
else if (rangesk == df::job_skill::CROSSBOW)
{
dwarf->has_tool[TOOL_CROSSBOW] = 1;
if (state != IDLE)
tool_count[TOOL_CROSSBOW]--;
}
}
}
// clear labors of dwarfs with clear_all set // clear labors of dwarfs with clear_all set
@ -2136,7 +2149,10 @@ private:
score += 1000; score += 1000;
if (default_labor_infos[labor].tool != TOOL_NONE && if (default_labor_infos[labor].tool != TOOL_NONE &&
d->has_tool[default_labor_infos[labor].tool]) d->has_tool[default_labor_infos[labor].tool])
score += 5000; score += 30000;
if (default_labor_infos[labor].tool != TOOL_NONE &&
!d->has_tool[default_labor_infos[labor].tool])
score -= 30000;
if (d->has_children && labor_outside[labor]) if (d->has_children && labor_outside[labor])
score -= 15000; score -= 15000;
if (d->armed && labor_outside[labor]) if (d->armed && labor_outside[labor])
@ -2159,6 +2175,8 @@ public:
cnt_setting = cnt_traction = cnt_crutch = 0; cnt_setting = cnt_traction = cnt_crutch = 0;
need_food_water = 0; need_food_water = 0;
labor_needed.clear();
for (int e = 0; e < TOOLS_MAX; e++) for (int e = 0; e < TOOLS_MAX; e++)
tool_count[e] = 0; tool_count[e] = 0;
@ -2194,8 +2212,8 @@ public:
// add job entries for designation-related jobs // add job entries for designation-related jobs
labor_needed[df::unit_labor::MINE] += std::min(tool_count[TOOL_PICK], dig_count); labor_needed[df::unit_labor::MINE] += dig_count;
labor_needed[df::unit_labor::CUTWOOD] += std::min(tool_count[TOOL_AXE], tree_count); labor_needed[df::unit_labor::CUTWOOD] += tree_count;
labor_needed[df::unit_labor::DETAIL] += detail_count; labor_needed[df::unit_labor::DETAIL] += detail_count;
labor_needed[df::unit_labor::HERBALIST] += plant_count; labor_needed[df::unit_labor::HERBALIST] += plant_count;
@ -2269,10 +2287,19 @@ public:
if (l == df::unit_labor::NONE) if (l == df::unit_labor::NONE)
continue; continue;
int before = labor_needed[l];
if (labor_infos[l].idle_dwarfs > 0) if (labor_infos[l].idle_dwarfs > 0)
labor_needed[l] = 0; labor_needed[l] = 0;
else else
labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]); labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]);
if (default_labor_infos[l].tool != TOOL_NONE)
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]);
} }
/* assign food haulers for rotting food items */ /* assign food haulers for rotting food items */
@ -2427,20 +2454,31 @@ public:
if (l == df::unit_labor::NONE) if (l == df::unit_labor::NONE)
continue; continue;
if (l == best_labor) tools_enum t = default_labor_infos[l].tool;
if (l == best_labor && ( t == TOOL_NONE || tool_in_use[t] < tool_count[t]) )
{ {
set_labor(*bestdwarf, l, true); set_labor(*bestdwarf, l, true);
tools_enum t = default_labor_infos[l].tool; if (t != TOOL_NONE && (*bestdwarf)->has_tool[t])
if (t != TOOL_NONE)
{ {
tool_count[t]--; df::job_type j;
if (!(*bestdwarf)->has_tool[t]) j = df::job_type::NONE;
if ((*bestdwarf)->dwarf->job.current_job)
j = (*bestdwarf)->dwarf->job.current_job->job_type;
if (print_debug)
out.print("LABORMANAGER: asking %s to pick up tools, current job %s\n", (*bestdwarf)->dwarf->name.first_name.c_str(), ENUM_KEY_STR(job_type, j).c_str());
(*bestdwarf)->dwarf->military.pickup_flags.bits.update = true; (*bestdwarf)->dwarf->military.pickup_flags.bits.update = true;
labors_changed = true;
} }
} }
else if ((*bestdwarf)->state == IDLE) else if ((*bestdwarf)->state == IDLE)
{
set_labor(*bestdwarf, l, false); set_labor(*bestdwarf, l, false);
} }
}
if (best_labor == df::unit_labor::HAUL_FOOD && priority_food > 0) if (best_labor == df::unit_labor::HAUL_FOOD && priority_food > 0)
priority_food--; priority_food--;
@ -2450,7 +2488,6 @@ public:
if (best_labor != df::unit_labor::NONE) if (best_labor != df::unit_labor::NONE)
{ {
busy_dwarfs.push_back(*bestdwarf);
labor_infos[best_labor].active_dwarfs++; labor_infos[best_labor].active_dwarfs++;
to_assign[best_labor]--; to_assign[best_labor]--;
} }
@ -2489,6 +2526,8 @@ public:
ENUM_KEY_STR(unit_labor, l).c_str(), score, ENUM_KEY_STR(unit_labor, l).c_str(), score,
ENUM_KEY_STR(unit_labor, (*d)->using_labor).c_str(), current_score); ENUM_KEY_STR(unit_labor, (*d)->using_labor).c_str(), current_score);
} }
if ((*d)->using_labor != df::unit_labor::NONE && score > current_score + 5000)
set_labor(*d, (*d)->using_labor, false);
} }
} }
} }
@ -2535,7 +2574,7 @@ public:
if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS &&
canary & (1 << l)) canary & (1 << l))
set_labor(*d, l, true); set_labor(*d, l, true);
else if (l == df::unit_labor::CLEAN || l == df::unit_labor::REMOVE_CONSTRUCTION) else if (l == df::unit_labor::CLEAN || l == df::unit_labor::REMOVE_CONSTRUCTION || l == df::unit_labor::PULL_LEVER)
set_labor(*d, l, true); set_labor(*d, l, true);
else else
set_labor(*d, l, false); set_labor(*d, l, false);
@ -2546,16 +2585,42 @@ public:
for (auto d = dwarf_info.begin(); d != dwarf_info.end(); d++) for (auto d = dwarf_info.begin(); d != dwarf_info.end(); d++)
{ {
if ((*d)->dwarf->job.current_job && (*d)->dwarf->job.current_job->job_type == df::job_type::PickupEquipment)
continue;
if ((*d)->dwarf->military.pickup_flags.bits.update)
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)
continue; continue;
tools_enum t = default_labor_infos[l].tool; tools_enum t = default_labor_infos[l].tool;
if (t != TOOL_NONE && tool_count[t] < 0 && (*d)->has_tool[t] && !(*d)->dwarf->status.labors[l]) if (t == TOOL_NONE)
continue;
bool has_tool = (*d)->has_tool[t];
bool needs_tool = (*d)->dwarf->status.labors[l];
if (has_tool != needs_tool)
{ {
tool_count[t]++; if (has_tool && tool_count[t] > tool_in_use[t])
(*d)->dwarf->military.pickup_flags.bits.update = 1; continue;
df::job_type j = df::job_type::NONE;
if ((*d)->dwarf->job.current_job)
j = (*d)->dwarf->job.current_job->job_type;
if (print_debug)
out.print("LABORMANAGER: asking %s to %s tools, current job %s, %d %d \n", (*d)->dwarf->name.first_name.c_str(), (has_tool) ? "drop" : "pick up", ENUM_KEY_STR(job_type, j).c_str(), has_tool, needs_tool);
(*d)->dwarf->military.pickup_flags.bits.update = true;
labors_changed = true;
if (needs_tool)
tool_in_use[t]++;
} }
} }
} }