|
3 | 3 | #include "PluginManager.h" |
4 | 4 | #include "TileTypes.h" |
5 | 5 |
|
| 6 | +#include "df/building_type.h" |
| 7 | +#include "df/building_hatchst.h" |
| 8 | +#include "df/building_bars_floorst.h" |
| 9 | +#include "df/building_grate_floorst.h" |
| 10 | +#include "df/tile_building_occ.h" |
6 | 11 | #include "modules/Buildings.h" |
7 | 12 | #include "modules/Gui.h" |
8 | 13 | #include "modules/Maps.h" |
@@ -168,11 +173,14 @@ static bool get_pathability_groups(color_ostream &out, unordered_set<uint16_t> * |
168 | 173 | static bool get_entry_tiles(unordered_set<df::coord> * entry_tiles, const unordered_set<uint16_t> & depot_pathability_groups) { |
169 | 174 | auto & edge = plotinfo->map_edge; |
170 | 175 | size_t num_edge_tiles = edge.surface_x.size(); |
| 176 | + uint32_t max_x, max_y, max_z; |
| 177 | + Maps::getTileSize(max_x, max_y, max_z); |
171 | 178 | bool found = false; |
172 | 179 | for (size_t idx = 0; idx < num_edge_tiles; ++idx) { |
173 | 180 | df::coord pos(edge.surface_x[idx], edge.surface_y[idx], edge.surface_z[idx]); |
174 | 181 | auto wgroup = Maps::getWalkableGroup(pos); |
175 | | - if (depot_pathability_groups.contains(wgroup)) { |
| 182 | + if (depot_pathability_groups.contains(wgroup) && |
| 183 | + (pos.x == 0 || pos.y == 0 || pos.x == (int16_t)max_x || pos.y == (int16_t)max_y)) { |
176 | 184 | found = true; |
177 | 185 | if (!entry_tiles) |
178 | 186 | break; |
@@ -203,20 +211,99 @@ struct FloodCtx { |
203 | 211 | : wgroup(wgroup), wagon_path(wagon_path), entry_tiles(entry_tiles) {} |
204 | 212 | }; |
205 | 213 |
|
206 | | -static bool is_wagon_traversible(FloodCtx & ctx, const df::coord & pos, const df::coord & prev_pos) { |
207 | | - if (auto bld = Buildings::findAtTile(pos)) { |
208 | | - auto btype = bld->getType(); |
209 | | - if (btype == df::building_type::Trap || btype == df::building_type::Door) |
| 214 | +static bool is_wagon_dynamic_traversible(df::tiletype_shape shape, const df::coord & pos) { |
| 215 | + auto bld = Buildings::findAtTile(pos); |
| 216 | + if (!bld) return false; |
| 217 | + |
| 218 | + auto btype = bld->getType(); |
| 219 | + // open hatch should be inaccessible regardless of the tile it sits on |
| 220 | + if (btype == df::building_type::Hatch) { |
| 221 | + if (shape == df::tiletype_shape::RAMP_TOP) |
210 | 222 | return false; |
| 223 | + |
| 224 | + auto& hatch = *static_cast<df::building_hatchst*>(bld); |
| 225 | + if (hatch.door_flags.bits.closed) |
| 226 | + return true; |
| 227 | + // open floor grate/bar should be inaccessible regardless of the tile it sits on |
| 228 | + } else if (btype == df::building_type::GrateFloor) { |
| 229 | + auto& b = *static_cast<df::building_grate_floorst*>(bld); |
| 230 | + if (b.gate_flags.bits.closed) |
| 231 | + return true; |
| 232 | + } else if (btype == df::building_type::BarsFloor) { |
| 233 | + auto& b = *static_cast<df::building_bars_floorst*>(bld); |
| 234 | + if (b.gate_flags.bits.closed) |
| 235 | + return true; |
211 | 236 | } |
| 237 | + // Doors, traps..etc |
| 238 | + return false; |
| 239 | +} |
| 240 | + |
| 241 | +// NOTE: When i.e. tracks, stairs have a bridge over them, the tile will have |
| 242 | +// an occupancy of floored. |
| 243 | +static bool is_wagon_tile_traversible(df::tiletype tt) { |
| 244 | + auto shape = tileShape(tt); |
| 245 | + auto special = tileSpecial(tt); |
| 246 | + auto material = tileMaterial(tt); |
| 247 | + |
| 248 | + // Allow ramps (murky pool and river tiles are blocked except for ramps) |
| 249 | + if (shape == df::tiletype_shape::RAMP_TOP) |
| 250 | + return true; |
| 251 | + // NOTE: smoothing a boulder turns it into a smoothed floor |
| 252 | + else if (shape == df::tiletype_shape::STAIR_UP || shape == df::tiletype_shape::STAIR_DOWN || |
| 253 | + shape == df::tiletype_shape::STAIR_UPDOWN || shape == df::tiletype_shape::BOULDER || |
| 254 | + shape == df::tiletype_shape::EMPTY || shape == df::tiletype_shape::NONE) |
| 255 | + return false; |
| 256 | + else if (special == df::tiletype_special::TRACK) |
| 257 | + return false; |
| 258 | + // Fires seem to have their own path group, and group for lava is 0 |
| 259 | + // According to wiki, the wagon won't path thru pool and river tiles, but ramps are ok |
| 260 | + else if (material == df::tiletype_material::POOL || material == df::tiletype_material::RIVER) |
| 261 | + return false; |
212 | 262 |
|
| 263 | + return true; |
| 264 | +} |
| 265 | + |
| 266 | +static bool is_wagon_traversible(FloodCtx & ctx, const df::coord & pos, const df::coord & prev_pos) { |
213 | 267 | auto tt = Maps::getTileType(pos); |
214 | 268 | if (!tt) |
215 | 269 | return false; |
216 | 270 |
|
217 | 271 | auto shape = tileShape(*tt); |
218 | | - if (shape == df::tiletype_shape::STAIR_UP || shape == df::tiletype_shape::STAIR_UPDOWN) |
| 272 | + auto occp = Maps::getTileOccupancy(pos); |
| 273 | + if (!occp) |
219 | 274 | return false; |
| 275 | + auto & occ = *occp; |
| 276 | + switch (occ.bits.building) { |
| 277 | + case tile_building_occ::Obstacle: // Statues, windmills (middle tile) |
| 278 | + //FALLTHROUGH |
| 279 | + case tile_building_occ::Well: |
| 280 | + //FALLTHROUGH |
| 281 | + case tile_building_occ::Impassable: // Raised bridges |
| 282 | + return false; |
| 283 | + |
| 284 | + case tile_building_occ::Dynamic: |
| 285 | + // doors(block), levers (block), traps (block), hatches (OK, but block on down ramp) |
| 286 | + // closed floor grates (OK), closed floor bars (OK) |
| 287 | + if (is_wagon_dynamic_traversible(shape, pos) == false) |
| 288 | + return false; |
| 289 | + break; |
| 290 | + |
| 291 | + case tile_building_occ::None: // Not occupied by a building |
| 292 | + //FALLTHROUGH |
| 293 | + case tile_building_occ::Planned: |
| 294 | + //FALLTHROUGH |
| 295 | + case tile_building_occ::Passable: |
| 296 | + // Any tile with no building or a passable building including |
| 297 | + // beds, supports, rollers, armor/weapon stands, cages (not traps), |
| 298 | + // open wall grate/vertical bars, retracted bridges, open floodgates, |
| 299 | + // workshops (tiles with open space are handled by the tile check) |
| 300 | + if (is_wagon_tile_traversible(*tt) == false) |
| 301 | + return false; |
| 302 | + break; |
| 303 | + case tile_building_occ::Floored: |
| 304 | + // depot, lowered bridges or retractable bridges, forbidden hatches |
| 305 | + break; |
| 306 | + } |
220 | 307 |
|
221 | 308 | if (ctx.wgroup == Maps::getWalkableGroup(pos)) |
222 | 309 | return true; |
@@ -248,12 +335,13 @@ static void check_wagon_tile(FloodCtx & ctx, const df::coord & pos) { |
248 | 335 | ctx.seen.emplace(pos); |
249 | 336 |
|
250 | 337 | if (ctx.entry_tiles.contains(pos)) { |
251 | | - ctx.wagon_path.emplace(pos); |
| 338 | + ctx.wagon_path.emplace(pos); // Is this needed? |
252 | 339 | ctx.search_edge.emplace(pos); |
253 | 340 | return; |
254 | 341 | } |
255 | 342 |
|
256 | | - if (is_wagon_traversible(ctx, pos+df::coord(-1, -1, 0), pos) && |
| 343 | + if (is_wagon_traversible(ctx, pos, pos) && |
| 344 | + is_wagon_traversible(ctx, pos+df::coord(-1, -1, 0), pos) && |
257 | 345 | is_wagon_traversible(ctx, pos+df::coord( 0, -1, 0), pos) && |
258 | 346 | is_wagon_traversible(ctx, pos+df::coord( 1, -1, 0), pos) && |
259 | 347 | is_wagon_traversible(ctx, pos+df::coord(-1, 0, 0), pos) && |
@@ -286,6 +374,7 @@ static bool wagon_flood(color_ostream &out, unordered_set<df::coord> * wagon_pat |
286 | 374 | ctx.wagon_path.emplace(depot_pos); |
287 | 375 | ctx.seen.emplace(depot_pos); |
288 | 376 | ctx.search_edge.emplace(depot_pos); |
| 377 | + |
289 | 378 | while (!ctx.search_edge.empty()) { |
290 | 379 | df::coord pos = ctx.search_edge.top(); |
291 | 380 | ctx.search_edge.pop(); |
|
0 commit comments