fix issue where items were accepted by a belt from opposite travel direction
This commit is contained in:
@@ -27,6 +27,56 @@ QPoint BeltSystem::adjacentTile(QPoint tile, Rotation dir)
|
||||
return tile;
|
||||
}
|
||||
|
||||
Rotation BeltSystem::oppositeRotation(Rotation dir)
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
case Rotation::North: return Rotation::South;
|
||||
case Rotation::East: return Rotation::West;
|
||||
case Rotation::South: return Rotation::North;
|
||||
case Rotation::West: return Rotation::East;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
bool BeltSystem::entersThroughOutputEdge(QPoint tile, Rotation travelDir) const
|
||||
{
|
||||
// An item travelling in travelDir crosses into the tile through the edge
|
||||
// opposite that direction. If that entry edge is one of the tile's output
|
||||
// edges, the tile must refuse the item (REQ-MAT-ACCEPT-DIR).
|
||||
const Rotation entryEdge = oppositeRotation(travelDir);
|
||||
|
||||
const std::map<std::pair<int, int>, BeltTile>::const_iterator beltIt =
|
||||
m_belts.find(key(tile));
|
||||
if (beltIt != m_belts.end())
|
||||
{
|
||||
return entryEdge == beltIt->second.direction;
|
||||
}
|
||||
|
||||
const std::map<std::pair<int, int>, SplitterTile>::const_iterator splIt =
|
||||
m_splitters.find(key(tile));
|
||||
if (splIt != m_splitters.end())
|
||||
{
|
||||
return entryEdge == splIt->second.outputA || entryEdge == splIt->second.outputB;
|
||||
}
|
||||
|
||||
const std::map<std::pair<int, int>, TunnelEntryTile>::const_iterator teIt =
|
||||
m_tunnelEntries.find(key(tile));
|
||||
if (teIt != m_tunnelEntries.end())
|
||||
{
|
||||
return entryEdge == teIt->second.direction;
|
||||
}
|
||||
|
||||
const std::map<std::pair<int, int>, TunnelExitTile>::const_iterator txIt =
|
||||
m_tunnelExits.find(key(tile));
|
||||
if (txIt != m_tunnelExits.end())
|
||||
{
|
||||
return entryEdge == txIt->second.direction;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QPointF BeltSystem::slotWorldPos(QPoint tile, Rotation dir, double progress)
|
||||
{
|
||||
// Map progress [0, 1] along the belt direction to a fractional tile-unit position.
|
||||
@@ -202,6 +252,12 @@ void BeltSystem::reevaluateTunnelPairing()
|
||||
|
||||
bool BeltSystem::tryPutItem(QPoint tile, Item item, Rotation fromDir)
|
||||
{
|
||||
// Refuse items that would enter through the tile's output edge (REQ-MAT-ACCEPT-DIR).
|
||||
if (entersThroughOutputEdge(tile, fromDir))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::map<std::pair<int, int>, BeltTile>::iterator bIt = m_belts.find(key(tile));
|
||||
if (bIt != m_belts.end())
|
||||
{
|
||||
@@ -579,6 +635,13 @@ void BeltSystem::moveItemsToNextTile()
|
||||
const QPoint here = QPoint(it->first.first, it->first.second);
|
||||
const QPoint next = adjacentTile(here, bt.direction);
|
||||
|
||||
// Refuse to hand off into a downstream tile's output edge (REQ-MAT-ACCEPT-DIR);
|
||||
// the item stays blocked at progress 1.0.
|
||||
if (entersThroughOutputEdge(next, bt.direction))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::map<std::pair<int, int>, BeltTile>::iterator nextBelt = m_belts.find(key(next));
|
||||
const std::map<std::pair<int, int>, SplitterTile>::iterator nextSplitter = m_splitters.find(key(next));
|
||||
|
||||
@@ -804,6 +867,12 @@ bool BeltSystem::tryPlaceOnBelt(QPoint tile, Item item)
|
||||
|
||||
bool BeltSystem::tryPushToTile(QPoint dest, Item item, Rotation fromDir)
|
||||
{
|
||||
// Refuse items that would enter through the tile's output edge (REQ-MAT-ACCEPT-DIR).
|
||||
if (entersThroughOutputEdge(dest, fromDir))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tryPlaceOnBelt(dest, item))
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -74,8 +74,10 @@ public:
|
||||
// port.direction = direction items flow on that tile
|
||||
//
|
||||
// tryPutItem: place item onto tile.
|
||||
// Returns false if the tile is not a belt/splitter, or tile full.
|
||||
// fromDir: travel direction of the item (used for splitter animation).
|
||||
// Returns false if the tile is not a belt/splitter/tunnel entry, tile full,
|
||||
// or the item would enter through the tile's output edge (REQ-MAT-ACCEPT-DIR).
|
||||
// fromDir: travel direction of the item (used for splitter animation and for
|
||||
// the output-edge check).
|
||||
bool tryPutItem(QPoint tile, Item item, Rotation fromDir = Rotation::West);
|
||||
|
||||
// tryTakeItem: remove and return the leading item from port.tile.
|
||||
@@ -117,6 +119,12 @@ private:
|
||||
|
||||
static std::pair<int, int> key(QPoint tile);
|
||||
static QPoint adjacentTile(QPoint tile, Rotation dir);
|
||||
static Rotation oppositeRotation(Rotation dir);
|
||||
|
||||
// True if an item travelling in travelDir would enter the transport tile at
|
||||
// `tile` through one of that tile's output edges (and must therefore be
|
||||
// refused). Returns false if no transport tile occupies `tile`.
|
||||
bool entersThroughOutputEdge(QPoint tile, Rotation travelDir) const;
|
||||
|
||||
// Returns the world-space centre of a slot given tile origin and progress.
|
||||
static QPointF slotWorldPos(QPoint tile, Rotation dir, double progress);
|
||||
|
||||
Reference in New Issue
Block a user