1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-07 00:58:39 +02:00

Improved Main menu

1) Added option to use custom logo and sublogo on Main menu, Scenario selection and Loading screen
2) Added option to use custom loading bar frame on Loading screen
This commit is contained in:
George King
2025-01-31 14:20:10 +01:00
committed by GitHub
parent 9754e72063
commit 26eac7d82b
5 changed files with 124 additions and 37 deletions

View File

@ -93,13 +93,27 @@ CSelectionBase::CSelectionBase(ESelectionScreen type)
if(screenType == ESelectionScreen::campaignList) if(screenType == ESelectionScreen::campaignList)
{ {
setBackground(ImagePath::builtin("CamCust.bmp")); setBackground(ImagePath::builtin("CamCust.bmp"));
pos = background->center();
} }
else else
{ {
const JsonVector & bgNames = CMainMenuConfig::get().getConfig()["game-select"].Vector(); const JsonNode& gameSelectConfig = CMainMenuConfig::get().getConfig()["scenario-selection"];
const JsonVector& bgNames = gameSelectConfig["background"].Vector();
setBackground(ImagePath::fromJson(*RandomGeneratorUtil::nextItem(bgNames, CRandomGenerator::getDefault()))); setBackground(ImagePath::fromJson(*RandomGeneratorUtil::nextItem(bgNames, CRandomGenerator::getDefault())));
pos = background->center();
// Set logo
const auto& logoConfig = gameSelectConfig["logo"];
if (!logoConfig.isNull() && logoConfig["name"].isVector() && !logoConfig["name"].Vector().empty())
logo = std::make_shared<CPicture>(ImagePath::fromJson(*RandomGeneratorUtil::nextItem(logoConfig["name"].Vector(), CRandomGenerator::getDefault())), Point(logoConfig["x"].Integer(), logoConfig["y"].Integer()));
// Set sublogo
const auto& sublogoConfig = gameSelectConfig["sublogo"];
if (!sublogoConfig.isNull() && sublogoConfig["name"].isVector() && !sublogoConfig["name"].Vector().empty())
sublogo = std::make_shared<CPicture>(ImagePath::fromJson(*RandomGeneratorUtil::nextItem(sublogoConfig["name"].Vector(), CRandomGenerator::getDefault())), Point(sublogoConfig["x"].Integer(), sublogoConfig["y"].Integer()));
} }
pos = background->center();
card = std::make_shared<InfoCard>(); card = std::make_shared<InfoCard>();
buttonBack = std::make_shared<CButton>(Point(581, 535), AnimationPath::builtin("SCNRBACK.DEF"), CGI->generaltexth->zelp[105], [=](){ close();}, EShortcut::GLOBAL_CANCEL); buttonBack = std::make_shared<CButton>(Point(581, 535), AnimationPath::builtin("SCNRBACK.DEF"), CGI->generaltexth->zelp[105], [=](){ close();}, EShortcut::GLOBAL_CANCEL);
} }

View File

@ -71,6 +71,9 @@ public:
std::shared_ptr<CButton> buttonBack; std::shared_ptr<CButton> buttonBack;
std::shared_ptr<CButton> buttonSimturns; std::shared_ptr<CButton> buttonSimturns;
std::shared_ptr<CPicture> logo;
std::shared_ptr<CPicture> sublogo;
std::shared_ptr<SelectionTab> tabSel; std::shared_ptr<SelectionTab> tabSel;
std::shared_ptr<OptionsTab> tabOpt; std::shared_ptr<OptionsTab> tabOpt;
std::shared_ptr<TurnOptionsTab> tabTurnOptions; std::shared_ptr<TurnOptionsTab> tabTurnOptions;

View File

