diff --git a/Mods/vcmi/config/vcmi/english.json b/Mods/vcmi/config/vcmi/english.json index 3c6b12bcd..3381a9bb3 100644 --- a/Mods/vcmi/config/vcmi/english.json +++ b/Mods/vcmi/config/vcmi/english.json @@ -82,10 +82,10 @@ "vcmi.lobby.header.channels" : "Chat Channels", "vcmi.lobby.header.chat.global" : "Global Game Chat - %s", // %s -> language name "vcmi.lobby.header.chat.match" : "Previous game chat from %s", // %s -> game start date & time - "vcmi.lobby.header.chat.private" : "Private chat with %s", // %s -> nickname of another player + "vcmi.lobby.header.chat.player" : "Private chat with %s", // %s -> nickname of another player "vcmi.lobby.header.history" : "Your Previous Games", "vcmi.lobby.header.players" : "Players Online - %d", - "vcmi.lobby.match.solo" : "Solo Game", + "vcmi.lobby.match.solo" : "Singleplayer Game", "vcmi.lobby.match.duel" : "Game with %s", "vcmi.lobby.match.multi" : "%d players", "vcmi.lobby.room.create" : "Create New Room", @@ -95,6 +95,7 @@ "vcmi.lobby.room.description.new" : "To start the game, select a scenario or set up a random map.", "vcmi.lobby.room.description.load" : "To start the game, use one of your saved games.", "vcmi.lobby.room.description.limit" : "Up to %d players can enter your room, including you.", + "vcmi.lobby.room.invite" : "Invite Players", "vcmi.lobby.room.new" : "New Game", "vcmi.lobby.room.load" : "Load Game", "vcmi.lobby.room.type" : "Room Type", diff --git a/Mods/vcmi/config/vcmi/ukrainian.json b/Mods/vcmi/config/vcmi/ukrainian.json index 6714cd6f3..ffd084659 100644 --- a/Mods/vcmi/config/vcmi/ukrainian.json +++ b/Mods/vcmi/config/vcmi/ukrainian.json @@ -82,7 +82,7 @@ "vcmi.lobby.header.channels" : "Канали чату", "vcmi.lobby.header.chat.global" : "Глобальний ігровий чат - %s", // %s -> language name "vcmi.lobby.header.chat.match" : "Чат минулої гри від %s", // %s -> game start date & time - "vcmi.lobby.header.chat.private" : "Приватний чат з %s", // %s -> nickname of another player + "vcmi.lobby.header.chat.player" : "Приватний чат з %s", // %s -> nickname of another player "vcmi.lobby.header.history" : "Ваші попередні ігри", "vcmi.lobby.header.players" : "Гравці в мережі - %d", "vcmi.lobby.match.solo" : "Одиночна гра", diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index a46b46d3e..13bcb61c9 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -96,6 +96,7 @@ set(client_SRCS renderSDL/SDL_Extensions.cpp globalLobby/GlobalLobbyClient.cpp + globalLobby/GlobalLobbyInviteWindow.cpp globalLobby/GlobalLobbyLoginWindow.cpp globalLobby/GlobalLobbyServerSetup.cpp globalLobby/GlobalLobbyWidget.cpp @@ -281,6 +282,7 @@ set(client_HEADERS globalLobby/GlobalLobbyClient.h globalLobby/GlobalLobbyDefines.h + globalLobby/GlobalLobbyInviteWindow.h globalLobby/GlobalLobbyLoginWindow.h globalLobby/GlobalLobbyServerSetup.h globalLobby/GlobalLobbyWidget.h diff --git a/client/globalLobby/GlobalLobbyClient.cpp b/client/globalLobby/GlobalLobbyClient.cpp index f62bdf7ed..bee0156e3 100644 --- a/client/globalLobby/GlobalLobbyClient.cpp +++ b/client/globalLobby/GlobalLobbyClient.cpp @@ -11,6 +11,7 @@ #include "StdInc.h" #include "GlobalLobbyClient.h" +#include "GlobalLobbyInviteWindow.h" #include "GlobalLobbyLoginWindow.h" #include "GlobalLobbyWindow.h" @@ -194,7 +195,7 @@ void GlobalLobbyClient::receiveActiveAccounts(const JsonNode & json) { activeAccounts.clear(); - for (auto const & jsonEntry : json["accounts"].Vector()) + for(const auto & jsonEntry : json["accounts"].Vector()) { GlobalLobbyAccount account; @@ -214,7 +215,7 @@ void GlobalLobbyClient::receiveActiveGameRooms(const JsonNode & json) { activeRooms.clear(); - for (auto const & jsonEntry : json["gameRooms"].Vector()) + for(const auto & jsonEntry : json["gameRooms"].Vector()) { GlobalLobbyRoom room; @@ -226,7 +227,7 @@ void GlobalLobbyClient::receiveActiveGameRooms(const JsonNode & json) int ageSeconds = jsonEntry["ageSeconds"].Integer(); room.startDateFormatted = getCurrentDateTimeFormatted(-ageSeconds); - for (auto const & jsonParticipant : jsonEntry["participants"].Vector()) + for(const auto & jsonParticipant : jsonEntry["participants"].Vector()) { GlobalLobbyAccount account; account.accountID = jsonParticipant["accountID"].String(); @@ -247,7 +248,7 @@ void GlobalLobbyClient::receiveMatchesHistory(const JsonNode & json) { matchesHistory.clear(); - for (auto const & jsonEntry : json["matchesHistory"].Vector()) + for(const auto & jsonEntry : json["matchesHistory"].Vector()) { GlobalLobbyRoom room; @@ -259,7 +260,7 @@ void GlobalLobbyClient::receiveMatchesHistory(const JsonNode & json) int ageSeconds = jsonEntry["ageSeconds"].Integer(); room.startDateFormatted = getCurrentDateTimeFormatted(-ageSeconds); - for (auto const & jsonParticipant : jsonEntry["participants"].Vector()) + for(const auto & jsonParticipant : jsonEntry["participants"].Vector()) { GlobalLobbyAccount account; account.accountID = jsonParticipant["accountID"].String(); @@ -273,11 +274,15 @@ void GlobalLobbyClient::receiveMatchesHistory(const JsonNode & json) auto lobbyWindowPtr = lobbyWindow.lock(); if(lobbyWindowPtr) - lobbyWindowPtr->onMatchesHistory(activeRooms); + lobbyWindowPtr->onMatchesHistory(matchesHistory); } void GlobalLobbyClient::receiveInviteReceived(const JsonNode & json) { + auto lobbyWindowPtr = lobbyWindow.lock(); + if(lobbyWindowPtr) + lobbyWindowPtr->onMatchesHistory(activeRooms); + assert(0); //TODO } @@ -473,6 +478,11 @@ void GlobalLobbyClient::activateInterface() GH.windows().pushWindow(createLoginWindow()); } +void GlobalLobbyClient::activateRoomInviteInterface() +{ + GH.windows().createAndPushWindow(); +} + void GlobalLobbyClient::sendProxyConnectionLogin(const NetworkConnectionPtr & netConnection) { JsonNode toSend; diff --git a/client/globalLobby/GlobalLobbyClient.h b/client/globalLobby/GlobalLobbyClient.h index 90f046267..ac11614e4 100644 --- a/client/globalLobby/GlobalLobbyClient.h +++ b/client/globalLobby/GlobalLobbyClient.h @@ -69,6 +69,7 @@ public: /// Activate interface and pushes lobby UI as top window void activateInterface(); + void activateRoomInviteInterface(); void sendMatchChatMessage(const std::string & messageText); void sendMessage(const JsonNode & data); diff --git a/client/globalLobby/GlobalLobbyInviteWindow.cpp b/client/globalLobby/GlobalLobbyInviteWindow.cpp new file mode 100644 index 000000000..0799e940c --- /dev/null +++ b/client/globalLobby/GlobalLobbyInviteWindow.cpp @@ -0,0 +1,78 @@ +/* + * GlobalLobbyInviteWindow.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#include "StdInc.h" +#include "GlobalLobbyInviteWindow.h" + +#include "GlobalLobbyClient.h" + +#include "../CServerHandler.h" +#include "../gui/CGuiHandler.h" +#include "../widgets/Buttons.h" +#include "../widgets/GraphicalPrimitiveCanvas.h" +#include "../widgets/Images.h" +#include "../widgets/ObjectLists.h" +#include "../widgets/TextControls.h" + +#include "../../lib/MetaString.h" +#include "../../lib/json/JsonNode.h" + +GlobalLobbyInviteAccountCard::GlobalLobbyInviteAccountCard(GlobalLobbyInviteWindow * window, const GlobalLobbyAccount & accountDescription) + : accountID(accountDescription.accountID) +{ + pos.w = 200; + pos.h = 40; + addUsedEvents(LCLICK); + + OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; + backgroundOverlay = std::make_shared(Rect(0, 0, pos.w, pos.h), ColorRGBA(0, 0, 0, 128), ColorRGBA(64, 64, 64, 64), 1); + labelName = std::make_shared(5, 10, FONT_SMALL, ETextAlignment::CENTERLEFT, Colors::WHITE, accountDescription.displayName); + labelStatus = std::make_shared(5, 30, FONT_SMALL, ETextAlignment::CENTERLEFT, Colors::YELLOW, accountDescription.status); +} + +void GlobalLobbyInviteAccountCard::clickPressed(const Point & cursorPosition) +{ + JsonNode message; + message["type"].String() = "sendInvite"; + message["accountID"].String() = accountID; + + CSH->getGlobalLobby().sendMessage(message); +} + +GlobalLobbyInviteWindow::GlobalLobbyInviteWindow() + : CWindowObject(BORDERED) +{ + OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; + + pos.w = 236; + pos.h = 400; + + filledBackground = std::make_shared(ImagePath::builtin("DiBoxBck"), Rect(0, 0, pos.w, pos.h)); + filledBackground->playerColored(PlayerColor(1)); + labelTitle = std::make_shared( + pos.w / 2, 20, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, MetaString::createFromTextID("vcmi.lobby.room.invite").toString() + ); + + const auto & createAccountCardCallback = [this](size_t index) -> std::shared_ptr + { + const auto & accounts = CSH->getGlobalLobby().getActiveAccounts(); + + if(index < accounts.size()) + return std::make_shared(this, accounts[index]); + return std::make_shared(); + }; + + listBackground = std::make_shared(Rect(8, 48, 220, 304), ColorRGBA(0, 0, 0, 64), ColorRGBA(64, 80, 128, 255), 1); + accountList = std::make_shared(createAccountCardCallback, Point(10, 50), Point(0, 40), 8, 0, 0, 1 | 4, Rect(200, 0, 300, 300)); + + buttonClose = std::make_shared(Point(86, 364), AnimationPath::builtin("MuBchck"), CButton::tooltip(), [this]() { close(); } ); + + center(); +} diff --git a/client/globalLobby/GlobalLobbyInviteWindow.h b/client/globalLobby/GlobalLobbyInviteWindow.h new file mode 100644 index 000000000..4a2e1dab5 --- /dev/null +++ b/client/globalLobby/GlobalLobbyInviteWindow.h @@ -0,0 +1,46 @@ +/* + * GlobalLobbyInviteWindow.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include "../windows/CWindowObject.h" + +class CLabel; +class FilledTexturePlayerColored; +class TransparentFilledRectangle; +class CListBox; +class CButton; +struct GlobalLobbyAccount; + +class GlobalLobbyInviteWindow : public CWindowObject +{ + std::shared_ptr filledBackground; + std::shared_ptr labelTitle; + std::shared_ptr accountList; + std::shared_ptr listBackground; + std::shared_ptr buttonClose; + +public: + GlobalLobbyInviteWindow(); +}; + +class GlobalLobbyInviteAccountCard : public CIntObject +{ + std::string accountID; + + std::shared_ptr backgroundOverlay; + std::shared_ptr labelName; + std::shared_ptr labelStatus; + std::shared_ptr labelInviteStatus; + std::shared_ptr buttonInvite; + + void clickPressed(const Point & cursorPosition) override; +public: + GlobalLobbyInviteAccountCard(GlobalLobbyInviteWindow * window, const GlobalLobbyAccount & accountDescription); +}; diff --git a/client/globalLobby/GlobalLobbyWidget.cpp b/client/globalLobby/GlobalLobbyWidget.cpp index f807b9a4e..34ddfba69 100644 --- a/client/globalLobby/GlobalLobbyWidget.cpp +++ b/client/globalLobby/GlobalLobbyWidget.cpp @@ -106,7 +106,10 @@ std::shared_ptr GlobalLobbyWidget::buildItemList(const JsonNode & co int sliderMode = config["sliderSize"].isNull() ? 0 : (1 | 4); // present, vertical, blue int initialPos = 0; - return std::make_shared(callback, position, itemOffset, visibleAmount, totalAmount, initialPos, sliderMode, Rect(sliderPosition, sliderSize)); + auto result = std::make_shared(callback, position, itemOffset, visibleAmount, totalAmount, initialPos, sliderMode, Rect(sliderPosition, sliderSize)); + + result->setRedrawParent(true); + return result; } std::shared_ptr GlobalLobbyWidget::getAccountNameLabel() diff --git a/client/globalLobby/GlobalLobbyWidget.h b/client/globalLobby/GlobalLobbyWidget.h index ae1c3502a..7a16d4109 100644 --- a/client/globalLobby/GlobalLobbyWidget.h +++ b/client/globalLobby/GlobalLobbyWidget.h @@ -62,7 +62,6 @@ class GlobalLobbyAccountCard : public GlobalLobbyChannelCardBase std::shared_ptr backgroundOverlay; std::shared_ptr labelName; std::shared_ptr labelStatus; - std::shared_ptr buttonInvite; public: GlobalLobbyAccountCard(GlobalLobbyWindow * window, const GlobalLobbyAccount & accountDescription); diff --git a/client/lobby/CSelectionBase.cpp b/client/lobby/CSelectionBase.cpp index df251d4f9..d55f4fcf7 100644 --- a/client/lobby/CSelectionBase.cpp +++ b/client/lobby/CSelectionBase.cpp @@ -26,6 +26,7 @@ #include "../gui/CGuiHandler.h" #include "../gui/Shortcut.h" #include "../gui/WindowHandler.h" +#include "../globalLobby/GlobalLobbyClient.h" #include "../mainmenu/CMainMenu.h" #include "../widgets/Buttons.h" #include "../widgets/CComponent.h" @@ -137,6 +138,9 @@ InfoCard::InfoCard() playerListBg = std::make_shared(ImagePath::builtin("CHATPLUG.bmp"), 16, 276); chat = std::make_shared(Rect(18, 126, 335, 143)); + buttonInvitePlayers = std::make_shared(Point(30, 360), AnimationPath::builtin("GSPBUT2.DEF"), CGI->generaltexth->zelp[105], [=](){ CSH->getGlobalLobby().activateRoomInviteInterface(); } ); + buttonOpenGlobalLobby = std::make_shared(Point(200, 360), AnimationPath::builtin("GSPBUT2.DEF"), CGI->generaltexth->zelp[105], [=](){ CSH->getGlobalLobby().activateInterface(); }); + if(SEL->screenType == ESelectionScreen::campaignList) { labelCampaignDescription = std::make_shared(26, 132, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::YELLOW, CGI->generaltexth->allTexts[38]); @@ -183,8 +187,7 @@ InfoCard::InfoCard() labelDifficulty = std::make_shared(62, 472, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); labelDifficultyPercent = std::make_shared(311, 472, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); - labelGroupPlayersAssigned = std::make_shared(FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE); - labelGroupPlayersUnassigned = std::make_shared(FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE); + labelGroupPlayers = std::make_shared(FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE); disableLabelRedraws(); } setChat(false); @@ -240,27 +243,21 @@ void InfoCard::changeSelection() OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; // FIXME: We recreate them each time because CLabelGroup don't use smart pointers - labelGroupPlayersAssigned = std::make_shared(FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE); - labelGroupPlayersUnassigned = std::make_shared(FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE); + labelGroupPlayers = std::make_shared(FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE); if(!showChat) - { - labelGroupPlayersAssigned->disable(); - labelGroupPlayersUnassigned->disable(); - } + labelGroupPlayers->disable(); + for(auto & p : CSH->playerNames) { - const auto pset = CSH->si->getPlayersSettings(p.first); - int pid = p.first; - if(pset) - { - auto name = boost::str(boost::format("%s (%d-%d %s)") % p.second.name % p.second.connection % pid % pset->color.toString()); - labelGroupPlayersAssigned->add(24, 285 + (int)labelGroupPlayersAssigned->currentSize()*(int)graphics->fonts[FONT_SMALL]->getLineHeight(), name); - } + int slotsUsed = labelGroupPlayers->currentSize(); + Point labelPosition; + + if (slotsUsed < 4) + labelPosition = Point(24, 285 + slotsUsed * graphics->fonts[FONT_SMALL]->getLineHeight()); // left column else - { - auto name = boost::str(boost::format("%s (%d-%d)") % p.second.name % p.second.connection % pid); - labelGroupPlayersUnassigned->add(193, 285 + (int)labelGroupPlayersUnassigned->currentSize()*(int)graphics->fonts[FONT_SMALL]->getLineHeight(), name); - } + labelPosition = Point(193, 285 + (slotsUsed - 4) * graphics->fonts[FONT_SMALL]->getLineHeight()); // right column + + labelGroupPlayers->add(labelPosition.x, labelPosition.y, p.second.name); } } @@ -289,8 +286,12 @@ void InfoCard::setChat(bool activateChat) labelVictoryConditionText->disable(); iconsLossCondition->disable(); labelLossConditionText->disable(); - labelGroupPlayersAssigned->enable(); - labelGroupPlayersUnassigned->enable(); + labelGroupPlayers->enable(); + } + if (CSH->inLobbyRoom()) + { + buttonInvitePlayers->enable(); + buttonOpenGlobalLobby->enable(); } mapDescription->disable(); chat->enable(); @@ -298,6 +299,8 @@ void InfoCard::setChat(bool activateChat) } else { + buttonInvitePlayers->disable(); + buttonOpenGlobalLobby->disable(); mapDescription->enable(); chat->disable(); playerListBg->disable(); @@ -315,8 +318,7 @@ void InfoCard::setChat(bool activateChat) iconsLossCondition->enable(); labelVictoryConditionText->enable(); labelLossConditionText->enable(); - labelGroupPlayersAssigned->disable(); - labelGroupPlayersUnassigned->disable(); + labelGroupPlayers->disable(); } } diff --git a/client/lobby/CSelectionBase.h b/client/lobby/CSelectionBase.h index 981f69df8..29b7ec911 100644 --- a/client/lobby/CSelectionBase.h +++ b/client/lobby/CSelectionBase.h @@ -104,8 +104,9 @@ class InfoCard : public CIntObject std::shared_ptr labelVictoryConditionText; std::shared_ptr labelLossConditionText; - std::shared_ptr labelGroupPlayersAssigned; - std::shared_ptr labelGroupPlayersUnassigned; + std::shared_ptr labelGroupPlayers; + std::shared_ptr buttonInvitePlayers; + std::shared_ptr buttonOpenGlobalLobby; public: bool showChat;