Handle death event manually before disposing a corpse if a death animation was not finished yet (feature #5146)

pull/541/head
Andrei Kortunov 5 years ago
parent 84b3aaedaa
commit b6044d231a

@ -176,6 +176,7 @@
Feature #5122: Use magic glow for enchanted arrows
Feature #5131: Custom skeleton bones
Feature #5132: Unique animations for different weapon types
Feature #5146: Safe Dispose corpse
Task #4686: Upgrade media decoder to a more current FFmpeg API
Task #4695: Optimize Distant Terrain memory consumption
Task #4789: Optimize cell transitions

@ -237,6 +237,8 @@ namespace MWBase
virtual float getActorsProcessingRange() const = 0;
virtual void notifyDied(const MWWorld::Ptr& actor) = 0;
virtual bool onOpen(const MWWorld::Ptr& ptr) = 0;
virtual void onClose(const MWWorld::Ptr& ptr) = 0;

@ -7,12 +7,15 @@
#include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/scriptmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwscript/interpretercontext.hpp"
#include "countdialog.hpp"
#include "inventorywindow.hpp"
@ -229,7 +232,26 @@ namespace MWGui
if (mPtr.getClass().isPersistent(mPtr))
MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}");
else
{
MWMechanics::CreatureStats& creatureStats = mPtr.getClass().getCreatureStats(mPtr);
// If we dispose corpse before end of death animation, we should update death counter counter manually.
// Also we should run actor's script - it may react on actor's death.
if (creatureStats.isDead() && !creatureStats.isDeathAnimationFinished())
{
creatureStats.setDeathAnimationFinished(true);
MWBase::Environment::get().getMechanicsManager()->notifyDied(mPtr);
const std::string script = mPtr.getClass().getScript(mPtr);
if (!script.empty() && MWBase::Environment::get().getWorld()->getScriptsEnabled())
{
MWScript::InterpreterContext interpreterContext (&mPtr.getRefData().getLocals(), mPtr);
MWBase::Environment::get().getScriptManager()->run (script, interpreterContext);
}
}
MWBase::Environment::get().getWorld()->deleteObject(mPtr);
}
mPtr = MWWorld::Ptr();
}

@ -1630,6 +1630,13 @@ namespace MWMechanics
updateCombatMusic();
}
void Actors::notifyDied(const MWWorld::Ptr &actor)
{
actor.getClass().getCreatureStats(actor).notifyDied();
++mDeathCount[Misc::StringUtils::lowerCase(actor.getCellRef().getRefId())];
}
void Actors::killDeadActors()
{
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
@ -1673,9 +1680,7 @@ namespace MWMechanics
}
else if (killResult == CharacterController::Result_DeathAnimJustFinished)
{
iter->first.getClass().getCreatureStats(iter->first).notifyDied();
++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())];
notifyDied(iter->first);
// Reset magic effects and recalculate derived effects
// One case where we need this is to make sure bound items are removed upon death

@ -71,6 +71,8 @@ namespace MWMechanics
PtrActorMap::const_iterator begin() { return mActors.begin(); }
PtrActorMap::const_iterator end() { return mActors.end(); }
void notifyDied(const MWWorld::Ptr &actor);
/// Check if the target actor was detected by an observer
/// If the observer is a non-NPC, check all actors in AI processing distance as observers
bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer);

@ -455,6 +455,11 @@ namespace MWMechanics
}
}
void MechanicsManager::notifyDied(const MWWorld::Ptr& actor)
{
mActors.notifyDied(actor);
}
float MechanicsManager::getActorsProcessingRange() const
{
return mActors.getProcessingRange();

@ -211,6 +211,8 @@ namespace MWMechanics
virtual float getActorsProcessingRange() const override;
virtual void notifyDied(const MWWorld::Ptr& actor) override;
/// Check if the target actor was detected by an observer
/// If the observer is a non-NPC, check all actors in AI processing distance as observers
virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) override;

@ -72,13 +72,10 @@ can loot during death animation
:Default: True
If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation,
if they are not in combat. However disposing corpses during death animation is not recommended -
death counter may not be incremented, and this behaviour can break quests.
This is how Morrowind behaves.
if they are not in combat. In this case we have to increment death counter and run disposed actor's script instantly.
If this setting is false, player has to wait until end of death animation in all cases.
This case is more safe, but makes using of summoned creatures exploit
(looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder.
Makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder.
Conflicts with mannequin mods, which use SkipAnim to prevent end of death animation.
This setting can be toggled in Advanced tab of the launcher.

@ -19,7 +19,7 @@
<item>
<widget class="QCheckBox" name="canLootDuringDeathAnimationCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation, if they are not in combat. However disposing corpses during death animation is not recommended - death counter may not be incremented, and this behaviour can break quests. This is how original Morrowind behaves.&lt;/p&gt;&lt;p&gt;If this setting is false, player has to wait until end of death animation in all cases. This case is more safe, but makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation, if they are not in combat. In this case we have to increment death counter and run disposed actor's script instantly.&lt;/p&gt;&lt;p&gt;If this setting is false, player has to wait until end of death animation in all cases. Makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder. Conflicts with mannequin mods, which use SkipAnim to prevent end of death animation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Can loot during death animation</string>

Loading…
Cancel
Save