diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 78e97c6de..a4d147c6b 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -56,6 +56,8 @@ bool OMW::Engine::frameStarted(const Ogre::FrameEvent& evt) mEnvironment.mWorld->advanceTime ( mEnvironment.mFrameDuration*mEnvironment.mWorld->getTimeScaleFactor()/3600); + mEnvironment.mWorld->markCellAsUnchanged(); + return true; } diff --git a/apps/openmw/mwrender/cell.hpp b/apps/openmw/mwrender/cell.hpp index 9e214209a..d6dd944ca 100644 --- a/apps/openmw/mwrender/cell.hpp +++ b/apps/openmw/mwrender/cell.hpp @@ -18,6 +18,9 @@ namespace MWRender /// memory. virtual void hide() = 0; + /// Destroy all rendering objects connected with this cell. + virtual void destroy() = 0; + /// Make the reference with the given handle visible. virtual void enable (const std::string& handle) = 0; diff --git a/apps/openmw/mwrender/interior.hpp b/apps/openmw/mwrender/interior.hpp index cd6834999..a8b5c7a8a 100644 --- a/apps/openmw/mwrender/interior.hpp +++ b/apps/openmw/mwrender/interior.hpp @@ -91,7 +91,7 @@ namespace MWRender virtual void hide(); /// Destroy all rendering objects connected with this cell. - void destroy(); // comment by Zini: shouldn't this go into the destructor? + virtual void destroy(); // comment by Zini: shouldn't this go into the destructor? /// Switch through lighting modes. void toggleLight(); diff --git a/apps/openmw/mwrender/playerpos.hpp b/apps/openmw/mwrender/playerpos.hpp index bae549201..0eed8b7b4 100644 --- a/apps/openmw/mwrender/playerpos.hpp +++ b/apps/openmw/mwrender/playerpos.hpp @@ -22,16 +22,22 @@ namespace MWRender camera(cam) { mPlayer.base = player; - mPlayer.ref.pos.pos[0] = mPlayer.ref.pos.pos[1] = mPlayer.ref.pos.pos[2]; + mPlayer.ref.pos.pos[0] = mPlayer.ref.pos.pos[1] = mPlayer.ref.pos.pos[2] = 0; } // Set the player position. Uses Morrowind coordinates. - void setPos(float _x, float _y, float _z) + void setPos(float _x, float _y, float _z, bool updateCamera = false) { mPlayer.ref.pos.pos[0] = _x; mPlayer.ref.pos.pos[1] = _y; mPlayer.ref.pos.pos[2] = _z; + if (updateCamera) + camera->setPosition (Ogre::Vector3 ( + mPlayer.ref.pos.pos[0], + mPlayer.ref.pos.pos[2], + mPlayer.ref.pos.pos[1])); + // TODO: Update sound listener } diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 73e131a8d..963cb5af8 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -27,17 +27,40 @@ namespace MWScript runtime.push (context.getWorld().hasCellChanged() ? 1 : 0); } }; + + class OpCOC : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string cell = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + ESM::Position pos; + pos.pos[0] = pos.pos[1] = pos.pos[2] = 0; + pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; + context.getWorld().changeCell (cell, pos); + } + }; const int opcodeCellChanged = 0x2000000; + const int opcodeCOC = 0x2000026; void registerExtensions (Compiler::Extensions& extensions) { extensions.registerFunction ("cellchanged", 'l', "", opcodeCellChanged); + extensions.registerInstruction ("coc", "S", opcodeCOC); + extensions.registerInstruction ("centeroncell", "S", opcodeCOC); } void installOpcodes (Interpreter::Interpreter& interpreter) { interpreter.installSegment5 (opcodeCellChanged, new OpCellChanged); + interpreter.installSegment5 (opcodeCOC, new OpCOC); } } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 90c84c773..6d78065b3 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -59,5 +59,6 @@ op 0x2000022: TurnMoonWhite op 0x2000023: TurnMoonRed op 0x2000024: GetMasserPhase op 0x2000025: GetSecundaPhase -opcodes 0x2000026-0x3ffffff unused +op 0x2000026: COC +opcodes 0x2000027-0x3ffffff unused diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 24bf27ea5..944d18f87 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -166,7 +166,7 @@ namespace MWWorld World::World (OEngine::Render::OgreRenderer& renderer, const boost::filesystem::path& dataDir, const std::string& master, const std::string& startCell, bool newGame) : mSkyManager (0), mScene (renderer), mPlayerPos (0), mCurrentCell (0), mGlobalVariables (0), - mSky (false) + mSky (false), mCellChanged (false) { boost::filesystem::path masterPath (dataDir); masterPath /= master; @@ -240,8 +240,7 @@ namespace MWWorld bool World::hasCellChanged() const { - // Cell change not implemented yet. - return false; + return mCellChanged; } Globals::Data& World::getGlobalVariable (const std::string& name) @@ -425,4 +424,51 @@ namespace MWWorld { return mGlobalVariables->getInt ("timescale"); } + + void World::changeCell (const std::string& cellName, const ESM::Position& position) + { + // Load cell. + mInteriors[cellName].loadInt (cellName, mStore, mEsm); + + // remove active + CellRenderCollection::iterator active = mActiveCells.begin(); + + if (active!=mActiveCells.end()) + { + active->second->destroy(); + delete active->second; + mActiveCells.erase (active); + } + + mLocalScripts.clear(); // FIXME won't work with exteriors + insertInteriorScripts (mInteriors[cellName]); + + mPlayerPos->setPos (position.pos[0], position.pos[1], position.pos[2]); + // TODO orientation + + // This connects the cell data with the rendering scene. + std::pair result = + mActiveCells.insert (std::make_pair (&mInteriors[cellName], + new MWRender::InteriorCellRender (mInteriors[cellName], mScene))); + + if (result.second) + { + // Load the cell and insert it into the renderer + result.first->second->show(); + } + + if (mSky) + { + toggleSky(); + // TODO set weather + toggleSky(); + } + + mCellChanged = true; + } + + void World::markCellAsUnchanged() + { + mCellChanged = false; + } } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index cd12501bf..abb17a6ee 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -15,6 +15,11 @@ #include "ptr.hpp" #include "globals.hpp" +namespace ESM +{ + struct Position; +} + namespace Render { class OgreRenderer; @@ -52,6 +57,7 @@ namespace MWWorld ScriptList mLocalScripts; MWWorld::Globals *mGlobalVariables; bool mSky; + bool mCellChanged; // not implemented World (const World&); @@ -112,6 +118,11 @@ namespace MWWorld void setMoonColour (bool red); float getTimeScaleFactor() const; + + void changeCell (const std::string& cellName, const ESM::Position& position); + ///< works only for interior cells currently. + + void markCellAsUnchanged(); }; }