Merge pull request #2508 from akortunov/counter

Handle death event manually if needed before disposing a corpse
pull/541/head
Alexei Dobrohotov 5 years ago committed by GitHub
commit a8f5fe3eff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

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

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

@ -7,12 +7,15 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/scriptmanager.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "../mwscript/interpretercontext.hpp"
#include "countdialog.hpp" #include "countdialog.hpp"
#include "inventorywindow.hpp" #include "inventorywindow.hpp"
@ -229,7 +232,26 @@ namespace MWGui
if (mPtr.getClass().isPersistent(mPtr)) if (mPtr.getClass().isPersistent(mPtr))
MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}"); MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}");
else 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); MWBase::Environment::get().getWorld()->deleteObject(mPtr);
}
mPtr = MWWorld::Ptr(); mPtr = MWWorld::Ptr();
} }

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

@ -211,6 +211,8 @@ namespace MWMechanics
virtual float getActorsProcessingRange() const override; virtual float getActorsProcessingRange() const override;
virtual void notifyDied(const MWWorld::Ptr& actor) override;
/// Check if the target actor was detected by an observer /// 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 /// 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; virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) override;

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

@ -19,7 +19,7 @@
<item> <item>
<widget class="QCheckBox" name="canLootDuringDeathAnimationCheckBox"> <widget class="QCheckBox" name="canLootDuringDeathAnimationCheckBox">
<property name="toolTip"> <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>
<property name="text"> <property name="text">
<string>Can loot during death animation</string> <string>Can loot during death animation</string>

Loading…
Cancel
Save