diff --git a/mapeditor/inspector/inspector.cpp b/mapeditor/inspector/inspector.cpp index b5a26a41f..e2bd905aa 100644 --- a/mapeditor/inspector/inspector.cpp +++ b/mapeditor/inspector/inspector.cpp @@ -67,7 +67,8 @@ void Initializer::initialize(CGCreature * o) if(!o) return; o->character = CGCreature::Character::HOSTILE; - o->putStack(SlotID(0), new CStackInstance(CreatureID(o->subID), 0, false)); + if(!o->hasStackAtSlot(SlotID(0))) + o->putStack(SlotID(0), new CStackInstance(CreatureID(o->subID), 0, false)); } void Initializer::initialize(CGDwelling * o) diff --git a/mapeditor/mainwindow.cpp b/mapeditor/mainwindow.cpp index 73b6d1524..c57dd2cef 100644 --- a/mapeditor/mainwindow.cpp +++ b/mapeditor/mainwindow.cpp @@ -1126,3 +1126,31 @@ void MainWindow::on_actionRecreate_obstacles_triggered() } + +void MainWindow::on_actionCut_triggered() +{ + if(controller.map()) + { + controller.copyToClipboard(mapLevel); + controller.commitObjectErase(mapLevel); + } +} + + +void MainWindow::on_actionCopy_triggered() +{ + if(controller.map()) + { + controller.copyToClipboard(mapLevel); + } +} + + +void MainWindow::on_actionPaste_triggered() +{ + if(controller.map()) + { + controller.pasteFromClipboard(mapLevel); + } +} + diff --git a/mapeditor/mainwindow.h b/mapeditor/mainwindow.h index a728c87dc..c3c30874a 100644 --- a/mapeditor/mainwindow.h +++ b/mapeditor/mainwindow.h @@ -98,6 +98,12 @@ private slots: void switchDefaultPlayer(const PlayerColor &); + void on_actionCut_triggered(); + + void on_actionCopy_triggered(); + + void on_actionPaste_triggered(); + public slots: void treeViewSelected(const QModelIndex &selected, const QModelIndex &deselected); diff --git a/mapeditor/mainwindow.ui b/mapeditor/mainwindow.ui index 6da92787e..766114052 100644 --- a/mapeditor/mainwindow.ui +++ b/mapeditor/mainwindow.ui @@ -79,6 +79,9 @@ + + + diff --git a/mapeditor/mapcontroller.cpp b/mapeditor/mapcontroller.cpp index 21eb65384..82d554b87 100644 --- a/mapeditor/mapcontroller.cpp +++ b/mapeditor/mapcontroller.cpp @@ -20,6 +20,7 @@ #include "../lib/CSkillHandler.h" #include "../lib/spells/CSpellHandler.h" #include "../lib/CHeroHandler.h" +#include "../lib/serializer/CMemorySerializer.h" #include "mapview.h" #include "scenelayer.h" #include "maphandler.h" @@ -323,6 +324,48 @@ void MapController::commitObjectErase(int level) main->mapChanged(); } +void MapController::copyToClipboard(int level) +{ + _clipboard.clear(); + _clipboardShiftIndex = 0; + auto selectedObjects = _scenes[level]->selectionObjectsView.getSelection(); + for(auto * obj : selectedObjects) + { + assert(obj->pos.z == level); + _clipboard.push_back(CMemorySerializer::deepCopy(*obj)); + } +} + +void MapController::pasteFromClipboard(int level) +{ + _scenes[level]->selectionObjectsView.clear(); + + auto shift = int3::getDirs()[_clipboardShiftIndex++]; + if(_clipboardShiftIndex == int3::getDirs().size()) + _clipboardShiftIndex = 0; + + for(auto & objuptr : _clipboard) + { + auto * obj = CMemorySerializer::deepCopy(*objuptr).release(); + auto newpos = objuptr->pos + shift; + if(_map->isInTheMap(newpos)) + obj->pos = newpos; + obj->pos.z = level; + + Initializer init(obj, defaultPlayer); + _map->getEditManager()->insertObject(obj); + _scenes[level]->selectionObjectsView.selectObject(obj); + _mapHandler->invalidate(obj); + } + + _scenes[level]->objectsView.draw(); + _scenes[level]->passabilityView.update(); + _scenes[level]->selectionObjectsView.draw(); + + _miniscenes[level]->updateViews(); + main->mapChanged(); +} + bool MapController::discardObject(int level) const { _scenes[level]->selectionObjectsView.clear(); diff --git a/mapeditor/mapcontroller.h b/mapeditor/mapcontroller.h index 3fef9adcc..1446225f6 100644 --- a/mapeditor/mapcontroller.h +++ b/mapeditor/mapcontroller.h @@ -49,6 +49,9 @@ public: void commitObjectCreate(int level); void commitObjectChange(int level); + void copyToClipboard(int level); + void pasteFromClipboard(int level); + bool discardObject(int level) const; void createObject(int level, CGObjectInstance * obj) const; bool canPlaceObject(int level, CGObjectInstance * obj, QString & error) const; @@ -64,6 +67,8 @@ private: MainWindow * main; mutable std::array, 2> _scenes; mutable std::array, 2> _miniscenes; + std::vector> _clipboard; + int _clipboardShiftIndex = 0; void connectScenes(); }; diff --git a/mapeditor/mapview.cpp b/mapeditor/mapview.cpp index c719b80f1..6af283db3 100644 --- a/mapeditor/mapview.cpp +++ b/mapeditor/mapview.cpp @@ -270,6 +270,7 @@ void MapView::mousePressEvent(QMouseEvent *event) if(event->button() == Qt::LeftButton) { auto * obj = sc->selectionObjectsView.selectObjectAt(tileStart.x, tileStart.y); + auto * obj2 = sc->selectionObjectsView.selectObjectAt(tileStart.x, tileStart.y, obj); if(obj) { if(sc->selectionObjectsView.isSelected(obj)) @@ -284,10 +285,13 @@ void MapView::mousePressEvent(QMouseEvent *event) } else { - if(!(qApp->keyboardModifiers() & Qt::ControlModifier)) - sc->selectionObjectsView.clear(); + if(!obj2 || !sc->selectionObjectsView.isSelected(obj2)) + { + if(!(qApp->keyboardModifiers() & Qt::ControlModifier)) + sc->selectionObjectsView.clear(); + sc->selectionObjectsView.selectObject(obj); + } sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::MOVEMENT; - sc->selectionObjectsView.selectObject(obj); } } else diff --git a/mapeditor/scenelayer.cpp b/mapeditor/scenelayer.cpp index 605237c5f..370af0549 100644 --- a/mapeditor/scenelayer.cpp +++ b/mapeditor/scenelayer.cpp @@ -399,7 +399,7 @@ void SelectionObjectsLayer::draw() redraw(); } -CGObjectInstance * SelectionObjectsLayer::selectObjectAt(int x, int y) const +CGObjectInstance * SelectionObjectsLayer::selectObjectAt(int x, int y, const CGObjectInstance * ignore) const { if(!map || !map->isInTheMap(int3(x, y, scene->level))) return nullptr; @@ -409,7 +409,7 @@ CGObjectInstance * SelectionObjectsLayer::selectObjectAt(int x, int y) const //visitable is most important for(auto & object : objects) { - if(!object.obj) + if(!object.obj || object.obj == ignore) continue; if(object.obj->visitableAt(x, y)) @@ -421,7 +421,7 @@ CGObjectInstance * SelectionObjectsLayer::selectObjectAt(int x, int y) const //if not visitable tile - try to get blocked for(auto & object : objects) { - if(!object.obj) + if(!object.obj || object.obj == ignore) continue; if(object.obj->blockingAt(x, y)) @@ -433,7 +433,7 @@ CGObjectInstance * SelectionObjectsLayer::selectObjectAt(int x, int y) const //finally, we can take any object for(auto & object : objects) { - if(!object.obj) + if(!object.obj || object.obj == ignore) continue; if(object.obj->coveringAt(x, y)) diff --git a/mapeditor/scenelayer.h b/mapeditor/scenelayer.h index 7b99b4df1..848c64d99 100644 --- a/mapeditor/scenelayer.h +++ b/mapeditor/scenelayer.h @@ -138,7 +138,7 @@ public: void draw(); - CGObjectInstance * selectObjectAt(int x, int y) const; + CGObjectInstance * selectObjectAt(int x, int y, const CGObjectInstance * ignore = nullptr) const; void selectObjects(int x1, int y1, int x2, int y2); void selectObject(CGObjectInstance *, bool inform = true); void deselectObject(CGObjectInstance *);