diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index db38c4779b..af9c380a31 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); } } diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 8b827d0a2b..859fabd117 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -190,6 +190,24 @@ void CSMPrefs::State::declare() declareBool ("scene-hide-basic", "Hide basic 3D scenes tooltips", false); 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 7f9e426c75..4725a993fc 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -1,11 +1,18 @@ #include "instancemode.hpp" +#include + #include "../../model/prefs/state.hpp" +#include "../../model/world/idtable.hpp" +#include "../../model/world/idtree.hpp" +#include "../../model/world/commands.hpp" + #include "mask.hpp" #include "object.hpp" #include "worldspacewidget.hpp" +#include "pagedworldspacewidget.hpp" CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) : EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference, "Instance editing", @@ -55,3 +62,140 @@ 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; + + 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); + + CSMWorld::IdTree& cellTable = dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)); + + 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)); + + bool dropped = false; + + std::vector ids = mime->getData(); + + 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())); + + 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(); + + incrementCommand.reset ( + new CSMWorld::ModifyCommand (cellTable, countIndex, count+1)); + } + + document.getUndoStack().beginMacro (createCommand->text()); + document.getUndoStack().push (createCommand.release()); + if (incrementCommand.get()) + 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 66451bd996..7649c241ca 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 e0707524db..c6e422bd10 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()); @@ -504,6 +509,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 e983fddd55..647341d1f4 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); @@ -96,6 +98,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 4b2ff9a5f0..e203a250ba 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 9e6fa97f43..70a20c216d 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 3b169b5c29..800fd3d6e4 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); + + 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 * CSMPrefs::get()["Scene Drops"]["distance"].toInt(); +} + 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 07e505fe2c..142ed04ca0 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 = Mask_Reference | Mask_Terrain, + bool ignoreHidden = false) const; + + virtual std::string getCellId (const osg::Vec3f& point) const = 0; + protected: virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); diff --git a/apps/openmw/mwbase/journal.hpp b/apps/openmw/mwbase/journal.hpp index 738014ba6e..cd87928903 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/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 801016e068..06a8ffa352 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -525,8 +525,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; @@ -549,6 +549,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/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index 2f5f02b01f..9f74d0733d 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 3ae3efcc8d..8711ab53a7 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 e6ffe22ab2..8ea72e3ba3 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 7f26a5bb90..c3e9406290 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/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index cf0fa3414a..8d6ce6beb4 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 0ebb595ddf..89f4d8cf37 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; @@ -269,8 +270,6 @@ namespace MWGui // normalized cell coordinates float nX,nY; - markerPos.interior = mInterior; - if (!mInterior) { int cellX, cellY; @@ -1078,7 +1077,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 a41d5d5270..227a9e3f96 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); @@ -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; @@ -107,7 +105,8 @@ namespace MWGui MyGUI::ImageBox* mCompass; std::string mPrefix; bool mChanged; - bool mFogOfWar; + bool mFogOfWarToggled; + bool mFogOfWarEnabled; int mMapWidgetSize; diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index fbfbd0e702..86ecd9dfb0 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 99553808b4..4214653095 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/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index ab8784beb1..6073076e00 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/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 9d5950a90e..200f484b57 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) @@ -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) diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 72ee0354ed..59165013d6 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(); diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index c305fb81fc..fcb7e8f3b2 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); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 9c63511b27..593fdcca52 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/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index ab9fa46110..d8c37061f9 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); } @@ -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) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 439ac19ec9..d1faf621c2 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/weather.cpp b/apps/openmw/mwworld/weather.cpp index c40913ff1b..03e7b581a0 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 Fallback::Map& fallback) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 789b1b64fa..c566a32b53 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); @@ -3064,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(); @@ -3113,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 53d640871e..a9dce46e87 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -622,8 +622,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); @@ -644,6 +644,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; }; } diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index f0865a0a98..4be56d5e6a 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 diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 6d2424aa5b..cf7fe1be70 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 @@ + + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 682d89ebcc..22270bb9f6 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -11,41 +11,49 @@ + + + + + + + + @@ -53,41 +61,49 @@ + + + + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 49c9c54191..6a2495e267 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