diff --git a/apps/opencs/model/world/cellcoordinates.cpp b/apps/opencs/model/world/cellcoordinates.cpp index 80ec9dc04..abb3bc82e 100644 --- a/apps/opencs/model/world/cellcoordinates.cpp +++ b/apps/opencs/model/world/cellcoordinates.cpp @@ -37,11 +37,16 @@ std::string CSMWorld::CellCoordinates::getId (const std::string& worldspace) con return stream.str(); } +bool CSMWorld::CellCoordinates::isExteriorCell (const std::string& id) +{ + return (!id.empty() && id[0]=='#'); +} + std::pair CSMWorld::CellCoordinates::fromId ( const std::string& id) { // no worldspace for now, needs to be changed for 1.1 - if (!id.empty() && id[0]=='#') + if (isExteriorCell(id)) { int x, y; char ignore; diff --git a/apps/opencs/model/world/cellcoordinates.hpp b/apps/opencs/model/world/cellcoordinates.hpp index 696868d00..9207aede5 100644 --- a/apps/opencs/model/world/cellcoordinates.hpp +++ b/apps/opencs/model/world/cellcoordinates.hpp @@ -32,12 +32,14 @@ namespace CSMWorld std::string getId (const std::string& worldspace) const; ///< Return the ID for the cell at these coordinates. + static bool isExteriorCell (const std::string& id); + /// \return first: CellCoordinates (or 0, 0 if cell does not have coordinates), /// second: is cell paged? /// /// \note The worldspace part of \a id is ignored static std::pair fromId (const std::string& id); - + /// \return cell coordinates such that given world coordinates are in it. static std::pair coordinatesToCellIndex (float x, float y); }; diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 3a6640c54..eb90e9db3 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -644,13 +644,16 @@ void CSVRender::Object::apply (CSMWorld::CommandMacro& commands) int column = collection.findColumnIndex (static_cast ( CSMWorld::Columns::ColumnId_Cell)); - std::pair cellIndex = collection.getRecord (recordIndex).get().getCellIndex(); + if (CSMWorld::CellCoordinates::isExteriorCell(collection.getRecord (recordIndex).get().mCell)) + { + std::pair cellIndex = collection.getRecord (recordIndex).get().getCellIndex(); - /// \todo figure out worldspace (not important until multiple worldspaces are supported) - std::string cellId = CSMWorld::CellCoordinates (cellIndex).getId (""); + /// \todo figure out worldspace (not important until multiple worldspaces are supported) + std::string cellId = CSMWorld::CellCoordinates (cellIndex).getId (""); - commands.push (new CSMWorld::ModifyCommand (*model, - model->index (recordIndex, column), QString::fromUtf8 (cellId.c_str()))); + commands.push (new CSMWorld::ModifyCommand (*model, + model->index (recordIndex, column), QString::fromUtf8 (cellId.c_str()))); + } } if (mOverrideFlags & Override_Rotation) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 82d5ddd5e..549931b9a 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -385,6 +385,7 @@ namespace MWBase ///Is the head of the creature underwater? virtual bool isSubmerged(const MWWorld::ConstPtr &object) const = 0; virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const = 0; + virtual bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const = 0; diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 38d1fd0b2..84a2e580f 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -261,7 +261,7 @@ namespace MWMechanics } /// Check if the given affect can be applied to the target. If \a castByPlayer, emits a message box on failure. - bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, bool castByPlayer) + bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer) { switch (effectId) { @@ -293,8 +293,20 @@ namespace MWMechanics return false; } break; - } + case ESM::MagicEffect::WaterWalking: + if (target.getClass().isPureWaterCreature(target) && MWBase::Environment::get().getWorld()->isSwimming(target)) + return false; + MWBase::World *world = MWBase::Environment::get().getWorld(); + + if (!world->isWaterWalkingCastableOnTarget(target)) + { + if (castByPlayer && caster == target) + MWBase::Environment::get().getWindowManager()->messageBox ("#{sMagicInvalidEffect}"); + return false; + } + break; + } return true; } @@ -386,7 +398,7 @@ namespace MWMechanics else canCastAnEffect = true; - if (!checkEffectTarget(effectIt->mEffectID, target, castByPlayer)) + if (!checkEffectTarget(effectIt->mEffectID, target, caster, castByPlayer)) continue; // caster needs to be an actor for linked effects (e.g. Absorb) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f46e7acff..8323eee87 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2098,6 +2098,19 @@ namespace MWWorld return pos.z() < cell->getWaterLevel(); } + bool World::isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const + { + const MWWorld::CellStore* cell = target.getCell(); + if (!cell->getCell()->hasWater()) + return true; + + // Based on observations from the original engine, the depth + // limit at which water walking can still be cast on a target + // in water appears to be the same as what the highest swimmable + // z position would be with SwimHeightScale + 1. + return !isUnderwater(target, mSwimHeightScale + 1); + } + bool World::isOnGround(const MWWorld::Ptr &ptr) const { return mPhysics->isOnGround(ptr); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index aa67c9ea8..da665e27c 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -481,6 +481,7 @@ namespace MWWorld virtual bool isSwimming(const MWWorld::ConstPtr &object) const; virtual bool isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const; virtual bool isWading(const MWWorld::ConstPtr &object) const; + virtual bool isWaterWalkingCastableOnTarget(const MWWorld::ConstPtr &target) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const;