Skip to content

Commit ef3144c

Browse files
authored
Merge pull request #5053 from dhthwy/wagonpathfix
#5031: Fix accessibility logic for wagons
2 parents 730ae37 + 5d24e07 commit ef3144c

File tree

2 files changed

+98
-8
lines changed

2 files changed

+98
-8
lines changed

docs/changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ Template for new versions:
9696
- `timestream`: improve FPS by a further 10%
9797
- `fix/occupancy`: additionally handle the case where tile building occupancy needs to be set instead of cleared
9898
- `orders`: ``orders sort`` now moves orders that are tied to a specific workshop to the top of the list in the global manager orders screen
99+
- `gui/pathable`: make wagon path to depot representation more robust
99100

100101
## Documentation
101102
- Dreamfort: add link to Dreamfort tutorial youtube series: https://www.youtube.com/playlist?list=PLzXx9JcB9oXxmrtkO1y8ZXzBCFEZrKxve

plugins/pathable.cpp

Lines changed: 97 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
#include "PluginManager.h"
44
#include "TileTypes.h"
55

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"
611
#include "modules/Buildings.h"
712
#include "modules/Gui.h"
813
#include "modules/Maps.h"
@@ -168,11 +173,14 @@ static bool get_pathability_groups(color_ostream &out, unordered_set<uint16_t> *
168173
static bool get_entry_tiles(unordered_set<df::coord> * entry_tiles, const unordered_set<uint16_t> & depot_pathability_groups) {
169174
auto & edge = plotinfo->map_edge;
170175
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);
171178
bool found = false;
172179
for (size_t idx = 0; idx < num_edge_tiles; ++idx) {
173180
df::coord pos(edge.surface_x[idx], edge.surface_y[idx], edge.surface_z[idx]);
174181
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)) {
176184
found = true;
177185
if (!entry_tiles)
178186
break;
@@ -203,20 +211,99 @@ struct FloodCtx {
203211
: wgroup(wgroup), wagon_path(wagon_path), entry_tiles(entry_tiles) {}
204212
};
205213

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)
210222
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;
211236
}
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;
212262

263+
return true;
264+
}
265+
266+
static bool is_wagon_traversible(FloodCtx & ctx, const df::coord & pos, const df::coord & prev_pos) {
213267
auto tt = Maps::getTileType(pos);
214268
if (!tt)
215269
return false;
216270

217271
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)
219274
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+
}
220307

221308
if (ctx.wgroup == Maps::getWalkableGroup(pos))
222309
return true;
@@ -248,12 +335,13 @@ static void check_wagon_tile(FloodCtx & ctx, const df::coord & pos) {
248335
ctx.seen.emplace(pos);
249336

250337
if (ctx.entry_tiles.contains(pos)) {
251-
ctx.wagon_path.emplace(pos);
338+
ctx.wagon_path.emplace(pos); // Is this needed?
252339
ctx.search_edge.emplace(pos);
253340
return;
254341
}
255342

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) &&
257345
is_wagon_traversible(ctx, pos+df::coord( 0, -1, 0), pos) &&
258346
is_wagon_traversible(ctx, pos+df::coord( 1, -1, 0), pos) &&
259347
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
286374
ctx.wagon_path.emplace(depot_pos);
287375
ctx.seen.emplace(depot_pos);
288376
ctx.search_edge.emplace(depot_pos);
377+
289378
while (!ctx.search_edge.empty()) {
290379
df::coord pos = ctx.search_edge.top();
291380
ctx.search_edge.pop();

0 commit comments

Comments
 (0)