1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-13 01:20:34 +02:00

Merge pull request #5560 from GeorgeK1ng/campaigns

[1.7] Campaigns configurations improvements
This commit is contained in:
Ivan Savenko
2025-04-02 13:54:50 +03:00
committed by GitHub
30 changed files with 285 additions and 71 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,20 @@
{
"basepath" : "campaigns/",
"images" :
[
{
"frame": 0,
"file" : "arrow-back-normal"
},
{
"frame": 1,
"file" : "arrow-back-down"
},
{
"frame": 2,
"file" : "arrow-back-hover"
}
]
}

View File

@ -0,0 +1,20 @@
{
"basepath" : "campaigns/",
"images" :
[
{
"frame": 0,
"file" : "arrow-next-normal"
},
{
"frame": 1,
"file" : "arrow-next-down"
},
{
"frame": 2,
"file" : "arrow-next-hover"
}
]
}

View File

@ -226,7 +226,6 @@
"vcmi.lobby.pvp.versus" : "对战",
"vcmi.client.errors.invalidMap" : "{非法地图或战役}\n\n启动游戏失败,选择的地图或者战役,无效或被污染。原因:\n%s",
"vcmi.client.errors.missingCampaigns" : "{找不到数据文件}\n\n没有找到战役数据文件!你可能使用了不完整或损坏的英雄无敌3数据文件,请重新安装数据文件。",
"vcmi.client.errors.modLoadingFailure" : "{加载mod失败}\n\n加载mod发生致命错误!游戏可能无法正常进行,也可能崩溃。请升级或禁用下列mod:\n\n",
"vcmi.server.errors.disconnected" : "{网络错误}\n\n与游戏服务器的连接已断开!",
"vcmi.server.errors.playerLeft" : "{玩家离开}\n\n%s玩家已断开游戏!", //%s -> player color

View File

@ -179,6 +179,7 @@
"vcmi.lobby.match.duel" : "Hra s %s", // %s -> nickname of another player
"vcmi.lobby.match.multi" : "%d hráčů",
"vcmi.lobby.room.create.hover" : "Vytvořit novou místnost",
"vcmi.lobby.room.create.help" : "Vytvoř novou místnost v online lobby, ke které se mohou připojit ostatní hráči.",
"vcmi.lobby.room.players.limit" : "Omezení počtu hráčů",
"vcmi.lobby.room.description.public" : "Jakýkoliv hráč se může připojit do veřejné místnosti.",
"vcmi.lobby.room.description.private" : "Pouze pozvaní hráči se mohou připojit do soukromé místnosti.",
@ -201,6 +202,8 @@
"vcmi.lobby.preview.error.mods" : "Použváte jinou sadu modifikací.",
"vcmi.lobby.preview.error.version" : "Používáte jinou verzi VCMI.",
"vcmi.lobby.channel.add" : "Přidat kanál",
"vcmi.lobby.channel.sendMessage.hover" : "Odeslat zprávu",
"vcmi.lobby.channel.sendMessage.help" : "Odeslat zprávu",
"vcmi.lobby.room.new" : "Nová hra",
"vcmi.lobby.room.load" : "Načíst hru",
"vcmi.lobby.room.type" : "Druh místnosti",
@ -223,7 +226,6 @@
"vcmi.lobby.pvp.versus" : "vs.",
"vcmi.client.errors.invalidMap" : "{Neplatná mapa nebo kampaň}\n\nChyba při startu hry! Vybraná mapa nebo kampaň může být neplatná nebo poškozená. Důvod:\n%s",
"vcmi.client.errors.missingCampaigns" : "{Chybějící datové soubory}\n\nDatové soubory kampaně nebyly nalezeny! Možná máte nekompletní nebo poškozené datové soubory Heroes 3. Prosíme, přeinstalujte hru.",
"vcmi.client.errors.modLoadingFailure" : "{Chyba při načítání modifikací}\n\nPři načítání modifikací byly nalezeny kritické problémy! Hra nemusí fungovat správně nebo může spadnout! Aktualizujte nebo deaktivujte následující modifikace:\n\n",
"vcmi.server.errors.disconnected" : "{Chyba sítě}\n\nPřipojení k hernímu serveru bylo ztraceno!",
"vcmi.server.errors.playerLeft" : "{Hráč opustil hru}\n\nHráč %s se odpojil ze hry!", //%s -> player color

