mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-07-21 11:14:04 +00:00
Add OpenMW 0.47 commits up to 10 Oct 2021
This commit is contained in:
commit
e010c61167
13 changed files with 56 additions and 62 deletions
|
@ -222,6 +222,7 @@ Programmers
|
||||||
Yuri Krupenin
|
Yuri Krupenin
|
||||||
zelurker
|
zelurker
|
||||||
Noah Gooder
|
Noah Gooder
|
||||||
|
Andrew Appuhamy (andrew-app)
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
|
|
@ -131,6 +131,7 @@
|
||||||
Bug #6043: Actor can have torch missing when torch animation is played
|
Bug #6043: Actor can have torch missing when torch animation is played
|
||||||
Bug #6047: Mouse bindings can be triggered during save loading
|
Bug #6047: Mouse bindings can be triggered during save loading
|
||||||
Bug #6136: Game freezes when NPCs try to open doors that are about to be closed
|
Bug #6136: Game freezes when NPCs try to open doors that are about to be closed
|
||||||
|
Bug #6294: Game crashes with empty pathgrid
|
||||||
Feature #390: 3rd person look "over the shoulder"
|
Feature #390: 3rd person look "over the shoulder"
|
||||||
Feature #832: OpenMW-CS: Handle deleted references
|
Feature #832: OpenMW-CS: Handle deleted references
|
||||||
Feature #1536: Show more information about level on menu
|
Feature #1536: Show more information about level on menu
|
||||||
|
@ -160,6 +161,7 @@
|
||||||
Feature #5519: Code Patch tab in launcher
|
Feature #5519: Code Patch tab in launcher
|
||||||
Feature #5524: Resume failed script execution after reload
|
Feature #5524: Resume failed script execution after reload
|
||||||
Feature #5545: Option to allow stealing from an unconscious NPC during combat
|
Feature #5545: Option to allow stealing from an unconscious NPC during combat
|
||||||
|
Feature #5551: Do not reboot PC after OpenMW installation on Windows
|
||||||
Feature #5563: Run physics update in background thread
|
Feature #5563: Run physics update in background thread
|
||||||
Feature #5579: MCP SetAngle enhancement
|
Feature #5579: MCP SetAngle enhancement
|
||||||
Feature #5580: Service refusal filtering
|
Feature #5580: Service refusal filtering
|
||||||
|
@ -174,6 +176,7 @@
|
||||||
Feature #5814: Bsatool should be able to create BSA archives, not only to extract it
|
Feature #5814: Bsatool should be able to create BSA archives, not only to extract it
|
||||||
Feature #5828: Support more than 8 lights
|
Feature #5828: Support more than 8 lights
|
||||||
Feature #5910: Fall back to delta time when physics can't keep up
|
Feature #5910: Fall back to delta time when physics can't keep up
|
||||||
|
Feature #5980: Support Bullet with double precision instead of one with single precision
|
||||||
Feature #6024: OpenMW-CS: Selecting terrain in "Terrain land editing" should support "Add to selection" and "Remove from selection" modes
|
Feature #6024: OpenMW-CS: Selecting terrain in "Terrain land editing" should support "Add to selection" and "Remove from selection" modes
|
||||||
Feature #6033: Include pathgrid to navigation mesh
|
Feature #6033: Include pathgrid to navigation mesh
|
||||||
Feature #6034: Find path based on area cost depending on NPC stats
|
Feature #6034: Find path based on area cost depending on NPC stats
|
||||||
|
|
|
@ -98,8 +98,8 @@ namespace MWInput
|
||||||
// We keep track of our own mouse position, so that moving the mouse while in
|
// We keep track of our own mouse position, so that moving the mouse while in
|
||||||
// game mode does not move the position of the GUI cursor
|
// game mode does not move the position of the GUI cursor
|
||||||
float uiScale = MWBase::Environment::get().getWindowManager()->getScalingFactor();
|
float uiScale = MWBase::Environment::get().getWindowManager()->getScalingFactor();
|
||||||
float xMove = xAxis * dt * 1500.0f / uiScale;
|
float xMove = xAxis * dt * 1500.0f / uiScale * mGamepadCursorSpeed;
|
||||||
float yMove = yAxis * dt * 1500.0f / uiScale;
|
float yMove = yAxis * dt * 1500.0f / uiScale * mGamepadCursorSpeed;
|
||||||
|
|
||||||
float mouseWheelMove = -zAxis * dt * 1500.0f;
|
float mouseWheelMove = -zAxis * dt * 1500.0f;
|
||||||
if (xMove != 0 || yMove != 0 || mouseWheelMove != 0)
|
if (xMove != 0 || yMove != 0 || mouseWheelMove != 0)
|
||||||
|
|
|
@ -44,14 +44,14 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool absorbSpell (const std::string& spellId, const MWWorld::Ptr& caster, const MWWorld::Ptr& target)
|
int getAbsorbChance(const MWWorld::Ptr& caster, const MWWorld::Ptr& target)
|
||||||
{
|
{
|
||||||
if (spellId.empty() || target.isEmpty() || caster == target || !target.getClass().isActor())
|
if(target.isEmpty() || caster == target || !target.getClass().isActor())
|
||||||
return false;
|
return 0;
|
||||||
|
|
||||||
CreatureStats& stats = target.getClass().getCreatureStats(target);
|
CreatureStats& stats = target.getClass().getCreatureStats(target);
|
||||||
if (stats.getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude() <= 0.f)
|
if (stats.getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude() <= 0.f)
|
||||||
return false;
|
return 0;
|
||||||
|
|
||||||
GetAbsorptionProbability check;
|
GetAbsorptionProbability check;
|
||||||
stats.getActiveSpells().visitEffectSources(check);
|
stats.getActiveSpells().visitEffectSources(check);
|
||||||
|
@ -59,9 +59,12 @@ namespace MWMechanics
|
||||||
if (target.getClass().hasInventoryStore(target))
|
if (target.getClass().hasInventoryStore(target))
|
||||||
target.getClass().getInventoryStore(target).visitEffectSources(check);
|
target.getClass().getInventoryStore(target).visitEffectSources(check);
|
||||||
|
|
||||||
int chance = check.mProbability * 100;
|
return check.mProbability * 100;
|
||||||
if (Misc::Rng::roll0to99() >= chance)
|
}
|
||||||
return false;
|
|
||||||
|
void absorbSpell (const std::string& spellId, const MWWorld::Ptr& caster, const MWWorld::Ptr& target)
|
||||||
|
{
|
||||||
|
CreatureStats& stats = target.getClass().getCreatureStats(target);
|
||||||
|
|
||||||
const auto& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
const auto& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
||||||
const ESM::Static* absorbStatic = esmStore.get<ESM::Static>().find("VFX_Absorb");
|
const ESM::Static* absorbStatic = esmStore.get<ESM::Static>().find("VFX_Absorb");
|
||||||
|
@ -85,7 +88,6 @@ namespace MWMechanics
|
||||||
DynamicStat<float> magicka = stats.getMagicka();
|
DynamicStat<float> magicka = stats.getMagicka();
|
||||||
magicka.setCurrent(magicka.getCurrent() + spellCost);
|
magicka.setCurrent(magicka.getCurrent() + spellCost);
|
||||||
stats.setMagicka(magicka);
|
stats.setMagicka(magicka);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,9 @@ namespace MWWorld
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
// Try to absorb a spell based on the magnitude of every Spell Absorption effect source on the target.
|
void absorbSpell(const std::string& spellId, const MWWorld::Ptr& caster, const MWWorld::Ptr& target);
|
||||||
bool absorbSpell(const std::string& spellId, const MWWorld::Ptr& caster, const MWWorld::Ptr& target);
|
// Calculate the chance to absorb a spell based on the magnitude of every Spell Absorption effect source on the target.
|
||||||
|
int getAbsorbChance(const MWWorld::Ptr& caster, const MWWorld::Ptr& target);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -136,8 +136,7 @@ namespace MWMechanics
|
||||||
// throughout the iteration of this spell's
|
// throughout the iteration of this spell's
|
||||||
// effects, we display a "can't re-cast" message
|
// effects, we display a "can't re-cast" message
|
||||||
|
|
||||||
// Try absorbing the spell. Some handling must still happen for absorbed effects.
|
int absorbChance = getAbsorbChance(caster, target);
|
||||||
bool absorbed = absorbSpell(mId, caster, target);
|
|
||||||
|
|
||||||
int currentEffectIndex = 0;
|
int currentEffectIndex = 0;
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (effects.mList.begin());
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (effects.mList.begin());
|
||||||
|
@ -159,6 +158,13 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
canCastAnEffect = true;
|
canCastAnEffect = true;
|
||||||
|
|
||||||
|
// Try absorbing the effect
|
||||||
|
if(absorbChance && Misc::Rng::roll0to99() < absorbChance)
|
||||||
|
{
|
||||||
|
absorbSpell(mId, caster, target);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!checkEffectTarget(effectIt->mEffectID, target, caster, castByPlayer))
|
if (!checkEffectTarget(effectIt->mEffectID, target, caster, castByPlayer))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -172,10 +178,6 @@ namespace MWMechanics
|
||||||
if (target.getClass().isActor() && target != caster && !caster.isEmpty() && isHarmful)
|
if (target.getClass().isActor() && target != caster && !caster.isEmpty() && isHarmful)
|
||||||
target.getClass().onHit(target, 0.0f, true, MWWorld::Ptr(), caster, osg::Vec3f(), true);
|
target.getClass().onHit(target, 0.0f, true, MWWorld::Ptr(), caster, osg::Vec3f(), true);
|
||||||
|
|
||||||
// Avoid proceeding further for absorbed spells.
|
|
||||||
if (absorbed)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Reflect harmful effects
|
// Reflect harmful effects
|
||||||
if (!reflected && reflectEffect(*effectIt, magicEffect, caster, target, reflectedEffects))
|
if (!reflected && reflectEffect(*effectIt, magicEffect, caster, target, reflectedEffects))
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -644,7 +644,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
mTaskScheduler->convexSweepTest(projectile->getConvexShape(), from_, to_, resultCallback);
|
mTaskScheduler->convexSweepTest(projectile->getConvexShape(), from_, to_, resultCallback);
|
||||||
|
|
||||||
const auto newpos = projectile->isActive() ? position : Misc::Convert::toOsg(resultCallback.m_hitPointWorld);
|
const auto newpos = projectile->isActive() ? position : Misc::Convert::toOsg(projectile->getHitPosition());
|
||||||
projectile->setPosition(newpos);
|
projectile->setPosition(newpos);
|
||||||
mTaskScheduler->updateSingleAabb(foundProjectile->second);
|
mTaskScheduler->updateSingleAabb(foundProjectile->second);
|
||||||
}
|
}
|
||||||
|
@ -717,7 +717,7 @@ namespace MWPhysics
|
||||||
mActors.emplace(ptr, std::move(actor));
|
mActors.emplace(ptr, std::move(actor));
|
||||||
}
|
}
|
||||||
|
|
||||||
int PhysicsSystem::addProjectile (const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius, bool canTraverseWater)
|
int PhysicsSystem::addProjectile (const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance = mShapeManager->getInstance(mesh);
|
osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance = mShapeManager->getInstance(mesh);
|
||||||
assert(shapeInstance);
|
assert(shapeInstance);
|
||||||
|
@ -725,7 +725,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
mProjectileId++;
|
mProjectileId++;
|
||||||
|
|
||||||
auto projectile = std::make_shared<Projectile>(caster, position, radius, canTraverseWater, mTaskScheduler.get(), this);
|
auto projectile = std::make_shared<Projectile>(caster, position, radius, mTaskScheduler.get(), this);
|
||||||
mProjectiles.emplace(mProjectileId, std::move(projectile));
|
mProjectiles.emplace(mProjectileId, std::move(projectile));
|
||||||
|
|
||||||
return mProjectileId;
|
return mProjectileId;
|
||||||
|
|
|
@ -125,7 +125,7 @@ namespace MWPhysics
|
||||||
void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, int collisionType = CollisionType_World);
|
void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, int collisionType = CollisionType_World);
|
||||||
void addActor (const MWWorld::Ptr& ptr, const std::string& mesh);
|
void addActor (const MWWorld::Ptr& ptr, const std::string& mesh);
|
||||||
|
|
||||||
int addProjectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius, bool canTraverseWater);
|
int addProjectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius);
|
||||||
void setCaster(int projectileId, const MWWorld::Ptr& caster);
|
void setCaster(int projectileId, const MWWorld::Ptr& caster);
|
||||||
void updateProjectile(const int projectileId, const osg::Vec3f &position) const;
|
void updateProjectile(const int projectileId, const osg::Vec3f &position) const;
|
||||||
void removeProjectile(const int projectileId);
|
void removeProjectile(const int projectileId);
|
||||||
|
|
|
@ -13,12 +13,10 @@
|
||||||
|
|
||||||
namespace MWPhysics
|
namespace MWPhysics
|
||||||
{
|
{
|
||||||
Projectile::Projectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, float radius, bool canCrossWaterSurface, PhysicsTaskScheduler* scheduler, PhysicsSystem* physicssystem)
|
Projectile::Projectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, float radius, PhysicsTaskScheduler* scheduler, PhysicsSystem* physicssystem)
|
||||||
: mCanCrossWaterSurface(canCrossWaterSurface)
|
: mHitWater(false)
|
||||||
, mCrossedWaterSurface(false)
|
|
||||||
, mActive(true)
|
, mActive(true)
|
||||||
, mCaster(caster)
|
, mCaster(caster)
|
||||||
, mWaterHitPosition(std::nullopt)
|
|
||||||
, mPhysics(physicssystem)
|
, mPhysics(physicssystem)
|
||||||
, mTaskScheduler(scheduler)
|
, mTaskScheduler(scheduler)
|
||||||
{
|
{
|
||||||
|
@ -72,11 +70,6 @@ osg::Vec3f Projectile::getPosition() const
|
||||||
return mPosition;
|
return mPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Projectile::canTraverseWater() const
|
|
||||||
{
|
|
||||||
return mCanCrossWaterSurface;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Projectile::hit(MWWorld::Ptr target, btVector3 pos, btVector3 normal)
|
void Projectile::hit(MWWorld::Ptr target, btVector3 pos, btVector3 normal)
|
||||||
{
|
{
|
||||||
if (!mActive.load(std::memory_order_acquire))
|
if (!mActive.load(std::memory_order_acquire))
|
||||||
|
@ -127,17 +120,4 @@ bool Projectile::isValidTarget(const MWWorld::Ptr& target) const
|
||||||
return validTarget;
|
return validTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<btVector3> Projectile::getWaterHitPosition()
|
|
||||||
{
|
|
||||||
return std::exchange(mWaterHitPosition, std::nullopt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Projectile::setWaterHitPosition(btVector3 pos)
|
|
||||||
{
|
|
||||||
if (mCrossedWaterSurface)
|
|
||||||
return;
|
|
||||||
mCrossedWaterSurface = true;
|
|
||||||
mWaterHitPosition = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
#include <LinearMath/btVector3.h>
|
#include <LinearMath/btVector3.h>
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ namespace MWPhysics
|
||||||
class Projectile final : public PtrHolder
|
class Projectile final : public PtrHolder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Projectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, float radius, bool canCrossWaterSurface, PhysicsTaskScheduler* scheduler, PhysicsSystem* physicssystem);
|
Projectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, float radius, PhysicsTaskScheduler* scheduler, PhysicsSystem* physicssystem);
|
||||||
~Projectile() override;
|
~Projectile() override;
|
||||||
|
|
||||||
btConvexShape* getConvexShape() const { return mConvexShape; }
|
btConvexShape* getConvexShape() const { return mConvexShape; }
|
||||||
|
@ -61,15 +60,25 @@ namespace MWPhysics
|
||||||
MWWorld::Ptr getCaster() const;
|
MWWorld::Ptr getCaster() const;
|
||||||
void setCaster(MWWorld::Ptr caster);
|
void setCaster(MWWorld::Ptr caster);
|
||||||
|
|
||||||
bool canTraverseWater() const;
|
void setHitWater()
|
||||||
|
{
|
||||||
|
mHitWater = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getHitWater() const
|
||||||
|
{
|
||||||
|
return mHitWater;
|
||||||
|
}
|
||||||
|
|
||||||
void hit(MWWorld::Ptr target, btVector3 pos, btVector3 normal);
|
void hit(MWWorld::Ptr target, btVector3 pos, btVector3 normal);
|
||||||
|
|
||||||
void setValidTargets(const std::vector<MWWorld::Ptr>& targets);
|
void setValidTargets(const std::vector<MWWorld::Ptr>& targets);
|
||||||
bool isValidTarget(const MWWorld::Ptr& target) const;
|
bool isValidTarget(const MWWorld::Ptr& target) const;
|
||||||
|
|
||||||
std::optional<btVector3> getWaterHitPosition();
|
btVector3 getHitPosition() const
|
||||||
void setWaterHitPosition(btVector3 pos);
|
{
|
||||||
|
return mHitPosition;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -78,12 +87,10 @@ namespace MWPhysics
|
||||||
|
|
||||||
std::unique_ptr<btCollisionObject> mCollisionObject;
|
std::unique_ptr<btCollisionObject> mCollisionObject;
|
||||||
bool mTransformUpdatePending;
|
bool mTransformUpdatePending;
|
||||||
bool mCanCrossWaterSurface;
|
bool mHitWater;
|
||||||
bool mCrossedWaterSurface;
|
|
||||||
std::atomic<bool> mActive;
|
std::atomic<bool> mActive;
|
||||||
MWWorld::Ptr mCaster;
|
MWWorld::Ptr mCaster;
|
||||||
MWWorld::Ptr mHitTarget;
|
MWWorld::Ptr mHitTarget;
|
||||||
std::optional<btVector3> mWaterHitPosition;
|
|
||||||
osg::Vec3f mPosition;
|
osg::Vec3f mPosition;
|
||||||
btVector3 mHitPosition;
|
btVector3 mHitPosition;
|
||||||
btVector3 mHitNormal;
|
btVector3 mHitNormal;
|
||||||
|
|
|
@ -47,9 +47,7 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
case CollisionType_Water:
|
case CollisionType_Water:
|
||||||
{
|
{
|
||||||
mProjectile->setWaterHitPosition(m_hitPointWorld);
|
mProjectile->setHitWater();
|
||||||
if (mProjectile->canTraverseWater())
|
|
||||||
return 1.f;
|
|
||||||
mProjectile->hit(MWWorld::Ptr(), m_hitPointWorld, m_hitNormalWorld);
|
mProjectile->hit(MWWorld::Ptr(), m_hitPointWorld, m_hitNormalWorld);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,7 +320,7 @@ namespace MWWorld
|
||||||
// in case there are multiple effects, the model is a dummy without geometry. Use the second effect for physics shape
|
// in case there are multiple effects, the model is a dummy without geometry. Use the second effect for physics shape
|
||||||
if (state.mIdMagic.size() > 1)
|
if (state.mIdMagic.size() > 1)
|
||||||
model = "meshes\\" + MWBase::Environment::get().getWorld()->getStore().get<ESM::Weapon>().find(state.mIdMagic.at(1))->mModel;
|
model = "meshes\\" + MWBase::Environment::get().getWorld()->getStore().get<ESM::Weapon>().find(state.mIdMagic.at(1))->mModel;
|
||||||
state.mProjectileId = mPhysics->addProjectile(caster, pos, model, true, false);
|
state.mProjectileId = mPhysics->addProjectile(caster, pos, model, true);
|
||||||
state.mToDelete = false;
|
state.mToDelete = false;
|
||||||
mMagicBolts.push_back(state);
|
mMagicBolts.push_back(state);
|
||||||
}
|
}
|
||||||
|
@ -345,7 +345,7 @@ namespace MWWorld
|
||||||
if (!ptr.getClass().getEnchantment(ptr).empty())
|
if (!ptr.getClass().getEnchantment(ptr).empty())
|
||||||
SceneUtil::addEnchantedGlow(state.mNode, mResourceSystem, ptr.getClass().getEnchantmentColor(ptr));
|
SceneUtil::addEnchantedGlow(state.mNode, mResourceSystem, ptr.getClass().getEnchantmentColor(ptr));
|
||||||
|
|
||||||
state.mProjectileId = mPhysics->addProjectile(actor, pos, model, false, true);
|
state.mProjectileId = mPhysics->addProjectile(actor, pos, model, false);
|
||||||
state.mToDelete = false;
|
state.mToDelete = false;
|
||||||
mProjectiles.push_back(state);
|
mProjectiles.push_back(state);
|
||||||
}
|
}
|
||||||
|
@ -496,9 +496,6 @@ namespace MWWorld
|
||||||
|
|
||||||
auto* projectile = mPhysics->getProjectile(projectileState.mProjectileId);
|
auto* projectile = mPhysics->getProjectile(projectileState.mProjectileId);
|
||||||
|
|
||||||
if (const auto hitWaterPos = projectile->getWaterHitPosition())
|
|
||||||
mRendering->emitWaterRipple(Misc::Convert::toOsg(*hitWaterPos));
|
|
||||||
|
|
||||||
const auto pos = projectile->getPosition();
|
const auto pos = projectile->getPosition();
|
||||||
projectileState.mNode->setPosition(pos);
|
projectileState.mNode->setPosition(pos);
|
||||||
|
|
||||||
|
@ -522,6 +519,8 @@ namespace MWWorld
|
||||||
if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().getRefId(), projectileState.mBowId))
|
if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().getRefId(), projectileState.mBowId))
|
||||||
bow = *invIt;
|
bow = *invIt;
|
||||||
}
|
}
|
||||||
|
if (projectile->getHitWater())
|
||||||
|
mRendering->emitWaterRipple(pos);
|
||||||
|
|
||||||
MWMechanics::projectileHit(caster, target, bow, projectileRef.getPtr(), pos, projectileState.mAttackStrength);
|
MWMechanics::projectileHit(caster, target, bow, projectileRef.getPtr(), pos, projectileState.mAttackStrength);
|
||||||
cleanupProjectile(projectileState);
|
cleanupProjectile(projectileState);
|
||||||
|
@ -654,7 +653,7 @@ namespace MWWorld
|
||||||
int weaponType = ptr.get<ESM::Weapon>()->mBase->mData.mType;
|
int weaponType = ptr.get<ESM::Weapon>()->mBase->mData.mType;
|
||||||
state.mThrown = MWMechanics::getWeaponType(weaponType)->mWeaponClass == ESM::WeaponType::Thrown;
|
state.mThrown = MWMechanics::getWeaponType(weaponType)->mWeaponClass == ESM::WeaponType::Thrown;
|
||||||
|
|
||||||
state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), model, false, true);
|
state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), model, false);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -707,7 +706,7 @@ namespace MWWorld
|
||||||
|
|
||||||
osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects);
|
osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(state.mEffects);
|
||||||
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture);
|
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture);
|
||||||
state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), model, true, false);
|
state.mProjectileId = mPhysics->addProjectile(state.getCaster(), osg::Vec3f(esm.mPosition), model, true);
|
||||||
|
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
for (const std::string &soundid : state.mSoundIds)
|
for (const std::string &soundid : state.mSoundIds)
|
||||||
|
|
|
@ -3672,6 +3672,7 @@ namespace MWWorld
|
||||||
bool underwater = MWBase::Environment::get().getWorld()->isUnderwater(MWMechanics::getPlayer().getCell(), worldPos);
|
bool underwater = MWBase::Environment::get().getWorld()->isUnderwater(MWMechanics::getPlayer().getCell(), worldPos);
|
||||||
if (underwater)
|
if (underwater)
|
||||||
{
|
{
|
||||||
|
MWMechanics::projectileHit(actor, Ptr(), bow, projectile, worldPos, attackStrength);
|
||||||
mRendering->emitWaterRipple(worldPos);
|
mRendering->emitWaterRipple(worldPos);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue