Add an option to use casting animations for magic items (feature #4962)

pull/2309/head
Andrei Kortunov 5 years ago
parent 7808cbbfe8
commit 35facc5cde

@ -68,6 +68,7 @@
Feature #4859: Make water reflections more configurable
Feature #4887: Add openmw command option to set initial random seed
Feature #4890: Make Distant Terrain configurable
Feature #4962: Add casting animations for magic items
Task #4686: Upgrade media decoder to a more current FFmpeg API
Task #4695: Optimize Distant Terrain memory consumption

@ -1195,7 +1195,7 @@ bool CharacterController::updateCreatureState()
if (!spellid.empty() && canCast)
{
MWMechanics::CastSpell cast(mPtr, nullptr, false, mCastingManualSpell);
cast.playSpellCastingEffects(spellid);
cast.playSpellCastingEffects(spellid, false);
if (!mAnimation->hasAnimation("spellcast"))
{
@ -1515,23 +1515,53 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
stats.getSpells().setSelectedSpell(selectedSpell);
}
std::string spellid = stats.getSpells().getSelectedSpell();
bool isMagicItem = false;
bool canCast = mCastingManualSpell || MWBase::Environment::get().getWorld()->startSpellCast(mPtr);
if(!spellid.empty() && canCast)
if (spellid.empty())
{
if (mPtr.getClass().hasInventoryStore(mPtr))
{
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
if (inv.getSelectedEnchantItem() != inv.end())
{
const MWWorld::Ptr& enchantItem = *inv.getSelectedEnchantItem();
spellid = enchantItem.getClass().getEnchantment(enchantItem);
isMagicItem = true;
}
}
}
static const bool useCastingAnimations = Settings::Manager::getBool("use magic item animations", "Game");
if (isMagicItem && !useCastingAnimations)
{
// Enchanted items by default do not use casting animations
MWBase::Environment::get().getWorld()->castSpell(mPtr);
resetIdle = false;
}
else if(!spellid.empty() && canCast)
{
MWMechanics::CastSpell cast(mPtr, nullptr, false, mCastingManualSpell);
cast.playSpellCastingEffects(spellid);
cast.playSpellCastingEffects(spellid, isMagicItem);
std::vector<ESM::ENAMstruct> effects;
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
const ESM::ENAMstruct &lastEffect = spell->mEffects.mList.back();
const ESM::MagicEffect *effect;
if (isMagicItem)
{
const ESM::Enchantment *enchantment = store.get<ESM::Enchantment>().find(spellid);
effects = enchantment->mEffects.mList;
}
else
{
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
effects = spell->mEffects.mList;
}
effect = store.get<ESM::MagicEffect>().find(lastEffect.mEffectID); // use last effect of list for color of VFX_Hands
const ESM::MagicEffect *effect = store.get<ESM::MagicEffect>().find(effects.back().mEffectID); // use last effect of list for color of VFX_Hands
const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_Hands");
for (size_t iter = 0; iter < spell->mEffects.mList.size(); ++iter) // play hands vfx for each effect
for (size_t iter = 0; iter < effects.size(); ++iter) // play hands vfx for each effect
{
if (mAnimation->getNode("Bip01 L Hand"))
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle);
@ -1540,7 +1570,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle);
}
const ESM::ENAMstruct &firstEffect = spell->mEffects.mList.at(0); // first effect used for casting animation
const ESM::ENAMstruct &firstEffect = effects.at(0); // first effect used for casting animation
std::string startKey;
std::string stopKey;
@ -1574,17 +1604,6 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
{
resetIdle = false;
}
if (mPtr.getClass().hasInventoryStore(mPtr))
{
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
if (inv.getSelectedEnchantItem() != inv.end())
{
// Enchanted items cast immediately (no animation)
MWBase::Environment::get().getWorld()->castSpell(mPtr);
}
}
}
else if(mWeaponType == WeapType_PickProbe)
{

@ -972,7 +972,7 @@ namespace MWMechanics
// A non-actor doesn't play its spell cast effects from a character controller, so play them here
if (!mCaster.getClass().isActor())
playSpellCastingEffects(mId);
playSpellCastingEffects(mId, false);
inflict(mCaster, mCaster, spell->mEffects, ESM::RT_Self);
@ -1047,15 +1047,27 @@ namespace MWMechanics
return true;
}
void CastSpell::playSpellCastingEffects(const std::string &spellid)
void CastSpell::playSpellCastingEffects(const std::string &spellid, bool enchantment)
{
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
if (enchantment)
{
const ESM::Enchantment *spell = store.get<ESM::Enchantment>().find(spellid);
playSpellCastingEffects(spell->mEffects.mList);
std::vector<std::string> addedEffects;
}
else
{
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
playSpellCastingEffects(spell->mEffects.mList);
}
}
for (std::vector<ESM::ENAMstruct>::const_iterator iter = spell->mEffects.mList.begin();
iter != spell->mEffects.mList.end(); ++iter)
void CastSpell::playSpellCastingEffects(const std::vector<ESM::ENAMstruct>& effects)
{
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
std::vector<std::string> addedEffects;
for (std::vector<ESM::ENAMstruct>::const_iterator iter = effects.begin(); iter != effects.end(); ++iter)
{
const ESM::MagicEffect *effect;
effect = store.get<ESM::MagicEffect>().find(iter->mEffectID);

@ -83,6 +83,9 @@ namespace MWMechanics
private:
MWWorld::Ptr mCaster; // May be empty
MWWorld::Ptr mTarget; // May be empty
void playSpellCastingEffects(const std::vector<ESM::ENAMstruct>& effects);
public:
bool mStack;
std::string mId; // ID of spell, potion, item etc
@ -109,7 +112,7 @@ namespace MWMechanics
/// @note Auto detects if spell, ingredient or potion
bool cast (const std::string& id);
void playSpellCastingEffects(const std::string &spellid);
void playSpellCastingEffects(const std::string &spellid, bool enchantment);
bool spellIncreasesSkill();

@ -1098,7 +1098,7 @@ namespace MWScript
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr (targetId, false);
MWMechanics::CastSpell cast(ptr, target, false, true);
cast.playSpellCastingEffects(spell->mId);
cast.playSpellCastingEffects(spell->mId, false);
cast.mHitPosition = target.getRefData().getPosition().asVec3();
cast.mAlwaysSucceed = true;
cast.cast(spell);

@ -126,6 +126,18 @@ This is how Morrowind behaves.
This setting can be toggled in Advanced tab of the launcher.
use magic item animations
-------------------------
:Type: boolean
:Range: True/False
:Default: False
If this setting is true, the engine will use casting animations for magic items, including scrolls.
Otherwise, there will be no casting animations, just as in original engine
This setting can only be configured by editing the settings configuration file.
show effect duration
--------------------

@ -261,6 +261,9 @@ weapon sheathing = false
# Allow non-standard ammunition solely to bypass normal weapon resistance or weakness
only appropriate ammunition bypasses resistance = false
# Use casting animations for magic items, just as for spells
use magic item animations = false
[General]
# Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16).

Loading…
Cancel
Save