diff --git a/source/frontend/StarInventory.cpp b/source/frontend/StarInventory.cpp index 390558c..650d2e3 100644 --- a/source/frontend/StarInventory.cpp +++ b/source/frontend/StarInventory.cpp @@ -20,6 +20,8 @@ #include "StarJsonExtra.hpp" #include "StarStatistics.hpp" #include "StarAugmentItem.hpp" +#include "StarObjectItem.hpp" +#include "StarInteractionTypes.hpp" namespace Star { @@ -94,6 +96,27 @@ InventoryPane::InventoryPane(MainInterface* parent, PlayerPtr player, ContainerI rightClickCallback(slot); }; + auto middleClickCallback = [this](String const& bagType, Widget* widget) { + if (!m_player->inWorld()) + return; + + auto itemGrid = convert(widget); + InventorySlot inventorySlot = BagSlot(bagType, itemGrid->selectedIndex()); + auto inventory = m_player->inventory(); + if (auto sourceItem = as(itemGrid->selectedItem())) { + if (auto actionTypeName = sourceItem->instanceValue("interactAction")) { + auto actionType = InteractActionTypeNames.getLeft(actionTypeName.toString()); + if (actionType >= InteractActionType::OpenCraftingInterface && actionType <= InteractActionType::ScriptPane) { + auto actionData = sourceItem->instanceValue("interactData", Json()); + if (actionData.isType(Json::Type::Object)) + actionData = actionData.set("openWithInventory", false); + InteractAction action(actionType, m_player->entityId(), actionData); + m_player->interact(action); + } + } + } + }; + 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); @@ -102,6 +125,7 @@ InventoryPane::InventoryPane(MainInterface* parent, PlayerPtr player, ContainerI auto itemGrid = itemBagConfig.get(name).getString("itemGrid"); invWindowReader.registerCallback(itemGrid, bind(leftClickCallback, name, _1)); invWindowReader.registerCallback(strf("{}.right", itemGrid), bind(bagGridCallback, name, _1)); + invWindowReader.registerCallback(strf("{}.middle", itemGrid), bind(middleClickCallback, name, _1)); } invWindowReader.registerCallback("close", [=](Widget*) { diff --git a/source/frontend/StarMainInterface.cpp b/source/frontend/StarMainInterface.cpp index 0d0cb5f..4098705 100644 --- a/source/frontend/StarMainInterface.cpp +++ b/source/frontend/StarMainInterface.cpp @@ -199,6 +199,9 @@ bool MainInterface::escapeDialogOpen() const { void MainInterface::openCraftingWindow(Json const& config, EntityId sourceEntityId) { if (m_craftingWindow && m_paneManager.isDisplayed(m_craftingWindow)) { m_paneManager.dismissPane(m_craftingWindow); + bool fromPlayer = false; + if (auto player = m_client->mainPlayer()) + fromPlayer = player->inWorld() && player->entityId() == sourceEntityId; if (m_craftingWindow->sourceEntityId() == sourceEntityId) { m_craftingWindow.reset(); return; @@ -215,21 +218,27 @@ void MainInterface::openCraftingWindow(Json const& config, EntityId sourceEntity void MainInterface::openMerchantWindow(Json const& config, EntityId sourceEntityId) { if (m_merchantWindow && m_paneManager.isDisplayed(m_merchantWindow)) { m_paneManager.dismissPane(m_merchantWindow); - if (m_merchantWindow->sourceEntityId() == sourceEntityId) { + bool fromPlayer = false; + if (auto player = m_client->mainPlayer()) + fromPlayer = player->inWorld() && player->entityId() == sourceEntityId; + if (!fromPlayer && m_merchantWindow->sourceEntityId() == sourceEntityId) { m_merchantWindow.reset(); return; } } + bool openWithInventory = config.getBool("openWithInventory", true); m_merchantWindow = make_shared(m_client->worldClient(), m_client->mainPlayer(), config, sourceEntityId); m_paneManager.displayPane(PaneLayer::Window, m_merchantWindow, - [this](PanePtr const&) { + [this, openWithInventory](PanePtr const&) { if (auto player = m_client->mainPlayer()) player->clearSwap(); - m_paneManager.dismissRegisteredPane(MainInterfacePanes::Inventory); + if (openWithInventory) + m_paneManager.dismissRegisteredPane(MainInterfacePanes::Inventory); }); - m_paneManager.displayRegisteredPane(MainInterfacePanes::Inventory); + if (openWithInventory) + m_paneManager.displayRegisteredPane(MainInterfacePanes::Inventory); m_paneManager.bringPaneAdjacent(m_paneManager.registeredPane(MainInterfacePanes::Inventory), m_merchantWindow, Root::singleton().assets()->json("/interface.config:bringAdjacentWindowGap").toFloat()); diff --git a/source/game/StarMaterialDatabase.cpp b/source/game/StarMaterialDatabase.cpp index 6577937..6363c5d 100644 --- a/source/game/StarMaterialDatabase.cpp +++ b/source/game/StarMaterialDatabase.cpp @@ -379,7 +379,7 @@ CollisionKind MaterialDatabase::materialCollisionKind(MaterialId materialId) con } bool MaterialDatabase::canPlaceInLayer(MaterialId materialId, TileLayer layer) const { - return layer == TileLayer::Foreground || !getMaterialInfo(materialId)->foregroundOnly; + return layer != TileLayer::Background || !getMaterialInfo(materialId)->foregroundOnly; } ItemDescriptor MaterialDatabase::materialItemDrop(MaterialId materialId) const { diff --git a/source/game/StarUniverseServer.cpp b/source/game/StarUniverseServer.cpp index 37bb8b7..af80e76 100644 --- a/source/game/StarUniverseServer.cpp +++ b/source/game/StarUniverseServer.cpp @@ -1650,14 +1650,14 @@ void UniverseServer::acceptConnection(UniverseConnection connection, MaybeplayerUuid)) { if (administrator) { - doDisconnection(*clashId, String("Duplicate Uuid joined and is Administrator so has priority.")); + doDisconnection(*clashId, "Duplicate Uuid joined and is Administrator so has priority."); } else { connectionFail("Duplicate player UUID"); return; } } - if (m_clients.size() + 1 > m_maxPlayers) { + if (m_clients.size() + 1 > m_maxPlayers && !administrator) { connectionFail("Max player connections"); return; } @@ -1734,8 +1734,14 @@ void UniverseServer::acceptConnection(UniverseConnection connection, Maybe defaultReviveWarp = assets->json("/universe_server.config").optString("defaultReviveWarp"); + if (defaultReviveWarp) { + Logger::info("UniverseServer: Spawning player at default warp"); + clientWarpPlayer(clientId, parseWarpAction(*defaultReviveWarp)); + } else { + Logger::info("UniverseServer: Spawning player at ship"); + clientWarpPlayer(clientId, WarpAlias::OwnShip); + } } clientFlyShip(clientId, clientContext->shipCoordinate().location(), clientContext->shipLocation()); diff --git a/source/windowing/StarItemGridWidget.cpp b/source/windowing/StarItemGridWidget.cpp index 3302ca6..be1cc42 100644 --- a/source/windowing/StarItemGridWidget.cpp +++ b/source/windowing/StarItemGridWidget.cpp @@ -106,7 +106,9 @@ Vec2I ItemGridWidget::positionOfSlot(size_t slotNumber) { bool ItemGridWidget::sendEvent(InputEvent const& event) { if (m_visible) { if (auto mouseButton = event.ptr()) { - if (mouseButton->mouseButton == MouseButton::Left || (m_rightClickCallback && mouseButton->mouseButton == MouseButton::Right)) { + if (mouseButton->mouseButton == MouseButton::Left + || (m_rightClickCallback && mouseButton->mouseButton == MouseButton::Right) + || (m_middleClickCallback && mouseButton->mouseButton == MouseButton::Middle)) { Vec2I mousePos = *context()->mousePosition(event); for (size_t i = 0; i < (m_bag->size() - m_bagOffset) && i < unsigned(m_dimensions[0] * m_dimensions[1]); ++i) { Vec2I loc = locOfItemSlot(i); @@ -116,6 +118,8 @@ bool ItemGridWidget::sendEvent(InputEvent const& event) { m_selectedIndex = i; if (mouseButton->mouseButton == MouseButton::Right) m_rightClickCallback(this); + else if (mouseButton->mouseButton == MouseButton::Middle) + m_middleClickCallback(this); else m_callback(this); return true; @@ -145,6 +149,10 @@ void ItemGridWidget::setRightClickCallback(WidgetCallbackFunc callback) { m_rightClickCallback = callback; } +void ItemGridWidget::setMiddleClickCallback(WidgetCallbackFunc callback) { + m_middleClickCallback = callback; +} + void ItemGridWidget::setItemBag(ItemBagConstPtr bag) { m_bag = bag; diff --git a/source/windowing/StarItemGridWidget.hpp b/source/windowing/StarItemGridWidget.hpp index 79c0469..11a78b3 100644 --- a/source/windowing/StarItemGridWidget.hpp +++ b/source/windowing/StarItemGridWidget.hpp @@ -41,6 +41,7 @@ public: bool sendEvent(InputEvent const& event) override; void setCallback(WidgetCallbackFunc callback); void setRightClickCallback(WidgetCallbackFunc callback); + void setMiddleClickCallback(WidgetCallbackFunc callback); void setItemBag(ItemBagConstPtr bag); void setProgress(float progress); @@ -93,6 +94,7 @@ private: unsigned m_selectedIndex; WidgetCallbackFunc m_callback; WidgetCallbackFunc m_rightClickCallback; + WidgetCallbackFunc m_middleClickCallback; }; } diff --git a/source/windowing/StarItemSlotWidget.cpp b/source/windowing/StarItemSlotWidget.cpp index 2958957..93d95d3 100644 --- a/source/windowing/StarItemSlotWidget.cpp +++ b/source/windowing/StarItemSlotWidget.cpp @@ -67,12 +67,16 @@ void ItemSlotWidget::update(float dt) { bool ItemSlotWidget::sendEvent(InputEvent const& event) { if (m_visible) { if (auto mouseButton = event.ptr()) { - if (mouseButton->mouseButton == MouseButton::Left || (m_rightClickCallback && mouseButton->mouseButton == MouseButton::Right)) { + if (mouseButton->mouseButton == MouseButton::Left + || (m_rightClickCallback && mouseButton->mouseButton == MouseButton::Right) + || (m_middleClickCallback && mouseButton->mouseButton == MouseButton::Middle)) { Vec2I mousePos = *context()->mousePosition(event); RectI itemArea = m_itemDraggableArea.translated(screenPosition()); if (itemArea.contains(mousePos)) { if (mouseButton->mouseButton == MouseButton::Right) m_rightClickCallback(this); + else if (mouseButton->mouseButton == MouseButton::Middle) + m_middleClickCallback(this); else m_callback(this); return true; @@ -92,6 +96,10 @@ void ItemSlotWidget::setRightClickCallback(WidgetCallbackFunc callback) { m_rightClickCallback = callback; } +void ItemSlotWidget::setMiddleClickCallback(WidgetCallbackFunc callback) { + m_middleClickCallback = callback; +} + void ItemSlotWidget::setItem(ItemPtr const& item) { m_item = item; } diff --git a/source/windowing/StarItemSlotWidget.hpp b/source/windowing/StarItemSlotWidget.hpp index 9e8772d..aaa4c9c 100644 --- a/source/windowing/StarItemSlotWidget.hpp +++ b/source/windowing/StarItemSlotWidget.hpp @@ -19,6 +19,7 @@ public: bool sendEvent(InputEvent const& event) override; void setCallback(WidgetCallbackFunc callback); void setRightClickCallback(WidgetCallbackFunc callback); + void setMiddleClickCallback(WidgetCallbackFunc callback); void setItem(ItemPtr const& item); ItemPtr item() const; void setProgress(float progress); @@ -61,6 +62,7 @@ private: WidgetCallbackFunc m_callback; WidgetCallbackFunc m_rightClickCallback; + WidgetCallbackFunc m_middleClickCallback; float m_progress; ProgressWidgetPtr m_durabilityBar; diff --git a/source/windowing/StarWidgetParsing.cpp b/source/windowing/StarWidgetParsing.cpp index b45294b..7a9ea4a 100644 --- a/source/windowing/StarWidgetParsing.cpp +++ b/source/windowing/StarWidgetParsing.cpp @@ -471,23 +471,27 @@ WidgetConstructResult WidgetParser::itemSlotHandler(String const& name, Json con String backingImage = config.getString("backingImage", ""); String callback = config.getString("callback", name); - String rightClickCallback; - if (callback.equals("null")) - rightClickCallback = callback; - else - rightClickCallback = callback + ".right"; + String rightClickCallback = callback.equals("null") ? callback : callback + ".right"; rightClickCallback = config.getString("rightClickCallback", rightClickCallback); + String middleClickCallback = callback.equals("null") ? callback : callback + ".middle"; + middleClickCallback = config.getString("middleClickCallback", middleClickCallback); + auto itemSlot = make_shared(ItemPtr(), backingImage); - if (!m_callbacks.contains(callback)) - throw WidgetParserException::format("Failed to find itemSlot callback named: '{}'", callback); - itemSlot->setCallback(m_callbacks.get(callback)); + if (auto leftClickCallback = m_callbacks.ptr(callback)) + itemSlot->setCallback(*leftClickCallback); + else + throw WidgetParserException::format("Failed to find ItemSlot callback named: '{}'", callback); - if (!m_callbacks.contains(rightClickCallback)) - throw WidgetParserException::format("Failed to find itemslot rightClickCallback named: '{}'", rightClickCallback); + if (auto callback = m_callbacks.ptr(rightClickCallback)) + itemSlot->setRightClickCallback(*callback); + else + throw WidgetParserException::format("Failed to find ItemSlot rightClickCallback named: '{}'", rightClickCallback); + + if (auto callback = m_callbacks.ptr(middleClickCallback)) + itemSlot->setMiddleClickCallback(*callback); - itemSlot->setRightClickCallback(m_callbacks.get(rightClickCallback)); itemSlot->setBackingImageAffinity(config.getBool("showBackingImageWhenFull", false), config.getBool("showBackingImageWhenEmpty", true)); itemSlot->showDurability(config.getBool("showDurability", false)); itemSlot->showCount(config.getBool("showCount", true)); @@ -515,33 +519,34 @@ WidgetConstructResult WidgetParser::itemGridHandler(String const& name, Json con } catch (MapException const& e) { throw WidgetParserException::format("Malformed gui json, missing a required value in the map. {}", outputException(e, false)); } - - String backingImage = config.getString("backingImage", ""); + String callback = config.getString("callback", name); - String rightClickCallback; - if (callback.equals("null")) - rightClickCallback = callback; - else - rightClickCallback = callback + ".right"; + String rightClickCallback = callback.equals("null") ? callback : callback + ".right"; rightClickCallback = config.getString("rightClickCallback", rightClickCallback); + String middleClickCallback = callback.equals("null") ? callback : callback + ".middle"; + middleClickCallback = config.getString("middleClickCallback", middleClickCallback); unsigned slotOffset = config.getInt("slotOffset", 0); + String backingImage = config.getString("backingImage", ""); auto itemGrid = make_shared(ItemBagConstPtr(), dimensions, rowSpacing, columnSpacing, backingImage, slotOffset); - if (!m_callbacks.contains(callback)) - throw WidgetParserException::format("Failed to find itemgrid callback named: '{}'", callback); - - itemGrid->setCallback(m_callbacks.get(callback)); - itemGrid->setBackingImageAffinity( - config.getBool("showBackingImageWhenFull", false), config.getBool("showBackingImageWhenEmpty", true)); + config.getBool("showBackingImageWhenFull", false), config.getBool("showBackingImageWhenEmpty", true)); itemGrid->showDurability(config.getBool("showDurability", false)); - if (!m_callbacks.contains(rightClickCallback)) - throw WidgetParserException::format("Failed to find itemgrid rightClickCallback named: '{}'", rightClickCallback); + if (auto leftClickCallback = m_callbacks.ptr(callback)) + itemGrid->setCallback(*leftClickCallback); + else + throw WidgetParserException::format("Failed to find ItemGrid callback named: '{}'", callback); + + if (auto callback = m_callbacks.ptr(rightClickCallback)) + itemGrid->setRightClickCallback(*callback); + else + throw WidgetParserException::format("Failed to find ItemGrid rightClickCallback named: '{}'", rightClickCallback); - itemGrid->setRightClickCallback(m_callbacks.get(rightClickCallback)); + if (auto callback = m_callbacks.ptr(middleClickCallback)) + itemGrid->setMiddleClickCallback(*callback); common(itemGrid, config);