View File

@ -226,7 +226,6 @@
"vcmi.lobby.pvp.versus" : "vs.",
"vcmi.client.errors.invalidMap" : "{Invalid map or campaign}\n\nFailed to start game! Selected map or campaign might be invalid or corrupted. Reason:\n%s",
"vcmi.client.errors.missingCampaigns" : "{Missing data files}\n\nCampaigns data files were not found! You may be using incomplete or corrupted Heroes 3 data files. Please reinstall game data.",
"vcmi.client.errors.modLoadingFailure" : "{Mod loading failure}\n\nCritical issues found when loading mods! Game may not work correctly or crash! Please update or disable following mods:\n\n",
"vcmi.server.errors.disconnected" : "{Network Error}\n\nConnection to game server has been lost!",
"vcmi.server.errors.playerLeft" : "{Player Left}\n\n%s player have disconnected from the game!", //%s -> player color

View File

@ -226,7 +226,6 @@
"vcmi.lobby.pvp.versus" : "vs.",
"vcmi.client.errors.invalidMap" : "{Ungültige Karte oder Kampagne}\n\nDas Spiel konnte nicht gestartet werden! Die ausgewählte Karte oder Kampagne ist möglicherweise ungültig oder beschädigt. Grund:\n%s",
"vcmi.client.errors.missingCampaigns" : "{Fehlende Dateien}\n\nEs wurden keine Kampagnendateien gefunden! Möglicherweise verwendest du unvollständige oder beschädigte Heroes 3 Datendateien. Bitte installiere die Spieldaten neu.",
"vcmi.client.errors.modLoadingFailure" : "{Mod Ladefehler}\n\nKritische Probleme beim Laden von Mods gefunden! Das Spiel könnte nicht korrekt funktionieren oder abstürzen! Bitte aktualisiere oder deaktiviere folgende Mods:\n\n",
"vcmi.server.errors.disconnected" : "{Netzwerkfehler}\n\nDie Verbindung zum Spielserver wurde unterbrochen!",
"vcmi.server.errors.playerLeft" : "{Verlassen eines Spielers}\n\n%s Spieler hat die Verbindung zum Spiel unterbrochen!", //%s -> player color

View File

@ -219,7 +219,6 @@
"vcmi.lobby.pvp.versus" : "vs.",
"vcmi.client.errors.invalidMap" : "{Érvénytelen térkép vagy kampány}\n\nNem sikerült elindítani a játékot! A kiválasztott térkép vagy kampány érvénytelen vagy sérült lehet. Indok:\n%s",
"vcmi.client.errors.missingCampaigns" : "{Hiányzó adatfájlok}\n\nNem találhatók kampány adatfájlok! Lehet, hogy hiányos vagy sérült Heroes 3 adatfájlokat használ. Telepítse újra az adatokat.",
"vcmi.client.errors.modLoadingFailure" : "{Mod betöltési hiba}\n\nKritikus problémák léptek fel a modok betöltésekor! A játék nem működhet megfelelően, vagy összeomolhat! Frissítse vagy tiltsa le az alábbi modokat:\n\n",
"vcmi.server.errors.disconnected" : "{Hálózati hiba}\n\nA kapcsolat a játékszerverrel megszakadt!",
"vcmi.server.errors.playerLeft" : "{Játékos kilépett}\n\n%s játékos kilépett a játékból!", //%s -> player color

View File

@ -221,7 +221,6 @@
"vcmi.lobby.pvp.versus" : "vs.",
"vcmi.client.errors.invalidMap" : "{Mappa o campagna non valida}\n\nImpossibile avviare la partita! La mappa o la campagna selezionata potrebbe essere non valida o corrotta. Motivo:\n%s",
"vcmi.client.errors.missingCampaigns" : "{File dati mancanti}\n\nI file dati delle campagne non sono stati trovati! Potresti avere file dati incompleti o corrotti di Heroes 3. Reinstalla i dati del gioco.",
"vcmi.client.errors.modLoadingFailure" : "{Errore di caricamento delle mod}\n\nSono stati rilevati problemi critici durante il caricamento delle mod! Il gioco potrebbe non funzionare correttamente o bloccarsi! Aggiorna o disattiva le seguenti mod:\n\n",
"vcmi.server.errors.disconnected" : "{Errore di rete}\n\nLa connessione al server di gioco è stata persa!",
"vcmi.server.errors.playerLeft" : "{Giocatore disconnesso}\n\nIl giocatore %s si è disconnesso dalla partita!", //%s -> player color

