1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-22 22:13:35 +02:00

Merge pull request #4900 from Laserlicht/chronicles_menu

Chronicles menu
This commit is contained in:
Ivan Savenko 2024-11-15 19:15:28 +02:00 committed by GitHub
commit 90304e5c8a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 189 additions and 10 deletions

View File

@ -875,6 +875,9 @@ void SelectionTab::parseSaves(const std::unordered_set<ResourcePath> & files)
void SelectionTab::parseCampaigns(const std::unordered_set<ResourcePath> & files)
{
auto campaignSets = JsonNode(JsonPath::builtin("config/campaignSets.json"));
auto mainmenu = JsonNode(JsonPath::builtin("config/mainmenu.json"));
allItems.reserve(files.size());
for(auto & file : files)
{
@ -882,8 +885,28 @@ void SelectionTab::parseCampaigns(const std::unordered_set<ResourcePath> & files
info->fileURI = file.getOriginalName();
info->campaignInit();
info->name = info->getNameForList();
if(info->campaign)
allItems.push_back(info);
{
// skip campaigns organized in sets
std::string foundInSet = "";
for (auto const & set : campaignSets.Struct())
for (auto const & item : set.second["items"].Vector())
if(file.getName() == ResourcePath(item["file"].String()).getName())
foundInSet = set.first;
// set has to be used in main menu
bool setInMainmenu = false;
if(!foundInSet.empty())
for (auto const & item : mainmenu["window"]["items"].Vector())
if(item["name"].String() == "campaign")
for (auto const & button : item["buttons"].Vector())
if(boost::algorithm::ends_with(boost::algorithm::to_lower_copy(button["command"].String()), boost::algorithm::to_lower_copy(foundInSet)))
setInMainmenu = true;
if(!setInMainmenu)
allItems.push_back(info);
}
}
}

View File

@ -67,7 +67,8 @@ CCampaignScreen::CCampaignScreen(const JsonNode & config, std::string name)
}
for(const JsonNode & node : config[name]["items"].Vector())
campButtons.push_back(std::make_shared<CCampaignButton>(node, config, campaignSet));
if(CResourceHandler::get()->existsResource(ResourcePath(node["file"].String(), EResType::CAMPAIGN)))
campButtons.push_back(std::make_shared<CCampaignButton>(node, config, campaignSet));
}
void CCampaignScreen::activate()

View File

