Merge pull request #3110 from ab9rf/5007-tailor

tailor: fix #3093, #3103
develop
Myk 2023-03-26 23:40:53 -07:00 committed by GitHub
commit b9767740e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 78 additions and 77 deletions

@ -44,7 +44,11 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
- `buildingplan`: you can no longer designate constructions on tiles with magma or deep water
- `buildingplan`: fixed material filter getting lost for planning buildings on save/reload
- `buildingplan`: respect building size limits (e.g. roads and bridges cannot be more than 31 tiles in any dimension)
- `tailor`: now properly discriminates between dyed and undyed cloth, no longer defaults to using adamantine, and properly tracks material requirements for already queued orders
- `tailor`: properly discriminates between dyed and undyed cloth
- `tailor`: no longer defaults to using adamantine
- `tailor`: properly tracks material requirements for already queued orders
- `tailor`: skips units who can't wear clothes
- `tailor`: hopefully won't over-order items any more
## Misc Improvements
- `buildingplan`: filters and global settings are now ignored when manually choosing items for a building

@ -144,13 +144,15 @@ static struct BadFlags {
} badFlags;
class Tailor {
private:
std::map<std::pair<df::item_type, int>, int> available; // key is item type & size
std::map<std::pair<df::item_type, int>, int> needed; // same
std::map<std::pair<df::item_type, int>, int> queued; // same
private:
std::map<int, int> sizes; // this maps body size to races
std::map<std::tuple<df::job_type, int, int>, int> orders; // key is item type, item subtype, size
std::map<std::pair<df::item_type, int>, int> available;
std::map<std::pair<df::item_type, int>, int> needed;
std::map<std::tuple<df::job_type, int, int>, int> orders;
std::map<MatType, int> supply;
std::map<MatType, int> reserves;
@ -169,50 +171,37 @@ public:
{
available.clear();
needed.clear();
queued.clear();
sizes.clear();
orders.clear();
supply.clear();
orders.clear();
}
void scan_clothing()
{
if (!inventory_sanity_checking)
for (auto i : world->items.other[df::items_other_id::ANY_GENERIC37]) // GENERIC37 is "nontattered clothing"
{
for (auto i : world->items.other[df::items_other_id::ANY_GENERIC37]) // GENERIC37 is "clothing"
if (i->flags.whole & badFlags.whole)
{
if (i->flags.whole & badFlags.whole)
continue;
if (i->getWear() >= 1)
continue;
df::item_type t = i->getType();
int size = world->raws.creatures.all[i->getMakerRace()]->adultsize;
available[std::make_pair(t, size)] += 1;
continue;
}
if (i->getWear() >= 1)
continue;
df::item_type t = i->getType();
int size = world->raws.creatures.all[i->getMakerRace()]->adultsize;
available[std::make_pair(t, size)] += 1;
}
else
{
auto& l = world->items.other[df::items_other_id::ANY_GENERIC37];
for (auto i : world->items.other[df::items_other_id::IN_PLAY])
if (DBG_NAME(cycle).isEnabled(DebugCategory::LDEBUG))
{
for (auto& i : available)
{
if (i->flags.whole & badFlags.whole)
continue;
if (!i->isClothing())
continue;
if (std::find(std::begin(l), std::end(l), i) == std::end(l))
{
DEBUG(cycle).print("tailor: clothing item %d missing from GENERIC37 list\n", i->id);
}
if (i->getWear() >= 1)
continue;
df::item_type t = i->getType();
int size = world->raws.creatures.all[i->getMakerRace()]->adultsize;
available[std::make_pair(t, size)] += 1;
df::item_type t;
int size;
std::tie(t, size) = i.first;
DEBUG(cycle).print("tailor: %d %s of size %d found\n",
i.second, ENUM_KEY_STR(item_type, t).c_str(), size);
}
}
}
@ -273,14 +262,13 @@ public:
if (!Units::isOwnCiv(u) ||
!Units::isOwnGroup(u) ||
!Units::isActive(u) ||
Units::isBaby(u))
continue; // skip units we don't control
Units::isBaby(u) ||
!Units::casteFlagSet(u->race, u->caste, df::enums::caste_raw_flags::EQUIPS))
continue; // skip units we don't control or that can't wear clothes
std::set <df::item_type> wearing;
wearing.clear();
std::set <df::item_type> ordered;
std::deque<df::item*> worn;
worn.clear();
for (auto inv : u->inventory)
{
@ -295,33 +283,35 @@ public:
int usize = world->raws.creatures.all[u->race]->adultsize;
sizes[usize] = u->race;
for (auto ty : std::set<df::item_type>{ df::item_type::ARMOR, df::item_type::PANTS, df::item_type::SHOES })
{
if (wearing.count(ty) == 0)
{
TRACE(cycle).print("tailor: one %s of size %d needed to cover %s\n",
ENUM_KEY_STR(item_type, ty).c_str(),
usize,
Translation::TranslateName(&u->name, false).c_str());
needed[std::make_pair(ty, usize)] += 1;
}
}
for (auto w : worn)
{
auto ty = w->getType();
auto oo = itemTypeMap.find(ty);
if (oo == itemTypeMap.end())
{
continue;
}
const df::job_type o = oo->second;
int isize = world->raws.creatures.all[w->getMakerRace()]->adultsize;
std::string description;
w->getItemDescription(&description, 0);
if (available[std::make_pair(ty, usize)] > 0)
if (wearing.count(ty) == 0)
{
if (available[std::make_pair(ty, usize)] > 0)
{
available[std::make_pair(ty, usize)] -= 1;
DEBUG(cycle).print("tailor: allocating a %s (size %d) to %s\n",
ENUM_KEY_STR(item_type, ty).c_str(), usize,
Translation::TranslateName(&u->name, false).c_str());
wearing.insert(ty);
}
else if (ordered.count(ty) == 0)
{
DEBUG(cycle).print ("tailor: %s (size %d) worn by %s (size %d) needs replacement, but none available\n",
description.c_str(), isize,
Translation::TranslateName(&u->name, false).c_str(), usize);
needed[std::make_pair(ty, usize)] += 1;
ordered.insert(ty);
}
}
if (wearing.count(ty) > 0)
{
if (w->flags.bits.owned)
{
@ -335,23 +325,21 @@ public:
);
}
if (wearing.count(ty) == 0)
{
DEBUG(cycle).print("tailor: allocating a %s (size %d) to %s\n",
ENUM_KEY_STR(item_type, ty).c_str(), usize,
Translation::TranslateName(&u->name, false).c_str());
available[std::make_pair(ty, usize)] -= 1;
}
if (w->getWear() > 1)
w->flags.bits.dump = true;
}
else
}
for (auto ty : std::set<df::item_type>{ df::item_type::ARMOR, df::item_type::PANTS, df::item_type::SHOES })
{
if (wearing.count(ty) == 0 && ordered.count(ty) == 0)
{
DEBUG(cycle).print ("tailor: %s (size %d) worn by %s (size %d) needs replacement, but none available\n",
description.c_str(), isize,
Translation::TranslateName(&u->name, false).c_str(), usize);
orders[std::make_tuple(o, w->getSubtype(), usize)] += 1;
TRACE(cycle).print("tailor: one %s of size %d needed to cover %s\n",
ENUM_KEY_STR(item_type, ty).c_str(),
usize,
Translation::TranslateName(&u->name, false).c_str());
needed[std::make_pair(ty, usize)] += 1;
}
}
}
@ -367,6 +355,9 @@ public:
int size = a.first.second;
int count = a.second;
if (count <= 0)
continue;
int sub = 0;
std::vector<int16_t> v;
@ -414,7 +405,6 @@ public:
if (f == jobTypeMap.end())
continue;
auto sub = o->item_subtype;
int race = o->hist_figure_id;
for (auto& m : all_materials)
@ -432,7 +422,14 @@ public:
int size = world->raws.creatures.all[race]->adultsize;
orders[std::make_tuple(o->job_type, sub, size)] -= o->amount_left;
auto tt = jobTypeMap.find(o->job_type);
if (tt == jobTypeMap.end())
{
continue;
}
needed[std::make_pair(tt->second, size)] -= o->amount_left;
TRACE(cycle).print("tailor: existing order for %d %s of size %d detected\n",
o->amount_left,
ENUM_KEY_STR(job_type, o->job_type).c_str(),
@ -576,8 +573,8 @@ public:
scan_clothing();
scan_materials();
scan_replacements();
create_orders();
scan_existing_orders();
create_orders();
return place_orders();
}