1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-27 03:35:27 +00:00
OpenMW/apps/openmw/mwgui/spellcreationdialog.cpp
2023-06-08 18:35:50 +02:00

774 lines
28 KiB
C++

#include "spellcreationdialog.hpp"
#include <MyGUI_Button.h>
#include <MyGUI_Gui.h>
#include <MyGUI_ImageBox.h>
#include <MyGUI_ScrollBar.h>
#include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/widgets/list.hpp>
#include <components/esm3/loadgmst.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/store.hpp"
#include "../mwmechanics/actorutil.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/spellutil.hpp"
#include "class.hpp"
#include "tooltips.hpp"
#include "widgets.hpp"
namespace
{
bool sortMagicEffects(short id1, short id2)
{
const MWWorld::Store<ESM::GameSetting>& gmst
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
return gmst.find(ESM::MagicEffect::indexToGmstString(id1))->mValue.getString()
< gmst.find(ESM::MagicEffect::indexToGmstString(id2))->mValue.getString();
}
void init(ESM::ENAMstruct& effect)
{
effect.mArea = 0;
effect.mDuration = 0;
effect.mEffectID = -1;
effect.mMagnMax = 0;
effect.mMagnMin = 0;
effect.mRange = 0;
effect.mSkill = -1;
effect.mAttribute = -1;
}
}
namespace MWGui
{
EditEffectDialog::EditEffectDialog()
: WindowModal("openmw_edit_effect.layout")
, mEditing(false)
, mMagicEffect(nullptr)
, mConstantEffect(false)
{
init(mEffect);
init(mOldEffect);
getWidget(mCancelButton, "CancelButton");
getWidget(mOkButton, "OkButton");
getWidget(mDeleteButton, "DeleteButton");
getWidget(mRangeButton, "RangeButton");
getWidget(mMagnitudeMinValue, "MagnitudeMinValue");
getWidget(mMagnitudeMaxValue, "MagnitudeMaxValue");
getWidget(mDurationValue, "DurationValue");
getWidget(mAreaValue, "AreaValue");
getWidget(mMagnitudeMinSlider, "MagnitudeMinSlider");
getWidget(mMagnitudeMaxSlider, "MagnitudeMaxSlider");
getWidget(mDurationSlider, "DurationSlider");
getWidget(mAreaSlider, "AreaSlider");
getWidget(mEffectImage, "EffectImage");
getWidget(mEffectName, "EffectName");
getWidget(mAreaText, "AreaText");
getWidget(mDurationBox, "DurationBox");
getWidget(mAreaBox, "AreaBox");
getWidget(mMagnitudeBox, "MagnitudeBox");
mRangeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EditEffectDialog::onRangeButtonClicked);
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EditEffectDialog::onOkButtonClicked);
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EditEffectDialog::onCancelButtonClicked);
mDeleteButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EditEffectDialog::onDeleteButtonClicked);
mMagnitudeMinSlider->eventScrollChangePosition
+= MyGUI::newDelegate(this, &EditEffectDialog::onMagnitudeMinChanged);
mMagnitudeMaxSlider->eventScrollChangePosition
+= MyGUI::newDelegate(this, &EditEffectDialog::onMagnitudeMaxChanged);
mDurationSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onDurationChanged);
mAreaSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onAreaChanged);
}
void EditEffectDialog::setConstantEffect(bool constant)
{
mConstantEffect = constant;
}
void EditEffectDialog::onOpen()
{
WindowModal::onOpen();
center();
}
bool EditEffectDialog::exit()
{
if (mEditing)
eventEffectModified(mOldEffect);
else
eventEffectRemoved(mEffect);
return true;
}
void EditEffectDialog::newEffect(const ESM::MagicEffect* effect)
{
bool allowSelf = (effect->mData.mFlags & ESM::MagicEffect::CastSelf) != 0;
bool allowTouch = (effect->mData.mFlags & ESM::MagicEffect::CastTouch) && !mConstantEffect;
setMagicEffect(effect);
mEditing = false;
mDeleteButton->setVisible(false);
mEffect.mRange = ESM::RT_Self;
if (!allowSelf)
mEffect.mRange = ESM::RT_Touch;
if (!allowTouch)
mEffect.mRange = ESM::RT_Target;
mEffect.mMagnMin = 1;
mEffect.mMagnMax = 1;
mEffect.mDuration = 1;
mEffect.mArea = 0;
mEffect.mSkill = -1;
mEffect.mAttribute = -1;
eventEffectAdded(mEffect);
onRangeButtonClicked(mRangeButton);
mMagnitudeMinSlider->setScrollPosition(0);
mMagnitudeMaxSlider->setScrollPosition(0);
mAreaSlider->setScrollPosition(0);
mDurationSlider->setScrollPosition(0);
mDurationValue->setCaption("1");
mMagnitudeMinValue->setCaption("1");
const std::string to{ MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "-") };
mMagnitudeMaxValue->setCaption(to + " 1");
mAreaValue->setCaption("0");
setVisible(true);
}
void EditEffectDialog::editEffect(ESM::ENAMstruct effect)
{
const ESM::MagicEffect* magicEffect
= MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(effect.mEffectID);
setMagicEffect(magicEffect);
mOldEffect = effect;
mEffect = effect;
mEditing = true;
mDeleteButton->setVisible(true);
mMagnitudeMinSlider->setScrollPosition(effect.mMagnMin - 1);
mMagnitudeMaxSlider->setScrollPosition(effect.mMagnMax - 1);
mAreaSlider->setScrollPosition(effect.mArea);
mDurationSlider->setScrollPosition(effect.mDuration - 1);
if (mEffect.mRange == ESM::RT_Self)
mRangeButton->setCaptionWithReplacing("#{sRangeSelf}");
else if (mEffect.mRange == ESM::RT_Target)
mRangeButton->setCaptionWithReplacing("#{sRangeTarget}");
else if (mEffect.mRange == ESM::RT_Touch)
mRangeButton->setCaptionWithReplacing("#{sRangeTouch}");
onMagnitudeMinChanged(mMagnitudeMinSlider, effect.mMagnMin - 1);
onMagnitudeMaxChanged(mMagnitudeMinSlider, effect.mMagnMax - 1);
onAreaChanged(mAreaSlider, effect.mArea);
onDurationChanged(mDurationSlider, effect.mDuration - 1);
eventEffectModified(mEffect);
updateBoxes();
}
void EditEffectDialog::setMagicEffect(const ESM::MagicEffect* effect)
{
mEffectImage->setImageTexture(Misc::ResourceHelpers::correctIconPath(
effect->mIcon, MWBase::Environment::get().getResourceSystem()->getVFS()));
mEffectName->setCaptionWithReplacing("#{" + ESM::MagicEffect::indexToGmstString(effect->mIndex) + "}");
mEffect.mEffectID = effect->mIndex;
mMagicEffect = effect;
updateBoxes();
}
void EditEffectDialog::updateBoxes()
{
static int startY = mMagnitudeBox->getPosition().top;
int curY = startY;
mMagnitudeBox->setVisible(false);
mDurationBox->setVisible(false);
mAreaBox->setVisible(false);
if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude))
{
mMagnitudeBox->setPosition(mMagnitudeBox->getPosition().left, curY);
mMagnitudeBox->setVisible(true);
curY += mMagnitudeBox->getSize().height;
}
if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) && mConstantEffect == false)
{
mDurationBox->setPosition(mDurationBox->getPosition().left, curY);
mDurationBox->setVisible(true);
curY += mDurationBox->getSize().height;
}
if (mEffect.mRange != ESM::RT_Self)
{
mAreaBox->setPosition(mAreaBox->getPosition().left, curY);
mAreaBox->setVisible(true);
// curY += mAreaBox->getSize().height;
}
}
void EditEffectDialog::onRangeButtonClicked(MyGUI::Widget* sender)
{
mEffect.mRange = (mEffect.mRange + 1) % 3;
// cycle through range types until we find something that's allowed
// does not handle the case where nothing is allowed (this should be prevented before opening the Add Effect
// dialog)
bool allowSelf = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf) != 0;
bool allowTouch = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch) && !mConstantEffect;
bool allowTarget = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTarget) && !mConstantEffect;
if (mEffect.mRange == ESM::RT_Self && !allowSelf)
mEffect.mRange = (mEffect.mRange + 1) % 3;
if (mEffect.mRange == ESM::RT_Touch && !allowTouch)
mEffect.mRange = (mEffect.mRange + 1) % 3;
if (mEffect.mRange == ESM::RT_Target && !allowTarget)
mEffect.mRange = (mEffect.mRange + 1) % 3;
if (mEffect.mRange == ESM::RT_Self)
{
mAreaSlider->setScrollPosition(0);
onAreaChanged(mAreaSlider, 0);
}
if (mEffect.mRange == ESM::RT_Self)
mRangeButton->setCaptionWithReplacing("#{sRangeSelf}");
else if (mEffect.mRange == ESM::RT_Target)
mRangeButton->setCaptionWithReplacing("#{sRangeTarget}");
else if (mEffect.mRange == ESM::RT_Touch)
mRangeButton->setCaptionWithReplacing("#{sRangeTouch}");
updateBoxes();
eventEffectModified(mEffect);
}
void EditEffectDialog::onDeleteButtonClicked(MyGUI::Widget* sender)
{
setVisible(false);
eventEffectRemoved(mEffect);
}
void EditEffectDialog::onOkButtonClicked(MyGUI::Widget* sender)
{
setVisible(false);
}
void EditEffectDialog::onCancelButtonClicked(MyGUI::Widget* sender)
{
setVisible(false);
exit();
}
void EditEffectDialog::setSkill(ESM::RefId skill)
{
mEffect.mSkill = skill.getIf<ESM::IndexRefId>()->getValue();
eventEffectModified(mEffect);
}
void EditEffectDialog::setAttribute(int attribute)
{
mEffect.mAttribute = attribute;
eventEffectModified(mEffect);
}
void EditEffectDialog::onMagnitudeMinChanged(MyGUI::ScrollBar* sender, size_t pos)
{
mMagnitudeMinValue->setCaption(MyGUI::utility::toString(pos + 1));
mEffect.mMagnMin = pos + 1;
// trigger the check again (see below)
onMagnitudeMaxChanged(mMagnitudeMaxSlider, mMagnitudeMaxSlider->getScrollPosition());
eventEffectModified(mEffect);
}
void EditEffectDialog::onMagnitudeMaxChanged(MyGUI::ScrollBar* sender, size_t pos)
{
// make sure the max value is actually larger or equal than the min value
size_t magnMin
= std::abs(mEffect.mMagnMin); // should never be < 0, this is just here to avoid the compiler warning
if (pos + 1 < magnMin)
{
pos = mEffect.mMagnMin - 1;
sender->setScrollPosition(pos);
}
mEffect.mMagnMax = pos + 1;
const std::string to{ MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "-") };
mMagnitudeMaxValue->setCaption(to + " " + MyGUI::utility::toString(pos + 1));
eventEffectModified(mEffect);
}
void EditEffectDialog::onDurationChanged(MyGUI::ScrollBar* sender, size_t pos)
{
mDurationValue->setCaption(MyGUI::utility::toString(pos + 1));
mEffect.mDuration = pos + 1;
eventEffectModified(mEffect);
}
void EditEffectDialog::onAreaChanged(MyGUI::ScrollBar* sender, size_t pos)
{
mAreaValue->setCaption(MyGUI::utility::toString(pos));
mEffect.mArea = pos;
eventEffectModified(mEffect);
}
// ------------------------------------------------------------------------------------------------
SpellCreationDialog::SpellCreationDialog()
: WindowBase("openmw_spellcreation_dialog.layout")
, EffectEditorBase(EffectEditorBase::Spellmaking)
{
getWidget(mNameEdit, "NameEdit");
getWidget(mMagickaCost, "MagickaCost");
getWidget(mSuccessChance, "SuccessChance");
getWidget(mAvailableEffectsList, "AvailableEffects");
getWidget(mUsedEffectsView, "UsedEffects");
getWidget(mPriceLabel, "PriceLabel");
getWidget(mBuyButton, "BuyButton");
getWidget(mCancelButton, "CancelButton");
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellCreationDialog::onCancelButtonClicked);
mBuyButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellCreationDialog::onBuyButtonClicked);
mNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SpellCreationDialog::onAccept);
setWidgets(mAvailableEffectsList, mUsedEffectsView);
}
void SpellCreationDialog::setPtr(const MWWorld::Ptr& actor)
{
mPtr = actor;
mNameEdit->setCaption({});
startEditing();
}
void SpellCreationDialog::onCancelButtonClicked(MyGUI::Widget* sender)
{
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_SpellCreation);
}
void SpellCreationDialog::onBuyButtonClicked(MyGUI::Widget* sender)
{
if (mEffects.size() <= 0)
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage30}");
return;
}
if (mNameEdit->getCaption().empty())
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage10}");
return;
}
if (mMagickaCost->getCaption() == "0")
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sEnchantmentMenu8}");
return;
}
MWWorld::Ptr player = MWMechanics::getPlayer();
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
int price = MyGUI::utility::parseInt(mPriceLabel->getCaption());
if (price > playerGold)
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage18}");
return;
}
mSpell.mName = mNameEdit->getCaption();
player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price);
// add gold to NPC trading gold pool
MWMechanics::CreatureStats& npcStats = mPtr.getClass().getCreatureStats(mPtr);
npcStats.setGoldPool(npcStats.getGoldPool() + price);
MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Mysticism Hit"));
const ESM::Spell* spell = MWBase::Environment::get().getESMStore()->insert(mSpell);
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
MWMechanics::Spells& spells = stats.getSpells();
spells.add(spell->mId);
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellCreation);
}
void SpellCreationDialog::onAccept(MyGUI::EditBox* sender)
{
onBuyButtonClicked(sender);
// To do not spam onAccept() again and again
MWBase::Environment::get().getWindowManager()->injectKeyRelease(MyGUI::KeyCode::None);
}
void SpellCreationDialog::onOpen()
{
center();
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit);
}
void SpellCreationDialog::onReferenceUnavailable()
{
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue);
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellCreation);
}
void SpellCreationDialog::notifyEffectsChanged()
{
if (mEffects.empty())
{
mMagickaCost->setCaption("0");
mPriceLabel->setCaption("0");
mSuccessChance->setCaption("0");
return;
}
float y = 0;
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
for (const ESM::ENAMstruct& effect : mEffects)
{
y += std::max(
1.f, MWMechanics::calcEffectCost(effect, nullptr, MWMechanics::EffectCostMethod::PlayerSpell));
if (effect.mRange == ESM::RT_Target)
y *= 1.5;
}
ESM::EffectList effectList;
effectList.mList = mEffects;
mSpell.mEffects = effectList;
mSpell.mData.mCost = int(y);
mSpell.mData.mType = ESM::Spell::ST_Spell;
mSpell.mData.mFlags = 0;
mMagickaCost->setCaption(MyGUI::utility::toString(int(y)));
float fSpellMakingValueMult = store.get<ESM::GameSetting>().find("fSpellMakingValueMult")->mValue.getFloat();
int price = std::max(1, static_cast<int>(y * fSpellMakingValueMult));
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true);
mPriceLabel->setCaption(MyGUI::utility::toString(int(price)));
float chance = MWMechanics::calcSpellBaseSuccessChance(&mSpell, MWMechanics::getPlayer(), nullptr);
int intChance = std::min(100, int(chance));
mSuccessChance->setCaption(MyGUI::utility::toString(intChance));
}
// ------------------------------------------------------------------------------------------------
EffectEditorBase::EffectEditorBase(Type type)
: mAvailableEffectsList(nullptr)
, mUsedEffectsView(nullptr)
, mAddEffectDialog()
, mSelectedEffect(0)
, mSelectedKnownEffectId(0)
, mConstantEffect(false)
, mType(type)
{
mAddEffectDialog.eventEffectAdded += MyGUI::newDelegate(this, &EffectEditorBase::onEffectAdded);
mAddEffectDialog.eventEffectModified += MyGUI::newDelegate(this, &EffectEditorBase::onEffectModified);
mAddEffectDialog.eventEffectRemoved += MyGUI::newDelegate(this, &EffectEditorBase::onEffectRemoved);
mAddEffectDialog.setVisible(false);
}
EffectEditorBase::~EffectEditorBase() {}
void EffectEditorBase::startEditing()
{
// get the list of magic effects that are known to the player
MWWorld::Ptr player = MWMechanics::getPlayer();
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
MWMechanics::Spells& spells = stats.getSpells();
std::vector<short> knownEffects;
for (const ESM::Spell* spell : spells)
{
// only normal spells count
if (spell->mData.mType != ESM::Spell::ST_Spell)
continue;
for (const ESM::ENAMstruct& effectInfo : spell->mEffects.mList)
{
const ESM::MagicEffect* effect
= MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(effectInfo.mEffectID);
// skip effects that do not allow spellmaking/enchanting
int requiredFlags
= (mType == Spellmaking) ? ESM::MagicEffect::AllowSpellmaking : ESM::MagicEffect::AllowEnchanting;
if (!(effect->mData.mFlags & requiredFlags))
continue;
if (std::find(knownEffects.begin(), knownEffects.end(), effectInfo.mEffectID) == knownEffects.end())
knownEffects.push_back(effectInfo.mEffectID);
}
}
std::sort(knownEffects.begin(), knownEffects.end(), sortMagicEffects);
mAvailableEffectsList->clear();
int i = 0;
for (const short effectId : knownEffects)
{
mAvailableEffectsList->addItem(MWBase::Environment::get()
.getESMStore()
->get<ESM::GameSetting>()
.find(ESM::MagicEffect::indexToGmstString(effectId))
->mValue.getString());
mButtonMapping[i] = effectId;
++i;
}
mAvailableEffectsList->adjustSize();
mAvailableEffectsList->scrollToTop();
for (const short effectId : knownEffects)
{
const std::string& name = MWBase::Environment::get()
.getESMStore()
->get<ESM::GameSetting>()
.find(ESM::MagicEffect::indexToGmstString(effectId))
->mValue.getString();
MyGUI::Widget* w = mAvailableEffectsList->getItemWidget(name);
ToolTips::createMagicEffectToolTip(w, effectId);
}
mEffects.clear();
updateEffectsView();
}
void EffectEditorBase::setWidgets(Gui::MWList* availableEffectsList, MyGUI::ScrollView* usedEffectsView)
{
mAvailableEffectsList = availableEffectsList;
mUsedEffectsView = usedEffectsView;
mAvailableEffectsList->eventWidgetSelected
+= MyGUI::newDelegate(this, &EffectEditorBase::onAvailableEffectClicked);
}
void EffectEditorBase::onSelectAttribute()
{
const ESM::MagicEffect* effect
= MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(mSelectedKnownEffectId);
mAddEffectDialog.newEffect(effect);
mAddEffectDialog.setAttribute(mSelectAttributeDialog->getAttributeId());
MWBase::Environment::get().getWindowManager()->removeDialog(std::move(mSelectAttributeDialog));
}
void EffectEditorBase::onSelectSkill()
{
const ESM::MagicEffect* effect
= MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(mSelectedKnownEffectId);
mAddEffectDialog.newEffect(effect);
mAddEffectDialog.setSkill(mSelectSkillDialog->getSkillId());
MWBase::Environment::get().getWindowManager()->removeDialog(std::move(mSelectSkillDialog));
}
void EffectEditorBase::onAttributeOrSkillCancel()
{
if (mSelectSkillDialog != nullptr)
MWBase::Environment::get().getWindowManager()->removeDialog(std::move(mSelectSkillDialog));
if (mSelectAttributeDialog != nullptr)
MWBase::Environment::get().getWindowManager()->removeDialog(std::move(mSelectAttributeDialog));
}
void EffectEditorBase::onAvailableEffectClicked(MyGUI::Widget* sender)
{
if (mEffects.size() >= 8)
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage28}");
return;
}
int buttonId = *sender->getUserData<int>();
mSelectedKnownEffectId = mButtonMapping[buttonId];
const ESM::MagicEffect* effect
= MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(mSelectedKnownEffectId);
bool allowSelf = (effect->mData.mFlags & ESM::MagicEffect::CastSelf) != 0;
bool allowTouch = (effect->mData.mFlags & ESM::MagicEffect::CastTouch) && !mConstantEffect;
bool allowTarget = (effect->mData.mFlags & ESM::MagicEffect::CastTarget) && !mConstantEffect;
if (!allowSelf && !allowTouch && !allowTarget)
return; // TODO: Show an error message popup?
if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill)
{
mSelectSkillDialog = std::make_unique<SelectSkillDialog>();
mSelectSkillDialog->eventCancel += MyGUI::newDelegate(this, &SpellCreationDialog::onAttributeOrSkillCancel);
mSelectSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &SpellCreationDialog::onSelectSkill);
mSelectSkillDialog->setVisible(true);
}
else if (effect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
{
mSelectAttributeDialog = std::make_unique<SelectAttributeDialog>();
mSelectAttributeDialog->eventCancel
+= MyGUI::newDelegate(this, &SpellCreationDialog::onAttributeOrSkillCancel);
mSelectAttributeDialog->eventItemSelected
+= MyGUI::newDelegate(this, &SpellCreationDialog::onSelectAttribute);
mSelectAttributeDialog->setVisible(true);
}
else
{
for (const ESM::ENAMstruct& effectInfo : mEffects)
{
if (effectInfo.mEffectID == mSelectedKnownEffectId)
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sOnetypeEffectMessage}");
return;
}
}
mAddEffectDialog.newEffect(effect);
}
}
void EffectEditorBase::onEffectModified(ESM::ENAMstruct effect)
{
mEffects[mSelectedEffect] = effect;
updateEffectsView();
}
void EffectEditorBase::onEffectRemoved(ESM::ENAMstruct effect)
{
mEffects.erase(mEffects.begin() + mSelectedEffect);
updateEffectsView();
}
void EffectEditorBase::updateEffectsView()
{
MyGUI::EnumeratorWidgetPtr oldWidgets = mUsedEffectsView->getEnumerator();
MyGUI::Gui::getInstance().destroyWidgets(oldWidgets);
MyGUI::IntSize size(0, 0);
int i = 0;
for (const ESM::ENAMstruct& effectInfo : mEffects)
{
Widgets::SpellEffectParams params;
params.mEffectID = effectInfo.mEffectID;
params.mSkill = effectInfo.mSkill;
params.mAttribute = effectInfo.mAttribute;
params.mDuration = effectInfo.mDuration;
params.mMagnMin = effectInfo.mMagnMin;
params.mMagnMax = effectInfo.mMagnMax;
params.mRange = effectInfo.mRange;
params.mArea = effectInfo.mArea;
params.mIsConstant = mConstantEffect;
MyGUI::Button* button = mUsedEffectsView->createWidget<MyGUI::Button>(
{}, MyGUI::IntCoord(0, size.height, 0, 24), MyGUI::Align::Default);
button->setUserData(i);
button->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellCreationDialog::onEditEffect);
button->setNeedMouseFocus(true);
Widgets::MWSpellEffectPtr effect = button->createWidget<Widgets::MWSpellEffect>(
"MW_EffectImage", MyGUI::IntCoord(0, 0, 0, 24), MyGUI::Align::Default);
effect->setNeedMouseFocus(false);
effect->setSpellEffect(params);
effect->setSize(effect->getRequestedWidth(), 24);
button->setSize(effect->getRequestedWidth(), 24);
size.width = std::max(size.width, effect->getRequestedWidth());
size.height += 24;
++i;
}
// Canvas size must be expressed with HScroll disabled, otherwise MyGUI would expand the scroll area when the
// scrollbar is hidden
mUsedEffectsView->setVisibleHScroll(false);
mUsedEffectsView->setCanvasSize(size);
mUsedEffectsView->setVisibleHScroll(true);
notifyEffectsChanged();
}
void EffectEditorBase::onEffectAdded(ESM::ENAMstruct effect)
{
mEffects.push_back(effect);
mSelectedEffect = mEffects.size() - 1;
updateEffectsView();
}
void EffectEditorBase::onEditEffect(MyGUI::Widget* sender)
{
int id = *sender->getUserData<int>();
mSelectedEffect = id;
mAddEffectDialog.editEffect(mEffects[id]);
mAddEffectDialog.setVisible(true);
}
void EffectEditorBase::setConstantEffect(bool constant)
{
mAddEffectDialog.setConstantEffect(constant);
mConstantEffect = constant;
if (!constant)
return;
for (auto it = mEffects.begin(); it != mEffects.end();)
{
if (it->mRange != ESM::RT_Self)
{
auto& store = *MWBase::Environment::get().getESMStore();
auto magicEffect = store.get<ESM::MagicEffect>().find(it->mEffectID);
if ((magicEffect->mData.mFlags & ESM::MagicEffect::CastSelf) == 0)
{
it = mEffects.erase(it);
continue;
}
it->mRange = ESM::RT_Self;
}
++it;
}
}
}