1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-18 03:21:27 +02:00

Merge remote-tracking branch 'upstream/develop' into develop

This commit is contained in:
Xilmi 2024-12-21 12:09:05 +01:00
commit 371063c44e
17 changed files with 83 additions and 70 deletions

View File

@ -1,10 +1,11 @@
# VCMI Project Changelog
## 1.5.7 -> 1.6.0 (in development)
## 1.5.7 -> 1.6.0
### Major changes
* Greatly improved decision-making of NullkillerAI
* Implemented support for multiple mod presets allowing player to quickly switch between them in Launcher
* Implemented handicap system, with options to reduce income and growth in addition to starting resources restriction
* Game will now show statistics after scenario completion, such as resources or army strength over time
* Implemented spell quick selection panel in combat
@ -66,6 +67,7 @@
* Mutare and Mutare Drake are now Overlord and not Warlock
* Elixir of Life no longer affects siege machines
* Banned skills known by hero now have minimal chance (1) instead of 0 to appear on levelup
* The Transport Artifact victory condition fulfilled by the enemy AI will no longer trigger a victory for human players if "standard victory" is enabled on the map
### Video / Audio
@ -178,6 +180,12 @@
### Launcher
* Implemented support for multiple mod presets allowing player to quickly switch between them
* Added new Start Game page to Launcher which is now used when starting the game
* Added option to create empty mod preset to quickly disable all mods
* Added button to update all installed mods to Start Game page
* Added diagnostics to detect common issues with Heroes III data files
* Added built-in help descriptions for functionalities such as data files import to better explain them to players
* It is now always possible to disable or uninstall a mod. Any mods that depend on this mod will be automatically disabled
* It is now always possible to update a mod, even if there are mods that depend on this mod.
* It is now possible to enable mod that conflicts with already active mod. Conflicting mods will be automatically disabled
@ -188,6 +196,8 @@
* Launcher will now correctly show conflicts on both sides - if mod A is marked as conflicting with B, then information on this conflict will be shown in description of both mod A and mod B (instead of only in mod B)
* Added Swedish translation
* Added better diagnostics for gog installer extraction errors
* It is no longer possible to start installation or update for a mod that is already being downloaded
* Fixed detection of existing Heroes III Complete or Shadow of Death data files during import
### Map Editor

View File

