diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index bce3f516e..58fa221e6 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -177,7 +177,7 @@ namespace MWBase virtual void changeCell(MWWorld::CellStore* cell) = 0; ///< change the active cell - virtual void setPlayerPos(const float x, const float y) = 0; + virtual void setPlayerPos(int cellX, int cellY, const float x, const float y) = 0; ///< set player position in map space virtual void setPlayerDir(const float x, const float y) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 2055aeeae..73fa92529 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -119,6 +119,7 @@ namespace MWBase virtual void setWaterHeight(const float height) = 0; virtual bool toggleWater() = 0; + virtual bool toggleWorld() = 0; virtual void adjustSky() = 0; @@ -136,7 +137,7 @@ namespace MWBase virtual MWWorld::LocalScripts& getLocalScripts() = 0; virtual bool hasCellChanged() const = 0; - ///< Has the player moved to a different cell, since the last frame? + ///< Has the set of active cells changed, since the last frame? virtual bool isCellExterior() const = 0; diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 4139a7d24..0bcd5062d 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -490,7 +490,7 @@ namespace unsigned int & page = mStates.top ().mPage; Book book = mStates.top ().mBook; - if (page < book->pageCount () - 2) + if (page+2 < book->pageCount()) { page += 2; updateShowingPages (); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 37bc4d1e3..80a3c5ae4 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -159,8 +159,6 @@ namespace MWGui , mLocalMap(NULL) , mPrefix() , mChanged(true) - , mLastPositionX(0.0f) - , mLastPositionY(0.0f) , mLastDirectionX(0.0f) , mLastDirectionY(0.0f) , mCompass(NULL) @@ -425,24 +423,24 @@ namespace MWGui mLocalMap->getParent()->_updateChilds(); } - void LocalMapBase::setPlayerPos(const float x, const float y) + void LocalMapBase::setPlayerPos(int cellX, int cellY, const float nx, const float ny) { updateMagicMarkers(); - if (x == mLastPositionX && y == mLastPositionY) - return; - notifyPlayerUpdate (); - MyGUI::IntSize size = mLocalMap->getCanvasSize(); - MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); - MyGUI::IntCoord viewsize = mLocalMap->getCoord(); - MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); - mLocalMap->setViewOffset(pos); + MyGUI::IntPoint pos(widgetSize+nx*widgetSize-16, widgetSize+ny*widgetSize-16); + pos.left += (cellX - mCurX) * widgetSize; + pos.top -= (cellY - mCurY) * widgetSize; - mCompass->setPosition(MyGUI::IntPoint(widgetSize+x*widgetSize-16, widgetSize+y*widgetSize-16)); - mLastPositionX = x; - mLastPositionY = y; + if (pos != mCompass->getPosition()) + { + mCompass->setPosition(pos); + MyGUI::IntPoint middle (pos.left+16, pos.top+16); + MyGUI::IntCoord viewsize = mLocalMap->getCoord(); + MyGUI::IntPoint viewOffset(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); + mLocalMap->setViewOffset(viewOffset); + } } void LocalMapBase::setPlayerDir(const float x, const float y) diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index e9c0c1a69..a8aaa8e45 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -75,7 +75,7 @@ namespace MWGui void setCellPrefix(const std::string& prefix); void setActiveCell(const int x, const int y, bool interior=false); void setPlayerDir(const float x, const float y); - void setPlayerPos(const float x, const float y); + void setPlayerPos(int cellX, int cellY, const float nx, const float ny); void onFrame(float dt); @@ -129,8 +129,6 @@ namespace MWGui float mMarkerUpdateTimer; - float mLastPositionX; - float mLastPositionY; float mLastDirectionX; float mLastDirectionY; }; diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 80f38ba40..d4520aad7 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -157,12 +157,11 @@ namespace MWGui , mMaxTime(0) { // defines - mBottomPadding = 20; - mNextBoxPadding = 20; + mBottomPadding = 48; + mNextBoxPadding = 4; getWidget(mMessageWidget, "message"); - mMessageWidget->setOverflowToTheLeft(true); mMessageWidget->setCaptionWithReplacing(mMessage); } @@ -178,7 +177,7 @@ namespace MWGui int MessageBox::getHeight () { - return mMainWidget->getHeight()+mNextBoxPadding; // 20 is the padding between this and the next MessageBox + return mMainWidget->getHeight()+mNextBoxPadding; } @@ -204,7 +203,6 @@ namespace MWGui getWidget(mMessageWidget, "message"); getWidget(mButtonsWidget, "buttons"); - mMessageWidget->setOverflowToTheLeft(true); mMessageWidget->setSize(400, mMessageWidget->getHeight()); mMessageWidget->setCaptionWithReplacing(message); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index e3bec3789..2bfc4f141 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -41,12 +41,11 @@ namespace MWGui getWidget(mHeadRotate, "HeadRotate"); - // Mouse wheel step is hardcoded to 50 in MyGUI 3.2 ("FIXME"). - // Give other steps the same value to accomodate. mHeadRotate->setScrollRange(1000); mHeadRotate->setScrollPosition(500); mHeadRotate->setScrollViewPage(50); mHeadRotate->setScrollPage(50); + mHeadRotate->setScrollWheelPage(50); mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate); // Set up next/previous buttons diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index cd378aadf..dd6339b4c 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -100,6 +100,15 @@ namespace MWGui if (spell->mData.mType!=ESM::Spell::ST_Spell) continue; // don't try to sell diseases, curses or powers + if (actor.getClass().isNpc()) + { + const ESM::Race* race = + MWBase::Environment::get().getWorld()->getStore().get().find( + actor.get()->mBase->mRace); + if (race->mPowers.exists(spell->mId)) + continue; + } + if (playerHasSpell(iter->first)) continue; diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 1116d6543..e2fac9d6d 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -422,12 +422,12 @@ namespace MWGui y *= 1.5; } - mSpell.mData.mCost = int(y); - ESM::EffectList effectList; effectList.mList = mEffects; mSpell.mEffects = effectList; + mSpell.mData.mCost = int(y); mSpell.mData.mType = ESM::Spell::ST_Spell; + mSpell.mData.mFlags = 0; mMagickaCost->setCaption(boost::lexical_cast(int(y))); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 70f4b5a2f..16295d3a5 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -880,9 +880,6 @@ namespace MWGui mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->getCell()->getGridX (), cell->getCell()->getGridY ()); mMap->cellExplored (cell->getCell()->getGridX(), cell->getCell()->getGridY()); - - mMap->setCellPrefix("Cell"); - mHud->setCellPrefix("Cell"); } else { @@ -900,14 +897,20 @@ namespace MWGui void WindowManager::setActiveMap(int x, int y, bool interior) { + if (!interior) + { + mMap->setCellPrefix("Cell"); + mHud->setCellPrefix("Cell"); + } + mMap->setActiveCell(x,y, interior); mHud->setActiveCell(x,y, interior); } - void WindowManager::setPlayerPos(const float x, const float y) + void WindowManager::setPlayerPos(int cellX, int cellY, const float x, const float y) { - mMap->setPlayerPos(x,y); - mHud->setPlayerPos(x,y); + mMap->setPlayerPos(cellX, cellY, x, y); + mHud->setPlayerPos(cellX, cellY, x, y); } void WindowManager::setPlayerDir(const float x, const float y) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 29d40c2e7..1dae77641 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -183,7 +183,7 @@ namespace MWGui virtual void updateSkillArea(); ///< update display of skills, factions, birth sign, reputation and bounty virtual void changeCell(MWWorld::CellStore* cell); ///< change the active cell - virtual void setPlayerPos(const float x, const float y); ///< set player position in map space + virtual void setPlayerPos(int cellX, int cellY, const float x, const float y); ///< set player position in map space virtual void setPlayerDir(const float x, const float y); ///< set player view direction in map space virtual void setFocusObject(const MWWorld::Ptr& focus); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 3cd30819c..10cd34749 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -936,9 +936,11 @@ namespace MWInput { clearAllBindings (control); - if (defaultKeyBindings.find(i) != defaultKeyBindings.end()) + if (defaultKeyBindings.find(i) != defaultKeyBindings.end() + && !mInputBinder->isKeyBound(defaultKeyBindings[i])) mInputBinder->addKeyBinding(control, defaultKeyBindings[i], ICS::Control::INCREASE); - else if (defaultMouseButtonBindings.find(i) != defaultMouseButtonBindings.end()) + else if (defaultMouseButtonBindings.find(i) != defaultMouseButtonBindings.end() + && !mInputBinder->isMouseButtonBound(defaultMouseButtonBindings[i])) mInputBinder->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a5063594a..82f60221b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1122,20 +1122,21 @@ namespace MWMechanics int hostilesCount = 0; // need to know this to play Battle music + // AI processing is only done within distance of 7168 units to the player. Note the "AI distance" slider doesn't affect this + // (it only does some throttling for targets beyond the "AI distance", so doesn't give any guarantees as to whether AI will be enabled or not) + // This distance could be made configurable later, but the setting must be marked with a big warning: + // using higher values will make a quest in Bloodmoon harder or impossible to complete (bug #1876) + const float sqrProcessingDistance = 7168*7168; + // AI and magic effects update for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) { updateActor(iter->first, duration); - - // AI processing is only done within distance of 7168 units to the player. Note the "AI distance" slider doesn't affect this - // (it only does some throttling for targets beyond the "AI distance", so doesn't give any guarantees as to whether AI will be enabled or not) - // This distance could be made configurable later, but the setting must be marked with a big warning: - // using higher values will make a quest in Bloodmoon harder or impossible to complete (bug #1876) if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos)) - <= 7168*7168) + <= sqrProcessingDistance) { if (timerUpdateAITargets == 0) { @@ -1182,6 +1183,11 @@ namespace MWMechanics CharacterController* playerCharacter = NULL; for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { + if (iter->first != player && + Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos)) + > sqrProcessingDistance) + continue; + if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get( ESM::MagicEffect::Paralyze).getMagnitude() > 0) iter->second->skipAnim(); diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 0341c9745..f28809d4f 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -260,15 +260,14 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) for(std::list::iterator it = mPackages.begin(); it != mPackages.end(); ++it) { - if(mPackages.front()->getPriority() <= package.getPriority()) + if((*it)->getPriority() <= package.getPriority()) { mPackages.insert(it,package.clone()); return; } } - if(mPackages.empty()) - mPackages.push_front (package.clone()); + mPackages.push_front (package.clone()); } AiPackage* MWMechanics::AiSequence::getActivePackage() diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 24e7b5aa1..90c180817 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -133,7 +133,7 @@ void MWMechanics::Alchemy::updateEffects() std::set effects (listEffects()); // general alchemy factor - float x = getChance(); + float x = getAlchemyFactor(); x *= mTools[ESM::Apparatus::MortarPestle].get()->mBase->mData.mQuality; x *= MWBase::Environment::get().getWorld()->getStore().get().find ("fPotionStrengthMult")->getFloat(); @@ -306,18 +306,15 @@ void MWMechanics::Alchemy::increaseSkill() mAlchemist.getClass().skillUsageSucceeded (mAlchemist, ESM::Skill::Alchemy, 0); } -float MWMechanics::Alchemy::getChance() const +float MWMechanics::Alchemy::getAlchemyFactor() const { const CreatureStats& creatureStats = mAlchemist.getClass().getCreatureStats (mAlchemist); const NpcStats& npcStats = mAlchemist.getClass().getNpcStats (mAlchemist); - if (beginEffects() == endEffects()) - return 0.f; - return (npcStats.getSkill (ESM::Skill::Alchemy).getModified() + - 0.1 * creatureStats.getAttribute (1).getModified() - + 0.1 * creatureStats.getAttribute (7).getModified()); + 0.1 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified() + + 0.1 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()); } int MWMechanics::Alchemy::countIngredients() const @@ -461,7 +458,14 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na if (listEffects().empty()) return Result_NoEffects; - if (getChance() (RAND_MAX)*100) + if (beginEffects() == endEffects()) + { + // all effects were nullified due to insufficient skill + removeIngredients(); + return Result_RandomFailure; + } + + if (getAlchemyFactor() (RAND_MAX)*100) { removeIngredients(); return Result_RandomFailure; diff --git a/apps/openmw/mwmechanics/alchemy.hpp b/apps/openmw/mwmechanics/alchemy.hpp index a2429ca8e..e6b8c6650 100644 --- a/apps/openmw/mwmechanics/alchemy.hpp +++ b/apps/openmw/mwmechanics/alchemy.hpp @@ -69,8 +69,7 @@ namespace MWMechanics void increaseSkill(); ///< Increase alchemist's skill. - float getChance() const; - ///< Return chance of success. + float getAlchemyFactor() const; int countIngredients() const; diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index 01447c6e4..7b8c43a06 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -72,7 +72,7 @@ namespace MWMechanics if (baseMagicka < iAutoSpellTimesCanCast * spell->mData.mCost) continue; - if (race && std::find(race->mPowers.mList.begin(), race->mPowers.mList.end(), spell->mId) != race->mPowers.mList.end()) + if (race && race->mPowers.exists(spell->mId)) continue; if (!attrSkillCheck(spell, actorSkills, actorAttributes)) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 63ffbc7e8..c134942b8 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -53,6 +53,9 @@ namespace MWMechanics MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); ESM::Enchantment enchantment; enchantment.mData.mCharge = getGemCharge(); + enchantment.mData.mAutocalc = 0; + enchantment.mData.mType = mCastStyle; + enchantment.mData.mCost = getEnchantPoints(); store.remove(mSoulGemPtr, 1, player); @@ -72,8 +75,6 @@ namespace MWMechanics { enchantment.mData.mCharge=0; } - enchantment.mData.mType = mCastStyle; - enchantment.mData.mCost = getEnchantPoints(); enchantment.mEffects = mEffectList; // Apply the enchantment diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index bb196f282..1850df904 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -19,6 +19,7 @@ namespace MWRender Camera::Camera (Ogre::Camera *camera) : mCamera(camera), mCameraNode(NULL), + mCameraPosNode(NULL), mAnimation(NULL), mFirstPersonView(true), mPreviewMode(false), @@ -26,8 +27,8 @@ namespace MWRender mNearest(30.f), mFurthest(800.f), mIsNearest(false), - mHeight(128.f), - mCameraDistance(300.f), + mHeight(124.f), + mCameraDistance(192.f), mDistanceAdjusted(false), mVanityToggleQueued(false), mViewModeToggleQueued(false) @@ -66,12 +67,16 @@ namespace MWRender } Ogre::Quaternion xr(Ogre::Radian(getPitch() + Ogre::Math::HALF_PI), Ogre::Vector3::UNIT_X); - if (!mVanity.enabled && !mPreviewMode) { - mCamera->getParentNode()->setOrientation(xr); - } else { + Ogre::Quaternion orient = xr; + if (mVanity.enabled || mPreviewMode) { Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::UNIT_Z); - mCamera->getParentNode()->setOrientation(zr * xr); + orient = zr * xr; } + + if (isFirstPerson()) + mCamera->getParentNode()->setOrientation(orient); + else + mCameraNode->setOrientation(orient); } const std::string &Camera::getHandle() const @@ -79,20 +84,40 @@ namespace MWRender return mTrackingPtr.getRefData().getHandle(); } - void Camera::attachTo(const MWWorld::Ptr &ptr) + Ogre::SceneNode* Camera::attachTo(const MWWorld::Ptr &ptr) { mTrackingPtr = ptr; Ogre::SceneNode *node = mTrackingPtr.getRefData().getBaseNode()->createChildSceneNode(Ogre::Vector3(0.0f, 0.0f, mHeight)); + node->setInheritScale(false); + Ogre::SceneNode *posNode = node->createChildSceneNode(); + posNode->setInheritScale(false); if(mCameraNode) { node->setOrientation(mCameraNode->getOrientation()); - node->setPosition(mCameraNode->getPosition()); - node->setScale(mCameraNode->getScale()); + posNode->setPosition(mCameraPosNode->getPosition()); mCameraNode->getCreator()->destroySceneNode(mCameraNode); + mCameraNode->getCreator()->destroySceneNode(mCameraPosNode); } mCameraNode = node; - if(!mCamera->isAttached()) - mCameraNode->attachObject(mCamera); + mCameraPosNode = posNode; + + if (!isFirstPerson()) + { + mCamera->detachFromParent(); + mCameraPosNode->attachObject(mCamera); + } + + return mCameraPosNode; + } + + void Camera::setPosition(const Ogre::Vector3& position) + { + mCameraPosNode->setPosition(position); + } + + void Camera::setPosition(float x, float y, float z) + { + setPosition(Ogre::Vector3(x,y,z)); } void Camera::updateListener() @@ -155,9 +180,9 @@ namespace MWRender processViewChange(); if (mFirstPersonView) { - mCamera->setPosition(0.f, 0.f, 0.f); + setPosition(0.f, 0.f, 0.f); } else { - mCamera->setPosition(0.f, 0.f, mCameraDistance); + setPosition(0.f, 0.f, mCameraDistance); } } @@ -172,7 +197,7 @@ namespace MWRender { // Changing the view will stop all playing animations, so if we are playing // anything important, queue the view change for later - if (!mPreviewMode) + if (isFirstPerson() && !mAnimation->upperBodyReady()) { mVanityToggleQueued = true; return false; @@ -191,14 +216,14 @@ namespace MWRender Ogre::Vector3 rot(0.f, 0.f, 0.f); if (mVanity.enabled) { rot.x = Ogre::Degree(-30.f).valueRadians(); - mMainCam.offset = mCamera->getPosition().z; + mMainCam.offset = mCameraPosNode->getPosition().z; } else { rot.x = getPitch(); offset = mMainCam.offset; } rot.z = getYaw(); - mCamera->setPosition(0.f, 0.f, offset); + setPosition(0.f, 0.f, offset); rotateCamera(rot, false); return true; @@ -215,7 +240,7 @@ namespace MWRender mPreviewMode = enable; processViewChange(); - float offset = mCamera->getPosition().z; + float offset = mCameraPosNode->getPosition().z; if (mPreviewMode) { mMainCam.offset = offset; offset = mPreviewCam.offset; @@ -224,7 +249,7 @@ namespace MWRender offset = mMainCam.offset; } - mCamera->setPosition(0.f, 0.f, offset); + setPosition(0.f, 0.f, offset); } void Camera::setSneakOffset(float offset) @@ -283,7 +308,7 @@ namespace MWRender float Camera::getCameraDistance() const { - return mCamera->getPosition().z; + return mCameraPosNode->getPosition().z; } void Camera::setCameraDistance(float dist, bool adjust, bool override) @@ -295,7 +320,7 @@ namespace MWRender Ogre::Vector3 v(0.f, 0.f, dist); if (adjust) { - v += mCamera->getPosition(); + v += mCameraPosNode->getPosition(); } if (v.z >= mFurthest) { v.z = mFurthest; @@ -305,7 +330,7 @@ namespace MWRender v.z = mNearest; mIsNearest = true; } - mCamera->setPosition(v); + setPosition(v); if (override) { if (mVanity.enabled || mPreviewMode) { @@ -322,9 +347,9 @@ namespace MWRender { if (mDistanceAdjusted) { if (mVanity.enabled || mPreviewMode) { - mCamera->setPosition(0, 0, mPreviewCam.offset); + setPosition(0, 0, mPreviewCam.offset); } else if (!mFirstPersonView) { - mCamera->setPosition(0, 0, mCameraDistance); + setPosition(0, 0, mCameraDistance); } } mDistanceAdjusted = false; @@ -355,10 +380,10 @@ namespace MWRender Ogre::TagPoint *tag = mAnimation->attachObjectToBone("Head", mCamera); tag->setInheritOrientation(false); } - else + else { mAnimation->setViewMode(NpcAnimation::VM_Normal); - mCameraNode->attachObject(mCamera); + mCameraPosNode->attachObject(mCamera); } rotateCamera(Ogre::Vector3(getPitch(), 0.f, getYaw()), false); } @@ -368,8 +393,7 @@ namespace MWRender mCamera->getParentSceneNode()->needUpdate(true); camera = mCamera->getRealPosition(); - focal = Ogre::Vector3((mCamera->getParentNode()->_getFullTransform() * - Ogre::Vector4(0.0f, 0.0f, 0.0f, 1.0f)).ptr()); + focal = mCameraNode->_getDerivedPosition(); } void Camera::togglePlayerLooking(bool enable) diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index f7b0ae6e8..c542dc96c 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -27,6 +27,7 @@ namespace MWRender Ogre::Camera *mCamera; Ogre::SceneNode *mCameraNode; + Ogre::SceneNode *mCameraPosNode; NpcAnimation *mAnimation; @@ -52,6 +53,9 @@ namespace MWRender /// Updates sound manager listener data void updateListener(); + void setPosition(const Ogre::Vector3& position); + void setPosition(float x, float y, float z); + public: Camera(Ogre::Camera *camera); ~Camera(); @@ -72,7 +76,7 @@ namespace MWRender const std::string &getHandle() const; /// Attach camera to object - void attachTo(const MWWorld::Ptr &); + Ogre::SceneNode* attachTo(const MWWorld::Ptr &); /// @param Force view mode switch, even if currently not allowed by the animation. void toggleViewMode(bool force=false); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 85f73ab7e..f4388eec5 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -25,7 +25,7 @@ using namespace MWRender; using namespace Ogre; LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManager* rendering) : - mInterior(false), mCellX(0), mCellY(0) + mInterior(false) { mRendering = rend; mRenderingManager = rendering; @@ -522,10 +522,9 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni { x = std::ceil(pos.x / sSize)-1; y = std::ceil(pos.y / sSize)-1; - mCellX = x; - mCellY = y; } - MWBase::Environment::get().getWindowManager()->setActiveMap(x,y,mInterior); + else + MWBase::Environment::get().getWindowManager()->setActiveMap(x,y,mInterior); // convert from world coordinates to texture UV coordinates std::string texBaseName; @@ -540,7 +539,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni texBaseName = mInteriorName + "_"; } - MWBase::Environment::get().getWindowManager()->setPlayerPos(u, v); + MWBase::Environment::get().getWindowManager()->setPlayerPos(x, y, u, v); MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, playerdirection.y); // explore radius (squared) diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index b531c3e29..4c60cbb11 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -134,7 +134,6 @@ namespace MWRender Ogre::RenderTarget* mRenderTarget; bool mInterior; - int mCellX, mCellY; Ogre::AxisAlignedBox mBounds; std::string mInteriorName; }; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4512bbbeb..6ed11b71f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -63,6 +63,7 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b , mPhysicsEngine(engine) , mTerrain(NULL) , mEffectManager(NULL) + , mRenderWorld(true) { mActors = new MWRender::Actors(mRendering, this); mObjects = new MWRender::Objects(mRendering); @@ -232,6 +233,15 @@ bool RenderingManager::toggleWater() return mWater->toggle(); } +bool RenderingManager::toggleWorld() +{ + mRenderWorld = !mRenderWorld; + + int visibilityMask = mRenderWorld ? ~int(0) : 0; + mRendering.getViewport()->setVisibilityMask(visibilityMask); + return mRenderWorld; +} + void RenderingManager::cellAdded (MWWorld::CellStore *store) { if (store->isExterior()) @@ -302,7 +312,7 @@ void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) if(mPlayerAnimation) mPlayerAnimation->updatePtr(ptr); if(mCamera->getHandle() == ptr.getRefData().getHandle()) - mCamera->attachTo(ptr); + attachCameraTo(ptr); } void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) @@ -317,7 +327,7 @@ void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) anim->rebuild(); if(mCamera->getHandle() == ptr.getRefData().getHandle()) { - mCamera->attachTo(ptr); + attachCameraTo(ptr); mCamera->setAnimation(anim); } } @@ -489,7 +499,7 @@ bool RenderingManager::toggleRenderMode(int mode) } } -void RenderingManager::configureFog(MWWorld::CellStore &mCell) +void RenderingManager::configureFog(const MWWorld::CellStore &mCell) { Ogre::ColourValue color; color.setAsABGR (mCell.getCell()->mAmbi.mFog); @@ -500,7 +510,7 @@ void RenderingManager::configureFog(MWWorld::CellStore &mCell) void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour) { mFogColour = colour; - float max = Settings::Manager::getFloat("max viewing distance", "Viewing distance"); + float max = Settings::Manager::getFloat("viewing distance", "Viewing distance"); if (density == 0) { @@ -732,7 +742,7 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec { setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } - else if (it->second == "max viewing distance" && it->first == "Viewing distance") + else if (it->second == "viewing distance" && it->first == "Viewing distance") { if (!MWBase::Environment::get().getWorld()->isCellExterior() && !MWBase::Environment::get().getWorld()->isCellQuasiExterior() && MWBase::Environment::get().getWorld()->getPlayerPtr().mCell) @@ -859,7 +869,13 @@ void RenderingManager::getTriangleBatchCount(unsigned int &triangles, unsigned i void RenderingManager::setupPlayer(const MWWorld::Ptr &ptr) { ptr.getRefData().setBaseNode(mRendering.getScene()->getSceneNode("player")); - mCamera->attachTo(ptr); + attachCameraTo(ptr); +} + +void RenderingManager::attachCameraTo(const MWWorld::Ptr &ptr) +{ + Ogre::SceneNode* cameraNode = mCamera->attachTo(ptr); + mSkyManager->attachToNode(cameraNode); } void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 43d22d5ca..2da084074 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -123,6 +123,7 @@ public: void setWaterHeight(const float height); bool toggleWater(); + bool toggleWorld(); /// Updates object rendering after cell change /// \param old Object reference in previous cell @@ -182,7 +183,7 @@ public: ///< request the local map for a cell /// configure fog according to cell - void configureFog(MWWorld::CellStore &mCell); + void configureFog(const MWWorld::CellStore &mCell); /// configure fog manually void configureFog(const float density, const Ogre::ColourValue& colour); @@ -220,6 +221,8 @@ private: void setAmbientMode(); void applyFog(bool underwater); + void attachCameraTo(const MWWorld::Ptr& ptr); + void setMenuTransparency(float val); bool mSunEnabled; @@ -266,6 +269,8 @@ private: MWRender::LocalMap* mLocalMap; MWRender::Shadows* mShadows; + + bool mRenderWorld; }; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 4620173b5..8e7bd3d89 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -382,9 +382,7 @@ void SkyManager::clearRain() for (std::map::iterator it = mRainModels.begin(); it != mRainModels.end();) { it->second.setNull(); - Ogre::SceneNode* parent = it->first->getParentSceneNode(); mSceneMgr->destroySceneNode(it->first); - mSceneMgr->destroySceneNode(parent); mRainModels.erase(it++); } } @@ -402,9 +400,7 @@ void SkyManager::updateRain(float dt) if (pos.z < -minHeight) { it->second.setNull(); - Ogre::SceneNode* parent = it->first->getParentSceneNode(); mSceneMgr->destroySceneNode(it->first); - mSceneMgr->destroySceneNode(parent); mRainModels.erase(it++); } else @@ -420,17 +416,20 @@ void SkyManager::updateRain(float dt) { mRainTimer = 0; + // TODO: handle rain settings from Morrowind.ini const float rangeRandom = 100; float xOffs = (std::rand()/(RAND_MAX+1.0)) * rangeRandom - (rangeRandom/2); float yOffs = (std::rand()/(RAND_MAX+1.0)) * rangeRandom - (rangeRandom/2); - Ogre::SceneNode* sceneNode = mCamera->getParentSceneNode()->createChildSceneNode(); - sceneNode->setInheritOrientation(false); // Create a separate node to control the offset, since a node with setInheritOrientation(false) will still // consider the orientation of the parent node for its position, just not for its orientation float startHeight = 700; - Ogre::SceneNode* offsetNode = sceneNode->createChildSceneNode(Ogre::Vector3(xOffs,yOffs,startHeight)); + Ogre::SceneNode* offsetNode = mParticleNode->createChildSceneNode(Ogre::Vector3(xOffs,yOffs,startHeight)); + // Spawn a new rain object for each instance. + // TODO: this is inefficient. We could try to use an Ogre::ParticleSystem instead, but then we would need to make assumptions + // about the rain meshes being Quads and their dimensions. + // Or we could clone meshes into one vertex buffer manually. NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(offsetNode, mRainEffect); for (unsigned int i=0; imEntities.size(); ++i) { @@ -562,12 +561,6 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) } else { - if (!mParticleNode) - { - mParticleNode = mCamera->getParentSceneNode()->createChildSceneNode(); - mParticleNode->setInheritOrientation(false); - } - mParticle = NifOgre::Loader::createObjects(mParticleNode, mCurrentParticleEffect); for(size_t i = 0; i < mParticle->mParticles.size(); ++i) { @@ -783,3 +776,16 @@ void SkyManager::setGlareEnabled (bool enabled) return; mSunGlare->setVisible (mSunEnabled && enabled); } + +void SkyManager::attachToNode(SceneNode *sceneNode) +{ + if (!mParticleNode) + { + mParticleNode = sceneNode->createChildSceneNode(); + mParticleNode->setInheritOrientation(false); + } + else + { + sceneNode->addChild(mParticleNode); + } +} diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index e40eb1dce..0544f17ef 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -116,6 +116,9 @@ namespace MWRender SkyManager(Ogre::SceneNode* root, Ogre::Camera* pCamera); ~SkyManager(); + /// Attach weather particle effects to this scene node (should be the Camera's parent node) + void attachToNode(Ogre::SceneNode* sceneNode); + void update(float duration); void enable(); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 626332564..b80c84d67 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -432,5 +432,6 @@ op 0x20002ac-0x20002c3: SetMagicEffect, explicit op 0x20002c4-0x20002db: ModMagicEffect op 0x20002dc-0x20002f3: ModMagicEffect, explicit op 0x20002f4: ResetActors +op 0x20002f5: ToggleWorld -opcodes 0x20002f5-0x3ffffff unused +opcodes 0x20002f6-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index be8c85bbf..ef879a95a 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -290,6 +290,17 @@ namespace MWScript } }; + class OpToggleWorld : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + runtime.getContext().report(MWBase::Environment::get().getWorld()->toggleWorld() ? "World -> On" + : "World -> Off"); + } + }; + class OpDontSaveObject : public Interpreter::Opcode0 { public: @@ -979,6 +990,7 @@ namespace MWScript interpreter.installSegment5 (Compiler::Misc::opcodeFadeTo, new OpFadeTo); interpreter.installSegment5 (Compiler::Misc::opcodeTogglePathgrid, new OpTogglePathgrid); interpreter.installSegment5 (Compiler::Misc::opcodeToggleWater, new OpToggleWater); + interpreter.installSegment5 (Compiler::Misc::opcodeToggleWorld, new OpToggleWorld); interpreter.installSegment5 (Compiler::Misc::opcodeDontSaveObject, new OpDontSaveObject); interpreter.installSegment5 (Compiler::Misc::opcodeToggleVanityMode, new OpToggleVanityMode); interpreter.installSegment5 (Compiler::Misc::opcodeGetPcSleep, new OpGetPcSleep); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index a316f0bb2..c98485dc9 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -5,7 +5,7 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" /// FIXME +#include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" @@ -117,6 +117,28 @@ namespace MWWorld } } + void Scene::getGridCenter(int &cellX, int &cellY) + { + int maxX = std::numeric_limits().min(); + int maxY = std::numeric_limits().min(); + int minX = std::numeric_limits().max(); + int minY = std::numeric_limits().max(); + CellStoreCollection::iterator iter = mActiveCells.begin(); + while (iter!=mActiveCells.end()) + { + assert ((*iter)->getCell()->isExterior()); + int x = (*iter)->getCell()->getGridX(); + int y = (*iter)->getCell()->getGridY(); + maxX = std::max(x, maxX); + maxY = std::max(y, maxY); + minX = std::min(x, minX); + minY = std::min(y, minY); + ++iter; + } + cellX = (minX + maxX) / 2; + cellY = (minY + maxY) / 2; + } + void Scene::update (float duration, bool paused) { if (mNeedMapUpdate) @@ -126,6 +148,13 @@ namespace MWWorld for (CellStoreCollection::iterator active = mActiveCells.begin(); active!=mActiveCells.end(); ++active) mRendering.requestMap(*active); mNeedMapUpdate = false; + + if (mCurrentCell->isExterior()) + { + int cellX, cellY; + getGridCenter(cellX, cellY); + MWBase::Environment::get().getWindowManager()->setActiveMap(cellX,cellY,false); + } } mRendering.update (duration, paused); @@ -213,41 +242,6 @@ namespace MWWorld MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell); } - void Scene::playerCellChange(CellStore *cell, const ESM::Position& pos, bool adjustPlayerPos) - { - MWBase::World *world = MWBase::Environment::get().getWorld(); - MWWorld::Ptr old = world->getPlayerPtr(); - world->getPlayer().setCell(cell); - - MWWorld::Ptr player = world->getPlayerPtr(); - mRendering.updatePlayerPtr(player); - - if (adjustPlayerPos) { - world->moveObject(player, pos.pos[0], pos.pos[1], pos.pos[2]); - - float x = Ogre::Radian(pos.rot[0]).valueDegrees(); - float y = Ogre::Radian(pos.rot[1]).valueDegrees(); - float z = Ogre::Radian(pos.rot[2]).valueDegrees(); - world->rotateObject(player, x, y, z); - - player.getClass().adjustPosition(player, true); - } - - MWBase::MechanicsManager *mechMgr = - MWBase::Environment::get().getMechanicsManager(); - - mechMgr->updateCell(old, player); - mechMgr->watchActor(player); - - mRendering.updateTerrain(); - - // Delay the map update until scripts have been given a chance to run. - // If we don't do this, objects that should be disabled will still appear on the map. - mNeedMapUpdate = true; - - MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); - } - void Scene::changeToVoid() { CellStoreCollection::iterator active = mActiveCells.begin(); @@ -257,7 +251,28 @@ namespace MWWorld mCurrentCell = NULL; } - void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos) + void Scene::playerMoved(const Ogre::Vector3 &pos) + { + if (!mCurrentCell || !mCurrentCell->isExterior()) + return; + + // figure out the center of the current cell grid (*not* necessarily mCurrentCell, which is the cell the player is in) + int cellX, cellY; + getGridCenter(cellX, cellY); + float centerX, centerY; + MWBase::Environment::get().getWorld()->indexToPosition(cellX, cellY, centerX, centerY, true); + const float maxDistance = 8192/2 + 1024; // 1/2 cell size + threshold + float distance = std::max(std::abs(centerX-pos.x), std::abs(centerY-pos.y)); + if (distance > maxDistance) + { + int newX, newY; + MWBase::Environment::get().getWorld()->positionToIndex(pos.x, pos.y, newX, newY); + changeCellGrid(newX, newY); + mRendering.updateTerrain(); + } + } + + void Scene::changeCellGrid (int X, int Y) { Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); Loading::ScopedLoad load(loadingListener); @@ -286,6 +301,7 @@ namespace MWWorld int refsToLoad = 0; // get the number of refs to load for (int x=X-1; x<=X+1; ++x) + { for (int y=Y-1; y<=Y+1; ++y) { CellStoreCollection::iterator iter = mActiveCells.begin(); @@ -304,11 +320,13 @@ namespace MWWorld if (iter==mActiveCells.end()) refsToLoad += MWBase::Environment::get().getWorld()->getExterior(x, y)->count(); } + } loadingListener->setProgressRange(refsToLoad); // Load cells for (int x=X-1; x<=X+1; ++x) + { for (int y=Y-1; y<=Y+1; ++y) { CellStoreCollection::iterator iter = mActiveCells.begin(); @@ -331,32 +349,47 @@ namespace MWWorld loadCell (cell, loadingListener); } } + } - // find current cell - CellStoreCollection::iterator iter = mActiveCells.begin(); + CellStore* current = MWBase::Environment::get().getWorld()->getExterior(X,Y); + MWBase::Environment::get().getWindowManager()->changeCell(current); - while (iter!=mActiveCells.end()) - { - assert ((*iter)->getCell()->isExterior()); + mCellChanged = true; - if (X==(*iter)->getCell()->getGridX() && - Y==(*iter)->getCell()->getGridY()) - break; + // Delay the map update until scripts have been given a chance to run. + // If we don't do this, objects that should be disabled will still appear on the map. + mNeedMapUpdate = true; + } - ++iter; - } + void Scene::changePlayerCell(CellStore *cell, const ESM::Position &pos, bool adjustPlayerPos) + { + mCurrentCell = cell; - assert (iter!=mActiveCells.end()); + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr old = world->getPlayerPtr(); + world->getPlayer().setCell(cell); - mCurrentCell = *iter; + MWWorld::Ptr player = world->getPlayerPtr(); + mRendering.updatePlayerPtr(player); - // adjust player - playerCellChange (mCurrentCell, position, adjustPlayerPos); + if (adjustPlayerPos) { + world->moveObject(player, pos.pos[0], pos.pos[1], pos.pos[2]); - // Sky system - MWBase::Environment::get().getWorld()->adjustSky(); + float x = Ogre::Radian(pos.rot[0]).valueDegrees(); + float y = Ogre::Radian(pos.rot[1]).valueDegrees(); + float z = Ogre::Radian(pos.rot[2]).valueDegrees(); + world->rotateObject(player, x, y, z); - mCellChanged = true; + player.getClass().adjustPosition(player, true); + } + + MWBase::MechanicsManager *mechMgr = + MWBase::Environment::get().getMechanicsManager(); + + mechMgr->updateCell(old, player); + mechMgr->watchActor(player); + + MWBase::Environment::get().getWorld()->adjustSky(); } //We need the ogre renderer and a scene node. @@ -427,33 +460,39 @@ namespace MWWorld // Load cell. std::cout << "cellName: " << cell->getCell()->mName << std::endl; - //Loading Interior loading text - loadCell (cell, loadingListener); - mCurrentCell = cell; + changePlayerCell(cell, position, true); // adjust fog mRendering.configureFog(*mCurrentCell); - // adjust player - playerCellChange (mCurrentCell, position); - // Sky system MWBase::Environment::get().getWorld()->adjustSky(); mCellChanged = true; MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); + + MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); + + // Delay the map update until scripts have been given a chance to run. + // If we don't do this, objects that should be disabled will still appear on the map. + mNeedMapUpdate = true; } - void Scene::changeToExteriorCell (const ESM::Position& position) + void Scene::changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos) { int x = 0; int y = 0; MWBase::Environment::get().getWorld()->positionToIndex (position.pos[0], position.pos[1], x, y); - changeCell (x, y, position, true); + changeCellGrid(x, y); + + CellStore* current = MWBase::Environment::get().getWorld()->getExterior(x, y); + changePlayerCell(current, position, adjustPlayerPos); + + mRendering.updateTerrain(); } CellStore* Scene::getCurrentCell () diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index e0eeee187..a9d80bf17 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -60,11 +60,13 @@ namespace MWWorld bool mNeedMapUpdate; - void playerCellChange (CellStore *cell, const ESM::Position& position, - bool adjustPlayerPos = true); - void insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener); + // Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center + void changeCellGrid (int X, int Y); + + void getGridCenter(int& cellX, int& cellY); + public: Scene (MWRender::RenderingManager& rendering, PhysicsSystem *physics); @@ -75,19 +77,21 @@ namespace MWWorld void loadCell (CellStore *cell, Loading::Listener* loadingListener); - void changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos); + void playerMoved (const Ogre::Vector3& pos); + + void changePlayerCell (CellStore* newCell, const ESM::Position& position, bool adjustPlayerPos); - CellStore* getCurrentCell (); + CellStore *getCurrentCell(); const CellStoreCollection& getActiveCells () const; bool hasCellChanged() const; - ///< Has the player moved to a different cell, since the last frame? + ///< Has the set of active cells changed, since the last frame? void changeToInteriorCell (const std::string& cellName, const ESM::Position& position); ///< Move to interior cell. - void changeToExteriorCell (const ESM::Position& position); + void changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos); ///< Move to exterior cell. void changeToVoid(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index dd766eed1..cf8c11574 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -241,7 +241,7 @@ namespace MWWorld pos.rot[0] = 0; pos.rot[1] = 0; pos.rot[2] = 0; - mWorldScene->changeToExteriorCell(pos); + mWorldScene->changeToExteriorCell(pos, true); } } @@ -920,7 +920,7 @@ namespace MWWorld mRendering->notifyWorldSpaceChanged(); } removeContainerScripts(getPlayerPtr()); - mWorldScene->changeToExteriorCell(position); + mWorldScene->changeToExteriorCell(position, true); addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell()); } @@ -1057,9 +1057,10 @@ namespace MWWorld changeToInteriorCell(Misc::StringUtils::lowerCase(newCell->getCell()->mName), pos); else { - int cellX = newCell->getCell()->getGridX(); - int cellY = newCell->getCell()->getGridY(); - mWorldScene->changeCell(cellX, cellY, pos, false); + if (mWorldScene->isCellActive(*newCell)) + mWorldScene->changePlayerCell(newCell, pos, false); + else + mWorldScene->changeToExteriorCell(pos, false); } addContainerScripts (getPlayerPtr(), newCell); } @@ -1120,6 +1121,10 @@ namespace MWWorld mRendering->moveObject(ptr, vec); mPhysics->moveObject (ptr); } + if (isPlayer) + { + mWorldScene->playerMoved (vec); + } } bool World::moveObjectImp(const Ptr& ptr, float x, float y, float z) @@ -1565,7 +1570,7 @@ namespace MWWorld bool World::isCellExterior() const { - CellStore *currentCell = mWorldScene->getCurrentCell(); + const CellStore *currentCell = mWorldScene->getCurrentCell(); if (currentCell) { return currentCell->getCell()->isExterior(); @@ -1575,7 +1580,7 @@ namespace MWWorld bool World::isCellQuasiExterior() const { - CellStore *currentCell = mWorldScene->getCurrentCell(); + const CellStore *currentCell = mWorldScene->getCurrentCell(); if (currentCell) { if (!(currentCell->getCell()->mData.mFlags & ESM::Cell::QuasiEx)) @@ -1663,6 +1668,11 @@ namespace MWWorld return mRendering->toggleWater(); } + bool World::toggleWorld() + { + return mRendering->toggleWorld(); + } + void World::PCDropped (const Ptr& item) { std::string script = item.getClass().getScript(item); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index d4f11f5b6..1a25edbe5 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -180,6 +180,7 @@ namespace MWWorld virtual void setWaterHeight(const float height); virtual bool toggleWater(); + virtual bool toggleWorld(); virtual void adjustSky(); @@ -197,7 +198,7 @@ namespace MWWorld virtual LocalScripts& getLocalScripts(); virtual bool hasCellChanged() const; - ///< Has the player moved to a different cell, since the last frame? + ///< Has the set of active cells changed, since the last frame? virtual bool isCellExterior() const; diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index e12ab65eb..25ee6fdb6 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -256,6 +256,8 @@ namespace Compiler extensions.registerInstruction ("fadeto", "ff", opcodeFadeTo); extensions.registerInstruction ("togglewater", "", opcodeToggleWater); extensions.registerInstruction ("twa", "", opcodeToggleWater); + extensions.registerInstruction ("toggleworld", "", opcodeToggleWorld); + extensions.registerInstruction ("tw", "", opcodeToggleWorld); extensions.registerInstruction ("togglepathgrid", "", opcodeTogglePathgrid); extensions.registerInstruction ("tpg", "", opcodeTogglePathgrid); extensions.registerInstruction ("dontsaveobject", "", opcodeDontSaveObject); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 440475773..5063397e1 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -212,6 +212,7 @@ namespace Compiler const int opcodeFadeOut = 0x200013d; const int opcodeFadeTo = 0x200013e; const int opcodeToggleWater = 0x2000144; + const int opcodeToggleWorld = 0x20002f5; const int opcodeTogglePathgrid = 0x2000146; const int opcodeDontSaveObject = 0x2000153; const int opcodeToggleVanityMode = 0x2000174; diff --git a/components/esm/spelllist.cpp b/components/esm/spelllist.cpp index aeface617..8ec386db4 100644 --- a/components/esm/spelllist.cpp +++ b/components/esm/spelllist.cpp @@ -20,4 +20,12 @@ void SpellList::save(ESMWriter &esm) const } } +bool SpellList::exists(const std::string &spell) const +{ + for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + if (Misc::StringUtils::ciEqual(*it, spell)) + return true; + return false; +} + } diff --git a/components/esm/spelllist.hpp b/components/esm/spelllist.hpp index 934bdda7a..bcd6ba798 100644 --- a/components/esm/spelllist.hpp +++ b/components/esm/spelllist.hpp @@ -16,6 +16,9 @@ namespace ESM { std::vector mList; + /// Is this spell ID in mList? + bool exists(const std::string& spell) const; + void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 44974eeb1..57379a334 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -73,38 +73,6 @@ namespace return NULL; } - - // Ogre::AxisAlignedBox::distance is broken in 1.8. - Ogre::Real distance(const Ogre::AxisAlignedBox& box, const Ogre::Vector3& v) - { - - if (box.contains(v)) - return 0; - else - { - Ogre::Vector3 maxDist(0,0,0); - const Ogre::Vector3& minimum = box.getMinimum(); - const Ogre::Vector3& maximum = box.getMaximum(); - - if (v.x < minimum.x) - maxDist.x = minimum.x - v.x; - else if (v.x > maximum.x) - maxDist.x = v.x - maximum.x; - - if (v.y < minimum.y) - maxDist.y = minimum.y - v.y; - else if (v.y > maximum.y) - maxDist.y = v.y - maximum.y; - - if (v.z < minimum.z) - maxDist.z = minimum.z - v.z; - else if (v.z > maximum.z) - maxDist.z = v.z - maximum.z; - - return maxDist.length(); - } - } - // Create a 2D quad void makeQuad(Ogre::SceneManager* sceneMgr, float left, float top, float right, float bottom, Ogre::MaterialPtr material) { @@ -270,7 +238,7 @@ bool QuadTreeNode::update(const Ogre::Vector3 &cameraPos) if (mBounds.isNull()) return true; - float dist = distance(mWorldBounds, cameraPos); + float dist = mWorldBounds.distance(cameraPos); // Make sure our scene node is attached if (!mSceneNode->isInSceneGraph()) diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index f874abaf8..6a6a6bf09 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -119,9 +119,11 @@ namespace ICS //bool sliderMoved(const OIS::JoyStickEvent &evt, int index); void addKeyBinding(Control* control, SDL_Scancode key, Control::ControlChangingDirection direction); + bool isKeyBound(SDL_Scancode key) const; void addMouseAxisBinding(Control* control, NamedAxis axis, Control::ControlChangingDirection direction); void addMouseButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction); - void addJoystickAxisBinding(Control* control, int deviceId, int axis, Control::ControlChangingDirection direction); + bool isMouseButtonBound(unsigned int button) const; + void addJoystickAxisBinding(Control* control, int deviceId, int axis, Control::ControlChangingDirection direction); void addJoystickButtonBinding(Control* control, int deviceId, unsigned int button, Control::ControlChangingDirection direction); void addJoystickPOVBinding(Control* control, int deviceId, int index, POVAxis axis, Control::ControlChangingDirection direction); void addJoystickSliderBinding(Control* control, int deviceId, int index, Control::ControlChangingDirection direction); diff --git a/extern/oics/ICSInputControlSystem_keyboard.cpp b/extern/oics/ICSInputControlSystem_keyboard.cpp index af0eec82a..ed35d9870 100644 --- a/extern/oics/ICSInputControlSystem_keyboard.cpp +++ b/extern/oics/ICSInputControlSystem_keyboard.cpp @@ -61,6 +61,11 @@ namespace ICS mControlsKeyBinderMap[ key ] = controlKeyBinderItem; } + bool InputControlSystem::isKeyBound(SDL_Scancode key) const + { + return mControlsKeyBinderMap.find(key) != mControlsKeyBinderMap.end(); + } + void InputControlSystem::removeKeyBinding(SDL_Scancode key) { ControlsKeyBinderMapType::iterator it = mControlsKeyBinderMap.find(key); diff --git a/extern/oics/ICSInputControlSystem_mouse.cpp b/extern/oics/ICSInputControlSystem_mouse.cpp index d1ef721b2..9742d389c 100644 --- a/extern/oics/ICSInputControlSystem_mouse.cpp +++ b/extern/oics/ICSInputControlSystem_mouse.cpp @@ -139,6 +139,11 @@ namespace ICS mControlsMouseButtonBinderMap[ button ] = controlMouseButtonBinderItem; } + bool InputControlSystem::isMouseButtonBound(unsigned int button) const + { + return mControlsMouseButtonBinderMap.find(button) != mControlsMouseButtonBinderMap.end(); + } + // get bindings InputControlSystem::NamedAxis InputControlSystem::getMouseAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction) { diff --git a/files/materials/atmosphere.shader b/files/materials/atmosphere.shader index c8a8e0220..5040052fc 100644 --- a/files/materials/atmosphere.shader +++ b/files/materials/atmosphere.shader @@ -12,13 +12,13 @@ { float4x4 viewFixed = view; #if !SH_GLSL - viewFixed[0][3] = 0; - viewFixed[1][3] = 0; - viewFixed[2][3] = 0; + viewFixed[0][3] = 0.0; + viewFixed[1][3] = 0.0; + viewFixed[2][3] = 0.0; #else - viewFixed[3][0] = 0; - viewFixed[3][1] = 0; - viewFixed[3][2] = 0; + viewFixed[3][0] = 0.0; + viewFixed[3][1] = 0.0; + viewFixed[3][2] = 0.0; #endif shOutputPosition = shMatrixMult(projection, shMatrixMult(viewFixed, shInputPosition)); alphaFade = shInputPosition.z < 150.0 ? 0.0 : 1.0; diff --git a/files/materials/clouds.shader b/files/materials/clouds.shader index 9e9b10256..90c4d0f84 100644 --- a/files/materials/clouds.shader +++ b/files/materials/clouds.shader @@ -14,13 +14,13 @@ float4x4 worldviewFixed = worldview; #if !SH_GLSL - worldviewFixed[0][3] = 0; - worldviewFixed[1][3] = 0; - worldviewFixed[2][3] = 0; + worldviewFixed[0][3] = 0.0; + worldviewFixed[1][3] = 0.0; + worldviewFixed[2][3] = 0.0; #else - worldviewFixed[3][0] = 0; - worldviewFixed[3][1] = 0; - worldviewFixed[3][2] = 0; + worldviewFixed[3][0] = 0.0; + worldviewFixed[3][1] = 0.0; + worldviewFixed[3][2] = 0.0; #endif shOutputPosition = shMatrixMult(proj, shMatrixMult(worldviewFixed, shInputPosition)); diff --git a/files/materials/moon.shader b/files/materials/moon.shader index a7d183d10..d369a1c68 100644 --- a/files/materials/moon.shader +++ b/files/materials/moon.shader @@ -13,13 +13,13 @@ shUniform(float4x4, projection) @shAutoConstant(projection, projection_matrix) { float4x4 viewFixed = view; #if !SH_GLSL - viewFixed[0][3] = 0; - viewFixed[1][3] = 0; - viewFixed[2][3] = 0; + viewFixed[0][3] = 0.0; + viewFixed[1][3] = 0.0; + viewFixed[2][3] = 0.0; #else - viewFixed[3][0] = 0; - viewFixed[3][1] = 0; - viewFixed[3][2] = 0; + viewFixed[3][0] = 0.0; + viewFixed[3][1] = 0.0; + viewFixed[3][2] = 0.0; #endif shOutputPosition = shMatrixMult(projection, shMatrixMult(viewFixed, shMatrixMult(world, shInputPosition))); UV = uv0; diff --git a/files/materials/sun.shader b/files/materials/sun.shader index abe4c97f1..fc747b522 100644 --- a/files/materials/sun.shader +++ b/files/materials/sun.shader @@ -13,13 +13,13 @@ shUniform(float4x4, projection) @shAutoConstant(projection, projection_matrix) { float4x4 viewFixed = view; #if !SH_GLSL - viewFixed[0][3] = 0; - viewFixed[1][3] = 0; - viewFixed[2][3] = 0; + viewFixed[0][3] = 0.0; + viewFixed[1][3] = 0.0; + viewFixed[2][3] = 0.0; #else - viewFixed[3][0] = 0; - viewFixed[3][1] = 0; - viewFixed[3][2] = 0; + viewFixed[3][0] = 0.0; + viewFixed[3][1] = 0.0; + viewFixed[3][2] = 0.0; #endif shOutputPosition = shMatrixMult(projection, shMatrixMult(viewFixed, shMatrixMult(world, shInputPosition))); UV = uv0; diff --git a/files/materials/water.shader b/files/materials/water.shader index 701154ffa..418b13715 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -40,7 +40,7 @@ SH_START_PROGRAM { - shOutputColour(0).xyz = shSample(animatedTexture, UV * 15).xyz * float3(1.0, 1.0, 1.0); + shOutputColour(0).xyz = shSample(animatedTexture, UV * float2(15.0, 15.0)).xyz * float3(1.0, 1.0, 1.0); shOutputColour(0).w = 0.7; #if FOG diff --git a/files/mygui/openmw_console.layout b/files/mygui/openmw_console.layout index c88c1955d..854568f9b 100644 --- a/files/mygui/openmw_console.layout +++ b/files/mygui/openmw_console.layout @@ -2,8 +2,7 @@ - - + diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index eda002040..49ee0a1de 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_messagebox.layout b/files/mygui/openmw_messagebox.layout index 8264d64b9..a70e14503 100644 --- a/files/mygui/openmw_messagebox.layout +++ b/files/mygui/openmw_messagebox.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 5945c68d7..fa6485688 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -346,10 +346,10 @@ - + - + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 67fd5ee8c..06d999189 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -122,8 +122,12 @@ small object size = 250 # Rendering distance for small objects small object distance = 3500 -# Max viewing distance at clear weather conditions -max viewing distance = 5600 +# Viewing distance at normal weather conditions +# The maximum distance with no pop-in will be: (see RenderingManager::configureFog) +# viewing distance / minimum weather fog depth (.69) * view frustum factor <= cell size (8192) - loading threshold (1024) +# view frustum factor takes into account that the view frustum end is a plane, so at the edges of the screen you can see further than you should be able to. +# exact factor would depend on FOV +viewing distance = 4600 # Distance at which fog starts (proportional to viewing distance) fog start factor = 0.5 diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index d3aa714f1..97418fae0 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -387,7 +387,7 @@ namespace Physic mHeightFieldMap [name] = hf; mDynamicsWorld->addRigidBody(body,CollisionType_HeightMap, - CollisionType_World|CollisionType_Actor|CollisionType_Raycasting); + CollisionType_Actor|CollisionType_Raycasting); } void PhysicEngine::removeHeightField(int x, int y) @@ -494,7 +494,7 @@ namespace Physic { assert (mCollisionObjectMap.find(name) == mCollisionObjectMap.end()); mCollisionObjectMap[name] = body; - mDynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_World|CollisionType_Actor|CollisionType_HeightMap); + mDynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_Actor|CollisionType_HeightMap); } else { diff --git a/libs/openengine/gui/layout.hpp b/libs/openengine/gui/layout.hpp index 26a3fdab8..cd530a1d9 100644 --- a/libs/openengine/gui/layout.hpp +++ b/libs/openengine/gui/layout.hpp @@ -42,6 +42,7 @@ namespace GUI MYGUI_ASSERT( ! _throw, "widget name '" << _name << "' in layout '" << mLayoutName << "' not found."); } + private: void initialise(const std::string & _layout, MyGUI::Widget* _parent = nullptr) { @@ -74,6 +75,7 @@ namespace GUI mListWindowRoot.clear(); } + public: void setCoord(int x, int y, int w, int h) { mMainWidget->setCoord(x,y,w,h); @@ -121,29 +123,6 @@ namespace GUI adjustWindowCaption(); } - void setState(const std::string& widget, const std::string& state) - { - MyGUI::Widget* pt; - getWidget(pt, widget); - pt->_setWidgetState(state); - } - - void setTextColor(const std::string& name, float r, float g, float b) - { - MyGUI::Widget* pt; - getWidget(pt, name); - MyGUI::TextBox *st = dynamic_cast(pt); - if(st != NULL) - st->setTextColour(MyGUI::Colour(b,g,r)); - } - - void setImage(const std::string& name, const std::string& imgName) - { - MyGUI::ImageBox* pt; - getWidget(pt, name); - pt->setImageTexture(imgName); - } - void adjustButtonSize(MyGUI::Button* button) { // adjust size of button to fit its text