diff --git a/Mods/vcmi/config/vcmi/czech.json b/Mods/vcmi/config/vcmi/czech.json index 1e9f8b2e8..f1c561b97 100644 --- a/Mods/vcmi/config/vcmi/czech.json +++ b/Mods/vcmi/config/vcmi/czech.json @@ -44,7 +44,7 @@ "vcmi.mainMenu.joinTCP" : "Připojit se do hry TCP/IP", "vcmi.mainMenu.playerName" : "Hráč", - "vcmi.lobby.filename" : "Název souboru", + "vcmi.lobby.filepath" : "Název souboru", "vcmi.lobby.creationDate" : "Datum vytvoření", "vcmi.server.errors.existingProcess" : "Již běží jiný server VCMI. Prosím, ukončete ho před startem nové hry.", diff --git a/Mods/vcmi/config/vcmi/english.json b/Mods/vcmi/config/vcmi/english.json index a14081798..c5cba2fa1 100644 --- a/Mods/vcmi/config/vcmi/english.json +++ b/Mods/vcmi/config/vcmi/english.json @@ -49,8 +49,12 @@ "vcmi.mainMenu.joinTCP" : "Join TCP/IP game", "vcmi.mainMenu.playerName" : "Player", - "vcmi.lobby.filename" : "Filename", + "vcmi.lobby.filepath" : "File path", "vcmi.lobby.creationDate" : "Creation date", + "vcmi.lobby.scenarioName" : "Scenario name", + "vcmi.lobby.mapPreview" : "Map preview", + "vcmi.lobby.noPreview" : "no preview", + "vcmi.lobby.noUnderground" : "no underground", "vcmi.server.errors.existingProcess" : "Another VCMI server process is running. Please terminate it before starting a new game.", "vcmi.server.errors.modsToEnable" : "{Following mods are required}", diff --git a/Mods/vcmi/config/vcmi/german.json b/Mods/vcmi/config/vcmi/german.json index abe112ebd..121deacb2 100644 --- a/Mods/vcmi/config/vcmi/german.json +++ b/Mods/vcmi/config/vcmi/german.json @@ -48,8 +48,12 @@ "vcmi.mainMenu.joinTCP" : "Trete TCP/IP Spiel bei", "vcmi.mainMenu.playerName" : "Spieler", - "vcmi.lobby.filename" : "Dateiname", + "vcmi.lobby.filepath" : "Dateipfad", "vcmi.lobby.creationDate" : "Erstellungsdatum", + "vcmi.lobby.scenarioName" : "Szenario-Name", + "vcmi.lobby.mapPreview" : "Kartenvorschau", + "vcmi.lobby.noPreview" : "Keine Vorschau", + "vcmi.lobby.noUnderground" : "Kein Untergrund", "vcmi.server.errors.existingProcess" : "Es läuft ein weiterer vcmiserver-Prozess, bitte beendet diesen zuerst", "vcmi.server.errors.modsToEnable" : "{Erforderliche Mods um das Spiel zu laden}", diff --git a/Mods/vcmi/config/vcmi/polish.json b/Mods/vcmi/config/vcmi/polish.json index 51c96dac4..1526e83e3 100644 --- a/Mods/vcmi/config/vcmi/polish.json +++ b/Mods/vcmi/config/vcmi/polish.json @@ -43,7 +43,7 @@ "vcmi.mainMenu.joinTCP" : "Dołącz do gry TCP/IP", "vcmi.mainMenu.playerName" : "Gracz", - "vcmi.lobby.filename" : "Nazwa pliku", + "vcmi.lobby.filepath" : "Nazwa pliku", "vcmi.lobby.creationDate" : "Data utworzenia", "vcmi.server.errors.existingProcess" : "Inny proces 'vcmiserver' został już uruchomiony, zakończ go nim przejdziesz dalej", diff --git a/Mods/vcmi/config/vcmi/ukrainian.json b/Mods/vcmi/config/vcmi/ukrainian.json index 4f5228821..9773fc7af 100644 --- a/Mods/vcmi/config/vcmi/ukrainian.json +++ b/Mods/vcmi/config/vcmi/ukrainian.json @@ -44,7 +44,7 @@ "vcmi.mainMenu.joinTCP" : "Приєднатися до TCP/IP гри", "vcmi.mainMenu.playerName" : "Гравець", - "vcmi.lobby.filename" : "Назва файлу", + "vcmi.lobby.filepath" : "Назва файлу", "vcmi.lobby.creationDate" : "Дата створення", "vcmi.server.errors.existingProcess" : "Працює інший процес vcmiserver, будь ласка, спочатку завершіть його", diff --git a/Mods/vcmi/config/vcmi/vietnamese.json b/Mods/vcmi/config/vcmi/vietnamese.json index 9926fce10..890e699d1 100644 --- a/Mods/vcmi/config/vcmi/vietnamese.json +++ b/Mods/vcmi/config/vcmi/vietnamese.json @@ -50,7 +50,7 @@ "vcmi.mainMenu.joinTCP": "Tham gia TCP/IP", "vcmi.mainMenu.playerName": "Người chơi", - "vcmi.lobby.filename": "Tên tập tin", + "vcmi.lobby.filepath": "Tên tập tin", "vcmi.lobby.creationDate": "Ngày tạo", "vcmi.server.errors.existingProcess": "1 chương trình VCMI khác đang chạy. Tắt nó trước khi mở cái mới", diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index ed53ca99a..2912d02cf 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -119,6 +119,7 @@ set(client_SRCS windows/CHeroOverview.cpp windows/CHeroWindow.cpp windows/CKingdomInterface.cpp + windows/CMapOverview.cpp windows/CMessage.cpp windows/CPuzzleWindow.cpp windows/CQuestLog.cpp @@ -285,6 +286,7 @@ set(client_HEADERS windows/CHeroWindow.h windows/CKingdomInterface.h windows/CMessage.h + windows/CMapOverview.h windows/CPuzzleWindow.h windows/CQuestLog.h windows/CSpellWindow.h diff --git a/client/VCMI_client.cbp b/client/VCMI_client.cbp index 57fc618b5..081be52ae 100644 --- a/client/VCMI_client.cbp +++ b/client/VCMI_client.cbp @@ -229,6 +229,8 @@ + + diff --git a/client/VCMI_client.vcxproj b/client/VCMI_client.vcxproj index 3fe7331f9..997bdba6a 100644 --- a/client/VCMI_client.vcxproj +++ b/client/VCMI_client.vcxproj @@ -238,6 +238,7 @@ + @@ -305,6 +306,7 @@ + diff --git a/client/VCMI_client.vcxproj.filters b/client/VCMI_client.vcxproj.filters index 8831d0480..9b717e834 100644 --- a/client/VCMI_client.vcxproj.filters +++ b/client/VCMI_client.vcxproj.filters @@ -25,6 +25,9 @@ windows + + windows + windows @@ -179,6 +182,9 @@ windows + + windows + windows diff --git a/client/gui/InterfaceObjectConfigurable.cpp b/client/gui/InterfaceObjectConfigurable.cpp index 3a1fd45cb..24d20d3fc 100644 --- a/client/gui/InterfaceObjectConfigurable.cpp +++ b/client/gui/InterfaceObjectConfigurable.cpp @@ -56,6 +56,8 @@ InterfaceObjectConfigurable::InterfaceObjectConfigurable(int used, Point offset) REGISTER_BUILDER("layout", &InterfaceObjectConfigurable::buildLayout); REGISTER_BUILDER("comboBox", &InterfaceObjectConfigurable::buildComboBox); REGISTER_BUILDER("textInput", &InterfaceObjectConfigurable::buildTextInput); + REGISTER_BUILDER("transparentFilledRectangle", &InterfaceObjectConfigurable::buildTransparentFilledRectangle); + REGISTER_BUILDER("textBox", &InterfaceObjectConfigurable::buildTextBox); } void InterfaceObjectConfigurable::registerBuilder(const std::string & type, BuilderFunction f) @@ -684,6 +686,33 @@ std::shared_ptr InterfaceObjectConfigurable::buildAnimation(const return anim; } +std::shared_ptr InterfaceObjectConfigurable::buildTransparentFilledRectangle(const JsonNode & config) const +{ + logGlobal->debug("Building widget TransparentFilledRectangle"); + + auto rect = readRect(config["rect"]); + auto color = readColor(config["color"]); + if(!config["colorLine"].isNull()) + { + auto colorLine = readColor(config["colorLine"]); + return std::make_shared(rect, color, colorLine); + } + return std::make_shared(rect, color); +} + +std::shared_ptr InterfaceObjectConfigurable::buildTextBox(const JsonNode & config) const +{ + logGlobal->debug("Building widget CTextBox"); + + auto rect = readRect(config["rect"]); + auto font = readFont(config["font"]); + auto alignment = readTextAlignment(config["alignment"]); + auto color = readColor(config["color"]); + auto text = readText(config["text"]); + + return std::make_shared(text, rect, 0, font, alignment, color); +} + std::shared_ptr InterfaceObjectConfigurable::buildWidget(JsonNode config) const { assert(!config.isNull()); diff --git a/client/gui/InterfaceObjectConfigurable.h b/client/gui/InterfaceObjectConfigurable.h index 30b96bfb4..cc812299e 100644 --- a/client/gui/InterfaceObjectConfigurable.h +++ b/client/gui/InterfaceObjectConfigurable.h @@ -29,6 +29,8 @@ class CShowableAnim; class CFilledTexture; class ComboBox; class CTextInput; +class TransparentFilledRectangle; +class CTextBox; #define REGISTER_BUILDER(type, method) registerBuilder(type, std::bind(method, this, std::placeholders::_1)) @@ -105,6 +107,8 @@ protected: std::shared_ptr buildLayout(const JsonNode &); std::shared_ptr buildComboBox(const JsonNode &); std::shared_ptr buildTextInput(const JsonNode &) const; + std::shared_ptr buildTransparentFilledRectangle(const JsonNode & config) const; + std::shared_ptr buildTextBox(const JsonNode & config) const; //composite widgets std::shared_ptr buildWidget(JsonNode config) const; diff --git a/client/lobby/SelectionTab.cpp b/client/lobby/SelectionTab.cpp index 9e0f87052..6faa7fc2c 100644 --- a/client/lobby/SelectionTab.cpp +++ b/client/lobby/SelectionTab.cpp @@ -27,11 +27,10 @@ #include "../widgets/TextControls.h" #include "../windows/GUIClasses.h" #include "../windows/InfoWindows.h" +#include "../windows/CMapOverview.h" #include "../render/CAnimation.h" -#include "../render/Canvas.h" #include "../render/IImage.h" #include "../render/IRenderHandler.h" -#include "../render/Graphics.h" #include "../../CCallback.h" @@ -41,8 +40,6 @@ #include "../../lib/GameSettings.h" #include "../../lib/filesystem/Filesystem.h" #include "../../lib/campaign/CampaignState.h" -#include "../../lib/mapping/CMap.h" -#include "../../lib/mapping/CMapService.h" #include "../../lib/mapping/CMapInfo.h" #include "../../lib/mapping/CMapHeader.h" #include "../../lib/mapping/MapFormat.h" @@ -366,13 +363,7 @@ void SelectionTab::showPopupWindow(const Point & cursorPosition) return; if(!curItems[py]->isFolder) - { - std::string text = boost::str(boost::format("{%1%}\r\n\r\n%2%:\r\n%3%") % curItems[py]->getNameTranslated() % CGI->generaltexth->translate("vcmi.lobby.filename") % curItems[py]->fullFileURI); - if(curItems[py]->date != "") - text += boost::str(boost::format("\r\n\r\n%1%:\r\n%2%") % CGI->generaltexth->translate("vcmi.lobby.creationDate") % curItems[py]->date); - - GH.windows().createAndPushWindow(text, ResourcePath(curItems[py]->fileURI), tabType); - } + GH.windows().createAndPushWindow(curItems[py]->getNameTranslated(), curItems[py]->fullFileURI, curItems[py]->date, ResourcePath(curItems[py]->fileURI), tabType); else CRClickPopup::createAndPush(curItems[py]->folderName); } @@ -822,121 +813,6 @@ std::unordered_set SelectionTab::getFiles(std::string dirURI, ERes return ret; } -SelectionTab::CMapInfoTooltipBox::CMapInfoTooltipBox(std::string text, ResourcePath resource, ESelectionScreen tabType) - : CWindowObject(BORDERED | RCLICK_POPUP) -{ - drawPlayerElements = tabType == ESelectionScreen::newGame; - renderImage = tabType == ESelectionScreen::newGame && settings["lobby"]["mapPreview"].Bool(); - - OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; - - std::vector> mapLayerImages; - if(renderImage) - mapLayerImages = createMinimaps(ResourcePath(resource.getName(), EResType::MAP), IMAGE_SIZE); - - if(mapLayerImages.size() == 0) - renderImage = false; - - pos = Rect(0, 0, 3 * BORDER + 2 * IMAGE_SIZE, 2000); - - auto drawLabel = [&]() { - label = std::make_shared(text, Rect(BORDER, BORDER, BORDER + 2 * IMAGE_SIZE, 350), 0, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE); - if(!label->slider) - label->resize(Point(BORDER + 2 * IMAGE_SIZE, label->label->textSize.y)); - }; - drawLabel(); - - int textHeight = std::min(350, label->label->textSize.y); - pos.h = BORDER + textHeight + BORDER; - if(renderImage) - pos.h += IMAGE_SIZE + BORDER; - backgroundTexture = std::make_shared(ImagePath::builtin("DIBOXBCK"), pos); - updateShadow(); - - drawLabel(); - - if(renderImage) - { - if(mapLayerImages.size() == 1) - image1 = std::make_shared(mapLayerImages[0], Point(BORDER + (BORDER + IMAGE_SIZE) / 2, textHeight + 2 * BORDER)); - else - { - image1 = std::make_shared(mapLayerImages[0], Point(BORDER, textHeight + 2 * BORDER)); - image2 = std::make_shared(mapLayerImages[1], Point(BORDER + IMAGE_SIZE + BORDER, textHeight + 2 * BORDER)); - } - } - - center(GH.getCursorPosition()); //center on mouse -#ifdef VCMI_MOBILE - moveBy({0, -pos.h / 2}); -#endif - fitToScreen(10); -} - -Canvas SelectionTab::CMapInfoTooltipBox::createMinimapForLayer(std::unique_ptr & map, int layer) -{ - Canvas canvas = Canvas(Point(map->width, map->height)); - - for (int y = 0; y < map->height; ++y) - for (int x = 0; x < map->width; ++x) - { - TerrainTile & tile = map->getTile(int3(x, y, layer)); - - ColorRGBA color = tile.terType->minimapUnblocked; - if (tile.blocked && (!tile.visitable)) - color = tile.terType->minimapBlocked; - - if(drawPlayerElements) - // if object at tile is owned - it will be colored as its owner - for (const CGObjectInstance *obj : tile.blockingObjects) - { - PlayerColor player = obj->getOwner(); - if(player == PlayerColor::NEUTRAL) - { - color = graphics->neutralColor; - break; - } - if (player.isValidPlayer()) - { - color = graphics->playerColors[player.getNum()]; - break; - } - } - - canvas.drawPoint(Point(x, y), color); - } - - return canvas; -} - -std::vector> SelectionTab::CMapInfoTooltipBox::createMinimaps(ResourcePath resource, int size) -{ - std::vector> ret = std::vector>(); - - CMapService mapService; - std::unique_ptr map; - try - { - map = mapService.loadMap(resource); - } - catch (...) - { - return ret; - } - - for(int i = 0; i < (map->twoLevel ? 2 : 1); i++) - { - Canvas canvas = createMinimapForLayer(map, i); - Canvas canvasScaled = Canvas(Point(size, size)); - canvasScaled.drawScaled(canvas, Point(0, 0), Point(size, size)); - std::shared_ptr img = GH.renderHandler().createImage(canvasScaled.getInternalSurface()); - - ret.push_back(img); - } - - return ret; -} - SelectionTab::ListItem::ListItem(Point position, std::shared_ptr iconsFormats, std::shared_ptr iconsVictory, std::shared_ptr iconsLoss) : CIntObject(LCLICK, position) { diff --git a/client/lobby/SelectionTab.h b/client/lobby/SelectionTab.h index e4d67ef83..50f501769 100644 --- a/client/lobby/SelectionTab.h +++ b/client/lobby/SelectionTab.h @@ -67,25 +67,6 @@ class SelectionTab : public CIntObject // FIXME: CSelectionBase use them too! std::shared_ptr iconsVictoryCondition; std::shared_ptr iconsLossCondition; - - class CMapInfoTooltipBox : public CWindowObject - { - const int IMAGE_SIZE = 169; - const int BORDER = 30; - - bool drawPlayerElements; - bool renderImage; - - std::shared_ptr backgroundTexture; - std::shared_ptr label; - std::shared_ptr image1; - std::shared_ptr image2; - - Canvas createMinimapForLayer(std::unique_ptr & map, int layer); - std::vector> createMinimaps(ResourcePath resource, int size); - public: - CMapInfoTooltipBox(std::string text, ResourcePath resource, ESelectionScreen tabType); - }; public: std::vector> allItems; std::vector> curItems; diff --git a/client/windows/CMapOverview.cpp b/client/windows/CMapOverview.cpp new file mode 100644 index 000000000..ffa7aeb03 --- /dev/null +++ b/client/windows/CMapOverview.cpp @@ -0,0 +1,206 @@ +/* + * CMapOverview.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 "CMapOverview.h" + +#include "../lobby/SelectionTab.h" + +#include + +#include "../gui/CGuiHandler.h" +#include "../gui/WindowHandler.h" +#include "../widgets/CComponent.h" +#include "../widgets/MiscWidgets.h" +#include "../widgets/TextControls.h" +#include "../windows/GUIClasses.h" +#include "../windows/InfoWindows.h" +#include "../render/CAnimation.h" +#include "../render/Canvas.h" +#include "../render/IImage.h" +#include "../render/IRenderHandler.h" +#include "../render/Graphics.h" + +#include "../../lib/CGeneralTextHandler.h" +#include "../../lib/CConfigHandler.h" +#include "../../lib/campaign/CampaignState.h" +#include "../../lib/mapping/CMap.h" +#include "../../lib/mapping/CMapService.h" +#include "../../lib/mapping/CMapInfo.h" +#include "../../lib/mapping/CMapHeader.h" +#include "../../lib/mapping/MapFormat.h" +#include "../../lib/TerrainHandler.h" +#include "../../lib/filesystem/Filesystem.h" + +#include "../../lib/serializer/BinaryDeserializer.h" +#include "../../lib/StartInfo.h" +#include "../../lib/rmg/CMapGenOptions.h" + +CMapOverview::CMapOverview(std::string mapName, std::string fileName, std::string date, ResourcePath resource, ESelectionScreen tabType) + : CWindowObject(BORDERED | RCLICK_POPUP), resource(resource), mapName(mapName), fileName(fileName), date(date), tabType(tabType) +{ + + OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; + + widget = std::make_shared(*this); + + updateShadow(); + + center(GH.getCursorPosition()); //center on mouse +#ifdef VCMI_MOBILE + moveBy({0, -pos.h / 2}); +#endif + fitToScreen(10); +} + +Canvas CMapOverviewWidget::createMinimapForLayer(std::unique_ptr & map, int layer) const +{ + Canvas canvas = Canvas(Point(map->width, map->height)); + + for (int y = 0; y < map->height; ++y) + for (int x = 0; x < map->width; ++x) + { + TerrainTile & tile = map->getTile(int3(x, y, layer)); + + ColorRGBA color = tile.terType->minimapUnblocked; + if (tile.blocked && (!tile.visitable)) + color = tile.terType->minimapBlocked; + + if(drawPlayerElements) + // if object at tile is owned - it will be colored as its owner + for (const CGObjectInstance *obj : tile.blockingObjects) + { + PlayerColor player = obj->getOwner(); + if(player == PlayerColor::NEUTRAL) + { + color = graphics->neutralColor; + break; + } + if (player.isValidPlayer()) + { + color = graphics->playerColors[player.getNum()]; + break; + } + } + + canvas.drawPoint(Point(x, y), color); + } + + return canvas; +} + +std::vector CMapOverviewWidget::createMinimaps(ResourcePath resource) const +{ + std::vector ret = std::vector(); + + CMapService mapService; + std::unique_ptr map; + try + { + map = mapService.loadMap(resource); + } + catch (const std::exception & e) + { + logGlobal->warn("Failed to generate map preview! %s", e.what()); + return ret; + } + + return createMinimaps(map); +} + +std::vector CMapOverviewWidget::createMinimaps(std::unique_ptr & map) const +{ + std::vector ret = std::vector(); + + for(int i = 0; i < (map->twoLevel ? 2 : 1); i++) + ret.push_back(createMinimapForLayer(map, i)); + + return ret; +} + +std::shared_ptr CMapOverviewWidget::buildDrawMinimap(const JsonNode & config) const +{ + logGlobal->debug("Building widget drawMinimap"); + + auto rect = readRect(config["rect"]); + auto id = config["id"].Integer(); + + if(id >= minimaps.size()) + return nullptr; + + Canvas canvasScaled = Canvas(Point(rect.w, rect.h)); + canvasScaled.drawScaled(minimaps[id], Point(0, 0), Point(rect.w, rect.h)); + std::shared_ptr img = GH.renderHandler().createImage(canvasScaled.getInternalSurface()); + + return std::make_shared(img, Point(rect.x, rect.y)); +} + +CMapOverviewWidget::CMapOverviewWidget(CMapOverview& parent): + InterfaceObjectConfigurable(), p(parent) +{ + drawPlayerElements = p.tabType == ESelectionScreen::newGame; + + const JsonNode config(JsonPath::builtin("config/widgets/mapOverview.json")); + + if(settings["lobby"]["mapPreview"].Bool()) + { + ResourcePath res = ResourcePath(p.resource.getName(), EResType::MAP); + std::unique_ptr campaignMap = nullptr; + if(p.tabType != ESelectionScreen::newGame && config["variables"]["mapPreviewForSaves"].Bool()) + { + CLoadFile lf(*CResourceHandler::get()->getResourceName(ResourcePath(p.resource.getName(), EResType::SAVEGAME)), MINIMAL_SERIALIZATION_VERSION); + lf.checkMagicBytes(SAVEGAME_MAGIC); + + std::unique_ptr mapHeader = std::make_unique(); + StartInfo * startInfo; + lf >> *(mapHeader) >> startInfo; + + if(startInfo->campState) + campaignMap = startInfo->campState->getMap(*startInfo->campState->currentScenario()); + res = ResourcePath(startInfo->fileURI, EResType::MAP); + } + if(!campaignMap) + minimaps = createMinimaps(res); + else + minimaps = createMinimaps(campaignMap); + } + + REGISTER_BUILDER("drawMinimap", &CMapOverviewWidget::buildDrawMinimap); + + build(config); + + if(auto w = widget("background")) + { + p.pos = w->pos; + } + if(auto w = widget("fileName")) + { + w->setText(p.fileName); + } + if(auto w = widget("mapName")) + { + w->setText(p.mapName); + } + if(auto w = widget("date")) + { + if(p.date.empty()) + { + std::time_t time = boost::filesystem::last_write_time(*CResourceHandler::get()->getResourceName(ResourcePath(p.resource.getName(), EResType::MAP))); + w->setText(vstd::getFormattedDateTime(time)); + } + else + w->setText(p.date); + } + if(auto w = widget("noUnderground")) + { + if(minimaps.size() == 0) + w->setText(""); + } +} diff --git a/client/windows/CMapOverview.h b/client/windows/CMapOverview.h new file mode 100644 index 000000000..1602e80c3 --- /dev/null +++ b/client/windows/CMapOverview.h @@ -0,0 +1,59 @@ +/* + * CMapOverview.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 + +VCMI_LIB_NAMESPACE_BEGIN +class CMap; +VCMI_LIB_NAMESPACE_END +#include "CWindowObject.h" +#include "../../lib/filesystem/ResourcePath.h" +#include "../gui/InterfaceObjectConfigurable.h" + +class CSlider; +class CLabel; +class CPicture; +class CFilledTexture; +class CTextBox; +class IImage; +class Canvas; +class TransparentFilledRectangle; +enum ESelectionScreen : ui8; + +class CMapOverview; + +class CMapOverviewWidget : public InterfaceObjectConfigurable +{ + CMapOverview& p; + + bool drawPlayerElements; + std::vector minimaps; + + Canvas createMinimapForLayer(std::unique_ptr & map, int layer) const; + std::vector createMinimaps(ResourcePath resource) const; + std::vector createMinimaps(std::unique_ptr & map) const; + + std::shared_ptr buildDrawMinimap(const JsonNode & config) const; +public: + CMapOverviewWidget(CMapOverview& p); +}; + +class CMapOverview : public CWindowObject +{ + std::shared_ptr widget; + +public: + const ResourcePath resource; + const std::string mapName; + const std::string fileName; + const std::string date; + const ESelectionScreen tabType; + + CMapOverview(std::string mapName, std::string fileName, std::string date, ResourcePath resource, ESelectionScreen tabType); +}; diff --git a/config/widgets/mapOverview.json b/config/widgets/mapOverview.json new file mode 100644 index 000000000..d451afda4 --- /dev/null +++ b/config/widgets/mapOverview.json @@ -0,0 +1,156 @@ +{ + "items": + [ + { + "name": "background", + "type": "texture", + "image": "DIBOXBCK", + "rect": {"w": 428, "h": 379} + }, + { + "type": "transparentFilledRectangle", + "rect": {"x": 5, "y": 5, "w": 418, "h": 20}, + "color": [0, 0, 0, 75], + "colorLine": [128, 100, 75, 255] + }, + { + "type": "label", + "font": "medium", + "alignment": "center", + "color": "yellow", + "text": "vcmi.lobby.scenarioName", + "position": {"x": 214, "y": 15} + }, + { + "type": "transparentFilledRectangle", + "rect": {"x": 5, "y": 30, "w": 418, "h": 20}, + "color": [0, 0, 0, 75], + "colorLine": [128, 100, 75, 255] + }, + { + "type": "label", + "name": "mapName", + "font": "small", + "alignment": "center", + "color": "white", + "text": "", + "position": {"x": 214, "y": 40} + }, + { + "type": "transparentFilledRectangle", + "rect": {"x": 5, "y": 55, "w": 418, "h": 20}, + "color": [0, 0, 0, 75], + "colorLine": [128, 100, 75, 255] + }, + { + "type": "label", + "font": "medium", + "alignment": "center", + "color": "yellow", + "text": "vcmi.lobby.mapPreview", + "position": {"x": 214, "y": 65} + }, + { + "type": "transparentFilledRectangle", + "rect": {"x": 29, "y": 79, "w": 171, "h": 171}, + "color": [0, 0, 0, 255], + "colorLine": [128, 100, 75, 255] + }, + { + "type": "label", + "font": "small", + "alignment": "center", + "color": "white", + "text": "vcmi.lobby.noPreview", + "position": {"x": 114, "y": 164} + }, + { + "type": "drawMinimap", + "id": 0, + "rect": {"x": 30, "y": 80, "w": 169, "h": 169} + }, + { + "type": "transparentFilledRectangle", + "rect": {"x": 228, "y": 79, "w": 171, "h": 171}, + "color": [0, 0, 0, 255], + "colorLine": [128, 100, 75, 255] + }, + { + "type": "label", + "name": "noUnderground", + "font": "small", + "alignment": "center", + "color": "white", + "text": "vcmi.lobby.noUnderground", + "position": {"x": 313, "y": 164} + }, + { + "type": "drawMinimap", + "id": 1, + "rect": {"x": 229, "y": 80, "w": 169, "h": 169} + }, + { + "type": "transparentFilledRectangle", + "rect": {"x": 5, "y": 254, "w": 418, "h": 20}, + "color": [0, 0, 0, 75], + "colorLine": [128, 100, 75, 255] + }, + { + "type": "label", + "font": "medium", + "alignment": "center", + "color": "yellow", + "text": "vcmi.lobby.creationDate", + "position": {"x": 214, "y": 264} + }, + { + "type": "transparentFilledRectangle", + "rect": {"x": 5, "y": 279, "w": 418, "h": 20}, + "color": [0, 0, 0, 75], + "colorLine": [128, 100, 75, 255] + }, + { + "type": "label", + "name": "date", + "font": "small", + "alignment": "center", + "color": "white", + "text": "", + "position": {"x": 214, "y": 289} + }, + { + "type": "transparentFilledRectangle", + "rect": {"x": 5, "y": 304, "w": 418, "h": 20}, + "color": [0, 0, 0, 75], + "colorLine": [128, 100, 75, 255] + }, + { + "type": "label", + "font": "medium", + "alignment": "center", + "color": "yellow", + "text": "vcmi.lobby.filepath", + "position": {"x": 214, "y": 314} + }, + { + "type": "transparentFilledRectangle", + "rect": {"x": 5, "y": 329, "w": 418, "h": 45}, + "color": [0, 0, 0, 75], + "colorLine": [128, 100, 75, 255] + }, + { + "type": "textBox", + "name": "fileName", + "font": "small", + "alignment": "center", + "color": "white", + "text": "", + "rect": {"x": 10, "y": 334, "w": 408, "h": 35} + } + ], + + "variables": + { + "mapPreviewForSaves": true + } +} diff --git a/docs/modders/Configurable_Widgets.md b/docs/modders/Configurable_Widgets.md index d13af3a64..9d3234e10 100644 --- a/docs/modders/Configurable_Widgets.md +++ b/docs/modders/Configurable_Widgets.md @@ -517,6 +517,22 @@ Configurable object has following structure: `"text"`: [text](#text), +### TextBox + +`"type": "textBox"` + +`"name": "string"` optional, object name + +`"font"`: [font](#font) + +`"alignment"`: [alignment](#text-alignment), + +`"color"`: [color](#color), + +`"text"`: [text](#text), + +`"rect"`: [rect](#rect) + ### Picture `"type": "picture"` @@ -559,6 +575,18 @@ Filling area with texture `"rect"`: [rect](#rect) +### TransparentFilledRectangle + +`"type": "transparentFilledRectangle"` + +`"name": "string"` optional, object name + +`"color"`: [color](#color) fill color of rectangle (supports transparency) + +`"colorLine"`: [color](#color) optional, 1px border color + +`"rect"`: [rect](#rect) + ### Animation `"type": "animation"` diff --git a/lib/StartInfo.h b/lib/StartInfo.h index 5c4797acc..127a2446a 100644 --- a/lib/StartInfo.h +++ b/lib/StartInfo.h @@ -102,6 +102,7 @@ struct DLL_LINKAGE StartInfo ui32 seedPostInit; //so we know that game is correctly synced at the start; 0 if not known yet ui32 mapfileChecksum; //0 if not relevant std::string startTimeIso8601; + std::string fileURI; SimturnsInfo simturnsInfo; TurnTimerInfo turnTimerInfo; std::string mapname; // empty for random map, otherwise name of the map or savegame @@ -127,6 +128,7 @@ struct DLL_LINKAGE StartInfo h & seedPostInit; h & mapfileChecksum; h & startTimeIso8601; + h & fileURI; h & simturnsInfo; h & turnTimerInfo; h & mapname; @@ -135,7 +137,7 @@ struct DLL_LINKAGE StartInfo } StartInfo() : mode(INVALID), difficulty(1), seedToBeUsed(0), seedPostInit(0), - mapfileChecksum(0), startTimeIso8601(vstd::getDateTimeISO8601Basic(std::time(0))) + mapfileChecksum(0), startTimeIso8601(vstd::getDateTimeISO8601Basic(std::time(0))), fileURI("") { } diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp index ea7bc27b9..a5b6a9471 100644 --- a/server/CVCMIServer.cpp +++ b/server/CVCMIServer.cpp @@ -318,6 +318,7 @@ bool CVCMIServer::prepareToStartGame() case StartInfo::CAMPAIGN: logNetwork->info("Preparing to start new campaign"); si->startTimeIso8601 = vstd::getDateTimeISO8601Basic(std::time(0)); + si->fileURI = mi->fileURI; si->campState->setCurrentMap(campaignMap); si->campState->setCurrentMapBonus(campaignBonus); gh->init(si.get(), progressTracking); @@ -326,6 +327,7 @@ bool CVCMIServer::prepareToStartGame() case StartInfo::NEW_GAME: logNetwork->info("Preparing to start new game"); si->startTimeIso8601 = vstd::getDateTimeISO8601Basic(std::time(0)); + si->fileURI = mi->fileURI; gh->init(si.get(), progressTracking); break;