diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 5d75cea35..f9c70e7ae 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -982,8 +982,11 @@ namespace MWMechanics /// \todo move update logic to Actor class where appropriate + // make a copy of the map to avoid invalidated iterators when an actor moves during the update + PtrActorMap actors = mActors; + // AI and magic effects update - for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + for(PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) { bool inProcessingRange = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() <= sqrProcessingDistance; @@ -996,6 +999,11 @@ namespace MWMechanics if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) { updateActor(iter->first, duration); + if (MWBase::Environment::get().getWorld()->hasCellChanged()) + { + return; // for now abort update of the old cell when cell changes by teleportation magic effect + // a better solution might be to apply cell changes at the end of the frame + } if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && inProcessingRange) { if (timerUpdateAITargets == 0) @@ -1003,7 +1011,7 @@ namespace MWMechanics if (iter->first != player) adjustCommandedActor(iter->first); - for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) + for(PtrActorMap::iterator it(actors.begin()); it != actors.end(); ++it) { if (it->first == iter->first || iter->first == player) // player is not AI-controlled continue; @@ -1015,7 +1023,7 @@ namespace MWMechanics float sqrHeadTrackDistance = std::numeric_limits::max(); MWWorld::Ptr headTrackTarget; - for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) + for(PtrActorMap::iterator it(actors.begin()); it != actors.end(); ++it) { if (it->first == iter->first) continue; @@ -1050,12 +1058,12 @@ namespace MWMechanics // Reaching the text keys may trigger Hit / Spellcast (and as such, particles), // so updating VFX immediately after that would just remove the particle effects instantly. // There needs to be a magic effect update in between. - for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + for(PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) iter->second->getCharacterController()->updateContinuousVfx(); // Animation/movement update CharacterController* playerCharacter = NULL; - for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + for(PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) { if (iter->first != player && (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2() @@ -1065,20 +1073,10 @@ namespace MWMechanics if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed()) iter->second->getCharacterController()->skipAnim(); - // Handle player last, in case a cell transition occurs by casting a teleportation spell - // (would invalidate the iterator) - if (iter->first == getPlayer()) - { - playerCharacter = iter->second->getCharacterController(); - continue; - } iter->second->getCharacterController()->update(duration); } - if (playerCharacter) - playerCharacter->update(duration); - - for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + for(PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) { const MWWorld::Class &cls = iter->first.getClass(); CreatureStats &stats = cls.getCreatureStats(iter->first); @@ -1136,7 +1134,7 @@ namespace MWMechanics bool detected = false; - for (PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + for (PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) { if (iter->first == player) // not the player continue; @@ -1179,7 +1177,8 @@ namespace MWMechanics void Actors::killDeadActors() { - for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) + PtrActorMap actors = mActors; + for(PtrActorMap::iterator iter(actors.begin()); iter != actors.end(); ++iter) { const MWWorld::Class &cls = iter->first.getClass(); CreatureStats &stats = cls.getCreatureStats(iter->first); @@ -1210,7 +1209,7 @@ namespace MWMechanics ++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())]; // Make sure spell effects are removed - for (PtrActorMap::iterator iter2(mActors.begin());iter2 != mActors.end();++iter2) + for (PtrActorMap::iterator iter2(actors.begin());iter2 != actors.end();++iter2) { MWMechanics::ActiveSpells& spells = iter2->first.getClass().getCreatureStats(iter2->first).getActiveSpells(); spells.purge(stats.getActorId());