@ -88,6 +88,18 @@ CMenuScreen::CMenuScreen(const JsonNode & configNode)
pos = background->center(); pos = background->center();
const auto& logoConfig = config["logo"];
if (!logoConfig.isNull() && logoConfig["name"].isVector() && !logoConfig["name"].Vector().empty()) {
auto logoImage = std::make_shared<CPicture>(ImagePath::fromJson(*RandomGeneratorUtil::nextItem(logoConfig["name"].Vector(), CRandomGenerator::getDefault())), Point(logoConfig["x"].Integer(), logoConfig["y"].Integer()));
images.push_back(logoImage);
}
const auto& sublogoConfig = config["sublogo"];
if (!sublogoConfig.isNull() && sublogoConfig["name"].isVector() && !sublogoConfig["name"].Vector().empty()) {
auto logoImage = std::make_shared<CPicture>(ImagePath::fromJson(*RandomGeneratorUtil::nextItem(sublogoConfig["name"].Vector(), CRandomGenerator::getDefault())), Point(sublogoConfig["x"].Integer(), sublogoConfig["y"].Integer()));
images.push_back(logoImage);
}
if(!config["video"].isNull()) if(!config["video"].isNull())
{ {
Point videoPosition(config["video"]["x"].Integer(), config["video"]["y"].Integer()); Point videoPosition(config["video"]["x"].Integer(), config["video"]["y"].Integer());
@ -300,8 +312,8 @@ CMainMenuConfig::CMainMenuConfig()
: campaignSets(JsonPath::builtin("config/campaignSets.json")) : campaignSets(JsonPath::builtin("config/campaignSets.json"))
, config(JsonPath::builtin("config/mainmenu.json")) , config(JsonPath::builtin("config/mainmenu.json"))
{ {
if (config["game-select"].Vector().empty()) if (!config["scenario-selection"].isStruct())
handleFatalError("Main menu config is invalid or corrupted. Please disable any mods or reinstall VCMI", false); handleFatalError("The main menu configuration file mainmenu.json is invalid or corrupted. Please check the file for errors, verify your mod setup, or reinstall VCMI to resolve the issue.", false);
} }
const CMainMenuConfig & CMainMenuConfig::get() const CMainMenuConfig & CMainMenuConfig::get()
@ -502,15 +514,6 @@ CMultiMode::CMultiMode(ESelectionScreen ScreenType)
if (multiplayerConfig.isVector() && !multiplayerConfig.Vector().empty()) if (multiplayerConfig.isVector() && !multiplayerConfig.Vector().empty())
picture = std::make_shared<CPicture>(ImagePath::fromJson(*RandomGeneratorUtil::nextItem(multiplayerConfig.Vector(), CRandomGenerator::getDefault())), 16, 77); picture = std::make_shared<CPicture>(ImagePath::fromJson(*RandomGeneratorUtil::nextItem(multiplayerConfig.Vector(), CRandomGenerator::getDefault())), 16, 77);
if (multiplayerConfig.isString())
picture = std::make_shared<CPicture>(ImagePath::fromJson(multiplayerConfig), 16, 77);
if (!picture)
{
picture = std::make_shared<CPicture>(ImagePath::builtin("MUMAP.bmp"), 16, 77);
logGlobal->error("Failed to load multiplayer picture");
}
textTitle = std::make_shared<CTextBox>("", Rect(7, 18, 440, 50), 0, FONT_BIG, ETextAlignment::CENTER, Colors::WHITE); textTitle = std::make_shared<CTextBox>("", Rect(7, 18, 440, 50), 0, FONT_BIG, ETextAlignment::CENTER, Colors::WHITE);
textTitle->setText(CGI->generaltexth->zelp[263].second); textTitle->setText(CGI->generaltexth->zelp[263].second);
@ -729,25 +732,51 @@ CLoadingScreen::CLoadingScreen(ImagePath background)
CCS->musich->stopMusic(5000); CCS->musich->stopMusic(5000);
const auto& conf = CMainMenuConfig::get().getConfig()["loading"]; const auto& conf = CMainMenuConfig::get().getConfig()["loading"];
const auto& nameConfig = conf["name"];
AnimationPath animationPath; // Load background
if (nameConfig.isVector() && !nameConfig.Vector().empty()) const auto& backgroundConfig = conf["background"];
animationPath = AnimationPath::fromJson(*RandomGeneratorUtil::nextItem(nameConfig.Vector(), CRandomGenerator::getDefault())); if (backgroundConfig.isVector() && !backgroundConfig.Vector().empty())
this->background = std::make_shared<CPicture>(ImagePath::fromJson(*RandomGeneratorUtil::nextItem(backgroundConfig.Vector(), CRandomGenerator::getDefault())));
if (nameConfig.isString()) // Load logo
animationPath = AnimationPath::fromJson(nameConfig); const auto& logoConfig = conf["logo"];
if (!logoConfig.isNull() && logoConfig["name"].isVector() && !logoConfig["name"].Vector().empty()) {
this->logo = std::make_shared<CPicture>(
ImagePath::fromJson(*RandomGeneratorUtil::nextItem(logoConfig["name"].Vector(), CRandomGenerator::getDefault())),
Point(logoConfig["x"].Integer(), logoConfig["y"].Integer())
);
}
if (conf.isStruct()) // Load sublogo
{ const auto& sublogoConfig = conf["sublogo"];
const int posx = conf["x"].Integer(); if (!sublogoConfig.isNull() && sublogoConfig["name"].isVector() && !sublogoConfig["name"].Vector().empty()) {
const int posy = conf["y"].Integer(); this->sublogo = std::make_shared<CPicture>(
const int blockSize = conf["size"].Integer(); ImagePath::fromJson(*RandomGeneratorUtil::nextItem(sublogoConfig["name"].Vector(), CRandomGenerator::getDefault())),
const int blocksAmount = conf["amount"].Integer(); Point(sublogoConfig["x"].Integer(), sublogoConfig["y"].Integer())
);
for (int i = 0; i < blocksAmount; ++i) }
// Load loadframe
const auto& loadframeConfig = conf["loadframe"];
if (loadframeConfig.isStruct()) {
this->loadFrame = std::make_shared<CPicture>(
ImagePath::fromJson(*RandomGeneratorUtil::nextItem(loadframeConfig["name"].Vector(), CRandomGenerator::getDefault())),
loadframeConfig["x"].Integer(),
loadframeConfig["y"].Integer()
);
}
// Load loadbar
const auto& loadbarConfig = conf["loadbar"];
if (loadbarConfig.isStruct()) {
AnimationPath loadbarPath = AnimationPath::fromJson(*RandomGeneratorUtil::nextItem(loadbarConfig["name"].Vector(), CRandomGenerator::getDefault()));
const int posx = loadbarConfig["x"].Integer();
const int posy = loadbarConfig["y"].Integer();
const int blockSize = loadbarConfig["size"].Integer();
const int blocksAmount = loadbarConfig["amount"].Integer();
for (int i = 0; i < blocksAmount; ++i)
{ {
progressBlocks.push_back(std::make_shared<CAnimImage>(animationPath, i, 0, posx + i * blockSize, posy)); progressBlocks.push_back(std::make_shared<CAnimImage>(loadbarPath, i, 0, posx + i * blockSize, posy));
progressBlocks.back()->deactivate(); progressBlocks.back()->deactivate();
progressBlocks.back()->visible = false; progressBlocks.back()->visible = false;
} }

View File

@ -192,7 +192,10 @@ public:
class CLoadingScreen : virtual public CWindowObject, virtual public Load::Progress class CLoadingScreen : virtual public CWindowObject, virtual public Load::Progress
{ {
std::vector<std::shared_ptr<CAnimImage>> progressBlocks; std::vector<std::shared_ptr<CAnimImage>> progressBlocks;
std::shared_ptr<CPicture> loadFrame;
std::shared_ptr<CPicture> logo;
std::shared_ptr<CPicture> sublogo;
ImagePath getBackground(); ImagePath getBackground();
public: public:

View File

@ -1,22 +1,60 @@
{ {
//images used in game selection screen //images used in game selection screen
"game-select" : ["gamselb0", "gamselb1"], "scenario-selection" :
{
//Loading screen background and progress bar "background" : ["gamselb0", "gamselb1"],
//"logo": {
// "name": ["logo/logo0", "logo/logo1", "logo/logo2"],
// "x": 20, "y": 20
//},
//"sublogo": {
// "name": ["sublogo/sublogo0", "sublogo/sublogo1", "sublogo/sublogo2"],
// "x": 20, "y": 120
//}
},
"loading" : "loading" :
{ {
"background" : ["loadbar"], "background" : ["loadbar"],
"x": 395, "y": 548, "size": 18, "amount": 20,
"name": "loadprog" "loadbar" : {
"name": ["loadprog"],
"x": 395, "y": 548, "size": 18, "amount": 20,
},
//"loadframe" : {
// "name": ["loadframe0", "loadframe1", "loadframe2", "loadframe3"],
// "x": 390, "y": 543
//},
//
//"logo": {
// "name": ["logo/logo0", "logo/logo1", "logo/logo2"],
// "x": 20, "y": 20
//},
//"sublogo": {
// "name": ["sublogo/sublogo0", "sublogo/sublogo1", "sublogo/sublogo2"],
// "x": 20, "y": 120
//}
}, },
//Multiplayer selection image
"multiplayer" : ["mumap"], "multiplayer" : ["mumap"],
//Main menu window, consists of several sub-menus aka items //Main menu window, consists of several sub-menus aka items
"window": "window":
{ {
"background" : "gamselbk", "background" : ["gamselbk"],
/// Left side logos
//"logo": {
// "name": ["logo/logo0", "logo/logo1", "logo/logo2"],
// "x": 20, "y": 20
//},
//"sublogo": {
// "name": ["sublogo/sublogo0", "sublogo/sublogo1", "sublogo/sublogo2"],
// "x": 20, "y": 120
//},
//"scalable" : true, //background will be scaled to screen size //"scalable" : true, //background will be scaled to screen size
//"video" : {"x": 8, "y": 105, "name":"CREDITS.SMK" },//Floating WoG logo. Disabled due to different position in various versions of H3. //"video" : {"x": 8, "y": 105, "name":"CREDITS.SMK" },//Floating WoG logo. Disabled due to different position in various versions of H3.
//"images" : [],//Optional, contains any additional images in the same format as video //"images" : [],//Optional, contains any additional images in the same format as video