mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-08 22:26:51 +02:00
Merge branch 'beta' into 'develop'
This commit is contained in:
18
ChangeLog.md
18
ChangeLog.md
@@ -1,5 +1,23 @@
|
||||
# VCMI Project Changelog
|
||||
|
||||
## 1.6.4 -> 1.6.5
|
||||
|
||||
### General
|
||||
|
||||
* Fixed corrupted graphics of generated assets like water tiles on mobile systems
|
||||
* All generated assets are now used directly from memory without saving them to disk
|
||||
* Launcher will now correctly show screenshots for already installed mods
|
||||
* Fixed broken icons in commander information dialog
|
||||
|
||||
### Stability
|
||||
|
||||
* Fixed regression causing crashes in combat when touchscreen input is in use
|
||||
* Fixed regression causing crash on attempt to upscale empty image
|
||||
* Fixed crash on some creature abilities from mods that cast targeted spells on unit with battle propagator
|
||||
* Fixed crash on accepting next turn in multiplayer when local player has game settings window open
|
||||
* Fixed crash in multiplayer when one player changes his starting options while another player has hero overview window open
|
||||
* Fixed crash on double-clicking login to global lobby button
|
||||
|
||||
## 1.6.3 -> 1.6.4
|
||||
|
||||
### General
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" :
|
||||
[
|
||||
{ "frame" : 0, "file" : "SECSK32:69"},
|
||||
{ "frame" : 1, "file" : "SECSK32:28"}
|
||||
{ "frame" : 0, "defFile" : "SECSK32", "defFrame" : 69 },
|
||||
{ "frame" : 1, "defFile" : "SECSK32", "defFrame" : 28 }
|
||||
]
|
||||
}
|
||||
|
@@ -199,6 +199,7 @@
|
||||
"vcmi.lobby.preview.error.invite" : "Nebyl jste pozván do této mísnosti.",
|
||||
"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.room.new" : "Nová hra",
|
||||
"vcmi.lobby.room.load" : "Načíst hru",
|
||||
"vcmi.lobby.room.type" : "Druh místnosti",
|
||||
@@ -326,9 +327,9 @@
|
||||
"vcmi.adventureOptions.smoothDragging.help" : "{Plynulé posouvání mapy}\n\nPokud je tato možnost aktivována, posouvání mapy bude plynulé.",
|
||||
"vcmi.adventureOptions.skipAdventureMapAnimations.hover" : "Přeskočit efekty mizení",
|
||||
"vcmi.adventureOptions.skipAdventureMapAnimations.help" : "{Přeskočit efekty mizení}\n\nKdyž je povoleno, přeskočí se efekty mizení objektů a podobné efekty (sběr surovin, nalodění atd.). V některých případech zrychlí uživatelské rozhraní na úkor estetiky. Obzvláště užitečné v PvP hrách. Pro maximální rychlost pohybu je toto nastavení aktivní bez ohledu na další volby.",
|
||||
"vcmi.adventureOptions.mapScrollSpeed1.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed5.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed6.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed1.hover" : "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed5.hover" : "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed6.hover" : "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed1.help" : "Nastavit posouvání mapy na velmi pomalé",
|
||||
"vcmi.adventureOptions.mapScrollSpeed5.help" : "Nastavit posouvání mapy na velmi rychlé",
|
||||
"vcmi.adventureOptions.mapScrollSpeed6.help" : "Nastavit posouvání mapy na okamžité",
|
||||
@@ -337,16 +338,16 @@
|
||||
|
||||
"vcmi.battleOptions.queueSizeLabel.hover" : "Zobrazit frontu pořadí tahů",
|
||||
"vcmi.battleOptions.queueSizeNoneButton.hover" : "VYPNUTO",
|
||||
"vcmi.battleOptions.queueSizeAutoButton.hover": "AUTO",
|
||||
"vcmi.battleOptions.queueSizeAutoButton.hover" : "AUTO",
|
||||
"vcmi.battleOptions.queueSizeSmallButton.hover" : "MALÁ",
|
||||
"vcmi.battleOptions.queueSizeBigButton.hover" : "VELKÁ",
|
||||
"vcmi.battleOptions.queueSizeNoneButton.help" : "Nezobrazovat frontu pořadí tahů.",
|
||||
"vcmi.battleOptions.queueSizeAutoButton.help" : "Nastavit automaticky velikost fronty pořadí tahů podle rozlišení obrazovky hry (Při výšce herního rozlišení menší než 700 pixelů je použita velikost MALÁ, jinak velikost VELKÁ)",
|
||||
"vcmi.battleOptions.queueSizeSmallButton.help" : "Zobrazit MALOU frontu pořadí tahů.",
|
||||
"vcmi.battleOptions.queueSizeBigButton.help" : "Zobrazit VELKOU frontu pořadí tahů (není podporováno, pokud výška rozlišení hry není alespoň 700 pixelů).",
|
||||
"vcmi.battleOptions.animationsSpeed1.hover": "",
|
||||
"vcmi.battleOptions.animationsSpeed5.hover": "",
|
||||
"vcmi.battleOptions.animationsSpeed6.hover": "",
|
||||
"vcmi.battleOptions.animationsSpeed1.hover" : "",
|
||||
"vcmi.battleOptions.animationsSpeed5.hover" : "",
|
||||
"vcmi.battleOptions.animationsSpeed6.hover" : "",
|
||||
"vcmi.battleOptions.animationsSpeed1.help" : "Nastavit rychlost animací na velmi pomalé.",
|
||||
"vcmi.battleOptions.animationsSpeed5.help" : "Nastavit rychlost animací na velmi rychlé.",
|
||||
"vcmi.battleOptions.animationsSpeed6.help" : "Nastavit rychlost animací na okamžité.",
|
||||
@@ -762,28 +763,28 @@
|
||||
"core.bonus.MECHANICAL.name" : "Mechanický",
|
||||
"core.bonus.PRISM_HEX_ATTACK_BREATH.name" : "Trojitý dech",
|
||||
"core.bonus.PRISM_HEX_ATTACK_BREATH.description" : "Útok trojitým dechem (útok přes 3 směry)",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.name": "Odolnost vůči kouzlům",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.name.air": "Odolnost vůči kouzlům vzduchu",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.name.fire": "Odolnost vůči kouzlům ohně",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.name.water": "Odolnost vůči kouzlům vody",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.name.earth": "Odolnost vůči kouzlům země",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.description": "Poškození ze všech kouzel sníženo o ${val}%.",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.description.air": "Poškození kouzel magie vzduchu sníženo o ${val}%.",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.description.fire": "Poškození kouzel magie ohně sníženo o ${val}%.",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.description.water": "Poškození kouzel magie vody sníženo o ${val}%.",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.description.earth": "Poškození kouzel magie země sníženo o ${val}%.",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.name": "Imunita vůči kouzlům",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.air": "Vzdušná imunita",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.fire": "Ohnivá imunita",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.water": "Vodní imunita",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.earth": "Zemská imunita",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.description": "Jednotka je imunní vůči všem kouzlům.",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.air": "Jednotka je imunní vůči všem kouzlům magie vzduchu.",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.fire": "Jednotka je imunní vůči všem kouzlům magie ohně.",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.water": "Jednotka je imunní vůči všem kouzlům magie vody.",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.earth": "Jednotka je imunní vůči všem kouzlům magie země.",
|
||||
"core.bonus.OPENING_BATTLE_SPELL.name": "Začíná kouzlem",
|
||||
"core.bonus.OPENING_BATTLE_SPELL.description": "Sesílá ${subtype.spell} na začátku bitvy.",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.name" : "Odolnost vůči kouzlům",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.name.air" : "Odolnost vůči kouzlům vzduchu",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.name.fire" : "Odolnost vůči kouzlům ohně",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.name.water" : "Odolnost vůči kouzlům vody",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.name.earth" : "Odolnost vůči kouzlům země",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.description" : "Poškození ze všech kouzel sníženo o ${val}%.",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.description.air" : "Poškození kouzel magie vzduchu sníženo o ${val}%.",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.description.fire" : "Poškození kouzel magie ohně sníženo o ${val}%.",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.description.water" : "Poškození kouzel magie vody sníženo o ${val}%.",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.description.earth" : "Poškození kouzel magie země sníženo o ${val}%.",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.name" : "Imunita vůči kouzlům",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.air" : "Vzdušná imunita",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.fire" : "Ohnivá imunita",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.water" : "Vodní imunita",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.name.earth" : "Zemská imunita",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.description" : "Jednotka je imunní vůči všem kouzlům.",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.air" : "Jednotka je imunní vůči všem kouzlům magie vzduchu.",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.fire" : "Jednotka je imunní vůči všem kouzlům magie ohně.",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.water" : "Jednotka je imunní vůči všem kouzlům magie vody.",
|
||||
"core.bonus.SPELL_SCHOOL_IMMUNITY.description.earth" : "Jednotka je imunní vůči všem kouzlům magie země.",
|
||||
"core.bonus.OPENING_BATTLE_SPELL.name" : "Začíná kouzlem",
|
||||
"core.bonus.OPENING_BATTLE_SPELL.description" : "Sesílá ${subtype.spell} na začátku bitvy.",
|
||||
|
||||
"spell.core.castleMoat.name" : "Hradní příkop",
|
||||
"spell.core.castleMoatTrigger.name" : "Hradní příkop",
|
||||
@@ -806,4 +807,4 @@
|
||||
"spell.core.strongholdMoatTrigger.name" : "Dřevěné bodce",
|
||||
"spell.core.summonDemons.name" : "Přivolání démonů",
|
||||
"spell.core.towerMoat.name" : "Pozemní mina"
|
||||
}
|
||||
}
|
||||
|
@@ -62,6 +62,7 @@
|
||||
#include "windows/CTutorialWindow.h"
|
||||
#include "windows/GUIClasses.h"
|
||||
#include "windows/InfoWindows.h"
|
||||
#include "windows/settings/SettingsMainWindow.h"
|
||||
|
||||
#include "../CCallback.h"
|
||||
|
||||
@@ -187,6 +188,7 @@ void CPlayerInterface::closeAllDialogs()
|
||||
while(true)
|
||||
{
|
||||
auto adventureWindow = GH.windows().topWindow<AdventureMapInterface>();
|
||||
auto settingsWindow = GH.windows().topWindow<SettingsMainWindow>();
|
||||
auto infoWindow = GH.windows().topWindow<CInfoWindow>();
|
||||
auto topWindow = GH.windows().topWindow<WindowBase>();
|
||||
|
||||
@@ -196,10 +198,16 @@ void CPlayerInterface::closeAllDialogs()
|
||||
if(infoWindow && infoWindow->ID != QueryID::NONE)
|
||||
break;
|
||||
|
||||
if (topWindow == nullptr)
|
||||
throw std::runtime_error("Invalid or non-existing top window! Total windows: " + std::to_string(GH.windows().count()));
|
||||
if (settingsWindow)
|
||||
{
|
||||
settingsWindow->close();
|
||||
continue;
|
||||
}
|
||||
|
||||
topWindow->close();
|
||||
if (topWindow)
|
||||
topWindow->close();
|
||||
else
|
||||
GH.windows().popWindows(1); // does not inherits from WindowBase, e.g. settings dialog
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -18,7 +18,6 @@
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "gui/WindowHandler.h"
|
||||
#include "render/IRenderHandler.h"
|
||||
#include "render/AssetGenerator.h"
|
||||
#include "ClientNetPackVisitors.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "../lib/gameState/CGameState.h"
|
||||
@@ -510,7 +509,7 @@ void ClientCommandManager::handleVsLog(std::istringstream & singleWordBuffer)
|
||||
|
||||
void ClientCommandManager::handleGenerateAssets()
|
||||
{
|
||||
AssetGenerator::generateAll();
|
||||
GH.renderHandler().exportGeneratedAssets();
|
||||
printCommandMessage("All assets generated");
|
||||
}
|
||||
|
||||
|
@@ -34,7 +34,6 @@
|
||||
#include "../render/IImage.h"
|
||||
#include "../render/IRenderHandler.h"
|
||||
#include "../render/IScreenHandler.h"
|
||||
#include "../render/AssetGenerator.h"
|
||||
#include "../CMT.h"
|
||||
#include "../PlayerLocalState.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
@@ -65,8 +64,6 @@ AdventureMapInterface::AdventureMapInterface():
|
||||
pos.w = GH.screenDimensions().x;
|
||||
pos.h = GH.screenDimensions().y;
|
||||
|
||||
AssetGenerator::createPaletteShiftedSprites();
|
||||
|
||||
shortcuts = std::make_shared<AdventureMapShortcuts>(*this);
|
||||
|
||||
widget = std::make_shared<AdventureMapWidget>(shortcuts);
|
||||
|
@@ -683,18 +683,24 @@ BattleHex::EDir BattleFieldController::selectAttackDirection(const BattleHex & m
|
||||
// | - - | - - | - - | - o o | o o - | - - | - - | o o
|
||||
|
||||
for (size_t i : { 1, 2, 3})
|
||||
attackAvailability[i] = occupiableHexes.contains(neighbours[i]) && occupiableHexes.contains(neighbours[i].cloneInDirection(BattleHex::RIGHT, false));
|
||||
{
|
||||
BattleHex target = neighbours[i].cloneInDirection(BattleHex::RIGHT, false);
|
||||
attackAvailability[i] = neighbours[i].isValid() && occupiableHexes.contains(neighbours[i]) && target.isValid() && occupiableHexes.contains(target);
|
||||
}
|
||||
|
||||
for (size_t i : { 4, 5, 0})
|
||||
attackAvailability[i] = occupiableHexes.contains(neighbours[i]) && occupiableHexes.contains(neighbours[i].cloneInDirection(BattleHex::LEFT, false));
|
||||
{
|
||||
BattleHex target = neighbours[i].cloneInDirection(BattleHex::LEFT, false);
|
||||
attackAvailability[i] = neighbours[i].isValid() && occupiableHexes.contains(neighbours[i]) && target.isValid() && occupiableHexes.contains(target);
|
||||
}
|
||||
|
||||
attackAvailability[6] = occupiableHexes.contains(neighbours[0]) && occupiableHexes.contains(neighbours[1]);
|
||||
attackAvailability[7] = occupiableHexes.contains(neighbours[3]) && occupiableHexes.contains(neighbours[4]);
|
||||
attackAvailability[6] = neighbours[0].isValid() && neighbours[1].isValid() && occupiableHexes.contains(neighbours[0]) && occupiableHexes.contains(neighbours[1]);
|
||||
attackAvailability[7] = neighbours[3].isValid() && neighbours[4].isValid() && occupiableHexes.contains(neighbours[3]) && occupiableHexes.contains(neighbours[4]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < 6; ++i)
|
||||
attackAvailability[i] = occupiableHexes.contains(neighbours[i]);
|
||||
attackAvailability[i] = neighbours[i].isValid() && occupiableHexes.contains(neighbours[i]);
|
||||
|
||||
attackAvailability[6] = false;
|
||||
attackAvailability[7] = false;
|
||||
@@ -739,7 +745,7 @@ BattleHex::EDir BattleFieldController::selectAttackDirection(const BattleHex & m
|
||||
|
||||
BattleHex BattleFieldController::fromWhichHexAttack(const BattleHex & attackTarget)
|
||||
{
|
||||
BattleHex::EDir direction = selectAttackDirection(getHoveredHex());
|
||||
BattleHex::EDir direction = selectAttackDirection(attackTarget);
|
||||
|
||||
const CStack * attacker = owner.stacksController->getActiveStack();
|
||||
|
||||
|
@@ -686,7 +686,12 @@ void StackInfoBasicPanel::initializeData(const CStack * stack)
|
||||
if (hasGraphics)
|
||||
{
|
||||
//FIXME: support permanent duration
|
||||
int duration = stack->getFirstBonus(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(effect)))->turnsRemain;
|
||||
auto spellBonuses = stack->getBonuses(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(effect)));
|
||||
|
||||
if (spellBonuses->empty())
|
||||
throw std::runtime_error("Failed to find effects for spell " + effect.toSpell()->getJsonKey());
|
||||
|
||||
int duration = spellBonuses->front()->duration;
|
||||
|
||||
icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SpellInt"), effect + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed));
|
||||
if(settings["general"]["enableUiEnhancements"].Bool())
|
||||
|
@@ -27,7 +27,6 @@
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/WindowHandler.h"
|
||||
#include "../media/ISoundPlayer.h"
|
||||
#include "../render/AssetGenerator.h"
|
||||
#include "../render/Colors.h"
|
||||
#include "../render/Canvas.h"
|
||||
#include "../render/IRenderHandler.h"
|
||||
@@ -80,7 +79,6 @@ BattleStacksController::BattleStacksController(BattleInterface & owner):
|
||||
stackToActivate(nullptr),
|
||||
animIDhelper(0)
|
||||
{
|
||||
AssetGenerator::createCombatUnitNumberWindow();
|
||||
//preparing graphics for displaying amounts of creatures
|
||||
amountNormal = GH.renderHandler().loadImage(ImagePath::builtin("combatUnitNumberWindowDefault"), EImageBlitMode::COLORKEY);
|
||||
amountPositive = GH.renderHandler().loadImage(ImagePath::builtin("combatUnitNumberWindowPositive"), EImageBlitMode::COLORKEY);
|
||||
|
@@ -116,6 +116,7 @@ void GlobalLobbyLoginWindow::onLogin()
|
||||
onConnectionSuccess();
|
||||
|
||||
buttonClose->block(true);
|
||||
buttonLogin->block(true);
|
||||
}
|
||||
|
||||
void GlobalLobbyLoginWindow::onConnectionSuccess()
|
||||
@@ -142,4 +143,5 @@ void GlobalLobbyLoginWindow::onConnectionFailed(const std::string & reason)
|
||||
|
||||
labelStatus->setText(formatter.toString());
|
||||
buttonClose->block(false);
|
||||
buttonLogin->block(false);
|
||||
}
|
||||
|
@@ -345,7 +345,7 @@ void WindowBase::close()
|
||||
if(!GH.windows().isTopWindow(this))
|
||||
{
|
||||
auto topWindow = GH.windows().topWindow<IShowActivatable>().get();
|
||||
throw std::runtime_error(std::string("Only top interface can be closed! Top window is ") + typeid(*this).name() + " but attempted to close " + typeid(*topWindow).name());
|
||||
throw std::runtime_error(std::string("Only top interface can be closed! Top window is ") + typeid(*topWindow).name() + " but attempted to close " + typeid(*this).name());
|
||||
}
|
||||
GH.windows().popWindows(1);
|
||||
}
|
||||
|
@@ -68,6 +68,9 @@ void OptionsTab::recreate()
|
||||
entries.clear();
|
||||
humanPlayers = 0;
|
||||
|
||||
for (auto heroOverview : GH.windows().findWindows<CHeroOverview>())
|
||||
heroOverview->close();
|
||||
|
||||
for (auto selectionWindow : GH.windows().findWindows<SelectionWindow>())
|
||||
{
|
||||
selectionWindow->reopen();
|
||||
|
@@ -18,7 +18,6 @@
|
||||
#include "../widgets/TextControls.h"
|
||||
#include "../CServerHandler.h"
|
||||
#include "../CGameInfo.h"
|
||||
#include "../render/AssetGenerator.h"
|
||||
|
||||
#include "../../lib/StartInfo.h"
|
||||
#include "../../lib/texts/CGeneralTextHandler.h"
|
||||
@@ -69,8 +68,6 @@ std::vector<SimturnsInfo> OptionsTabBase::getSimturnsPresets() const
|
||||
|
||||
OptionsTabBase::OptionsTabBase(const JsonPath & configPath)
|
||||
{
|
||||
AssetGenerator::createAdventureOptionsCleanBackground();
|
||||
|
||||
recActions = 0;
|
||||
|
||||
auto setTimerPresetCallback = [this](int index){
|
||||
|
@@ -38,7 +38,6 @@
|
||||
#include "../widgets/VideoWidget.h"
|
||||
#include "../windows/InfoWindows.h"
|
||||
#include "../CServerHandler.h"
|
||||
#include "../render/AssetGenerator.h"
|
||||
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
@@ -278,7 +277,7 @@ CMenuEntry::CMenuEntry(CMenuScreen * parent, const JsonNode & config)
|
||||
for (const auto& item : campaign["items"].Vector()) {
|
||||
std::string filename = item["file"].String();
|
||||
|
||||
if (CResourceHandler::get()->existsResource(ResourcePath(filename + ".h3c"))) {
|
||||
if (CResourceHandler::get()->existsResource(ResourcePath(filename, EResType::CAMPAIGN))) {
|
||||
fileExists = true;
|
||||
break;
|
||||
}
|
||||
@@ -428,9 +427,6 @@ 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);
|
||||
|
@@ -29,36 +29,60 @@
|
||||
#include "../lib/RoadHandler.h"
|
||||
#include "../lib/TerrainHandler.h"
|
||||
|
||||
void AssetGenerator::clear()
|
||||
AssetGenerator::AssetGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
void AssetGenerator::initialize()
|
||||
{
|
||||
// clear to avoid non updated sprites after mod change (if base imnages are used)
|
||||
if(boost::filesystem::is_directory(VCMIDirs::get().userDataPath() / "Generated"))
|
||||
boost::filesystem::remove_all(VCMIDirs::get().userDataPath() / "Generated");
|
||||
}
|
||||
|
||||
void AssetGenerator::generateAll()
|
||||
{
|
||||
createBigSpellBook();
|
||||
createAdventureOptionsCleanBackground();
|
||||
for (int i = 0; i < PlayerColor::PLAYER_LIMIT_I; ++i)
|
||||
createPlayerColoredBackground(PlayerColor(i));
|
||||
createCombatUnitNumberWindow();
|
||||
createCampaignBackground();
|
||||
createChroniclesCampaignImages();
|
||||
imageFiles[ImagePath::builtin("AdventureOptionsBackgroundClear.png")] = [this](){ return createAdventureOptionsCleanBackground();};
|
||||
imageFiles[ImagePath::builtin("SpellBookLarge.png")] = [this](){ return createBigSpellBook();};
|
||||
|
||||
imageFiles[ImagePath::builtin("combatUnitNumberWindowDefault.png")] = [this](){ return createCombatUnitNumberWindow(0.6f, 0.2f, 1.0f);};
|
||||
imageFiles[ImagePath::builtin("combatUnitNumberWindowNeutral.png")] = [this](){ return createCombatUnitNumberWindow(1.0f, 1.0f, 2.0f);};
|
||||
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();};
|
||||
|
||||
for (PlayerColor color(0); color < PlayerColor::PLAYER_LIMIT; ++color)
|
||||
imageFiles[ImagePath::builtin("DialogBoxBackground_" + color.toString())] = [this, color](){ return createPlayerColoredBackground(color);};
|
||||
|
||||
for(int i = 1; i < 9; i++)
|
||||
imageFiles[ImagePath::builtin("CampaignHc" + std::to_string(i) + "Image.png")] = [this, i](){ return createChroniclesCampaignImages(i);};
|
||||
|
||||
createPaletteShiftedSprites();
|
||||
}
|
||||
|
||||
void AssetGenerator::createAdventureOptionsCleanBackground()
|
||||
std::shared_ptr<ISharedImage> AssetGenerator::generateImage(const ImagePath & image)
|
||||
{
|
||||
std::string filename = "data/AdventureOptionsBackgroundClear.png";
|
||||
if (imageFiles.count(image))
|
||||
return imageFiles.at(image)()->toSharedImage(); // TODO: cache?
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(CResourceHandler::get()->existsResource(ResourcePath(filename))) // overridden by mod, no generation
|
||||
return;
|
||||
std::map<ImagePath, std::shared_ptr<ISharedImage>> AssetGenerator::generateAllImages()
|
||||
{
|
||||
std::map<ImagePath, std::shared_ptr<ISharedImage>> result;
|
||||
|
||||
if(!CResourceHandler::get("local")->createResource(filename))
|
||||
return;
|
||||
ResourcePath savePath(filename, EResType::IMAGE);
|
||||
for (const auto & entry : imageFiles)
|
||||
result[entry.first] = entry.second()->toSharedImage();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::map<AnimationPath, AssetGenerator::AnimationLayoutMap> AssetGenerator::generateAllAnimations()
|
||||
{
|
||||
return animationFiles;
|
||||
}
|
||||
|
||||
AssetGenerator::CanvasPtr AssetGenerator::createAdventureOptionsCleanBackground()
|
||||
{
|
||||
auto locator = ImageLocator(ImagePath::builtin("ADVOPTBK"), EImageBlitMode::OPAQUE);
|
||||
|
||||
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
|
||||
@@ -74,20 +98,11 @@ void AssetGenerator::createAdventureOptionsCleanBackground()
|
||||
canvas.draw(img, Point(53, 567), Rect(53, 520, 339, 3));
|
||||
canvas.draw(img, Point(53, 520), Rect(53, 264, 339, 47));
|
||||
|
||||
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
|
||||
return image;
|
||||
}
|
||||
|
||||
void AssetGenerator::createBigSpellBook()
|
||||
AssetGenerator::CanvasPtr AssetGenerator::createBigSpellBook()
|
||||
{
|
||||
std::string filename = "data/SpellBookLarge.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("SpelBack"), EImageBlitMode::OPAQUE);
|
||||
|
||||
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
|
||||
@@ -135,21 +150,11 @@ void AssetGenerator::createBigSpellBook()
|
||||
canvas.draw(img, Point(575, 465), Rect(417, 406, 37, 45));
|
||||
canvas.draw(img, Point(667, 465), Rect(478, 406, 37, 47));
|
||||
|
||||
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
|
||||
return image;
|
||||
}
|
||||
|
||||
void AssetGenerator::createPlayerColoredBackground(const PlayerColor & player)
|
||||
AssetGenerator::CanvasPtr AssetGenerator::createPlayerColoredBackground(const PlayerColor & player)
|
||||
{
|
||||
std::string filename = "data/DialogBoxBackground_" + player.toString() + ".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("DiBoxBck"), EImageBlitMode::OPAQUE);
|
||||
|
||||
std::shared_ptr<IImage> texture = GH.renderHandler().loadImage(locator);
|
||||
@@ -169,71 +174,44 @@ void AssetGenerator::createPlayerColoredBackground(const PlayerColor & player)
|
||||
|
||||
assert(player.isValidPlayer());
|
||||
if (!player.isValidPlayer())
|
||||
{
|
||||
logGlobal->error("Unable to colorize to invalid player color %d!", player.getNum());
|
||||
return;
|
||||
}
|
||||
throw std::runtime_error("Unable to colorize to invalid player color" + std::to_string(player.getNum()));
|
||||
|
||||
texture->adjustPalette(filters[player.getNum()], 0);
|
||||
texture->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
|
||||
|
||||
auto image = GH.renderHandler().createImage(texture->dimensions(), CanvasScalingPolicy::IGNORE);
|
||||
Canvas canvas = image->getCanvas();
|
||||
canvas.draw(texture, Point(0,0));
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void AssetGenerator::createCombatUnitNumberWindow()
|
||||
AssetGenerator::CanvasPtr AssetGenerator::createCombatUnitNumberWindow(float multR, float multG, float multB)
|
||||
{
|
||||
std::string filenameToSave = "data/combatUnitNumberWindow";
|
||||
|
||||
ResourcePath savePathDefault(filenameToSave + "Default.png", EResType::IMAGE);
|
||||
ResourcePath savePathNeutral(filenameToSave + "Neutral.png", EResType::IMAGE);
|
||||
ResourcePath savePathPositive(filenameToSave + "Positive.png", EResType::IMAGE);
|
||||
ResourcePath savePathNegative(filenameToSave + "Negative.png", EResType::IMAGE);
|
||||
|
||||
if(CResourceHandler::get()->existsResource(savePathDefault)) // overridden by mod, no generation
|
||||
return;
|
||||
|
||||
if(!CResourceHandler::get("local")->createResource(savePathDefault.getOriginalName() + ".png") ||
|
||||
!CResourceHandler::get("local")->createResource(savePathNeutral.getOriginalName() + ".png") ||
|
||||
!CResourceHandler::get("local")->createResource(savePathPositive.getOriginalName() + ".png") ||
|
||||
!CResourceHandler::get("local")->createResource(savePathNegative.getOriginalName() + ".png"))
|
||||
return;
|
||||
|
||||
auto locator = ImageLocator(ImagePath::builtin("CMNUMWIN"), EImageBlitMode::OPAQUE);
|
||||
locator.layer = EImageBlitMode::OPAQUE;
|
||||
|
||||
std::shared_ptr<IImage> texture = GH.renderHandler().loadImage(locator);
|
||||
|
||||
static const auto shifterNormal = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 0.6f, 0.2f, 1.0f );
|
||||
static const auto shifterPositive = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 0.2f, 1.0f, 0.2f );
|
||||
static const auto shifterNegative = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 1.0f, 0.2f, 0.2f );
|
||||
static const auto shifterNeutral = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 1.0f, 1.0f, 0.2f );
|
||||
const auto shifter= ColorFilter::genRangeShifter(0.f, 0.f, 0.f, multR, multG, multB);
|
||||
|
||||
// do not change border color
|
||||
static const int32_t ignoredMask = 1 << 26;
|
||||
|
||||
texture->adjustPalette(shifterNormal, ignoredMask);
|
||||
texture->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePathDefault));
|
||||
texture->adjustPalette(shifterPositive, ignoredMask);
|
||||
texture->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePathPositive));
|
||||
texture->adjustPalette(shifterNegative, ignoredMask);
|
||||
texture->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePathNegative));
|
||||
texture->adjustPalette(shifterNeutral, ignoredMask);
|
||||
texture->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePathNeutral));
|
||||
texture->adjustPalette(shifter, ignoredMask);
|
||||
|
||||
auto image = GH.renderHandler().createImage(texture->dimensions(), CanvasScalingPolicy::IGNORE);
|
||||
Canvas canvas = image->getCanvas();
|
||||
canvas.draw(texture, Point(0,0));
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void AssetGenerator::createCampaignBackground()
|
||||
AssetGenerator::CanvasPtr 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"), EImageBlitMode::OPAQUE);
|
||||
|
||||
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
|
||||
auto image = GH.renderHandler().createImage(Point(800, 600), CanvasScalingPolicy::IGNORE);
|
||||
auto image = GH.renderHandler().createImage(Point(200, 116), CanvasScalingPolicy::IGNORE);
|
||||
Canvas canvas = image->getCanvas();
|
||||
|
||||
canvas.draw(img, Point(0, 0), Rect(0, 0, 800, 600));
|
||||
@@ -264,171 +242,112 @@ void AssetGenerator::createCampaignBackground()
|
||||
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull);
|
||||
canvas.draw(imgSkull, Point(562, 509), Rect(178, 108, 43, 19));
|
||||
|
||||
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
|
||||
return image;
|
||||
}
|
||||
|
||||
void AssetGenerator::createChroniclesCampaignImages()
|
||||
AssetGenerator::CanvasPtr AssetGenerator::createChroniclesCampaignImages(int chronicle)
|
||||
{
|
||||
for(int i = 1; i < 9; i++)
|
||||
auto imgPathBg = ImagePath::builtin("data/chronicles_" + std::to_string(chronicle) + "/GamSelBk");
|
||||
auto locator = ImageLocator(imgPathBg, EImageBlitMode::OPAQUE);
|
||||
|
||||
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
|
||||
auto image = GH.renderHandler().createImage(Point(800, 600), CanvasScalingPolicy::IGNORE);
|
||||
Canvas canvas = image->getCanvas();
|
||||
|
||||
std::array sourceRect = {
|
||||
Rect(149, 144, 200, 116),
|
||||
Rect(156, 150, 200, 116),
|
||||
Rect(171, 153, 200, 116),
|
||||
Rect(35, 358, 200, 116),
|
||||
Rect(216, 248, 200, 116),
|
||||
Rect(58, 234, 200, 116),
|
||||
Rect(184, 219, 200, 116),
|
||||
Rect(268, 210, 200, 116),
|
||||
};
|
||||
|
||||
canvas.draw(img, Point(0, 0), sourceRect.at(chronicle-1));
|
||||
|
||||
if (chronicle == 8)
|
||||
{
|
||||
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, EImageBlitMode::OPAQUE);
|
||||
|
||||
std::shared_ptr<IImage> img = GH.renderHandler().loadImage(locator);
|
||||
auto image = GH.renderHandler().createImage(Point(800, 600), CanvasScalingPolicy::IGNORE);
|
||||
Canvas canvas = image->getCanvas();
|
||||
|
||||
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"), EImageBlitMode::OPAQUE);
|
||||
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull);
|
||||
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;
|
||||
}
|
||||
|
||||
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
|
||||
//skull
|
||||
auto locatorSkull = ImageLocator(ImagePath::builtin("CampSP1"), EImageBlitMode::OPAQUE);
|
||||
std::shared_ptr<IImage> imgSkull = GH.renderHandler().loadImage(locatorSkull);
|
||||
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));
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void AssetGenerator::createPaletteShiftedSprites()
|
||||
{
|
||||
std::vector<std::string> tiles;
|
||||
std::vector<std::vector<std::variant<TerrainPaletteAnimation, RiverPaletteAnimation>>> paletteAnimations;
|
||||
for(auto entity : VLC->terrainTypeHandler->objects)
|
||||
{
|
||||
if(entity->paletteAnimation.size())
|
||||
{
|
||||
tiles.push_back(entity->tilesFilename.getName());
|
||||
std::vector<std::variant<TerrainPaletteAnimation, RiverPaletteAnimation>> tmpAnim;
|
||||
for(auto & animEntity : entity->paletteAnimation)
|
||||
tmpAnim.push_back(animEntity);
|
||||
paletteAnimations.push_back(tmpAnim);
|
||||
}
|
||||
if(entity->paletteAnimation.empty())
|
||||
continue;
|
||||
|
||||
std::vector<PaletteAnimation> paletteShifts;
|
||||
for(auto & animEntity : entity->paletteAnimation)
|
||||
paletteShifts.push_back({animEntity.start, animEntity.length});
|
||||
|
||||
generatePaletteShiftedAnimation(entity->tilesFilename, paletteShifts);
|
||||
|
||||
}
|
||||
for(auto entity : VLC->riverTypeHandler->objects)
|
||||
{
|
||||
if(entity->paletteAnimation.size())
|
||||
{
|
||||
tiles.push_back(entity->tilesFilename.getName());
|
||||
std::vector<std::variant<TerrainPaletteAnimation, RiverPaletteAnimation>> tmpAnim;
|
||||
for(auto & animEntity : entity->paletteAnimation)
|
||||
tmpAnim.push_back(animEntity);
|
||||
paletteAnimations.push_back(tmpAnim);
|
||||
}
|
||||
}
|
||||
if(entity->paletteAnimation.empty())
|
||||
continue;
|
||||
|
||||
for(int i = 0; i < tiles.size(); i++)
|
||||
{
|
||||
auto sprite = tiles[i];
|
||||
std::vector<PaletteAnimation> paletteShifts;
|
||||
for(auto & animEntity : entity->paletteAnimation)
|
||||
paletteShifts.push_back({animEntity.start, animEntity.length});
|
||||
|
||||
JsonNode config;
|
||||
config["basepath"].String() = sprite + "_Shifted/";
|
||||
config["images"].Vector();
|
||||
|
||||
auto filename = AnimationPath::builtin(sprite).addPrefix("SPRITES/");
|
||||
auto filenameNew = AnimationPath::builtin(sprite + "_Shifted").addPrefix("SPRITES/");
|
||||
|
||||
if(CResourceHandler::get()->existsResource(ResourcePath(filenameNew.getName(), EResType::JSON))) // overridden by mod, no generation
|
||||
return;
|
||||
|
||||
auto anim = GH.renderHandler().loadAnimation(filename, EImageBlitMode::COLORKEY);
|
||||
for(int j = 0; j < anim->size(); j++)
|
||||
{
|
||||
int maxLen = 1;
|
||||
for(int k = 0; k < paletteAnimations[i].size(); k++)
|
||||
{
|
||||
auto element = paletteAnimations[i][k];
|
||||
if(std::holds_alternative<TerrainPaletteAnimation>(element))
|
||||
maxLen = std::lcm(maxLen, std::get<TerrainPaletteAnimation>(element).length);
|
||||
else
|
||||
maxLen = std::lcm(maxLen, std::get<RiverPaletteAnimation>(element).length);
|
||||
}
|
||||
for(int l = 0; l < maxLen; l++)
|
||||
{
|
||||
std::string spriteName = sprite + boost::str(boost::format("%02d") % j) + "_" + std::to_string(l) + ".png";
|
||||
std::string filenameNewImg = "sprites/" + sprite + "_Shifted" + "/" + spriteName;
|
||||
ResourcePath savePath(filenameNewImg, EResType::IMAGE);
|
||||
|
||||
if(!CResourceHandler::get("local")->createResource(filenameNewImg))
|
||||
return;
|
||||
|
||||
auto imgLoc = anim->getImageLocator(j, 0);
|
||||
auto img = GH.renderHandler().loadImage(imgLoc);
|
||||
for(int k = 0; k < paletteAnimations[i].size(); k++)
|
||||
{
|
||||
auto element = paletteAnimations[i][k];
|
||||
if(std::holds_alternative<TerrainPaletteAnimation>(element))
|
||||
{
|
||||
auto tmp = std::get<TerrainPaletteAnimation>(element);
|
||||
img->shiftPalette(tmp.start, tmp.length, l % tmp.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tmp = std::get<RiverPaletteAnimation>(element);
|
||||
img->shiftPalette(tmp.start, tmp.length, l % tmp.length);
|
||||
}
|
||||
}
|
||||
|
||||
auto image = GH.renderHandler().createImage(Point(32, 32), CanvasScalingPolicy::IGNORE);
|
||||
Canvas canvas = image->getCanvas();
|
||||
canvas.draw(img, Point((32 - img->dimensions().x) / 2, (32 - img->dimensions().y) / 2));
|
||||
image->exportBitmap(*CResourceHandler::get("local")->getResourceName(savePath));
|
||||
|
||||
JsonNode node(JsonMap{
|
||||
{ "group", JsonNode(l) },
|
||||
{ "frame", JsonNode(j) },
|
||||
{ "file", JsonNode(spriteName) }
|
||||
});
|
||||
config["images"].Vector().push_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
ResourcePath savePath(filenameNew.getOriginalName(), EResType::JSON);
|
||||
if(!CResourceHandler::get("local")->createResource(filenameNew.getOriginalName() + ".json"))
|
||||
return;
|
||||
|
||||
std::fstream file(CResourceHandler::get("local")->getResourceName(savePath)->c_str(), std::ofstream::out | std::ofstream::trunc);
|
||||
file << config.toString();
|
||||
generatePaletteShiftedAnimation(entity->tilesFilename, paletteShifts);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetGenerator::generatePaletteShiftedAnimation(const AnimationPath & sprite, const std::vector<PaletteAnimation> & paletteAnimations)
|
||||
{
|
||||
AnimationLayoutMap layout;
|
||||
|
||||
auto animation = GH.renderHandler().loadAnimation(sprite, EImageBlitMode::COLORKEY);
|
||||
|
||||
int paletteTransformLength = 1;
|
||||
for (const auto & transform : paletteAnimations)
|
||||
paletteTransformLength = std::lcm(paletteTransformLength, transform.length);
|
||||
|
||||
for(int tileIndex = 0; tileIndex < animation->size(); tileIndex++)
|
||||
{
|
||||
for(int paletteIndex = 0; paletteIndex < paletteTransformLength; paletteIndex++)
|
||||
{
|
||||
ImagePath spriteName = ImagePath::builtin(sprite.getName() + boost::str(boost::format("%02d") % tileIndex) + "_" + std::to_string(paletteIndex) + ".png");
|
||||
layout[paletteIndex].push_back(ImageLocator(spriteName, EImageBlitMode::SIMPLE));
|
||||
|
||||
imageFiles[spriteName] = [=](){ return createPaletteShiftedImage(sprite, paletteAnimations, tileIndex, paletteIndex);};
|
||||
}
|
||||
}
|
||||
|
||||
AnimationPath shiftedPath = AnimationPath::builtin("SPRITES/" + sprite.getName() + "_SHIFTED");
|
||||
animationFiles[shiftedPath] = layout;
|
||||
}
|
||||
|
||||
AssetGenerator::CanvasPtr AssetGenerator::createPaletteShiftedImage(const AnimationPath & source, const std::vector<PaletteAnimation> & palette, int frameIndex, int paletteShiftCounter)
|
||||
{
|
||||
auto animation = GH.renderHandler().loadAnimation(source, EImageBlitMode::COLORKEY);
|
||||
|
||||
auto imgLoc = animation->getImageLocator(frameIndex, 0);
|
||||
auto img = GH.renderHandler().loadImage(imgLoc);
|
||||
|
||||
for(const auto & element : palette)
|
||||
img->shiftPalette(element.start, element.length, paletteShiftCounter % element.length);
|
||||
|
||||
auto image = GH.renderHandler().createImage(Point(32, 32), CanvasScalingPolicy::IGNORE);
|
||||
Canvas canvas = image->getCanvas();
|
||||
canvas.draw(img, Point((32 - img->dimensions().x) / 2, (32 - img->dimensions().y) / 2));
|
||||
|
||||
return image;
|
||||
|
||||
}
|
||||
|
@@ -9,20 +9,53 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ImageLocator.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class PlayerColor;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class ISharedImage;
|
||||
class CanvasImage;
|
||||
|
||||
class AssetGenerator
|
||||
{
|
||||
public:
|
||||
static void clear();
|
||||
static void generateAll();
|
||||
static void createAdventureOptionsCleanBackground();
|
||||
static void createBigSpellBook();
|
||||
static void createPlayerColoredBackground(const PlayerColor & player);
|
||||
static void createCombatUnitNumberWindow();
|
||||
static void createCampaignBackground();
|
||||
static void createChroniclesCampaignImages();
|
||||
static void createPaletteShiftedSprites();
|
||||
using AnimationLayoutMap = std::map<size_t, std::vector<ImageLocator>>;
|
||||
using CanvasPtr = std::shared_ptr<CanvasImage>;
|
||||
|
||||
AssetGenerator();
|
||||
|
||||
void initialize();
|
||||
|
||||
std::shared_ptr<ISharedImage> generateImage(const ImagePath & image);
|
||||
|
||||
std::map<ImagePath, std::shared_ptr<ISharedImage>> generateAllImages();
|
||||
std::map<AnimationPath, AnimationLayoutMap> generateAllAnimations();
|
||||
|
||||
private:
|
||||
using ImageGenerationFunctor = std::function<CanvasPtr()>;
|
||||
|
||||
struct PaletteAnimation
|
||||
{
|
||||
/// index of first color to cycle
|
||||
int32_t start;
|
||||
/// total numbers of colors to cycle
|
||||
int32_t length;
|
||||
};
|
||||
|
||||
std::map<ImagePath, ImageGenerationFunctor> imageFiles;
|
||||
std::map<AnimationPath, AnimationLayoutMap> animationFiles;
|
||||
|
||||
CanvasPtr createAdventureOptionsCleanBackground();
|
||||
CanvasPtr createBigSpellBook();
|
||||
CanvasPtr createPlayerColoredBackground(const PlayerColor & player);
|
||||
CanvasPtr createCombatUnitNumberWindow(float multR, float multG, float multB);
|
||||
CanvasPtr createCampaignBackground();
|
||||
CanvasPtr createChroniclesCampaignImages(int chronicle);
|
||||
CanvasPtr createPaletteShiftedImage(const AnimationPath & source, const std::vector<PaletteAnimation> & animation, int frameIndex, int paletteShiftCounter);
|
||||
|
||||
void createPaletteShiftedSprites();
|
||||
void generatePaletteShiftedAnimation(const AnimationPath & source, const std::vector<PaletteAnimation> & animation);
|
||||
|
||||
};
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include "../render/IScreenHandler.h"
|
||||
#include "../renderSDL/SDL_Extensions.h"
|
||||
#include "../renderSDL/SDLImageScaler.h"
|
||||
#include "../renderSDL/SDLImage.h"
|
||||
|
||||
#include <SDL_image.h>
|
||||
#include <SDL_surface.h>
|
||||
@@ -61,3 +62,8 @@ Point CanvasImage::dimensions() const
|
||||
{
|
||||
return {surface->w, surface->h};
|
||||
}
|
||||
|
||||
std::shared_ptr<ISharedImage> CanvasImage::toSharedImage()
|
||||
{
|
||||
return std::make_shared<SDLImageShared>(surface);
|
||||
}
|
||||
|
@@ -34,6 +34,8 @@ public:
|
||||
void shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove) override{};
|
||||
void adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask) override{};
|
||||
|
||||
std::shared_ptr<ISharedImage> toSharedImage();
|
||||
|
||||
private:
|
||||
SDL_Surface * surface;
|
||||
CanvasScalingPolicy scalingPolicy;
|
||||
|
@@ -50,4 +50,6 @@ public:
|
||||
|
||||
/// Returns font with specified identifer
|
||||
virtual std::shared_ptr<const IFont> loadFont(EFonts font) = 0;
|
||||
|
||||
virtual void exportGeneratedAssets() = 0;
|
||||
};
|
||||
|
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "../gui/CGuiHandler.h"
|
||||
|
||||
#include "../render/AssetGenerator.h"
|
||||
#include "../render/CAnimation.h"
|
||||
#include "../render/CanvasImage.h"
|
||||
#include "../render/CDefFile.h"
|
||||
@@ -43,6 +44,13 @@
|
||||
#include <vcmi/SkillService.h>
|
||||
#include <vcmi/spells/Service.h>
|
||||
|
||||
RenderHandler::RenderHandler()
|
||||
:assetGenerator(std::make_unique<AssetGenerator>())
|
||||
{
|
||||
}
|
||||
|
||||
RenderHandler::~RenderHandler() = default;
|
||||
|
||||
std::shared_ptr<CDefFile> RenderHandler::getAnimationFile(const AnimationPath & path)
|
||||
{
|
||||
AnimationPath actualPath = boost::starts_with(path.getName(), "SPRITES") ? path : path.addPrefix("SPRITES/");
|
||||
@@ -201,12 +209,28 @@ std::shared_ptr<ScalableImageShared> RenderHandler::loadImageImpl(const ImageLoc
|
||||
return scaledImage;
|
||||
}
|
||||
|
||||
std::shared_ptr<SDLImageShared> RenderHandler::loadImageFromFileUncached(const ImageLocator & locator)
|
||||
std::shared_ptr<ISharedImage> RenderHandler::loadImageFromFileUncached(const ImageLocator & locator)
|
||||
{
|
||||
if(locator.image)
|
||||
{
|
||||
// TODO: create EmptySharedImage class that will be instantiated if image does not exists or fails to load
|
||||
return std::make_shared<SDLImageShared>(*locator.image);
|
||||
auto imagePath = *locator.image;
|
||||
auto imagePathSprites = imagePath.addPrefix("SPRITES/");
|
||||
auto imagePathData = imagePath.addPrefix("DATA/");
|
||||
|
||||
if(CResourceHandler::get()->existsResource(imagePathSprites))
|
||||
return std::make_shared<SDLImageShared>(imagePathSprites);
|
||||
|
||||
if(CResourceHandler::get()->existsResource(imagePathData))
|
||||
return std::make_shared<SDLImageShared>(imagePathData);
|
||||
|
||||
if(CResourceHandler::get()->existsResource(imagePath))
|
||||
return std::make_shared<SDLImageShared>(imagePath);
|
||||
|
||||
auto generated = assetGenerator->generateImage(imagePath);
|
||||
if (generated)
|
||||
return generated;
|
||||
|
||||
return std::make_shared<SDLImageShared>(ImagePath::builtin("DEFAULT"));
|
||||
}
|
||||
|
||||
if(locator.defFile)
|
||||
@@ -423,6 +447,10 @@ static void detectOverlappingBuildings(RenderHandler * renderHandler, const Fact
|
||||
|
||||
void RenderHandler::onLibraryLoadingFinished(const Services * services)
|
||||
{
|
||||
assert(animationLayouts.empty());
|
||||
assetGenerator->initialize();
|
||||
animationLayouts = assetGenerator->generateAllAnimations();
|
||||
|
||||
addImageListEntries(services->creatures());
|
||||
addImageListEntries(services->heroTypes());
|
||||
addImageListEntries(services->artifacts());
|
||||
@@ -469,3 +497,9 @@ std::shared_ptr<const IFont> RenderHandler::loadFont(EFonts font)
|
||||
fonts[font] = loadedFont;
|
||||
return loadedFont;
|
||||
}
|
||||
|
||||
void RenderHandler::exportGeneratedAssets()
|
||||
{
|
||||
for (const auto & entry : assetGenerator->generateAllImages())
|
||||
entry.second->exportBitmap(VCMIDirs::get().userDataPath() / "Generated" / (entry.first.getOriginalName() + ".png"), nullptr);
|
||||
}
|
||||
|
@@ -18,8 +18,9 @@ VCMI_LIB_NAMESPACE_END
|
||||
class CDefFile;
|
||||
class SDLImageShared;
|
||||
class ScalableImageShared;
|
||||
class AssetGenerator;
|
||||
|
||||
class RenderHandler : public IRenderHandler
|
||||
class RenderHandler final : public IRenderHandler
|
||||
{
|
||||
using AnimationLayoutMap = std::map<size_t, std::vector<ImageLocator>>;
|
||||
|
||||
@@ -27,6 +28,7 @@ class RenderHandler : public IRenderHandler
|
||||
std::map<AnimationPath, AnimationLayoutMap> animationLayouts;
|
||||
std::map<SharedImageLocator, std::shared_ptr<ScalableImageShared>> imageFiles;
|
||||
std::map<EFonts, std::shared_ptr<const IFont>> fonts;
|
||||
std::unique_ptr<AssetGenerator> assetGenerator;
|
||||
|
||||
std::shared_ptr<CDefFile> getAnimationFile(const AnimationPath & path);
|
||||
AnimationLayoutMap & getAnimationLayout(const AnimationPath & path, int scalingFactor, EImageBlitMode mode);
|
||||
@@ -38,13 +40,15 @@ class RenderHandler : public IRenderHandler
|
||||
|
||||
std::shared_ptr<ScalableImageShared> loadImageImpl(const ImageLocator & config);
|
||||
|
||||
std::shared_ptr<SDLImageShared> loadImageFromFileUncached(const ImageLocator & locator);
|
||||
std::shared_ptr<ISharedImage> loadImageFromFileUncached(const ImageLocator & locator);
|
||||
|
||||
ImageLocator getLocatorForAnimationFrame(const AnimationPath & path, int frame, int group, int scaling, EImageBlitMode mode);
|
||||
|
||||
int getScalingFactor() const;
|
||||
|
||||
public:
|
||||
RenderHandler();
|
||||
~RenderHandler();
|
||||
|
||||
// IRenderHandler implementation
|
||||
void onLibraryLoadingFinished(const Services * services) override;
|
||||
@@ -61,4 +65,6 @@ public:
|
||||
|
||||
/// Returns font with specified identifer
|
||||
std::shared_ptr<const IFont> loadFont(EFonts font) override;
|
||||
|
||||
void exportGeneratedAssets() override;
|
||||
};
|
||||
|
@@ -306,6 +306,10 @@ std::shared_ptr<const ISharedImage> SDLImageShared::scaleTo(const Point & size,
|
||||
|
||||
void SDLImageShared::exportBitmap(const boost::filesystem::path& path, SDL_Palette * palette) const
|
||||
{
|
||||
auto directory = path;
|
||||
directory.remove_filename();
|
||||
boost::filesystem::create_directories(directory);
|
||||
|
||||
assert(upscalingInProgress == false);
|
||||
if (!surf)
|
||||
return;
|
||||
|
@@ -120,6 +120,9 @@ const Rect & SDLImageOptimizer::getResultDimensions() const
|
||||
|
||||
void SDLImageScaler::scaleSurface(Point targetDimensions, EScalingAlgorithm algorithm)
|
||||
{
|
||||
if (!intermediate)
|
||||
return; // may happen on scaling of empty images
|
||||
|
||||
if(!targetDimensions.x || !targetDimensions.y)
|
||||
throw std::runtime_error("invalid scaling dimensions!");
|
||||
|
||||
@@ -144,6 +147,9 @@ void SDLImageScaler::scaleSurface(Point targetDimensions, EScalingAlgorithm algo
|
||||
|
||||
void SDLImageScaler::scaleSurfaceIntegerFactor(int factor, EScalingAlgorithm algorithm)
|
||||
{
|
||||
if (!intermediate)
|
||||
return; // may happen on scaling of empty images
|
||||
|
||||
if(factor == 0)
|
||||
throw std::runtime_error("invalid scaling factor!");
|
||||
|
||||
|
@@ -13,7 +13,6 @@
|
||||
#include "MiscWidgets.h"
|
||||
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../render/AssetGenerator.h"
|
||||
#include "../render/IImage.h"
|
||||
#include "../render/IRenderHandler.h"
|
||||
#include "../render/CAnimation.h"
|
||||
@@ -184,8 +183,6 @@ FilledTexturePlayerColored::FilledTexturePlayerColored(Rect position)
|
||||
|
||||
void FilledTexturePlayerColored::setPlayerColor(PlayerColor player)
|
||||
{
|
||||
AssetGenerator::createPlayerColoredBackground(player);
|
||||
|
||||
ImagePath imagePath = ImagePath::builtin("DialogBoxBackground_" + player.toString() + ".bmp");
|
||||
|
||||
texture = GH.renderHandler().loadImage(imagePath, EImageBlitMode::COLORKEY);
|
||||
|
@@ -234,7 +234,11 @@ CStackWindow::ActiveSpellsSection::ActiveSpellsSection(CStackWindow * owner, int
|
||||
spellText = CGI->generaltexth->allTexts[610]; //"%s, duration: %d rounds."
|
||||
boost::replace_first(spellText, "%s", spell->getNameTranslated());
|
||||
//FIXME: support permanent duration
|
||||
int duration = battleStack->getFirstBonus(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(effect)))->turnsRemain;
|
||||
auto spellBonuses = battleStack->getBonuses(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(effect)));
|
||||
if (spellBonuses->empty())
|
||||
throw std::runtime_error("Failed to find effects for spell " + effect.toSpell()->getJsonKey());
|
||||
|
||||
int duration = spellBonuses->front()->duration;
|
||||
boost::replace_first(spellText, "%d", std::to_string(duration));
|
||||
|
||||
spellIcons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SpellInt"), effect + 1, 0, firstPos.x + offset.x * printed, firstPos.y + offset.y * printed));
|
||||
|
@@ -32,7 +32,6 @@
|
||||
#include "../widgets/Buttons.h"
|
||||
#include "../widgets/VideoWidget.h"
|
||||
#include "../adventureMap/AdventureMapInterface.h"
|
||||
#include "../render/AssetGenerator.h"
|
||||
|
||||
#include "../../CCallback.h"
|
||||
|
||||
@@ -118,7 +117,6 @@ CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _m
|
||||
|
||||
if(isBigSpellbook)
|
||||
{
|
||||
AssetGenerator::createBigSpellBook();
|
||||
background = std::make_shared<CPicture>(ImagePath::builtin("SpellBookLarge"), 0, 0);
|
||||
updateShadow();
|
||||
}
|
||||
|
@@ -29,7 +29,6 @@ private:
|
||||
std::shared_ptr<CIntObject> createTab(size_t index);
|
||||
void openTab(size_t index);
|
||||
|
||||
void close(); //TODO: copypaste of WindowBase::close(), consider changing Windowbase to IWindowbase with default close() implementation and changing WindowBase inheritance to CIntObject + IWindowBase
|
||||
|
||||
void loadGameButtonCallback();
|
||||
void saveGameButtonCallback();
|
||||
@@ -40,6 +39,7 @@ private:
|
||||
public:
|
||||
SettingsMainWindow(BattleInterface * parentBattleInterface = nullptr);
|
||||
|
||||
void close(); //TODO: copypaste of WindowBase::close(), consider changing Windowbase to IWindowbase with default close() implementation and changing WindowBase inheritance to CIntObject + IWindowBase
|
||||
void showAll(Canvas & to) override;
|
||||
void onScreenResize() override;
|
||||
};
|
||||
|
@@ -27,7 +27,6 @@
|
||||
#include "../client/media/CMusicHandler.h"
|
||||
#include "../client/media/CSoundHandler.h"
|
||||
#include "../client/media/CVideoHandler.h"
|
||||
#include "../client/render/AssetGenerator.h"
|
||||
#include "../client/render/Graphics.h"
|
||||
#include "../client/render/IRenderHandler.h"
|
||||
#include "../client/render/IScreenHandler.h"
|
||||
@@ -235,8 +234,6 @@ int main(int argc, char * argv[])
|
||||
logGlobal->info("Creating console and configuring logger: %d ms", pomtime.getDiff());
|
||||
logGlobal->info("The log file will be saved to %s", logPath);
|
||||
|
||||
AssetGenerator::clear();
|
||||
|
||||
// Init filesystem and settings
|
||||
try
|
||||
{
|
||||
|
6
debian/changelog
vendored
6
debian/changelog
vendored
@@ -4,6 +4,12 @@ vcmi (1.7.0) jammy; urgency=medium
|
||||
|
||||
-- Ivan Savenko <saven.ivan@gmail.com> Fri, 30 May 2025 12:00:00 +0200
|
||||
|
||||
vcmi (1.6.5) jammy; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Ivan Savenko <saven.ivan@gmail.com> Mon, 3 Feb 2025 12:00:00 +0200
|
||||
|
||||
vcmi (1.6.4) jammy; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
@@ -1,9 +1,9 @@
|
||||
# VCMI Project
|
||||
|
||||
[](https://github.com/vcmi/vcmi/actions/workflows/github.yml?query=branch%3Adevelop+event%3Apush)
|
||||
[](https://github.com/vcmi/vcmi/releases/tag/1.6.2)
|
||||
[](https://github.com/vcmi/vcmi/releases/tag/1.6.3)
|
||||
[](https://github.com/vcmi/vcmi/releases/tag/1.6.4)
|
||||
[](https://github.com/vcmi/vcmi/releases/tag/1.6.5)
|
||||
[](https://github.com/vcmi/vcmi/releases)
|
||||
|
||||
VCMI is an open-source recreation of Heroes of Might & Magic III engine, giving it new and extended possibilities.
|
||||
|
@@ -91,6 +91,7 @@
|
||||
<launchable type="desktop-id">vcmilauncher.desktop</launchable>
|
||||
<releases>
|
||||
<release version="1.7.0" date="2025-05-30" type="development"/>
|
||||
<release version="1.6.5" date="2025-02-03" type="stable"/>
|
||||
<release version="1.6.4" date="2025-01-31" type="stable"/>
|
||||
<release version="1.6.3" date="2025-01-10" type="stable"/>
|
||||
<release version="1.6.2" date="2025-01-03" type="stable"/>
|
||||
|
@@ -71,7 +71,7 @@ QStringList ModState::getConflicts() const
|
||||
|
||||
QStringList ModState::getScreenshots() const
|
||||
{
|
||||
return stringListStdToQt(impl.getLocalizedValue("screenshots").convertTo<std::vector<std::string>>());
|
||||
return stringListStdToQt(impl.getRepositoryValue("screenshots").convertTo<std::vector<std::string>>());
|
||||
}
|
||||
|
||||
QString ModState::getBaseLanguage() const
|
||||
|
@@ -161,12 +161,24 @@ uint32_t TextOperations::getUnicodeCodepoint(char data, const std::string & enco
|
||||
|
||||
std::string TextOperations::toUnicode(const std::string &text, const std::string &encoding)
|
||||
{
|
||||
return boost::locale::conv::to_utf<char>(text, encoding);
|
||||
try {
|
||||
return boost::locale::conv::to_utf<char>(text, encoding);
|
||||
}
|
||||
catch (const boost::locale::conv::conversion_error &)
|
||||
{
|
||||
throw std::runtime_error("Failed to convert text '" + text + "' from encoding " + encoding );
|
||||
}
|
||||
}
|
||||
|
||||
std::string TextOperations::fromUnicode(const std::string &text, const std::string &encoding)
|
||||
{
|
||||
return boost::locale::conv::from_utf<char>(text, encoding);
|
||||
try {
|
||||
return boost::locale::conv::from_utf<char>(text, encoding);
|
||||
}
|
||||
catch (const boost::locale::conv::conversion_error &)
|
||||
{
|
||||
throw std::runtime_error("Failed to convert text '" + text + "' to encoding " + encoding );
|
||||
}
|
||||
}
|
||||
|
||||
void TextOperations::trimRightUnicode(std::string & text, const size_t amount)
|
||||
|
@@ -230,10 +230,10 @@ QVariantMap TownEventDialog::resourcesToVariant()
|
||||
auto res = params.value("resources").toMap();
|
||||
for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i)
|
||||
{
|
||||
auto * itemType = ui->resourcesTable->item(i, 0);
|
||||
auto itemType = QString::fromStdString(GameConstants::RESOURCE_NAMES[i]);
|
||||
auto * itemQty = static_cast<QSpinBox *> (ui->resourcesTable->cellWidget(i, 1));
|
||||
|
||||
res[itemType->text()] = QVariant::fromValue(itemQty->value());
|
||||
res[itemType] = QVariant::fromValue(itemQty->value());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@@ -979,10 +979,12 @@ void MainWindow::on_actionLevel_triggered()
|
||||
ui->minimapView->setScene(controller.miniScene(mapLevel));
|
||||
if (mapLevel == 0)
|
||||
{
|
||||
ui->actionLevel->setText(tr("View underground"));
|
||||
ui->actionLevel->setToolTip(tr("View underground"));
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->actionLevel->setText(tr("View surface"));
|
||||
ui->actionLevel->setToolTip(tr("View surface"));
|
||||
}
|
||||
}
|
||||
|
@@ -1067,7 +1067,7 @@
|
||||
</action>
|
||||
<action name="actionLevel">
|
||||
<property name="text">
|
||||
<string>U/G</string>
|
||||
<string>View underground</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>View underground</string>
|
||||
|
@@ -96,9 +96,9 @@ void TimedEvent::on_TimedEvent_finished(int result)
|
||||
auto res = target->data(Qt::UserRole).toMap().value("resources").toMap();
|
||||
for(int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i)
|
||||
{
|
||||
auto * itemType = ui->resources->item(i, 0);
|
||||
auto itemType = QString::fromStdString(GameConstants::RESOURCE_NAMES[i]);
|
||||
auto * itemQty = ui->resources->item(i, 1);
|
||||
res[itemType->text()] = QVariant::fromValue(itemQty->text().toInt());
|
||||
res[itemType] = QVariant::fromValue(itemQty->text().toInt());
|
||||
}
|
||||
descriptor["resources"] = res;
|
||||
|
||||
|
@@ -464,7 +464,7 @@
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="1141"/>
|
||||
<source>General</source>
|
||||
<translation>Všeobecné</translation>
|
||||
<translation>Nastavení</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="1144"/>
|
||||
@@ -474,7 +474,7 @@
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="1155"/>
|
||||
<source>Players settings</source>
|
||||
<translation>Hráčské nastavení</translation>
|
||||
<translation>Hráči</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="1166"/>
|
||||
@@ -500,7 +500,7 @@
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="1216"/>
|
||||
<source>Validate</source>
|
||||
<translation>Ověřit</translation>
|
||||
<translation>Validátor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="1227"/>
|
||||
@@ -2457,7 +2457,7 @@
|
||||
<message>
|
||||
<location filename="../validator.ui" line="17"/>
|
||||
<source>Map validation results</source>
|
||||
<translation>Výsledky ověření mapy</translation>
|
||||
<translation>Výsledky validátoru</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../validator.cpp" line="54"/>
|
||||
@@ -2660,10 +2660,6 @@
|
||||
<source>Map size</source>
|
||||
<translation>Velikost mapy</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Two level map</source>
|
||||
<translation type="vanished">Dvouvrstvá mapa</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="200"/>
|
||||
<source>Height</source>
|
||||
@@ -2689,14 +2685,6 @@
|
||||
<source>Players</source>
|
||||
<translation>Hráči</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>0</source>
|
||||
<translation type="vanished">0</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Human/Computer</source>
|
||||
<translation type="vanished">Hráč/počítač</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="93"/>
|
||||
<source>S (36x36)</source>
|
||||
@@ -2735,10 +2723,6 @@
|
||||
<source>Random</source>
|
||||
<translation>Náhodně</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Computer only</source>
|
||||
<translation type="vanished">Pouze počítač</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="444"/>
|
||||
<source>Human teams</source>
|
||||
@@ -2851,10 +2835,6 @@
|
||||
<source>OK</source>
|
||||
<translation>OK</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ok</source>
|
||||
<translation type="vanished">Dobře</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="1044"/>
|
||||
<source>Cancel</source>
|
||||
|
Reference in New Issue
Block a user