mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-04 03:40:14 +00:00
Merge pull request #2309 from akortunov/enchant_animations
Add an option to use casting animations for magic items
This commit is contained in:
commit
e9f6c11cc9
@ -70,6 +70,7 @@
|
|||||||
Feature #4859: Make water reflections more configurable
|
Feature #4859: Make water reflections more configurable
|
||||||
Feature #4887: Add openmw command option to set initial random seed
|
Feature #4887: Add openmw command option to set initial random seed
|
||||||
Feature #4890: Make Distant Terrain configurable
|
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 #4686: Upgrade media decoder to a more current FFmpeg API
|
||||||
Task #4695: Optimize Distant Terrain memory consumption
|
Task #4695: Optimize Distant Terrain memory consumption
|
||||||
|
|
||||||
|
@ -1195,7 +1195,7 @@ bool CharacterController::updateCreatureState()
|
|||||||
if (!spellid.empty() && canCast)
|
if (!spellid.empty() && canCast)
|
||||||
{
|
{
|
||||||
MWMechanics::CastSpell cast(mPtr, nullptr, false, mCastingManualSpell);
|
MWMechanics::CastSpell cast(mPtr, nullptr, false, mCastingManualSpell);
|
||||||
cast.playSpellCastingEffects(spellid);
|
cast.playSpellCastingEffects(spellid, false);
|
||||||
|
|
||||||
if (!mAnimation->hasAnimation("spellcast"))
|
if (!mAnimation->hasAnimation("spellcast"))
|
||||||
{
|
{
|
||||||
@ -1515,23 +1515,53 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||||||
stats.getSpells().setSelectedSpell(selectedSpell);
|
stats.getSpells().setSelectedSpell(selectedSpell);
|
||||||
}
|
}
|
||||||
std::string spellid = stats.getSpells().getSelectedSpell();
|
std::string spellid = stats.getSpells().getSelectedSpell();
|
||||||
|
bool isMagicItem = false;
|
||||||
bool canCast = mCastingManualSpell || MWBase::Environment::get().getWorld()->startSpellCast(mPtr);
|
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);
|
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 MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
|
if (isMagicItem)
|
||||||
const ESM::ENAMstruct &lastEffect = spell->mEffects.mList.back();
|
{
|
||||||
const ESM::MagicEffect *effect;
|
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");
|
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"))
|
if (mAnimation->getNode("Bip01 L Hand"))
|
||||||
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle);
|
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);
|
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 startKey;
|
||||||
std::string stopKey;
|
std::string stopKey;
|
||||||
@ -1574,17 +1604,6 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||||||
{
|
{
|
||||||
resetIdle = false;
|
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)
|
else if(mWeaponType == WeapType_PickProbe)
|
||||||
{
|
{
|
||||||
|
@ -971,7 +971,7 @@ namespace MWMechanics
|
|||||||
|
|
||||||
// A non-actor doesn't play its spell cast effects from a character controller, so play them here
|
// A non-actor doesn't play its spell cast effects from a character controller, so play them here
|
||||||
if (!mCaster.getClass().isActor())
|
if (!mCaster.getClass().isActor())
|
||||||
playSpellCastingEffects(mId);
|
playSpellCastingEffects(mId, false);
|
||||||
|
|
||||||
inflict(mCaster, mCaster, spell->mEffects, ESM::RT_Self);
|
inflict(mCaster, mCaster, spell->mEffects, ESM::RT_Self);
|
||||||
|
|
||||||
@ -1046,15 +1046,27 @@ namespace MWMechanics
|
|||||||
return true;
|
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 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
|
||||||
|
playSpellCastingEffects(spell->mEffects.mList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CastSpell::playSpellCastingEffects(const std::vector<ESM::ENAMstruct>& effects)
|
||||||
|
{
|
||||||
|
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
std::vector<std::string> addedEffects;
|
std::vector<std::string> addedEffects;
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator iter = effects.begin(); iter != effects.end(); ++iter)
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator iter = spell->mEffects.mList.begin();
|
|
||||||
iter != spell->mEffects.mList.end(); ++iter)
|
|
||||||
{
|
{
|
||||||
const ESM::MagicEffect *effect;
|
const ESM::MagicEffect *effect;
|
||||||
effect = store.get<ESM::MagicEffect>().find(iter->mEffectID);
|
effect = store.get<ESM::MagicEffect>().find(iter->mEffectID);
|
||||||
|
@ -83,6 +83,9 @@ namespace MWMechanics
|
|||||||
private:
|
private:
|
||||||
MWWorld::Ptr mCaster; // May be empty
|
MWWorld::Ptr mCaster; // May be empty
|
||||||
MWWorld::Ptr mTarget; // May be empty
|
MWWorld::Ptr mTarget; // May be empty
|
||||||
|
|
||||||
|
void playSpellCastingEffects(const std::vector<ESM::ENAMstruct>& effects);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool mStack;
|
bool mStack;
|
||||||
std::string mId; // ID of spell, potion, item etc
|
std::string mId; // ID of spell, potion, item etc
|
||||||
@ -109,7 +112,7 @@ namespace MWMechanics
|
|||||||
/// @note Auto detects if spell, ingredient or potion
|
/// @note Auto detects if spell, ingredient or potion
|
||||||
bool cast (const std::string& id);
|
bool cast (const std::string& id);
|
||||||
|
|
||||||
void playSpellCastingEffects(const std::string &spellid);
|
void playSpellCastingEffects(const std::string &spellid, bool enchantment);
|
||||||
|
|
||||||
bool spellIncreasesSkill();
|
bool spellIncreasesSkill();
|
||||||
|
|
||||||
|
@ -1098,7 +1098,7 @@ namespace MWScript
|
|||||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr (targetId, false);
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr (targetId, false);
|
||||||
|
|
||||||
MWMechanics::CastSpell cast(ptr, target, false, true);
|
MWMechanics::CastSpell cast(ptr, target, false, true);
|
||||||
cast.playSpellCastingEffects(spell->mId);
|
cast.playSpellCastingEffects(spell->mId, false);
|
||||||
cast.mHitPosition = target.getRefData().getPosition().asVec3();
|
cast.mHitPosition = target.getRefData().getPosition().asVec3();
|
||||||
cast.mAlwaysSucceed = true;
|
cast.mAlwaysSucceed = true;
|
||||||
cast.cast(spell);
|
cast.cast(spell);
|
||||||
|
@ -126,6 +126,18 @@ This is how Morrowind behaves.
|
|||||||
|
|
||||||
This setting can be toggled in Advanced tab of the launcher.
|
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
|
show effect duration
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
@ -261,6 +261,9 @@ weapon sheathing = false
|
|||||||
# Allow non-standard ammunition solely to bypass normal weapon resistance or weakness
|
# Allow non-standard ammunition solely to bypass normal weapon resistance or weakness
|
||||||
only appropriate ammunition bypasses resistance = false
|
only appropriate ammunition bypasses resistance = false
|
||||||
|
|
||||||
|
# Use casting animations for magic items, just as for spells
|
||||||
|
use magic item animations = false
|
||||||
|
|
||||||
[General]
|
[General]
|
||||||
|
|
||||||
# Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16).
|
# Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16).
|
||||||
|
Loading…
x
Reference in New Issue
Block a user