View File

@ -221,7 +221,6 @@
"vcmi.lobby.deleteUnsupportedSave" : "{Znaleziono niekompatybilne zapisy gry}\n\nVCMI wykrył %d zapisów gry, które nie są już wspierane. Prawdopodobnie ze względu na różne wersje gry.\n\nCzy chcesz je usunąć?",
"vcmi.client.errors.invalidMap" : "{Błędna mapa lub kampania}\n\nNie udało się stworzyć gry! Wybrana mapa lub kampania jest niepoprawna lub uszkodzona. Powód:\n%s",
"vcmi.client.errors.missingCampaigns" : "{Brakujące pliki gry}\n\nPliki kampanii nie zostały znalezione! Możliwe że używasz niekompletnych lub uszkodzonych plików Heroes 3. Spróbuj ponownej instalacji plików gry.",
"vcmi.server.errors.disconnected" : "{Błąd sieciowy}\n\nUtracono połączenie z serwerem!",
"vcmi.server.errors.playerLeft" : "{Rozłączenie z graczem}\n\n%s opuścił rozgrywkę!", //%s -> player color
"vcmi.server.errors.existingProcess" : "Inny proces 'vcmiserver' został już uruchomiony, zakończ go nim przejdziesz dalej",

View File

@ -220,7 +220,6 @@
"vcmi.lobby.pvp.versus" : "vs.",
"vcmi.client.errors.invalidMap" : "{Mapa ou campanha inválido}\n\nFalha ao iniciar o jogo! O mapa ou campanha selecionado pode ser inválido ou corrompido. Motivo:\n%s",
"vcmi.client.errors.missingCampaigns" : "{Arquivos de dados ausentes}\n\nOs arquivos de dados das campanhas não foram encontrados! Você pode estar usando arquivos de dados incompletos ou corrompidos do Heroes 3. Por favor, reinstale os dados do jogo.",
"vcmi.client.errors.modLoadingFailure" : "{Falha ao carregar mod}\n\nProblemas críticos encontrados ao carregar mods! O jogo pode não funcionar corretamente ou travar! Por favor, atualize ou desative os seguintes mods:\n\n",
"vcmi.server.errors.disconnected" : "{Erro de Rede}\n\nA conexão com o servidor do jogo foi perdida!",
"vcmi.server.errors.playerLeft" : "{Jogador Saiu}\n\nO jogador %s desconectou-se do jogo!", //%s -> player color

View File

@ -218,7 +218,6 @@
"vcmi.lobby.pvp.randomTownVs.help" : "Написать в чате два случайных города",
"vcmi.lobby.pvp.versus" : "против",
"vcmi.client.errors.invalidMap" : "{Недопустимая карта или кампания}\n\nНе удалось запустить игру! Возможно, выбранная карта или кампания недействительны или повреждены. Причина:\n%s",
"vcmi.client.errors.missingCampaigns" : "{Отсутствуют файлы данных}\n\nФайлы данных кампаний не найдены! Возможно, вы используете неполные или поврежденные файлы данных Heroes 3. Пожалуйста, переустановите игровые данные.",
"vcmi.client.errors.modLoadingFailure" : "{Ошибка загрузки модов}\n\nПри загрузке модов обнаружены серьезные проблемы! Игра может работать некорректно или вылетать! Пожалуйста, обновите или отключите следующие моды:\n\n",
"vcmi.server.errors.disconnected" : "{Сетевая ошибка}\n\nПодключение к игровому серверу потеряно!",
"vcmi.server.errors.playerLeft" : "{Игрок вышел}\n\n%s игрок отключился от игры!", //%s -> player color

View File