@ -38,6 +38,7 @@
#include "../widgets/VideoWidget.h"
#include "../windows/InfoWindows.h"
#include "../CServerHandler.h"
#include "../render/AssetGenerator.h"
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
@ -403,6 +404,9 @@ void CMainMenu::openCampaignScreen(std::string name)
{
auto const & config = CMainMenuConfig::get().getCampaigns();
AssetGenerator::createCampaignBackground();
AssetGenerator::createChroniclesCampaignImages();
if(!vstd::contains(config.Struct(), name))
{
logGlobal->error("Unknown campaign set: %s", name);
@ -413,7 +417,9 @@ void CMainMenu::openCampaignScreen(std::string name)
for (auto const & entry : config[name]["items"].Vector())
{
ResourcePath resourceID(entry["file"].String(), EResType::CAMPAIGN);
if (!CResourceHandler::get()->existsResource(resourceID))
if(entry["optional"].Bool())
continue;
if(!CResourceHandler::get()->existsResource(resourceID))
campaignsFound = false;
}

View File

@ -30,6 +30,8 @@ void AssetGenerator::generateAll()
for (int i = 0; i < PlayerColor::PLAYER_LIMIT_I; ++i)
createPlayerColoredBackground(PlayerColor(i));
createCombatUnitNumberWindow();
createCampaignBackground();
createChroniclesCampaignImages();
}
void AssetGenerator::createAdventureOptionsCleanBackground()
@ -206,3 +208,121 @@ void AssetGenerator::createCombatUnitNumberWindow()
texture->adjustPalette(shifterNeutral, ignoredMask);
texture->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePathNeutral));
}
void AssetGenerator::createCampaignBackground()
{
std::string filename = "data/CampaignBackground8.png";
if(CResourceHandler::get()->existsResource(ResourcePath(filename))) // overridden by mod, no generation
return;
if(!CResourceHandler::get("local")->createResource(filename))
return;
ResourcePath savePath(filename, EResType::IMAGE);
auto locator = ImageLocator(ImagePath::builtin("CAMPBACK"));
locator.scalingFactor = 1;
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator, EImageBlitMode::OPAQUE);
Canvas canvas = Canvas(Point(800, 600), CanvasScalingPolicy::IGNORE);
canvas.draw(img, Point(0, 0), Rect(0, 0, 800, 600));
// left image
canvas.draw(img, Point(220, 73), Rect(290, 73, 141, 115));
canvas.draw(img, Point(37, 70), Rect(87, 70, 207, 120));
// right image
canvas.draw(img, Point(513, 67), Rect(463, 67, 71, 126));
canvas.draw(img, Point(586, 71), Rect(536, 71, 207, 117));
// middle image
canvas.draw(img, Point(306, 68), Rect(86, 68, 209, 122));
// disabled fields
canvas.draw(img, Point(40, 72), Rect(313, 74, 197, 114));
canvas.draw(img, Point(310, 72), Rect(313, 74, 197, 114));
canvas.draw(img, Point(590, 72), Rect(313, 74, 197, 114));
canvas.draw(img, Point(43, 245), Rect(313, 74, 197, 114));
canvas.draw(img, Point(313, 244), Rect(313, 74, 197, 114));
canvas.draw(img, Point(586, 246), Rect(313, 74, 197, 114));
canvas.draw(img, Point(34, 417), Rect(313, 74, 197, 114));
canvas.draw(img, Point(404, 414), Rect(313, 74, 197, 114));
// skull
auto locatorSkull = ImageLocator(ImagePath::builtin("CAMPNOSC"));
locatorSkull.scalingFactor = 1;
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull, EImageBlitMode::OPAQUE);
canvas.draw(imgSkull, Point(562, 509), Rect(178, 108, 43, 19));
std::shared_ptr<IImage> image = GH.renderHandler().createImage(canvas.getInternalSurface());
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
}
void AssetGenerator::createChroniclesCampaignImages()
{
for(int i = 1; i < 9; i++)
{
std::string filename = "data/CampaignHc" + std::to_string(i) + "Image.png";
if(CResourceHandler::get()->existsResource(ResourcePath(filename))) // overridden by mod, no generation
continue;
auto imgPathBg = ImagePath::builtin("data/chronicles_" + std::to_string(i) + "/GamSelBk");
if(!CResourceHandler::get()->existsResource(imgPathBg)) // Chronicle episode not installed
continue;
if(!CResourceHandler::get("local")->createResource(filename))
continue;
ResourcePath savePath(filename, EResType::IMAGE);
auto locator = ImageLocator(imgPathBg);
locator.scalingFactor = 1;
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator, EImageBlitMode::OPAQUE);
Canvas canvas = Canvas(Point(200, 116), CanvasScalingPolicy::IGNORE);
switch (i)
{
case 1:
canvas.draw(img, Point(0, 0), Rect(149, 144, 200, 116));
break;
case 2:
canvas.draw(img, Point(0, 0), Rect(156, 150, 200, 116));
break;
case 3:
canvas.draw(img, Point(0, 0), Rect(171, 153, 200, 116));
break;
case 4:
canvas.draw(img, Point(0, 0), Rect(35, 358, 200, 116));
break;
case 5:
canvas.draw(img, Point(0, 0), Rect(216, 248, 200, 116));
break;
case 6:
canvas.draw(img, Point(0, 0), Rect(58, 234, 200, 116));
break;
case 7:
canvas.draw(img, Point(0, 0), Rect(184, 219, 200, 116));
break;
case 8:
canvas.draw(img, Point(0, 0), Rect(268, 210, 200, 116));
//skull
auto locatorSkull = ImageLocator(ImagePath::builtin("CampSP1"));
locatorSkull.scalingFactor = 1;
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull, EImageBlitMode::OPAQUE);
canvas.draw(imgSkull, Point(162, 94), Rect(162, 94, 41, 22));
canvas.draw(img, Point(162, 94), Rect(424, 304, 14, 4));
canvas.draw(img, Point(162, 98), Rect(424, 308, 10, 4));
canvas.draw(img, Point(158, 102), Rect(424, 312, 10, 4));
canvas.draw(img, Point(154, 106), Rect(424, 316, 10, 4));
break;
}
std::shared_ptr<IImage> image = GH.renderHandler().createImage(canvas.getInternalSurface());
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
}
}

View File

@ -21,4 +21,6 @@ public:
static void createBigSpellBook();
static void createPlayerColoredBackground(const PlayerColor & player);
static void createCombatUnitNumberWindow();
static void createCampaignBackground();
static void createChroniclesCampaignImages();
};

View File

