2022-08-28 23:28:36 +02:00
|
|
|
#include "mainwindow.h"
|
|
|
|
#include "ui_mainwindow.h"
|
|
|
|
|
|
|
|
#include <QApplication.h>
|
|
|
|
#include <QFileDialog>
|
2022-08-29 20:19:05 +02:00
|
|
|
#include <QFile>
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QFileInfo>
|
2022-08-28 23:28:36 +02:00
|
|
|
|
|
|
|
#include "../lib/VCMIDirs.h"
|
|
|
|
#include "../lib/VCMI_Lib.h"
|
|
|
|
#include "../lib/logging/CBasicLogConfigurator.h"
|
|
|
|
#include "../lib/CConfigHandler.h"
|
|
|
|
#include "../lib/filesystem/Filesystem.h"
|
|
|
|
#include "../lib/GameConstants.h"
|
2022-08-29 20:19:05 +02:00
|
|
|
#include "../lib/mapping/CMapService.h"
|
|
|
|
#include "../lib/mapping/CMap.h"
|
2022-08-31 20:05:57 +02:00
|
|
|
#include "../lib/Terrain.h"
|
|
|
|
#include "../lib/mapObjects/CObjectClassesHandler.h"
|
2022-08-28 23:28:36 +02:00
|
|
|
|
|
|
|
|
|
|
|
#include "CGameInfo.h"
|
2022-08-30 00:44:02 +02:00
|
|
|
#include "maphandler.h"
|
2022-08-30 04:38:24 +02:00
|
|
|
#include "graphics.h"
|
2022-08-30 15:08:33 +02:00
|
|
|
#include "windownewmap.h"
|
2022-08-28 23:28:36 +02:00
|
|
|
|
|
|
|
static CBasicLogConfigurator * logConfig;
|
|
|
|
|
|
|
|
void init()
|
|
|
|
{
|
|
|
|
loadDLLClasses();
|
|
|
|
const_cast<CGameInfo*>(CGI)->setFromLib();
|
|
|
|
logGlobal->info("Initializing VCMI_Lib");
|
|
|
|
}
|
|
|
|
|
|
|
|
MainWindow::MainWindow(QWidget *parent) :
|
|
|
|
QMainWindow(parent),
|
|
|
|
ui(new Ui::MainWindow)
|
|
|
|
{
|
|
|
|
ui->setupUi(this);
|
|
|
|
|
2022-08-31 20:05:57 +02:00
|
|
|
ui->mapView->setMain(this);
|
|
|
|
|
2022-08-28 23:28:36 +02:00
|
|
|
//configure logging
|
|
|
|
const boost::filesystem::path logPath = VCMIDirs::get().userCachePath() / "VCMI_Editor_log.txt";
|
|
|
|
console = new CConsoleHandler();
|
|
|
|
logConfig = new CBasicLogConfigurator(logPath, console);
|
|
|
|
logConfig->configureDefault();
|
|
|
|
logGlobal->info("The log file will be saved to %s", logPath);
|
|
|
|
|
|
|
|
//init
|
|
|
|
preinitDLL(::console);
|
|
|
|
settings.init();
|
|
|
|
|
|
|
|
// Initialize logging based on settings
|
|
|
|
logConfig->configure();
|
|
|
|
logGlobal->debug("settings = %s", settings.toJsonNode().toJson());
|
|
|
|
|
|
|
|
// Some basic data validation to produce better error messages in cases of incorrect install
|
|
|
|
auto testFile = [](std::string filename, std::string message) -> bool
|
|
|
|
{
|
|
|
|
if (CResourceHandler::get()->existsResource(ResourceID(filename)))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
logGlobal->error("Error: %s was not found!", message);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
if(!testFile("DATA/HELP.TXT", "Heroes III data") ||
|
|
|
|
!testFile("MODS/VCMI/MOD.JSON", "VCMI data"))
|
|
|
|
{
|
|
|
|
QApplication::quit();
|
|
|
|
}
|
|
|
|
|
|
|
|
conf.init();
|
|
|
|
logGlobal->info("Loading settings");
|
|
|
|
|
|
|
|
CGI = new CGameInfo(); //contains all global informations about game (texts, lodHandlers, map handler etc.)
|
|
|
|
init();
|
|
|
|
|
2022-08-30 04:38:24 +02:00
|
|
|
graphics = new Graphics(); // should be before curh->init()
|
|
|
|
graphics->load();//must be after Content loading but should be in main thread
|
|
|
|
|
2022-08-28 23:28:36 +02:00
|
|
|
|
|
|
|
if(!testFile("DATA/new-menu/Background.png", "Cannot find file"))
|
|
|
|
{
|
|
|
|
QApplication::quit();
|
|
|
|
}
|
|
|
|
|
|
|
|
//now let's try to draw
|
|
|
|
auto resPath = *CResourceHandler::get()->getResourceName(ResourceID("DATA/new-menu/Background.png"));
|
|
|
|
|
2022-08-31 20:05:57 +02:00
|
|
|
scenes[0] = new MapScene(this, 0);
|
|
|
|
scenes[1] = new MapScene(this, 1);
|
|
|
|
ui->mapView->setScene(scenes[0]);
|
2022-08-28 23:28:36 +02:00
|
|
|
|
2022-08-30 15:08:33 +02:00
|
|
|
sceneMini = new QGraphicsScene(this);
|
|
|
|
ui->minimapView->setScene(sceneMini);
|
|
|
|
|
2022-08-31 20:05:57 +02:00
|
|
|
scenes[0]->addPixmap(QPixmap(QString::fromStdString(resPath.native())));
|
|
|
|
|
|
|
|
//loading objects
|
|
|
|
loadObjectsTree();
|
2022-08-30 15:08:33 +02:00
|
|
|
|
|
|
|
show();
|
2022-08-31 20:05:57 +02:00
|
|
|
|
|
|
|
setStatusMessage("privet");
|
2022-08-28 23:28:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
MainWindow::~MainWindow()
|
|
|
|
{
|
|
|
|
delete ui;
|
|
|
|
}
|
|
|
|
|
2022-08-31 20:05:57 +02:00
|
|
|
void MainWindow::setStatusMessage(const QString & status)
|
|
|
|
{
|
|
|
|
statusBar()->showMessage(status);
|
|
|
|
}
|
|
|
|
|
2022-08-30 23:24:12 +02:00
|
|
|
void MainWindow::reloadMap(int level)
|
2022-08-30 15:08:33 +02:00
|
|
|
{
|
|
|
|
MapHandler mapHandler(map.get());
|
|
|
|
|
|
|
|
for(int j = 0; j < map->height; ++j)
|
|
|
|
{
|
|
|
|
for(int i = 0; i < map->width; ++i)
|
|
|
|
{
|
2022-08-30 23:24:12 +02:00
|
|
|
mapHandler.drawTerrainTile(i, j, level);
|
|
|
|
mapHandler.drawObjects(i, j, level);
|
2022-08-30 15:08:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto mapSizePx = mapHandler.surface.rect();
|
2022-08-31 20:05:57 +02:00
|
|
|
float ratio = std::fmin(mapSizePx.width() / 192., mapSizePx.height() / 192.);
|
2022-08-30 15:08:33 +02:00
|
|
|
minimap = mapHandler.surface;
|
|
|
|
minimap.setDevicePixelRatio(ratio);
|
|
|
|
|
2022-08-31 20:05:57 +02:00
|
|
|
scenes[level]->updateViews(mapHandler.surface);
|
|
|
|
|
|
|
|
//sceneMini->clear();
|
|
|
|
//sceneMini->addPixmap(minimap);
|
|
|
|
}
|
2022-08-30 15:08:33 +02:00
|
|
|
|
2022-08-31 20:05:57 +02:00
|
|
|
CMap * MainWindow::getMap()
|
|
|
|
{
|
|
|
|
return map.get();
|
2022-08-30 15:08:33 +02:00
|
|
|
}
|
|
|
|
|
2022-08-30 23:24:12 +02:00
|
|
|
void MainWindow::setMapRaw(std::unique_ptr<CMap> cmap)
|
2022-08-30 15:08:33 +02:00
|
|
|
{
|
|
|
|
map = std::move(cmap);
|
2022-08-30 23:24:12 +02:00
|
|
|
}
|
|
|
|
|
2022-08-31 20:05:57 +02:00
|
|
|
void MainWindow::setMap(bool isNew)
|
2022-08-30 23:24:12 +02:00
|
|
|
{
|
2022-08-31 20:05:57 +02:00
|
|
|
unsaved = isNew;
|
|
|
|
if(isNew)
|
|
|
|
filename.clear();
|
|
|
|
|
|
|
|
setWindowTitle(filename + "* - VCMI Map Editor");
|
2022-08-30 15:08:33 +02:00
|
|
|
reloadMap();
|
2022-08-31 20:05:57 +02:00
|
|
|
if(map->twoLevel)
|
|
|
|
reloadMap(1);
|
|
|
|
|
|
|
|
mapLevel = 0;
|
|
|
|
ui->mapView->setScene(scenes[mapLevel]);
|
2022-08-30 15:08:33 +02:00
|
|
|
}
|
|
|
|
|
2022-08-28 23:28:36 +02:00
|
|
|
void MainWindow::on_actionOpen_triggered()
|
|
|
|
{
|
2022-08-30 15:08:33 +02:00
|
|
|
auto filenameSelect = QFileDialog::getOpenFileName(this, tr("Open Image"), QString::fromStdString(VCMIDirs::get().userCachePath().native()), tr("Homm3 Files (*.vmap *.h3m)"));
|
2022-08-29 20:19:05 +02:00
|
|
|
|
2022-08-30 15:08:33 +02:00
|
|
|
if(filenameSelect.isNull())
|
2022-08-29 20:19:05 +02:00
|
|
|
return;
|
|
|
|
|
2022-08-30 15:08:33 +02:00
|
|
|
QFileInfo fi(filenameSelect);
|
2022-08-29 20:19:05 +02:00
|
|
|
std::string fname = fi.fileName().toStdString();
|
|
|
|
std::string fdir = fi.dir().path().toStdString();
|
2022-08-30 02:48:44 +02:00
|
|
|
ResourceID resId("MAPS/" + fname, EResType::MAP);
|
|
|
|
//ResourceID resId("MAPS/SomeMap.vmap", EResType::MAP);
|
2022-08-29 20:19:05 +02:00
|
|
|
|
|
|
|
if(!CResourceHandler::get()->existsResource(resId))
|
|
|
|
{
|
|
|
|
QMessageBox::information(this, "Failed to open map", "Only map folder is supported");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CMapService mapService;
|
|
|
|
try
|
|
|
|
{
|
2022-08-30 00:44:02 +02:00
|
|
|
map = mapService.loadMap(resId);
|
2022-08-29 20:19:05 +02:00
|
|
|
}
|
|
|
|
catch(const std::exception & e)
|
|
|
|
{
|
|
|
|
QMessageBox::critical(this, "Failed to open map", e.what());
|
|
|
|
}
|
2022-08-30 00:44:02 +02:00
|
|
|
|
2022-08-31 20:05:57 +02:00
|
|
|
setMap(false);
|
2022-08-30 15:08:33 +02:00
|
|
|
}
|
|
|
|
|
2022-08-30 23:24:12 +02:00
|
|
|
void MainWindow::saveMap()
|
2022-08-30 15:08:33 +02:00
|
|
|
{
|
|
|
|
if(!map)
|
|
|
|
return;
|
|
|
|
|
2022-08-30 23:24:12 +02:00
|
|
|
if(!unsaved)
|
2022-08-30 15:08:33 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
CMapService mapService;
|
|
|
|
try
|
2022-08-30 00:44:02 +02:00
|
|
|
{
|
2022-08-30 23:24:12 +02:00
|
|
|
mapService.saveMap(map, filename.toStdString());
|
2022-08-30 00:44:02 +02:00
|
|
|
}
|
2022-08-30 15:08:33 +02:00
|
|
|
catch(const std::exception & e)
|
|
|
|
{
|
|
|
|
QMessageBox::critical(this, "Failed to save map", e.what());
|
|
|
|
}
|
|
|
|
|
|
|
|
unsaved = false;
|
|
|
|
setWindowTitle(filename + " - VCMI Map Editor");
|
|
|
|
}
|
|
|
|
|
2022-08-30 23:24:12 +02:00
|
|
|
void MainWindow::on_actionSave_as_triggered()
|
|
|
|
{
|
|
|
|
if(!map)
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto filenameSelect = QFileDialog::getSaveFileName(this, tr("Save map"), "", tr("VCMI maps (*.vmap)"));
|
|
|
|
|
|
|
|
if(filenameSelect.isNull())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(filenameSelect == filename)
|
|
|
|
return;
|
|
|
|
|
|
|
|
filename = filenameSelect;
|
|
|
|
|
|
|
|
saveMap();
|
|
|
|
}
|
|
|
|
|
2022-08-30 15:08:33 +02:00
|
|
|
|
|
|
|
void MainWindow::on_actionNew_triggered()
|
|
|
|
{
|
|
|
|
auto newMapDialog = new WindowNewMap(this);
|
2022-08-28 23:28:36 +02:00
|
|
|
}
|
|
|
|
|
2022-08-30 23:24:12 +02:00
|
|
|
void MainWindow::on_actionSave_triggered()
|
|
|
|
{
|
|
|
|
if(!map)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(filename.isNull())
|
|
|
|
{
|
|
|
|
auto filenameSelect = QFileDialog::getSaveFileName(this, tr("Save map"), "", tr("VCMI maps (*.vmap)"));
|
|
|
|
|
|
|
|
if(filenameSelect.isNull())
|
|
|
|
return;
|
|
|
|
|
|
|
|
filename = filenameSelect;
|
|
|
|
}
|
|
|
|
|
|
|
|
saveMap();
|
|
|
|
}
|
|
|
|
|
2022-08-31 20:05:57 +02:00
|
|
|
void MainWindow::loadObjectsTree()
|
|
|
|
{
|
|
|
|
for(auto & terrain : Terrain::Manager::terrains())
|
|
|
|
{
|
|
|
|
ui->listTerrains->addItem(QString::fromStdString(terrain));
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
createHandler(bth, "Bonus type", pomtime);
|
|
|
|
createHandler(generaltexth, "General text", pomtime);
|
|
|
|
createHandler(heroh, "Hero", pomtime);
|
|
|
|
createHandler(arth, "Artifact", pomtime);
|
|
|
|
createHandler(creh, "Creature", pomtime);
|
|
|
|
createHandler(townh, "Town", pomtime);
|
|
|
|
createHandler(objh, "Object", pomtime);
|
|
|
|
createHandler(objtypeh, "Object types information", pomtime);
|
|
|
|
createHandler(spellh, "Spell", pomtime);
|
|
|
|
createHandler(skillh, "Skill", pomtime);
|
|
|
|
createHandler(terviewh, "Terrain view pattern", pomtime);
|
|
|
|
createHandler(tplh, "Template", pomtime); //templates need already resolved identifiers (refactor?)
|
|
|
|
createHandler(scriptHandler, "Script", pomtime);
|
|
|
|
createHandler(battlefieldsHandler, "Battlefields", pomtime);
|
|
|
|
createHandler(obstacleHandler, "Obstacles", pomtime);*/
|
|
|
|
|
|
|
|
std::map<std::string, std::vector<std::string>> identifiers;
|
|
|
|
|
|
|
|
for(auto primaryID : VLC->objtypeh->knownObjects())
|
|
|
|
{
|
|
|
|
//QList<QStandardItem*> objTypes;
|
|
|
|
|
|
|
|
for(auto secondaryID : VLC->objtypeh->knownSubObjects(primaryID))
|
|
|
|
{
|
|
|
|
//QList<QStandardItem*> objSubTypes;
|
|
|
|
auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID);
|
|
|
|
|
|
|
|
/*if(handler->isStaticObject())
|
|
|
|
{
|
|
|
|
for(auto temp : handler->getTemplates())
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
|
|
|
|
identifiers[handler->typeName].push_back(handler->subTypeName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
objectsModel.setHorizontalHeaderLabels(QStringList() << QStringLiteral("Type"));
|
|
|
|
QList<QStandardItem*> objTypes;
|
|
|
|
for(auto & el1 : identifiers)
|
|
|
|
{
|
|
|
|
auto * objTypei = new QStandardItem(QString::fromStdString(el1.first));
|
|
|
|
for(auto & el2 : el1.second)
|
|
|
|
{
|
|
|
|
objTypei->appendRow(new QStandardItem(QString::fromStdString(el2)));
|
|
|
|
}
|
|
|
|
objectsModel.appendRow(objTypei);
|
|
|
|
}
|
|
|
|
ui->treeView->setModel(&objectsModel);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::on_actionLevel_triggered()
|
|
|
|
{
|
|
|
|
if(map && map->twoLevel)
|
|
|
|
{
|
|
|
|
mapLevel = mapLevel ? 0 : 1;
|
|
|
|
ui->mapView->setScene(scenes[mapLevel]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::on_actionPass_triggered(bool checked)
|
|
|
|
{
|
|
|
|
if(map)
|
|
|
|
{
|
|
|
|
scenes[0]->passabilityView.show(checked);
|
|
|
|
scenes[1]->passabilityView.show(checked);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MainWindow::on_actionGrid_triggered(bool checked)
|
|
|
|
{
|
|
|
|
if(map)
|
|
|
|
{
|
|
|
|
scenes[0]->gridView.show(checked);
|
|
|
|
scenes[1]->gridView.show(checked);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|