1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-22 22:13:35 +02:00

Implemented object placement and filtering

This commit is contained in:
nordsoft 2022-09-03 08:12:07 +04:00
parent c17b1f909d
commit 0fffa846b4
17 changed files with 627 additions and 128 deletions

View File

@ -42,6 +42,11 @@ int CMapGenerator::getRandomSeed() const
return randomSeed;
}
void CMapGenerator::disableModificator(const std::string & modificator)
{
disabledModificators.insert(modificator);
}
void CMapGenerator::loadConfig()
{
static const ResourceID path("config/randomMap.json");
@ -137,7 +142,7 @@ std::unique_ptr<CMap> CMapGenerator::generate(bool empty)
genZones();
Load::Progress::step();
map->map().calculateGuardingGreaturePositions(); //clear map so that all tiles are unguarded
map->addModificators();
map->addModificators(disabledModificators);
Load::Progress::step(3);
fillZones();
//updated guarded tiles will be calculated in CGameState::initMapObjects()

View File

@ -57,6 +57,7 @@ public:
const CMapGenOptions& getMapGenOptions() const;
std::unique_ptr<CMap> generate(bool emptyMap = false);
void disableModificator(const std::string & modificator);
void findZonesForQuestArts();
@ -76,6 +77,7 @@ private:
CMapGenOptions& mapGenOptions;
Config config;
std::unique_ptr<RmgMap> map;
std::set<std::string> disabledModificators;
std::vector<rmg::ZoneConnection> connectionsLeft;

View File

@ -108,38 +108,38 @@ void RmgMap::initTiles(CMapGenerator & generator)
}
}
void RmgMap::addModificators()
void RmgMap::addModificators(const std::set<std::string> & disableModificators)
{
for(auto & z : getZones())
{
auto zone = z.second;
zone->addModificator<ObjectManager>();
zone->addModificator<TreasurePlacer>();
zone->addModificator<ObstaclePlacer>();
zone->addModificator<TerrainPainter>();
zone->addModificator<TreasurePlacer>(!disableModificators.count("TreasurePlacer"));
zone->addModificator<ObstaclePlacer>(!disableModificators.count("ObstaclePlacer"));
zone->addModificator<TerrainPainter>(!disableModificators.count("TerrainPainter"));
if(zone->getType() == ETemplateZoneType::WATER)
{
for(auto & z1 : getZones())
{
z1.second->addModificator<WaterAdopter>();
z1.second->addModificator<WaterAdopter>(!disableModificators.count("Water"));
z1.second->getModificator<WaterAdopter>()->setWaterZone(zone->getId());
}
zone->addModificator<WaterProxy>();
zone->addModificator<WaterRoutes>();
zone->addModificator<WaterProxy>(!disableModificators.count("Water"));
zone->addModificator<WaterRoutes>(!disableModificators.count("WaterRoutes") && !disableModificators.count("Water"));
}
else
{
zone->addModificator<TownPlacer>();
zone->addModificator<ConnectionsPlacer>();
zone->addModificator<RoadPlacer>();
zone->addModificator<RiverPlacer>();
zone->addModificator<ConnectionsPlacer>(!disableModificators.count("ConnectionsPlacer"));
zone->addModificator<RoadPlacer>(!disableModificators.count("RoadPlacer"));
zone->addModificator<RiverPlacer>(!disableModificators.count("RiverPlacer"));
}
if(zone->isUnderground())
{
zone->addModificator<RockPlacer>();
zone->addModificator<RockPlacer>(!disableModificators.count("RockPlacer"));
}
}

View File

@ -62,7 +62,7 @@ public:
ui32 getZoneCount(TFaction faction);
ui32 getTotalZoneCount() const;
void initTiles(CMapGenerator & generator);
void addModificators();
void addModificators(const std::set<std::string> & disableModificators);
bool isAllowedSpell(SpellID sid) const;

View File

@ -304,6 +304,11 @@ Modificator::Modificator(Zone & zone, RmgMap & map, CMapGenerator & generator) :
{
}
void Modificator::disable()
{
enabled = false;
}
void Modificator::setName(const std::string & n)
{
name = n;
@ -333,7 +338,8 @@ void Modificator::run()
CStopWatch processTime;
try
{
process();
if(enabled)
process();
}
catch(rmgException &e)
{

View File

@ -50,6 +50,8 @@ public:
void setName(const std::string & n);
const std::string & getName() const;
void disable();
void run();
void dependency(Modificator * modificator);
@ -66,6 +68,7 @@ private:
std::string name;
bool started = false;
bool finished = false;
bool enabled = true;
std::list<Modificator*> preceeders; //must be ordered container
void dump();
};
@ -115,9 +118,11 @@ public:
}
template<class T>
void addModificator()
void addModificator(bool enabled = true)
{
modificators.emplace_back(new T(*this, map, generator));
if(!enabled)
modificators.back()->disable();
}
void initModificators();

View File

@ -14,6 +14,7 @@ set(editor_SRCS
generatorprogress.cpp
mapview.cpp
radiopushbutton.cpp
objectbrowser.cpp
)
set(editor_HEADERS
@ -31,6 +32,7 @@ set(editor_HEADERS
generatorprogress.h
mapview.h
radiopushbutton.h
objectbrowser.h
)
set(editor_FORMS

View File

@ -25,6 +25,7 @@
#include "maphandler.h"
#include "graphics.h"
#include "windownewmap.h"
#include "objectbrowser.h"
static CBasicLogConfigurator * logConfig;
@ -91,7 +92,7 @@ MainWindow::MainWindow(QWidget *parent) :
}
//now let's try to draw
auto resPath = *CResourceHandler::get()->getResourceName(ResourceID("DATA/new-menu/Background.png"));
//auto resPath = *CResourceHandler::get()->getResourceName(ResourceID("DATA/new-menu/Background.png"));
scenes[0] = new MapScene(this, 0);
scenes[1] = new MapScene(this, 1);
@ -103,7 +104,7 @@ MainWindow::MainWindow(QWidget *parent) :
scenePreview = new QGraphicsScene(this);
ui->objectPreview->setScene(scenePreview);
scenes[0]->addPixmap(QPixmap(QString::fromStdString(resPath.native())));
//scenes[0]->addPixmap(QPixmap(QString::fromStdString(resPath.native())));
//loading objects
loadObjectsTree();
@ -292,86 +293,241 @@ void MainWindow::terrainButtonClicked(Terrain terrain)
scenes[mapLevel]->terrainView.draw();
}
void MainWindow::addGroupIntoCatalog(const std::string & groupName, bool staticOnly)
{
auto knownObjects = VLC->objtypeh->knownObjects();
for(auto ID : knownObjects)
{
if(catalog.count(ID))
continue;
addGroupIntoCatalog(groupName, staticOnly, ID);
}
}
void MainWindow::addGroupIntoCatalog(const std::string & groupName, bool staticOnly, int ID)
{
QStandardItem * itemGroup = nullptr;
auto itms = objectsModel.findItems(QString::fromStdString(groupName));
if(itms.empty())
{
itemGroup = new QStandardItem(QString::fromStdString(groupName));
objectsModel.appendRow(itemGroup);
}
else
{
itemGroup = itms.front();
}
auto knownSubObjects = VLC->objtypeh->knownSubObjects(ID);
bool singleSubObject = knownSubObjects.size() == 1;
for(auto secondaryID : knownSubObjects)
{
auto factory = VLC->objtypeh->getHandlerFor(ID, secondaryID);
auto templates = factory->getTemplates();
bool singleTemplate = templates.size() == 1;
if(staticOnly && !factory->isStaticObject())
continue;
auto * itemType = new QStandardItem(QString::fromStdString(factory->subTypeName));
for(int templateId = 0; templateId < templates.size(); ++templateId)
{
auto templ = templates[templateId];
QJsonObject data{{"id", QJsonValue(ID)},
{"subid", QJsonValue(secondaryID)},
{"template", QJsonValue(templateId)},
{"animationEditor", QString::fromStdString(templ.editorAnimationFile)},
{"animation", QString::fromStdString(templ.animationFile)}};
if(singleTemplate)
{
itemType->setData(data);
}
else
{
auto * item = new QStandardItem(QString::fromStdString(templ.stringID));
item->setData(data);
itemType->appendRow(item);
}
}
itemGroup->appendRow(itemType);
catalog.insert(ID);
}
}
void MainWindow::loadObjectsTree()
{
ui->terrainFilterCombo->addItem("");
//adding terrains
for(auto & terrain : Terrain::Manager::terrains())
{
QPushButton *b = new QPushButton(QString::fromStdString(terrain));
ui->terrainLayout->addWidget(b);
connect(b, &QPushButton::clicked, this, [this, terrain]{ terrainButtonClicked(terrain); });
//filter
ui->terrainFilterCombo->addItem(QString::fromStdString(terrain));
}
//add spacer to keep terrain button on the top
ui->terrainLayout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
if(objectBrowser)
throw std::runtime_error("object browser exists");
//model
objectsModel.setHorizontalHeaderLabels(QStringList() << QStringLiteral("Type"));
//adding towns
auto * itemGroup = new QStandardItem("TOWNS");
for(auto secondaryID : VLC->objtypeh->knownSubObjects(Obj::TOWN))
{
auto factory = VLC->objtypeh->getHandlerFor(Obj::TOWN, secondaryID);
auto * itemType = new QStandardItem(QString::fromStdString(factory->subTypeName));
for(int templateId = 0; templateId < factory->getTemplates().size(); ++templateId)
{
auto templ = factory->getTemplates()[templateId];
auto * item = new QStandardItem(QString::fromStdString(templ.stringID));
QJsonObject data{{"id", QJsonValue(Obj::TOWN)},
{"subid", QJsonValue(secondaryID)},
{"animationEditor", QString::fromStdString(templ.editorAnimationFile)},
{"animation", QString::fromStdString(templ.animationFile)}};
item->setData(data);
itemType->appendRow(item);
}
itemGroup->appendRow(itemType);
}
objectsModel.appendRow(itemGroup);
/*
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);*/
//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);
}
}
ui->treeView->setModel(&objectsModel);
objectBrowser = new ObjectBrowser(this);
objectBrowser->setSourceModel(&objectsModel);
objectBrowser->setDynamicSortFilter(false);
objectBrowser->setRecursiveFilteringEnabled(true);
ui->treeView->setModel(objectBrowser);
ui->treeView->setSelectionBehavior(QAbstractItemView::SelectItems);
ui->treeView->setSelectionMode(QAbstractItemView::SingleSelection);
connect(ui->treeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(treeViewSelected(const QModelIndex &, const QModelIndex &)));
//adding objects
addGroupIntoCatalog("TOWNS", false, Obj::TOWN);
addGroupIntoCatalog("TOWNS", false, Obj::RANDOM_TOWN);
addGroupIntoCatalog("TOWNS", false, Obj::SHIPYARD);
addGroupIntoCatalog("TOWNS", false, Obj::GARRISON);
addGroupIntoCatalog("TOWNS", false, Obj::GARRISON2);
addGroupIntoCatalog("MISC", false, Obj::ALTAR_OF_SACRIFICE);
addGroupIntoCatalog("MISC", false, Obj::ARENA);
addGroupIntoCatalog("MISC", false, Obj::BLACK_MARKET);
addGroupIntoCatalog("MISC", false, Obj::BORDERGUARD);
addGroupIntoCatalog("MISC", false, Obj::KEYMASTER);
addGroupIntoCatalog("MISC", false, Obj::BUOY);
addGroupIntoCatalog("MISC", false, Obj::CAMPFIRE);
addGroupIntoCatalog("MISC", false, Obj::CARTOGRAPHER);
addGroupIntoCatalog("MISC", false, Obj::SWAN_POND);
addGroupIntoCatalog("MISC", false, Obj::COVER_OF_DARKNESS);
addGroupIntoCatalog("MISC", false, Obj::CORPSE);
addGroupIntoCatalog("MISC", false, Obj::MARLETTO_TOWER);
addGroupIntoCatalog("MISC", false, Obj::DERELICT_SHIP);
addGroupIntoCatalog("MISC", false, Obj::DRAGON_UTOPIA);
addGroupIntoCatalog("MISC", false, Obj::FAERIE_RING);
addGroupIntoCatalog("MISC", false, Obj::FLOTSAM);
addGroupIntoCatalog("MISC", false, Obj::FOUNTAIN_OF_FORTUNE);
addGroupIntoCatalog("MISC", false, Obj::FOUNTAIN_OF_YOUTH);
addGroupIntoCatalog("MISC", false, Obj::GARDEN_OF_REVELATION);
addGroupIntoCatalog("MISC", false, Obj::HILL_FORT);
addGroupIntoCatalog("MISC", false, Obj::IDOL_OF_FORTUNE);
addGroupIntoCatalog("MISC", false, Obj::LIBRARY_OF_ENLIGHTENMENT);
addGroupIntoCatalog("MISC", false, Obj::LIGHTHOUSE);
addGroupIntoCatalog("MISC", false, Obj::SCHOOL_OF_MAGIC);
addGroupIntoCatalog("MISC", false, Obj::MAGIC_SPRING);
addGroupIntoCatalog("MISC", false, Obj::MAGIC_WELL);
addGroupIntoCatalog("MISC", false, Obj::MERCENARY_CAMP);
addGroupIntoCatalog("MISC", false, Obj::MERMAID);
addGroupIntoCatalog("MISC", false, Obj::MYSTICAL_GARDEN);
addGroupIntoCatalog("MISC", false, Obj::OASIS);
addGroupIntoCatalog("MISC", false, Obj::OBELISK);
addGroupIntoCatalog("MISC", false, Obj::REDWOOD_OBSERVATORY);
addGroupIntoCatalog("MISC", false, Obj::OCEAN_BOTTLE);
addGroupIntoCatalog("MISC", false, Obj::PILLAR_OF_FIRE);
addGroupIntoCatalog("MISC", false, Obj::STAR_AXIS);
addGroupIntoCatalog("MISC", false, Obj::RALLY_FLAG);
addGroupIntoCatalog("MISC", false, Obj::LEAN_TO);
addGroupIntoCatalog("MISC", false, Obj::WATERING_HOLE);
addGroupIntoCatalog("PRISON", false, Obj::PRISON);
addGroupIntoCatalog("ARTIFACTS", false, Obj::ARTIFACT);
addGroupIntoCatalog("ARTIFACTS", false, Obj::RANDOM_ART);
addGroupIntoCatalog("ARTIFACTS", false, Obj::RANDOM_TREASURE_ART);
addGroupIntoCatalog("ARTIFACTS", false, Obj::RANDOM_MINOR_ART);
addGroupIntoCatalog("ARTIFACTS", false, Obj::RANDOM_MAJOR_ART);
addGroupIntoCatalog("ARTIFACTS", false, Obj::RANDOM_RELIC_ART);
addGroupIntoCatalog("RESOURCES", false, Obj::PANDORAS_BOX);
addGroupIntoCatalog("RESOURCES", false, Obj::RANDOM_RESOURCE);
addGroupIntoCatalog("RESOURCES", false, Obj::RESOURCE);
addGroupIntoCatalog("RESOURCES", false, Obj::SEA_CHEST);
addGroupIntoCatalog("RESOURCES", false, Obj::TREASURE_CHEST);
addGroupIntoCatalog("RESOURCES", false, Obj::SPELL_SCROLL);
addGroupIntoCatalog("BANKS", false, Obj::CREATURE_BANK);
addGroupIntoCatalog("DWELLINGS", false, Obj::CREATURE_GENERATOR1);
addGroupIntoCatalog("DWELLINGS", false, Obj::CREATURE_GENERATOR2);
addGroupIntoCatalog("DWELLINGS", false, Obj::CREATURE_GENERATOR3);
addGroupIntoCatalog("DWELLINGS", false, Obj::CREATURE_GENERATOR4);
addGroupIntoCatalog("DWELLINGS", false, Obj::RANDOM_DWELLING);
addGroupIntoCatalog("DWELLINGS", false, Obj::RANDOM_DWELLING_LVL);
addGroupIntoCatalog("DWELLINGS", false, Obj::RANDOM_DWELLING_FACTION);
addGroupIntoCatalog("GROUNDS", false, Obj::CURSED_GROUND1);
addGroupIntoCatalog("GROUNDS", false, Obj::MAGIC_PLAINS1);
addGroupIntoCatalog("GROUNDS", false, Obj::CLOVER_FIELD);
addGroupIntoCatalog("GROUNDS", false, Obj::CURSED_GROUND2);
addGroupIntoCatalog("GROUNDS", false, Obj::EVIL_FOG);
addGroupIntoCatalog("GROUNDS", false, Obj::FAVORABLE_WINDS);
addGroupIntoCatalog("GROUNDS", false, Obj::FIERY_FIELDS);
addGroupIntoCatalog("GROUNDS", false, Obj::HOLY_GROUNDS);
addGroupIntoCatalog("GROUNDS", false, Obj::LUCID_POOLS);
addGroupIntoCatalog("GROUNDS", false, Obj::MAGIC_CLOUDS);
addGroupIntoCatalog("GROUNDS", false, Obj::MAGIC_PLAINS2);
addGroupIntoCatalog("GROUNDS", false, Obj::ROCKLANDS);
addGroupIntoCatalog("TELEPORTS", false, Obj::MONOLITH_ONE_WAY_ENTRANCE);
addGroupIntoCatalog("TELEPORTS", false, Obj::MONOLITH_ONE_WAY_EXIT);
addGroupIntoCatalog("TELEPORTS", false, Obj::MONOLITH_TWO_WAY);
addGroupIntoCatalog("TELEPORTS", false, Obj::SUBTERRANEAN_GATE);
addGroupIntoCatalog("TELEPORTS", false, Obj::WHIRLPOOL);
addGroupIntoCatalog("MINES", false, Obj::MINE);
addGroupIntoCatalog("MINES", false, Obj::ABANDONED_MINE);
addGroupIntoCatalog("MINES", false, Obj::WINDMILL);
addGroupIntoCatalog("MINES", false, Obj::WATER_WHEEL);
addGroupIntoCatalog("TRIGGERS", false, Obj::EVENT);
addGroupIntoCatalog("TRIGGERS", false, Obj::GRAIL);
addGroupIntoCatalog("TRIGGERS", false, Obj::SIGN);
addGroupIntoCatalog("MONSTERS", false, Obj::MONSTER);
addGroupIntoCatalog("MONSTERS", false, Obj::RANDOM_MONSTER);
addGroupIntoCatalog("MONSTERS", false, Obj::RANDOM_MONSTER_L1);
addGroupIntoCatalog("MONSTERS", false, Obj::RANDOM_MONSTER_L2);
addGroupIntoCatalog("MONSTERS", false, Obj::RANDOM_MONSTER_L3);
addGroupIntoCatalog("MONSTERS", false, Obj::RANDOM_MONSTER_L4);
addGroupIntoCatalog("MONSTERS", false, Obj::RANDOM_MONSTER_L5);
addGroupIntoCatalog("MONSTERS", false, Obj::RANDOM_MONSTER_L6);
addGroupIntoCatalog("MONSTERS", false, Obj::RANDOM_MONSTER_L7);
addGroupIntoCatalog("QUESTS", false, Obj::SEER_HUT);
addGroupIntoCatalog("QUESTS", false, Obj::BORDER_GATE);
addGroupIntoCatalog("QUESTS", false, Obj::QUEST_GUARD);
addGroupIntoCatalog("QUESTS", false, Obj::HUT_OF_MAGI);
addGroupIntoCatalog("QUESTS", false, Obj::EYE_OF_MAGI);
addGroupIntoCatalog("OBSTACLES", true);
addGroupIntoCatalog("OTHER", false);
/*
HERO = 34,
LEAN_TO = 39,
PYRAMID = 63,//subtype 0
WOG_OBJECT = 63,//subtype > 0
RANDOM_HERO = 70,
REFUGEE_CAMP = 78,
SANCTUARY = 80,
SCHOLAR = 81,
CRYPT = 84,
SHIPWRECK = 85,
SHIPWRECK_SURVIVOR = 86,
SHRINE_OF_MAGIC_INCANTATION = 88,
SHRINE_OF_MAGIC_GESTURE = 89,
SHRINE_OF_MAGIC_THOUGHT = 90,
SIRENS = 92,
STABLES = 94,
TAVERN = 95,
TEMPLE = 96,
DEN_OF_THIEVES = 97,
TRADING_POST = 99,
LEARNING_STONE = 100,
TREE_OF_KNOWLEDGE = 102,
UNIVERSITY = 104,
WAGON = 105,
WAR_MACHINE_FACTORY = 106,
SCHOOL_OF_WAR = 107,
WARRIORS_TOMB = 108,
WITCH_HUT = 113,
HOLE = 124,
FREELANCERS_GUILD = 213,
HERO_PLACEHOLDER = 214,
TRADING_POST_SNOW = 221,
*/
}
void MainWindow::on_actionLevel_triggered()
@ -400,8 +556,6 @@ void MainWindow::on_actionGrid_triggered(bool checked)
scenes[0]->gridView.show(checked);
scenes[1]->gridView.show(checked);
}
auto idx = ui->treeView->selectionModel()->currentIndex();
}
@ -453,34 +607,48 @@ void MainWindow::on_toolErase_clicked()
}
}
void MainWindow::treeViewSelected(const QModelIndex & index, const QModelIndex & deselected)
void MainWindow::preparePreview(const QModelIndex &index, bool createNew)
{
objPreview.fill(QColor(255, 255, 255));
auto * item = objectsModel.itemFromIndex(index);
if(item)
auto data = objectsModel.itemFromIndex(objectBrowser->mapToSource(index))->data().toJsonObject();
if(!data.empty())
{
auto data = item->data().toJsonObject();
if(!data.empty())
auto animfile = data["animationEditor"];
if(animfile != QJsonValue::Undefined)
{
auto animfile = data["animationEditor"];
if(animfile != QJsonValue::Undefined)
{
if(animfile.toString().isEmpty())
animfile = data["animation"];
if(animfile.toString().isEmpty())
animfile = data["animation"];
QPainter painter(&objPreview);
Animation animation(animfile.toString().toStdString());
animation.preload();
auto picture = animation.getImage(0);
if(picture && picture->width() && picture->height())
{
qreal xscale = qreal(128) / qreal(picture->width()), yscale = qreal(128) / qreal(picture->height());
qreal scale = std::min(xscale, yscale);
painter.scale(scale, scale);
painter.drawImage(QPoint(0, 0), *picture);
}
QPainter painter(&objPreview);
Animation animation(animfile.toString().toStdString());
animation.preload();
auto picture = animation.getImage(0);
if(picture && picture->width() && picture->height())
{
qreal xscale = qreal(128) / qreal(picture->width()), yscale = qreal(128) / qreal(picture->height());
qreal scale = std::min(xscale, yscale);
painter.scale(scale, scale);
painter.drawImage(QPoint(0, 0), *picture);
}
auto objId = data["id"].toInt();
auto objSubId = data["subid"].toInt();
auto templateId = data["template"].toInt();
scenes[mapLevel]->selectionObjectsView.clear();
if(scenes[mapLevel]->selectionObjectsView.newObject)
{
createNew = true;
delete scenes[mapLevel]->selectionObjectsView.newObject;
}
if(createNew)
{
auto factory = VLC->objtypeh->getHandlerFor(objId, objSubId);
auto templ = factory->getTemplates()[templateId];
scenes[mapLevel]->selectionObjectsView.newObject = factory->create(templ);
scenes[mapLevel]->selectionObjectsView.draw();
}
}
}
@ -489,3 +657,44 @@ void MainWindow::treeViewSelected(const QModelIndex & index, const QModelIndex &
scenePreview->addPixmap(objPreview);
}
void MainWindow::treeViewSelected(const QModelIndex & index, const QModelIndex & deselected)
{
preparePreview(index, false);
}
void MainWindow::on_treeView_activated(const QModelIndex &index)
{
ui->toolBrush->setChecked(false);
ui->toolBrush2->setChecked(false);
ui->toolBrush4->setChecked(false);
ui->toolArea->setChecked(false);
ui->toolLasso->setChecked(false);
ui->mapView->selectionTool = MapView::SelectionTool::None;
preparePreview(index, true);
}
void MainWindow::on_terrainFilterCombo_currentTextChanged(const QString &arg1)
{
if(!objectBrowser)
return;
objectBrowser->terrain = arg1.isEmpty() ? Terrain::ANY : Terrain(arg1.toStdString());
objectBrowser->invalidate();
objectBrowser->sort(0);
}
void MainWindow::on_filter_textChanged(const QString &arg1)
{
if(!objectBrowser)
return;
objectBrowser->filter = arg1;
objectBrowser->invalidate();
objectBrowser->sort(0);
}

View File

@ -10,6 +10,7 @@
#include "mapview.h"
class CMap;
class ObjectBrowser;
namespace Ui {
class MainWindow;
@ -38,6 +39,8 @@ public:
MapView * getMapView();
int getMapLevel() const {return mapLevel;}
private slots:
void on_actionOpen_triggered();
@ -61,13 +64,24 @@ private slots:
void on_toolErase_clicked();
void on_treeView_activated(const QModelIndex &index);
void on_terrainFilterCombo_currentTextChanged(const QString &arg1);
void on_filter_textChanged(const QString &arg1);
public slots:
void treeViewSelected(const QModelIndex &selected, const QModelIndex &deselected);
private:
void preparePreview(const QModelIndex &index, bool createNew);
void addGroupIntoCatalog(const std::string & groupName, bool staticOnly);
void addGroupIntoCatalog(const std::string & groupName, bool staticOnly, int ID);
private:
Ui::MainWindow *ui;
ObjectBrowser * objectBrowser = nullptr;
std::unique_ptr<MapHandler> mapHandler;
std::array<MapScene *, 2> scenes;
QGraphicsScene * sceneMini;
@ -82,6 +96,8 @@ private:
QStandardItemModel objectsModel;
int mapLevel = 0;
std::set<int> catalog;
};
#endif // MAINWINDOW_H

View File

@ -35,6 +35,9 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="mouseTracking">
<bool>true</bool>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
@ -88,7 +91,7 @@
</widget>
<widget class="QDockWidget" name="dockWidget_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -161,7 +164,7 @@
</widget>
<widget class="QDockWidget" name="dockWidget_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -169,7 +172,7 @@
<property name="minimumSize">
<size>
<width>192</width>
<height>183</height>
<height>196</height>
</size>
</property>
<property name="maximumSize">
@ -223,6 +226,9 @@
<string>Objects</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
@ -245,6 +251,9 @@
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="filter"/>
</item>
<item>
<widget class="QTreeView" name="treeView">
<property name="sizePolicy">
@ -253,12 +262,21 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="mouseTracking">
<bool>false</bool>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::NoDragDrop</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectItems</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>

View File

@ -97,6 +97,53 @@ void MapHandler::drawTerrainTile(QPainter & painter, int x, int y, int z)
painter.drawImage(x * tileSize, y * tileSize, terrainImages.at(tinfo.terType)[tinfo.terView]->mirrored(hflip, vflip));
}
void MapHandler::drawRoad(QPainter & painter, int x, int y, int z)
{
auto & tinfo = map->getTile(int3(x, y, z));
auto * tinfoUpper = map->isInTheMap(int3(x, y - 1, z)) ? &map->getTile(int3(x, y - 1, z)) : nullptr;
/*if(tinfoUpper && tinfoUpper->roadType != ROAD_NAMES[0])
{
ui8 rotation = (tinfoUpper->extTileFlags >> 4) % 4;
bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3);
if(roadImages.at(tinfoUpper->roadType).size() > tinfoUpper->roadDir)
{
painter.drawImage(x * tileSize, y * tileSize, roadImages.at(tinfoUpper->roadType)[tinfoUpper->roadDir]->mirrored(hflip, vflip));
}
}*/
if(tinfo.roadType != ROAD_NAMES[0]) //print road from this tile
{
ui8 rotation = (tinfo.extTileFlags >> 4) % 4;
bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3);
if(roadImages.at(tinfo.roadType).size() > tinfo.roadDir)
{
painter.drawImage(x * tileSize, y * tileSize, roadImages.at(tinfo.roadType)[tinfo.roadDir]->mirrored(hflip, vflip));
}
}
}
void MapHandler::drawRiver(QPainter & painter, int x, int y, int z)
{
auto & tinfo = map->getTile(int3(x, y, z));
if(tinfo.riverType == RIVER_NAMES[0])
return;
if(riverImages.at(tinfo.riverType).size() <= tinfo.riverDir)
return;
ui8 rotation = (tinfo.extTileFlags >> 2) % 4;
bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3);
painter.drawImage(x * tileSize, y * tileSize, riverImages.at(tinfo.riverType)[tinfo.riverDir]->mirrored(hflip, vflip));
}
void MapHandler::initObjectRects()
{
//initializing objects / rects

View File

@ -88,9 +88,9 @@ public:
void drawTerrainTile(QPainter & painter, int x, int y, int z);
/// draws a river segment on current tile
//void drawRiver(const TerrainTile & tinfo) const;
void drawRiver(QPainter & painter, int x, int y, int z);
/// draws a road segment on current tile
//void drawRoad(const TerrainTile & tinfo, const TerrainTile * tinfoUpper) const;
void drawRoad(QPainter & painter, int x, int y, int z);
/// draws all objects on current tile (higher-level logic, unlike other draw*** methods)
void drawObjects(QPainter & painter, int x, int y, int z);
void drawObject(QPainter & painter, const TerrainTileObject & object);

View File

@ -37,14 +37,17 @@ void MapView::mouseMoveEvent(QMouseEvent *mouseEvent)
switch(selectionTool)
{
case MapView::SelectionTool::Brush:
if(pressedOnSelected)
if(mouseEvent->buttons() & Qt::RightButton)
sc->selectionTerrainView.erase(tile);
else
else if(mouseEvent->buttons() == Qt::LeftButton)
sc->selectionTerrainView.select(tile);
sc->selectionTerrainView.draw();
break;
case MapView::SelectionTool::Area:
if(mouseEvent->buttons() & Qt::RightButton)
break;
sc->selectionTerrainView.clear();
for(int j = std::min(tile.y, tileStart.y); j < std::max(tile.y, tileStart.y); ++j)
{
@ -57,8 +60,18 @@ void MapView::mouseMoveEvent(QMouseEvent *mouseEvent)
break;
case MapView::SelectionTool::None:
if(mouseEvent->buttons() & Qt::RightButton)
break;
auto sh = tile - tileStart;
sc->selectionObjectsView.shift = QPoint(sh.x, sh.y);
if((sh.x || sh.y) && sc->selectionObjectsView.newObject)
{
sc->selectionObjectsView.shift = QPoint(tile.x, tile.y);
sc->selectionObjectsView.selectObject(sc->selectionObjectsView.newObject);
}
sc->selectionObjectsView.draw();
break;
}
@ -85,14 +98,18 @@ void MapView::mousePressEvent(QMouseEvent *event)
case MapView::SelectionTool::Brush:
sc->selectionObjectsView.clear();
sc->selectionObjectsView.draw();
if(pressedOnSelected)
if(event->button() == Qt::RightButton)
sc->selectionTerrainView.erase(tileStart);
else
else if(event->button() == Qt::LeftButton)
sc->selectionTerrainView.select(tileStart);
sc->selectionTerrainView.draw();
break;
case MapView::SelectionTool::Area:
if(event->button() == Qt::RightButton)
break;
sc->selectionTerrainView.clear();
sc->selectionTerrainView.draw();
sc->selectionObjectsView.clear();
@ -102,9 +119,18 @@ void MapView::mousePressEvent(QMouseEvent *event)
case MapView::SelectionTool::None:
sc->selectionTerrainView.clear();
sc->selectionTerrainView.draw();
sc->selectionObjectsView.clear();
sc->selectionObjectsView.selectObjectAt(tileStart.x, tileStart.y);
sc->selectionObjectsView.draw();
if(sc->selectionObjectsView.newObject && sc->selectionObjectsView.isSelected(sc->selectionObjectsView.newObject))
{
}
else
{
sc->selectionObjectsView.clear();
if(event->button() == Qt::LeftButton)
sc->selectionObjectsView.selectObjectAt(tileStart.x, tileStart.y);
sc->selectionObjectsView.draw();
}
break;
}
@ -119,12 +145,24 @@ void MapView::mouseReleaseEvent(QMouseEvent *event)
if(!sc)
return;
if(sc->selectionObjectsView.newObject)
{
if(!sc->selectionObjectsView.isSelected(sc->selectionObjectsView.newObject) || event->button() == Qt::RightButton)
{
delete sc->selectionObjectsView.newObject;
sc->selectionObjectsView.newObject = nullptr;
}
}
switch(selectionTool)
{
case MapView::SelectionTool::None:
if(event->button() == Qt::RightButton)
break;
//switch position
if(sc->selectionObjectsView.applyShift())
{
sc->selectionObjectsView.newObject = nullptr;
main->resetMapHandler();
sc->updateViews();
}
@ -406,14 +444,24 @@ void TerrainView::draw(bool onlyDirty)
}
for(auto & t : forRedrawing)
{
//TODO: fix water and roads
main->getMapHandler()->drawTerrainTile(painter, t.x, t.y, scene->level);
//main->getMapHandler()->drawRiver(painter, t.x, t.y, scene->level);
//main->getMapHandler()->drawRoad(painter, t.x, t.y, scene->level);
}
}
else
{
for(int j = 0; j < map->height; ++j)
{
for(int i = 0; i < map->width; ++i)
{
//TODO: fix water and roads
main->getMapHandler()->drawTerrainTile(painter, i, j, scene->level);
//main->getMapHandler()->drawRiver(painter, i, j, scene->level);
//main->getMapHandler()->drawRoad(painter, i, j, scene->level);
}
}
}
dirty.clear();
@ -489,7 +537,7 @@ void ObjectsView::setDirty(const CGObjectInstance * object)
dirty.insert(object);
}
SelectionObjectsView::SelectionObjectsView(MainWindow * m, MapScene * s): BasicView(m, s)
SelectionObjectsView::SelectionObjectsView(MainWindow * m, MapScene * s): BasicView(m, s), newObject(nullptr)
{
}
@ -501,6 +549,9 @@ void SelectionObjectsView::update()
selectedObjects.clear();
shift = QPoint();
if(newObject)
delete newObject;
newObject = nullptr;
pixmap.reset(new QPixmap(map->width * 32, map->height * 32));
//pixmap->fill(QColor(0, 0, 0, 0));
@ -521,17 +572,20 @@ void SelectionObjectsView::draw()
for(auto * obj : selectedObjects)
{
QRect bbox(obj->getPosition().x, obj->getPosition().y, 1, 1);
for(auto & t : obj->getBlockedPos())
if(obj != newObject)
{
QPoint topLeft(std::min(t.x, bbox.topLeft().x()), std::min(t.y, bbox.topLeft().y()));
bbox.setTopLeft(topLeft);
QPoint bottomRight(std::max(t.x, bbox.bottomRight().x()), std::max(t.y, bbox.bottomRight().y()));
bbox.setBottomRight(bottomRight);
}
QRect bbox(obj->getPosition().x, obj->getPosition().y, 1, 1);
for(auto & t : obj->getBlockedPos())
{
QPoint topLeft(std::min(t.x, bbox.topLeft().x()), std::min(t.y, bbox.topLeft().y()));
bbox.setTopLeft(topLeft);
QPoint bottomRight(std::max(t.x, bbox.bottomRight().x()), std::max(t.y, bbox.bottomRight().y()));
bbox.setBottomRight(bottomRight);
}
painter.setOpacity(1.0);
painter.drawRect(bbox.x() * 32, bbox.y() * 32, bbox.width() * 32, bbox.height() * 32);
painter.setOpacity(1.0);
painter.drawRect(bbox.x() * 32, bbox.y() * 32, bbox.width() * 32, bbox.height() * 32);
}
//show translation
if(shift.x() || shift.y())
@ -601,8 +655,18 @@ bool SelectionObjectsView::applyShift()
for(auto * obj : selectedObjects)
{
int3 pos = obj->pos;
pos.z = main->getMapLevel();
pos.x += shift.x(); pos.y += shift.y();
main->getMap()->getEditManager()->moveObject(obj, pos);
if(obj == newObject)
{
newObject->pos = pos;
main->getMap()->getEditManager()->insertObject(newObject);
}
else
{
main->getMap()->getEditManager()->moveObject(obj, pos);
}
}
return true;
}
@ -614,6 +678,7 @@ void SelectionObjectsView::deleteSelection()
for(auto * obj : selectedObjects)
{
main->getMap()->getEditManager()->removeObject(obj);
delete obj;
}
clear();
}
@ -625,6 +690,16 @@ std::set<CGObjectInstance *> SelectionObjectsView::selectObjects(int x1, int y1,
return result;
}
void SelectionObjectsView::selectObject(CGObjectInstance * obj)
{
selectedObjects.insert(obj);
}
bool SelectionObjectsView::isSelected(const CGObjectInstance * obj) const
{
return selectedObjects.count(const_cast<CGObjectInstance*>(obj));
}
void SelectionObjectsView::clear()
{
selectedObjects.clear();

View File

@ -136,6 +136,8 @@ public:
CGObjectInstance * selectObjectAt(int x, int y);
std::set<CGObjectInstance *> selectObjects(int x1, int y1, int x2, int y2);
void selectObject(CGObjectInstance *);
bool isSelected(const CGObjectInstance *) const;
void moveSelection(int x, int y);
void clear();
@ -143,6 +145,7 @@ public:
void deleteSelection();
QPoint shift;
CGObjectInstance * newObject;
private:
std::set<CGObjectInstance *> selectedObjects;

View File

@ -0,0 +1,87 @@
#include "objectbrowser.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
ObjectBrowser::ObjectBrowser(QObject *parent)
: QSortFilterProxyModel{parent}, terrain(Terrain::ANY)
{
}
bool ObjectBrowser::filterAcceptsRow(int source_row, const QModelIndex & source_parent) const
{
bool result = QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
QModelIndex currentIndex = sourceModel()->index(source_row, 0, source_parent);
int childCount = currentIndex.model()->rowCount(currentIndex);
if(childCount)
return false;
auto item = dynamic_cast<QStandardItemModel*>(sourceModel())->itemFromIndex(currentIndex);
if(!item)
return result;
if(!filterAcceptsRowText(source_row, source_parent))
return false;
if(terrain == Terrain::ANY)
return result;
auto data = item->data().toJsonObject();
if(data.empty())
return result;
auto objIdJson = data["id"];
if(objIdJson == QJsonValue::Undefined)
return result;
auto objId = data["id"].toInt();
auto objSubId = data["subid"].toInt();
auto templateId = data["template"].toInt();
auto factory = VLC->objtypeh->getHandlerFor(objId, objSubId);
auto templ = factory->getTemplates()[templateId];
result = result & templ.canBePlacedAt(terrain);
//text filter
return result;
}
bool ObjectBrowser::filterAcceptsRowText(int source_row, const QModelIndex &source_parent) const
{
if(source_parent.isValid())
{
if(filterAcceptsRowText(source_parent.row(), source_parent.parent()))
return true;
}
QModelIndex index = sourceModel()->index(source_row, 0 ,source_parent);
if(!index.isValid())
return false;
auto item = dynamic_cast<QStandardItemModel*>(sourceModel())->itemFromIndex(index);
if(!item)
return false;
return (filter.isNull() || filter.isEmpty() || item->text().contains(filter, Qt::CaseInsensitive));
}
/*bool ObjectBrowser::filterAcceptsRowItself(int source_row, const QModelIndex & source_parent) const
{
//accept if any of the parents is accepted on it's own merits
QModelIndex parent = source_parent;
while(parent.isValid())
{
if (filterAcceptsRowItself(parent.row(), parent.parent()))
return true;
parent = parent.parent();
}
//accept if any of the children is accepted on it's own merits
if (hasAcceptedChildren(source_row, source_parent))
{
return true;
}
return false;
}*/

20
mapeditor/objectbrowser.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef OBJECTBROWSER_H
#define OBJECTBROWSER_H
#include <QSortFilterProxyModel>
#include "../lib/Terrain.h"
class ObjectBrowser : public QSortFilterProxyModel
{
public:
explicit ObjectBrowser(QObject *parent = nullptr);
Terrain terrain;
QString filter;
protected:
bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const override;
bool filterAcceptsRowText(int source_row, const QModelIndex &source_parent) const;
};
#endif // OBJECTBROWSER_H

View File

@ -70,6 +70,10 @@ void WindowNewMap::on_okButtong_clicked()
mapGenOptions.setMonsterStrength(monster);
CMapGenerator generator(mapGenOptions);
//TODO: fix water and roads
generator.disableModificator("RoadPlacer");
generator.disableModificator("RiverPlacer");
auto progressBarWnd = new GeneratorProgress(generator, this);
progressBarWnd->show();