From dbf9f815453fefd5ae26a51f9f7731c7d84449ad Mon Sep 17 00:00:00 2001 From: DualFroz Date: Wed, 9 Sep 2026 18:27:18 +0200 Subject: [PATCH] feat: add shiftClick and hotbarSwap to SlotAction --- core/src/SlotAction.cpp | 152 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/core/src/SlotAction.cpp b/core/src/SlotAction.cpp index dad767d..cb6c454 100644 --- a/core/src/SlotAction.cpp +++ b/core/src/SlotAction.cpp @@ -151,3 +151,155 @@ SlotActionResult rightClick(ContainerMenu& menu, CursorStack& cursor, const Slot int index = action.slotIndex; if (!menu.validIndex(index)) return out; + if (cursor.empty()) { + if (menu.stackAt(index).empty()) return out; + int half = (menu.stackAt(index).count + 1) / 2; + MetaStack taken = takeFromSlot(menu, index, half, out); + if (taken.empty()) return out; + out.moved = taken.count; + cursor.held = taken; + out.cursorChanged = true; + out.applied = true; + return out; + } + + if (isResultSlot(menu, index)) return out; + + MetaStack single = splitOff(cursor.held, 1); + int moved = putIntoSlot(menu, index, single); + if (moved == 0) { + transferAll(single, cursor.held); + return out; + } + out.moved = moved; + out.cursorChanged = true; + out.applied = true; + return out; +} + +SlotActionResult shiftClick(ContainerMenu& menu, const SlotAction& action) { + SlotActionResult out; + int index = action.slotIndex; + if (!menu.validIndex(index) || menu.stackAt(index).empty()) return out; + + if (isResultSlot(menu, index)) { + CraftingView view = menu.crafting(); + int rounds = view.craftAll(view.maxCrafts()); + if (rounds <= 0) return out; + out.craftedResult = true; + out.craftedCount = rounds; + out.applied = true; + return out; + } + + std::vector targets = transferTargetsFor(menu, index); + MetaStack moving = menu.slot(index).cell.takeAll(); + int moved = menu.distributeInto(targets, moving); + if (!moving.empty()) { + // Whatever did not fit goes straight back where it came from. + menu.slot(index).cell.insert(moving); + } + touchCraftInput(menu, index); + if (moved == 0) return out; + out.moved = moved; + out.applied = true; + return out; +} + +SlotActionResult hotbarSwap(ContainerMenu& menu, const SlotAction& action) { + SlotActionResult out; + int index = action.slotIndex; + const MenuLayout& layout = menu.layout(); + if (!menu.validIndex(index) || layout.hotbarFirst < 0) return out; + if (action.hotbarButton < 0 || action.hotbarButton >= layout.hotbarCount) return out; + + int hotbarIndex = layout.hotbarFirst + action.hotbarButton; + if (hotbarIndex == index) return out; + + if (isResultSlot(menu, index)) { + if (!menu.stackAt(hotbarIndex).empty()) return out; + MetaStack crafted = takeFromSlot(menu, index, menu.stackAt(index).count, out); + if (crafted.empty()) return out; + out.moved = crafted.count; + menu.slot(hotbarIndex).cell.stack = crafted; + out.applied = true; + return out; + } + + MenuSlot& source = menu.slot(index); + MenuSlot& hotbar = menu.slot(hotbarIndex); + if (source.takeOnly) return out; + if (source.cell.stack.empty() && hotbar.cell.stack.empty()) return out; + if (!hotbar.cell.stack.empty()) { + if (!menu.canPlace(index, hotbar.cell.stack)) return out; + if (source.cell.limitFor(hotbar.cell.stack) < hotbar.cell.stack.count) return out; + } + + out.moved = source.cell.stack.count + hotbar.cell.stack.count; + MetaStack carried = source.cell.stack; + source.cell.stack = hotbar.cell.stack; + hotbar.cell.stack = carried; + touchCraftInput(menu, index); + out.applied = true; + return out; +} + +SlotActionResult middleClick(ContainerMenu& menu, CursorStack& cursor, const SlotAction& action) { + SlotActionResult out; + int index = action.slotIndex; + if (!menu.validIndex(index) || !menu.creativeMode()) return out; + if (!cursor.empty() || menu.stackAt(index).empty()) return out; + + MetaStack clone = menu.stackAt(index); + clone.count = clone.maxCount(); + out.created = clone.count; + cursor.held = clone; + out.cursorChanged = true; + out.applied = true; + return out; +} + +SlotActionResult doubleClick(ContainerMenu& menu, CursorStack& cursor) { + SlotActionResult out; + if (cursor.empty() || cursor.held.room() == 0) return out; + + // Partial stacks first: a double click is meant to tidy up leftovers before + // it starts breaking apart full stacks. + for (int pass = 0; pass < 2; ++pass) { + for (int i = 0; i < menu.slotCount(); ++i) { + if (cursor.held.room() == 0) break; + MenuSlot& source = menu.slot(i); + if (source.takeOnly || source.cell.stack.empty()) continue; + if (!stacksMergeable(source.cell.stack, cursor.held)) continue; + bool partial = source.cell.stack.count < source.cell.stack.maxCount(); + if ((pass == 0) != partial) continue; + int before = cursor.held.count; + transferAll(source.cell.stack, cursor.held); + int gained = cursor.held.count - before; + if (gained > 0) { + out.moved += gained; + touchCraftInput(menu, i); + } + } + } + if (out.moved == 0) return out; + out.cursorChanged = true; + out.applied = true; + return out; +} + +SlotActionResult dragStart(ContainerMenu& menu, CursorStack& cursor, DragState& drag, + const SlotAction& action, bool rightButton) { + SlotActionResult out; + if (cursor.empty()) return out; + drag.reset(); + drag.active = true; + drag.rightButton = rightButton; + drag.payload = cursor.held; + if (menu.validIndex(action.slotIndex) && menu.canPlace(action.slotIndex, cursor.held)) { + drag.paintedSlots.push_back(action.slotIndex); + } + out.applied = true; + return out; +} +