mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-22 22:13:35 +02:00
Merge branch 'cpp-map-editor' into EraseAction
This commit is contained in:
commit
ce2ab1a431
@ -21,6 +21,7 @@ set(editor_SRCS
|
||||
playerparams.cpp
|
||||
scenelayer.cpp
|
||||
mapcontroller.cpp
|
||||
validator.cpp
|
||||
)
|
||||
|
||||
set(editor_HEADERS
|
||||
@ -45,6 +46,7 @@ set(editor_HEADERS
|
||||
playerparams.h
|
||||
scenelayer.h
|
||||
mapcontroller.h
|
||||
validator.h
|
||||
)
|
||||
|
||||
set(editor_FORMS
|
||||
@ -54,6 +56,7 @@ set(editor_FORMS
|
||||
mapsettings.ui
|
||||
playersettings.ui
|
||||
playerparams.ui
|
||||
validator.ui
|
||||
)
|
||||
|
||||
assign_source_group(${editor_SRCS} ${editor_HEADERS} VCMI_launcher.rc)
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "inspector.h"
|
||||
#include "mapsettings.h"
|
||||
#include "playersettings.h"
|
||||
#include "validator.h"
|
||||
|
||||
static CBasicLogConfigurator * logConfig;
|
||||
|
||||
@ -229,6 +230,20 @@ void MainWindow::saveMap()
|
||||
|
||||
if(!unsaved)
|
||||
return;
|
||||
|
||||
//validate map
|
||||
auto issues = Validator::validate(controller.map());
|
||||
bool critical = false;
|
||||
for(auto & issue : issues)
|
||||
critical |= issue.critical;
|
||||
|
||||
if(!issues.empty())
|
||||
{
|
||||
if(critical)
|
||||
QMessageBox::warning(this, "Map validation", "Map has critical problems and most probably will not be playable. Open Validator from the Map menu to see issues found");
|
||||
else
|
||||
QMessageBox::information(this, "Map validation", "Map has some errors. Open Validator from the Map menu to see issues found");
|
||||
}
|
||||
|
||||
CMapService mapService;
|
||||
try
|
||||
@ -825,3 +840,9 @@ void MainWindow::onSelectionMade(int level, bool anythingSelected)
|
||||
ui->toolErase->setEnabled(anythingSelected);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionValidate_triggered()
|
||||
{
|
||||
new Validator(controller.map(), this);
|
||||
}
|
||||
|
||||
|
@ -85,6 +85,8 @@ private slots:
|
||||
|
||||
void on_actionPlayers_settings_triggered();
|
||||
|
||||
void on_actionValidate_triggered();
|
||||
|
||||
public slots:
|
||||
|
||||
void treeViewSelected(const QModelIndex &selected, const QModelIndex &deselected);
|
||||
|
@ -51,7 +51,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1024</width>
|
||||
<height>18</height>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
@ -69,6 +69,7 @@
|
||||
</property>
|
||||
<addaction name="actionMapSettings"/>
|
||||
<addaction name="actionPlayers_settings"/>
|
||||
<addaction name="actionValidate"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuEdit">
|
||||
<property name="title">
|
||||
@ -893,6 +894,11 @@
|
||||
<string>Neutral</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionValidate">
|
||||
<property name="text">
|
||||
<string>Validate</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
129
mapeditor/validator.cpp
Normal file
129
mapeditor/validator.cpp
Normal file
@ -0,0 +1,129 @@
|
||||
#include "StdInc.h"
|
||||
#include "validator.h"
|
||||
#include "ui_validator.h"
|
||||
#include "../lib/mapObjects/MapObjects.h"
|
||||
|
||||
Validator::Validator(const CMap * map, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::Validator)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
show();
|
||||
|
||||
std::array<QString, 2> icons{"mapeditor/icons/mod-update.png", "mapeditor/icons/mod-delete.png"};
|
||||
|
||||
for(auto & issue : Validator::validate(map))
|
||||
{
|
||||
auto * item = new QListWidgetItem(QIcon(icons[issue.critical ? 1 : 0]), issue.message);
|
||||
ui->listWidget->addItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
Validator::~Validator()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
std::list<Validator::Issue> Validator::validate(const CMap * map)
|
||||
{
|
||||
std::list<Validator::Issue> issues;
|
||||
|
||||
if(!map)
|
||||
{
|
||||
issues.emplace_back("Map is not loaded", true);
|
||||
return issues;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
int hplayers = 0;
|
||||
int cplayers = 0;
|
||||
std::map<int, int> amountOfCastles;
|
||||
for(int i = 0; i < map->players.size(); ++i)
|
||||
{
|
||||
auto & p = map->players[i];
|
||||
if(p.canAnyonePlay())
|
||||
amountOfCastles[i] = 0;
|
||||
if(p.canComputerPlay)
|
||||
++cplayers;
|
||||
if(p.canHumanPlay)
|
||||
++hplayers;
|
||||
if(p.allowedFactions.empty())
|
||||
issues.emplace_back(QString("No factions allowed for player %1").arg(i), true);
|
||||
}
|
||||
if(hplayers + cplayers == 0)
|
||||
issues.emplace_back("No players allowed to play this map", true);
|
||||
if(hplayers + cplayers == 1)
|
||||
issues.emplace_back("Map is allowed for one player and cannot be started", true);
|
||||
if(!hplayers)
|
||||
issues.emplace_back("No human players allowed to play this map", true);
|
||||
|
||||
for(auto o : map->objects)
|
||||
{
|
||||
if(auto * ins = dynamic_cast<CArmedInstance*>(o.get()))
|
||||
{
|
||||
if(ins->getOwner() == PlayerColor::UNFLAGGABLE)
|
||||
issues.emplace_back(QString("Armored instance %1 is UNFLAGGABLE but must have NEUTRAL or player owner").arg(ins->instanceName.c_str()), true);
|
||||
}
|
||||
if(auto * ins = dynamic_cast<CGTownInstance*>(o.get()))
|
||||
{
|
||||
bool has = amountOfCastles.count(ins->getOwner().getNum());
|
||||
if(!has && ins->getOwner() != PlayerColor::NEUTRAL)
|
||||
issues.emplace_back(QString("Town %1 has undefined owner %s").arg(ins->instanceName.c_str(), ins->getOwner().getStr().c_str()), true);
|
||||
if(has)
|
||||
++amountOfCastles[ins->getOwner().getNum()];
|
||||
}
|
||||
if(auto * ins = dynamic_cast<CGHeroInstance*>(o.get()))
|
||||
{
|
||||
bool has = amountOfCastles.count(ins->getOwner().getNum());
|
||||
if(!has)
|
||||
issues.emplace_back(QString("Hero %1 must have an owner").arg(ins->instanceName.c_str()), true);
|
||||
else
|
||||
issues.emplace_back(QString("Hero %1: heroes on map are not supported in current version").arg(ins->instanceName.c_str()), false);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto & mp : amountOfCastles)
|
||||
if(mp.second == 0)
|
||||
issues.emplace_back(QString("Player %1 doesn't have any starting town").arg(mp.first), false);
|
||||
|
||||
bool roadWarning = false;
|
||||
bool riverWarning = false;
|
||||
for(int k : {0, 1})
|
||||
{
|
||||
if(k && !map->twoLevel)
|
||||
break;
|
||||
for(int j = 0; j < map->height; ++j)
|
||||
{
|
||||
for(int i = 0; i < map->width; ++i)
|
||||
{
|
||||
if(map->getTile(int3(i, j, k)).roadType != ROAD_NAMES[0])
|
||||
roadWarning = true;
|
||||
if(map->getTile(int3(i, j, k)).riverType != RIVER_NAMES[0])
|
||||
riverWarning = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(roadWarning)
|
||||
issues.emplace_back("Roads are presented on the map but not supported by Map Editor", false);
|
||||
if(riverWarning)
|
||||
issues.emplace_back("Rivers are presented on the map but not supported by Map Editor", false);
|
||||
|
||||
if(map->name.empty())
|
||||
issues.emplace_back("Map name is not specified", false);
|
||||
if(map->description.empty())
|
||||
issues.emplace_back("Map description is not specified", false);
|
||||
}
|
||||
catch(const std::exception & e)
|
||||
{
|
||||
issues.emplace_back(QString("Exception occurs during validation: %1").arg(e.what()), true);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
issues.emplace_back("Unknown exception occurs during validation", true);
|
||||
}
|
||||
|
||||
return issues;
|
||||
}
|
33
mapeditor/validator.h
Normal file
33
mapeditor/validator.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef VALIDATOR_H
|
||||
#define VALIDATOR_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "../lib/mapping/CMap.h"
|
||||
|
||||
namespace Ui {
|
||||
class Validator;
|
||||
}
|
||||
|
||||
class Validator : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct Issue
|
||||
{
|
||||
QString message;
|
||||
bool critical;
|
||||
|
||||
Issue(const QString & m, bool c): message(m), critical(c) {}
|
||||
};
|
||||
|
||||
public:
|
||||
explicit Validator(const CMap * map, QWidget *parent = nullptr);
|
||||
~Validator();
|
||||
|
||||
static std::list<Issue> validate(const CMap * map);
|
||||
|
||||
private:
|
||||
Ui::Validator *ui;
|
||||
};
|
||||
|
||||
#endif // VALIDATOR_H
|
72
mapeditor/validator.ui
Normal file
72
mapeditor/validator.ui
Normal file
@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Validator</class>
|
||||
<widget class="QDialog" name="Validator">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::NonModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>482</width>
|
||||
<height>178</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Map validation results</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>18</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="resizeMode">
|
||||
<enum>QListView::Adjust</enum>
|
||||
</property>
|
||||
<property name="gridSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="viewMode">
|
||||
<enum>QListView::ListMode</enum>
|
||||
</property>
|
||||
<property name="uniformItemSizes">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
Loading…
Reference in New Issue
Block a user