From 0e641f12464b47c8225292968bcbca5fb6ec1bd5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Jul 2010 12:29:23 +0200 Subject: [PATCH] implemented coc instruction --- apps/openmw/engine.cpp | 2 + apps/openmw/mwrender/cell.hpp | 3 ++ apps/openmw/mwrender/interior.hpp | 2 +- apps/openmw/mwrender/playerpos.hpp | 10 ++++- apps/openmw/mwscript/cellextensions.cpp | 23 +++++++++++ apps/openmw/mwscript/docs/vmformat.txt | 3 +- apps/openmw/mwworld/world.cpp | 52 +++++++++++++++++++++++-- apps/openmw/mwworld/world.hpp | 11 ++++++ 8 files changed, 99 insertions(+), 7 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 78e97c6ded..a4d147c6ba 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 9e214209ab..d6dd944caf 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 cd6834999c..a8b5c7a8ae 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 bae5492018..0eed8b7b4d 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 73e131a8de..963cb5af89 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 90c84c773e..6d78065b32 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 24bf27ea54..944d18f872 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 cd12501bfb..abb17a6ee6 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(); }; }