@ -72,7 +72,6 @@
"vcmi.lobby.sortDate" : "Ordena los mapas por la fecha de modificación",
"vcmi.client.errors.invalidMap" : "{Mapa o Campaña invalido}\n\n¡No se pudo iniciar el juego! El mapa o la campaña seleccionados pueden no ser válidos o estar dañados. Motivo:\n%s",
"vcmi.client.errors.missingCampaigns" : "{Archivos de datos faltantes}\n\n¡No se encontraron los archivos de datos de las campañas! Quizás estés utilizando archivos de datos incompletos o dañados de Heroes 3. Por favor, reinstala los datos del juego.",
"vcmi.server.errors.existingProcess" : "Otro servidor VCMI está en ejecución. Por favor, termínalo antes de comenzar un nuevo juego.",
"vcmi.server.errors.modsToEnable" : "{Se requieren los siguientes mods}",
"vcmi.server.errors.modsToDisable" : "{Deben desactivarse los siguientes mods}",

View File

@ -223,7 +223,6 @@
"vcmi.lobby.pvp.versus" : "vs.",
"vcmi.client.errors.invalidMap" : "{Ogiltig karta eller kampanj}\n\nMisslyckades med att starta spelet! Vald karta eller kampanj kan vara ogiltig eller skadad. Orsak:\n%s",
"vcmi.client.errors.missingCampaigns" : "{Saknade datafiler}\n\nDatafiler för kampanjen hittades inte! Du kanske använder ofullständiga eller skadade Heroes 3-datafiler. Vänligen installera om speldata.",
"vcmi.client.errors.modLoadingFailure": "{Moddladdningsfel}\n\nKritiska fel upptäcktes vid laddning av moddar! Spelet kanske inte fungerar korrekt eller kraschar! Vänligen uppdatera eller inaktivera följande moddar:\n\n",
"vcmi.server.errors.disconnected" : "{Nätverksfel}\n\nAnslutningen till spelservern har förlorats!",
"vcmi.server.errors.playerLeft" : "{Spelare har lämnat}\n\n%s-spelare har kopplat bort sig från spelet!", //%s -> spelarens färg

View File

@ -226,7 +226,6 @@
"vcmi.lobby.pvp.versus" : "проти",
"vcmi.client.errors.invalidMap" : "{Пошкоджена карта або кампанія}\n\nНе вдалося запустити гру! Вибрана карта або кампанія може бути невірною або пошкодженою. Причина:\n%s",
"vcmi.client.errors.missingCampaigns" : "{Не вистачає файлів даних}\n\nФайли даних кампаній не знайдено! Можливо, ви використовуєте неповні або пошкоджені файли даних Heroes 3. Будь ласка, перевстановіть дані гри.",
"vcmi.client.errors.modLoadingFailure" : "{Помилка завантаження модифікації}\n\nВиявлено критичні проблеми при завантаженні модифікацій! Гра може працювати некоректно або аварійно завершитись! Будь ласка, оновіть або вимкніть наступні моди:\n\n",
"vcmi.server.errors.disconnected" : "{Помилка мережі}\n\nВтрачено зв'язок з сервером гри!",
"vcmi.server.errors.playerLeft" : "{Гравець покинув гру}\n\n%s гравець від'єднався від гри!", //%s -> player color

View File

@ -219,7 +219,6 @@
"vcmi.lobby.pvp.versus" : "vs.",
"vcmi.client.errors.invalidMap" : "{Bản đồ hoặc chiến dịch không hợp lệ}\n\nKhông thể bắt đầu trò chơi! Bản đồ hoặc chiến dịch đã chọn có thể không hợp lệ hoặc bị lỗi như sau:\n%s",
"vcmi.client.errors.missingCampaigns" : "{Thiếu tệp tin dữ liệu}\n\nKhông tìm thấy tệp tin dữ liệu của chiến dịch! Có thể bạn đang sử dụng các tệp tin dữ liệu Heroes 3 bị thiếu hoặc bị lỗi. Hãy thử cài đặt lại trò chơi.",
"vcmi.client.errors.modLoadingFailure" : "{Lỗi tải mod}\n\nĐã phát hiện ra lỗi nghiêm trọng khi tải mod! Trò chơi có thể không hoạt động chính xác hoặc bị văng! Hãy cập nhật hoặc tắt các mod sau:\n\n",
"vcmi.server.errors.disconnected" : "{Mạng bị lỗi}\n\nĐã mất kết nối tới máy chủ trò chơi!",
"vcmi.server.errors.playerLeft" : "{Người chơi}\n\n%s đã ngắt kết nối khỏi trò chơi!", //%s -> màu của người chơi