@ -47,5 +47,21 @@
{ "id": 6, "x":34, "y":417, "file":"DATA/FINAL", "image":"CAMPUA1", "video":"UNHOLY", "requires": [4] },
{ "id": 7, "x":404, "y":414, "file":"DATA/SECRET", "image":"CAMPSP1", "video":"SPECTRE", "requires": [6] }
]
},
"chr":
{
"images" : [ {"x": 0, "y": 0, "name":"data/CampaignBackground8"} ],
"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN" },
"items":
[
{ "id": 1, "x":40, "y":72, "file":"Maps/Chronicles/Hc1_Main", "image":"CampaignHc1Image", "video":"", "requires": [], "optional": true },
{ "id": 2, "x":310, "y":72, "file":"Maps/Chronicles/Hc2_Main", "image":"CampaignHc2Image", "video":"", "requires": [], "optional": true },
{ "id": 3, "x":590, "y":72, "file":"Maps/Chronicles/Hc3_Main", "image":"CampaignHc3Image", "video":"", "requires": [], "optional": true },
{ "id": 4, "x":43, "y":245, "file":"Maps/Chronicles/Hc4_Main", "image":"CampaignHc4Image", "video":"", "requires": [], "optional": true },
{ "id": 5, "x":313, "y":244, "file":"Maps/Chronicles/Hc5_Main", "image":"CampaignHc5Image", "video":"", "requires": [], "optional": true },
{ "id": 6, "x":586, "y":244, "file":"Maps/Chronicles/Hc6_Main", "image":"CampaignHc6Image", "video":"", "requires": [], "optional": true },
{ "id": 7, "x":34, "y":413, "file":"Maps/Chronicles/Hc7_Main", "image":"CampaignHc7Image", "video":"", "requires": [], "optional": true },
{ "id": 8, "x":404, "y":414, "file":"Maps/Chronicles/Hc8_Main", "image":"CampaignHc8Image", "video":"", "requires": [], "optional": true }
]
}
}

View File

@ -9,10 +9,10 @@
VCMI is an open-source recreation of Heroes of Might & Magic III engine, giving it new and extended possibilities.
<p>
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.3.0/Castle%20Siege.jpg?raw=true" alt="Vanilla town siege in extended window" style="height:120px;"/>
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.3.0/Town%20Screen%20with%20Radial%20Menu.jpg?raw=true" alt="Vanilla town view with radial menu for touchscreen devices" style="height:120px;"/>
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.4.0/Big%20spellbook.jpg?raw=true" alt="Large Spellbook with German translation" style="height:120px;"/>
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.4.0/Quick%20Hero%20Select%20Bastion.jpg?raw=true" alt="New widget for Hero selection, featuring Pavillon Town" style="height:120px;"/>
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.3.0/Castle%20Siege.jpg?raw=true" alt="Vanilla town siege in extended window" style="height:120px;"/>
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.3.0/Town%20Screen%20with%20Radial%20Menu.jpg?raw=true" alt="Vanilla town view with radial menu for touchscreen devices" style="height:120px;"/>
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.4.0/Big%20spellbook.jpg?raw=true" alt="Large Spellbook with German translation" style="height:120px;"/>
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.4.0/Quick%20Hero%20Select%20Bastion.jpg?raw=true" alt="New widget for Hero selection, featuring Pavillon Town" style="height:120px;"/>
</p>
@ -37,10 +37,12 @@ Please see corresponding installation guide articles for details for your platfo
- [Android](players/Installation_Android.md)
- [iOS](players/Installation_iOS.md)
See also installation guide for [Heroes Chronicles](players/Heroes_Chronicles.md).
<p>
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.4.0/Antagarich%20Burning%20Battle.jpg?raw=true" alt="Forge Town in battle" style="height:120px;"/>
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.4.0/Town%20and%20Unit.jpg?raw=true" alt="Asylum town with new creature dialog" style="height:120px;"/>
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.4.0/Siege.jpg?raw=true" alt="Ruins town siege" style="height:120px;"/>
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.4.0/Antagarich%20Burning%20Battle.jpg?raw=true" alt="Forge Town in battle" style="height:120px;"/>
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.4.0/Town%20and%20Unit.jpg?raw=true" alt="Asylum town with new creature dialog" style="height:120px;"/>
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.4.0/Siege.jpg?raw=true" alt="Ruins town siege" style="height:120px;"/>
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.4.0/Editor.jpg?raw=true" alt="Map editor" style="height:120px;"/>
</p>

View File

@ -0,0 +1,9 @@
# Heroes Chronicles
It also possible to play the Heroes Chronicles with VCMI. You still need a completly installed VCMI (with heroes 3 sod / complete files).
You also need Heroes Chronicles from [gog.com](https://www.gog.com/en/game/heroes_chronicles_all_chapters). You need to download the offline installer. CD installations are not supported yet.
You can use the "Install file" button in the launcher to select the downloaded exe files. This process can take a while (especially on mobile platforms) and need some temporary free space.
After that you can select Heroes Chronicles from Campaign selection menu (button or custom campaign).