@ -26,7 +26,7 @@ android {
minSdk = qtMinSdkVersion as Integer
targetSdk = qtTargetSdkVersion as Integer // ANDROID_TARGET_SDK_VERSION in the CMake project
versionCode 1600
versionCode 1610
versionName "1.6.0"
setProperty("archivesBaseName", "vcmi")

View File

@ -12,6 +12,7 @@
#include "../renderSDL/SDL_Extensions.h"
#include "../lib/ExceptionsCommon.h"
#include "../lib/filesystem/Filesystem.h"
#include "../lib/vcmi_endian.h"
@ -112,40 +113,47 @@ SDL_Surface * BitmapHandler::loadBitmapFromDir(const ImagePath & path)
SDL_Surface * ret=nullptr;
auto readFile = CResourceHandler::get()->load(path)->readAll();
try {
auto readFile = CResourceHandler::get()->load(path)->readAll();
if (isPCX(readFile.first.get()))
{//H3-style PCX
ret = loadH3PCX(readFile.first.get(), readFile.second);
if (!ret)
{
logGlobal->error("Failed to open %s as H3 PCX!", path.getOriginalName());
return nullptr;
}
}
else
{ //loading via SDL_Image
ret = IMG_Load_RW(
//create SDL_RW with our data (will be deleted by SDL)
SDL_RWFromConstMem((void*)readFile.first.get(), (int)readFile.second),
1); // mark it for auto-deleting
if (ret)
{
if (ret->format->palette)
if (isPCX(readFile.first.get()))
{//H3-style PCX
ret = loadH3PCX(readFile.first.get(), readFile.second);
if (!ret)
{
// set correct value for alpha\unused channel
// NOTE: might be unnecessary with SDL2
for (int i=0; i < ret->format->palette->ncolors; i++)
ret->format->palette->colors[i].a = SDL_ALPHA_OPAQUE;
logGlobal->error("Failed to open %s as H3 PCX!", path.getOriginalName());
return nullptr;
}
}
else
{
logGlobal->error("Failed to open %s via SDL_Image", path.getOriginalName());
logGlobal->error("Reason: %s", IMG_GetError());
return nullptr;
{ //loading via SDL_Image
ret = IMG_Load_RW(
//create SDL_RW with our data (will be deleted by SDL)
SDL_RWFromConstMem((void*)readFile.first.get(), (int)readFile.second),
1); // mark it for auto-deleting
if (ret)
{
if (ret->format->palette)
{
// set correct value for alpha\unused channel
// NOTE: might be unnecessary with SDL2
for (int i=0; i < ret->format->palette->ncolors; i++)
ret->format->palette->colors[i].a = SDL_ALPHA_OPAQUE;
}
}
else
{
logGlobal->error("Failed to open %s via SDL_Image", path.getOriginalName());
logGlobal->error("Reason: %s", IMG_GetError());
return nullptr;
}
}
}
catch (const DataLoadingException & e)
{
logGlobal->error("%s", e.what());
return nullptr;
}
// When modifying anything here please check two use cases:
// 1) Vampire mansion in Necropolis (not 1st color is transparent)

View File

@ -111,12 +111,12 @@ public:
virtual bool isTransparent(const Point & coords) const = 0;
virtual void draw(SDL_Surface * where, SDL_Palette * palette, const Point & dest, const Rect * src, const ColorRGBA & colorMultiplier, uint8_t alpha, EImageBlitMode mode) const = 0;
virtual std::shared_ptr<IImage> createImageReference(EImageBlitMode mode) const = 0;
[[nodiscard]] virtual std::shared_ptr<IImage> createImageReference(EImageBlitMode mode) const = 0;
virtual std::shared_ptr<const ISharedImage> horizontalFlip() const = 0;
virtual std::shared_ptr<const ISharedImage> verticalFlip() const = 0;
virtual std::shared_ptr<const ISharedImage> scaleInteger(int factor, SDL_Palette * palette, EImageBlitMode blitMode) const = 0;
virtual std::shared_ptr<const ISharedImage> scaleTo(const Point & size, SDL_Palette * palette) const = 0;
[[nodiscard]] virtual std::shared_ptr<const ISharedImage> horizontalFlip() const = 0;
[[nodiscard]] virtual std::shared_ptr<const ISharedImage> verticalFlip() const = 0;
[[nodiscard]] virtual std::shared_ptr<const ISharedImage> scaleInteger(int factor, SDL_Palette * palette, EImageBlitMode blitMode) const = 0;
[[nodiscard]] virtual std::shared_ptr<const ISharedImage> scaleTo(const Point & size, SDL_Palette * palette) const = 0;
virtual ~ISharedImage() = default;

View File

@ -43,6 +43,9 @@ void ImageScaled::scaleInteger(int factor)
void ImageScaled::scaleTo(const Point & size)
{
if (source)
source = source->scaleTo(size, nullptr);
if (body)
body = body->scaleTo(size * GH.screenHandler().getScalingFactor(), nullptr);
}

View File

@ -57,11 +57,11 @@ public:
void exportBitmap(const boost::filesystem::path & path, SDL_Palette * palette) const override;
Point dimensions() const override;
bool isTransparent(const Point & coords) const override;
std::shared_ptr<IImage> createImageReference(EImageBlitMode mode) const override;
std::shared_ptr<const ISharedImage> horizontalFlip() const override;
std::shared_ptr<const ISharedImage> verticalFlip() const override;
std::shared_ptr<const ISharedImage> scaleInteger(int factor, SDL_Palette * palette, EImageBlitMode blitMode) const override;
std::shared_ptr<const ISharedImage> scaleTo(const Point & size, SDL_Palette * palette) const override;
[[nodiscard]] std::shared_ptr<IImage> createImageReference(EImageBlitMode mode) const override;
[[nodiscard]] std::shared_ptr<const ISharedImage> horizontalFlip() const override;
[[nodiscard]] std::shared_ptr<const ISharedImage> verticalFlip() const override;
[[nodiscard]] std::shared_ptr<const ISharedImage> scaleInteger(int factor, SDL_Palette * palette, EImageBlitMode blitMode) const override;
[[nodiscard]] std::shared_ptr<const ISharedImage> scaleTo(const Point & size, SDL_Palette * palette) const override;
friend class SDLImageLoader;
};

2
debian/changelog vendored
View File

@ -2,7 +2,7 @@ vcmi (1.6.0) jammy; urgency=medium
* New upstream release
-- Ivan Savenko <saven.ivan@gmail.com> Fri, 30 Aug 2024 12:00:00 +0200
-- Ivan Savenko <saven.ivan@gmail.com> Fri, 20 Dec 2024 12:00:00 +0200
vcmi (1.5.7) jammy; urgency=medium

View File

@ -1,9 +1,7 @@
# VCMI Project
[![VCMI](https://github.com/vcmi/vcmi/actions/workflows/github.yml/badge.svg?branch=develop&event=push)](https://github.com/vcmi/vcmi/actions/workflows/github.yml?query=branch%3Adevelop+event%3Apush)
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.0/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.0)
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.6/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.6)
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.7/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.7)
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.6.0/total)](https://github.com/vcmi/vcmi/releases/tag/1.6.0)
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/total)](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.

View File

@ -90,7 +90,7 @@
</screenshots>
<launchable type="desktop-id">vcmilauncher.desktop</launchable>
<releases>
<release version="1.6.0" date="2024-08-30" type="development"/>
<release version="1.6.0" date="2024-12-20" type="stable"/>
<release version="1.5.7" date="2024-08-26" type="stable"/>
<release version="1.5.6" date="2024-08-04" type="stable"/>
<release version="1.5.5" date="2024-07-17" type="stable"/>

View File

@ -55,8 +55,6 @@ class FirstLaunchView : public QWidget
bool checkCanInstallExtras();
bool checkCanInstallMod(const QString & modID);
void installMod(const QString & modID);
public:
explicit FirstLaunchView(QWidget * parent = nullptr);

View File

@ -55,7 +55,7 @@ void CModListView::changeEvent(QEvent *event)
if(event->type() == QEvent::LanguageChange)
{
ui->retranslateUi(this);
modModel->reloadRepositories();
modModel->reloadViewModel();
}
QWidget::changeEvent(event);
}
@ -127,7 +127,7 @@ CModListView::CModListView(QWidget * parent)
ui->progressWidget->setVisible(false);
dlManager = nullptr;
modModel->reloadRepositories();
modModel->reloadViewModel();
if(settings["launcher"]["autoCheckRepositories"].Bool())
loadRepositories();
@ -147,7 +147,7 @@ CModListView::CModListView(QWidget * parent)
void CModListView::reload()
{
modStateModel->reloadLocalState();
modModel->reloadRepositories();
modModel->reloadViewModel();
}
void CModListView::loadRepositories()
@ -611,7 +611,7 @@ void CModListView::on_uninstallButton_clicked()
if(modStateModel->isModEnabled(modName))
manager->disableMod(modName);
manager->uninstallMod(modName);
modModel->reloadRepositories();
reload();
}
checkManagerErrors();
@ -781,7 +781,8 @@ void CModListView::installFiles(QStringList files)
{
logGlobal->info("Installing repository: started");
manager->setRepositoryData(accumulatedRepositoryData);
modModel->reloadRepositories();
modModel->reloadViewModel();
accumulatedRepositoryData.clear();
static const QString repositoryCachePath = CLauncherDirs::downloadsPath() + "/repositoryCache.json";
JsonUtils::jsonToFile(repositoryCachePath, modStateModel->getRepositoryData());
@ -792,8 +793,7 @@ void CModListView::installFiles(QStringList files)
{
logGlobal->info("Installing mods: started");
installMods(mods);
modStateModel->reloadLocalState();
modModel->reloadRepositories();
reload();
logGlobal->info("Installing mods: ended");
}
@ -817,8 +817,7 @@ void CModListView::installFiles(QStringList files)
{
ChroniclesExtractor ce(this, [&prog](float progress) { prog = progress; });
ce.installChronicles(exe);
modStateModel->reloadLocalState();
modModel->reloadRepositories();
reload();
enableModByName("chronicles");
return true;
});
@ -835,8 +834,7 @@ void CModListView::installFiles(QStringList files)
ui->pushButton->setEnabled(true);
ui->progressWidget->setVisible(false);
//update
modStateModel->reloadLocalState();
modModel->reloadRepositories();
reload();
}
logGlobal->info("Installing chronicles: ended");
}
@ -877,6 +875,8 @@ void CModListView::installMods(QStringList archives)
}
}
reload(); // FIXME: better way that won't reset selection
for(int i = 0; i < modNames.size(); i++)
{
logGlobal->info("Installing mod '%s'", modNames[i].toStdString());
@ -884,6 +884,8 @@ void CModListView::installMods(QStringList archives)
manager->installMod(modNames[i], archives[i]);
}
reload();
if (!modsToEnable.empty())
{
manager->enableMods(modsToEnable);
@ -1128,7 +1130,7 @@ void CModListView::deletePreset(const QString & presetName)
void CModListView::activatePreset(const QString & presetName)
{
modStateModel->activatePreset(presetName);
modStateModel->reloadLocalState();
reload();
}
void CModListView::renamePreset(const QString & oldPresetName, const QString & newPresetName)

View File

@ -322,6 +322,9 @@ li.checked::marker { content: &quot;\2612&quot;; }
<property name="value">
<number>0</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="textVisible">
<bool>true</bool>
</property>

View File

@ -192,9 +192,6 @@ bool ModStateController::doInstallMod(QString modname, QString archivePath)
if(!QFile(archivePath).exists())
return addError(modname, tr("Mod archive is missing"));
if(localMods.contains(modname))
return addError(modname, tr("Mod with such name is already installed"));
std::vector<std::string> filesToExtract;
QString modDirName = ::detectModArchive(archivePath, modname, filesToExtract);
if(!modDirName.size())
@ -237,8 +234,6 @@ bool ModStateController::doInstallMod(QString modname, QString archivePath)
QString upperLevel = modDirName.section('/', 0, 0);
if(upperLevel != modDirName)
removeModDir(destDir + upperLevel);
modList->reloadLocalState();
return true;
}
@ -256,8 +251,6 @@ bool ModStateController::doUninstallMod(QString modname)
if(!removeModDir(modDir))
return addError(modname, tr("Mod is located in a protected directory, please remove it manually:\n") + modFullDir.absolutePath());
modList->reloadLocalState();
return true;
}