View File

@ -65,6 +65,10 @@ enum class EShortcut
MAIN_MENU_CAMPAIGN_ROE,
MAIN_MENU_CAMPAIGN_AB,
MAIN_MENU_CAMPAIGN_CUSTOM,
MAIN_MENU_CAMPAIGN_CHR,
MAIN_MENU_CAMPAIGN_HOTA,
MAIN_MENU_CAMPAIGN_WOG,
MAIN_MENU_CAMPAIGN_VCMI,
MAIN_MENU_HOTSEAT,
MAIN_MENU_LOBBY,

View File

@ -150,6 +150,10 @@ EShortcut ShortcutHandler::findShortcut(const std::string & identifier ) const
{"mainMenuCampaignRoe", EShortcut::MAIN_MENU_CAMPAIGN_ROE },
{"mainMenuCampaignAb", EShortcut::MAIN_MENU_CAMPAIGN_AB },
{"mainMenuCampaignCustom", EShortcut::MAIN_MENU_CAMPAIGN_CUSTOM },
{"mainMenuCampaignChr", EShortcut::MAIN_MENU_CAMPAIGN_CHR },
{"mainMenuCampaignHota", EShortcut::MAIN_MENU_CAMPAIGN_HOTA },
{"mainMenuCampaignWog", EShortcut::MAIN_MENU_CAMPAIGN_WOG },
{"mainMenuCampaignVCMI", EShortcut::MAIN_MENU_CAMPAIGN_VCMI },
{"mainMenuLobby", EShortcut::MAIN_MENU_LOBBY },
{"lobbyBeginStandardGame", EShortcut::LOBBY_BEGIN_STANDARD_GAME },
{"lobbyBeginCampaign", EShortcut::LOBBY_BEGIN_CAMPAIGN },

View File

