mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-22 23:11:33 +00:00
Keep showing NPC health while dealing damage
This commit is contained in:
parent
7a0a11b30c
commit
f68e7ce0b5
4 changed files with 52 additions and 27 deletions
|
@ -6,6 +6,7 @@
|
||||||
Bug #5057: Weapon swing sound plays at same pitch whether it hits or misses
|
Bug #5057: Weapon swing sound plays at same pitch whether it hits or misses
|
||||||
Bug #5129: Stuttering animation on Centurion Archer
|
Bug #5129: Stuttering animation on Centurion Archer
|
||||||
Bug #5977: Fatigueless NPCs' corpse underwater changes animation on game load
|
Bug #5977: Fatigueless NPCs' corpse underwater changes animation on game load
|
||||||
|
Bug #6427: Enemy health bar disappears before damaging effect ends
|
||||||
Bug #6937: Divided by Nix Hounds quest is broken
|
Bug #6937: Divided by Nix Hounds quest is broken
|
||||||
Bug #6939: OpenMW-CS: ID columns are too short
|
Bug #6939: OpenMW-CS: ID columns are too short
|
||||||
Bug #6949: Sun Damage effect doesn't work in quasi exteriors
|
Bug #6949: Sun Damage effect doesn't work in quasi exteriors
|
||||||
|
|
|
@ -13,11 +13,13 @@
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
#include "actorutil.hpp"
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "spellcasting.hpp"
|
#include "spellcasting.hpp"
|
||||||
#include "spelleffects.hpp"
|
#include "spelleffects.hpp"
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
#include "../mwrender/animation.hpp"
|
#include "../mwrender/animation.hpp"
|
||||||
|
@ -230,6 +232,9 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
|
bool updatedHitOverlay = false;
|
||||||
|
bool updatedEnemy = false;
|
||||||
// Update effects
|
// Update effects
|
||||||
for(auto spellIt = mSpells.begin(); spellIt != mSpells.end();)
|
for(auto spellIt = mSpells.begin(); spellIt != mSpells.end();)
|
||||||
{
|
{
|
||||||
|
@ -239,7 +244,7 @@ namespace MWMechanics
|
||||||
for(auto it = spellIt->mEffects.begin(); it != spellIt->mEffects.end();)
|
for(auto it = spellIt->mEffects.begin(); it != spellIt->mEffects.end();)
|
||||||
{
|
{
|
||||||
auto result = applyMagicEffect(ptr, caster, *spellIt, *it, duration);
|
auto result = applyMagicEffect(ptr, caster, *spellIt, *it, duration);
|
||||||
if(result == MagicApplicationResult::REFLECTED)
|
if(result.mType == MagicApplicationResult::Type::REFLECTED)
|
||||||
{
|
{
|
||||||
if(!reflected)
|
if(!reflected)
|
||||||
{
|
{
|
||||||
|
@ -253,10 +258,22 @@ namespace MWMechanics
|
||||||
reflectedEffect.mFlags = ESM::ActiveEffect::Flag_Ignore_Reflect | ESM::ActiveEffect::Flag_Ignore_SpellAbsorption;
|
reflectedEffect.mFlags = ESM::ActiveEffect::Flag_Ignore_Reflect | ESM::ActiveEffect::Flag_Ignore_SpellAbsorption;
|
||||||
it = spellIt->mEffects.erase(it);
|
it = spellIt->mEffects.erase(it);
|
||||||
}
|
}
|
||||||
else if(result == MagicApplicationResult::REMOVED)
|
else if(result.mType == MagicApplicationResult::Type::REMOVED)
|
||||||
it = spellIt->mEffects.erase(it);
|
it = spellIt->mEffects.erase(it);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
++it;
|
++it;
|
||||||
|
if(!updatedEnemy && result.mShowHealth && caster == player && ptr != player)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->setEnemy(ptr);
|
||||||
|
updatedEnemy = true;
|
||||||
|
}
|
||||||
|
if(!updatedHitOverlay && result.mShowHit && ptr == player)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->activateHitOverlay(false);
|
||||||
|
updatedHitOverlay = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
removedSpell = applyPurges(ptr, &spellIt, &it);
|
removedSpell = applyPurges(ptr, &spellIt, &it);
|
||||||
if(removedSpell)
|
if(removedSpell)
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -299,7 +299,7 @@ namespace
|
||||||
stats.setMagicka(magicka);
|
stats.setMagicka(magicka);
|
||||||
}
|
}
|
||||||
|
|
||||||
MWMechanics::MagicApplicationResult applyProtections(const MWWorld::Ptr& target, const MWWorld::Ptr& caster,
|
MWMechanics::MagicApplicationResult::Type applyProtections(const MWWorld::Ptr& target, const MWWorld::Ptr& caster,
|
||||||
const MWMechanics::ActiveSpells::ActiveSpellParams& spellParams, ESM::ActiveEffect& effect, const ESM::MagicEffect* magicEffect)
|
const MWMechanics::ActiveSpells::ActiveSpellParams& spellParams, ESM::ActiveEffect& effect, const ESM::MagicEffect* magicEffect)
|
||||||
{
|
{
|
||||||
auto& stats = target.getClass().getCreatureStats(target);
|
auto& stats = target.getClass().getCreatureStats(target);
|
||||||
|
@ -323,7 +323,7 @@ namespace
|
||||||
{
|
{
|
||||||
if(canReflect && Misc::Rng::roll0to99(prng) < activeEffect.mMagnitude)
|
if(canReflect && Misc::Rng::roll0to99(prng) < activeEffect.mMagnitude)
|
||||||
{
|
{
|
||||||
return MWMechanics::MagicApplicationResult::REFLECTED;
|
return MWMechanics::MagicApplicationResult::Type::REFLECTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(activeEffect.mEffectId == ESM::MagicEffect::SpellAbsorption)
|
else if(activeEffect.mEffectId == ESM::MagicEffect::SpellAbsorption)
|
||||||
|
@ -331,7 +331,7 @@ namespace
|
||||||
if(canAbsorb && Misc::Rng::roll0to99(prng) < activeEffect.mMagnitude)
|
if(canAbsorb && Misc::Rng::roll0to99(prng) < activeEffect.mMagnitude)
|
||||||
{
|
{
|
||||||
absorbSpell(spellParams.getId(), caster, target);
|
absorbSpell(spellParams.getId(), caster, target);
|
||||||
return MWMechanics::MagicApplicationResult::REMOVED;
|
return MWMechanics::MagicApplicationResult::Type::REMOVED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,12 +356,12 @@ namespace
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}");
|
||||||
else if (caster == MWMechanics::getPlayer())
|
else if (caster == MWMechanics::getPlayer())
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResisted}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResisted}");
|
||||||
return MWMechanics::MagicApplicationResult::REMOVED;
|
return MWMechanics::MagicApplicationResult::Type::REMOVED;
|
||||||
}
|
}
|
||||||
effect.mMinMagnitude *= magnitudeMult;
|
effect.mMinMagnitude *= magnitudeMult;
|
||||||
effect.mMaxMagnitude *= magnitudeMult;
|
effect.mMaxMagnitude *= magnitudeMult;
|
||||||
}
|
}
|
||||||
return MWMechanics::MagicApplicationResult::APPLIED;
|
return MWMechanics::MagicApplicationResult::Type::APPLIED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::map<int, std::string> sBoundItemsMap{
|
static const std::map<int, std::string> sBoundItemsMap{
|
||||||
|
@ -382,7 +382,7 @@ namespace
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
|
||||||
void applyMagicEffect(const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const ActiveSpells::ActiveSpellParams& spellParams, ESM::ActiveEffect& effect, bool& invalid, bool& receivedMagicDamage, bool& recalculateMagicka)
|
void applyMagicEffect(const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const ActiveSpells::ActiveSpellParams& spellParams, ESM::ActiveEffect& effect, bool& invalid, bool& receivedMagicDamage, bool& affectedHealth, bool& recalculateMagicka)
|
||||||
{
|
{
|
||||||
const auto world = MWBase::Environment::get().getWorld();
|
const auto world = MWBase::Environment::get().getWorld();
|
||||||
bool godmode = target == getPlayer() && world->getGodModeState();
|
bool godmode = target == getPlayer() && world->getGodModeState();
|
||||||
|
@ -606,7 +606,7 @@ void applyMagicEffect(const MWWorld::Ptr& target, const MWWorld::Ptr& caster, co
|
||||||
static const bool uncappedDamageFatigue = Settings::Manager::getBool("uncapped damage fatigue", "Game");
|
static const bool uncappedDamageFatigue = Settings::Manager::getBool("uncapped damage fatigue", "Game");
|
||||||
adjustDynamicStat(target, index, -effect.mMagnitude, index == 2 && uncappedDamageFatigue);
|
adjustDynamicStat(target, index, -effect.mMagnitude, index == 2 && uncappedDamageFatigue);
|
||||||
if(index == 0)
|
if(index == 0)
|
||||||
receivedMagicDamage = true;
|
receivedMagicDamage = affectedHealth = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -641,6 +641,8 @@ void applyMagicEffect(const MWWorld::Ptr& target, const MWWorld::Ptr& caster, co
|
||||||
restoreSkill(target, effect, effect.mMagnitude);
|
restoreSkill(target, effect, effect.mMagnitude);
|
||||||
break;
|
break;
|
||||||
case ESM::MagicEffect::RestoreHealth:
|
case ESM::MagicEffect::RestoreHealth:
|
||||||
|
affectedHealth = true;
|
||||||
|
[[fallthrough]];
|
||||||
case ESM::MagicEffect::RestoreMagicka:
|
case ESM::MagicEffect::RestoreMagicka:
|
||||||
case ESM::MagicEffect::RestoreFatigue:
|
case ESM::MagicEffect::RestoreFatigue:
|
||||||
adjustDynamicStat(target, effect.mEffectId - ESM::MagicEffect::RestoreHealth, effect.mMagnitude);
|
adjustDynamicStat(target, effect.mEffectId - ESM::MagicEffect::RestoreHealth, effect.mMagnitude);
|
||||||
|
@ -662,7 +664,7 @@ void applyMagicEffect(const MWWorld::Ptr& target, const MWWorld::Ptr& caster, co
|
||||||
float damage = effect.mMagnitude * damageScale;
|
float damage = effect.mMagnitude * damageScale;
|
||||||
adjustDynamicStat(target, 0, -damage);
|
adjustDynamicStat(target, 0, -damage);
|
||||||
if (damage > 0.f)
|
if (damage > 0.f)
|
||||||
receivedMagicDamage = true;
|
receivedMagicDamage = affectedHealth = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ESM::MagicEffect::DrainHealth:
|
case ESM::MagicEffect::DrainHealth:
|
||||||
|
@ -674,7 +676,7 @@ void applyMagicEffect(const MWWorld::Ptr& target, const MWWorld::Ptr& caster, co
|
||||||
int index = effect.mEffectId - ESM::MagicEffect::DrainHealth;
|
int index = effect.mEffectId - ESM::MagicEffect::DrainHealth;
|
||||||
adjustDynamicStat(target, index, -effect.mMagnitude, uncappedDamageFatigue && index == 2);
|
adjustDynamicStat(target, index, -effect.mMagnitude, uncappedDamageFatigue && index == 2);
|
||||||
if(index == 0)
|
if(index == 0)
|
||||||
receivedMagicDamage = true;
|
receivedMagicDamage = affectedHealth = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ESM::MagicEffect::FortifyHealth:
|
case ESM::MagicEffect::FortifyHealth:
|
||||||
|
@ -733,7 +735,7 @@ void applyMagicEffect(const MWWorld::Ptr& target, const MWWorld::Ptr& caster, co
|
||||||
if(!caster.isEmpty())
|
if(!caster.isEmpty())
|
||||||
adjustDynamicStat(caster, index, effect.mMagnitude);
|
adjustDynamicStat(caster, index, effect.mMagnitude);
|
||||||
if(index == 0)
|
if(index == 0)
|
||||||
receivedMagicDamage = true;
|
receivedMagicDamage = affectedHealth = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ESM::MagicEffect::AbsorbAttribute:
|
case ESM::MagicEffect::AbsorbAttribute:
|
||||||
|
@ -839,22 +841,23 @@ MagicApplicationResult applyMagicEffect(const MWWorld::Ptr& target, const MWWorl
|
||||||
bool invalid = false;
|
bool invalid = false;
|
||||||
bool receivedMagicDamage = false;
|
bool receivedMagicDamage = false;
|
||||||
bool recalculateMagicka = false;
|
bool recalculateMagicka = false;
|
||||||
|
bool affectedHealth = false;
|
||||||
if(effect.mEffectId == ESM::MagicEffect::Corprus && spellParams.shouldWorsen())
|
if(effect.mEffectId == ESM::MagicEffect::Corprus && spellParams.shouldWorsen())
|
||||||
{
|
{
|
||||||
spellParams.worsen();
|
spellParams.worsen();
|
||||||
for(auto& otherEffect : spellParams.getEffects())
|
for(auto& otherEffect : spellParams.getEffects())
|
||||||
{
|
{
|
||||||
if(isCorprusEffect(otherEffect))
|
if(isCorprusEffect(otherEffect))
|
||||||
applyMagicEffect(target, caster, spellParams, otherEffect, invalid, receivedMagicDamage, recalculateMagicka);
|
applyMagicEffect(target, caster, spellParams, otherEffect, invalid, receivedMagicDamage, affectedHealth, recalculateMagicka);
|
||||||
}
|
}
|
||||||
if(target == getPlayer())
|
if(target == getPlayer())
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicCorprusWorsens}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicCorprusWorsens}");
|
||||||
return MagicApplicationResult::APPLIED;
|
return {MagicApplicationResult::Type::APPLIED, receivedMagicDamage, affectedHealth};
|
||||||
}
|
}
|
||||||
else if(shouldRemoveEffect(target, effect))
|
else if(shouldRemoveEffect(target, effect))
|
||||||
{
|
{
|
||||||
onMagicEffectRemoved(target, spellParams, effect);
|
onMagicEffectRemoved(target, spellParams, effect);
|
||||||
return MagicApplicationResult::REMOVED;
|
return {MagicApplicationResult::Type::REMOVED, receivedMagicDamage, affectedHealth};
|
||||||
}
|
}
|
||||||
const auto* magicEffect = world->getStore().get<ESM::MagicEffect>().find(effect.mEffectId);
|
const auto* magicEffect = world->getStore().get<ESM::MagicEffect>().find(effect.mEffectId);
|
||||||
if(effect.mFlags & ESM::ActiveEffect::Flag_Applied)
|
if(effect.mFlags & ESM::ActiveEffect::Flag_Applied)
|
||||||
|
@ -862,10 +865,10 @@ MagicApplicationResult applyMagicEffect(const MWWorld::Ptr& target, const MWWorl
|
||||||
if(magicEffect->mData.mFlags & ESM::MagicEffect::Flags::AppliedOnce)
|
if(magicEffect->mData.mFlags & ESM::MagicEffect::Flags::AppliedOnce)
|
||||||
{
|
{
|
||||||
effect.mTimeLeft -= dt;
|
effect.mTimeLeft -= dt;
|
||||||
return MagicApplicationResult::APPLIED;
|
return {MagicApplicationResult::Type::APPLIED, receivedMagicDamage, affectedHealth};
|
||||||
}
|
}
|
||||||
else if(!dt)
|
else if(!dt)
|
||||||
return MagicApplicationResult::APPLIED;
|
return {MagicApplicationResult::Type::APPLIED, receivedMagicDamage, affectedHealth};
|
||||||
}
|
}
|
||||||
if(effect.mEffectId == ESM::MagicEffect::Lock)
|
if(effect.mEffectId == ESM::MagicEffect::Lock)
|
||||||
{
|
{
|
||||||
|
@ -925,9 +928,9 @@ MagicApplicationResult applyMagicEffect(const MWWorld::Ptr& target, const MWWorl
|
||||||
auto& magnitudes = stats.getMagicEffects();
|
auto& magnitudes = stats.getMagicEffects();
|
||||||
if(spellParams.getType() != ESM::ActiveSpells::Type_Ability && !(effect.mFlags & ESM::ActiveEffect::Flag_Applied))
|
if(spellParams.getType() != ESM::ActiveSpells::Type_Ability && !(effect.mFlags & ESM::ActiveEffect::Flag_Applied))
|
||||||
{
|
{
|
||||||
MagicApplicationResult result = applyProtections(target, caster, spellParams, effect, magicEffect);
|
MagicApplicationResult::Type result = applyProtections(target, caster, spellParams, effect, magicEffect);
|
||||||
if(result != MagicApplicationResult::APPLIED)
|
if(result != MagicApplicationResult::Type::APPLIED)
|
||||||
return result;
|
return {result, receivedMagicDamage, affectedHealth};
|
||||||
}
|
}
|
||||||
float oldMagnitude = 0.f;
|
float oldMagnitude = 0.f;
|
||||||
if(effect.mFlags & ESM::ActiveEffect::Flag_Applied)
|
if(effect.mFlags & ESM::ActiveEffect::Flag_Applied)
|
||||||
|
@ -956,13 +959,13 @@ MagicApplicationResult applyMagicEffect(const MWWorld::Ptr& target, const MWWorl
|
||||||
effect.mMagnitude = oldMagnitude;
|
effect.mMagnitude = oldMagnitude;
|
||||||
effect.mFlags |= ESM::ActiveEffect::Flag_Applied | ESM::ActiveEffect::Flag_Remove;
|
effect.mFlags |= ESM::ActiveEffect::Flag_Applied | ESM::ActiveEffect::Flag_Remove;
|
||||||
effect.mTimeLeft -= dt;
|
effect.mTimeLeft -= dt;
|
||||||
return MagicApplicationResult::APPLIED;
|
return {MagicApplicationResult::Type::APPLIED, receivedMagicDamage, affectedHealth};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(effect.mEffectId == ESM::MagicEffect::Corprus)
|
if(effect.mEffectId == ESM::MagicEffect::Corprus)
|
||||||
spellParams.worsen();
|
spellParams.worsen();
|
||||||
else
|
else
|
||||||
applyMagicEffect(target, caster, spellParams, effect, invalid, receivedMagicDamage, recalculateMagicka);
|
applyMagicEffect(target, caster, spellParams, effect, invalid, receivedMagicDamage, affectedHealth, recalculateMagicka);
|
||||||
effect.mMagnitude = magnitude;
|
effect.mMagnitude = magnitude;
|
||||||
magnitudes.add(EffectKey(effect.mEffectId, effect.mArg), EffectParam(effect.mMagnitude - oldMagnitude));
|
magnitudes.add(EffectKey(effect.mEffectId, effect.mArg), EffectParam(effect.mMagnitude - oldMagnitude));
|
||||||
}
|
}
|
||||||
|
@ -977,11 +980,9 @@ MagicApplicationResult applyMagicEffect(const MWWorld::Ptr& target, const MWWorl
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
effect.mFlags |= ESM::ActiveEffect::Flag_Applied | ESM::ActiveEffect::Flag_Remove;
|
effect.mFlags |= ESM::ActiveEffect::Flag_Applied | ESM::ActiveEffect::Flag_Remove;
|
||||||
if (receivedMagicDamage && target == getPlayer())
|
|
||||||
MWBase::Environment::get().getWindowManager()->activateHitOverlay(false);
|
|
||||||
if(recalculateMagicka)
|
if(recalculateMagicka)
|
||||||
target.getClass().getCreatureStats(target).recalculateMagicka();
|
target.getClass().getCreatureStats(target).recalculateMagicka();
|
||||||
return MagicApplicationResult::APPLIED;
|
return {MagicApplicationResult::Type::APPLIED, receivedMagicDamage, affectedHealth};
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeMagicEffect(const MWWorld::Ptr& target, ActiveSpells::ActiveSpellParams& spellParams, const ESM::ActiveEffect& effect)
|
void removeMagicEffect(const MWWorld::Ptr& target, ActiveSpells::ActiveSpellParams& spellParams, const ESM::ActiveEffect& effect)
|
||||||
|
|
|
@ -13,9 +13,15 @@ namespace MWWorld
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
enum class MagicApplicationResult
|
struct MagicApplicationResult
|
||||||
{
|
{
|
||||||
APPLIED, REMOVED, REFLECTED
|
enum class Type
|
||||||
|
{
|
||||||
|
APPLIED, REMOVED, REFLECTED
|
||||||
|
};
|
||||||
|
Type mType;
|
||||||
|
bool mShowHit;
|
||||||
|
bool mShowHealth;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Applies a tick of a single effect. Returns true if the effect should be removed immediately
|
// Applies a tick of a single effect. Returns true if the effect should be removed immediately
|
||||||
|
|
Loading…
Reference in a new issue