From 1b8fc20ad53fded507407fe0f0a52486d626b6f5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 26 Apr 2023 21:01:21 -0700 Subject: [PATCH] check items for accessibility for dialogs before we only checked when doing the cycle, so if an inaccessible item were manually selected, we'd never be able to build --- docs/changelog.txt | 1 + plugins/buildingplan/buildingplan.cpp | 2 +- plugins/buildingplan/buildingplan.h | 2 +- plugins/buildingplan/buildingplan_cycle.cpp | 42 ++++++++++----------- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 91f25a323..66904aa6d 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -38,6 +38,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Fixes - `autoclothing`: eliminate game lag when there are many inventory items in the fort - `buildingplan`: fixed size limit calculations for rollers +- `buildingplan`: fixed items not being checked for accessibility in the filter and item selection dialogs - `dig-now`: properly detect and complete smoothing designations that have been converted into active jobs ## Misc Improvements diff --git a/plugins/buildingplan/buildingplan.cpp b/plugins/buildingplan/buildingplan.cpp index 05b2c0af6..ce424f9c6 100644 --- a/plugins/buildingplan/buildingplan.cpp +++ b/plugins/buildingplan/buildingplan.cpp @@ -704,7 +704,7 @@ static int scanAvailableItems(color_ostream &out, df::building_type type, int16_ filter.setMaterials(set()); special.clear(); } - if (itemPassesScreen(item) && matchesFilters(item, jitem, heat, filter, special)) { + if (itemPassesScreen(out, item) && matchesFilters(item, jitem, heat, filter, special)) { if (item_ids) item_ids->emplace_back(item->id); if (counts) { diff --git a/plugins/buildingplan/buildingplan.h b/plugins/buildingplan/buildingplan.h index 5c4f25aa4..9bfd38731 100644 --- a/plugins/buildingplan/buildingplan.h +++ b/plugins/buildingplan/buildingplan.h @@ -54,7 +54,7 @@ void set_config_val(DFHack::PersistentDataItem &c, int index, int value); void set_config_bool(DFHack::PersistentDataItem &c, int index, bool value); std::vector getVectorIds(DFHack::color_ostream &out, const df::job_item *job_item, bool ignore_filters); -bool itemPassesScreen(df::item * item); +bool itemPassesScreen(DFHack::color_ostream& out, df::item* item); df::job_item getJobItemWithHeatSafety(const df::job_item *job_item, HeatSafety heat); bool matchesFilters(df::item * item, const df::job_item * job_item, HeatSafety heat, const ItemFilter &item_filter, const std::set &special); bool isJobReady(DFHack::color_ostream &out, const std::vector &jitems); diff --git a/plugins/buildingplan/buildingplan_cycle.cpp b/plugins/buildingplan/buildingplan_cycle.cpp index 3213e741d..45cafe474 100644 --- a/plugins/buildingplan/buildingplan_cycle.cpp +++ b/plugins/buildingplan/buildingplan_cycle.cpp @@ -43,10 +43,27 @@ struct BadFlags { } }; -bool itemPassesScreen(df::item * item) { +// This is tricky. we want to choose an item that can be brought to the job site, but that's not +// necessarily the same as job->pos. it could be many tiles off in any direction (e.g. for bridges), or +// up or down (e.g. for stairs). For now, just return if the item is on a walkable tile. +static bool isAccessible(color_ostream& out, df::item* item) { + df::coord item_pos = Items::getPosition(item); + df::map_block* block = Maps::getTileBlock(item_pos); + bool is_walkable = false; + if (block) { + uint16_t walkability_group = index_tile(block->walkable, item_pos); + is_walkable = walkability_group != 0; + TRACE(cycle, out).print("item %d in walkability_group %u at (%d,%d,%d) is %saccessible from job site\n", + item->id, walkability_group, item_pos.x, item_pos.y, item_pos.z, is_walkable ? "(probably) " : "not "); + } + return is_walkable; +} + +bool itemPassesScreen(color_ostream& out, df::item* item) { static const BadFlags bad_flags; return !(item->flags.whole & bad_flags.whole) - && !item->isAssignedToStockpile(); + && !item->isAssignedToStockpile() + && isAccessible(out, item); } df::job_item getJobItemWithHeatSafety(const df::job_item *job_item, HeatSafety heat) { @@ -165,22 +182,6 @@ static df::building * popInvalidTasks(color_ostream &out, Bucket &task_queue, return NULL; } -// This is tricky. we want to choose an item that can be brought to the job site, but that's not -// necessarily the same as job->pos. it could be many tiles off in any direction (e.g. for bridges), or -// up or down (e.g. for stairs). For now, just return if the item is on a walkable tile. -static bool isAccessibleFrom(color_ostream &out, df::item *item, df::job *job) { - df::coord item_pos = Items::getPosition(item); - df::map_block *block = Maps::getTileBlock(item_pos); - bool is_walkable = false; - if (block) { - uint16_t walkability_group = index_tile(block->walkable, item_pos); - is_walkable = walkability_group != 0; - TRACE(cycle,out).print("item %d in walkability_group %u at (%d,%d,%d) is %saccessible from job site\n", - item->id, walkability_group, item_pos.x, item_pos.y, item_pos.z, is_walkable ? "" : "not "); - } - return is_walkable; -} - static void doVector(color_ostream &out, df::job_item_vector_id vector_id, map &buckets, unordered_map &planned_buildings, @@ -195,7 +196,7 @@ static void doVector(color_ostream &out, df::job_item_vector_id vector_id, item_it != item_vector.rend(); ++item_it) { auto item = *item_it; - if (!itemPassesScreen(item)) + if (!itemPassesScreen(out, item)) continue; for (auto bucket_it = buckets.begin(); bucket_it != buckets.end(); ) { TRACE(cycle,out).print("scanning bucket: %s/%s\n", @@ -218,8 +219,7 @@ static void doVector(color_ostream &out, df::job_item_vector_id vector_id, auto filter_idx = task.second; const int rev_filter_idx = num_filters - (filter_idx+1); auto &pb = planned_buildings.at(id); - if (isAccessibleFrom(out, item, job) - && matchesFilters(item, jitems[filter_idx], pb.heat_safety, + if (matchesFilters(item, jitems[filter_idx], pb.heat_safety, pb.item_filters[rev_filter_idx], pb.specials) && Job::attachJobItem(job, item, df::job_item_ref::Hauled, filter_idx))