@ -48,10 +48,33 @@ CCampaignScreen::CCampaignScreen(const JsonNode & config, std::string name)
{
OBJECT_CONSTRUCTION;
for(const JsonNode & node : config[name]["images"].Vector())
const auto& campaigns = config[name]["items"].Vector();
// Define mapping of background name -> campaigns per page
const std::unordered_map<std::string, int> campaignsPerPageMap = {
{"CampaignBackground4", 4},
{"CampaignBackground5", 5},
{"CampaignBackground6", 6},
{"CampaignBackground7", 7},
{"CAMPBACK", 7},
{"CAMPBKX2", 7},
{"CampaignBackground8", 8}
};
// Process images and check if name is in the map
for (const JsonNode& node : config[name]["images"].Vector())
{
images.push_back(CMainMenu::createPicture(node));
if(!images.empty())
std::string imageName = node["name"].String();
auto it = campaignsPerPageMap.find(imageName);
if (it != campaignsPerPageMap.end())
{
campaignsPerPage = it->second;
}
}
if (!images.empty())
{
images[0]->center(); // move background to center
moveTo(images[0]->pos.topLeft()); // move everything else to center
@ -59,15 +82,48 @@ CCampaignScreen::CCampaignScreen(const JsonNode & config, std::string name)
pos = images[0]->pos; // fix height\width of this window
}
if(!config[name]["exitbutton"].isNull())
for (const auto& node : campaigns)
{
auto button = std::make_shared<CCampaignButton>(node, config, campaignSet);
button->enable();
campButtons.push_back(button);
}
maxPages = (campaigns.size() + campaignsPerPage - 1) / campaignsPerPage;
if (!config[name]["nextbutton"].isNull())
{
buttonNext = std::make_shared<CButton>(
Point(config[name]["nextbutton"]["x"].Integer(), config[name]["nextbutton"]["y"].Integer()),
AnimationPath::fromJson(config[name]["nextbutton"]["name"]),
std::make_pair("", ""),
[this, name]() { switchPage(1); }
);
buttonNext->setHoverable(true);
buttonNext->disable();
}
if (!config[name]["backbutton"].isNull())
{
buttonPrev = std::make_shared<CButton>(
Point(config[name]["backbutton"]["x"].Integer(), config[name]["backbutton"]["y"].Integer()),
AnimationPath::fromJson(config[name]["backbutton"]["name"]),
std::make_pair("", ""),
[this, name]() { switchPage(-1); }
);
buttonPrev->setHoverable(true);
buttonPrev->disable();
}
page = std::make_shared<CLabel>(10, 570, FONT_MEDIUM, ETextAlignment::BOTTOMLEFT, Colors::YELLOW, "");
if (!config[name]["exitbutton"].isNull())
{
buttonBack = createExitButton(config[name]["exitbutton"]);
buttonBack->setHoverable(true);
}
for(const JsonNode & node : config[name]["items"].Vector())
if(CResourceHandler::get()->existsResource(ResourcePath(node["file"].String(), EResType::CAMPAIGN)))
campButtons.push_back(std::make_shared<CCampaignButton>(node, config, campaignSet));
updateCampaignButtons(config);
}
void CCampaignScreen::activate()
@ -101,11 +157,18 @@ CCampaignScreen::CCampaignButton::CCampaignButton(const JsonNode & config, const
status = CCampaignScreen::ENABLED;
if(CResourceHandler::get()->existsResource(ResourcePath(campFile, EResType::CAMPAIGN)))
{
auto header = CampaignHandler::getHeader(campFile);
hoverText = header->getNameTranslated();
if(persistentStorage["completedCampaigns"][header->getFilename()].Bool())
if (persistentStorage["completedCampaigns"][header->getFilename()].Bool())
status = CCampaignScreen::COMPLETED;
}
else
{
status = CCampaignScreen::DISABLED;
}
for(const JsonNode & node : parentConfig[campaignSet]["items"].Vector())
{
@ -154,3 +217,54 @@ void CCampaignScreen::CCampaignButton::hover(bool on)
hoverLabel->setText(" ");
}
}
void CCampaignScreen::switchPage(int delta)
{
currentPage += delta;
currentPage = std::clamp(currentPage, 0, maxPages - 1);
const auto& campaignConfig = CMainMenuConfig::get().getCampaigns();
updateCampaignButtons(campaignConfig);
}
void CCampaignScreen::updateCampaignButtons(const JsonNode & parentConfig)
{
const auto& campaigns = parentConfig[campaignSet]["items"].Vector();
int minId = (currentPage * campaignsPerPage) + 1;
int maxId = minId + campaignsPerPage - 1;
for(size_t i = 0; i < campButtons.size(); ++i)
{
int campaignId = campaigns[i]["id"].Integer();
if(campaignId >= minId && campaignId <= maxId)
campButtons[i]->enable();
else
campButtons[i]->disable();
if(!CResourceHandler::get()->existsResource(ResourcePath(campaigns[i]["file"].String(), EResType::CAMPAIGN)))
{
campButtons[i]->disable();
logGlobal->warn("Campaign %s doesn't exist", campaigns[i]["file"].String());
}
}
if(buttonNext && buttonPrev)
{
page->setText(std::to_string(currentPage + 1) + "/" + std::to_string(maxPages));
if (maxId < campaigns.size())
buttonNext->enable();
else
buttonNext->disable();
if (currentPage > 0)
buttonPrev->enable();
else
buttonPrev->disable();
}
redraw();
}

View File

@ -56,9 +56,19 @@ private:
std::vector<std::shared_ptr<CCampaignButton>> campButtons;
std::vector<std::shared_ptr<CPicture>> images;
std::shared_ptr<CButton> buttonBack;
std::shared_ptr<CButton> buttonNext;
std::shared_ptr<CButton> buttonPrev;
std::shared_ptr<CLabel> page;
std::shared_ptr<CButton> createExitButton(const JsonNode & button);
int campaignsPerPage = 8;
int currentPage = 0;
int maxPages = 0;
void switchPage(int delta);
void updateCampaignButtons(const JsonNode& parentConfig);
public:
CCampaignScreen(const JsonNode & config, std::string campaignSet);

View File

@ -425,22 +425,6 @@ void CMainMenu::openCampaignScreen(std::string name)
return;
}
bool campaignsFound = true;
for (auto const & entry : config[name]["items"].Vector())
{
ResourcePath resourceID(entry["file"].String(), EResType::CAMPAIGN);
if(entry["optional"].Bool())
continue;
if(!CResourceHandler::get()->existsResource(resourceID))
campaignsFound = false;
}
if (!campaignsFound)
{
CInfoWindow::showInfoDialog(LIBRARY->generaltexth->translate("vcmi.client.errors.missingCampaigns"), std::vector<std::shared_ptr<CComponent>>(), PlayerColor(1));
return;
}
ENGINE->windows().createAndPushWindow<CCampaignScreen>(config, name);
}

