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:
BIN
Mods/vcmi/Content/Sprites/campaigns/arrow-back-down.png
Normal file
BIN
Mods/vcmi/Content/Sprites/campaigns/arrow-back-down.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
BIN
Mods/vcmi/Content/Sprites/campaigns/arrow-back-hover.png
Normal file
BIN
Mods/vcmi/Content/Sprites/campaigns/arrow-back-hover.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
BIN
Mods/vcmi/Content/Sprites/campaigns/arrow-back-normal.png
Normal file
BIN
Mods/vcmi/Content/Sprites/campaigns/arrow-back-normal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
BIN
Mods/vcmi/Content/Sprites/campaigns/arrow-next-down.png
Normal file
BIN
Mods/vcmi/Content/Sprites/campaigns/arrow-next-down.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
BIN
Mods/vcmi/Content/Sprites/campaigns/arrow-next-hover.png
Normal file
BIN
Mods/vcmi/Content/Sprites/campaigns/arrow-next-hover.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
BIN
Mods/vcmi/Content/Sprites/campaigns/arrow-next-normal.png
Normal file
BIN
Mods/vcmi/Content/Sprites/campaigns/arrow-next-normal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
20
Mods/vcmi/Content/Sprites/campaigns/back.json
Normal file
20
Mods/vcmi/Content/Sprites/campaigns/back.json
Normal 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"
|
||||
}
|
||||
]
|
||||
|
||||
}
|
20
Mods/vcmi/Content/Sprites/campaigns/next.json
Normal file
20
Mods/vcmi/Content/Sprites/campaigns/next.json
Normal 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"
|
||||
}
|
||||
]
|
||||
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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}",
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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 },
|
||||
|
@ -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();
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -165,6 +165,10 @@
|
||||
"mainMenuCampaignCustom": "C",
|
||||
"mainMenuCampaignRoe": "R",
|
||||
"mainMenuCampaignSod": "S",
|
||||
"mainMenuCampaignChr": "T",
|
||||
"mainMenuCampaignHota": "H",
|
||||
"mainMenuCampaignWog": "W",
|
||||
"mainMenuCampaignVCMI": "V",
|
||||
"mainMenuCredits": "C",
|
||||
"mainMenuHighScores": "H",
|
||||
"mainMenuHostGame": "C",
|
||||
|
Reference in New Issue
Block a user