mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-30 22:15:32 +00:00
Unify magic effect tick functions
- Removes duplicated code - Handle some zero-duration instant effects that were not handled before (disintegrate, sun damage, elemental damage)
This commit is contained in:
parent
77f1387da8
commit
278a078e9d
7 changed files with 229 additions and 205 deletions
|
@ -129,6 +129,11 @@ namespace MWBase
|
|||
OffenseType type, int arg=0, bool victimAware=false) = 0;
|
||||
/// @return false if the attack was considered a "friendly hit" and forgiven
|
||||
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0;
|
||||
|
||||
/// Notify that actor was killed, add a murder bounty if applicable
|
||||
/// @note No-op for non-player attackers
|
||||
virtual void actorKilled (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0;
|
||||
|
||||
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
||||
/// @param container The container the item is in; may be empty for an item in the world
|
||||
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
|
||||
|
|
|
@ -751,12 +751,7 @@ namespace MWClass
|
|||
attacker.getClass().getNpcStats(attacker).addWerewolfKill();
|
||||
}
|
||||
|
||||
// Simple check for who attacked first: if the player attacked first, a crimeId should be set
|
||||
// Doesn't handle possible edge case where no one reported the assault, but in such a case,
|
||||
// for bystanders it is not possible to tell who attacked first, anyway.
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
if (attacker == player && ptr.getClass().getNpcStats(ptr).getCrimeId() != -1 && ptr != player)
|
||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(player, ptr, MWBase::MechanicsManager::OT_Murder);
|
||||
MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, attacker);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -67,44 +67,6 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a
|
|||
}
|
||||
}
|
||||
|
||||
bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate)
|
||||
{
|
||||
if (ptr.getClass().hasInventoryStore(ptr))
|
||||
{
|
||||
MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr);
|
||||
MWWorld::ContainerStoreIterator item =
|
||||
inv.getSlot(slot);
|
||||
if (item != inv.end())
|
||||
{
|
||||
if (!item->getClass().hasItemHealth(*item))
|
||||
return false;
|
||||
int charge = item->getClass().getItemHealth(*item);
|
||||
|
||||
if (charge == 0)
|
||||
return false;
|
||||
|
||||
// FIXME: charge should be a float, not int so that damage < 1 per frame can be applied.
|
||||
// This was also a bug in the original engine.
|
||||
charge -=
|
||||
std::min(static_cast<int>(disintegrate),
|
||||
charge);
|
||||
item->getCellRef().setCharge(charge);
|
||||
|
||||
if (charge == 0)
|
||||
{
|
||||
// Will unequip the broken item and try to find a replacement
|
||||
if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
inv.autoEquip(ptr);
|
||||
else
|
||||
inv.unequipItem(*item, ptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class CheckActorCommanded : public MWMechanics::EffectSourceVisitor
|
||||
{
|
||||
MWWorld::Ptr mActor;
|
||||
|
@ -516,8 +478,12 @@ namespace MWMechanics
|
|||
|
||||
bool wasDead = creatureStats.isDead();
|
||||
|
||||
// FIXME: effect ticks should go into separate functions so they can be used with either
|
||||
// magnitude (instant effect) or magnitude*duration
|
||||
// tickable effects (i.e. effects having a lasting impact after expiry)
|
||||
// these effects can be applied as "instant" (handled in spellcasting.cpp) or with a duration, handled here
|
||||
for (MagicEffects::Collection::const_iterator it = effects.begin(); it != effects.end(); ++it)
|
||||
{
|
||||
effectTick(creatureStats, ptr, it->first, it->second.getMagnitude() * duration);
|
||||
}
|
||||
|
||||
// attributes
|
||||
for(int i = 0;i < ESM::Attribute::Length;++i)
|
||||
|
@ -527,9 +493,6 @@ namespace MWMechanics
|
|||
effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() -
|
||||
effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()));
|
||||
|
||||
stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration);
|
||||
stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration);
|
||||
|
||||
creatureStats.setAttribute(i, stat);
|
||||
}
|
||||
|
||||
|
@ -559,12 +522,6 @@ namespace MWMechanics
|
|||
// Fatigue can be decreased below zero meaning the actor will be knocked out
|
||||
i == 2);
|
||||
|
||||
|
||||
float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).getMagnitude()
|
||||
- creatureStats.getMagicEffects().get(ESM::MagicEffect::DamageHealth+i).getMagnitude()
|
||||
- creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth+i).getMagnitude();
|
||||
stat.setCurrent(stat.getCurrent() + currentDiff * duration, i == 2);
|
||||
|
||||
creatureStats.setDynamic(i, stat);
|
||||
}
|
||||
|
||||
|
@ -592,90 +549,11 @@ namespace MWMechanics
|
|||
creatureStats.setAiSetting(CreatureStats::AI_Flee, stat);
|
||||
}
|
||||
|
||||
// Apply disintegration (reduces item health)
|
||||
float disintegrateWeapon = effects.get(ESM::MagicEffect::DisintegrateWeapon).getMagnitude();
|
||||
if (disintegrateWeapon > 0)
|
||||
disintegrateSlot(ptr, MWWorld::InventoryStore::Slot_CarriedRight, disintegrateWeapon*duration);
|
||||
float disintegrateArmor = effects.get(ESM::MagicEffect::DisintegrateArmor).getMagnitude();
|
||||
if (disintegrateArmor > 0)
|
||||
{
|
||||
// According to UESP
|
||||
int priorities[] = {
|
||||
MWWorld::InventoryStore::Slot_CarriedLeft,
|
||||
MWWorld::InventoryStore::Slot_Cuirass,
|
||||
MWWorld::InventoryStore::Slot_LeftPauldron,
|
||||
MWWorld::InventoryStore::Slot_RightPauldron,
|
||||
MWWorld::InventoryStore::Slot_LeftGauntlet,
|
||||
MWWorld::InventoryStore::Slot_RightGauntlet,
|
||||
MWWorld::InventoryStore::Slot_Helmet,
|
||||
MWWorld::InventoryStore::Slot_Greaves,
|
||||
MWWorld::InventoryStore::Slot_Boots
|
||||
};
|
||||
|
||||
for (unsigned int i=0; i<sizeof(priorities)/sizeof(int); ++i)
|
||||
{
|
||||
if (disintegrateSlot(ptr, priorities[i], disintegrateArmor*duration))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool receivedMagicDamage = false;
|
||||
|
||||
if (creatureStats.getMagicEffects().get(ESM::MagicEffect::DamageHealth).getMagnitude() > 0.0f
|
||||
|| creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth).getMagnitude() > 0.0f)
|
||||
receivedMagicDamage = true;
|
||||
|
||||
// Apply damage ticks
|
||||
int damageEffects[] = {
|
||||
ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison,
|
||||
ESM::MagicEffect::SunDamage
|
||||
};
|
||||
|
||||
DynamicStat<float> health = creatureStats.getHealth();
|
||||
for (unsigned int i=0; i<sizeof(damageEffects)/sizeof(int); ++i)
|
||||
{
|
||||
float magnitude = creatureStats.getMagicEffects().get(damageEffects[i]).getMagnitude();
|
||||
|
||||
if (damageEffects[i] == ESM::MagicEffect::SunDamage)
|
||||
{
|
||||
// isInCell shouldn't be needed, but updateActor called during game start
|
||||
if (!ptr.isInCell() || !ptr.getCell()->isExterior())
|
||||
continue;
|
||||
float time = MWBase::Environment::get().getWorld()->getTimeStamp().getHour();
|
||||
float timeDiff = std::min(7.f, std::max(0.f, std::abs(time - 13)));
|
||||
float damageScale = 1.f - timeDiff / 7.f;
|
||||
// When cloudy, the sun damage effect is halved
|
||||
static float fMagicSunBlockedMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||
"fMagicSunBlockedMult")->getFloat();
|
||||
|
||||
int weather = MWBase::Environment::get().getWorld()->getCurrentWeather();
|
||||
if (weather > 1)
|
||||
damageScale *= fMagicSunBlockedMult;
|
||||
health.setCurrent(health.getCurrent() - magnitude * duration * damageScale);
|
||||
|
||||
if (magnitude * damageScale > 0.0f)
|
||||
receivedMagicDamage = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
health.setCurrent(health.getCurrent() - magnitude * duration);
|
||||
|
||||
if (magnitude > 0.0f)
|
||||
receivedMagicDamage = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (receivedMagicDamage && ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
MWBase::Environment::get().getWindowManager()->activateHitOverlay(false);
|
||||
|
||||
creatureStats.setHealth(health);
|
||||
|
||||
if (!wasDead && creatureStats.isDead())
|
||||
{
|
||||
// The actor was killed by a magic effect. Figure out if the player was responsible for it.
|
||||
const ActiveSpells& spells = creatureStats.getActiveSpells();
|
||||
bool killedByPlayer = false;
|
||||
bool murderedByPlayer = false;
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
for (ActiveSpells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
||||
{
|
||||
|
@ -685,33 +563,29 @@ namespace MWMechanics
|
|||
{
|
||||
int effectId = effectIt->mEffectId;
|
||||
bool isDamageEffect = false;
|
||||
|
||||
int damageEffects[] = {
|
||||
ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison,
|
||||
ESM::MagicEffect::SunDamage, ESM::MagicEffect::DamageHealth, ESM::MagicEffect::AbsorbHealth
|
||||
};
|
||||
|
||||
for (unsigned int i=0; i<sizeof(damageEffects)/sizeof(int); ++i)
|
||||
{
|
||||
if (damageEffects[i] == effectId)
|
||||
isDamageEffect = true;
|
||||
}
|
||||
|
||||
|
||||
if (effectId == ESM::MagicEffect::DamageHealth || effectId == ESM::MagicEffect::AbsorbHealth)
|
||||
isDamageEffect = true;
|
||||
|
||||
MWWorld::Ptr caster = MWBase::Environment::get().getWorld()->searchPtrViaActorId(spell.mCasterActorId);
|
||||
if (isDamageEffect && caster == player)
|
||||
{
|
||||
killedByPlayer = true;
|
||||
// Simple check for who attacked first: if the player attacked first, a crimeId should be set
|
||||
// Doesn't handle possible edge case where no one reported the assault, but in such a case,
|
||||
// for bystanders it is not possible to tell who attacked first, anyway.
|
||||
if (ptr.getClass().isNpc() && ptr.getClass().getNpcStats(ptr).getCrimeId() != -1
|
||||
&& ptr != player)
|
||||
murderedByPlayer = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (murderedByPlayer)
|
||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(player, ptr, MWBase::MechanicsManager::OT_Murder);
|
||||
if (killedByPlayer && player.getClass().getNpcStats(player).isWerewolf())
|
||||
player.getClass().getNpcStats(player).addWerewolfKill();
|
||||
if (killedByPlayer)
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, player);
|
||||
if (player.getClass().getNpcStats(player).isWerewolf())
|
||||
player.getClass().getNpcStats(player).addWerewolfKill();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: dirty flag for magic effects to avoid some unnecessary work below?
|
||||
|
@ -795,9 +669,6 @@ namespace MWMechanics
|
|||
skill.setModifier(static_cast<int>(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() -
|
||||
effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() -
|
||||
effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()));
|
||||
|
||||
skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration);
|
||||
skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1330,6 +1330,27 @@ namespace MWMechanics
|
|||
return true;
|
||||
}
|
||||
|
||||
void MechanicsManager::actorKilled(const MWWorld::Ptr &victim, const MWWorld::Ptr &attacker)
|
||||
{
|
||||
if (attacker.isEmpty() || attacker != MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
return;
|
||||
|
||||
if (victim == attacker)
|
||||
return; // known to happen
|
||||
|
||||
if (!victim.getClass().isNpc())
|
||||
return; // TODO: implement animal rights
|
||||
|
||||
const MWMechanics::NpcStats& victimStats = victim.getClass().getNpcStats(victim);
|
||||
|
||||
// Simple check for who attacked first: if the player attacked first, a crimeId should be set
|
||||
// Doesn't handle possible edge case where no one reported the assault, but in such a case,
|
||||
// for bystanders it is not possible to tell who attacked first, anyway.
|
||||
if (victimStats.getCrimeId() != -1)
|
||||
MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, victim, MWBase::MechanicsManager::OT_Murder);
|
||||
|
||||
}
|
||||
|
||||
bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer)
|
||||
{
|
||||
if (observer.getClass().getCreatureStats(observer).isDead() || !observer.getRefData().isEnabled())
|
||||
|
|
|
@ -120,6 +120,11 @@ namespace MWMechanics
|
|||
OffenseType type, int arg=0, bool victimAware=false);
|
||||
/// @return false if the attack was considered a "friendly hit" and forgiven
|
||||
virtual bool actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
|
||||
|
||||
/// Notify that actor was killed, add a murder bounty if applicable
|
||||
/// @note No-op for non-player attackers
|
||||
virtual void actorKilled (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
|
||||
|
||||
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
||||
/// @param container The container the item is in; may be empty for an item in the world
|
||||
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "../mwrender/animation.hpp"
|
||||
|
||||
#include "magiceffects.hpp"
|
||||
|
@ -65,57 +67,6 @@ namespace
|
|||
target.getClass().getCreatureStats(target).setDynamic(attribute, value);
|
||||
}
|
||||
|
||||
// TODO: refactor the effect tick functions in Actors so they can be reused here
|
||||
void applyInstantEffectTick(MWMechanics::EffectKey effect, const MWWorld::Ptr& target, float magnitude)
|
||||
{
|
||||
int effectId = effect.mId;
|
||||
if (effectId == ESM::MagicEffect::DamageHealth)
|
||||
{
|
||||
applyDynamicStatsEffect(0, target, magnitude * -1);
|
||||
}
|
||||
else if (effectId == ESM::MagicEffect::RestoreHealth)
|
||||
{
|
||||
applyDynamicStatsEffect(0, target, magnitude);
|
||||
}
|
||||
else if (effectId == ESM::MagicEffect::DamageFatigue)
|
||||
{
|
||||
applyDynamicStatsEffect(2, target, magnitude * -1);
|
||||
}
|
||||
else if (effectId == ESM::MagicEffect::RestoreFatigue)
|
||||
{
|
||||
applyDynamicStatsEffect(2, target, magnitude);
|
||||
}
|
||||
else if (effectId == ESM::MagicEffect::DamageMagicka)
|
||||
{
|
||||
applyDynamicStatsEffect(1, target, magnitude * -1);
|
||||
}
|
||||
else if (effectId == ESM::MagicEffect::RestoreMagicka)
|
||||
{
|
||||
applyDynamicStatsEffect(1, target, magnitude);
|
||||
}
|
||||
else if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute)
|
||||
{
|
||||
int attribute = effect.mArg;
|
||||
MWMechanics::AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute);
|
||||
if (effectId == ESM::MagicEffect::DamageAttribute)
|
||||
value.damage(magnitude);
|
||||
else
|
||||
value.restore(magnitude);
|
||||
target.getClass().getCreatureStats(target).setAttribute(attribute, value);
|
||||
}
|
||||
else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill)
|
||||
{
|
||||
if (target.getTypeName() != typeid(ESM::NPC).name())
|
||||
return;
|
||||
int skill = effect.mArg;
|
||||
MWMechanics::SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill);
|
||||
if (effectId == ESM::MagicEffect::DamageSkill)
|
||||
value.damage(magnitude);
|
||||
else
|
||||
value.restore(magnitude);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
|
@ -530,7 +481,14 @@ namespace MWMechanics
|
|||
else
|
||||
{
|
||||
if (hasDuration && target.getClass().isActor())
|
||||
applyInstantEffectTick(EffectKey(*effectIt), target, magnitude);
|
||||
{
|
||||
bool wasDead = target.getClass().getCreatureStats(target).isDead();
|
||||
effectTick(target.getClass().getCreatureStats(target), target, EffectKey(*effectIt), magnitude);
|
||||
bool isDead = target.getClass().getCreatureStats(target).isDead();
|
||||
|
||||
if (!wasDead && isDead)
|
||||
MWBase::Environment::get().getMechanicsManager()->actorKilled(target, caster);
|
||||
}
|
||||
else
|
||||
applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude);
|
||||
}
|
||||
|
@ -960,4 +918,170 @@ namespace MWMechanics
|
|||
|| (effectId >= ESM::MagicEffect::SummonFabricant
|
||||
&& effectId <= ESM::MagicEffect::SummonCreature05));
|
||||
}
|
||||
|
||||
bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate)
|
||||
{
|
||||
if (ptr.getClass().hasInventoryStore(ptr))
|
||||
{
|
||||
MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr);
|
||||
MWWorld::ContainerStoreIterator item =
|
||||
inv.getSlot(slot);
|
||||
if (item != inv.end())
|
||||
{
|
||||
if (!item->getClass().hasItemHealth(*item))
|
||||
return false;
|
||||
int charge = item->getClass().getItemHealth(*item);
|
||||
|
||||
if (charge == 0)
|
||||
return false;
|
||||
|
||||
// FIXME: charge should be a float, not int so that damage < 1 per frame can be applied.
|
||||
// This was also a bug in the original engine.
|
||||
charge -=
|
||||
std::min(static_cast<int>(disintegrate),
|
||||
charge);
|
||||
item->getCellRef().setCharge(charge);
|
||||
|
||||
if (charge == 0)
|
||||
{
|
||||
// Will unequip the broken item and try to find a replacement
|
||||
if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
inv.autoEquip(ptr);
|
||||
else
|
||||
inv.unequipItem(*item, ptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void adjustDynamicStat(CreatureStats& creatureStats, int index, float magnitude)
|
||||
{
|
||||
DynamicStat<float> stat = creatureStats.getDynamic(index);
|
||||
stat.setCurrent(stat.getCurrent() + magnitude, index == 2);
|
||||
creatureStats.setDynamic(index, stat);
|
||||
}
|
||||
|
||||
void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey &effectKey, float magnitude)
|
||||
{
|
||||
if (magnitude == 0.f)
|
||||
return;
|
||||
|
||||
bool receivedMagicDamage = false;
|
||||
|
||||
switch (effectKey.mId)
|
||||
{
|
||||
case ESM::MagicEffect::DamageAttribute:
|
||||
{
|
||||
AttributeValue attr = creatureStats.getAttribute(effectKey.mArg);
|
||||
attr.damage(magnitude);
|
||||
creatureStats.setAttribute(effectKey.mArg, attr);
|
||||
break;
|
||||
}
|
||||
case ESM::MagicEffect::RestoreAttribute:
|
||||
{
|
||||
AttributeValue attr = creatureStats.getAttribute(effectKey.mArg);
|
||||
attr.restore(magnitude);
|
||||
creatureStats.setAttribute(effectKey.mArg, attr);
|
||||
break;
|
||||
}
|
||||
case ESM::MagicEffect::RestoreHealth:
|
||||
case ESM::MagicEffect::RestoreMagicka:
|
||||
case ESM::MagicEffect::RestoreFatigue:
|
||||
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::RestoreHealth, magnitude);
|
||||
break;
|
||||
case ESM::MagicEffect::DamageHealth:
|
||||
case ESM::MagicEffect::DamageMagicka:
|
||||
case ESM::MagicEffect::DamageFatigue:
|
||||
receivedMagicDamage = true;
|
||||
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude);
|
||||
break;
|
||||
case ESM::MagicEffect::AbsorbHealth:
|
||||
case ESM::MagicEffect::AbsorbMagicka:
|
||||
case ESM::MagicEffect::AbsorbFatigue:
|
||||
if (magnitude > 0.f)
|
||||
receivedMagicDamage = true;
|
||||
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude);
|
||||
break;
|
||||
|
||||
case ESM::MagicEffect::DisintegrateArmor:
|
||||
{
|
||||
// According to UESP
|
||||
int priorities[] = {
|
||||
MWWorld::InventoryStore::Slot_CarriedLeft,
|
||||
MWWorld::InventoryStore::Slot_Cuirass,
|
||||
MWWorld::InventoryStore::Slot_LeftPauldron,
|
||||
MWWorld::InventoryStore::Slot_RightPauldron,
|
||||
MWWorld::InventoryStore::Slot_LeftGauntlet,
|
||||
MWWorld::InventoryStore::Slot_RightGauntlet,
|
||||
MWWorld::InventoryStore::Slot_Helmet,
|
||||
MWWorld::InventoryStore::Slot_Greaves,
|
||||
MWWorld::InventoryStore::Slot_Boots
|
||||
};
|
||||
|
||||
for (unsigned int i=0; i<sizeof(priorities)/sizeof(int); ++i)
|
||||
{
|
||||
if (disintegrateSlot(actor, priorities[i], magnitude))
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESM::MagicEffect::DisintegrateWeapon:
|
||||
disintegrateSlot(actor, MWWorld::InventoryStore::Slot_CarriedRight, magnitude);
|
||||
break;
|
||||
|
||||
case ESM::MagicEffect::SunDamage:
|
||||
{
|
||||
// isInCell shouldn't be needed, but updateActor called during game start
|
||||
if (!actor.isInCell() || !actor.getCell()->isExterior())
|
||||
break;
|
||||
float time = MWBase::Environment::get().getWorld()->getTimeStamp().getHour();
|
||||
float timeDiff = std::min(7.f, std::max(0.f, std::abs(time - 13)));
|
||||
float damageScale = 1.f - timeDiff / 7.f;
|
||||
// When cloudy, the sun damage effect is halved
|
||||
static float fMagicSunBlockedMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||
"fMagicSunBlockedMult")->getFloat();
|
||||
|
||||
int weather = MWBase::Environment::get().getWorld()->getCurrentWeather();
|
||||
if (weather > 1)
|
||||
damageScale *= fMagicSunBlockedMult;
|
||||
|
||||
adjustDynamicStat(creatureStats, 0, -magnitude * damageScale);
|
||||
if (magnitude * damageScale > 0.f)
|
||||
receivedMagicDamage = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case ESM::MagicEffect::FireDamage:
|
||||
case ESM::MagicEffect::ShockDamage:
|
||||
case ESM::MagicEffect::FrostDamage:
|
||||
case ESM::MagicEffect::Poison:
|
||||
{
|
||||
adjustDynamicStat(creatureStats, 0, -magnitude);
|
||||
receivedMagicDamage = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case ESM::MagicEffect::DamageSkill:
|
||||
case ESM::MagicEffect::RestoreSkill:
|
||||
{
|
||||
if (!actor.getClass().isNpc())
|
||||
break;
|
||||
NpcStats &npcStats = actor.getClass().getNpcStats(actor);
|
||||
SkillValue& skill = npcStats.getSkill(effectKey.mArg);
|
||||
if (effectKey.mId == ESM::MagicEffect::RestoreSkill)
|
||||
skill.restore(magnitude);
|
||||
else
|
||||
skill.damage(magnitude);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (receivedMagicDamage && actor == MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
MWBase::Environment::get().getWindowManager()->activateHitOverlay(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace MWMechanics
|
|||
{
|
||||
struct EffectKey;
|
||||
class MagicEffects;
|
||||
class CreatureStats;
|
||||
|
||||
ESM::Skill::SkillEnum spellSchoolToSkill(int school);
|
||||
|
||||
|
@ -60,6 +61,8 @@ namespace MWMechanics
|
|||
|
||||
int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor);
|
||||
|
||||
void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude);
|
||||
|
||||
class CastSpell
|
||||
{
|
||||
private:
|
||||
|
|
Loading…
Reference in a new issue