View File

@ -43,7 +43,11 @@ void AssetGenerator::initialize()
imageFiles[ImagePath::builtin("combatUnitNumberWindowPositive.png")] = [this](){ return createCombatUnitNumberWindow(0.2f, 1.0f, 0.2f);};
imageFiles[ImagePath::builtin("combatUnitNumberWindowNegative.png")] = [this](){ return createCombatUnitNumberWindow(1.0f, 0.2f, 0.2f);};
imageFiles[ImagePath::builtin("CampaignBackground8.png")] = [this](){ return createCampaignBackground();};
imageFiles[ImagePath::builtin("CampaignBackground4.png")] = [this]() { return createCampaignBackground(4); };
imageFiles[ImagePath::builtin("CampaignBackground5.png")] = [this]() { return createCampaignBackground(5); };
imageFiles[ImagePath::builtin("CampaignBackground6.png")] = [this]() { return createCampaignBackground(6); };
imageFiles[ImagePath::builtin("CampaignBackground7.png")] = [this]() { return createCampaignBackground(7); };
imageFiles[ImagePath::builtin("CampaignBackground8.png")] = [this]() { return createCampaignBackground(8); };
for (PlayerColor color(0); color < PlayerColor::PLAYER_LIMIT; ++color)
imageFiles[ImagePath::builtin("DialogBoxBackground_" + color.toString())] = [this, color](){ return createPlayerColoredBackground(color);};
@ -202,41 +206,102 @@ AssetGenerator::CanvasPtr AssetGenerator::createCombatUnitNumberWindow(float mul
return image;
}
AssetGenerator::CanvasPtr AssetGenerator::createCampaignBackground() const
AssetGenerator::CanvasPtr AssetGenerator::createCampaignBackground(int selection) const
{
auto locator = ImageLocator(ImagePath::builtin("CAMPBACK"), EImageBlitMode::OPAQUE);
auto locator = ImageLocator(ImagePath::builtin("CAMPBACK"), EImageBlitMode::OPAQUE);
std::shared_ptr<IImage> img = ENGINE->renderHandler().loadImage(locator);
auto image = ENGINE->renderHandler().createImage(Point(800, 600), CanvasScalingPolicy::IGNORE);
Canvas canvas = image->getCanvas();
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));
// BigBlock section
auto bigBlock = ENGINE->renderHandler().createImage(Point(248, 114), CanvasScalingPolicy::IGNORE);
Rect bigBlockRegion(292, 74, 248, 114);
Canvas croppedBigBlock = bigBlock->getCanvas();
croppedBigBlock.draw(img, Point(0, 0), bigBlockRegion);
bigBlock->scaleTo(Point(200, 114), EScalingAlgorithm::NEAREST);
// right image
canvas.draw(img, Point(513, 67), Rect(463, 67, 71, 126));
canvas.draw(img, Point(586, 71), Rect(536, 71, 207, 117));
// SmallBlock section
auto smallBlock = ENGINE->renderHandler().createImage(Point(248, 114), CanvasScalingPolicy::IGNORE);
Canvas croppedSmallBlock = smallBlock->getCanvas();
croppedSmallBlock.draw(img, Point(0, 0), bigBlockRegion);
smallBlock->scaleTo(Point(134, 114), EScalingAlgorithm::NEAREST);
// middle image
canvas.draw(img, Point(306, 68), Rect(86, 68, 209, 122));
// Tripple block section
auto trippleBlock = ENGINE->renderHandler().createImage(Point(72, 116), CanvasScalingPolicy::IGNORE);
Rect trippleBlockSection(512, 246, 72, 116);
Canvas croppedTrippleBlock = trippleBlock->getCanvas();
croppedTrippleBlock.draw(img, Point(0, 0), trippleBlockSection);
trippleBlock->scaleTo(Point(70, 114), EScalingAlgorithm::NEAREST);
// 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
// First campaigns line
if (selection > 7)
{
// Rebuild 1. campaigns line from 2 to 3 fields
canvas.draw(bigBlock, Point(40, 72));
canvas.draw(trippleBlock, Point(240, 73));
canvas.draw(bigBlock, Point(310, 72));
canvas.draw(trippleBlock, Point(510, 72));
canvas.draw(bigBlock, Point(580, 72));
canvas.draw(trippleBlock, Point(780, 72));
}
else
{
// Empty 1 + 2. field
canvas.draw(bigBlock, Point(90, 72));
canvas.draw(bigBlock, Point(540, 72));
}
// Second campaigns line
// 3. Field
canvas.draw(bigBlock, Point(43, 245));
if (selection == 4)
{
// Disabled 4. field
canvas.draw(trippleBlock, Point(310, 245));
canvas.draw(smallBlock, Point(380, 245));
}
else
{
// Empty 4. field
canvas.draw(bigBlock, Point(314, 244));
}
// 5. Field
canvas.draw(bigBlock, Point(586, 246));
// Third campaigns line
// 6. Field
if (selection >= 6)
{
canvas.draw(bigBlock, Point(32, 417));
}
else
{
canvas.draw(trippleBlock, Point(30, 417));
canvas.draw(smallBlock, Point(100, 417));
}
auto locatorSkull = ImageLocator(ImagePath::builtin("CAMPNOSC"), EImageBlitMode::OPAQUE);
std::shared_ptr<IImage> imgSkull = ENGINE->renderHandler().loadImage(locatorSkull);
canvas.draw(imgSkull, Point(562, 509), Rect(178, 108, 43, 19));
if (selection >= 7)
{
// Only skull part
canvas.draw(bigBlock, Point(404, 417));
canvas.draw(imgSkull, Point(563, 512), Rect(178, 108, 43, 19));
}
else
{
// Original disabled field with skull and stone for 8. field
imgSkull->scaleTo(Point(238, 150), EScalingAlgorithm::NEAREST);
canvas.draw(imgSkull, Point(385, 400));
}
return image;
}

