implement 4 items on belt tile
This commit is contained in:
@@ -66,7 +66,6 @@ void BeltSystem::placeSplitter(QPoint tile, Rotation outputA, Rotation outputB)
|
|||||||
st.outputA = outputA;
|
st.outputA = outputA;
|
||||||
st.outputB = outputB;
|
st.outputB = outputB;
|
||||||
st.nextOutputIsA = true;
|
st.nextOutputIsA = true;
|
||||||
st.backDir = Rotation::North; // irrelevant until back is set
|
|
||||||
m_splitters[key(tile)] = st;
|
m_splitters[key(tile)] = st;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,10 +210,10 @@ bool BeltSystem::tryPutItem(QPoint tile, Item item, Rotation fromDir)
|
|||||||
m_splitters.find(key(tile));
|
m_splitters.find(key(tile));
|
||||||
if (splIt != m_splitters.end())
|
if (splIt != m_splitters.end())
|
||||||
{
|
{
|
||||||
if (!splIt->second.back)
|
if (splIt->second.back.size() < 2)
|
||||||
{
|
{
|
||||||
splIt->second.back = BeltItemSlot{item, 0.0};
|
splIt->second.back.push_back(BeltItemSlot{item, 0.0});
|
||||||
splIt->second.backDir = fromDir;
|
splIt->second.backDir.push_back(fromDir);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -224,15 +223,9 @@ bool BeltSystem::tryPutItem(QPoint tile, Item item, Rotation fromDir)
|
|||||||
m_tunnelEntries.find(key(tile));
|
m_tunnelEntries.find(key(tile));
|
||||||
if (teIt != m_tunnelEntries.end())
|
if (teIt != m_tunnelEntries.end())
|
||||||
{
|
{
|
||||||
TunnelEntryTile& te = teIt->second;
|
if (teIt->second.itemSlots.size() < 4)
|
||||||
if (!te.front)
|
|
||||||
{
|
{
|
||||||
te.front = BeltItemSlot{item, 0.0};
|
teIt->second.itemSlots.push_back(BeltItemSlot{item, 0.0});
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!te.back)
|
|
||||||
{
|
|
||||||
te.back = BeltItemSlot{item, 0.0};
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -251,11 +244,10 @@ std::optional<Item> BeltSystem::tryTakeItem(Port port)
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
BeltTile& bt = beltIt->second;
|
BeltTile& bt = beltIt->second;
|
||||||
if (bt.front && bt.front->progress >= 1.0)
|
if (!bt.itemSlots.empty() && bt.itemSlots.front().progress >= 1.0)
|
||||||
{
|
{
|
||||||
const Item taken = bt.front->item;
|
const Item taken = bt.itemSlots.front().item;
|
||||||
bt.front = bt.back;
|
bt.itemSlots.erase(bt.itemSlots.begin());
|
||||||
bt.back = std::nullopt;
|
|
||||||
return taken;
|
return taken;
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@@ -285,11 +277,11 @@ std::optional<Item> BeltSystem::tryTakeItem(Port port)
|
|||||||
if (txIt != m_tunnelExits.end())
|
if (txIt != m_tunnelExits.end())
|
||||||
{
|
{
|
||||||
TunnelExitTile& tx = txIt->second;
|
TunnelExitTile& tx = txIt->second;
|
||||||
if (tx.direction == port.direction && tx.front && tx.front->progress >= 1.0)
|
if (tx.direction == port.direction && !tx.itemSlots.empty()
|
||||||
|
&& tx.itemSlots.front().progress >= 1.0)
|
||||||
{
|
{
|
||||||
const Item taken = tx.front->item;
|
const Item taken = tx.itemSlots.front().item;
|
||||||
tx.front = tx.back;
|
tx.itemSlots.erase(tx.itemSlots.begin());
|
||||||
tx.back = std::nullopt;
|
|
||||||
return taken;
|
return taken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -308,9 +300,9 @@ std::optional<ItemType> BeltSystem::peekItem(Port port) const
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
const BeltTile& bt = beltIt->second;
|
const BeltTile& bt = beltIt->second;
|
||||||
if (bt.front && bt.front->progress >= 1.0)
|
if (!bt.itemSlots.empty() && bt.itemSlots.front().progress >= 1.0)
|
||||||
{
|
{
|
||||||
return bt.front->item.type;
|
return bt.itemSlots.front().item.type;
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@@ -335,9 +327,10 @@ std::optional<ItemType> BeltSystem::peekItem(Port port) const
|
|||||||
if (txIt != m_tunnelExits.end())
|
if (txIt != m_tunnelExits.end())
|
||||||
{
|
{
|
||||||
const TunnelExitTile& tx = txIt->second;
|
const TunnelExitTile& tx = txIt->second;
|
||||||
if (tx.direction == port.direction && tx.front && tx.front->progress >= 1.0)
|
if (tx.direction == port.direction && !tx.itemSlots.empty()
|
||||||
|
&& tx.itemSlots.front().progress >= 1.0)
|
||||||
{
|
{
|
||||||
return tx.front->item.type;
|
return tx.itemSlots.front().item.type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,14 +348,14 @@ void BeltSystem::clearTiles(const std::vector<QPoint>& tiles)
|
|||||||
const std::map<std::pair<int, int>, BeltTile>::iterator bIt = m_belts.find(key(tile));
|
const std::map<std::pair<int, int>, BeltTile>::iterator bIt = m_belts.find(key(tile));
|
||||||
if (bIt != m_belts.end())
|
if (bIt != m_belts.end())
|
||||||
{
|
{
|
||||||
bIt->second.front = std::nullopt;
|
bIt->second.itemSlots.clear();
|
||||||
bIt->second.back = std::nullopt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<std::pair<int, int>, SplitterTile>::iterator sIt = m_splitters.find(key(tile));
|
const std::map<std::pair<int, int>, SplitterTile>::iterator sIt = m_splitters.find(key(tile));
|
||||||
if (sIt != m_splitters.end())
|
if (sIt != m_splitters.end())
|
||||||
{
|
{
|
||||||
sIt->second.back = std::nullopt;
|
sIt->second.back.clear();
|
||||||
|
sIt->second.backDir.clear();
|
||||||
sIt->second.frontA = std::nullopt;
|
sIt->second.frontA = std::nullopt;
|
||||||
sIt->second.frontB = std::nullopt;
|
sIt->second.frontB = std::nullopt;
|
||||||
}
|
}
|
||||||
@@ -371,8 +364,7 @@ void BeltSystem::clearTiles(const std::vector<QPoint>& tiles)
|
|||||||
m_tunnelEntries.find(key(tile));
|
m_tunnelEntries.find(key(tile));
|
||||||
if (teIt != m_tunnelEntries.end())
|
if (teIt != m_tunnelEntries.end())
|
||||||
{
|
{
|
||||||
teIt->second.front = std::nullopt;
|
teIt->second.itemSlots.clear();
|
||||||
teIt->second.back = std::nullopt;
|
|
||||||
for (TunnelLink& link : m_tunnelLinks)
|
for (TunnelLink& link : m_tunnelLinks)
|
||||||
{
|
{
|
||||||
if (link.entryTile == tile)
|
if (link.entryTile == tile)
|
||||||
@@ -386,8 +378,7 @@ void BeltSystem::clearTiles(const std::vector<QPoint>& tiles)
|
|||||||
m_tunnelExits.find(key(tile));
|
m_tunnelExits.find(key(tile));
|
||||||
if (txIt != m_tunnelExits.end())
|
if (txIt != m_tunnelExits.end())
|
||||||
{
|
{
|
||||||
txIt->second.front = std::nullopt;
|
txIt->second.itemSlots.clear();
|
||||||
txIt->second.back = std::nullopt;
|
|
||||||
for (TunnelLink& link : m_tunnelLinks)
|
for (TunnelLink& link : m_tunnelLinks)
|
||||||
{
|
{
|
||||||
if (link.exitTile == tile)
|
if (link.exitTile == tile)
|
||||||
@@ -419,33 +410,26 @@ void BeltSystem::advanceProgress()
|
|||||||
{
|
{
|
||||||
BeltTile& bt = it->second;
|
BeltTile& bt = it->second;
|
||||||
|
|
||||||
if (bt.front)
|
for (std::size_t i = 0; i < bt.itemSlots.size(); ++i)
|
||||||
{
|
{
|
||||||
bt.front->progress += m_progressPerTick;
|
bt.itemSlots[i].progress += m_progressPerTick;
|
||||||
if (bt.front->progress > 1.0)
|
|
||||||
|
// Absolute cap: slot i cannot exceed 1.0 - i * 0.25.
|
||||||
|
const double absoluteCap = 1.0 - i * 0.25;
|
||||||
|
if (bt.itemSlots[i].progress > absoluteCap)
|
||||||
{
|
{
|
||||||
bt.front->progress = 1.0;
|
bt.itemSlots[i].progress = absoluteCap;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (bt.back)
|
// Gap constraint: must stay 0.25 behind the slot ahead.
|
||||||
{
|
if (i > 0)
|
||||||
bt.back->progress += m_progressPerTick;
|
|
||||||
|
|
||||||
// Back must not overtake front.
|
|
||||||
if (bt.front && bt.back->progress >= bt.front->progress)
|
|
||||||
{
|
{
|
||||||
bt.back->progress = bt.front->progress - m_progressPerTick;
|
const double gapCap = bt.itemSlots[i - 1].progress - 0.25;
|
||||||
if (bt.back->progress < 0.0)
|
if (bt.itemSlots[i].progress > gapCap)
|
||||||
{
|
{
|
||||||
bt.back->progress = 0.0;
|
bt.itemSlots[i].progress = (gapCap < 0.0 ? 0.0 : gapCap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bt.back->progress > 0.5)
|
|
||||||
{
|
|
||||||
bt.back->progress = 0.5;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,12 +438,26 @@ void BeltSystem::advanceProgress()
|
|||||||
{
|
{
|
||||||
SplitterTile& st = it->second;
|
SplitterTile& st = it->second;
|
||||||
|
|
||||||
if (st.back)
|
for (std::size_t i = 0; i < st.back.size(); ++i)
|
||||||
{
|
{
|
||||||
st.back->progress += m_progressPerTick;
|
st.back[i].progress += m_progressPerTick;
|
||||||
if (st.back->progress > 0.5)
|
const double absoluteCap = 0.5 - i * 0.25;
|
||||||
|
if (st.back[i].progress > absoluteCap)
|
||||||
{
|
{
|
||||||
st.back->progress = 0.5;
|
st.back[i].progress = absoluteCap;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
const double gapCap = st.back[i - 1].progress - 0.25;
|
||||||
|
if (gapCap < 0.0)
|
||||||
|
{
|
||||||
|
st.back[i].progress = 0.0;
|
||||||
|
}
|
||||||
|
else if (st.back[i].progress > gapCap)
|
||||||
|
{
|
||||||
|
st.back[i].progress = gapCap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,29 +488,23 @@ void BeltSystem::advanceTunnelProgress()
|
|||||||
{
|
{
|
||||||
TunnelEntryTile& te = it->second;
|
TunnelEntryTile& te = it->second;
|
||||||
|
|
||||||
if (te.front)
|
for (std::size_t i = 0; i < te.itemSlots.size(); ++i)
|
||||||
{
|
{
|
||||||
te.front->progress += m_progressPerTick;
|
te.itemSlots[i].progress += m_progressPerTick;
|
||||||
if (te.front->progress > 1.0)
|
|
||||||
{
|
|
||||||
te.front->progress = 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (te.back)
|
const double absoluteCap = 1.0 - i * 0.25;
|
||||||
{
|
if (te.itemSlots[i].progress > absoluteCap)
|
||||||
te.back->progress += m_progressPerTick;
|
|
||||||
if (te.front && te.back->progress >= te.front->progress)
|
|
||||||
{
|
{
|
||||||
te.back->progress = te.front->progress - m_progressPerTick;
|
te.itemSlots[i].progress = absoluteCap;
|
||||||
if (te.back->progress < 0.0)
|
|
||||||
{
|
|
||||||
te.back->progress = 0.0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (te.back->progress > 0.5)
|
|
||||||
|
if (i > 0)
|
||||||
{
|
{
|
||||||
te.back->progress = 0.5;
|
const double gapCap = te.itemSlots[i - 1].progress - 0.25;
|
||||||
|
if (te.itemSlots[i].progress > gapCap)
|
||||||
|
{
|
||||||
|
te.itemSlots[i].progress = (gapCap < 0.0 ? 0.0 : gapCap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -522,29 +514,23 @@ void BeltSystem::advanceTunnelProgress()
|
|||||||
{
|
{
|
||||||
TunnelExitTile& tx = it->second;
|
TunnelExitTile& tx = it->second;
|
||||||
|
|
||||||
if (tx.front)
|
for (std::size_t i = 0; i < tx.itemSlots.size(); ++i)
|
||||||
{
|
{
|
||||||
tx.front->progress += m_progressPerTick;
|
tx.itemSlots[i].progress += m_progressPerTick;
|
||||||
if (tx.front->progress > 1.0)
|
|
||||||
{
|
|
||||||
tx.front->progress = 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tx.back)
|
const double absoluteCap = 1.0 - i * 0.25;
|
||||||
{
|
if (tx.itemSlots[i].progress > absoluteCap)
|
||||||
tx.back->progress += m_progressPerTick;
|
|
||||||
if (tx.front && tx.back->progress >= tx.front->progress)
|
|
||||||
{
|
{
|
||||||
tx.back->progress = tx.front->progress - m_progressPerTick;
|
tx.itemSlots[i].progress = absoluteCap;
|
||||||
if (tx.back->progress < 0.0)
|
|
||||||
{
|
|
||||||
tx.back->progress = 0.0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (tx.back->progress > 0.5)
|
|
||||||
|
if (i > 0)
|
||||||
{
|
{
|
||||||
tx.back->progress = 0.5;
|
const double gapCap = tx.itemSlots[i - 1].progress - 0.25;
|
||||||
|
if (tx.itemSlots[i].progress > gapCap)
|
||||||
|
{
|
||||||
|
tx.itemSlots[i].progress = (gapCap < 0.0 ? 0.0 : gapCap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -561,7 +547,7 @@ void BeltSystem::advanceTunnelProgress()
|
|||||||
}
|
}
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
{
|
{
|
||||||
const double maxProgress = link.items[i - 1].progress - 0.5;
|
const double maxProgress = link.items[i - 1].progress - 0.25;
|
||||||
if (ti.progress > maxProgress)
|
if (ti.progress > maxProgress)
|
||||||
{
|
{
|
||||||
ti.progress = maxProgress;
|
ti.progress = maxProgress;
|
||||||
@@ -582,7 +568,7 @@ void BeltSystem::moveItemsToNextTile()
|
|||||||
it != m_belts.end(); ++it)
|
it != m_belts.end(); ++it)
|
||||||
{
|
{
|
||||||
BeltTile& bt = it->second;
|
BeltTile& bt = it->second;
|
||||||
if (!bt.front || bt.front->progress < 1.0)
|
if (bt.itemSlots.empty() || bt.itemSlots.front().progress < 1.0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -595,39 +581,31 @@ void BeltSystem::moveItemsToNextTile()
|
|||||||
|
|
||||||
if (nextBelt != m_belts.end())
|
if (nextBelt != m_belts.end())
|
||||||
{
|
{
|
||||||
if (tryPlaceOnBelt(next, bt.front->item))
|
if (tryPlaceOnBelt(next, bt.itemSlots.front().item))
|
||||||
{
|
{
|
||||||
bt.front = bt.back;
|
bt.itemSlots.erase(bt.itemSlots.begin());
|
||||||
bt.back = std::nullopt;
|
|
||||||
}
|
}
|
||||||
// else: next belt is full — item stays blocked at progress 1.0.
|
// else: next belt is full — item stays blocked at progress 1.0.
|
||||||
}
|
}
|
||||||
else if (nextSplitter != m_splitters.end())
|
else if (nextSplitter != m_splitters.end())
|
||||||
{
|
{
|
||||||
if (!nextSplitter->second.back)
|
if (nextSplitter->second.back.size() < 2)
|
||||||
{
|
{
|
||||||
nextSplitter->second.back = BeltItemSlot{bt.front->item, 0.0};
|
nextSplitter->second.back.push_back(BeltItemSlot{bt.itemSlots.front().item, 0.0});
|
||||||
nextSplitter->second.backDir = bt.direction;
|
nextSplitter->second.backDir.push_back(bt.direction);
|
||||||
bt.front = bt.back;
|
bt.itemSlots.erase(bt.itemSlots.begin());
|
||||||
bt.back = std::nullopt;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const std::map<std::pair<int, int>, TunnelEntryTile>::iterator nextEntry =
|
const std::map<std::pair<int, int>, TunnelEntryTile>::iterator nextEntry =
|
||||||
m_tunnelEntries.find(key(next));
|
m_tunnelEntries.find(key(next));
|
||||||
if (nextEntry != m_tunnelEntries.end() && !nextEntry->second.back)
|
if (nextEntry != m_tunnelEntries.end()
|
||||||
|
&& nextEntry->second.itemSlots.size() < 4)
|
||||||
{
|
{
|
||||||
if (!nextEntry->second.front)
|
nextEntry->second.itemSlots.push_back(
|
||||||
{
|
BeltItemSlot{bt.itemSlots.front().item, 0.0});
|
||||||
nextEntry->second.front = BeltItemSlot{bt.front->item, 0.0};
|
bt.itemSlots.erase(bt.itemSlots.begin());
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nextEntry->second.back = BeltItemSlot{bt.front->item, 0.0};
|
|
||||||
}
|
|
||||||
bt.front = bt.back;
|
|
||||||
bt.back = std::nullopt;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -663,17 +641,16 @@ void BeltSystem::moveItemsToNextTile()
|
|||||||
it != m_tunnelExits.end(); ++it)
|
it != m_tunnelExits.end(); ++it)
|
||||||
{
|
{
|
||||||
TunnelExitTile& tx = it->second;
|
TunnelExitTile& tx = it->second;
|
||||||
if (!tx.front || tx.front->progress < 1.0)
|
if (tx.itemSlots.empty() || tx.itemSlots.front().progress < 1.0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QPoint here = QPoint(it->first.first, it->first.second);
|
const QPoint here = QPoint(it->first.first, it->first.second);
|
||||||
const QPoint next = adjacentTile(here, tx.direction);
|
const QPoint next = adjacentTile(here, tx.direction);
|
||||||
if (tryPushToTile(next, tx.front->item, tx.direction))
|
if (tryPushToTile(next, tx.itemSlots.front().item, tx.direction))
|
||||||
{
|
{
|
||||||
tx.front = tx.back;
|
tx.itemSlots.erase(tx.itemSlots.begin());
|
||||||
tx.back = std::nullopt;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -688,23 +665,22 @@ void BeltSystem::moveTunnelItems()
|
|||||||
if (teIt != m_tunnelEntries.end())
|
if (teIt != m_tunnelEntries.end())
|
||||||
{
|
{
|
||||||
TunnelEntryTile& te = teIt->second;
|
TunnelEntryTile& te = teIt->second;
|
||||||
if (te.front && te.front->progress >= 1.0)
|
if (!te.itemSlots.empty() && te.itemSlots.front().progress >= 1.0)
|
||||||
{
|
{
|
||||||
const bool canEnter = link.items.empty()
|
const bool canEnter = link.items.empty()
|
||||||
|| link.items.back().progress >= 0.5;
|
|| link.items.back().progress >= 0.25;
|
||||||
if (canEnter)
|
if (canEnter)
|
||||||
{
|
{
|
||||||
TunnelTransitItem ti;
|
TunnelTransitItem ti;
|
||||||
ti.item = te.front->item;
|
ti.item = te.itemSlots.front().item;
|
||||||
ti.progress = 0.0;
|
ti.progress = 0.0;
|
||||||
link.items.push_back(ti);
|
link.items.push_back(ti);
|
||||||
te.front = te.back;
|
te.itemSlots.erase(te.itemSlots.begin());
|
||||||
te.back = std::nullopt;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transit front → exit back
|
// Transit front → exit
|
||||||
if (!link.items.empty() && link.items.front().progress >= link.length)
|
if (!link.items.empty() && link.items.front().progress >= link.length)
|
||||||
{
|
{
|
||||||
const std::map<std::pair<int, int>, TunnelExitTile>::iterator txIt =
|
const std::map<std::pair<int, int>, TunnelExitTile>::iterator txIt =
|
||||||
@@ -712,14 +688,9 @@ void BeltSystem::moveTunnelItems()
|
|||||||
if (txIt != m_tunnelExits.end())
|
if (txIt != m_tunnelExits.end())
|
||||||
{
|
{
|
||||||
TunnelExitTile& tx = txIt->second;
|
TunnelExitTile& tx = txIt->second;
|
||||||
if (!tx.back && !tx.front)
|
if (tx.itemSlots.size() < 4)
|
||||||
{
|
{
|
||||||
tx.front = BeltItemSlot{link.items.front().item, 0.0};
|
tx.itemSlots.push_back(BeltItemSlot{link.items.front().item, 0.0});
|
||||||
link.items.erase(link.items.begin());
|
|
||||||
}
|
|
||||||
else if (!tx.back && tx.front)
|
|
||||||
{
|
|
||||||
tx.back = BeltItemSlot{link.items.front().item, 0.0};
|
|
||||||
link.items.erase(link.items.begin());
|
link.items.erase(link.items.begin());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -733,24 +704,26 @@ void BeltSystem::routeSplitterItems()
|
|||||||
it != m_splitters.end(); ++it)
|
it != m_splitters.end(); ++it)
|
||||||
{
|
{
|
||||||
SplitterTile& st = it->second;
|
SplitterTile& st = it->second;
|
||||||
if (!st.back || st.back->progress < 0.5)
|
if (st.back.empty() || st.back.front().progress < 0.5)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Item& item = st.back->item;
|
const Item& item = st.back.front().item;
|
||||||
|
|
||||||
const bool matchesA = st.filterA.empty() ||
|
const bool matchesA = st.filterA.empty() ||
|
||||||
std::find(st.filterA.begin(), st.filterA.end(), item.type) != st.filterA.end();
|
std::find(st.filterA.begin(), st.filterA.end(), item.type) != st.filterA.end();
|
||||||
const bool matchesB = st.filterB.empty() ||
|
const bool matchesB = st.filterB.empty() ||
|
||||||
std::find(st.filterB.begin(), st.filterB.end(), item.type) != st.filterB.end();
|
std::find(st.filterB.begin(), st.filterB.end(), item.type) != st.filterB.end();
|
||||||
|
|
||||||
|
bool routed = false;
|
||||||
|
|
||||||
if (matchesA && !matchesB)
|
if (matchesA && !matchesB)
|
||||||
{
|
{
|
||||||
if (!st.frontA)
|
if (!st.frontA)
|
||||||
{
|
{
|
||||||
st.frontA = BeltItemSlot{item, 0.0};
|
st.frontA = BeltItemSlot{item, 0.0};
|
||||||
st.back = std::nullopt;
|
routed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (matchesB && !matchesA)
|
else if (matchesB && !matchesA)
|
||||||
@@ -758,7 +731,7 @@ void BeltSystem::routeSplitterItems()
|
|||||||
if (!st.frontB)
|
if (!st.frontB)
|
||||||
{
|
{
|
||||||
st.frontB = BeltItemSlot{item, 0.0};
|
st.frontB = BeltItemSlot{item, 0.0};
|
||||||
st.back = std::nullopt;
|
routed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (matchesA && matchesB)
|
else if (matchesA && matchesB)
|
||||||
@@ -769,30 +742,36 @@ void BeltSystem::routeSplitterItems()
|
|||||||
if (preferA && !st.frontA)
|
if (preferA && !st.frontA)
|
||||||
{
|
{
|
||||||
st.frontA = BeltItemSlot{item, 0.0};
|
st.frontA = BeltItemSlot{item, 0.0};
|
||||||
st.back = std::nullopt;
|
|
||||||
st.nextOutputIsA = false;
|
st.nextOutputIsA = false;
|
||||||
|
routed = true;
|
||||||
}
|
}
|
||||||
else if (!preferA && !st.frontB)
|
else if (!preferA && !st.frontB)
|
||||||
{
|
{
|
||||||
st.frontB = BeltItemSlot{item, 0.0};
|
st.frontB = BeltItemSlot{item, 0.0};
|
||||||
st.back = std::nullopt;
|
|
||||||
st.nextOutputIsA = true;
|
st.nextOutputIsA = true;
|
||||||
|
routed = true;
|
||||||
}
|
}
|
||||||
else if (preferA && !st.frontB)
|
else if (preferA && !st.frontB)
|
||||||
{
|
{
|
||||||
// Preferred (A) is full — fall back to B; nextOutputIsA stays.
|
// Preferred (A) is full — fall back to B; nextOutputIsA stays.
|
||||||
st.frontB = BeltItemSlot{item, 0.0};
|
st.frontB = BeltItemSlot{item, 0.0};
|
||||||
st.back = std::nullopt;
|
routed = true;
|
||||||
}
|
}
|
||||||
else if (!preferA && !st.frontA)
|
else if (!preferA && !st.frontA)
|
||||||
{
|
{
|
||||||
// Preferred (B) is full — fall back to A; nextOutputIsA stays.
|
// Preferred (B) is full — fall back to A; nextOutputIsA stays.
|
||||||
st.frontA = BeltItemSlot{item, 0.0};
|
st.frontA = BeltItemSlot{item, 0.0};
|
||||||
st.back = std::nullopt;
|
routed = true;
|
||||||
}
|
}
|
||||||
// else both fronts occupied — back stays.
|
// else both fronts occupied — back stays.
|
||||||
}
|
}
|
||||||
// else (!matchesA && !matchesB): stall — back stays.
|
// else (!matchesA && !matchesB): stall — back stays.
|
||||||
|
|
||||||
|
if (routed)
|
||||||
|
{
|
||||||
|
st.back.erase(st.back.begin());
|
||||||
|
st.backDir.erase(st.backDir.begin());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -805,24 +784,12 @@ bool BeltSystem::tryPlaceOnBelt(QPoint tile, Item item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
BeltTile& bt = it->second;
|
BeltTile& bt = it->second;
|
||||||
|
if (bt.itemSlots.size() < 4)
|
||||||
if (!bt.front)
|
|
||||||
{
|
{
|
||||||
bt.front = BeltItemSlot{item, 0.0};
|
bt.itemSlots.push_back(BeltItemSlot{item, 0.0});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!bt.back)
|
return false; // all slots occupied
|
||||||
{
|
|
||||||
bt.back = BeltItemSlot{item, 0.0};
|
|
||||||
|
|
||||||
// Ensure ordering invariant: front has higher progress.
|
|
||||||
if (bt.back->progress > bt.front->progress)
|
|
||||||
{
|
|
||||||
std::swap(bt.front, bt.back);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false; // both slots occupied
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BeltSystem::tryPushToTile(QPoint dest, Item item, Rotation fromDir)
|
bool BeltSystem::tryPushToTile(QPoint dest, Item item, Rotation fromDir)
|
||||||
@@ -836,10 +803,10 @@ bool BeltSystem::tryPushToTile(QPoint dest, Item item, Rotation fromDir)
|
|||||||
m_splitters.find(key(dest));
|
m_splitters.find(key(dest));
|
||||||
if (splIt != m_splitters.end())
|
if (splIt != m_splitters.end())
|
||||||
{
|
{
|
||||||
if (!splIt->second.back)
|
if (splIt->second.back.size() < 2)
|
||||||
{
|
{
|
||||||
splIt->second.back = BeltItemSlot{item, 0.0};
|
splIt->second.back.push_back(BeltItemSlot{item, 0.0});
|
||||||
splIt->second.backDir = fromDir;
|
splIt->second.backDir.push_back(fromDir);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -849,15 +816,9 @@ bool BeltSystem::tryPushToTile(QPoint dest, Item item, Rotation fromDir)
|
|||||||
m_tunnelEntries.find(key(dest));
|
m_tunnelEntries.find(key(dest));
|
||||||
if (teIt != m_tunnelEntries.end())
|
if (teIt != m_tunnelEntries.end())
|
||||||
{
|
{
|
||||||
TunnelEntryTile& te = teIt->second;
|
if (teIt->second.itemSlots.size() < 4)
|
||||||
if (!te.front)
|
|
||||||
{
|
{
|
||||||
te.front = BeltItemSlot{item, 0.0};
|
teIt->second.itemSlots.push_back(BeltItemSlot{item, 0.0});
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!te.back)
|
|
||||||
{
|
|
||||||
te.back = BeltItemSlot{item, 0.0};
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -867,15 +828,9 @@ bool BeltSystem::tryPushToTile(QPoint dest, Item item, Rotation fromDir)
|
|||||||
m_tunnelExits.find(key(dest));
|
m_tunnelExits.find(key(dest));
|
||||||
if (txIt != m_tunnelExits.end())
|
if (txIt != m_tunnelExits.end())
|
||||||
{
|
{
|
||||||
TunnelExitTile& tx = txIt->second;
|
if (txIt->second.itemSlots.size() < 4)
|
||||||
if (!tx.front)
|
|
||||||
{
|
{
|
||||||
tx.front = BeltItemSlot{item, 0.0};
|
txIt->second.itemSlots.push_back(BeltItemSlot{item, 0.0});
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!tx.back)
|
|
||||||
{
|
|
||||||
tx.back = BeltItemSlot{item, 0.0};
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -901,19 +856,12 @@ void BeltSystem::forEachVisualItem(QRect viewportTiles,
|
|||||||
|
|
||||||
const BeltTile& bt = entry.second;
|
const BeltTile& bt = entry.second;
|
||||||
|
|
||||||
if (bt.front)
|
// Render least-progressed first (bottom) → most-progressed last (top).
|
||||||
|
for (int i = static_cast<int>(bt.itemSlots.size()) - 1; i >= 0; --i)
|
||||||
{
|
{
|
||||||
VisualItem vi;
|
VisualItem vi;
|
||||||
vi.type = bt.front->item.type;
|
vi.type = bt.itemSlots[i].item.type;
|
||||||
vi.worldPos = slotWorldPos(tile, bt.direction, bt.front->progress);
|
vi.worldPos = slotWorldPos(tile, bt.direction, bt.itemSlots[i].progress);
|
||||||
visit(vi);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bt.back)
|
|
||||||
{
|
|
||||||
VisualItem vi;
|
|
||||||
vi.type = bt.back->item.type;
|
|
||||||
vi.worldPos = slotWorldPos(tile, bt.direction, bt.back->progress);
|
|
||||||
visit(vi);
|
visit(vi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -928,28 +876,51 @@ void BeltSystem::forEachVisualItem(QRect viewportTiles,
|
|||||||
|
|
||||||
const SplitterTile& st = entry.second;
|
const SplitterTile& st = entry.second;
|
||||||
|
|
||||||
if (st.back)
|
// Unassigned items: least-progressed first (bottom), then higher-progressed (top).
|
||||||
|
for (int i = static_cast<int>(st.back.size()) - 1; i >= 0; --i)
|
||||||
{
|
{
|
||||||
VisualItem vi;
|
VisualItem vi;
|
||||||
vi.type = st.back->item.type;
|
vi.type = st.back[i].item.type;
|
||||||
vi.worldPos = slotWorldPos(tile, st.backDir, st.back->progress);
|
vi.worldPos = slotWorldPos(tile, st.backDir[i], st.back[i].progress);
|
||||||
visit(vi);
|
visit(vi);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st.frontA)
|
// Output-slot items rendered on top of unassigned, in clockwise order from East.
|
||||||
|
// East=0, South=1, West=2, North=3 — lower rank rendered first (bottom).
|
||||||
|
auto clockwiseRank = [](Rotation r) -> int
|
||||||
{
|
{
|
||||||
VisualItem vi;
|
switch (r)
|
||||||
vi.type = st.frontA->item.type;
|
{
|
||||||
vi.worldPos = slotWorldPos(tile, st.outputA, st.frontA->progress);
|
case Rotation::East: return 0;
|
||||||
visit(vi);
|
case Rotation::South: return 1;
|
||||||
}
|
case Rotation::West: return 2;
|
||||||
|
case Rotation::North: return 3;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
if (st.frontB)
|
const bool aBeforeB = clockwiseRank(st.outputA) <= clockwiseRank(st.outputB);
|
||||||
|
|
||||||
|
auto renderFront = [&](const std::optional<BeltItemSlot>& slot, Rotation dir)
|
||||||
{
|
{
|
||||||
VisualItem vi;
|
if (slot)
|
||||||
vi.type = st.frontB->item.type;
|
{
|
||||||
vi.worldPos = slotWorldPos(tile, st.outputB, st.frontB->progress);
|
VisualItem vi;
|
||||||
visit(vi);
|
vi.type = slot->item.type;
|
||||||
|
vi.worldPos = slotWorldPos(tile, dir, slot->progress);
|
||||||
|
visit(vi);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (aBeforeB)
|
||||||
|
{
|
||||||
|
renderFront(st.frontA, st.outputA);
|
||||||
|
renderFront(st.frontB, st.outputB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
renderFront(st.frontB, st.outputB);
|
||||||
|
renderFront(st.frontA, st.outputA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -962,18 +933,11 @@ void BeltSystem::forEachVisualItem(QRect viewportTiles,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const TunnelEntryTile& te = entry.second;
|
const TunnelEntryTile& te = entry.second;
|
||||||
if (te.front)
|
for (int i = static_cast<int>(te.itemSlots.size()) - 1; i >= 0; --i)
|
||||||
{
|
{
|
||||||
VisualItem vi;
|
VisualItem vi;
|
||||||
vi.type = te.front->item.type;
|
vi.type = te.itemSlots[i].item.type;
|
||||||
vi.worldPos = slotWorldPos(tile, te.direction, te.front->progress);
|
vi.worldPos = slotWorldPos(tile, te.direction, te.itemSlots[i].progress);
|
||||||
visit(vi);
|
|
||||||
}
|
|
||||||
if (te.back)
|
|
||||||
{
|
|
||||||
VisualItem vi;
|
|
||||||
vi.type = te.back->item.type;
|
|
||||||
vi.worldPos = slotWorldPos(tile, te.direction, te.back->progress);
|
|
||||||
visit(vi);
|
visit(vi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -987,18 +951,11 @@ void BeltSystem::forEachVisualItem(QRect viewportTiles,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const TunnelExitTile& tx = entry.second;
|
const TunnelExitTile& tx = entry.second;
|
||||||
if (tx.front)
|
for (int i = static_cast<int>(tx.itemSlots.size()) - 1; i >= 0; --i)
|
||||||
{
|
{
|
||||||
VisualItem vi;
|
VisualItem vi;
|
||||||
vi.type = tx.front->item.type;
|
vi.type = tx.itemSlots[i].item.type;
|
||||||
vi.worldPos = slotWorldPos(tile, tx.direction, tx.front->progress);
|
vi.worldPos = slotWorldPos(tile, tx.direction, tx.itemSlots[i].progress);
|
||||||
visit(vi);
|
|
||||||
}
|
|
||||||
if (tx.back)
|
|
||||||
{
|
|
||||||
VisualItem vi;
|
|
||||||
vi.type = tx.back->item.type;
|
|
||||||
vi.worldPos = slotWorldPos(tile, tx.direction, tx.back->progress);
|
|
||||||
visit(vi);
|
visit(vi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,8 +123,8 @@ private:
|
|||||||
struct BeltTile
|
struct BeltTile
|
||||||
{
|
{
|
||||||
Rotation direction;
|
Rotation direction;
|
||||||
std::optional<BeltItemSlot> front; // higher progress; closer to output
|
// front (highest progress) at index 0; back (just entered) at end. Max 4.
|
||||||
std::optional<BeltItemSlot> back; // lower progress; closer to input
|
std::vector<BeltItemSlot> itemSlots;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SplitterTile
|
struct SplitterTile
|
||||||
@@ -134,8 +134,9 @@ private:
|
|||||||
std::vector<ItemType> filterA; // empty = accept all
|
std::vector<ItemType> filterA; // empty = accept all
|
||||||
std::vector<ItemType> filterB;
|
std::vector<ItemType> filterB;
|
||||||
bool nextOutputIsA; // alternation state
|
bool nextOutputIsA; // alternation state
|
||||||
std::optional<BeltItemSlot> back; // progress [0, 0.5]; entering from input belt
|
// Unassigned items: [0] = routing candidate (higher progress, caps at 0.5). Max 2.
|
||||||
Rotation backDir; // direction of the feeding belt (for animation)
|
std::vector<BeltItemSlot> back;
|
||||||
|
std::vector<Rotation> backDir; // feeding belt direction, parallel to back
|
||||||
std::optional<BeltItemSlot> frontA; // progress [0, 1]; routed to outputA
|
std::optional<BeltItemSlot> frontA; // progress [0, 1]; routed to outputA
|
||||||
std::optional<BeltItemSlot> frontB; // progress [0, 1]; routed to outputB
|
std::optional<BeltItemSlot> frontB; // progress [0, 1]; routed to outputB
|
||||||
};
|
};
|
||||||
@@ -144,15 +145,15 @@ private:
|
|||||||
{
|
{
|
||||||
Rotation direction;
|
Rotation direction;
|
||||||
int maxDistance;
|
int maxDistance;
|
||||||
std::optional<BeltItemSlot> front;
|
// front (highest progress) at index 0; back at end. Max 4.
|
||||||
std::optional<BeltItemSlot> back;
|
std::vector<BeltItemSlot> itemSlots;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TunnelExitTile
|
struct TunnelExitTile
|
||||||
{
|
{
|
||||||
Rotation direction;
|
Rotation direction;
|
||||||
std::optional<BeltItemSlot> front;
|
// front (highest progress) at index 0; back at end. Max 4.
|
||||||
std::optional<BeltItemSlot> back;
|
std::vector<BeltItemSlot> itemSlots;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TunnelTransitItem
|
struct TunnelTransitItem
|
||||||
|
|||||||
@@ -66,17 +66,19 @@ TEST_CASE("BeltSystem: tryPutItem fails after removeTile", "[belt]")
|
|||||||
// Capacity
|
// Capacity
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
TEST_CASE("BeltSystem: two items fit in one tile", "[belt]")
|
TEST_CASE("BeltSystem: four items fit in one tile", "[belt]")
|
||||||
{
|
{
|
||||||
BeltSystem bs(kFastBeltSpeed);
|
BeltSystem bs(kFastBeltSpeed);
|
||||||
const QPoint tile(0, 0);
|
const QPoint tile(0, 0);
|
||||||
bs.placeBelt(tile, Rotation::East);
|
bs.placeBelt(tile, Rotation::East);
|
||||||
|
|
||||||
REQUIRE(bs.tryPutItem(tile, makeItem("iron_ore")));
|
REQUIRE(bs.tryPutItem(tile, makeItem("a")));
|
||||||
REQUIRE(bs.tryPutItem(tile, makeItem("copper_ore")));
|
REQUIRE(bs.tryPutItem(tile, makeItem("b")));
|
||||||
|
REQUIRE(bs.tryPutItem(tile, makeItem("c")));
|
||||||
|
REQUIRE(bs.tryPutItem(tile, makeItem("d")));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("BeltSystem: third tryPutItem on full tile returns false", "[belt]")
|
TEST_CASE("BeltSystem: fifth tryPutItem on full tile returns false", "[belt]")
|
||||||
{
|
{
|
||||||
BeltSystem bs(kFastBeltSpeed);
|
BeltSystem bs(kFastBeltSpeed);
|
||||||
const QPoint tile(0, 0);
|
const QPoint tile(0, 0);
|
||||||
@@ -84,8 +86,10 @@ TEST_CASE("BeltSystem: third tryPutItem on full tile returns false", "[belt]")
|
|||||||
|
|
||||||
bs.tryPutItem(tile, makeItem("a"));
|
bs.tryPutItem(tile, makeItem("a"));
|
||||||
bs.tryPutItem(tile, makeItem("b"));
|
bs.tryPutItem(tile, makeItem("b"));
|
||||||
|
bs.tryPutItem(tile, makeItem("c"));
|
||||||
|
bs.tryPutItem(tile, makeItem("d"));
|
||||||
|
|
||||||
REQUIRE_FALSE(bs.tryPutItem(tile, makeItem("c")));
|
REQUIRE_FALSE(bs.tryPutItem(tile, makeItem("e")));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -217,6 +221,8 @@ TEST_CASE("BeltSystem: item stays blocked when next tile is full", "[belt]")
|
|||||||
// Fill tileB to capacity.
|
// Fill tileB to capacity.
|
||||||
bs.tryPutItem(tileB, makeItem("b1"));
|
bs.tryPutItem(tileB, makeItem("b1"));
|
||||||
bs.tryPutItem(tileB, makeItem("b2"));
|
bs.tryPutItem(tileB, makeItem("b2"));
|
||||||
|
bs.tryPutItem(tileB, makeItem("b3"));
|
||||||
|
bs.tryPutItem(tileB, makeItem("b4"));
|
||||||
|
|
||||||
// Place item in tileA — should be blocked.
|
// Place item in tileA — should be blocked.
|
||||||
bs.tryPutItem(tileA, makeItem("a1"));
|
bs.tryPutItem(tileA, makeItem("a1"));
|
||||||
@@ -226,11 +232,11 @@ TEST_CASE("BeltSystem: item stays blocked when next tile is full", "[belt]")
|
|||||||
REQUIRE(bs.tryTakeItem(eastPort(tileA)).has_value());
|
REQUIRE(bs.tryTakeItem(eastPort(tileA)).has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("BeltSystem: belt back slot is capped at progress 0.5", "[belt]")
|
TEST_CASE("BeltSystem: belt second slot is capped at progress 0.75", "[belt]")
|
||||||
{
|
{
|
||||||
// Use progress/tick = 0.4 so the cap is observable: without it, back would
|
// Use progress/tick = 0.4 so the cap is observable: without it, slot[1] would
|
||||||
// advance to 0.8 while front is stuck at 1.0, and then need only 1 more tick
|
// advance to 0.8 while slot[0] is stuck at 1.0. With the 0.75 cap it stays
|
||||||
// after being promoted. With the cap it stays at 0.5 and needs 2 more ticks.
|
// at 0.75 and needs exactly 1 more tick after promotion.
|
||||||
const double medBeltSpeed = 0.4 * static_cast<double>(kTickRateHz);
|
const double medBeltSpeed = 0.4 * static_cast<double>(kTickRateHz);
|
||||||
BeltSystem bs(medBeltSpeed);
|
BeltSystem bs(medBeltSpeed);
|
||||||
|
|
||||||
@@ -239,21 +245,18 @@ TEST_CASE("BeltSystem: belt back slot is capped at progress 0.5", "[belt]")
|
|||||||
|
|
||||||
// Advance front item to the output edge; it stays there (no next tile).
|
// Advance front item to the output edge; it stays there (no next tile).
|
||||||
bs.tryPutItem(tile, makeItem("front_item"));
|
bs.tryPutItem(tile, makeItem("front_item"));
|
||||||
bs.tick(); // front: 0.4
|
bs.tick(); // slot[0]: 0.4
|
||||||
bs.tick(); // front: 0.8
|
bs.tick(); // slot[0]: 0.8
|
||||||
bs.tick(); // front: 1.0 (capped, stuck)
|
bs.tick(); // slot[0]: 1.0 (capped, stuck)
|
||||||
|
|
||||||
// Place back item; front is at 1.0 and not blocking (back < 1.0).
|
// Place second item; slot[0] is at 1.0.
|
||||||
bs.tryPutItem(tile, makeItem("back_item"));
|
bs.tryPutItem(tile, makeItem("back_item"));
|
||||||
bs.tick(); // back: 0.4
|
bs.tick(); // slot[1]: 0.4
|
||||||
bs.tick(); // back would reach 0.8 — must be capped at 0.5
|
bs.tick(); // slot[1] would reach 0.8 — capped at 0.75
|
||||||
|
|
||||||
// Remove front; back (now promoted to front) must be at 0.5, not 0.8.
|
// Remove front; slot[1] (now promoted to slot[0]) must be at 0.75.
|
||||||
REQUIRE(bs.tryTakeItem(eastPort(tile)).has_value());
|
REQUIRE(bs.tryTakeItem(eastPort(tile)).has_value());
|
||||||
// At 0.4/tick, 0.5 → 0.9 after one tick — not at 1.0 yet.
|
// At 0.4/tick, 0.75 → 1.0 (capped) after one tick — available.
|
||||||
bs.tick();
|
|
||||||
REQUIRE_FALSE(bs.tryTakeItem(eastPort(tile)).has_value());
|
|
||||||
// 0.9 → 1.0 after a second tick — now available.
|
|
||||||
bs.tick();
|
bs.tick();
|
||||||
REQUIRE(bs.tryTakeItem(eastPort(tile)).has_value());
|
REQUIRE(bs.tryTakeItem(eastPort(tile)).has_value());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user