diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 194e8f695..27980f070 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -539,6 +539,7 @@ namespace MWBase virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) = 0; virtual void launchProjectile (MWWorld::Ptr& actor, MWWorld::Ptr& projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr& bow, float speed, float attackStrength) = 0; + virtual void updateProjectilesCasters() = 0; virtual void applyLoopingParticles(const MWWorld::Ptr& ptr) = 0; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 382b348b9..b2decde2f 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -604,7 +604,9 @@ namespace MWPhysics return object->getCollisionObject(); return nullptr; }(); - assert(caster); + + if (caster == nullptr) + Log(Debug::Warning) << "No caster for projectile " << projectileId; ProjectileConvexCallback resultCallback(caster, btFrom, btTo, projectile); resultCallback.m_collisionFilterMask = 0xff; @@ -695,6 +697,15 @@ namespace MWPhysics return mProjectileId; } + void PhysicsSystem::setCaster(int projectileId, const MWWorld::Ptr& caster) + { + const auto foundProjectile = mProjectiles.find(projectileId); + assert(foundProjectile != mProjectiles.end()); + auto* projectile = foundProjectile->second.get(); + + projectile->setCaster(caster); + } + bool PhysicsSystem::toggleCollisionMode() { ActorMap::iterator found = mActors.find(MWMechanics::getPlayer()); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 57ebbadbb..80b2d98bc 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -125,6 +125,7 @@ namespace MWPhysics 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); + void setCaster(int projectileId, const MWWorld::Ptr& caster); void updateProjectile(const int projectileId, const osg::Vec3f &position) const; void removeProjectile(const int projectileId); diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 72e4b1ae0..f605344bf 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -539,6 +539,8 @@ void MWState::StateManager::loadGame (const Character *character, const std::str MWBase::Environment::get().getWorld()->changeToCell(cell->getCell()->getCellId(), pos, true, false); } + MWBase::Environment::get().getWorld()->updateProjectilesCasters(); + // Vanilla MW will restart startup scripts when a save game is loaded. This is unintuitive, // but some mods may be using it as a reload detector. MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup(); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 3ffc7bb95..f483905dd 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -352,6 +352,29 @@ namespace MWWorld mProjectiles.push_back(state); } + void ProjectileManager::updateCasters() + { + for (auto& state : mProjectiles) + mPhysics->setCaster(state.mProjectileId, state.getCaster()); + + for (auto& state : mMagicBolts) + { + // casters are identified by actor id in the savegame. objects doesn't have one so they can't be identified back. + // TODO: should object-type caster be restored from savegame? + if (state.mActorId == -1) + continue; + + auto caster = state.getCaster(); + if (caster.isEmpty()) + { + Log(Debug::Error) << "Couldn't find caster with ID " << state.mActorId; + cleanupMagicBolt(state); + continue; + } + mPhysics->setCaster(state.mProjectileId, caster); + } + } + void ProjectileManager::update(float dt) { periodicCleanup(dt); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index c047d90dd..e4bcae1ae 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -54,6 +54,8 @@ namespace MWWorld void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& pos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength); + void updateCasters(); + void update(float dt); void processHits(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b609f325c..01b90e907 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3186,6 +3186,11 @@ namespace MWWorld mProjectileManager->launchMagicBolt(spellId, caster, fallbackDirection); } + void World::updateProjectilesCasters() + { + mProjectileManager->updateCasters(); + } + class ApplyLoopingParticlesVisitor : public MWMechanics::EffectSourceVisitor { private: diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index bc2baafd8..23153a31c 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -644,6 +644,7 @@ namespace MWWorld void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) override; void launchProjectile (MWWorld::Ptr& actor, MWWorld::Ptr& projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr& bow, float speed, float attackStrength) override; + void updateProjectilesCasters() override; void applyLoopingParticles(const MWWorld::Ptr& ptr) override;