View File

@ -49,7 +49,7 @@ private:
CanvasPtr createBigSpellBook() const;
CanvasPtr createPlayerColoredBackground(const PlayerColor & player) const;
CanvasPtr createCombatUnitNumberWindow(float multR, float multG, float multB) const;
CanvasPtr createCampaignBackground() const;
CanvasPtr createCampaignBackground(int selection) const;
CanvasPtr createChroniclesCampaignImages(int chronicle) const;
CanvasPtr createPaletteShiftedImage(const AnimationPath & source, const std::vector<PaletteAnimation> & animation, int frameIndex, int paletteShiftCounter) const;

View File

@ -18,9 +18,8 @@
{
"images" :
[
{"x": 0, "y": 0, "name":"CAMPBACK"},
{"x": 34, "y": 417, "name":"CAMP1FWX"},//one campaign have special inactive image
{"x": 385, "y": 401, "name":"CAMPNOSC"},//and the last one is not present
{"x": 0, "y": 0, "name":"CampaignBackground6"},
{"x": 34, "y": 417, "name":"CAMP1FWX"} // 6. campaign have special inactive image
],
"exitbutton" : {"x": 658, "y": 482, "name":"CMPSCAN" },
"items":
@ -54,14 +53,14 @@
"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": 1, "x":41, "y":72, "file":"Maps/Chronicles/Hc1_Main", "image":"CampaignHc1Image", "video":"", "requires": [], "optional": true },
{ "id": 2, "x":312, "y":72, "file":"Maps/Chronicles/Hc2_Main", "image":"CampaignHc2Image", "video":"", "requires": [], "optional": true },
{ "id": 3, "x":581, "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": 6, "x":585, "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 }
{ "id": 8, "x":404, "y":415, "file":"Maps/Chronicles/Hc8_Main", "image":"CampaignHc8Image", "video":"", "requires": [], "optional": true }
]
}
}

View File

@ -165,6 +165,10 @@
"mainMenuCampaignCustom": "C",
"mainMenuCampaignRoe": "R",
"mainMenuCampaignSod": "S",
"mainMenuCampaignChr": "T",
"mainMenuCampaignHota": "H",
"mainMenuCampaignWog": "W",
"mainMenuCampaignVCMI": "V",
"mainMenuCredits": "C",
"mainMenuHighScores": "H",
"mainMenuHostGame": "C",