mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-19 21:10:12 +02:00
Merge pull request #5541 from IvanSavenko/crashfix
[beta] Backport of fixes for crashes
This commit is contained in:
commit
f3bd6e0b9c
@ -617,7 +617,13 @@ void SelectionTab::sort()
|
|||||||
if(!sortModeAscending)
|
if(!sortModeAscending)
|
||||||
{
|
{
|
||||||
if(firstMapIndex)
|
if(firstMapIndex)
|
||||||
std::reverse(std::next(curItems.begin(), boost::starts_with(curItems[0]->folderName, "..") ? 1 : 0), std::next(curItems.begin(), firstMapIndex - 1));
|
{
|
||||||
|
auto startIt = std::next(curItems.begin(), boost::starts_with(curItems[0]->folderName, "..") ? 1 : 0);
|
||||||
|
auto endIt = std::next(curItems.begin(), firstMapIndex - 1);
|
||||||
|
if(startIt > endIt)
|
||||||
|
std::swap(startIt, endIt);
|
||||||
|
std::reverse(startIt, endIt);
|
||||||
|
}
|
||||||
std::reverse(std::next(curItems.begin(), firstMapIndex), curItems.end());
|
std::reverse(std::next(curItems.begin(), firstMapIndex), curItems.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,6 +398,8 @@ void CHeroGSlot::gesture(bool on, const Point & initialPosition, const Point & f
|
|||||||
std::vector<std::shared_ptr<CComponent>> resComps;
|
std::vector<std::shared_ptr<CComponent>> resComps;
|
||||||
for(TResources::nziterator i(upgradableSlots.totalCosts); i.valid(); i++)
|
for(TResources::nziterator i(upgradableSlots.totalCosts); i.valid(); i++)
|
||||||
resComps.push_back(std::make_shared<CComponent>(ComponentType::RESOURCE, i->resType, i->resVal));
|
resComps.push_back(std::make_shared<CComponent>(ComponentType::RESOURCE, i->resType, i->resVal));
|
||||||
|
if(resComps.empty())
|
||||||
|
resComps.push_back(std::make_shared<CComponent>(ComponentType::RESOURCE, static_cast<GameResID>(GameResID::GOLD), 0)); // add at least gold, when there are no costs
|
||||||
resComps.back()->newLine = true;
|
resComps.back()->newLine = true;
|
||||||
for(auto & upgradeInfo : upgradableSlots.upgradeInfos)
|
for(auto & upgradeInfo : upgradableSlots.upgradeInfos)
|
||||||
resComps.push_back(std::make_shared<CComponent>(ComponentType::CREATURE, upgradeInfo.second.getUpgrade(), obj->Slots().at(upgradeInfo.first)->count));
|
resComps.push_back(std::make_shared<CComponent>(ComponentType::CREATURE, upgradeInfo.second.getUpgrade(), obj->Slots().at(upgradeInfo.first)->count));
|
||||||
|
@ -330,25 +330,6 @@ void FirstLaunchView::extractGogData()
|
|||||||
return file;
|
return file;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto checkMagic = [this](QString filename, QString filter, QByteArray magic)
|
|
||||||
{
|
|
||||||
QString titleErr = tr("You have to select %1 file!", "param is file extension").arg(filter);
|
|
||||||
|
|
||||||
QFile tmpFile(filename);
|
|
||||||
if(!tmpFile.open(QIODevice::ReadOnly))
|
|
||||||
{
|
|
||||||
QMessageBox::critical(this, tr("File cannot be opened"), tmpFile.errorString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QByteArray magicFile = tmpFile.read(magic.length());
|
|
||||||
if(!magicFile.startsWith(magic))
|
|
||||||
{
|
|
||||||
QMessageBox::critical(this, tr("Invalid file selected"), titleErr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
QString filterBin = tr("GOG data") + " (*.bin)";
|
QString filterBin = tr("GOG data") + " (*.bin)";
|
||||||
QString filterExe = tr("GOG installer") + " (*.exe)";
|
QString filterExe = tr("GOG installer") + " (*.exe)";
|
||||||
|
|
||||||
@ -363,10 +344,49 @@ void FirstLaunchView::extractGogData()
|
|||||||
ui->pushButtonGogInstall->setVisible(false);
|
ui->pushButtonGogInstall->setVisible(false);
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
|
|
||||||
QTimer::singleShot(100, this, [this, fileExe, fileBin, checkMagic, filterBin, filterExe](){ // background to make sure FileDialog is closed...
|
QTimer::singleShot(100, this, [this, fileBin, fileExe](){ // background to make sure FileDialog is closed...
|
||||||
|
extractGogDataAsync(fileBin, fileExe);
|
||||||
|
ui->progressBarGog->setVisible(false);
|
||||||
|
ui->pushButtonGogInstall->setVisible(true);
|
||||||
|
setEnabled(true);
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void FirstLaunchView::extractGogDataAsync(QString filePathBin, QString filePathExe)
|
||||||
|
{
|
||||||
|
logGlobal->info("Extracting gog data from '%s' and '%s'", filePathBin.toStdString(), filePathExe.toStdString());
|
||||||
|
|
||||||
|
#ifdef ENABLE_INNOEXTRACT
|
||||||
|
auto checkMagic = [](QString filename, QString filter, QByteArray magic)
|
||||||
|
{
|
||||||
|
logGlobal->info("Checking file %s", filename.toStdString());
|
||||||
|
|
||||||
|
QFile tmpFile(filename);
|
||||||
|
if(!tmpFile.open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
|
logGlobal->info("File cannot be opened: %s", tmpFile.errorString().toStdString());
|
||||||
|
return tr("Failed to open file: %1").arg(tmpFile.errorString());
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray magicFile = tmpFile.read(magic.length());
|
||||||
|
if(!magicFile.startsWith(magic))
|
||||||
|
{
|
||||||
|
logGlobal->info("Invalid file selected: %s", filter.toStdString());
|
||||||
|
return tr("You have to select %1 file!", "param is file extension").arg(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
logGlobal->info("Checking file %s", filename.toStdString());
|
||||||
|
return QString();
|
||||||
|
};
|
||||||
|
|
||||||
|
QString filterBin = tr("GOG data") + " (*.bin)";
|
||||||
|
QString filterExe = tr("GOG installer") + " (*.exe)";
|
||||||
|
|
||||||
QDir tempDir(pathToQString(VCMIDirs::get().userDataPath()));
|
QDir tempDir(pathToQString(VCMIDirs::get().userDataPath()));
|
||||||
if(tempDir.cd("tmp"))
|
if(tempDir.cd("tmp"))
|
||||||
{
|
{
|
||||||
|
logGlobal->info("Cleaning up old data");
|
||||||
tempDir.removeRecursively(); // remove if already exists (e.g. previous crash)
|
tempDir.removeRecursively(); // remove if already exists (e.g. previous crash)
|
||||||
tempDir.cdUp();
|
tempDir.cdUp();
|
||||||
}
|
}
|
||||||
@ -374,21 +394,27 @@ void FirstLaunchView::extractGogData()
|
|||||||
if(!tempDir.cd("tmp"))
|
if(!tempDir.cd("tmp"))
|
||||||
return; // should not happen - but avoid deleting wrong folder in any case
|
return; // should not happen - but avoid deleting wrong folder in any case
|
||||||
|
|
||||||
|
logGlobal->info("Using '%s' as temporary directory", tempDir.path().toStdString());
|
||||||
|
|
||||||
QString tmpFileExe = tempDir.filePath("h3_gog.exe");
|
QString tmpFileExe = tempDir.filePath("h3_gog.exe");
|
||||||
QString tmpFileBin = tempDir.filePath("h3_gog-1.bin");
|
QString tmpFileBin = tempDir.filePath("h3_gog-1.bin");
|
||||||
|
|
||||||
Helper::performNativeCopy(fileExe, tmpFileExe);
|
logGlobal->info("Performing native copy...");
|
||||||
Helper::performNativeCopy(fileBin, tmpFileBin);
|
Helper::performNativeCopy(filePathExe, tmpFileExe);
|
||||||
|
Helper::performNativeCopy(filePathBin, tmpFileBin);
|
||||||
if (!checkMagic(tmpFileBin, filterBin, QByteArray{"idska32"}) ||
|
logGlobal->info("Native copy completed");
|
||||||
!checkMagic(tmpFileExe, filterExe, QByteArray{"MZ"}))
|
|
||||||
return;
|
|
||||||
|
|
||||||
logGlobal->info("Installing exe '%s' ('%s')", tmpFileExe.toStdString(), fileExe.toStdString());
|
|
||||||
logGlobal->info("Installing bin '%s' ('%s')", tmpFileBin.toStdString(), fileBin.toStdString());
|
|
||||||
|
|
||||||
QString errorText{};
|
QString errorText{};
|
||||||
|
|
||||||
|
if (errorText.isEmpty())
|
||||||
|
errorText = checkMagic(tmpFileBin, filterBin, QByteArray{"idska32"});
|
||||||
|
|
||||||
|
if (errorText.isEmpty())
|
||||||
|
errorText = checkMagic(tmpFileExe, filterExe, QByteArray{"MZ"});
|
||||||
|
|
||||||
|
logGlobal->info("Installing exe '%s' ('%s')", tmpFileExe.toStdString(), filePathExe.toStdString());
|
||||||
|
logGlobal->info("Installing bin '%s' ('%s')", tmpFileBin.toStdString(), filePathBin.toStdString());
|
||||||
|
|
||||||
auto isGogGalaxyExe = [](QString fileToTest) {
|
auto isGogGalaxyExe = [](QString fileToTest) {
|
||||||
QFile file(fileToTest);
|
QFile file(fileToTest);
|
||||||
quint64 fileSize = file.size();
|
quint64 fileSize = file.size();
|
||||||
@ -404,22 +430,28 @@ void FirstLaunchView::extractGogData()
|
|||||||
return data.contains(magicId);
|
return data.contains(magicId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if(errorText.isEmpty())
|
||||||
|
{
|
||||||
if(isGogGalaxyExe(tmpFileExe))
|
if(isGogGalaxyExe(tmpFileExe))
|
||||||
|
{
|
||||||
|
logGlobal->info("Gog Galaxy detected! Aborting...");
|
||||||
errorText = tr("You've provided a GOG Galaxy installer! This file doesn't contain the game. Please download the offline backup game installer!");
|
errorText = tr("You've provided a GOG Galaxy installer! This file doesn't contain the game. Please download the offline backup game installer!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(errorText.isEmpty())
|
if(errorText.isEmpty())
|
||||||
|
{
|
||||||
|
logGlobal->info("Performing extraction using innoextract...");
|
||||||
errorText = Innoextract::extract(tmpFileExe, tempDir.path(), [this](float progress) {
|
errorText = Innoextract::extract(tmpFileExe, tempDir.path(), [this](float progress) {
|
||||||
ui->progressBarGog->setValue(progress * 100);
|
ui->progressBarGog->setValue(progress * 100);
|
||||||
qApp->processEvents();
|
qApp->processEvents();
|
||||||
});
|
});
|
||||||
|
logGlobal->info("Extraction done!");
|
||||||
|
}
|
||||||
|
|
||||||
QString hashError;
|
QString hashError;
|
||||||
if(!errorText.isEmpty())
|
if(!errorText.isEmpty())
|
||||||
hashError = Innoextract::getHashError(tmpFileExe, tmpFileBin, fileExe, fileBin);
|
hashError = Innoextract::getHashError(tmpFileExe, tmpFileBin, filePathExe, filePathBin);
|
||||||
|
|
||||||
ui->progressBarGog->setVisible(false);
|
|
||||||
ui->pushButtonGogInstall->setVisible(true);
|
|
||||||
setEnabled(true);
|
|
||||||
|
|
||||||
QStringList dirData = tempDir.entryList({"data"}, QDir::Filter::Dirs);
|
QStringList dirData = tempDir.entryList({"data"}, QDir::Filter::Dirs);
|
||||||
if(!errorText.isEmpty() || dirData.empty() || QDir(tempDir.filePath(dirData.front())).entryList({"*.lod"}, QDir::Filter::Files).empty())
|
if(!errorText.isEmpty() || dirData.empty() || QDir(tempDir.filePath(dirData.front())).entryList({"*.lod"}, QDir::Filter::Files).empty())
|
||||||
@ -439,10 +471,11 @@ void FirstLaunchView::extractGogData()
|
|||||||
tempDir.removeRecursively();
|
tempDir.removeRecursively();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logGlobal->info("Copying provided game files...");
|
||||||
copyHeroesData(tempDir.path(), true);
|
copyHeroesData(tempDir.path(), true);
|
||||||
|
|
||||||
tempDir.removeRecursively();
|
tempDir.removeRecursively();
|
||||||
});
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ class FirstLaunchView : public QWidget
|
|||||||
|
|
||||||
QString getHeroesInstallDir();
|
QString getHeroesInstallDir();
|
||||||
void extractGogData();
|
void extractGogData();
|
||||||
|
void extractGogDataAsync(QString filePathBin, QString filePathExe);
|
||||||
void copyHeroesData(const QString & path = {}, bool move = false);
|
void copyHeroesData(const QString & path = {}, bool move = false);
|
||||||
|
|
||||||
// Tab Mod Preset
|
// Tab Mod Preset
|
||||||
|
@ -474,9 +474,17 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h) const
|
|||||||
SetAvailableCreatures sac;
|
SetAvailableCreatures sac;
|
||||||
sac.tid = id;
|
sac.tid = id;
|
||||||
sac.creatures = creatures;
|
sac.creatures = creatures;
|
||||||
sac.creatures[0].first = !h->getArt(ArtifactPosition::MACH1); //ballista
|
|
||||||
sac.creatures[1].first = !h->getArt(ArtifactPosition::MACH3); //first aid tent
|
for (auto & entry : sac.creatures)
|
||||||
sac.creatures[2].first = !h->getArt(ArtifactPosition::MACH2); //ammo cart
|
{
|
||||||
|
CreatureID creature = entry.second.at(0);
|
||||||
|
ArtifactID warMachine = creature.toCreature()->warMachine;
|
||||||
|
|
||||||
|
if (h->hasArt(warMachine, true, false))
|
||||||
|
entry.first = 0;
|
||||||
|
else
|
||||||
|
entry.first = 1;
|
||||||
|
}
|
||||||
cb->sendAndApply(sac);
|
cb->sendAndApply(sac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2397,7 +2397,18 @@ bool CGameHandler::recruitCreatures(ObjectInstanceID objid, ObjectInstanceID dst
|
|||||||
COMPLAIN_RET_FALSE_IF(!hero, "Only hero can buy war machines");
|
COMPLAIN_RET_FALSE_IF(!hero, "Only hero can buy war machines");
|
||||||
COMPLAIN_RET_FALSE_IF(artId == ArtifactID::CATAPULT, "Catapult cannot be recruited!");
|
COMPLAIN_RET_FALSE_IF(artId == ArtifactID::CATAPULT, "Catapult cannot be recruited!");
|
||||||
COMPLAIN_RET_FALSE_IF(nullptr == art, "Invalid war machine artifact");
|
COMPLAIN_RET_FALSE_IF(nullptr == art, "Invalid war machine artifact");
|
||||||
|
COMPLAIN_RET_FALSE_IF(hero->hasArt(artId),"Hero already has this machine!");
|
||||||
|
|
||||||
|
bool hasFreeSlot = false;
|
||||||
|
for(auto slot : art->getPossibleSlots().at(ArtBearer::HERO))
|
||||||
|
if (hero->getArt(slot) == nullptr)
|
||||||
|
hasFreeSlot = true;
|
||||||
|
|
||||||
|
if (!hasFreeSlot)
|
||||||
|
{
|
||||||
|
auto slot = art->getPossibleSlots().at(ArtBearer::HERO).front();
|
||||||
|
removeArtifact(ArtifactLocation(hero->id, slot));
|
||||||
|
}
|
||||||
return giveHeroNewArtifact(hero, artId, ArtifactPosition::FIRST_AVAILABLE);
|
return giveHeroNewArtifact(hero, artId, ArtifactPosition::FIRST_AVAILABLE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
Loading…
x
Reference in New Issue
Block a user