1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-21 06:53:53 +00:00

Merge branch 'awholelottanothing' into 'master'

Don't crash on spells or enchantments without effects

Closes #7712

See merge request OpenMW/openmw!3643
This commit is contained in:
Alexei Kotov 2023-12-11 13:02:51 +00:00
commit ad8392b7d1
7 changed files with 71 additions and 65 deletions

View file

@ -103,6 +103,7 @@
Bug #7665: Alchemy menu is missing the ability to deselect and choose different qualities of an apparatus Bug #7665: Alchemy menu is missing the ability to deselect and choose different qualities of an apparatus
Bug #7675: Successful lock spell doesn't produce a sound Bug #7675: Successful lock spell doesn't produce a sound
Bug #7679: Scene luminance value flashes when toggling shaders Bug #7679: Scene luminance value flashes when toggling shaders
Bug #7712: Casting doesn't support spells and enchantments with no effects
Feature #3537: Shader-based water ripples Feature #3537: Shader-based water ripples
Feature #5492: Let rain and snow collide with statics Feature #5492: Let rain and snow collide with statics
Feature #6149: Dehardcode Lua API_REVISION Feature #6149: Dehardcode Lua API_REVISION

View file

@ -423,17 +423,21 @@ namespace MWGui
mSpellBox->setUserString("Spell", spellId.serialize()); mSpellBox->setUserString("Spell", spellId.serialize());
mSpellBox->setUserData(MyGUI::Any::Null); mSpellBox->setUserData(MyGUI::Any::Null);
// use the icon of the first effect if (!spell->mEffects.mList.empty())
const ESM::MagicEffect* effect = MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find( {
spell->mEffects.mList.front().mEffectID); // use the icon of the first effect
const ESM::MagicEffect* effect = MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(
std::string icon = effect->mIcon; spell->mEffects.mList.front().mEffectID);
std::replace(icon.begin(), icon.end(), '/', '\\'); std::string icon = effect->mIcon;
int slashPos = icon.rfind('\\'); std::replace(icon.begin(), icon.end(), '/', '\\');
icon.insert(slashPos + 1, "b_"); size_t slashPos = icon.rfind('\\');
icon = Misc::ResourceHelpers::correctIconPath(icon, MWBase::Environment::get().getResourceSystem()->getVFS()); icon.insert(slashPos + 1, "b_");
icon = Misc::ResourceHelpers::correctIconPath(
mSpellImage->setSpellIcon(icon); icon, MWBase::Environment::get().getResourceSystem()->getVFS());
mSpellImage->setSpellIcon(icon);
}
else
mSpellImage->setSpellIcon({});
} }
void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent)

View file

@ -202,7 +202,7 @@ namespace MWGui
setIcon(ptr); setIcon(ptr);
} }
void SpellWidget::setSpellIcon(const std::string& icon) void SpellWidget::setSpellIcon(std::string_view icon)
{ {
if (mFrame && !mCurrentFrame.empty()) if (mFrame && !mCurrentFrame.empty())
{ {

View file

@ -58,7 +58,7 @@ namespace MWGui
{ {
MYGUI_RTTI_DERIVED(SpellWidget) MYGUI_RTTI_DERIVED(SpellWidget)
public: public:
void setSpellIcon(const std::string& icon); void setSpellIcon(std::string_view icon);
}; };
} }

View file

@ -237,13 +237,15 @@ namespace MWGui
params.mNoTarget = false; params.mNoTarget = false;
effects.push_back(params); effects.push_back(params);
} }
if (MWMechanics::spellIncreasesSkill( // display school of spells that contribute to skill progress
spell)) // display school of spells that contribute to skill progress if (MWMechanics::spellIncreasesSkill(spell))
{ {
MWWorld::Ptr player = MWMechanics::getPlayer(); ESM::RefId id = MWMechanics::getSpellSchool(spell, MWMechanics::getPlayer());
const auto& school if (!id.empty())
= store->get<ESM::Skill>().find(MWMechanics::getSpellSchool(spell, player))->mSchool; {
info.text = "#{sSchool}: " + MyGUI::TextIterator::toTagsString(school->mName).asUTF8(); const auto& school = store->get<ESM::Skill>().find(id)->mSchool;
info.text = "#{sSchool}: " + MyGUI::TextIterator::toTagsString(school->mName).asUTF8();
}
} }
auto cost = focus->getUserString("SpellCost"); auto cost = focus->getUserString("SpellCost");
if (!cost.empty() && cost != "0") if (!cost.empty() && cost != "0")

