#include "StarContainerInterface.hpp" #include "StarCasting.hpp" #include "StarContainerEntity.hpp" #include "StarWorldClient.hpp" #include "StarRoot.hpp" #include "StarItemTooltip.hpp" #include "StarItemGridWidget.hpp" #include "StarLabelWidget.hpp" #include "StarImageWidget.hpp" #include "StarPaneManager.hpp" #include "StarFuelWidget.hpp" #include "StarPlayer.hpp" #include "StarItemDatabase.hpp" #include "StarObject.hpp" #include "StarPlayerInventory.hpp" #include "StarConfigLuaBindings.hpp" #include "StarPlayerLuaBindings.hpp" #include "StarStatusControllerLuaBindings.hpp" #include "StarWidgetLuaBindings.hpp" #include "StarAugmentItem.hpp" namespace Star { ContainerPane::ContainerPane(WorldClientPtr worldClient, PlayerPtr player, ContainerInteractorPtr containerInteractor) { m_worldClient = worldClient; m_player = player; m_containerInteractor = std::move(containerInteractor); auto container = m_containerInteractor->openContainer(); auto guiConfig = container->containerGuiConfig(); if (auto scripts = guiConfig.opt("scripts").apply(jsonToStringList)) { if (!m_script) { m_script.emplace(); m_script->setScripts(*scripts); } m_script->addCallbacks("widget", LuaBindings::makeWidgetCallbacks(this)); m_script->addCallbacks("config", LuaBindings::makeConfigCallbacks( [guiConfig](String const& name, Json const& def) { return guiConfig.query(name, def); })); m_script->addCallbacks("player", LuaBindings::makePlayerCallbacks(m_player.get())); m_script->addCallbacks("status", LuaBindings::makeStatusControllerCallbacks(m_player->statusController())); LuaCallbacks containerPaneCallbacks; containerPaneCallbacks.registerCallback("containerEntityId", [this]() -> Maybe { return m_containerInteractor->openContainerId(); }); containerPaneCallbacks.registerCallback("playerEntityId", [this]() { return m_player->entityId(); }); containerPaneCallbacks.registerCallback("dismiss", [this]() { dismiss(); }); m_script->addCallbacks("pane", containerPaneCallbacks); m_script->setUpdateDelta(guiConfig.getUInt("scriptDelta", 1)); } auto rightClickCallback = [this](size_t index) { if (m_expectingSwap != ExpectingSwap::None) return; if (ItemPtr slotItem = m_containerInteractor->openContainer()->itemBag()->at(index)) { auto swapItem = m_player->inventory()->swapSlotItem(); if (!swapItem || swapItem->empty() || swapItem->couldStack(slotItem)) { size_t count = swapItem ? swapItem->couldStack(slotItem) : slotItem->maxStack(); if (context()->shiftHeld()) count = max(1, min(count, slotItem->count() / 2)); else count = 1; m_containerInteractor->takeFromContainerSlot(index, count); m_expectingSwap = ExpectingSwap::SwapSlotStack; } else if (is(swapItem)) { m_containerInteractor->applyAugmentInContainer(index, swapItem); m_player->inventory()->setSwapSlotItem({}); m_expectingSwap = ExpectingSwap::SwapSlot; } } }; m_reader.registerCallback("close", [this](Widget*) { dismiss(); }); m_reader.registerCallback("itemGrid", [=](Widget* paneObj) { if (auto itemGrid = as(paneObj)) swapSlot(itemGrid); else throw GuiException("Invalid object type, expected ItemGridWidget."); }); m_reader.registerCallback("itemGrid.right", [=](Widget* paneObj) { if (auto itemGrid = as(paneObj)) rightClickCallback(itemGrid->selectedIndex()); else throw GuiException("Invalid object type, expected ItemGridWidget."); }); m_reader.registerCallback("itemGrid2", [=](Widget* paneObj) { if (auto itemGrid = as(paneObj)) swapSlot(itemGrid); else throw GuiException("Invalid object type, expected ItemGridWidget."); }); m_reader.registerCallback("itemGrid2.right", [=](Widget* paneObj) { if (auto itemGrid = as(paneObj)) rightClickCallback(itemGrid->selectedIndex()); else throw GuiException("Invalid object type, expected ItemGridWidget."); }); m_reader.registerCallback("outputItemGrid", [=](Widget* paneObj) { if (auto itemGrid = as(paneObj)) swapSlot(itemGrid); else throw GuiException("Invalid object type, expected ItemGridWidget."); }); m_reader.registerCallback("outputItemGrid.right", [=](Widget* paneObj) { if (auto itemGrid = as(paneObj)) rightClickCallback(itemGrid->selectedIndex()); else throw GuiException("Invalid object type, expected ItemGridWidget."); }); m_reader.registerCallback("toggleCrafting", [=](Widget*) { toggleCrafting(); }); m_reader.registerCallback("clear", [=](Widget*) { clear(); }); m_reader.registerCallback("burn", [=](Widget*) { burn(); }); for (auto const& callbackName : jsonToStringList(guiConfig.get("scriptWidgetCallbacks", JsonArray{}))) { m_reader.registerCallback(callbackName, [this, callbackName](Widget* widget) { m_script->invoke(callbackName, widget->name(), widget->data()); }); } m_reader.construct(guiConfig.get("gui"), this); if (auto countWidget = fetchChild("count")) countWidget->setText(countWidget->text().replace("", toString(container->containerSize()))); m_itemBag = make_shared(container->containerSize()); auto items = container->containerItems(); fetchChild("itemGrid")->setItemBag(m_itemBag); if (containsChild("itemGrid2")) fetchChild("itemGrid2")->setItemBag(m_itemBag); if (containsChild("outputItemGrid")) fetchChild("outputItemGrid")->setItemBag(m_itemBag); if (container->iconItem()) { auto itemDatabase = Root::singleton().itemDatabase(); auto iconItem = itemDatabase->itemShared(container->iconItem()); auto icon = make_shared(iconItem, "/interface/inventory/portrait.png"); icon->showDurability(false); icon->showRarity(false); icon->setBackingImageAffinity(true, true); setTitle(icon, container->containerDescription(), container->containerSubTitle()); } if (containsChild("objectImage")) if (auto containerObject = as(m_containerInteractor->openContainer())) fetchChild("objectImage")->setDrawables(containerObject->cursorHintDrawables()); m_expectingSwap = ExpectingSwap::None; } void ContainerPane::displayed() { Pane::displayed(); m_expectingSwap = ExpectingSwap::None; if (m_script) { if (m_worldClient && m_worldClient->inWorld()) m_script->init(m_worldClient.get()); m_script->invoke("displayed"); } } void ContainerPane::dismissed() { Pane::dismissed(); if (m_script) { m_script->invoke("dismissed"); m_script->uninit(); } } bool ContainerPane::giveContainerResult(ContainerResult result) { if (m_expectingSwap == ExpectingSwap::None) return false; for (auto item : result) { auto inv = m_player->inventory(); m_player->triggerPickupEvents(item); if (m_expectingSwap == ExpectingSwap::SwapSlot) { m_player->clearSwap(); inv->setSwapSlotItem(item); } else if (m_expectingSwap == ExpectingSwap::SwapSlotStack) { auto swapItem = inv->swapSlotItem(); if (swapItem && swapItem->stackWith(item)) { continue; } else { inv->clearSwap(); inv->setSwapSlotItem(item); } } else { m_containerInteractor->addToContainer(inv->addItems(item)); } } m_expectingSwap = ExpectingSwap::None; return true; } PanePtr ContainerPane::createTooltip(Vec2I const& screenPosition) { ItemPtr item; if (auto child = getChildAt(screenPosition)) { if (auto itemSlot = as(child)) item = itemSlot->item(); if (auto itemGrid = as(child)) item = itemGrid->itemAt(screenPosition); } if (item) return ItemTooltipBuilder::buildItemTooltip(item, m_player); return {}; } void ContainerPane::swapSlot(ItemGridWidget* grid) { auto inv = m_player->inventory(); if (context()->shiftHeld()) { auto containerItem = grid->selectedItem(); if (containerItem && inv->itemsCanFit(containerItem) >= containerItem->count()) { m_containerInteractor->swapInContainer(grid->selectedIndex(), {}); m_expectingSwap = ExpectingSwap::Inventory; } } else { m_containerInteractor->swapInContainer(grid->selectedIndex(), inv->swapSlotItem()); inv->setSwapSlotItem({}); m_expectingSwap = ExpectingSwap::SwapSlot; } } void ContainerPane::startCrafting() { m_containerInteractor->startCraftingInContainer(); } void ContainerPane::stopCrafting() { m_containerInteractor->stopCraftingInContainer(); } void ContainerPane::toggleCrafting() { if (m_containerInteractor->openContainer()->isCrafting()) stopCrafting(); else startCrafting(); } void ContainerPane::clear() { m_containerInteractor->clearContainer(); } void ContainerPane::burn() { m_containerInteractor->burnContainer(); } void ContainerPane::update(float dt) { Pane::update(dt); if (m_script) m_script->update(m_script->updateDt(dt)); m_itemBag->clearItems(); if (!m_containerInteractor->containerOpen()) { dismiss(); } else { auto container = m_containerInteractor->openContainer(); for (size_t i = 0; i < m_itemBag->size(); ++i) m_itemBag->putItems(i, container->containerItems()[i]); if (container->isInteractive()) { if (auto itemGrid = fetchChild("itemGrid")) { itemGrid->setProgress(container->craftingProgress()); itemGrid->updateAllItemSlots(); } if (auto itemGrid = fetchChild("itemGrid2")) { itemGrid->setProgress(container->craftingProgress()); itemGrid->updateAllItemSlots(); } if (auto fuelGauge = fetchChild("fuelGauge")) { fuelGauge->setCurrentFuelLevel(m_worldClient->getProperty("ship.fuel", 0).toUInt()); fuelGauge->setMaxFuelLevel(m_worldClient->getProperty("ship.maxFuel", 0).toUInt()); float totalFuelAmount = 0; for (auto& item : container->containerItems()) { if (item) totalFuelAmount += item->instanceValue("fuelAmount", 0).toUInt() * item->count(); } fuelGauge->setPotentialFuelAmount(totalFuelAmount); fuelGauge->setRequestedFuelAmount(0); } } } } }