From 7dd7be7f0ec646a8691877ad0e51defd103f00a5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 10 Jan 2016 08:56:15 +0100 Subject: [PATCH 01/17] make scenes drop target for referenceables --- apps/opencs/view/render/instancemode.cpp | 84 +++++++++++++++++++ apps/opencs/view/render/instancemode.hpp | 4 + .../view/render/pagedworldspacewidget.cpp | 11 +++ .../view/render/pagedworldspacewidget.hpp | 2 + .../view/render/unpagedworldspacewidget.cpp | 5 ++ .../view/render/unpagedworldspacewidget.hpp | 2 + apps/opencs/view/render/worldspacewidget.cpp | 48 +++++++++++ apps/opencs/view/render/worldspacewidget.hpp | 13 +++ 8 files changed, 169 insertions(+) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index a4d147bb4..6c3593369 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -1,8 +1,13 @@ #include "instancemode.hpp" +#include + #include "../../model/prefs/state.hpp" +#include "../../model/world/idtable.hpp" +#include "../../model/world/commands.hpp" + #include "elements.hpp" #include "object.hpp" #include "worldspacewidget.hpp" @@ -55,3 +60,82 @@ void CSVRender::InstanceMode::secondarySelectPressed (osg::ref_ptr tag) } } } + +void CSVRender::InstanceMode::dragEnterEvent (QDragEnterEvent *event) +{ + if (const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData())) + { + if (!mime->fromDocument (getWorldspaceWidget().getDocument())) + return; + + /// \todo document check + if (mime->holdsType (CSMWorld::UniversalId::Type_Referenceable)) + event->accept(); + } +} + +void CSVRender::InstanceMode::dropEvent (QDropEvent* event) +{ + if (const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData())) + { + CSMDoc::Document& document = getWorldspaceWidget().getDocument(); + + if (!mime->fromDocument (document)) + return; + + osg::Vec3f insertPoint = getWorldspaceWidget().getIntersectionPoint (event->pos()); + + std::string cellId = getWorldspaceWidget().getCellId (insertPoint); + + bool dropped = false; + + std::vector ids = mime->getData(); + + CSMWorld::IdTable& referencesTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_References)); + + CSMWorld::IdTable& cellTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)); + + for (std::vector::const_iterator iter (ids.begin()); + iter!=ids.end(); ++iter) + if (mime->isReferencable (iter->getType())) + { + // create reference + std::auto_ptr createCommand ( + new CSMWorld::CreateCommand ( + referencesTable, document.getData().getReferences().getNewId())); + + createCommand->addValue (referencesTable.findColumnIndex ( + CSMWorld::Columns::ColumnId_Cell), QString::fromUtf8 (cellId.c_str())); + createCommand->addValue (referencesTable.findColumnIndex ( + CSMWorld::Columns::ColumnId_PositionXPos), insertPoint.x()); + createCommand->addValue (referencesTable.findColumnIndex ( + CSMWorld::Columns::ColumnId_PositionYPos), insertPoint.y()); + createCommand->addValue (referencesTable.findColumnIndex ( + CSMWorld::Columns::ColumnId_PositionZPos), insertPoint.z()); + createCommand->addValue (referencesTable.findColumnIndex ( + CSMWorld::Columns::ColumnId_ReferenceableId), + QString::fromUtf8 (iter->getId().c_str())); + + // increase reference count in cell + QModelIndex countIndex = cellTable.getModelIndex (cellId, + cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_RefNumCounter)); + + int count = cellTable.data (countIndex).toInt(); + + std::auto_ptr incrementCommand ( + new CSMWorld::ModifyCommand (cellTable, countIndex, count+1)); + + document.getUndoStack().beginMacro (createCommand->text()); + document.getUndoStack().push (createCommand.release()); + document.getUndoStack().push (incrementCommand.release()); + document.getUndoStack().endMacro(); + + dropped = true; + } + + if (dropped) + event->accept(); + } +} diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 66451bd99..7649c241c 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -20,6 +20,10 @@ namespace CSVRender virtual void primarySelectPressed (osg::ref_ptr tag); virtual void secondarySelectPressed (osg::ref_ptr tag); + + virtual void dragEnterEvent (QDragEnterEvent *event); + + virtual void dropEvent (QDropEvent* event); }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index dae5990e6..e30f238a2 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -504,6 +504,17 @@ void CSVRender::PagedWorldspaceWidget::clearSelection (int elementMask) flagAsModified(); } +std::string CSVRender::PagedWorldspaceWidget::getCellId (const osg::Vec3f& point) const +{ + const int cellSize = 8192; + + CSMWorld::CellCoordinates cellCoordinates ( + static_cast (std::floor (point.x()/cellSize)), + static_cast (std::floor (point.y()/cellSize))); + + return cellCoordinates.getId (mWorldspace); +} + CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector ( CSVWidget::SceneToolbar *parent) { diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index e983fddd5..bc8e0da64 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -96,6 +96,8 @@ namespace CSVRender /// \param elementMask Elements to be affected by the clear operation virtual void clearSelection (int elementMask); + virtual std::string getCellId (const osg::Vec3f& point) const; + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 68f068dac..701f50825 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -108,6 +108,11 @@ void CSVRender::UnpagedWorldspaceWidget::clearSelection (int elementMask) flagAsModified(); } +std::string CSVRender::UnpagedWorldspaceWidget::getCellId (const osg::Vec3f& point) const +{ + return mCellId; +} + void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 9e6fa97f4..70a20c216 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -46,6 +46,8 @@ namespace CSVRender /// \param elementMask Elements to be affected by the clear operation virtual void clearSelection (int elementMask); + virtual std::string getCellId (const osg::Vec3f& point) const; + private: virtual void referenceableDataChanged (const QModelIndex& topLeft, diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index f0d398641..0383b0bcf 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -315,6 +315,54 @@ CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument() return mDocument; } +osg::Vec3f CSVRender::WorldspaceWidget::getIntersectionPoint (const QPoint& localPos, + unsigned int interactionMask, bool ignoreHidden) const +{ + // (0,0) is considered the lower left corner of an OpenGL window + int x = localPos.x(); + int y = height() - localPos.y(); + + osg::ref_ptr intersector ( + new osgUtil::LineSegmentIntersector (osgUtil::Intersector::WINDOW, x, y)); + + intersector->setIntersectionLimit (osgUtil::LineSegmentIntersector::NO_LIMIT); + osgUtil::IntersectionVisitor visitor (intersector); + + unsigned int mask = interactionMask; + + if (ignoreHidden) + mask &= getVisibilityMask(); + + visitor.setTraversalMask (mask << 1); + + mView->getCamera()->accept (visitor); + + for (osgUtil::LineSegmentIntersector::Intersections::iterator iter = intersector->getIntersections().begin(); + iter!=intersector->getIntersections().end(); ++iter) + { + // reject back-facing polygons + osg::Vec3f normal = osg::Matrix::transform3x3 ( + iter->getWorldIntersectNormal(), mView->getCamera()->getViewMatrix()); + + if (normal.z()>=0) + return iter->getWorldIntersectPoint(); + } + + osg::Matrixd matrix; + matrix.preMult (mView->getCamera()->getViewport()->computeWindowMatrix()); + matrix.preMult (mView->getCamera()->getProjectionMatrix()); + matrix.preMult (mView->getCamera()->getViewMatrix()); + matrix = osg::Matrixd::inverse (matrix); + + osg::Vec3d start = matrix.preMult (intersector->getStart()); + osg::Vec3d end = matrix.preMult (intersector->getEnd()); + + osg::Vec3d direction = end-start; + direction.normalize(); + + return start+direction * 50; +} + void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event) { const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 54376cee4..0edf9f0b2 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -127,6 +127,19 @@ namespace CSVRender /// \param elementMask Elements to be affected by the clear operation virtual void clearSelection (int elementMask) = 0; + /// Return the next intersection point with scene elements matched by + /// \a interactionMask based on \a localPos and the camera vector. + /// If there is no such point, instead a point "in front" of \a localPos will be + /// returned. + /// + /// \param ignoreHidden ignore elements specified in interactionMask that are + /// flagged as not visible. + osg::Vec3f getIntersectionPoint (const QPoint& localPos, + unsigned int interactionMask = Element_Reference | Element_Terrain, + bool ignoreHidden = false) const; + + virtual std::string getCellId (const osg::Vec3f& point) const = 0; + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); From 5b9d6cce989720aa65828bcba8e13b78d10758af Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 11 Jan 2016 09:03:02 +0100 Subject: [PATCH 02/17] made drop distance configurable --- apps/opencs/model/prefs/state.cpp | 5 +++++ apps/opencs/view/render/worldspacewidget.cpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 8b827d0a2..d2ad0f6ef 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -190,6 +190,11 @@ void CSMPrefs::State::declare() declareBool ("scene-hide-basic", "Hide basic 3D scenes tooltips", false); declareInt ("scene-delay", "Tooltip delay in milliseconds", 500). setMin (1); + + declareCategory ("Scene Drops"); + declareInt ("distance", "Drop Distance", 50). + setTooltip ("If an instance drop can not be placed against another object at the " + "insert point, it will be placed by this distance from the insert point instead"); } void CSMPrefs::State::declareCategory (const std::string& key) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 0383b0bcf..536126689 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -360,7 +360,7 @@ osg::Vec3f CSVRender::WorldspaceWidget::getIntersectionPoint (const QPoint& loca osg::Vec3d direction = end-start; direction.normalize(); - return start+direction * 50; + return start + direction * CSMPrefs::get()["Scene Drops"]["distance"].toInt(); } void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event) From 190bf158878943f7ad358b8caed706f4f2b02fe7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Jan 2016 22:37:36 +0100 Subject: [PATCH 03/17] SettingsWindow: support auto-updating of slider labels through the layout file --- apps/openmw/mwgui/settingswindow.cpp | 53 ++++++++++------------- apps/openmw/mwgui/settingswindow.hpp | 5 +-- files/mygui/openmw_settings_window.layout | 7 ++- 3 files changed, 29 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index fbfbd0e70..86ecd9dfb 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -130,12 +130,14 @@ namespace MWGui if (type == sliderType) { MyGUI::ScrollBar* scroll = current->castType(); + std::string valueStr; if (getSettingValueType(current) == "Float") { // TODO: ScrollBar isn't meant for this. should probably use a dedicated FloatSlider widget float min,max; getSettingMinMax(scroll, min, max); float value = Settings::Manager::getFloat(getSettingName(current), getSettingCategory(current)); + valueStr = MyGUI::utility::toString((int)value); value = std::max(min, std::min(value, max)); value = (value-min)/(max-min); @@ -144,15 +146,30 @@ namespace MWGui else { int value = Settings::Manager::getInt(getSettingName(current), getSettingCategory(current)); + valueStr = MyGUI::utility::toString(value); scroll->setScrollPosition(value); } scroll->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); + updateSliderLabel(scroll, valueStr); } configureWidgets(current); } } + void SettingsWindow::updateSliderLabel(MyGUI::ScrollBar *scroller, const std::string& value) + { + std::string labelWidgetName = scroller->getUserString("SettingLabelWidget"); + if (!labelWidgetName.empty()) + { + MyGUI::TextBox* textBox; + getWidget(textBox, labelWidgetName); + std::string labelCaption = scroller->getUserString("SettingLabelCaption"); + boost::algorithm::replace_all(labelCaption, "%s", value); + textBox->setCaptionWithReplacing(labelCaption); + } + } + SettingsWindow::SettingsWindow() : WindowBase("openmw_settings_window.layout"), mKeyboardMode(true) @@ -167,17 +184,13 @@ namespace MWGui getWidget(mFullscreenButton, "FullscreenButton"); getWidget(mVSyncButton, "VSyncButton"); getWidget(mWindowBorderButton, "WindowBorderButton"); - getWidget(mFOVSlider, "FOVSlider"); - getWidget(mAnisotropySlider, "AnisotropySlider"); getWidget(mTextureFilteringButton, "TextureFilteringButton"); - getWidget(mAnisotropyLabel, "AnisotropyLabel"); getWidget(mAnisotropyBox, "AnisotropyBox"); getWidget(mShadersButton, "ShadersButton"); getWidget(mShadowsEnabledButton, "ShadowsEnabledButton"); getWidget(mShadowsTextureSize, "ShadowsTextureSize"); getWidget(mControlsBox, "ControlsBox"); getWidget(mResetControlsButton, "ResetControlsButton"); - getWidget(mDifficultySlider, "DifficultySlider"); getWidget(mKeyboardSwitch, "KeyboardButton"); getWidget(mControllerSwitch, "ControllerButton"); getWidget(mWaterTextureSize, "WaterTextureSize"); @@ -238,7 +251,6 @@ namespace MWGui std::string tmip = Settings::Manager::getString("texture mipmap", "General"); mTextureFilteringButton->setCaption(textureMipmappingToStr(tmip)); - mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(Settings::Manager::getInt("anisotropy", "General")) + ")"); int waterTextureSize = Settings::Manager::getInt ("rtt size", "Water"); if (waterTextureSize >= 512) @@ -255,15 +267,6 @@ namespace MWGui mShadowsEnabledButton->setEnabled(false); } - MyGUI::TextBox* fovText; - getWidget(fovText, "FovText"); - fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(Settings::Manager::getInt("field of view", "Camera"))) + ")"); - - MyGUI::TextBox* diffText; - getWidget(diffText, "DifficultyText"); - - diffText->setCaptionWithReplacing("#{sDifficulty} (" + MyGUI::utility::toString(int(Settings::Manager::getInt("difficulty", "Game"))) + ")"); - mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video")); mKeyboardSwitch->setStateSelected(true); @@ -439,6 +442,7 @@ namespace MWGui { if (getSettingType(scroller) == "Slider") { + std::string valueStr; if (getSettingValueType(scroller) == "Float") { float value = pos / float(scroller->getScrollRange()-1); @@ -447,28 +451,15 @@ namespace MWGui getSettingMinMax(scroller, min, max); value = min + (max-min) * value; Settings::Manager::setFloat(getSettingName(scroller), getSettingCategory(scroller), value); - - if (scroller == mFOVSlider) - { - MyGUI::TextBox* fovText; - getWidget(fovText, "FovText"); - fovText->setCaption("Field of View (" + MyGUI::utility::toString(int(value)) + ")"); - } - if (scroller == mDifficultySlider) - { - MyGUI::TextBox* diffText; - getWidget(diffText, "DifficultyText"); - diffText->setCaptionWithReplacing("#{sDifficulty} (" + MyGUI::utility::toString(int(value)) + ")"); - } + valueStr = MyGUI::utility::toString(int(value)); } else { Settings::Manager::setInt(getSettingName(scroller), getSettingCategory(scroller), pos); - if (scroller == mAnisotropySlider) - { - mAnisotropyLabel->setCaption("Anisotropy (" + MyGUI::utility::toString(pos) + ")"); - } + valueStr = MyGUI::utility::toString(pos); } + updateSliderLabel(scroller, valueStr); + apply(); } } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 99553808b..421465309 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -30,11 +30,7 @@ namespace MWGui MyGUI::Button* mFullscreenButton; MyGUI::Button* mVSyncButton; MyGUI::Button* mWindowBorderButton; - MyGUI::ScrollBar* mFOVSlider; - MyGUI::ScrollBar* mDifficultySlider; - MyGUI::ScrollBar* mAnisotropySlider; MyGUI::ComboBox* mTextureFilteringButton; - MyGUI::TextBox* mAnisotropyLabel; MyGUI::Widget* mAnisotropyBox; MyGUI::Button* mShadersButton; @@ -76,6 +72,7 @@ namespace MWGui void apply(); void configureWidgets(MyGUI::Widget* widget); + void updateSliderLabel(MyGUI::ScrollBar* scroller, const std::string& value); private: void resetScrollbars(); diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 6d2424aa5..cf7fe1be7 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -61,6 +61,8 @@ + + @@ -274,7 +276,6 @@ - @@ -285,6 +286,8 @@ + + @@ -334,6 +337,8 @@ + + From 4f8f166f69e6ce2ccecc0a2ce3d8dbc9919dc0cb Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Jan 2016 23:27:42 +0100 Subject: [PATCH 04/17] Fix GetPcInJail to work as in the original engine --- apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwscript/miscextensions.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 8 ++++++++ apps/openmw/mwworld/worldimp.hpp | 2 ++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index ebce2e1bf..462d08727 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -545,6 +545,8 @@ namespace MWBase virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target) = 0; virtual void removeContainerScripts(const MWWorld::Ptr& reference) = 0; + + virtual bool isPlayerInJail() const = 0; }; } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 9c63511b2..593fdcca5 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1014,7 +1014,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime &runtime) { - runtime.push (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Jail)); + runtime.push (MWBase::Environment::get().getWorld()->isPlayerInJail()); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 15826009d..19d90e209 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2996,6 +2996,14 @@ namespace MWWorld } } + bool World::isPlayerInJail() const + { + if (mGoToJail) + return true; + + return MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Jail); + } + void World::spawnRandomCreature(const std::string &creatureList) { const ESM::CreatureLevList* list = getStore().get().find(creatureList); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 4ed97759e..5f0507ace 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -645,6 +645,8 @@ namespace MWWorld /// Return the distance between actor's weapon and target's collision box. virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target); + + virtual bool isPlayerInJail() const; }; } From 0da6d249fe5748496d605ad19bc1243d96ad6549 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Jan 2016 00:26:09 +0100 Subject: [PATCH 05/17] Fix the window pinning button's borders not accepting mouse clicks --- files/mygui/openmw_windows.skin.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 682d89ebc..22270bb9f 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -11,41 +11,49 @@ + + + + + + + + @@ -53,41 +61,49 @@ + + + + + + + + From 4690fd3f222b3363944df53ab15887a7cc2632c6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Jan 2016 00:43:15 +0100 Subject: [PATCH 06/17] Change the local map exploration radius to better match the original engine --- apps/openmw/mwrender/localmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 9d5950a90..b3d19090f 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -526,7 +526,7 @@ void LocalMap::updatePlayer (const osg::Vec3f& position, const osg::Quat& orient } // explore radius (squared) - const float exploreRadius = (mInterior ? 0.1f : 0.3f) * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1 + const float exploreRadius = 0.17f * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1 const float sqrExploreRadius = square(exploreRadius); const float exploreRadiusUV = exploreRadius / sFogOfWarResolution; // explore radius from 0 to 1 (UV space) From ca4e859f613c4521cae17aa4ef19190391e5242c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Jan 2016 00:45:12 +0100 Subject: [PATCH 07/17] Remove unused argument --- apps/openmw/mwgui/mapwindow.cpp | 4 +--- apps/openmw/mwgui/mapwindow.hpp | 2 -- apps/openmw/mwrender/localmap.cpp | 2 +- apps/openmw/mwrender/localmap.hpp | 2 +- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 0ebb595dd..bc8f41599 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -269,8 +269,6 @@ namespace MWGui // normalized cell coordinates float nX,nY; - markerPos.interior = mInterior; - if (!mInterior) { int cellX, cellY; @@ -1078,7 +1076,7 @@ namespace MWGui { if (!mLocalMapRender) return true; - return mLocalMapRender->isPositionExplored(nX, nY, cellX, cellY, interior); + return mLocalMapRender->isPositionExplored(nX, nY, cellX, cellY); } } diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index a41d5d527..0ab38f1e3 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -78,7 +78,6 @@ namespace MWGui { MarkerUserData(MWRender::LocalMap* map) : mLocalMapRender(map) - , interior(false) , cellX(0) , cellY(0) , nX(0.f) @@ -89,7 +88,6 @@ namespace MWGui bool isPositionExplored() const; MWRender::LocalMap* mLocalMapRender; - bool interior; int cellX; int cellY; float nX; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index b3d19090f..200f484b5 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -478,7 +478,7 @@ osg::Vec2f LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int return pos; } -bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interior) +bool LocalMap::isPositionExplored (float nX, float nY, int x, int y) { const MapSegment& segment = mSegments[std::make_pair(x, y)]; if (!segment.mFogOfWarImage) diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 72ee0354e..59165013d 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -99,7 +99,7 @@ namespace MWRender /** * Check if a given position is explored by the player (i.e. not obscured by fog of war) */ - bool isPositionExplored (float nX, float nY, int x, int y, bool interior); + bool isPositionExplored (float nX, float nY, int x, int y); osg::Group* getRoot(); From ef20962fc5f9d2ba19faa679cac1c4c02bbc87a4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Jan 2016 01:08:30 +0100 Subject: [PATCH 08/17] Disable fog of war rendering on the HUD map by default --- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 11 ++++++----- apps/openmw/mwgui/mapwindow.hpp | 5 +++-- files/settings-default.cfg | 4 ++++ 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index cf0fa3414..8d6ce6beb 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -69,7 +69,7 @@ namespace MWGui HUD::HUD(CustomMarkerCollection &customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) : Layout("openmw_hud.layout") - , LocalMapBase(customMarkers, localMapRender) + , LocalMapBase(customMarkers, localMapRender, Settings::Manager::getBool("local map hud fog of war", "Map")) , mHealth(NULL) , mMagicka(NULL) , mStamina(NULL) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index bc8f41599..89f4d8cf3 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -156,7 +156,7 @@ namespace MWGui // ------------------------------------------------------ - LocalMapBase::LocalMapBase(CustomMarkerCollection &markers, MWRender::LocalMap* localMapRender) + LocalMapBase::LocalMapBase(CustomMarkerCollection &markers, MWRender::LocalMap* localMapRender, bool fogOfWarEnabled) : mLocalMapRender(localMapRender) , mCurX(0) , mCurY(0) @@ -165,7 +165,8 @@ namespace MWGui , mCompass(NULL) , mPrefix() , mChanged(true) - , mFogOfWar(true) + , mFogOfWarToggled(true) + , mFogOfWarEnabled(fogOfWarEnabled) , mMapWidgetSize(0) , mCustomMarkers(markers) , mMarkerUpdateTimer(0.0f) @@ -222,9 +223,9 @@ namespace MWGui bool LocalMapBase::toggleFogOfWar() { - mFogOfWar = !mFogOfWar; + mFogOfWarToggled = !mFogOfWarToggled; applyFogOfWar(); - return mFogOfWar; + return mFogOfWarToggled; } void LocalMapBase::applyFogOfWar() @@ -238,7 +239,7 @@ namespace MWGui int y = mCurY + (-1*(my-1)); MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; - if (!mFogOfWar) + if (!mFogOfWarToggled || !mFogOfWarEnabled) { fog->setImageTexture(""); continue; diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 0ab38f1e3..227a9e3f9 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -61,7 +61,7 @@ namespace MWGui class LocalMapBase { public: - LocalMapBase(CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender); + LocalMapBase(CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender, bool fogOfWarEnabled = true); virtual ~LocalMapBase(); void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int mapWidgetSize); @@ -105,7 +105,8 @@ namespace MWGui MyGUI::ImageBox* mCompass; std::string mPrefix; bool mChanged; - bool mFogOfWar; + bool mFogOfWarToggled; + bool mFogOfWarEnabled; int mMapWidgetSize; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 49c9c5419..6a2495e26 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -47,6 +47,10 @@ global map cell size = 18 # cell, 256 is 1/8 cell. See documentation for details. (e.g. 64 to 256). local map hud widget size = 256 +# Enables Fog of War rendering on the HUD map. Default is Off since with default settings +# the map is so small that the fog would not obscure anything, just darken the edges slightly. +local map hud fog of war = false + # Resolution of local map in GUI window in pixels. See documentation # for details which may affect cell load performance. (e.g. 128 to 1024). local map resolution = 256 From f315a4386fabeb6d96648e58a1c239c557d9257a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 11 Jan 2016 23:07:01 +0100 Subject: [PATCH 09/17] Accept an implicit reference in Journal (Fixes #3135) --- apps/openmw/mwbase/journal.hpp | 3 ++- apps/openmw/mwdialogue/journalentry.cpp | 8 ++++---- apps/openmw/mwdialogue/journalentry.hpp | 4 ++-- apps/openmw/mwdialogue/journalimp.cpp | 4 ++-- apps/openmw/mwdialogue/journalimp.hpp | 3 ++- apps/openmw/mwscript/dialogueextensions.cpp | 9 +++++++-- 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/journal.hpp b/apps/openmw/mwbase/journal.hpp index 738014ba6..cd8792890 100644 --- a/apps/openmw/mwbase/journal.hpp +++ b/apps/openmw/mwbase/journal.hpp @@ -50,8 +50,9 @@ namespace MWBase virtual ~Journal() {} - virtual void addEntry (const std::string& id, int index) = 0; + virtual void addEntry (const std::string& id, int index, const MWWorld::Ptr& actor) = 0; ///< Add a journal entry. + /// @param actor Used as context for replacing of escape sequences (%name, etc). virtual void setJournalIndex (const std::string& id, int index) = 0; ///< Set the journal index without adding an entry. diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index 2f5f02b01..9f74d0733 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -102,8 +102,8 @@ namespace MWDialogue {} StampedJournalEntry::StampedJournalEntry (const std::string& topic, const std::string& infoId, - int day, int month, int dayOfMonth) - : JournalEntry (topic, infoId, MWWorld::Ptr()), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth) + int day, int month, int dayOfMonth, const MWWorld::Ptr& actor) + : JournalEntry (topic, infoId, actor), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth) {} StampedJournalEntry::StampedJournalEntry (const ESM::JournalEntry& record) @@ -119,12 +119,12 @@ namespace MWDialogue entry.mDayOfMonth = mDayOfMonth; } - StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index) + StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index, const MWWorld::Ptr& actor) { int day = MWBase::Environment::get().getWorld()->getGlobalInt ("dayspassed"); int month = MWBase::Environment::get().getWorld()->getGlobalInt ("month"); int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalInt ("day"); - return StampedJournalEntry (topic, idFromIndex (topic, index), day, month, dayOfMonth); + return StampedJournalEntry (topic, idFromIndex (topic, index), day, month, dayOfMonth, actor); } } diff --git a/apps/openmw/mwdialogue/journalentry.hpp b/apps/openmw/mwdialogue/journalentry.hpp index 3ae3efcc8..8711ab53a 100644 --- a/apps/openmw/mwdialogue/journalentry.hpp +++ b/apps/openmw/mwdialogue/journalentry.hpp @@ -64,13 +64,13 @@ namespace MWDialogue StampedJournalEntry(); StampedJournalEntry (const std::string& topic, const std::string& infoId, - int day, int month, int dayOfMonth); + int day, int month, int dayOfMonth, const MWWorld::Ptr& actor); StampedJournalEntry (const ESM::JournalEntry& record); void write (ESM::JournalEntry& entry) const; - static StampedJournalEntry makeFromQuest (const std::string& topic, int index); + static StampedJournalEntry makeFromQuest (const std::string& topic, int index, const MWWorld::Ptr& actor); }; } diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index e6ffe22ab..8ea72e3ba 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -75,7 +75,7 @@ namespace MWDialogue mTopics.clear(); } - void Journal::addEntry (const std::string& id, int index) + void Journal::addEntry (const std::string& id, int index, const MWWorld::Ptr& actor) { // bail out of we already have heard this... std::string infoId = JournalEntry::idFromIndex (id, index); @@ -83,7 +83,7 @@ namespace MWDialogue if (i->mTopic == id && i->mInfoId == infoId) return; - StampedJournalEntry entry = StampedJournalEntry::makeFromQuest (id, index); + StampedJournalEntry entry = StampedJournalEntry::makeFromQuest (id, index, actor); mJournal.push_back (entry); diff --git a/apps/openmw/mwdialogue/journalimp.hpp b/apps/openmw/mwdialogue/journalimp.hpp index 7f26a5bb9..c3e940629 100644 --- a/apps/openmw/mwdialogue/journalimp.hpp +++ b/apps/openmw/mwdialogue/journalimp.hpp @@ -29,8 +29,9 @@ namespace MWDialogue virtual void clear(); - virtual void addEntry (const std::string& id, int index); + virtual void addEntry (const std::string& id, int index, const MWWorld::Ptr& actor); ///< Add a journal entry. + /// @param actor Used as context for replacing of escape sequences (%name, etc). virtual void setJournalIndex (const std::string& id, int index); ///< Set the journal index without adding an entry. diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index c305fb81f..fcb7e8f3b 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -22,12 +22,17 @@ namespace MWScript { namespace Dialogue { + template class OpJournal : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { + MWWorld::Ptr ptr = R()(runtime, false); // required=false + if (ptr.isEmpty()) + ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + std::string quest = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); @@ -37,7 +42,7 @@ namespace MWScript // Invoking Journal with a non-existing index is allowed, and triggers no errors. Seriously? :( try { - MWBase::Environment::get().getJournal()->addEntry (quest, index); + MWBase::Environment::get().getJournal()->addEntry (quest, index, ptr); } catch (...) { @@ -270,7 +275,7 @@ namespace MWScript void installOpcodes (Interpreter::Interpreter& interpreter) { - interpreter.installSegment5 (Compiler::Dialogue::opcodeJournal, new OpJournal); + interpreter.installSegment5 (Compiler::Dialogue::opcodeJournal, new OpJournal); interpreter.installSegment5 (Compiler::Dialogue::opcodeSetJournalIndex, new OpSetJournalIndex); interpreter.installSegment5 (Compiler::Dialogue::opcodeGetJournalIndex, new OpGetJournalIndex); interpreter.installSegment5 (Compiler::Dialogue::opcodeAddTopic, new OpAddTopic); From 4e6a60672d3cc265f7532433f79f73eeb2e8bf03 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 Jan 2016 00:31:34 +0100 Subject: [PATCH 10/17] When a spell explodes on an actor do not apply it to that actor twice (Fixes #3142) --- apps/openmw/mwbase/world.hpp | 4 ++-- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwworld/projectilemanager.cpp | 3 ++- apps/openmw/mwworld/worldimp.cpp | 7 +++++-- apps/openmw/mwworld/worldimp.hpp | 4 ++-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 462d08727..a1580c434 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -521,8 +521,8 @@ namespace MWBase virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) = 0; - virtual void explodeSpell (const osg::Vec3f& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0; + virtual void explodeSpell (const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, + const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0; virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index ab8784beb..6073076e0 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -552,7 +552,7 @@ namespace MWMechanics } if (!exploded) - MWBase::Environment::get().getWorld()->explodeSpell(mHitPosition, effects, caster, range, mId, mSourceName); + MWBase::Environment::get().getWorld()->explodeSpell(mHitPosition, effects, caster, target, range, mId, mSourceName); if (!reflectedEffects.mList.empty()) inflict(caster, target, reflectedEffects, range, true, exploded); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 439ac19ec..d1faf621c 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -237,7 +237,8 @@ namespace MWWorld if (hit) { - MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, ESM::RT_Target, it->mSpellId, it->mSourceName); + MWBase::Environment::get().getWorld()->explodeSpell(pos, it->mEffects, caster, result.mHitObject, + ESM::RT_Target, it->mSpellId, it->mSourceName); MWBase::Environment::get().getSoundManager()->stopSound(it->mSound); mParent->removeChild(it->mNode); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 19d90e209..810eff643 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3072,8 +3072,8 @@ namespace MWWorld mRendering->spawnEffect(model, textureOverride, worldPos); } - void World::explodeSpell(const osg::Vec3f &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, - const std::string& id, const std::string& sourceName) + void World::explodeSpell(const osg::Vec3f &origin, const ESM::EffectList &effects, const Ptr &caster, const Ptr& ignore, + ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) { std::map > toApply; for (std::vector::const_iterator effectIt = effects.mList.begin(); @@ -3121,6 +3121,9 @@ namespace MWWorld if (apply->first == caster) continue; + if (apply->first == ignore) + continue; + if (source.isEmpty()) source = apply->first; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5f0507ace..6eed4e484 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -623,8 +623,8 @@ namespace MWWorld virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos); - virtual void explodeSpell (const osg::Vec3f& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName); + virtual void explodeSpell (const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster, + const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName); virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor); From ef1a1125e028573931604f5b459ec0f07d31ed28 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 Jan 2016 17:10:23 +0100 Subject: [PATCH 11/17] Fix an error in restocking logic (Fixes #3131) --- apps/openmw/mwworld/containerstore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index ab9fa4611..45390405e 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -529,10 +529,10 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW { std::map::iterator listInMap = allowedForReplace.find(itemOrList); - int restockNum = it->mCount; + int restockNum = std::abs(it->mCount); //If we know we must restock less, take it into account if(listInMap != allowedForReplace.end()) - restockNum += listInMap->second;//We add, because list items have negative count + restockNum -= std::min(restockNum, listInMap->second); //restock addInitialItem(itemOrList, owner, restockNum, true); } From 6eba647a9d4b88925997aba9f2495f367857a519 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 14 Jan 2016 13:19:37 +0100 Subject: [PATCH 12/17] added accessor function for cell selection in paged worldspace --- apps/opencs/view/render/pagedworldspacewidget.cpp | 5 +++++ apps/opencs/view/render/pagedworldspacewidget.hpp | 2 ++ 2 files changed, 7 insertions(+) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index e30f238a2..414076cea 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -432,6 +432,11 @@ void CSVRender::PagedWorldspaceWidget::setCellSelection (const CSMWorld::CellSel emit cellSelectionChanged (mSelection); } +const CSMWorld::CellSelection& CSVRender::PagedWorldspaceWidget::getCellSelection() const +{ + return mSelection; +} + std::pair< int, int > CSVRender::PagedWorldspaceWidget::getCoordinatesFromId (const std::string& record) const { std::istringstream stream (record.c_str()); diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index bc8e0da64..647341d1f 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -80,6 +80,8 @@ namespace CSVRender void setCellSelection(const CSMWorld::CellSelection& selection); + const CSMWorld::CellSelection& getCellSelection() const; + /// \return Drop handled? virtual bool handleDrop (const std::vector& data, DropType type); From 55627c08532356e348e115af58da90f9bb55af7d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 14 Jan 2016 13:20:01 +0100 Subject: [PATCH 13/17] handling drops into cells that do not exist or are not shown --- apps/opencs/model/prefs/state.cpp | 13 ++++ apps/opencs/view/render/instancemode.cpp | 84 ++++++++++++++++++++---- 2 files changed, 85 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index d2ad0f6ef..859fabd11 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -191,10 +191,23 @@ void CSMPrefs::State::declare() declareInt ("scene-delay", "Tooltip delay in milliseconds", 500). setMin (1); + EnumValue createAndInsert ("Create cell and insert"); + EnumValue showAndInsert ("Show cell and insert"); + EnumValue dontInsert ("Discard"); + EnumValue insertAnyway ("Insert anyway"); + EnumValues insertOutsideCell; + insertOutsideCell.add (createAndInsert).add (dontInsert).add (insertAnyway); + EnumValues insertOutsideVisibleCell; + insertOutsideVisibleCell.add (showAndInsert).add (dontInsert).add (insertAnyway); + declareCategory ("Scene Drops"); declareInt ("distance", "Drop Distance", 50). setTooltip ("If an instance drop can not be placed against another object at the " "insert point, it will be placed by this distance from the insert point instead"); + declareEnum ("outside-drop", "Handling drops outside of cells", createAndInsert). + addValues (insertOutsideCell); + declareEnum ("outside-visible-drop", "Handling drops outside of visible cells", showAndInsert). + addValues (insertOutsideVisibleCell); } void CSMPrefs::State::declareCategory (const std::string& key) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 6c3593369..b6430036b 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -6,11 +6,13 @@ #include "../../model/prefs/state.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/world/idtree.hpp" #include "../../model/world/commands.hpp" #include "elements.hpp" #include "object.hpp" #include "worldspacewidget.hpp" +#include "pagedworldspacewidget.hpp" CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Element_Reference, "Instance editing", @@ -68,7 +70,6 @@ void CSVRender::InstanceMode::dragEnterEvent (QDragEnterEvent *event) if (!mime->fromDocument (getWorldspaceWidget().getDocument())) return; - /// \todo document check if (mime->holdsType (CSMWorld::UniversalId::Type_Referenceable)) event->accept(); } @@ -87,15 +88,68 @@ void CSVRender::InstanceMode::dropEvent (QDropEvent* event) std::string cellId = getWorldspaceWidget().getCellId (insertPoint); - bool dropped = false; + CSMWorld::IdTree& cellTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)); - std::vector ids = mime->getData(); + bool noCell = document.getData().getCells().searchId (cellId)==-1; + + if (noCell) + { + std::string mode = CSMPrefs::get()["Scene Drops"]["outside-drop"].toString(); + + // target cell does not exist + if (mode=="Discard") + return; + + if (mode=="Create cell and insert") + { + std::auto_ptr createCommand ( + new CSMWorld::CreateCommand (cellTable, cellId)); + + int parentIndex = cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_Cell); + int index = cellTable.findNestedColumnIndex (parentIndex, CSMWorld::Columns::ColumnId_Interior); + createCommand->addNestedValue (parentIndex, index, false); + + document.getUndoStack().push (createCommand.release()); + + if (CSVRender::PagedWorldspaceWidget *paged = + dynamic_cast (&getWorldspaceWidget())) + { + CSMWorld::CellSelection selection = paged->getCellSelection(); + selection.add (CSMWorld::CellCoordinates::fromId (cellId).first); + paged->setCellSelection (selection); + } + + noCell = false; + } + } + else if (CSVRender::PagedWorldspaceWidget *paged = + dynamic_cast (&getWorldspaceWidget())) + { + CSMWorld::CellSelection selection = paged->getCellSelection(); + if (!selection.has (CSMWorld::CellCoordinates::fromId (cellId).first)) + { + // target cell exists, but is not shown + std::string mode = + CSMPrefs::get()["Scene Drops"]["outside-visible-drop"].toString(); + + if (mode=="Discard") + return; + + if (mode=="Show cell and insert") + { + selection.add (CSMWorld::CellCoordinates::fromId (cellId).first); + paged->setCellSelection (selection); + } + } + } CSMWorld::IdTable& referencesTable = dynamic_cast ( *document.getData().getTableModel (CSMWorld::UniversalId::Type_References)); - CSMWorld::IdTable& cellTable = dynamic_cast ( - *document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)); + bool dropped = false; + + std::vector ids = mime->getData(); for (std::vector::const_iterator iter (ids.begin()); iter!=ids.end(); ++iter) @@ -118,18 +172,24 @@ void CSVRender::InstanceMode::dropEvent (QDropEvent* event) CSMWorld::Columns::ColumnId_ReferenceableId), QString::fromUtf8 (iter->getId().c_str())); - // increase reference count in cell - QModelIndex countIndex = cellTable.getModelIndex (cellId, - cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_RefNumCounter)); + std::auto_ptr incrementCommand; + + if (!noCell) + { + // increase reference count in cell + QModelIndex countIndex = cellTable.getModelIndex (cellId, + cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_RefNumCounter)); - int count = cellTable.data (countIndex).toInt(); + int count = cellTable.data (countIndex).toInt(); - std::auto_ptr incrementCommand ( - new CSMWorld::ModifyCommand (cellTable, countIndex, count+1)); + incrementCommand.reset ( + new CSMWorld::ModifyCommand (cellTable, countIndex, count+1)); + } document.getUndoStack().beginMacro (createCommand->text()); document.getUndoStack().push (createCommand.release()); - document.getUndoStack().push (incrementCommand.release()); + if (incrementCommand.get()) + document.getUndoStack().push (incrementCommand.release()); document.getUndoStack().endMacro(); dropped = true; From 62fe47b144d8312f90b5d773c31712d876f76779 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 Jan 2016 15:37:43 +0100 Subject: [PATCH 14/17] Load default terrain if there is none defined --- components/esmterrain/storage.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index f0865a0a9..4be56d5e6 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -14,6 +14,8 @@ namespace ESMTerrain { + const float defaultHeight = -2048; + Storage::Storage(const VFS::Manager *vfs) : mVFS(vfs) { @@ -62,7 +64,9 @@ namespace ESMTerrain return true; } - return false; + min = defaultHeight; + max = defaultHeight; + return true; } void Storage::fixNormal (osg::Vec3f& normal, int cellX, int cellY, int col, int row) @@ -203,7 +207,7 @@ namespace ESMTerrain assert (vertX < numVerts); assert (vertY < numVerts); - float height = -2048; + float height = defaultHeight; if (heightData) height = heightData->mHeights[col*ESM::Land::LAND_SIZE + row]; @@ -412,7 +416,7 @@ namespace ESMTerrain const ESM::Land* land = getLand(cellX, cellY); if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) - return -2048; + return defaultHeight; // Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition From 091ca9743e97f16368c028d15ab00ec113e50b64 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Jan 2016 16:41:29 +0100 Subject: [PATCH 15/17] Do not write LandData twice (Fixes #3140) --- apps/opencs/model/doc/savingstages.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index db38c4779..af9c380a3 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -394,10 +394,6 @@ void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) CSMWorld::Land record = land.get(); writer.startRecord (record.sRecordId); record.save (writer, land.mState == CSMWorld::RecordBase::State_Deleted); - - if (const ESM::Land::LandData *data = record.getLandData (record.mDataTypes)) - data->save (mState.getWriter()); - writer.endRecord (record.sRecordId); } } From 0b84b3c2cf3253b0cf6c514485fd4601677859a4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Jan 2016 17:41:39 +0100 Subject: [PATCH 16/17] Don't crash when region weather chances don't add to 100 The invalid weather ID was resulting in out-of-bounds vector access later in the code. --- apps/openmw/mwworld/weather.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 5ce3d5c2f..321637194 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -321,10 +321,14 @@ void RegionWeather::chooseNewWeather() { sum += mChances[i]; if(chance <= sum) - break; + { + mWeather = i; + return; + } } - mWeather = i; + // if we hit this path then the chances don't add to 100, choose a default weather instead + mWeather = 0; } MoonModel::MoonModel(const std::string& name, const MWWorld::Fallback& fallback) From 4f2a031f4e66e50946ada6b20ada8f03d981fc6c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Jan 2016 18:34:47 +0100 Subject: [PATCH 17/17] Improve error message --- apps/openmw/mwworld/containerstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 45390405e..d8c37061f 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -627,7 +627,7 @@ int MWWorld::ContainerStore::getType (const ConstPtr& ptr) return Type_Weapon; throw std::runtime_error ( - "Object of type " + ptr.getTypeName() + " can not be placed into a container"); + "Object '" + ptr.getCellRef().getRefId() + "' of type " + ptr.getTypeName() + " can not be placed into a container"); } MWWorld::Ptr MWWorld::ContainerStore::search (const std::string& id)