View file

@ -1605,18 +1605,19 @@ namespace MWMechanics
effects = &spell->mEffects.mList; effects = &spell->mEffects.mList;
cast.playSpellCastingEffects(spell); cast.playSpellCastingEffects(spell);
} }
if (mCanCast) if (!effects->empty())
{ {
const ESM::MagicEffect* effect = store.get<ESM::MagicEffect>().find( if (mCanCast)
effects->back().mEffectID); // use last effect of list for color of VFX_Hands
const ESM::Static* castStatic
= world->getStore().get<ESM::Static>().find(ESM::RefId::stringRefId("VFX_Hands"));
const VFS::Manager* const vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
if (!effects->empty())
{ {
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
= world->getStore().get<ESM::Static>().find(ESM::RefId::stringRefId("VFX_Hands"));
const VFS::Manager* const vfs
= MWBase::Environment::get().getResourceSystem()->getVFS();
if (mAnimation->getNode("Bip01 L Hand")) if (mAnimation->getNode("Bip01 L Hand"))
mAnimation->addEffect( mAnimation->addEffect(
Misc::ResourceHelpers::correctMeshPath(castStatic->mModel, vfs), -1, false, Misc::ResourceHelpers::correctMeshPath(castStatic->mModel, vfs), -1, false,
@ -1627,44 +1628,44 @@ namespace MWMechanics
Misc::ResourceHelpers::correctMeshPath(castStatic->mModel, vfs), -1, false, Misc::ResourceHelpers::correctMeshPath(castStatic->mModel, vfs), -1, false,
"Bip01 R Hand", effect->mParticle); "Bip01 R Hand", effect->mParticle);
} }
} // first effect used for casting animation
const ESM::ENAMstruct& firstEffect = effects->front();
const ESM::ENAMstruct& firstEffect = effects->at(0); // first effect used for casting animation std::string startKey;
std::string stopKey;
std::string startKey; if (isRandomAttackAnimation(mCurrentWeapon))
std::string stopKey;
if (isRandomAttackAnimation(mCurrentWeapon))
{
startKey = "start";
stopKey = "stop";
if (mCanCast)
world->castSpell(
mPtr, mCastingManualSpell); // No "release" text key to use, so cast immediately
mCastingManualSpell = false;
mCanCast = false;
}
else
{
switch (firstEffect.mRange)
{ {
case 0: startKey = "start";
mAttackType = "self"; stopKey = "stop";
break; if (mCanCast)
case 1: world->castSpell(
mAttackType = "touch"; mPtr, mCastingManualSpell); // No "release" text key to use, so cast immediately
break; mCastingManualSpell = false;
case 2: mCanCast = false;
mAttackType = "target"; }
break; else
{
switch (firstEffect.mRange)
{
case 0:
mAttackType = "self";
break;
case 1:
mAttackType = "touch";
break;
case 2:
mAttackType = "target";
break;
}
startKey = mAttackType + " start";
stopKey = mAttackType + " stop";
} }
startKey = mAttackType + " start"; mAnimation->play(mCurrentWeapon, priorityWeapon, MWRender::Animation::BlendMask_All, false,
stopKey = mAttackType + " stop"; 1, startKey, stopKey, 0.0f, 0);
mUpperBodyState = UpperBodyState::Casting;
} }
mAnimation->play(mCurrentWeapon, priorityWeapon, MWRender::Animation::BlendMask_All, false, 1,
startKey, stopKey, 0.0f, 0);
mUpperBodyState = UpperBodyState::Casting;
} }
else else
{ {

View file

@ -524,11 +524,9 @@ namespace MWWorld
const ESM::Enchantment* enchantment const ESM::Enchantment* enchantment
= MWBase::Environment::get().getESMStore()->get<ESM::Enchantment>().search(enchantmentName); = MWBase::Environment::get().getESMStore()->get<ESM::Enchantment>().search(enchantmentName);
if (!enchantment) if (!enchantment || enchantment->mEffects.mList.empty())
return result; return result;
assert(enchantment->mEffects.mList.size());
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().search( const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().search(
enchantment->mEffects.mList.front().mEffectID); enchantment->mEffects.mList.front().mEffectID);
if (!magicEffect) if (!magicEffect)