From 50fe6727cb7e23ff31130199515793ff6cba6156 Mon Sep 17 00:00:00 2001 From: dhthwy <302825+dhthwy@users.noreply.github.com> Date: Fri, 29 Nov 2024 09:12:26 -0500 Subject: [PATCH 1/8] #5031: Handle top ramps when pathfinding to depot --- plugins/pathable.cpp | 81 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 579ffb17f1..0228065eff 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -240,6 +240,31 @@ static bool is_wagon_traversible(FloodCtx & ctx, const df::coord & pos, const df return false; } +static bool is_wagon_traversible_by_ramp(FloodCtx & ctx, const df::coord & pos) { + if ((is_wagon_traversible(ctx, pos+df::coord(-1, -1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 0, -1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 1, -1, 0), pos)) || // Top + + (is_wagon_traversible(ctx, pos+df::coord(-1, 0, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 0, 0, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 1, 0, 0), pos)) || // Middle + + (is_wagon_traversible(ctx, pos+df::coord(-1, 1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 0, 1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 1, 1, 0), pos)) || // Bottom + + (is_wagon_traversible(ctx, pos+df::coord(-1, -1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord(-1, 0, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord(-1, 1, 0), pos)) || // Left + + (is_wagon_traversible(ctx, pos+df::coord( 1, -1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 1, 0, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 1, 1, 0), pos))) { // Right + return true; + } + return false; +} + static void check_wagon_tile(FloodCtx & ctx, const df::coord & pos) { if (ctx.seen.contains(pos)) return; @@ -252,15 +277,53 @@ static void check_wagon_tile(FloodCtx & ctx, const df::coord & pos) { return; } - if (is_wagon_traversible(ctx, pos+df::coord(-1, -1, 0), pos) && - is_wagon_traversible(ctx, pos+df::coord( 0, -1, 0), pos) && - is_wagon_traversible(ctx, pos+df::coord( 1, -1, 0), pos) && - is_wagon_traversible(ctx, pos+df::coord(-1, 0, 0), pos) && - is_wagon_traversible(ctx, pos+df::coord( 1, 0, 0), pos) && - is_wagon_traversible(ctx, pos+df::coord(-1, 1, 0), pos) && - is_wagon_traversible(ctx, pos+df::coord( 0, 1, 0), pos) && - is_wagon_traversible(ctx, pos+df::coord( 1, 1, 0), pos)) - { + auto tt = Maps::getTileType(pos); + if (!tt) + return; + + auto shape = tileShape(*tt); + +#if 0 + if (shape == df::tiletype_shape::RAMP_TOP) { + std::cerr << "check_wagon_tile start" << std::endl; + bool r = is_wagon_traversible(ctx, pos+df::coord(-1, -1, 0), pos); + std::cerr << r << ", " + coord_to_str(pos+df::coord(-1, -1, 0)) + ", pos=" + coord_to_str(pos) << std::endl; + + r = is_wagon_traversible(ctx, pos+df::coord( 0, -1, 0), pos); + std::cerr << r << ", " + coord_to_str(pos+df::coord(0, -1, 0)) + ", pos=" + coord_to_str(pos) << std::endl; + + r = is_wagon_traversible(ctx, pos+df::coord( 1, -1, 0), pos); + std::cerr << r << ", " + coord_to_str(pos+df::coord(1, -1, 0)) + ", pos=" + coord_to_str(pos) << std::endl; + + r = is_wagon_traversible(ctx, pos+df::coord(-1, 0, 0), pos); + std::cerr << r << ", " + coord_to_str(pos+df::coord(-1, 0, 0)) + ", pos=" + coord_to_str(pos) << std::endl; + + r = is_wagon_traversible(ctx, pos+df::coord( 1, 0, 0), pos); + std::cerr << r << ", " + coord_to_str(pos+df::coord(1, 0, 0)) + ", pos=" + coord_to_str(pos) << std::endl; + + r = is_wagon_traversible(ctx, pos+df::coord( -1, 1, 0), pos); + std::cerr << r << ", " + coord_to_str(pos+df::coord(-1, 1, 0)) + ", pos=" + coord_to_str(pos) << std::endl; + + r = is_wagon_traversible(ctx, pos+df::coord( 0, 1, 0), pos); + std::cerr << r << ", " + coord_to_str(pos+df::coord(0, 1, 0)) + ", pos=" + coord_to_str(pos) << std::endl; + + r = is_wagon_traversible(ctx, pos+df::coord( 1, 1, 0), pos); + std::cerr << r << ", " + coord_to_str(pos+df::coord(1, 1, 0)) + ", pos=" + coord_to_str(pos) << std::endl; + std::cerr << "check_wagon_tile end" << std::endl; + } +#endif + + + if ((shape != df::tiletype_shape::RAMP_TOP && + (is_wagon_traversible(ctx, pos+df::coord(-1, -1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 0, -1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 1, -1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord(-1, 0, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 1, 0, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord(-1, 1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 0, 1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 1, 1, 0), pos))) || + (shape == df::tiletype_shape::RAMP_TOP && is_wagon_traversible_by_ramp(ctx, pos))) { ctx.wagon_path.emplace(pos); ctx.search_edge.emplace(pos); } From 7e6ec6fe852dfffdd5510a5d3bd9e54a48991b5f Mon Sep 17 00:00:00 2001 From: dhthwy <302825+dhthwy@users.noreply.github.com> Date: Fri, 29 Nov 2024 12:52:41 -0500 Subject: [PATCH 2/8] #5031: Assign RAMP_TOP a walkability group from an adjacent tile --- library/modules/Maps.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- plugins/pathable.cpp | 2 +- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index c207360ac4..ae309c29c1 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -757,9 +757,45 @@ bool Maps::ReadGeology(vector > *layer_mats, vector return true; } -uint16_t Maps::getWalkableGroup(df::coord pos) { +uint16_t getNeighborWalkableGroup(df::map_block * block, df::coord pos) { + auto neighborGroup = [block, pos](int dx, int dy) { + return index_tile(block->walkable, pos + df::coord(dx, dy, 0)); + }; + + constexpr std::array, 8> directions = {{ + {-1, -1}, {0, -1}, {1, -1}, + {-1, 0}, {1, 0}, + {-1, 1}, {0, 1}, {1, 1} + }}; + + for (const auto& [dx, dy] : directions) { + uint16_t g = neighborGroup(dx, dy); + if (g) return g; + } + return 0; +} + +uint16_t Maps::getWalkableGroup(df::coord pos) +{ auto block = getTileBlock(pos); - return block ? index_tile(block->walkable, pos) : 0; + if (!block) return 0; + + /* + * RAMP_TOP tiles do not have a walkability group assigned to them directly. + * To determine walkability, we assign the group of an adjacent tile, + * with the constraint that the assigned group matches the walkability group + * of the same tile one z-level below. + */ + auto tt = getTileType(pos); + if (tt && tileShape(*tt) == df::tiletype_shape::RAMP_TOP) { + auto below_group = getWalkableGroup(pos + df::coord(0, 0, -1)); + if (below_group != 0) { + auto neigh_group = getNeighborWalkableGroup(block, pos); + return below_group == neigh_group ? neigh_group : 0; + } + } + + return index_tile(block->walkable, pos); } bool Maps::canWalkBetween(df::coord pos1, df::coord pos2) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 0228065eff..e3882c381d 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -298,7 +298,7 @@ static void check_wagon_tile(FloodCtx & ctx, const df::coord & pos) { r = is_wagon_traversible(ctx, pos+df::coord(-1, 0, 0), pos); std::cerr << r << ", " + coord_to_str(pos+df::coord(-1, 0, 0)) + ", pos=" + coord_to_str(pos) << std::endl; - r = is_wagon_traversible(ctx, pos+df::coord( 1, 0, 0), pos); + r = is_wagon_traversible(ctx, pos+df::coord( 1, 0, 0), pos); std::cerr << r << ", " + coord_to_str(pos+df::coord(1, 0, 0)) + ", pos=" + coord_to_str(pos) << std::endl; r = is_wagon_traversible(ctx, pos+df::coord( -1, 1, 0), pos); From ec83a702ffe8c545882b18c8cecc5efdeac8bc87 Mon Sep 17 00:00:00 2001 From: dhthwy <302825+dhthwy@users.noreply.github.com> Date: Fri, 29 Nov 2024 12:55:22 -0500 Subject: [PATCH 3/8] #5031: Remove debug prints --- plugins/pathable.cpp | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index e3882c381d..8535ce2ab9 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -282,38 +282,6 @@ static void check_wagon_tile(FloodCtx & ctx, const df::coord & pos) { return; auto shape = tileShape(*tt); - -#if 0 - if (shape == df::tiletype_shape::RAMP_TOP) { - std::cerr << "check_wagon_tile start" << std::endl; - bool r = is_wagon_traversible(ctx, pos+df::coord(-1, -1, 0), pos); - std::cerr << r << ", " + coord_to_str(pos+df::coord(-1, -1, 0)) + ", pos=" + coord_to_str(pos) << std::endl; - - r = is_wagon_traversible(ctx, pos+df::coord( 0, -1, 0), pos); - std::cerr << r << ", " + coord_to_str(pos+df::coord(0, -1, 0)) + ", pos=" + coord_to_str(pos) << std::endl; - - r = is_wagon_traversible(ctx, pos+df::coord( 1, -1, 0), pos); - std::cerr << r << ", " + coord_to_str(pos+df::coord(1, -1, 0)) + ", pos=" + coord_to_str(pos) << std::endl; - - r = is_wagon_traversible(ctx, pos+df::coord(-1, 0, 0), pos); - std::cerr << r << ", " + coord_to_str(pos+df::coord(-1, 0, 0)) + ", pos=" + coord_to_str(pos) << std::endl; - - r = is_wagon_traversible(ctx, pos+df::coord( 1, 0, 0), pos); - std::cerr << r << ", " + coord_to_str(pos+df::coord(1, 0, 0)) + ", pos=" + coord_to_str(pos) << std::endl; - - r = is_wagon_traversible(ctx, pos+df::coord( -1, 1, 0), pos); - std::cerr << r << ", " + coord_to_str(pos+df::coord(-1, 1, 0)) + ", pos=" + coord_to_str(pos) << std::endl; - - r = is_wagon_traversible(ctx, pos+df::coord( 0, 1, 0), pos); - std::cerr << r << ", " + coord_to_str(pos+df::coord(0, 1, 0)) + ", pos=" + coord_to_str(pos) << std::endl; - - r = is_wagon_traversible(ctx, pos+df::coord( 1, 1, 0), pos); - std::cerr << r << ", " + coord_to_str(pos+df::coord(1, 1, 0)) + ", pos=" + coord_to_str(pos) << std::endl; - std::cerr << "check_wagon_tile end" << std::endl; - } -#endif - - if ((shape != df::tiletype_shape::RAMP_TOP && (is_wagon_traversible(ctx, pos+df::coord(-1, -1, 0), pos) && is_wagon_traversible(ctx, pos+df::coord( 0, -1, 0), pos) && From 2b768683acba766e86a4cbd049c02a28c39d11c6 Mon Sep 17 00:00:00 2001 From: dhthwy <302825+dhthwy@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:04:59 -0500 Subject: [PATCH 4/8] #5031: Fix MSVC build. Missing headers? --- library/modules/Maps.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index ae309c29c1..9206ae5a8f 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -63,6 +63,8 @@ distribution. #include "df/world_underground_region.h" #include "df/z_level_flags.h" +#include +#include #include #include #include From 3c7a3b22bfaa0e3aeff39b777f01e89d7a9d0b2c Mon Sep 17 00:00:00 2001 From: dhthwy <302825+dhthwy@users.noreply.github.com> Date: Sat, 30 Nov 2024 13:48:41 -0500 Subject: [PATCH 5/8] #5031: make wagon_flood() check it reaches an edge tile for correctly reporting wagon accessibility --- plugins/pathable.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 8535ce2ab9..28969dc1ad 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -214,6 +214,7 @@ static bool is_wagon_traversible(FloodCtx & ctx, const df::coord & pos, const df return false; auto shape = tileShape(*tt); + if (shape == df::tiletype_shape::STAIR_UP || shape == df::tiletype_shape::STAIR_UPDOWN) return false; @@ -272,7 +273,7 @@ static void check_wagon_tile(FloodCtx & ctx, const df::coord & pos) { ctx.seen.emplace(pos); if (ctx.entry_tiles.contains(pos)) { - ctx.wagon_path.emplace(pos); + ctx.wagon_path.emplace(pos); // Is this needed? ctx.search_edge.emplace(pos); return; } @@ -323,7 +324,8 @@ static bool wagon_flood(color_ostream &out, unordered_set * wagon_pat TRACE(log,out).print("checking tile: (%d, %d, %d); pathability group: %d\n", pos.x, pos.y, pos.z, Maps::getWalkableGroup(pos)); - if (entry_tiles.contains(pos)) { + // Ensure our wagon flood end points lands on an edge tile. + if ((pos.x == 0 || pos.y == 0) && entry_tiles.contains(pos)) { found = true; if (!wagon_path) break; From 8ea4f6afac3e8e6788eba1060ca4d1577835ad50 Mon Sep 17 00:00:00 2001 From: dhthwy <302825+dhthwy@users.noreply.github.com> Date: Sun, 1 Dec 2024 13:18:32 -0500 Subject: [PATCH 6/8] #5031: Make wagon pathability tests more robust --- plugins/pathable.cpp | 84 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 6 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 28969dc1ad..ff8e2938b2 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -2,6 +2,11 @@ #include "PluginManager.h" #include "TileTypes.h" +#include "df/building_type.h" +#include "df/building_hatchst.h" +#include "df/building_bars_floorst.h" +#include "df/building_grate_floorst.h" +#include "df/tile_building_occ.h" #include "modules/Buildings.h" #include "modules/Gui.h" #include "modules/Maps.h" @@ -202,25 +207,74 @@ struct FloodCtx { : wgroup(wgroup), wagon_path(wagon_path), entry_tiles(entry_tiles) {} }; -static bool is_wagon_traversible(FloodCtx & ctx, const df::coord & pos, const df::coord & prev_pos) { - if (auto bld = Buildings::findAtTile(pos)) { - auto btype = bld->getType(); - if (btype == df::building_type::Trap || btype == df::building_type::Door) +static bool is_wagon_dynamic_traversible(df::tiletype_shape shape, const df::coord & pos) { + auto bld = Buildings::findAtTile(pos); + if (!bld) return false; + + auto btype = bld->getType(); + // open hatch should be inaccessible regardless of the tile it sits on + if (btype == df::building_type::Hatch) { + if (shape == df::tiletype_shape::RAMP_TOP) return false; + + auto& hatch = *static_cast(bld); + if (hatch.door_flags.bits.closed) + return true; + // open floor grate/bar should be inaccessible regardless of the tile it sits on + } else if (btype == df::building_type::GrateFloor) { + auto& b = *static_cast(bld); + if (b.gate_flags.bits.closed) + return true; + } else if (btype == df::building_type::BarsFloor) { + auto& b = *static_cast(bld); + if (b.gate_flags.bits.closed) + return true; } + // Doors, traps..etc + return false; +} +static bool is_wagon_traversible(FloodCtx & ctx, const df::coord & pos, const df::coord & prev_pos) { auto tt = Maps::getTileType(pos); if (!tt) return false; auto shape = tileShape(*tt); - if (shape == df::tiletype_shape::STAIR_UP || shape == df::tiletype_shape::STAIR_UPDOWN) - return false; + auto& occ = *Maps::getTileOccupancy(pos); + switch (occ.bits.building) { + case tile_building_occ::Obstacle: // Statue + //fallthrough + case tile_building_occ::Well: + //fallthrough + case tile_building_occ::Impassable: + return false; + + case tile_building_occ::Dynamic: // doors(block), levers (block), traps (block), hatches (OK, but block on down ramp), closed floor grates (OK), closed floor bars (OK) + if (is_wagon_dynamic_traversible(shape, pos) == false) + return false; + break; + case tile_building_occ::None: // Not occupied by a building + // TODO smoothed boulders are traversable + if (shape == df::tiletype_shape::STAIR_UP || shape == df::tiletype_shape::STAIR_DOWN || + shape == df::tiletype_shape::STAIR_UPDOWN || shape == df::tiletype_shape::BOULDER || + shape == df::tiletype_shape::EMPTY || shape == df::tiletype_shape::NONE) + return false; + break; + case tile_building_occ::Planned: + //fallthrough + case tile_building_occ::Passable: // bed, support, rollers, armor/weapon stand, bed, cage, open wall grate/vertical bars + //fallthrough + case tile_building_occ::Floored: // depot, lowered bridge, forbidden hatch + default: + break; + } if (ctx.wgroup == Maps::getWalkableGroup(pos)) return true; + // RAMP_TOP is assigned a walkability group if that commit is accepted + // so this test, I think, would be useless. if (shape == df::tiletype_shape::RAMP_TOP ) { df::coord pos_below = pos + df::coord(0, 0, -1); if (Maps::getWalkableGroup(pos_below)) { @@ -296,6 +350,22 @@ static void check_wagon_tile(FloodCtx & ctx, const df::coord & pos) { ctx.wagon_path.emplace(pos); ctx.search_edge.emplace(pos); } + +#if 0 + // Use this if we don't mind red Xs on down ramps + if ((is_wagon_traversible(ctx, pos+df::coord(-1, -1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 0, -1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 1, -1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord(-1, 0, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 1, 0, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord(-1, 1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 0, 1, 0), pos) && + is_wagon_traversible(ctx, pos+df::coord( 1, 1, 0), pos))) { + ctx.wagon_path.emplace(pos); + ctx.search_edge.emplace(pos); + } +#endif + } // returns true if a continuous 3-wide path can be found to an entry tile @@ -325,6 +395,8 @@ static bool wagon_flood(color_ostream &out, unordered_set * wagon_pat Maps::getWalkableGroup(pos)); // Ensure our wagon flood end points lands on an edge tile. + // When there is no path to the depot entry_tiles will not + // contain any edge tiles. if ((pos.x == 0 || pos.y == 0) && entry_tiles.contains(pos)) { found = true; if (!wagon_path) From a0a37f39f54fa074f69b1d0ec80ba4043030d1b6 Mon Sep 17 00:00:00 2001 From: dhthwy <302825+dhthwy@users.noreply.github.com> Date: Sun, 1 Dec 2024 15:51:33 -0500 Subject: [PATCH 7/8] Correctly handle wagon accessible tiles for passable buildings --- plugins/pathable.cpp | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index ec8af8bc76..cf7fde2b5d 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -235,6 +235,15 @@ static bool is_wagon_dynamic_traversible(df::tiletype_shape shape, const df::coo return false; } +static bool is_wagon_tile_traversible(df::tiletype_shape shape) { + // TODO: smoothed boulders are traversible + if (shape == df::tiletype_shape::STAIR_UP || shape == df::tiletype_shape::STAIR_DOWN || + shape == df::tiletype_shape::STAIR_UPDOWN || shape == df::tiletype_shape::BOULDER || + shape == df::tiletype_shape::EMPTY || shape == df::tiletype_shape::NONE) + return false; + return true; +} + static bool is_wagon_traversible(FloodCtx & ctx, const df::coord & pos, const df::coord & prev_pos) { auto tt = Maps::getTileType(pos); if (!tt) @@ -245,29 +254,34 @@ static bool is_wagon_traversible(FloodCtx & ctx, const df::coord & pos, const df auto& occ = *Maps::getTileOccupancy(pos); switch (occ.bits.building) { case tile_building_occ::Obstacle: // Statue - //fallthrough + //FALLTHROUGH case tile_building_occ::Well: - //fallthrough - case tile_building_occ::Impassable: + //FALLTHROUGH + case tile_building_occ::Impassable: // Raised bridge return false; - case tile_building_occ::Dynamic: // doors(block), levers (block), traps (block), hatches (OK, but block on down ramp), closed floor grates (OK), closed floor bars (OK) + case tile_building_occ::Dynamic: + // doors(block), levers (block), traps (block), hatches (OK, but block on down ramp) + // closed floor grates (OK), closed floor bars (OK) if (is_wagon_dynamic_traversible(shape, pos) == false) return false; break; + case tile_building_occ::None: // Not occupied by a building - // TODO smoothed boulders are traversable - if (shape == df::tiletype_shape::STAIR_UP || shape == df::tiletype_shape::STAIR_DOWN || - shape == df::tiletype_shape::STAIR_UPDOWN || shape == df::tiletype_shape::BOULDER || - shape == df::tiletype_shape::EMPTY || shape == df::tiletype_shape::NONE) + //FALLTHROUGH + case tile_building_occ::Planned: + //FALLTHROUGH + case tile_building_occ::Passable: + // bed, support, rollers, armor/weapon stand, cage (not trap) + // open wall grate/vertical bars, retracted bridge, open floodgate + if (is_wagon_tile_traversible(shape) == false) return false; break; - case tile_building_occ::Planned: - //fallthrough - case tile_building_occ::Passable: // bed, support, rollers, armor/weapon stand, bed, cage, open wall grate/vertical bars - //fallthrough - case tile_building_occ::Floored: // depot, lowered bridge, forbidden hatch + case tile_building_occ::Floored: + // depot, lowered bridge, retracable bridge, forbidden hatch + break; default: + //NOTREACHED break; } From 2a1a7345793c5e56929435071d52e9ab6bd1300c Mon Sep 17 00:00:00 2001 From: dhthwy <302825+dhthwy@users.noreply.github.com> Date: Mon, 2 Dec 2024 10:00:18 -0500 Subject: [PATCH 8/8] #5031: handle tracks, murky pool and river tiles --- plugins/pathable.cpp | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index cf7fde2b5d..4dba417a05 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -235,12 +235,28 @@ static bool is_wagon_dynamic_traversible(df::tiletype_shape shape, const df::coo return false; } -static bool is_wagon_tile_traversible(df::tiletype_shape shape) { - // TODO: smoothed boulders are traversible - if (shape == df::tiletype_shape::STAIR_UP || shape == df::tiletype_shape::STAIR_DOWN || +// NOTE: When i.e. tracks, stairs have a bridge over them, the tile will have +// an occupancy of floored. +static bool is_wagon_tile_traversible(df::tiletype& tt) { + auto shape = tileShape(tt); + auto special = tileSpecial(tt); + auto material = tileMaterial(tt); + + // Allow murky pool ramps + if (shape == df::tiletype_shape::RAMP_TOP) + return true; + // NOTE: smoothing a boulder turns it into a smoothed floor + else if (shape == df::tiletype_shape::STAIR_UP || shape == df::tiletype_shape::STAIR_DOWN || shape == df::tiletype_shape::STAIR_UPDOWN || shape == df::tiletype_shape::BOULDER || shape == df::tiletype_shape::EMPTY || shape == df::tiletype_shape::NONE) return false; + else if (special == df::tiletype_special::TRACK) + return false; + // Fires seem to have their own path group, and group for lava is 0 + // According to wiki, the wagon won't path thru pool and river tiles, but ramps are ok + else if (material == df::tiletype_material::POOL || material == df::tiletype_material::RIVER) + return false; + return true; } @@ -250,14 +266,13 @@ static bool is_wagon_traversible(FloodCtx & ctx, const df::coord & pos, const df return false; auto shape = tileShape(*tt); - auto& occ = *Maps::getTileOccupancy(pos); switch (occ.bits.building) { - case tile_building_occ::Obstacle: // Statue + case tile_building_occ::Obstacle: // Statues, windmills (middle tile) //FALLTHROUGH case tile_building_occ::Well: //FALLTHROUGH - case tile_building_occ::Impassable: // Raised bridge + case tile_building_occ::Impassable: // Raised bridges return false; case tile_building_occ::Dynamic: @@ -272,13 +287,15 @@ static bool is_wagon_traversible(FloodCtx & ctx, const df::coord & pos, const df case tile_building_occ::Planned: //FALLTHROUGH case tile_building_occ::Passable: - // bed, support, rollers, armor/weapon stand, cage (not trap) - // open wall grate/vertical bars, retracted bridge, open floodgate - if (is_wagon_tile_traversible(shape) == false) + // Any tile with no building or a passable building including + // beds, supports, rollers, armor/weapon stands, cages (not traps), + // open wall grate/vertical bars, retracted bridges, open floodgates, + // workshops (tiles with open space are handled by the tile check) + if (is_wagon_tile_traversible(*tt) == false) return false; break; case tile_building_occ::Floored: - // depot, lowered bridge, retracable bridge, forbidden hatch + // depot, lowered bridges or retractable bridges, forbidden hatches break; default: //NOTREACHED