From 72fe37083c6f0767cf61d1eda7b95a9e89ebed91 Mon Sep 17 00:00:00 2001 From: Alistair-Afton Date: Wed, 16 Sep 2026 17:04:31 +0200 Subject: [PATCH] buildingplan: link windows to existing zones Glass and gem windows cannot create rooms themselves, so canMakeRoom rejects them even though they contribute value to rooms and zones. Treat both window types as zoning candidates and cover the bidirectional links with fortress tests. --- docs/changelog.txt | 1 + library/modules/Buildings.cpp | 9 +++++- test/modules/buildings_fortress.lua | 50 +++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 test/modules/buildings_fortress.lua diff --git a/docs/changelog.txt b/docs/changelog.txt index da5a2d4d7c..4b9c2aad3b 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -73,6 +73,7 @@ Template for new versions: - `autodump`: ``destroy`` no longer leaves the contents of destroyed containers in limbo or crashes when destroying unit-held items - `buildingplan`: fix roller material estimate asking for one chain per tile instead of one chain total - `buildingplan`: fix "Unlink all" only unlinking some mechanisms (or crashing) when freeing mechanisms from the building +- `buildingplan`: link planned gem and glass windows to existing rooms and zones - `timestream`: deal properly with units who have breathing difficulties - `stocks`: overlay now resets scroll position when collapsing categories so the item list is no longer left blank and unscrollable - Fixed persistent site data API (``dfhack.persistent.saveSiteData``/``getSiteData``) failing on newly reclaimed fortresses until the first save diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index ddedbbc1b6..52513530cb 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -195,7 +195,14 @@ static void zone_into_building_unidir(df::building* bld, df::building_civzonest* static bool is_suitable_building_for_zoning(df::building* bld) { - return bld->canMakeRoom(); + switch (bld->getType()) + { + case building_type::WindowGlass: + case building_type::WindowGem: + return true; + default: + return bld->canMakeRoom(); + } } static void add_building_to_zone(df::building* bld, df::building_civzonest* zone) diff --git a/test/modules/buildings_fortress.lua b/test/modules/buildings_fortress.lua new file mode 100644 index 0000000000..f932a8098b --- /dev/null +++ b/test/modules/buildings_fortress.lua @@ -0,0 +1,50 @@ +config.target = 'core' +config.mode = 'fortress' + +local function contains(vec, value) + for _,entry in ipairs(vec) do + if entry == value then return true end + end + return false +end + +local function construct_window_in_zone(window_type) + for _,zone in ipairs(df.global.world.buildings.other.ANY_ZONE) do + if zone.room.extents then + for y = zone.y1, zone.y2 do + for x = zone.x1, zone.x2 do + local pos = xyz2pos(x, y, zone.z) + if not dfhack.buildings.findAtTile(pos) then + local bld = dfhack.buildings.constructBuilding{ + pos=pos, + type=window_type, + filters=dfhack.buildings.getFiltersByType( + {}, window_type, -1, -1), + } + if bld then return bld, zone end + end + end + end + end + end +end + +local function expect_window_linked(window_type) + local bld, zone = construct_window_in_zone(window_type) + expect.ne(nil, bld, 'could not find a zone tile suitable for a window') + if not bld then return end + dfhack.with_finalize( + function() dfhack.buildings.deconstruct(bld) end, + function() + expect.true_(contains(bld.relations, zone)) + expect.true_(contains(zone.contained_buildings, bld)) + end) +end + +function test.constructed_gem_window_is_linked_to_zone() + expect_window_linked(df.building_type.WindowGem) +end + +function test.constructed_glass_window_is_linked_to_zone() + expect_window_linked(df.building_type.WindowGlass) +end