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 */,
BUSY /* Clean */,
OTHER /* Rest */,
BUSY /* PickupEquipment */,
OTHER /* PickupEquipment */,
BUSY /* DumpItem */,
OTHER /* StrangeMoodCrafter */,
OTHER /* StrangeMoodJeweller */,
@ -414,7 +414,7 @@ struct labor_default
static std::vector<struct labor_info> 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_WOOD */ {100, 0, TOOL_NONE},
/* HAUL_BODY */ {200, 0, TOOL_NONE},
@ -1607,7 +1607,7 @@ private:
bool labors_changed;
int tool_count[TOOLS_MAX];
bool reequip_needed[TOOLS_MAX];
int tool_in_use[TOOLS_MAX];
int cnt_recover_wounded;
int cnt_diagnosis;
@ -1639,7 +1639,69 @@ private:
bool old = dwarf->dwarf->status.labors[labor];
dwarf->dwarf->status.labors[labor] = value;
if (old != value)
{
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
out.print("Trade depot found but trader is not requested.\n");
}
}
}
}
@ -1729,7 +1792,10 @@ private:
void count_tools()
{
for (int e = TOOL_NONE; e < TOOLS_MAX; e++)
{
tool_count[e] = 0;
tool_in_use[e] = 0;
}
priority_food = 0;
@ -1776,66 +1842,20 @@ 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;
if (!j)
continue;
process_job(j);
}
if (j->flags.bits.suspend || j->flags.bits.item_lost)
for (auto jp = world->job_postings.begin(); jp != world->job_postings.end(); jp++)
{
if ((*jp)->flags.bits.dead)
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)
{
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)
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
bool is_on_break = false;
@ -1972,12 +2018,9 @@ private:
if (labor != df::unit_labor::NONE)
{
labor_infos[labor].busy_dwarfs++;
if (!dwarf->dwarf->status.labors[labor])
if (default_labor_infos[labor].tool != TOOL_NONE)
{
out.print("LABORMANAGER: dwarf %s (id %d) is doing job %s(%d) but is not enabled for labor %s(%d).\n",
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);
tool_in_use[default_labor_infos[labor].tool]++;
}
}
}
@ -2044,37 +2087,7 @@ private:
}
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
@ -2136,7 +2149,10 @@ private:
score += 1000;
if (default_labor_infos[labor].tool != TOOL_NONE &&
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])
score -= 15000;
if (d->armed && labor_outside[labor])
@ -2159,6 +2175,8 @@ public:
cnt_setting = cnt_traction = cnt_crutch = 0;
need_food_water = 0;
labor_needed.clear();
for (int e = 0; e < TOOLS_MAX; e++)
tool_count[e] = 0;
@ -2194,8 +2212,8 @@ public:
// 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::CUTWOOD] += std::min(tool_count[TOOL_AXE], tree_count);
labor_needed[df::unit_labor::MINE] += dig_count;
labor_needed[df::unit_labor::CUTWOOD] += tree_count;
labor_needed[df::unit_labor::DETAIL] += detail_count;
labor_needed[df::unit_labor::HERBALIST] += plant_count;
@ -2269,10 +2287,19 @@ public:
if (l == df::unit_labor::NONE)
continue;
int before = labor_needed[l];
if (labor_infos[l].idle_dwarfs > 0)
labor_needed[l] = 0;
else
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 */
@ -2427,19 +2454,30 @@ public:
if (l == df::unit_labor::NONE)
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);
tools_enum t = default_labor_infos[l].tool;
if (t != TOOL_NONE)
if (t != TOOL_NONE && (*bestdwarf)->has_tool[t])
{
tool_count[t]--;
if (!(*bestdwarf)->has_tool[t])
(*bestdwarf)->dwarf->military.pickup_flags.bits.update = true;
df::job_type j;
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;
labors_changed = true;
}
}
else if ((*bestdwarf)->state == IDLE)
{
set_labor(*bestdwarf, l, false);
}
}
if (best_labor == df::unit_labor::HAUL_FOOD && priority_food > 0)
@ -2450,7 +2488,6 @@ public:
if (best_labor != df::unit_labor::NONE)
{
busy_dwarfs.push_back(*bestdwarf);
labor_infos[best_labor].active_dwarfs++;
to_assign[best_labor]--;
}
@ -2489,6 +2526,8 @@ public:
ENUM_KEY_STR(unit_labor, l).c_str(), 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 &&
canary & (1 << l))
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);
else
set_labor(*d, l, false);
@ -2546,16 +2585,42 @@ public:
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)
{
if (l == df::unit_labor::NONE)
continue;
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]++;
(*d)->dwarf->military.pickup_flags.bits.update = 1;
if (has_tool && tool_count[t] > tool_in_use[t])
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]++;
}
}
}