diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index f45b44470..3c4d36de7 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -154,9 +154,11 @@ void Launcher::DataFilesPage::setProfile(int index, bool savePrevious) { if (index >= -1 && index < ui.profilesComboBox->count()) { - QString previous = ui.profilesComboBox->itemText(ui.profilesComboBox->currentIndex()); + QString previous = mPreviousProfile; QString current = ui.profilesComboBox->itemText(index); + mPreviousProfile = current; + setProfile (previous, current, savePrevious); } } @@ -167,9 +169,6 @@ void Launcher::DataFilesPage::setProfile (const QString &previous, const QString if (previous == current) return; - if (previous.isEmpty()) - return; - if (!previous.isEmpty() && savePrevious) saveSettings (previous); @@ -207,12 +206,16 @@ void Launcher::DataFilesPage::slotProfileRenamed(const QString &previous, const void Launcher::DataFilesPage::slotProfileChanged(int index) { + // in case the event was triggered externally + if (ui.profilesComboBox->currentIndex() != index) + ui.profilesComboBox->setCurrentIndex(index); + setProfile (index, true); } void Launcher::DataFilesPage::on_newProfileAction_triggered() { - if (!mProfileDialog->exec() == QDialog::Accepted) + if (mProfileDialog->exec() != QDialog::Accepted) return; QString profile = mProfileDialog->lineEdit()->text(); @@ -222,9 +225,10 @@ void Launcher::DataFilesPage::on_newProfileAction_triggered() saveSettings(); - mSelector->clearCheckStates(); + mLauncherSettings.setValue(QString("Profiles/currentprofile"), profile); addProfile(profile, true); + mSelector->clearCheckStates(); mSelector->setGameFile(); @@ -238,10 +242,8 @@ void Launcher::DataFilesPage::addProfile (const QString &profile, bool setAsCurr if (profile.isEmpty()) return; - if (ui.profilesComboBox->findText (profile) != -1) - return; - - ui.profilesComboBox->addItem (profile); + if (ui.profilesComboBox->findText (profile) == -1) + ui.profilesComboBox->addItem (profile); if (setAsCurrent) setProfile (ui.profilesComboBox->findText (profile), false); @@ -257,10 +259,12 @@ void Launcher::DataFilesPage::on_deleteProfileAction_triggered() if (!showDeleteMessageBox (profile)) return; - // Remove the profile from the combobox - ui.profilesComboBox->removeItem (ui.profilesComboBox->findText (profile)); + // this should work since the Default profile can't be deleted and is always index 0 + int next = ui.profilesComboBox->currentIndex()-1; + ui.profilesComboBox->setCurrentIndex(next); removeProfile(profile); + ui.profilesComboBox->removeItem(ui.profilesComboBox->findText(profile)); saveSettings(); diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 5beeb0e03..15fa00308 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -67,6 +67,8 @@ namespace Launcher Config::GameSettings &mGameSettings; Config::LauncherSettings &mLauncherSettings; + QString mPreviousProfile; + QString mDataLocal; void setPluginsCheckstates(Qt::CheckState state); diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 2bec88998..34be298d3 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -281,7 +281,8 @@ namespace MWBase virtual void deleteObject (const MWWorld::Ptr& ptr) = 0; virtual void undeleteObject (const MWWorld::Ptr& ptr) = 0; - virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; + virtual MWWorld::Ptr moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; + ///< @return an updated Ptr in case the Ptr's cell changes virtual void moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z) = 0; diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 4983a4a4f..848d2c7a0 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -95,7 +95,7 @@ namespace MWMechanics * +----------------> * high cost */ - bool PathgridGraph::load(const ESM::Cell* cell) + bool PathgridGraph::load(const MWWorld::CellStore *cell) { if(!cell) return false; @@ -103,10 +103,9 @@ namespace MWMechanics if(mIsGraphConstructed) return true; - mCell = cell; - mIsExterior = cell->isExterior(); - mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*cell); - + mCell = cell->getCell(); + mIsExterior = cell->getCell()->isExterior(); + mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*cell->getCell()); if(!mPathgrid) return false; diff --git a/apps/openmw/mwmechanics/pathgrid.hpp b/apps/openmw/mwmechanics/pathgrid.hpp index 5d01dca00..2742957a6 100644 --- a/apps/openmw/mwmechanics/pathgrid.hpp +++ b/apps/openmw/mwmechanics/pathgrid.hpp @@ -21,7 +21,7 @@ namespace MWMechanics public: PathgridGraph(); - bool load(const ESM::Cell *cell); + bool load(const MWWorld::CellStore *cell); // returns true if end point is strongly connected (i.e. reachable // from start point) both start and end are pathgrid point indexes diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 4f5536ca3..972c1b6dd 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -231,8 +231,9 @@ void Debugging::togglePathgrid() void Debugging::enableCellPathgrid(MWWorld::CellStore *store) { + MWBase::World* world = MWBase::Environment::get().getWorld(); const ESM::Pathgrid *pathgrid = - MWBase::Environment::get().getWorld()->getStore().get().search(*store->getCell()); + world->getStore().get().search(*store->getCell()); if (!pathgrid) return; Vector3 cellPathGridPos(0, 0, 0); diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 88aa46a98..5d52033a8 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -589,4 +589,10 @@ namespace MWScript { return mTargetId; } + + void InterpreterContext::updatePtr(const MWWorld::Ptr& updated) + { + if (!mReference.isEmpty()) + mReference = updated; + } } diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index bcf02e68e..354df00bd 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -169,6 +169,9 @@ namespace MWScript MWWorld::Ptr getReference(bool required=true); ///< Reference, that the script is running from (can be empty) + void updatePtr(const MWWorld::Ptr& updated); + ///< Update the Ptr stored in mReference, if there is one stored there. Should be called after the reference has been moved to a new cell. + virtual std::string getTargetId() const; }; } diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 80b13d6bb..b39b3507a 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -224,20 +224,23 @@ namespace MWScript float ay = ptr.getRefData().getPosition().pos[1]; float az = ptr.getRefData().getPosition().pos[2]; + MWWorld::Ptr updated = ptr; if(axis == "x") { - MWBase::Environment::get().getWorld()->moveObject(ptr,pos,ay,az); + updated = MWBase::Environment::get().getWorld()->moveObject(ptr,pos,ay,az); } else if(axis == "y") { - MWBase::Environment::get().getWorld()->moveObject(ptr,ax,pos,az); + updated = MWBase::Environment::get().getWorld()->moveObject(ptr,ax,pos,az); } else if(axis == "z") { - MWBase::Environment::get().getWorld()->moveObject(ptr,ax,ay,pos); + updated = MWBase::Environment::get().getWorld()->moveObject(ptr,ax,ay,pos); } else throw std::runtime_error ("invalid axis: " + axis); + + dynamic_cast(runtime.getContext()).updatePtr(updated); } }; @@ -317,6 +320,8 @@ namespace MWScript { MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z); ptr = MWWorld::Ptr(ptr.getBase(), store); + dynamic_cast(runtime.getContext()).updatePtr(ptr); + float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) @@ -365,15 +370,18 @@ namespace MWScript // another morrowind oddity: player will be moved to the exterior cell at this location, // non-player actors will move within the cell they are in. + MWWorld::Ptr updated; if (ptr.getRefData().getHandle() == "player") { - MWBase::Environment::get().getWorld()->moveObject(ptr, - MWBase::Environment::get().getWorld()->getExterior(cx,cy),x,y,z); + MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z); + updated = MWWorld::Ptr(ptr.getBase(), cell); } else { - MWBase::Environment::get().getWorld()->moveObject(ptr, x, y, z); + updated = MWBase::Environment::get().getWorld()->moveObject(ptr, x, y, z); } + dynamic_cast(runtime.getContext()).updatePtr(updated); float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); @@ -640,8 +648,10 @@ namespace MWScript ptr.getRefData().setLocalRotation(rot); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0,0,0,true); - MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0], - ptr.getCellRef().getPosition().pos[1], ptr.getCellRef().getPosition().pos[2]); + + dynamic_cast(runtime.getContext()).updatePtr( + MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0], + ptr.getCellRef().getPosition().pos[1], ptr.getCellRef().getPosition().pos[2])); } }; @@ -680,7 +690,8 @@ namespace MWScript throw std::runtime_error ("invalid movement axis: " + axis); Ogre::Vector3 worldPos = ptr.getRefData().getBaseNode()->convertLocalToWorldPosition(posChange); - MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z); + dynamic_cast(runtime.getContext()).updatePtr( + MWBase::Environment::get().getWorld()->moveObject(ptr, worldPos.x, worldPos.y, worldPos.z)); } }; @@ -703,17 +714,18 @@ namespace MWScript const float *objPos = ptr.getRefData().getPosition().pos; + MWWorld::Ptr updated; if (axis == "x") { - MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0]+movement, objPos[1], objPos[2]); + updated = MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0]+movement, objPos[1], objPos[2]); } else if (axis == "y") { - MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1]+movement, objPos[2]); + updated = MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1]+movement, objPos[2]); } else if (axis == "z") { - MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1], objPos[2]+movement); + updated = MWBase::Environment::get().getWorld()->moveObject(ptr, objPos[0], objPos[1], objPos[2]+movement); } else throw std::runtime_error ("invalid movement axis: " + axis); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 52e70fef2..f1a8451ea 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -413,7 +413,7 @@ namespace MWWorld // TODO: the pathgrid graph only needs to be loaded for active cells, so move this somewhere else. // In a simple test, loading the graph for all cells in MW + expansions took 200 ms - mPathgridGraph.load(mCell); + mPathgridGraph.load(this); } } diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 90786acd4..83e911174 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -141,6 +141,8 @@ namespace MWWorld mStores[ESM::REC_SSCR] = &mStartScripts; mStores[ESM::REC_STAT] = &mStatics; mStores[ESM::REC_WEAP] = &mWeapons; + + mPathgrids.setCells(mCells); } void clearDynamic () diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index c8fa087c2..c4070f032 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -849,15 +849,28 @@ namespace MWWorld Interior mInt; Exterior mExt; + Store* mCells; + public: - void load(ESM::ESMReader &esm, const std::string &id) { + void setCells(Store& cells) + { + mCells = &cells; + } + void load(ESM::ESMReader &esm, const std::string &id) { ESM::Pathgrid pathgrid; pathgrid.load(esm); + // Unfortunately the Pathgrid record model does not specify whether the pathgrid belongs to an interior or exterior cell. + // For interior cells, mCell is the cell name, but for exterior cells it is either the cell name or if that doesn't exist, the cell's region name. + // mX and mY will be (0,0) for interior cells, but there is also an exterior cell with the coordinates of (0,0), so that doesn't help. + // Check whether mCell is an interior cell. This isn't perfect, will break if a Region with the same name as an interior cell is created. + // A proper fix should be made for future versions of the file format. + bool interior = mCells->search(pathgrid.mCell) != NULL; + // Try to overwrite existing record - if (!pathgrid.mCell.empty()) + if (interior) { std::pair ret = mInt.insert(std::make_pair(pathgrid.mCell, pathgrid)); if (!ret.second) @@ -865,8 +878,7 @@ namespace MWWorld } else { - std::pair ret = mExt.insert(std::make_pair(std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY), - pathgrid)); + std::pair ret = mExt.insert(std::make_pair(std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY), pathgrid)); if (!ret.second) ret.first->second = pathgrid; } @@ -886,45 +898,47 @@ namespace MWWorld return NULL; } - const ESM::Pathgrid *find(int x, int y) const { - const ESM::Pathgrid *ptr = search(x, y); - if (ptr == 0) { - std::ostringstream msg; - msg << "Pathgrid at (" << x << ", " << y << ") not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - - const ESM::Pathgrid *search(const std::string &name) const { + const ESM::Pathgrid *search(const std::string& name) const { Interior::const_iterator it = mInt.find(name); if (it != mInt.end()) return &(it->second); return NULL; } - const ESM::Pathgrid *find(const std::string &name) const { - const ESM::Pathgrid *ptr = search(name); - if (ptr == 0) { + const ESM::Pathgrid *find(int x, int y) const { + const ESM::Pathgrid* pathgrid = search(x,y); + if (!pathgrid) + { + std::ostringstream msg; + msg << "Pathgrid in cell '" << x << " " << y << "' not found"; + throw std::runtime_error(msg.str()); + } + return pathgrid; + } + + const ESM::Pathgrid* find(const std::string& name) const { + const ESM::Pathgrid* pathgrid = search(name); + if (!pathgrid) + { std::ostringstream msg; msg << "Pathgrid in cell '" << name << "' not found"; throw std::runtime_error(msg.str()); } - return ptr; + return pathgrid; } const ESM::Pathgrid *search(const ESM::Cell &cell) const { - if (cell.mData.mFlags & ESM::Cell::Interior) { + if (!(cell.mData.mFlags & ESM::Cell::Interior)) + return search(cell.mData.mX, cell.mData.mY); + else return search(cell.mName); - } - return search(cell.mData.mX, cell.mData.mY); } const ESM::Pathgrid *find(const ESM::Cell &cell) const { - if (cell.mData.mFlags & ESM::Cell::Interior) { + if (!(cell.mData.mFlags & ESM::Cell::Interior)) + return find(cell.mData.mX, cell.mData.mY); + else return find(cell.mName); - } - return find(cell.mData.mX, cell.mData.mY); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2607a6d4d..e24e99c30 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1158,6 +1158,7 @@ namespace MWWorld ptr.getClass().copyToCell(ptr, *newCell, pos); mRendering->updateObjectCell(ptr, copy); + ptr.getRefData().setBaseNode(NULL); MWBase::Environment::get().getSoundManager()->updatePtr (ptr, copy); MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); @@ -1187,7 +1188,7 @@ namespace MWWorld } } - bool World::moveObjectImp(const Ptr& ptr, float x, float y, float z) + MWWorld::Ptr World::moveObjectImp(const Ptr& ptr, float x, float y, float z) { CellStore *cell = ptr.getCell(); @@ -1200,12 +1201,14 @@ namespace MWWorld moveObject(ptr, cell, x, y, z); - return cell != ptr.getCell(); + MWWorld::Ptr updated = ptr; + updated.mCell = cell; + return updated; } - void World::moveObject (const Ptr& ptr, float x, float y, float z) + MWWorld::Ptr World::moveObject (const Ptr& ptr, float x, float y, float z) { - moveObjectImp(ptr, x, y, z); + return moveObjectImp(ptr, x, y, z); } void World::scaleObject (const Ptr& ptr, float scale) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c93d517c1..c8e254b2f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -104,8 +104,8 @@ namespace MWWorld void rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust); - bool moveObjectImp (const Ptr& ptr, float x, float y, float z); - ///< @return true if the active cell (cell player is in) changed + Ptr moveObjectImp (const Ptr& ptr, float x, float y, float z); + ///< @return an updated Ptr in case the Ptr's cell changes Ptr copyObjectToCell(const Ptr &ptr, CellStore* cell, ESM::Position pos, bool adjustPos=true); @@ -341,7 +341,8 @@ namespace MWWorld virtual void deleteObject (const Ptr& ptr); virtual void undeleteObject (const Ptr& ptr); - virtual void moveObject (const Ptr& ptr, float x, float y, float z); + virtual MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z); + ///< @return an updated Ptr in case the Ptr's cell changes virtual void moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z); virtual void scaleObject (const Ptr& ptr, float scale); diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 16d54ff51..203f27e6e 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -391,6 +391,10 @@ namespace Compiler { if (get (c)) { + /// \todo hack to allow a space in comparison operators (add option to disable) + if (c==' ') + get (c); + if (c=='=') special = S_cmpEQ; else @@ -398,7 +402,7 @@ namespace Compiler special = S_cmpEQ; putback (c); // return false; -// Allow = as synonym for ==. \todo optionally disable for post-1.0 scripting improvements. +/// Allow = as synonym for ==. \todo optionally disable for post-1.0 scripting improvements. } } else @@ -411,6 +415,10 @@ namespace Compiler { if (get (c)) { + /// \todo hack to allow a space in comparison operators (add option to disable) + if (c==' ' && !get (c)) + return false; + if (c=='=') special = S_cmpNE; else @@ -441,6 +449,10 @@ namespace Compiler { if (get (c)) { + /// \todo hack to allow a space in comparison operators (add option to disable) + if (c==' ') + get (c); + if (c=='=') { special = S_cmpLE; @@ -461,6 +473,10 @@ namespace Compiler { if (get (c)) { + /// \todo hack to allow a space in comparison operators (add option to disable) + if (c==' ') + get (c); + if (c=='=') { special = S_cmpGE; diff --git a/components/config/settingsbase.hpp b/components/config/settingsbase.hpp index 92ca34cdf..e6b0908e0 100644 --- a/components/config/settingsbase.hpp +++ b/components/config/settingsbase.hpp @@ -50,7 +50,7 @@ namespace Config bool readFile(QTextStream &stream) { - mCache.clear(); + Map cache; QString sectionPrefix; @@ -79,31 +79,30 @@ namespace Config mSettings.remove(key); - QStringList values = mCache.values(key); + QStringList values = cache.values(key); if (!values.contains(value)) { if (mMultiValue) { - mCache.insertMulti(key, value); + cache.insertMulti(key, value); } else { - mCache.insert(key, value); + cache.insert(key, value); } } } } if (mSettings.isEmpty()) { - mSettings = mCache; // This is the first time we read a file + mSettings = cache; // This is the first time we read a file return true; } // Merge the changed keys with those which didn't - mSettings.unite(mCache); + mSettings.unite(cache); return true; } private: Map mSettings; - Map mCache; bool mMultiValue; };