View File

@ -27,8 +27,6 @@ class ModStateController : public QObject, public boost::noncopyable
bool doInstallMod(QString mod, QString archivePath);
bool doUninstallMod(QString mod);
QVariantMap localMods;
QStringList recentErrors;
bool addError(QString modname, QString message);
bool removeModDir(QString mod);

View File

@ -195,7 +195,7 @@ QVariant ModStateItemModel::headerData(int section, Qt::Orientation orientation,
return QVariant();
}
void ModStateItemModel::reloadRepositories()
void ModStateItemModel::reloadViewModel()
{
beginResetModel();
endResetModel();

View File

@ -72,7 +72,7 @@ public:
explicit ModStateItemModel(std::shared_ptr<ModStateModel> model, QObject * parent);
/// CModListContainer overrides
void reloadRepositories();
void reloadViewModel();
void modChanged(QString modID);
QVariant data(const QModelIndex & index, int role) const override;

View File

@ -654,7 +654,7 @@ void ModManager::updatePreset(const ModDependenciesResolver & testResolver)
for (const auto & modID : newBrokenMods)
{
const auto & mod = getModDescription(modID);
if (vstd::contains(newActiveMods, mod.getTopParentID()))
if (mod.getTopParentID().empty() || vstd::contains(newActiveMods, mod.getTopParentID()))
modsPreset->setModActive(modID, false);
}