diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 1873583c1c..4e4e9062d7 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -145,6 +145,7 @@ set(GAMEWORLD_HEADER mwworld/containerutil.hpp mwworld/player.hpp mwworld/doingphysics.hpp + mwworld/cellfunctors.hpp ) source_group(apps\\openmw\\mwworld FILES ${GAMEWORLD} ${GAMEWORLD_HEADER}) @@ -206,6 +207,7 @@ set(GAMEMECHANICS_HEADER mwmechanics/stat.hpp mwmechanics/creaturestats.hpp mwmechanics/magiceffects.hpp + mwmechanics/movement.hpp ) source_group(apps\\openmw\\mwmechanics FILES ${GAMEMECHANICS} ${GAMEMECHANICS_HEADER}) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 3eaff2fe14..b78eb15820 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include "components/esm/records.hpp" #include #include @@ -158,7 +160,8 @@ bool OMW::Engine::frameStarted(const Ogre::FrameEvent& evt) mEnvironment.mWorld->markCellAsUnchanged(); // update actors - mEnvironment.mMechanicsManager->update(); + std::vector > movement; + mEnvironment.mMechanicsManager->update (movement); if (focusFrameCounter++ == focusUpdateFrame) { @@ -179,6 +182,8 @@ bool OMW::Engine::frameStarted(const Ogre::FrameEvent& evt) focusFrameCounter = 0; } + + mEnvironment.mWorld->doPhysics (movement, mEnvironment.mFrameDuration); } catch (const std::exception& e) { @@ -388,7 +393,7 @@ void OMW::Engine::go() else { pos.pos[0] = pos.pos[1] = 0; - mEnvironment.mWorld->changeCell (mCellName, pos); + mEnvironment.mWorld->changeToInteriorCell (mCellName, pos); } // Sets up the input system diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 6c96811d8a..7a72ddb8cf 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -23,6 +23,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 1d4afc0960..2dbeae3605 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -26,6 +26,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 1217d56a69..d637956412 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -26,6 +26,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 3679eb7eea..964ccbdfe6 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -26,6 +26,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 07ded02640..a264f2a1cd 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -26,6 +26,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index ea61508b8d..1da55e6f69 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -23,6 +23,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 0d358441a0..8cde67671b 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -35,6 +35,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertActorPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 4f294ce872..8a34d3abe5 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -30,6 +30,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index e4ea509f91..c88e1794b6 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -26,6 +26,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index de5c06a73e..159196eb2c 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -31,6 +31,7 @@ namespace MWClass MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); // Extract the color and convert to floating point const int color = ref->base->data.color; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 3b08ff199a..9a4b98b431 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -26,6 +26,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index d4ffdce380..f9995b77f8 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -26,6 +26,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index bc933b9189..4678df2221 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -256,8 +256,9 @@ namespace MWClass cellRender.insertMesh (headModel, Ogre::Vector3( 0, 0, 5), axis, Ogre::Radian(0), npcName + "head", neckandup, neckNumbers); neckandup[neckNumbers++] = npcName + "head"; cellRender.insertMesh (hairModel, Ogre::Vector3( 0, -1, 0), axis, Ogre::Radian(0), npcName + "hair", neckandup, neckNumbers); - ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); + cellRender.insertActorPhysics(); + ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } void Npc::enable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const @@ -392,7 +393,8 @@ namespace MWClass { case Run: - throw std::runtime_error ("run stance not manually setable for NPCs"); + stats.mRun = set; + break; case Sneak: @@ -414,7 +416,10 @@ namespace MWClass { case Run: - return ignoreForce ? false : stats.mForceRun; + if (!ignoreForce && stats.mForceRun) + return true; + + return stats.mRun; case Sneak: @@ -436,6 +441,35 @@ namespace MWClass return getStance (ptr, Run) ? 600 : 300; // TODO calculate these values from stats } + MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const + { + if (!ptr.getRefData().getMovement().get()) + { + boost::shared_ptr movement ( + new MWMechanics::Movement); + + ptr.getRefData().getMovement() = movement; + } + + return *ptr.getRefData().getMovement(); + } + + Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const + { + Ogre::Vector3 vector (0, 0, 0); + + if (ptr.getRefData().getMovement().get()) + { + vector.x = - ptr.getRefData().getMovement()->mLeftRight * 200; + vector.z = - ptr.getRefData().getMovement()->mForwardBackward * 200; + + if (getStance (ptr, Run, false)) + vector *= 2; + } + + return vector; + } + void Npc::registerSelf() { boost::shared_ptr instance (new Npc); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 1d9d90c4de..9f29878da4 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -56,6 +56,13 @@ namespace MWClass virtual float getSpeed (const MWWorld::Ptr& ptr) const; ///< Return movement speed. + virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; + ///< Return desired movement. + + virtual Ogre::Vector3 getMovementVector (const MWWorld::Ptr& ptr) const; + ///< Return desired movement vector (determined based on movement settings, + /// stance and stats). + static void registerSelf(); }; } diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index e163473f75..6c9889a7b8 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -26,6 +26,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 9188ae9ea3..028d8b5e3e 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -26,6 +26,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 7b42bc95cc..b9b5036fbc 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -26,6 +26,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 33e3e0ed42..851b4d7bf9 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -21,6 +21,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 4c14e58ea9..a985a7e42f 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -26,6 +26,7 @@ namespace MWClass { MWRender::Rendering rendering (cellRender, ref->ref); cellRender.insertMesh ("meshes\\" + model); + cellRender.insertObjectPhysics(); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); } } diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index 1cc6eca2ab..dc21680af4 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -41,27 +41,25 @@ namespace MWInput A_MoveLeft, // Move player left / right A_MoveRight, - A_MoveUp, // Move up / down - A_MoveDown, A_MoveForward, // Forward / Backward A_MoveBackward, A_Activate, - A_Use, //Use weapon, spell, etc. + A_Use, //Use weapon, spell, etc. A_Jump, - A_AutoMove, //Toggle Auto-move forward - A_Rest, //Rest - A_Journal, //Journal - A_Weapon, //Draw/Sheath weapon - A_Spell, //Ready/Unready Casting - A_AlwaysRun, //Toggle Always Run + A_AutoMove, //Toggle Auto-move forward + A_Rest, //Rest + A_Journal, //Journal + A_Weapon, //Draw/Sheath weapon + A_Spell, //Ready/Unready Casting + A_AlwaysRun, //Toggle Always Run A_CycleSpellLeft, //cycling through spells A_CycleSpellRight, A_CycleWeaponLeft,//Cycling through weapons A_CycleWeaponRight, - A_ToggleSneak, //Toggles Sneak, add Push-Sneak later - A_ToggleWalk, //Toggle Walking/Running + A_ToggleSneak, //Toggles Sneak, add Push-Sneak later + A_ToggleWalk, //Toggle Walking/Running A_QuickSave, A_QuickLoad, @@ -143,24 +141,19 @@ namespace MWInput void toggleAutoMove() { - if (player.getAutoMove() == false) - { - player.setAutoMove(true); - } else { - player.setAutoMove(false); - } + player.setAutoMove (!player.getAutoMove()); } void toggleWalking() { - player.setisWalking(true); + player.toggleRunning(); } // Exit program now button (which is disabled in GUI mode) void exitNow() { - if(!windows.isGuiMode()) - exit.exitNow(); + if(!windows.isGuiMode()) + exit.exitNow(); } public: @@ -262,73 +255,54 @@ namespace MWInput poller.bind(A_MoveRight, KC_D); poller.bind(A_MoveForward, KC_W); poller.bind(A_MoveBackward, KC_S); - - // Use shift and ctrl for up and down - poller.bind(A_MoveUp, KC_LSHIFT); - poller.bind(A_MoveDown, KC_LCONTROL); } //NOTE: Used to check for movement keys bool frameStarted(const Ogre::FrameEvent &evt) { - // Tell OIS to handle all input events - input.capture(); + // Tell OIS to handle all input events + input.capture(); - // Update windows/gui as a result of input events - // For instance this could mean opening a new window/dialog, - // by doing this after the input events are handled we - // ensure that window/gui changes appear quickly while - // avoiding that window/gui changes does not happen in - // event callbacks (which may crash) - windows.update(); + // Update windows/gui as a result of input events + // For instance this could mean opening a new window/dialog, + // by doing this after the input events are handled we + // ensure that window/gui changes appear quickly while + // avoiding that window/gui changes does not happen in + // event callbacks (which may crash) + windows.update(); - // Disable movement in Gui mode - if(windows.isGuiMode()) return true; + // Disable movement in Gui mode + if (windows.isGuiMode()) return true; - float speed = 300 * evt.timeSinceLastFrame; //placeholder player speed? - //float TESTwalkSpeed = 100 * evt.timeSinceLastFrame; //How about another? + // Configure player movement according to keyboard input. Actual movement will + // be done in the physics system. + if (poller.isDown(A_MoveLeft)) + { + player.setAutoMove (false); + player.setLeftRight (1); + } + else if (poller.isDown(A_MoveRight)) + { + player.setAutoMove (false); + player.setLeftRight (-1); + } + else + player.setLeftRight (0); - float moveX = 0, moveY = 0, moveZ = 0; + if (poller.isDown(A_MoveForward)) + { + player.setAutoMove (false); + player.setForwardBackward (1); + } + else if (poller.isDown(A_MoveBackward)) + { + player.setAutoMove (false); + player.setForwardBackward (-1); + } + else + player.setForwardBackward (0); - //execute Automove - condition checked in function - player.executeAutoMove((float)evt.timeSinceLastFrame); //or since last frame? - - //Poll and execute movement keys - will disable automove if pressed. - if(poller.isDown(A_MoveLeft)) - { - player.setAutoMove(false); - moveX -= speed; - } - - if(poller.isDown(A_MoveRight)) - { - player.setAutoMove(false); - moveX += speed; - } - - if(poller.isDown(A_MoveForward)) - { - player.setAutoMove(false); - moveZ -= speed; - } - - if(poller.isDown(A_MoveBackward)) - { - player.setAutoMove(false); - moveZ += speed; - } - - - // TODO: These should be enabled for floating modes (like - // swimming and levitation) and disabled for everything else. - if(poller.isDown(A_MoveUp)) moveY += speed; - if(poller.isDown(A_MoveDown)) moveY -= speed; - - if(moveX != 0 || moveY != 0 || moveZ != 0) - player.moveRel(moveX, moveY, moveZ); - - - return true; + return true; } // Switch between gui modes. Besides controlling the Gui windows diff --git a/apps/openmw/mwmechanics/mechanicsmanager.cpp b/apps/openmw/mwmechanics/mechanicsmanager.cpp index 05219d6aaf..df0b5616c9 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.cpp @@ -234,11 +234,17 @@ namespace MWMechanics void MechanicsManager::removeActor (const MWWorld::Ptr& ptr) { + if (ptr==mWatched) + mWatched = MWWorld::Ptr(); + mActors.erase (ptr); } void MechanicsManager::dropActors (const MWWorld::Ptr::CellStore *cellStore) { + if (!mWatched.isEmpty() && mWatched.getCell()==cellStore) + mWatched = MWWorld::Ptr(); + std::set::iterator iter = mActors.begin(); while (iter!=mActors.end()) @@ -255,7 +261,7 @@ namespace MWMechanics mWatched = ptr; } - void MechanicsManager::update() + void MechanicsManager::update (std::vector >& movement) { if (!mWatched.isEmpty()) { @@ -350,6 +356,15 @@ namespace MWMechanics mEnvironment.mWindowManager->configureSkills (majorSkills, minorSkills); } + + for (std::set::iterator iter (mActors.begin()); iter!=mActors.end(); + ++iter) + { + Ogre::Vector3 vector = MWWorld::Class::get (*iter).getMovementVector (*iter); + + if (vector!=Ogre::Vector3::ZERO) + movement.push_back (std::make_pair (iter->getRefData().getHandle(), vector)); + } } void MechanicsManager::setPlayerName (const std::string& name) diff --git a/apps/openmw/mwmechanics/mechanicsmanager.hpp b/apps/openmw/mwmechanics/mechanicsmanager.hpp index 26d3621ab9..2e2192638f 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.hpp @@ -2,12 +2,19 @@ #define GAME_MWMECHANICS_MECHANICSMANAGER_H #include +#include +#include #include "../mwworld/ptr.hpp" #include "creaturestats.hpp" #include "npcstats.hpp" +namespace Ogre +{ + class Vector3; +} + namespace MWWorld { class Environment; @@ -53,8 +60,8 @@ namespace MWMechanics ///< On each update look for changes in a previously registered actor and update the /// GUI accordingly. - void update(); - ///< Update actor stats + void update (std::vector >& movement); + ///< Update actor stats and store desired velocity vectors in \a movement void setPlayerName (const std::string& name); ///< Set player name. diff --git a/apps/openmw/mwmechanics/movement.hpp b/apps/openmw/mwmechanics/movement.hpp new file mode 100644 index 0000000000..a555ac010a --- /dev/null +++ b/apps/openmw/mwmechanics/movement.hpp @@ -0,0 +1,16 @@ +#ifndef GAME_MWMECHANICS_MOVEMENT_H +#define GAME_MWMECHANICS_MOVEMENT_H + +namespace MWMechanics +{ + /// Desired movement for an actor + struct Movement + { + signed char mLeftRight; // 1: wants to move left, -1: wants to move right + signed char mForwardBackward; // 1:wants to move forward, -1: wants to move backward + + Movement() : mLeftRight (0), mForwardBackward (0) {} + }; +} + +#endif diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index fa0e46b1ac..aeb5f56d5b 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -21,10 +21,12 @@ namespace MWMechanics bool mForceRun; bool mForceSneak; + bool mRun; bool mSneak; bool mCombat; - NpcStats() : mForceRun (false), mForceSneak (false), mSneak (false), mCombat (false) {} + NpcStats() : mForceRun (false), mForceSneak (false), mRun (false), mSneak (false), + mCombat (false) {} }; } diff --git a/apps/openmw/mwrender/cellimp.hpp b/apps/openmw/mwrender/cellimp.hpp index 91676e11c0..272bfeeab4 100644 --- a/apps/openmw/mwrender/cellimp.hpp +++ b/apps/openmw/mwrender/cellimp.hpp @@ -45,6 +45,9 @@ namespace MWRender virtual void scaleMesh(Ogre::Vector3 axis, std::string sceneNodeName[], int elements) = 0; + virtual void insertObjectPhysics() = 0; + + virtual void insertActorPhysics() = 0; /// insert a light related to the most recent insertBegin call. virtual void insertLight(float r, float g, float b, float radius) = 0; diff --git a/apps/openmw/mwrender/exterior.cpp b/apps/openmw/mwrender/exterior.cpp index cd2a7680d4..c1d7641b87 100644 --- a/apps/openmw/mwrender/exterior.cpp +++ b/apps/openmw/mwrender/exterior.cpp @@ -58,6 +58,8 @@ void ExteriorCellRender::insertBegin (ESM::CellRef &ref) // Rotates first around z, then y, then x mInsert->setOrientation(xr*yr*zr); + + mInsertMesh.clear(); } @@ -81,18 +83,18 @@ void ExteriorCellRender::insertMesh(const std::string &mesh, Ogre::Vector3 vec, if(sceneParent[i] != "" && parent->getChild(sceneParent[i])) parent = dynamic_cast (parent->getChild(sceneParent[i])); } - + mNpcPart = parent->createChildSceneNode(sceneNodeName); NIFLoader::load(mesh); MovableObject *ent = mScene.getMgr()->createEntity(mesh); - + mNpcPart->translate(vec); mNpcPart->rotate(axis, angle); // mNpcPart->translate(vec); //mNpcPart->rotate(axis, angle); mNpcPart->attachObject(ent); //mNpcPart-> - + } */ void ExteriorCellRender::insertMesh(const std::string &mesh, Ogre::Vector3 vec, Ogre::Vector3 axis, Ogre::Radian angle, std::string sceneNodeName, std::string sceneParent[], int elements) @@ -108,7 +110,7 @@ void ExteriorCellRender::insertMesh(const std::string &mesh, Ogre::Vector3 vec, if(sceneParent[i] != "" && parent->getChild(sceneParent[i])) parent = dynamic_cast (parent->getChild(sceneParent[i])); } - + mNpcPart = parent->createChildSceneNode(sceneNodeName); MeshPtr good2 = NIFLoader::load(mesh); @@ -120,7 +122,7 @@ void ExteriorCellRender::insertMesh(const std::string &mesh, Ogre::Vector3 vec, mNpcPart->rotate(axis, angle); } else{ - + mNpcPart->rotate(axis, angle); mNpcPart->translate(vec); } @@ -202,6 +204,22 @@ void ExteriorCellRender::insertMesh(const std::string &mesh) NIFLoader::load(mesh); MovableObject *ent = mScene.getMgr()->createEntity(mesh); mInsert->attachObject(ent); + + if (mInsertMesh.empty()) + mInsertMesh = mesh; +} + +void ExteriorCellRender::insertObjectPhysics() +{ + if (!mInsertMesh.empty()) + mScene.addObject (mInsert->getName(), mInsertMesh, mInsert->getOrientation(), + mInsert->getScale().x, mInsert->getPosition()); +} + +void ExteriorCellRender::insertActorPhysics() +{ + if (!mInsertMesh.empty()) + mScene.addActor (mInsert->getName(), mInsertMesh, mInsert->getPosition()); } // insert a light related to the most recent insertBegin call. diff --git a/apps/openmw/mwrender/exterior.hpp b/apps/openmw/mwrender/exterior.hpp index 67d41bcacd..93491f263e 100644 --- a/apps/openmw/mwrender/exterior.hpp +++ b/apps/openmw/mwrender/exterior.hpp @@ -54,6 +54,7 @@ namespace MWRender Ogre::SceneNode *mBase; Ogre::SceneNode *mInsert; + std::string mInsertMesh; Ogre::SceneNode *mNpcPart; // 0 normal, 1 more bright, 2 max @@ -67,11 +68,15 @@ namespace MWRender /// insert a mesh related to the most recent insertBegin call. virtual void insertMesh(const std::string &mesh, Ogre::Vector3 vec, Ogre::Vector3 axis, Ogre::Radian angle, std::string sceneNodeName, std::string sceneParent[], int elements); virtual void insertMesh(const std::string &mesh, Ogre::Vector3 vec, Ogre::Vector3 axis, Ogre::Radian angle, std::string sceneNodeName, std::string sceneParent[], int elements, bool translateFirst); - + virtual void insertMesh(const std::string &mesh); virtual void rotateMesh(Ogre::Vector3 axis, Ogre::Radian angle, std::string sceneNodeName[], int elements); virtual void scaleMesh(Ogre::Vector3 axis, std::string sceneNodeName[], int elements); + virtual void insertObjectPhysics(); + + virtual void insertActorPhysics(); + /// insert a light related to the most recent insertBegin call. virtual void insertLight(float r, float g, float b, float radius); @@ -85,7 +90,7 @@ namespace MWRender void configureFog(); void setAmbientMode(); - + public: diff --git a/apps/openmw/mwrender/interior.cpp b/apps/openmw/mwrender/interior.cpp index 6e1f0d2973..e096b7757e 100644 --- a/apps/openmw/mwrender/interior.cpp +++ b/apps/openmw/mwrender/interior.cpp @@ -60,6 +60,8 @@ void InteriorCellRender::insertBegin (ESM::CellRef &ref) // Rotates first around z, then y, then x insert->setOrientation(xr*yr*zr); + + mInsertMesh.clear(); } // insert a mesh related to the most recent insertBegin call. @@ -100,7 +102,7 @@ void InteriorCellRender::insertMesh(const std::string &mesh, Ogre::Vector3 vec, if(sceneParent[i] != "" && parent->getChild(sceneParent[i])) parent = dynamic_cast (parent->getChild(sceneParent[i])); } - + npcPart = parent->createChildSceneNode(sceneNodeName); //npcPart->showBoundingBox(true); @@ -108,7 +110,7 @@ void InteriorCellRender::insertMesh(const std::string &mesh, Ogre::Vector3 vec, MovableObject *ent = scene.getMgr()->createEntity(mesh); //ent->extr - + // MovableObject *ent2 = scene.getMgr()->createEntity(bounds // ); //ent-> @@ -119,7 +121,7 @@ void InteriorCellRender::insertMesh(const std::string &mesh, Ogre::Vector3 vec, npcPart->rotate(axis, angle); } else{ - + npcPart->rotate(axis, angle); npcPart->translate(vec); } @@ -185,6 +187,22 @@ void InteriorCellRender::insertMesh(const std::string &mesh) NIFLoader::load(mesh); MovableObject *ent = scene.getMgr()->createEntity(mesh); insert->attachObject(ent); + + if (mInsertMesh.empty()) + mInsertMesh = mesh; +} + +void InteriorCellRender::insertObjectPhysics() +{ + if (!mInsertMesh.empty()) + scene.addObject (insert->getName(), mInsertMesh, insert->getOrientation(), + insert->getScale().x, insert->getPosition()); +} + +void InteriorCellRender::insertActorPhysics() +{ + if (!mInsertMesh.empty()) + scene.addActor (insert->getName(), mInsertMesh, insert->getPosition()); } // insert a light related to the most recent insertBegin call. diff --git a/apps/openmw/mwrender/interior.hpp b/apps/openmw/mwrender/interior.hpp index a389435214..7c4b2aaf11 100644 --- a/apps/openmw/mwrender/interior.hpp +++ b/apps/openmw/mwrender/interior.hpp @@ -54,6 +54,7 @@ namespace MWRender Ogre::SceneNode *base; Ogre::SceneNode *insert; + std::string mInsertMesh; Ogre::SceneNode *npcPart; // 0 normal, 1 more bright, 2 max @@ -69,6 +70,11 @@ namespace MWRender virtual void insertMesh(const std::string &mesh); virtual void insertMesh(const std::string &mesh, Ogre::Vector3 vec, Ogre::Vector3 axis, Ogre::Radian angle, std::string sceneNodeName, std::string sceneParent[], int elements); virtual void insertMesh(const std::string &mesh, Ogre::Vector3 vec, Ogre::Vector3 axis, Ogre::Radian angle, std::string sceneNodeName, std::string sceneParent[], int elements, bool translateFirst); + + virtual void insertObjectPhysics(); + + virtual void insertActorPhysics(); + /// insert a light related to the most recent insertBegin call. virtual void insertLight(float r, float g, float b, float radius); diff --git a/apps/openmw/mwrender/mwscene.cpp b/apps/openmw/mwrender/mwscene.cpp index 6a0920b949..1c2303ce43 100644 --- a/apps/openmw/mwrender/mwscene.cpp +++ b/apps/openmw/mwrender/mwscene.cpp @@ -42,7 +42,10 @@ MWScene::MWScene(OEngine::Render::OgreRenderer &_rend) //used to obtain ingame information of ogre objects (which are faced or selected) mRaySceneQuery = rend.getScene()->createRayQuery(Ray()); - mPlayer = new MWRender::Player (getCamera()); + Ogre::SceneNode *playerNode = mwRoot->createChildSceneNode(); + playerNode->attachObject (getCamera()); + + mPlayer = new MWRender::Player (getCamera(), playerNode->getName()); } MWScene::~MWScene() @@ -99,16 +102,24 @@ std::pair MWScene::getFacedHandle (MWWorld::World& world) return std::pair(handle, distance); } -void MWScene::doPhysics (float duration, MWWorld::World& world) +void MWScene::doPhysics (float duration, MWWorld::World& world, + const std::vector >& actors) { // stop changes to world from being reported back to the physics system MWWorld::DoingPhysics scopeGuard; -} + // move object directly for now -> TODO replace with physics + for (std::vector >::const_iterator iter (actors.begin()); + iter!=actors.end(); ++iter) + { + MWWorld::Ptr ptr = world.getPtrViaHandle (iter->first); -void MWScene::setMovement (const std::vector& actors) -{ + Ogre::SceneNode *sceneNode = rend.getScene()->getSceneNode (iter->first); + Ogre::Vector3 newPos = sceneNode->getPosition() + sceneNode->getOrientation() * iter->second; + + world.moveObject (ptr, newPos.x, newPos.y, newPos.z); + } } void MWScene::addObject (const std::string& handle, const std::string& mesh, @@ -128,8 +139,9 @@ void MWScene::removeObject (const std::string& handle) } -void MWScene::moveObject (const std::string& handle, const Ogre::Vector3& position) +void MWScene::moveObject (const std::string& handle, const Ogre::Vector3& position, bool updatePhysics) { + rend.getScene()->getSceneNode (handle)->setPosition (position); } diff --git a/apps/openmw/mwrender/mwscene.hpp b/apps/openmw/mwrender/mwscene.hpp index e408738af7..e974e0342e 100644 --- a/apps/openmw/mwrender/mwscene.hpp +++ b/apps/openmw/mwrender/mwscene.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace Ogre { @@ -60,11 +61,8 @@ namespace MWRender std::pair getFacedHandle (MWWorld::World& world); /// Run physics simulation and modify \a world accordingly. - void doPhysics (float duration, MWWorld::World& world); - - /// Inform phyiscs system about desired velocity vectors for actors - /// (in Morrowind coordinates). - void setMovement (const std::vector& actors); + void doPhysics (float duration, MWWorld::World& world, + const std::vector >& actors); /// Add object to physics system. void addObject (const std::string& handle, const std::string& mesh, @@ -78,7 +76,7 @@ namespace MWRender void removeObject (const std::string& handle); /// Move object. - void moveObject (const std::string& handle, const Ogre::Vector3& position); + void moveObject (const std::string& handle, const Ogre::Vector3& position, bool updatePhysics); /// Change object's orientation. void rotateObject (const std::string& handle, const Ogre::Quaternion& rotation); diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index badc77bdaa..7dcaeee096 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -3,6 +3,7 @@ namespace MWRender { - Player::Player (Ogre::Camera *camera) : mCamera (camera) + Player::Player (Ogre::Camera *camera, const std::string& handle) + : mCamera (camera), mHandle (handle) {} } diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index a8f8d24fec..f2d8191162 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWRENDER_PLAYER_H #define GAME_MWRENDER_PLAYER_H +#include + namespace Ogre { class Camera; @@ -12,12 +14,15 @@ namespace MWRender class Player { Ogre::Camera *mCamera; + std::string mHandle; public: - Player (Ogre::Camera *camera); + Player (Ogre::Camera *camera, const std::string& handle); Ogre::Camera *getCamera() { return mCamera; } + + std::string getHandle() const { return mHandle; } }; } diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 4d30254693..a84de3edd7 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -53,7 +53,7 @@ namespace MWScript else { pos.pos[0] = pos.pos[1] = 0; - context.getWorld().changeCell (cell, pos); + context.getWorld().changeToInteriorCell (cell, pos); } } }; diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 3db2948184..207e2c50e9 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -16,6 +16,6 @@ namespace MWWorld if (mCellName.empty()) environment.mWorld->changeToExteriorCell (mPosition); else - environment.mWorld->changeCell (mCellName, mPosition); + environment.mWorld->changeToInteriorCell (mCellName, mPosition); } } diff --git a/apps/openmw/mwworld/cellfunctors.hpp b/apps/openmw/mwworld/cellfunctors.hpp new file mode 100644 index 0000000000..5ff801f01c --- /dev/null +++ b/apps/openmw/mwworld/cellfunctors.hpp @@ -0,0 +1,31 @@ +#ifndef GAME_MWWORLD_CELLFUNCTORS_H +#define GAME_MWWORLD_CELLFUNCTORS_H + +#include +#include + +#include "refdata.hpp" + +namespace ESM +{ + class CellRef; +} + +namespace MWWorld +{ + /// List all (Ogre-)handles. + struct ListHandles + { + std::vector mHandles; + + bool operator() (ESM::CellRef& ref, RefData& data) + { + std::string handle = data.getHandle(); + if (!handle.empty()) + mHandles.push_back (handle); + return true; + } + }; +} + +#endif diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 837b3b2942..670cf90b20 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -3,6 +3,8 @@ #include +#include + #include "ptr.hpp" #include "nullaction.hpp" @@ -112,6 +114,16 @@ namespace MWWorld return 0; } + MWMechanics::Movement& Class::getMovementSettings (const Ptr& ptr) const + { + throw std::runtime_error ("movement settings not supported by class"); + } + + Ogre::Vector3 Class::getMovementVector (const Ptr& ptr) const + { + return Ogre::Vector3 (0, 0, 0); + } + const Class& Class::get (const std::string& key) { std::map >::const_iterator iter = sClasses.find (key); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 51c727aad7..8ad9ba58fe 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -10,6 +10,11 @@ #include "containerstore.hpp" #include "refdata.hpp" +namespace Ogre +{ + class Vector3; +} + namespace MWRender { class CellRenderImp; @@ -19,6 +24,7 @@ namespace MWMechanics { struct CreatureStats; struct NpcStats; + struct Movement; } namespace MWWorld @@ -126,6 +132,13 @@ namespace MWWorld virtual float getSpeed (const Ptr& ptr) const; ///< Return movement speed. + virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const; + ///< Return desired movement. + + virtual Ogre::Vector3 getMovementVector (const Ptr& ptr) const; + ///< Return desired movement vector (determined based on movement settings, + /// stance and stats). + static const Class& get (const std::string& key); ///< If there is no class for this \a key, an exception is thrown. diff --git a/apps/openmw/mwworld/doingphysics.cpp b/apps/openmw/mwworld/doingphysics.cpp index 63c6244e99..27fb27c576 100644 --- a/apps/openmw/mwworld/doingphysics.cpp +++ b/apps/openmw/mwworld/doingphysics.cpp @@ -4,6 +4,7 @@ namespace MWWorld { int DoingPhysics::sCounter = 0; + int DoingPhysics::sSuppress = 0; DoingPhysics::DoingPhysics() { @@ -17,6 +18,16 @@ namespace MWWorld bool DoingPhysics::isDoingPhysics() { - return sCounter>0; + return sCounter>0 || sSuppress>0; + } + + SuppressDoingPhysics::SuppressDoingPhysics() + { + ++DoingPhysics::sSuppress; + } + + SuppressDoingPhysics::~SuppressDoingPhysics() + { + --DoingPhysics::sSuppress; } } diff --git a/apps/openmw/mwworld/doingphysics.hpp b/apps/openmw/mwworld/doingphysics.hpp index 7ea2b0f418..d38e4bb15d 100644 --- a/apps/openmw/mwworld/doingphysics.hpp +++ b/apps/openmw/mwworld/doingphysics.hpp @@ -3,10 +3,13 @@ namespace MWWorld { - ///< Scope guard for blocking physics updates during physics simulation. + class SuppressDoingPhysics; + + /// Scope guard for blocking physics updates during physics simulation. class DoingPhysics { static int sCounter; + static int sSuppress; private: @@ -20,6 +23,23 @@ namespace MWWorld ~DoingPhysics(); static bool isDoingPhysics(); + + friend class SuppressDoingPhysics; + }; + + /// Scope guard for temporarily lifting the block issues by DoingPhysics + class SuppressDoingPhysics + { + private: + + SuppressDoingPhysics (const SuppressDoingPhysics&); + SuppressDoingPhysics& operator= (const SuppressDoingPhysics&); + + public: + + SuppressDoingPhysics(); + + ~SuppressDoingPhysics(); }; } diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index b0805269dd..c4b17f48fd 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -4,20 +4,21 @@ #include "../mwrender/player.hpp" #include "world.hpp" +#include "class.hpp" namespace MWWorld { Player::Player (MWRender::Player *renderer, const ESM::NPC *player, MWWorld::World& world) : - mCellStore (0), mRenderer (renderer), mWorld (world), mClass (0), mCollisionMode (true) + mCellStore (0), mRenderer (renderer), mWorld (world), mClass (0), mCollisionMode (true), + mAutoMove (false), mForwardBackward (0) { mPlayer.base = player; mName = player->name; mMale = !(player->flags & ESM::NPC::Female); mRace = player->race; mPlayer.ref.pos.pos[0] = mPlayer.ref.pos.pos[1] = mPlayer.ref.pos.pos[2] = 0; + mPlayer.mData.setHandle (renderer->getHandle()); mClass = new ESM::Class (*world.getStore().classes.find (player->cls)); - mAutoMove = false; - misWalking = false; } Player::~Player() @@ -64,4 +65,45 @@ namespace MWWorld mClass = new_class; } + void Player::setAutoMove (bool enable) + { + MWWorld::Ptr ptr = getPlayer(); + + mAutoMove = enable; + + int value = mForwardBackward; + + if (mAutoMove) + value = 1; + + MWWorld::Class::get (ptr).getMovementSettings (ptr).mForwardBackward = value; + } + + void Player::setLeftRight (int value) + { + MWWorld::Ptr ptr = getPlayer(); + + MWWorld::Class::get (ptr).getMovementSettings (ptr).mLeftRight = value; + } + + void Player::setForwardBackward (int value) + { + MWWorld::Ptr ptr = getPlayer(); + + mForwardBackward = value; + + if (mAutoMove) + value = 1; + + MWWorld::Class::get (ptr).getMovementSettings (ptr).mForwardBackward = value; + } + + void Player::toggleRunning() + { + MWWorld::Ptr ptr = getPlayer(); + + bool running = MWWorld::Class::get (ptr).getStance (ptr, MWWorld::Class::Run, true); + + MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Run, !running); + } } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 5174c2d33d..1b28baf9b9 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -30,9 +30,8 @@ namespace MWWorld std::string mBirthsign; ESM::Class *mClass; bool mCollisionMode; - bool mAutoMove; - bool misWalking;//Testing... + int mForwardBackward; public: @@ -117,33 +116,13 @@ namespace MWWorld return mAutoMove; } - void setAutoMove(bool setMe) - { - mAutoMove = setMe; - } + void setAutoMove (bool enable); -//NOTE: we don't have speed being calculated yet, so for now this function only requires a frame duration. -/// float value representing time since last call - void executeAutoMove(float duration) - { - float X_Val = 0.0f; - float Y_Val = 0.0f; - float Z_Val = 300.0f * duration * -1.0f; - if (mAutoMove == true) - { - moveRel(X_Val, Y_Val, Z_Val); - } - } + void setLeftRight (int value); - bool getisWalking() - { - return misWalking; - } + void setForwardBackward (int value); - void setisWalking(bool setMe) - { - misWalking = setMe; - } + void toggleRunning(); }; } #endif diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index a8cf3aed80..a9613248e6 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -9,6 +9,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/movement.hpp" #include "containerstore.hpp" @@ -36,6 +37,7 @@ namespace MWWorld // are never copied outside of container operations. boost::shared_ptr mCreatureStats; boost::shared_ptr mNpcStats; + boost::shared_ptr mMovement; boost::shared_ptr > mContainerStore; @@ -102,6 +104,11 @@ namespace MWWorld return mNpcStats; } + boost::shared_ptr& getMovement() + { + return mMovement; + } + boost::shared_ptr >& getContainerStore() { return mContainerStore; diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 52547adc25..44a16aee71 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -22,6 +22,7 @@ #include "refdata.hpp" #include "globals.hpp" #include "doingphysics.hpp" +#include "cellfunctors.hpp" namespace { @@ -271,6 +272,15 @@ namespace MWWorld void World::unloadCell (CellRenderCollection::iterator iter) { + ListHandles functor; + iter->first->forEach (functor); + + { // silence annoying g++ warning + for (std::vector::const_iterator iter (functor.mHandles.begin()); + iter!=functor.mHandles.end(); ++iter) + mScene.removeObject (*iter); + } + removeScripts (iter->first); mEnvironment.mMechanicsManager->dropActors (iter->first); iter->second->destroy(); @@ -295,9 +305,12 @@ namespace MWWorld } } - void World::playerCellChange (Ptr::CellStore *cell, const ESM::Position& position) + void World::playerCellChange (Ptr::CellStore *cell, const ESM::Position& position, + bool adjustPlayerPos) { - mPlayer->setPos (position.pos[0], position.pos[1], position.pos[2], true); + if (adjustPlayerPos) + mPlayer->setPos (position.pos[0], position.pos[1], position.pos[2], true); + mPlayer->setCell (cell); // TODO orientation @@ -316,8 +329,87 @@ namespace MWWorld } } + void World::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos) + { + SuppressDoingPhysics scopeGuard; + + // remove active + mEnvironment.mMechanicsManager->removeActor (mPlayer->getPlayer()); + + CellRenderCollection::iterator active = mActiveCells.begin(); + + while (active!=mActiveCells.end()) + { + if (!(active->first->cell->data.flags & ESM::Cell::Interior)) + { + if (std::abs (X-active->first->cell->data.gridX)<=1 && + std::abs (Y-active->first->cell->data.gridY)<=1) + { + // keep cells within the new 3x3 grid + ++active; + continue; + } + } + + unloadCell (active++); + } + + // Load cells + for (int x=X-1; x<=X+1; ++x) + for (int y=Y-1; y<=Y+1; ++y) + { + CellRenderCollection::iterator iter = mActiveCells.begin(); + + while (iter!=mActiveCells.end()) + { + assert (!(iter->first->cell->data.flags & ESM::Cell::Interior)); + + if (x==iter->first->cell->data.gridX && + y==iter->first->cell->data.gridY) + break; + + ++iter; + } + + if (iter==mActiveCells.end()) + { + mExteriors[std::make_pair (x, y)].loadExt (x, y, mStore, mEsm); + Ptr::CellStore *cell = &mExteriors[std::make_pair (x, y)]; + + loadCell (cell, new MWRender::ExteriorCellRender (*cell, mEnvironment, mScene)); + } + } + + // find current cell + CellRenderCollection::iterator iter = mActiveCells.begin(); + + while (iter!=mActiveCells.end()) + { + assert (!(iter->first->cell->data.flags & ESM::Cell::Interior)); + + if (X==iter->first->cell->data.gridX && + Y==iter->first->cell->data.gridY) + break; + + ++iter; + } + + assert (iter!=mActiveCells.end()); + + mCurrentCell = iter->first; + + // adjust player + playerCellChange (&mExteriors[std::make_pair (X, Y)], position, adjustPlayerPos); + + // Sky system + adjustSky(); + + mCellChanged = true; + } + World::World (OEngine::Render::OgreRenderer& renderer, const boost::filesystem::path& dataDir, - const std::string& master, const boost::filesystem::path& resDir, bool newGame, Environment& environment) + const std::string& master, const boost::filesystem::path& resDir, + bool newGame, Environment& environment) : mSkyManager (0), mScene (renderer), mPlayer (0), mCurrentCell (0), mGlobalVariables (0), mSky (false), mCellChanged (false), mEnvironment (environment) { @@ -331,6 +423,7 @@ namespace MWWorld mStore.load (mEsm); mPlayer = new MWWorld::Player (mScene.getPlayer(), mStore.npcs.find ("player"), *this); + mScene.addActor (mPlayer->getPlayer().getRefData().getHandle(), "", Ogre::Vector3 (0, 0, 0)); // global variables mGlobalVariables = new Globals (mStore); @@ -418,7 +511,8 @@ namespace MWWorld Ptr World::getPtrViaHandle (const std::string& handle) { - // TODO player + if (mPlayer->getPlayer().getRefData().getHandle()==handle) + return mPlayer->getPlayer(); for (CellRenderCollection::iterator iter (mActiveCells.begin()); iter!=mActiveCells.end(); ++iter) @@ -587,8 +681,10 @@ namespace MWWorld return mGlobalVariables->getInt ("timescale"); } - void World::changeCell (const std::string& cellName, const ESM::Position& position) + void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { + SuppressDoingPhysics scopeGuard; + // remove active CellRenderCollection::iterator active = mActiveCells.begin(); @@ -614,89 +710,14 @@ namespace MWWorld //currentRegion->name = ""; } - void World::changeCell (int X, int Y, const ESM::Position& position) - { - // remove active - CellRenderCollection::iterator active = mActiveCells.begin(); - - while (active!=mActiveCells.end()) - { - if (!(active->first->cell->data.flags & ESM::Cell::Interior)) - { - if (std::abs (X-active->first->cell->data.gridX)<=1 && - std::abs (Y-active->first->cell->data.gridY)<=1) - { - // keep cells within the new 3x3 grid - ++active; - continue; - } - } - - unloadCell (active++); - } - - // Load cells - for (int x=X-1; x<=X+1; ++x) - for (int y=Y-1; y<=Y+1; ++y) - { - CellRenderCollection::iterator iter = mActiveCells.begin(); - - while (iter!=mActiveCells.end()) - { - assert (!(iter->first->cell->data.flags & ESM::Cell::Interior)); - - if (x==iter->first->cell->data.gridX && - y==iter->first->cell->data.gridY) - break; - - ++iter; - } - - if (iter==mActiveCells.end()) - { - mExteriors[std::make_pair (x, y)].loadExt (x, y, mStore, mEsm); - Ptr::CellStore *cell = &mExteriors[std::make_pair (x, y)]; - - loadCell (cell, new MWRender::ExteriorCellRender (*cell, mEnvironment, mScene)); - } - } - - // find current cell - CellRenderCollection::iterator iter = mActiveCells.begin(); - - while (iter!=mActiveCells.end()) - { - assert (!(iter->first->cell->data.flags & ESM::Cell::Interior)); - - if (X==iter->first->cell->data.gridX && - Y==iter->first->cell->data.gridY) - break; - - ++iter; - } - - assert (iter!=mActiveCells.end()); - - mCurrentCell = iter->first; - - // adjust player - playerCellChange (&mExteriors[std::make_pair (X, Y)], position); - - // Sky system - adjustSky(); - - mCellChanged = true; - } - - - void World::changeToExteriorCell (const ESM::Position& position) + void World::changeToExteriorCell (const ESM::Position& position) { int x = 0; int y = 0; positionToIndex (position.pos[0], position.pos[1], x, y); - changeCell (x, y, position); + changeCell (x, y, position, true); } const ESM::Cell *World::getExterior (const std::string& cellName) const @@ -722,6 +743,7 @@ namespace MWWorld return 0; } + void World::markCellAsUnchanged() { mCellChanged = false; @@ -781,15 +803,16 @@ namespace MWWorld if (mCurrentCell->cell->data.gridX!=cellX || mCurrentCell->cell->data.gridY!=cellY) { - changeCell (cellX, cellY, mPlayer->getPlayer().getCellRef().pos); - - if (!DoingPhysics::isDoingPhysics()) - mScene.moveObject (ptr.getRefData().getHandle(), Ogre::Vector3 (x, y, z)); + changeCell (cellX, cellY, mPlayer->getPlayer().getCellRef().pos, false); } + } } } + mScene.moveObject (ptr.getRefData().getHandle(), Ogre::Vector3 (x, y, z), + !DoingPhysics::isDoingPhysics()); + // TODO cell change for non-player ref } @@ -821,4 +844,10 @@ namespace MWWorld if (y<0) --cellY; } + + void World::doPhysics (const std::vector >& actors, + float duration) + { + mScene.doPhysics (duration, *this, actors); + } } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index ce66a63d7e..15b6df233b 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -14,6 +14,11 @@ #include "ptr.hpp" #include "globals.hpp" +namespace Ogre +{ + class Vector3; +} + namespace ESM { struct Position; @@ -83,14 +88,19 @@ namespace MWWorld void loadCell (Ptr::CellStore *cell, MWRender::CellRender *render); - void playerCellChange (Ptr::CellStore *cell, const ESM::Position& position); + void playerCellChange (Ptr::CellStore *cell, const ESM::Position& position, + bool adjustPlayerPos = true); void adjustSky(); + void changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos); + ///< Move from exterior to interior or from interior cell to a different + /// interior cell. public: World (OEngine::Render::OgreRenderer& renderer, const boost::filesystem::path& dataDir, - const std::string& master, const boost::filesystem::path& resDir, bool newGame, Environment& environment); + const std::string& master, const boost::filesystem::path& resDir, bool newGame, + Environment& environment); ~World(); @@ -138,12 +148,11 @@ namespace MWWorld float getTimeScaleFactor() const; - void changeCell (const std::string& cellName, const ESM::Position& position); - ///< works only for interior cells currently. - - void changeCell (int X, int Y, const ESM::Position& position); + void changeToInteriorCell (const std::string& cellName, const ESM::Position& position); + ///< Move to interior cell. void changeToExteriorCell (const ESM::Position& position); + ///< Move to exterior cell. const ESM::Cell *getExterior (const std::string& cellName) const; ///< Return a cell matching the given name or a 0-pointer, if there is no such cell. @@ -162,6 +171,10 @@ namespace MWWorld void positionToIndex (float x, float y, int &cellX, int &cellY) const; ///< Convert position to cell numbers + + void doPhysics (const std::vector >& actors, + float duration); + ///< Run physics simulation and modify \a world accordingly. }; } diff --git a/components/esm_store/cell_store.hpp b/components/esm_store/cell_store.hpp index 6acd81dcec..43860dff38 100644 --- a/components/esm_store/cell_store.hpp +++ b/components/esm_store/cell_store.hpp @@ -133,7 +133,48 @@ namespace ESMS loadRefs(store, esm); } + /// Call functor (ref) for each reference. functor must return a bool. Returning + /// false will abort the iteration. + /// \return Iteration completed? + template + bool forEach (Functor& functor) + { + return + forEachImp (functor, activators) && + forEachImp (functor, potions) && + forEachImp (functor, appas) && + forEachImp (functor, armors) && + forEachImp (functor, books) && + forEachImp (functor, clothes) && + forEachImp (functor, containers) && + forEachImp (functor, creatures) && + forEachImp (functor, doors) && + forEachImp (functor, ingreds) && + forEachImp (functor, creatureLists) && + forEachImp (functor, itemLists) && + forEachImp (functor, lights) && + forEachImp (functor, lockpicks) && + forEachImp (functor, miscItems) && + forEachImp (functor, npcs) && + forEachImp (functor, probes) && + forEachImp (functor, repairs) && + forEachImp (functor, statics) && + forEachImp (functor, weapons); + } + private: + + template + bool forEachImp (Functor& functor, List& list) + { + for (typename List::List::iterator iter (list.list.begin()); iter!=list.list.end(); + ++iter) + if (!functor (iter->ref, iter->mData)) + return false; + + return true; + } + void loadRefs(const ESMStore &store, ESMReader &esm) { assert (cell);