Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/frontend/StarInventory.cpp
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
commit6352e8e3196f78388b6c771073f9e03eaa612673 (patch)
treee23772f79a7fbc41bc9108951e9e136857484bf4 /source/frontend/StarInventory.cpp
parent6741a057e5639280d85d0f88ba26f000baa58f61 (diff)
everything everywhere
all at once
Diffstat (limited to 'source/frontend/StarInventory.cpp')
-rw-r--r--source/frontend/StarInventory.cpp426
1 files changed, 426 insertions, 0 deletions
diff --git a/source/frontend/StarInventory.cpp b/source/frontend/StarInventory.cpp
new file mode 100644
index 0000000..72d91e6
--- /dev/null
+++ b/source/frontend/StarInventory.cpp
@@ -0,0 +1,426 @@
+#include "StarInventory.hpp"
+#include "StarGuiReader.hpp"
+#include "StarItemTooltip.hpp"
+#include "StarSimpleTooltip.hpp"
+#include "StarRoot.hpp"
+#include "StarUniverseClient.hpp"
+#include "StarItemGridWidget.hpp"
+#include "StarButtonWidget.hpp"
+#include "StarPortraitWidget.hpp"
+#include "StarPaneManager.hpp"
+#include "StarLabelWidget.hpp"
+#include "StarImageWidget.hpp"
+#include "StarPlayerInventory.hpp"
+#include "StarPlayerCompanions.hpp"
+#include "StarWorldClient.hpp"
+#include "StarAssets.hpp"
+#include "StarItem.hpp"
+#include "StarMainInterface.hpp"
+#include "StarMerchantInterface.hpp"
+#include "StarJsonExtra.hpp"
+#include "StarStatistics.hpp"
+#include "StarAugmentItem.hpp"
+
+namespace Star {
+
+InventoryPane::InventoryPane(MainInterface* parent, PlayerPtr player, ContainerInteractorPtr containerInteractor) {
+ m_parent = parent;
+ m_player = move(player);
+ m_containerInteractor = move(containerInteractor);
+
+ GuiReader invWindowReader;
+ auto config = Root::singleton().assets()->json("/interface/windowconfig/playerinventory.config");
+
+ auto leftClickCallback = [this](String const& bagType, Widget* widget) {
+ auto itemGrid = convert<ItemGridWidget>(widget);
+ InventorySlot inventorySlot = BagSlot(bagType, itemGrid->selectedIndex());
+
+ if (context()->shiftHeld()) {
+ if (auto sourceItem = itemGrid->selectedItem()) {
+ if (auto activeMerchantPane = m_parent->activeMerchantPane()) {
+ auto remainder = activeMerchantPane->addItems(m_player->inventory()->takeSlot(inventorySlot));
+ if (remainder && !remainder->empty())
+ m_player->inventory()->setItem(inventorySlot, remainder);
+ } else if (m_containerInteractor->containerOpen()) {
+ m_player->inventory()->takeSlot(inventorySlot);
+ m_containerInteractor->addToContainer(sourceItem);
+ m_containerSource = inventorySlot;
+ m_expectingSwap = true;
+ }
+ }
+ } else {
+ m_player->inventory()->shiftSwap(inventorySlot);
+ }
+ };
+
+ auto rightClickCallback = [this](InventorySlot slot) {
+ if (ItemPtr slotItem = m_player->inventory()->itemsAt(slot)) {
+ auto swapItem = m_player->inventory()->swapSlotItem();
+ if (!swapItem || swapItem->empty() || swapItem->couldStack(slotItem)) {
+ uint64_t count = swapItem ? swapItem->couldStack(slotItem) : slotItem->maxStack();
+ if (context()->shiftHeld())
+ count = max(1, min<int>(count, slotItem->count() / 2));
+ else
+ count = 1;
+
+ if (auto taken = slotItem->take(count)) {
+ if (swapItem)
+ swapItem->stackWith(taken);
+ else
+ m_player->inventory()->setSwapSlotItem(taken);
+ }
+ } else if (auto augment = as<AugmentItem>(swapItem)) {
+ if (auto augmented = augment->applyTo(slotItem))
+ m_player->inventory()->setItem(slot, augmented);
+ }
+ }
+ };
+ auto bagGridCallback = [rightClickCallback](String const& bagType, Widget* widget) {
+ auto slot = BagSlot(bagType, convert<ItemGridWidget>(widget)->selectedIndex());
+ rightClickCallback(slot);
+ };
+
+ Json itemBagConfig = config.get("bagConfig");
+ auto bagOrder = itemBagConfig.toObject().keys().sorted([&itemBagConfig](String const& a, String const& b) {
+ return itemBagConfig.get(a).getInt("order", 0) < itemBagConfig.get(b).getInt("order", 0);
+ });
+ for (auto name : bagOrder) {
+ auto itemGrid = itemBagConfig.get(name).getString("itemGrid");
+ invWindowReader.registerCallback(itemGrid, bind(leftClickCallback, name, _1));
+ invWindowReader.registerCallback(strf("%s.right", itemGrid), bind(bagGridCallback, name, _1));
+ }
+
+ invWindowReader.registerCallback("close", [=](Widget*) {
+ dismiss();
+ });
+
+ invWindowReader.registerCallback("sort", [=](Widget*) {
+ m_player->inventory()->condenseBagStacks(m_selectedTab);
+ m_player->inventory()->sortBag(m_selectedTab);
+ // Don't show sorted items as new items
+ m_itemGrids[m_selectedTab]->updateItemState();
+ m_itemGrids[m_selectedTab]->clearChangedSlots();
+ });
+
+ invWindowReader.registerCallback("gridModeSelector", [=](Widget* widget) {
+ auto selected = convert<ButtonWidget>(widget)->data().toString();
+ selectTab(m_tabButtonData.keyOf(selected));
+ });
+
+ auto registerSlotCallbacks = [&](String name, InventorySlot slot) {
+ invWindowReader.registerCallback(name, [=](Widget* paneObj) {
+ if (as<ItemSlotWidget>(paneObj))
+ m_player->inventory()->shiftSwap(slot);
+ else
+ throw GuiException("Invalid object type, expected ItemSlotWidget");
+ });
+ invWindowReader.registerCallback(name + ".right", [=](Widget* paneObj) {
+ if (as<ItemSlotWidget>(paneObj))
+ rightClickCallback(slot);
+ else
+ throw GuiException("Invalid object type, expected ItemSlotWidget");
+ });
+ };
+
+ for (auto const p : EquipmentSlotNames)
+ registerSlotCallbacks(p.second, p.first);
+ registerSlotCallbacks("trash", TrashSlot());
+
+ invWindowReader.construct(config.get("paneLayout"), this);
+
+ m_trashSlot = fetchChild<ItemSlotWidget>("trash");
+ m_trashBurn = GameTimer(config.get("trashBurnTimeout").toFloat());
+
+ m_disabledTechOverlays.append(fetchChild<ImageWidget>("techHeadDisabled"));
+ m_disabledTechOverlays.append(fetchChild<ImageWidget>("techBodyDisabled"));
+ m_disabledTechOverlays.append(fetchChild<ImageWidget>("techLegsDisabled"));
+
+ for (auto const p : EquipmentSlotNames) {
+ if (auto itemSlot = fetchChild<ItemSlotWidget>(p.second))
+ itemSlot->setItem(m_player->inventory()->itemsAt(p.first));
+ }
+
+ for (auto name : bagOrder) {
+ auto itemTab = itemBagConfig.get(name);
+ m_itemGrids[name] = fetchChild<ItemGridWidget>(itemTab.getString("itemGrid"));
+ m_itemGrids[name]->setItemBag(m_player->inventory()->bagContents(name));
+ m_itemGrids[name]->hide();
+ m_newItemMarkers[name] = fetchChild<Widget>(itemTab.getString("newItemMarker"));
+ m_tabButtonData[name] = itemTab.getString("tabButtonData");
+ }
+ selectTab(bagOrder[0]);
+
+ auto centralPortrait = fetchChild<PortraitWidget>("portrait");
+ centralPortrait->setEntity(m_player);
+
+ auto portrait = make_shared<PortraitWidget>(m_player, PortraitMode::Bust);
+ portrait->setIconMode();
+ setTitle(portrait, m_player->name(), config.getString("subtitle"));
+
+ m_expectingSwap = false;
+
+ if (auto item = m_player->inventory()->swapSlotItem())
+ m_currentSwapSlotItem = item->descriptor();
+ m_pickUpSounds = jsonToStringList(config.get("sounds").get("pickup"));
+ m_putDownSounds = jsonToStringList(config.get("sounds").get("putdown"));
+}
+
+void InventoryPane::displayed() {
+ Pane::displayed();
+ m_expectingSwap = false;
+
+ for (auto grid : m_itemGrids)
+ grid.second->updateItemState();
+ m_itemGrids[m_selectedTab]->indicateChangedSlots();
+}
+
+PanePtr InventoryPane::createTooltip(Vec2I const& screenPosition) {
+ ItemPtr item;
+ if (auto child = getChildAt(screenPosition)) {
+ if (auto itemSlot = as<ItemSlotWidget>(child)) {
+ item = itemSlot->item();
+ if (!item) {
+ auto widgetData = itemSlot->data();
+ if (widgetData && widgetData.type() == Json::Type::Object) {
+ if (auto text = widgetData.optString("tooltipText"))
+ return SimpleTooltipBuilder::buildTooltip(*text);
+ }
+ }
+ }
+ if (auto itemGrid = as<ItemGridWidget>(child))
+ item = itemGrid->itemAt(screenPosition);
+ }
+ if (item)
+ return ItemTooltipBuilder::buildItemTooltip(item, m_player);
+
+ auto techDatabase = Root::singleton().techDatabase();
+ for (auto const& p : TechTypeNames) {
+ if (auto techIcon = fetchChild<ImageWidget>(strf("tech%s", p.second))) {
+ if (techIcon->screenBoundRect().contains(screenPosition)) {
+ if (auto techModule = m_player->techs()->equippedTechs().maybe(p.first))
+ return SimpleTooltipBuilder::buildTooltip(techDatabase->tech(*techModule).description);
+ }
+ }
+ }
+
+ return {};
+}
+
+bool InventoryPane::giveContainerResult(ContainerResult result) {
+ if (!m_expectingSwap)
+ return false;
+
+ for (auto item : result) {
+ auto inv = m_player->inventory();
+ m_player->triggerPickupEvents(item);
+
+ auto remainder = inv->stackWith(m_containerSource, item);
+ if (remainder && !remainder->empty())
+ m_player->giveItem(remainder);
+ }
+
+ m_expectingSwap = false;
+ return true;
+}
+
+void InventoryPane::updateItems() {
+ for (auto p : m_itemGrids)
+ p.second->updateItemState();
+}
+
+bool InventoryPane::containsNewItems() const {
+ for (auto p : m_itemGrids) {
+ if (p.second->slotsChanged())
+ return true;
+ }
+ return false;
+}
+
+void InventoryPane::update() {
+ auto inventory = m_player->inventory();
+ auto context = Widget::context();
+
+ HashSet<ItemPtr> customBarItems;
+ for (uint8_t i = 0; i < inventory->customBarIndexes(); ++i) {
+ if (auto primarySlot = inventory->customBarPrimarySlot(i)) {
+ if (auto primaryItem = inventory->itemsAt(*primarySlot))
+ customBarItems.add(primaryItem);
+ }
+ if (auto secondarySlot = inventory->customBarSecondarySlot(i)) {
+ if (auto secondaryItem = inventory->itemsAt(*secondarySlot))
+ customBarItems.add(secondaryItem);
+ }
+ }
+
+ m_trashSlot->setItem(inventory->itemsAt(TrashSlot()));
+ m_trashSlot->showLinkIndicator(customBarItems.contains(m_trashSlot->item()));
+ if (auto trashItem = m_trashSlot->item()) {
+ if (m_trashBurn.tick() && trashItem->count() > 0) {
+ m_player->statistics()->recordEvent("trashItem", JsonObject{
+ {"itemName", trashItem->name()},
+ {"count", trashItem->count()},
+ {"category", trashItem->category()}
+ });
+ trashItem->take(trashItem->count());
+ }
+ } else {
+ m_trashBurn.reset();
+ }
+ m_trashSlot->setProgress(m_trashBurn.timer / m_trashBurn.time);
+
+ for (auto const& p : EquipmentSlotNames) {
+ if (auto itemSlot = fetchChild<ItemSlotWidget>(p.second)) {
+ itemSlot->setItem(inventory->itemsAt(p.first));
+ itemSlot->showLinkIndicator(customBarItems.contains(itemSlot->item()));
+ }
+ }
+
+ auto techDatabase = Root::singleton().techDatabase();
+ for (auto const& p : TechTypeNames) {
+ if (auto techIcon = fetchChild<ImageWidget>(strf("tech%s", p.second))) {
+ if (auto techModule = m_player->techs()->equippedTechs().maybe(p.first))
+ techIcon->setImage(techDatabase->tech(*techModule).icon);
+ else
+ techIcon->setImage("");
+ }
+ }
+
+ if (ItemPtr swapSlot = inventory->swapSlotItem()) {
+ for (auto pair : m_itemGrids) {
+ if (pair.first != m_selectedTab && PlayerInventory::itemAllowedInBag(swapSlot, pair.first)) {
+ selectTab(pair.first);
+ break;
+ }
+ }
+ }
+
+ for (auto p : m_itemGrids) {
+ p.second->updateItemState();
+ for (size_t i = 0; i < p.second->itemSlots(); ++i) {
+ auto itemWidget = p.second->itemWidgetAt(i);
+ itemWidget->showLinkIndicator(customBarItems.contains(itemWidget->item()));
+ }
+ }
+
+ m_itemGrids[m_selectedTab]->clearChangedSlots();
+
+ for (auto pair : m_newItemMarkers) {
+ if (m_itemGrids[pair.first]->slotsChanged())
+ pair.second->show();
+ else
+ pair.second->hide();
+ }
+
+ for (auto techOverlay : m_disabledTechOverlays)
+ techOverlay->setVisibility(m_player->techOverridden());
+
+ auto healthLabel = fetchChild<LabelWidget>("healthtext");
+ healthLabel->setText(strf("%d", m_player->maxHealth()));
+ auto energyLabel = fetchChild<LabelWidget>("energytext");
+ energyLabel->setText(strf("%d", m_player->maxEnergy()));
+ auto weaponLabel = fetchChild<LabelWidget>("weapontext");
+ weaponLabel->setText(strf("%d%%", ceil(m_player->powerMultiplier() * 100)));
+ auto defenseLabel = fetchChild<LabelWidget>("defensetext");
+ if (m_player->protection() == 0)
+ defenseLabel->setText("--");
+ else
+ defenseLabel->setText(strf("%d", ceil(m_player->protection())));
+
+ auto moneyLabel = fetchChild<LabelWidget>("lblMoney");
+ moneyLabel->setText(strf("%d", m_player->currency("money")));
+
+ if (m_player->currency("essence") > 0) {
+ fetchChild<ImageWidget>("imgEssenceIcon")->show();
+ auto essenceLabel = fetchChild<LabelWidget>("lblEssence");
+ essenceLabel->show();
+ essenceLabel->setText(strf("%d", m_player->currency("essence")));
+ } else {
+ fetchChild<ImageWidget>("imgEssenceIcon")->hide();
+ fetchChild<LabelWidget>("lblEssence")->hide();
+ }
+
+ auto config = Root::singleton().assets()->json("/interface/windowconfig/playerinventory.config");
+
+ auto pets = m_player->companions()->getCompanions("pets");
+ if (pets.size() > 0) {
+ auto pet = pets.first();
+ auto companionImage = fetchChild<ImageWidget>("companionSlot");
+ companionImage->setVisibility(true);
+
+ companionImage->setDrawables(pet->portrait());
+ auto nameLabel = fetchChild<LabelWidget>("companionName");
+ if (auto name = pet->name()) {
+ nameLabel->setText(pet->name()->toUpper());
+ } else {
+ nameLabel->setText(config.getString("defaultPetNameLabel"));
+ }
+
+ auto attackLabel = fetchChild<LabelWidget>("companionAttackStat");
+ if (auto attack = pet->stat("attack")) {
+ attackLabel->setText(strf("%.0f", *attack));
+ } else {
+ attackLabel->setText("");
+ }
+
+ auto defenseLabel = fetchChild<LabelWidget>("companionDefenseStat");
+ if (auto defense = pet->stat("defense")) {
+ defenseLabel->setText(strf("%.0f", *defense));
+ } else {
+ defenseLabel->setText("");
+ }
+
+ if (containsChild("companionHealthBar")) {
+ auto healthBar = fetchChild<ProgressWidget>("companionHealthBar");
+ Maybe<float> health = pet->resource("health");
+ Maybe<float> healthMax = pet->resourceMax("health");
+ if (health && healthMax) {
+ healthBar->setCurrentProgressLevel(*health);
+ healthBar->setMaxProgressLevel(*healthMax);
+ } else {
+ healthBar->setCurrentProgressLevel(0);
+ healthBar->setMaxProgressLevel(1);
+ }
+ }
+ } else {
+ fetchChild<ImageWidget>("companionSlot")->setVisibility(false);
+
+ fetchChild<LabelWidget>("companionName")->setText(config.getString("defaultPetNameLabel"));
+
+ fetchChild<LabelWidget>("companionAttackStat")->setText("");
+ fetchChild<LabelWidget>("companionDefenseStat")->setText("");
+
+ if (containsChild("companionHealthBar")) {
+ auto healthBar = fetchChild<ProgressWidget>("companionHealthBar");
+ healthBar->setCurrentProgressLevel(0);
+ healthBar->setMaxProgressLevel(1);
+ }
+ }
+
+ if (auto item = inventory->swapSlotItem()) {
+ if (!m_currentSwapSlotItem || !item->matches(*m_currentSwapSlotItem, true) || item->count() > m_currentSwapSlotItem->count())
+ context->playAudio(RandomSource().randFrom(m_pickUpSounds));
+ else if (item->count() < m_currentSwapSlotItem->count())
+ context->playAudio(RandomSource().randFrom(m_putDownSounds));
+
+ m_currentSwapSlotItem = item->descriptor();
+ } else {
+ if (m_currentSwapSlotItem)
+ context->playAudio(RandomSource().randFrom(m_putDownSounds));
+ m_currentSwapSlotItem = {};
+ }
+}
+
+void InventoryPane::selectTab(String const& selected) {
+ for (auto grid : m_itemGrids)
+ grid.second->hide();
+ m_selectedTab = selected;
+ m_itemGrids[m_selectedTab]->show();
+ m_itemGrids[m_selectedTab]->indicateChangedSlots();
+
+ auto tabs = fetchChild<ButtonGroupWidget>("gridModeSelector");
+ for (auto button : tabs->buttons())
+ if (button->data().toString().equalsIgnoreCase(m_tabButtonData[selected]))
+ tabs->select(tabs->id(button));
+}
+
+}