1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-30 03:32:36 +00:00
OpenMW/apps/openmw/mwgui/spellcreationdialog.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

773 lines
28 KiB
C++
Raw Normal View History

2012-09-23 00:36:20 +02:00
#include "spellcreationdialog.hpp"
#include <MyGUI_Button.h>
2015-01-10 02:50:43 +01:00
#include <MyGUI_Gui.h>
#include <MyGUI_ImageBox.h>
#include <MyGUI_ScrollBar.h>
2015-01-10 02:50:43 +01:00
#include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp>
2015-01-10 03:56:06 +01:00
#include <components/widgets/list.hpp>
#include <components/esm3/loadgmst.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp"
2012-09-23 00:36:20 +02:00
#include "../mwbase/windowmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/store.hpp"
2012-09-23 00:36:20 +02:00
#include "../mwmechanics/actorutil.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/spellutil.hpp"
2012-10-23 11:42:38 +02:00
2012-10-03 15:06:54 +02:00
#include "class.hpp"
2012-09-23 00:36:20 +02:00
#include "tooltips.hpp"
2015-01-10 03:56:06 +01:00
#include "widgets.hpp"
2012-09-23 00:36:20 +02:00
namespace
{
bool sortMagicEffects(short id1, short id2)
{
const MWWorld::Store<ESM::GameSetting>& gmst
2023-04-20 21:07:53 +02:00
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
2023-05-23 19:06:08 +02:00
return gmst.find(ESM::MagicEffect::indexToGmstString(id1))->mValue.getString()
< gmst.find(ESM::MagicEffect::indexToGmstString(id2))->mValue.getString();
2012-09-23 00:36:20 +02:00
}
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;
}
2012-09-23 00:36:20 +02:00
}
namespace MWGui
{
EditEffectDialog::EditEffectDialog()
: WindowModal("openmw_edit_effect.layout")
2012-10-03 15:06:54 +02:00
, mEditing(false)
2018-10-09 10:21:12 +04:00
, mMagicEffect(nullptr)
, mConstantEffect(false)
2012-09-24 08:09:16 +02:00
{
init(mEffect);
init(mOldEffect);
2012-09-24 08:09:16 +02:00
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");
2012-10-11 18:26:29 +02:00
getWidget(mDurationBox, "DurationBox");
getWidget(mAreaBox, "AreaBox");
getWidget(mMagnitudeBox, "MagnitudeBox");
2012-09-24 08:09:16 +02:00
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);
2012-10-11 18:26:29 +02:00
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;
2012-09-24 08:09:16 +02:00
}
void EditEffectDialog::onOpen()
2012-09-24 08:09:16 +02:00
{
WindowModal::onOpen();
2012-09-24 08:09:16 +02:00
center();
}
2017-09-23 12:18:39 +02:00
bool EditEffectDialog::exit()
{
if (mEditing)
eventEffectModified(mOldEffect);
else
eventEffectRemoved(mEffect);
2017-09-23 12:18:39 +02:00
return true;
}
2012-10-03 15:06:54 +02:00
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;
2012-10-03 15:06:54 +02:00
setMagicEffect(effect);
mEditing = false;
mDeleteButton->setVisible(false);
2012-10-11 18:26:29 +02:00
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);
2012-10-11 18:26:29 +02:00
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");
2012-10-11 18:26:29 +02:00
mAreaValue->setCaption("0");
setVisible(true);
2012-10-03 15:06:54 +02:00
}
void EditEffectDialog::editEffect(ESM::ENAMstruct effect)
{
const ESM::MagicEffect* magicEffect
2023-04-20 21:07:53 +02:00
= MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(effect.mEffectID);
2012-10-03 15:06:54 +02:00
setMagicEffect(magicEffect);
mOldEffect = effect;
2012-10-03 15:06:54 +02:00
mEffect = effect;
mEditing = true;
mDeleteButton->setVisible(true);
2012-10-11 18:26:29 +02:00
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}");
2012-10-11 18:26:29 +02:00
onMagnitudeMinChanged(mMagnitudeMinSlider, effect.mMagnMin - 1);
onMagnitudeMaxChanged(mMagnitudeMinSlider, effect.mMagnMax - 1);
onAreaChanged(mAreaSlider, effect.mArea);
onDurationChanged(mDurationSlider, effect.mDuration - 1);
eventEffectModified(mEffect);
updateBoxes();
2012-10-03 15:06:54 +02:00
}
void EditEffectDialog::setMagicEffect(const ESM::MagicEffect* effect)
2012-09-24 08:09:16 +02:00
{
mEffectImage->setImageTexture(Misc::ResourceHelpers::correctIconPath(
effect->mIcon, MWBase::Environment::get().getResourceSystem()->getVFS()));
2012-09-24 08:09:16 +02:00
2023-05-23 19:06:08 +02:00
mEffectName->setCaptionWithReplacing("#{" + ESM::MagicEffect::indexToGmstString(effect->mIndex) + "}");
2012-10-03 15:06:54 +02:00
mEffect.mEffectID = effect->mIndex;
2012-10-11 18:26:29 +02:00
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)
2012-10-11 18:26:29 +02:00
{
mDurationBox->setPosition(mDurationBox->getPosition().left, curY);
mDurationBox->setVisible(true);
curY += mDurationBox->getSize().height;
}
if (mEffect.mRange != ESM::RT_Self)
2012-10-11 18:26:29 +02:00
{
mAreaBox->setPosition(mAreaBox->getPosition().left, curY);
mAreaBox->setVisible(true);
2014-09-26 17:12:48 +02:00
// curY += mAreaBox->getSize().height;
2012-10-11 18:26:29 +02:00
}
2012-09-24 08:09:16 +02:00
}
void EditEffectDialog::onRangeButtonClicked(MyGUI::Widget* sender)
{
mEffect.mRange = (mEffect.mRange + 1) % 3;
2012-09-24 08:09:16 +02:00
2012-10-11 18:26:29 +02:00
// 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;
2012-10-11 18:26:29 +02:00
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}");
2012-10-11 18:26:29 +02:00
updateBoxes();
eventEffectModified(mEffect);
2012-09-24 08:09:16 +02:00
}
void EditEffectDialog::onDeleteButtonClicked(MyGUI::Widget* sender)
{
2012-10-03 15:06:54 +02:00
setVisible(false);
2012-09-24 08:09:16 +02:00
2012-10-03 15:06:54 +02:00
eventEffectRemoved(mEffect);
2012-09-24 08:09:16 +02:00
}
void EditEffectDialog::onOkButtonClicked(MyGUI::Widget* sender)
{
setVisible(false);
}
void EditEffectDialog::onCancelButtonClicked(MyGUI::Widget* sender)
{
2017-09-23 12:18:39 +02:00
setVisible(false);
exit();
2012-09-24 08:09:16 +02:00
}
2023-06-06 17:24:22 +02:00
void EditEffectDialog::setSkill(ESM::RefId skill)
2012-10-03 15:06:54 +02:00
{
mEffect.mSkill = ESM::Skill::refIdToIndex(skill);
eventEffectModified(mEffect);
2012-10-03 15:06:54 +02:00
}
void EditEffectDialog::setAttribute(int attribute)
{
mEffect.mAttribute = attribute;
eventEffectModified(mEffect);
2012-10-03 15:06:54 +02:00
}
2012-10-11 18:26:29 +02:00
void EditEffectDialog::onMagnitudeMinChanged(MyGUI::ScrollBar* sender, size_t pos)
{
mMagnitudeMinValue->setCaption(MyGUI::utility::toString(pos + 1));
2012-10-11 18:26:29 +02:00
mEffect.mMagnMin = pos + 1;
// trigger the check again (see below)
onMagnitudeMaxChanged(mMagnitudeMaxSlider, mMagnitudeMaxSlider->getScrollPosition());
eventEffectModified(mEffect);
2012-10-11 18:26:29 +02:00
}
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", "-") };
2012-10-11 18:26:29 +02:00
mMagnitudeMaxValue->setCaption(to + " " + MyGUI::utility::toString(pos + 1));
eventEffectModified(mEffect);
2012-10-11 18:26:29 +02:00
}
void EditEffectDialog::onDurationChanged(MyGUI::ScrollBar* sender, size_t pos)
{
mDurationValue->setCaption(MyGUI::utility::toString(pos + 1));
2012-10-11 18:26:29 +02:00
mEffect.mDuration = pos + 1;
eventEffectModified(mEffect);
2012-10-11 18:26:29 +02:00
}
void EditEffectDialog::onAreaChanged(MyGUI::ScrollBar* sender, size_t pos)
{
mAreaValue->setCaption(MyGUI::utility::toString(pos));
2012-10-11 18:26:29 +02:00
mEffect.mArea = pos;
eventEffectModified(mEffect);
2012-10-11 18:26:29 +02:00
}
2012-09-24 08:09:16 +02:00
// ------------------------------------------------------------------------------------------------
SpellCreationDialog::SpellCreationDialog()
: WindowBase("openmw_spellcreation_dialog.layout")
, EffectEditorBase(EffectEditorBase::Spellmaking)
2012-09-23 00:36:20 +02:00
{
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);
2012-09-24 08:09:16 +02:00
setWidgets(mAvailableEffectsList, mUsedEffectsView);
}
2012-10-03 15:06:54 +02:00
void SpellCreationDialog::setPtr(const MWWorld::Ptr& actor)
{
mPtr = actor;
mNameEdit->setCaption({});
startEditing();
2012-09-23 00:36:20 +02:00
}
void SpellCreationDialog::onCancelButtonClicked(MyGUI::Widget* sender)
{
2017-09-23 12:18:39 +02:00
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_SpellCreation);
}
void SpellCreationDialog::onBuyButtonClicked(MyGUI::Widget* sender)
{
2012-10-15 21:54:19 +02:00
if (mEffects.size() <= 0)
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage30}");
2012-10-15 21:54:19 +02:00
return;
}
if (mNameEdit->getCaption().empty())
2012-10-15 21:54:19 +02:00
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage10}");
2012-10-15 21:54:19 +02:00
return;
}
2012-10-23 11:42:38 +02:00
if (mMagickaCost->getCaption() == "0")
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sEnchantmentMenu8}");
2012-10-23 11:42:38 +02:00
return;
}
2015-08-21 21:12:39 +12:00
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)
2012-10-23 11:42:38 +02:00
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage18}");
2012-10-23 11:42:38 +02:00
return;
}
2012-10-15 21:54:19 +02:00
mSpell.mName = mNameEdit->getCaption();
2012-10-23 11:42:38 +02:00
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);
2012-10-23 11:42:38 +02:00
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Mysticism Hit"));
2012-10-23 11:42:38 +02:00
2023-04-20 21:07:53 +02:00
const ESM::Spell* spell = MWBase::Environment::get().getESMStore()->insert(mSpell);
2012-10-15 21:54:19 +02:00
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
2012-10-15 21:54:19 +02:00
MWMechanics::Spells& spells = stats.getSpells();
spells.add(spell->mId);
2012-10-15 21:54:19 +02:00
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellCreation);
}
2012-09-23 00:36:20 +02:00
void SpellCreationDialog::onAccept(MyGUI::EditBox* sender)
{
onBuyButtonClicked(sender);
2018-09-10 12:55:00 +04:00
// To do not spam onAccept() again and again
MWBase::Environment::get().getWindowManager()->injectKeyRelease(MyGUI::KeyCode::None);
}
void SpellCreationDialog::onOpen()
2012-09-23 00:36:20 +02:00
{
center();
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit);
2012-09-23 00:36:20 +02:00
}
void SpellCreationDialog::onReferenceUnavailable()
{
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue);
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellCreation);
2012-09-23 00:36:20 +02:00
}
2012-10-23 11:42:38 +02:00
void SpellCreationDialog::notifyEffectsChanged()
{
if (mEffects.empty())
{
mMagickaCost->setCaption("0");
mPriceLabel->setCaption("0");
mSuccessChance->setCaption("0");
return;
}
2012-10-23 11:42:38 +02:00
float y = 0;
2023-04-20 21:07:53 +02:00
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
for (const ESM::ENAMstruct& effect : mEffects)
2012-10-23 11:42:38 +02:00
{
y += std::max(
1.f, MWMechanics::calcEffectCost(effect, nullptr, MWMechanics::EffectCostMethod::PlayerSpell));
if (effect.mRange == ESM::RT_Target)
2012-10-23 11:42:38 +02:00
y *= 1.5;
}
ESM::EffectList effectList;
effectList.mList = mEffects;
mSpell.mEffects = effectList;
mSpell.mData.mCost = int(y);
2012-10-23 11:42:38 +02:00
mSpell.mData.mType = ESM::Spell::ST_Spell;
mSpell.mData.mFlags = 0;
2012-10-23 11:42:38 +02:00
mMagickaCost->setCaption(MyGUI::utility::toString(int(y)));
2012-10-23 11:42:38 +02:00
2018-08-29 18:38:12 +03:00
float fSpellMakingValueMult = store.get<ESM::GameSetting>().find("fSpellMakingValueMult")->mValue.getFloat();
2012-10-23 11:42:38 +02:00
int price = std::max(1, static_cast<int>(y * fSpellMakingValueMult));
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true);
2012-10-23 11:42:38 +02:00
mPriceLabel->setCaption(MyGUI::utility::toString(int(price)));
2012-10-23 11:42:38 +02:00
2018-10-09 10:21:12 +04:00
float chance = MWMechanics::calcSpellBaseSuccessChance(&mSpell, MWMechanics::getPlayer(), nullptr);
int intChance = std::min(100, int(chance));
mSuccessChance->setCaption(MyGUI::utility::toString(intChance));
2012-10-23 11:42:38 +02:00
}
// ------------------------------------------------------------------------------------------------
EffectEditorBase::EffectEditorBase(Type type)
2018-10-09 10:21:12 +04:00
: mAvailableEffectsList(nullptr)
, mUsedEffectsView(nullptr)
, mAddEffectDialog()
, mSelectedEffect(0)
, mSelectedKnownEffectId(0)
, mConstantEffect(false)
, mType(type)
2012-09-23 00:36:20 +02:00
{
mAddEffectDialog.eventEffectAdded += MyGUI::newDelegate(this, &EffectEditorBase::onEffectAdded);
mAddEffectDialog.eventEffectModified += MyGUI::newDelegate(this, &EffectEditorBase::onEffectModified);
mAddEffectDialog.eventEffectRemoved += MyGUI::newDelegate(this, &EffectEditorBase::onEffectRemoved);
mAddEffectDialog.setVisible(false);
}
2012-09-23 00:36:20 +02:00
EffectEditorBase::~EffectEditorBase() {}
void EffectEditorBase::startEditing()
{
2012-09-23 00:36:20 +02:00
// get the list of magic effects that are known to the player
2015-08-21 21:12:39 +12:00
MWWorld::Ptr player = MWMechanics::getPlayer();
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
2012-09-23 00:36:20 +02:00
MWMechanics::Spells& spells = stats.getSpells();
std::vector<short> knownEffects;
for (const ESM::Spell* spell : spells)
2012-09-23 00:36:20 +02:00
{
// only normal spells count
if (spell->mData.mType != ESM::Spell::ST_Spell)
2012-09-23 00:36:20 +02:00
continue;
for (const ESM::ENAMstruct& effectInfo : spell->mEffects.mList)
2012-09-23 00:36:20 +02:00
{
const ESM::MagicEffect* effect
2023-04-20 21:07:53 +02:00
= 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);
2012-09-23 00:36:20 +02:00
}
}
std::sort(knownEffects.begin(), knownEffects.end(), sortMagicEffects);
mAvailableEffectsList->clear();
2013-03-28 17:41:00 +01:00
int i = 0;
for (const short effectId : knownEffects)
2012-09-23 00:36:20 +02:00
{
mAvailableEffectsList->addItem(MWBase::Environment::get()
2023-04-20 21:07:53 +02:00
.getESMStore()
->get<ESM::GameSetting>()
2023-05-23 19:06:08 +02:00
.find(ESM::MagicEffect::indexToGmstString(effectId))
->mValue.getString());
mButtonMapping[i] = effectId;
2013-03-28 17:41:00 +01:00
++i;
2012-09-23 00:36:20 +02:00
}
mAvailableEffectsList->adjustSize();
mAvailableEffectsList->scrollToTop();
2012-09-23 00:36:20 +02:00
for (const short effectId : knownEffects)
2012-09-23 00:36:20 +02:00
{
2022-08-28 15:06:31 +02:00
const std::string& name = MWBase::Environment::get()
2023-04-20 21:07:53 +02:00
.getESMStore()
->get<ESM::GameSetting>()
2023-05-23 19:06:08 +02:00
.find(ESM::MagicEffect::indexToGmstString(effectId))
->mValue.getString();
2012-09-23 00:36:20 +02:00
MyGUI::Widget* w = mAvailableEffectsList->getItemWidget(name);
ToolTips::createMagicEffectToolTip(w, effectId);
2012-09-23 00:36:20 +02:00
}
2012-10-15 21:54:19 +02:00
mEffects.clear();
updateEffectsView();
2012-09-23 00:36:20 +02:00
}
void EffectEditorBase::setWidgets(Gui::MWList* availableEffectsList, MyGUI::ScrollView* usedEffectsView)
2012-09-23 00:36:20 +02:00
{
mAvailableEffectsList = availableEffectsList;
mUsedEffectsView = usedEffectsView;
2012-09-23 00:36:20 +02:00
mAvailableEffectsList->eventWidgetSelected
+= MyGUI::newDelegate(this, &EffectEditorBase::onAvailableEffectClicked);
2012-09-23 00:36:20 +02:00
}
void EffectEditorBase::onSelectAttribute()
2012-10-03 15:06:54 +02:00
{
const ESM::MagicEffect* effect
2023-04-20 21:07:53 +02:00
= MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(mSelectedKnownEffectId);
mAddEffectDialog.newEffect(effect);
2012-10-03 15:06:54 +02:00
mAddEffectDialog.setAttribute(mSelectAttributeDialog->getAttributeId());
MWBase::Environment::get().getWindowManager()->removeDialog(std::move(mSelectAttributeDialog));
2012-10-03 15:06:54 +02:00
}
void EffectEditorBase::onSelectSkill()
2012-10-03 15:06:54 +02:00
{
const ESM::MagicEffect* effect
2023-04-20 21:07:53 +02:00
= MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(mSelectedKnownEffectId);
mAddEffectDialog.newEffect(effect);
mAddEffectDialog.setSkill(mSelectSkillDialog->getSkillId());
MWBase::Environment::get().getWindowManager()->removeDialog(std::move(mSelectSkillDialog));
2012-10-03 15:06:54 +02:00
}
void EffectEditorBase::onAttributeOrSkillCancel()
2012-10-03 15:06:54 +02:00
{
if (mSelectSkillDialog != nullptr)
MWBase::Environment::get().getWindowManager()->removeDialog(std::move(mSelectSkillDialog));
if (mSelectAttributeDialog != nullptr)
MWBase::Environment::get().getWindowManager()->removeDialog(std::move(mSelectAttributeDialog));
2012-10-03 15:06:54 +02:00
}
void EffectEditorBase::onAvailableEffectClicked(MyGUI::Widget* sender)
2012-09-24 08:09:16 +02:00
{
2012-10-23 11:42:38 +02:00
if (mEffects.size() >= 8)
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage28}");
2012-10-23 11:42:38 +02:00
return;
}
2012-09-24 08:09:16 +02:00
2013-03-28 17:41:00 +01:00
int buttonId = *sender->getUserData<int>();
mSelectedKnownEffectId = mButtonMapping[buttonId];
2012-10-15 21:54:19 +02:00
const ESM::MagicEffect* effect
2023-04-20 21:07:53 +02:00
= MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(mSelectedKnownEffectId);
2022-02-28 16:42:22 +01:00
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?
2012-10-03 15:06:54 +02:00
if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill)
{
mSelectSkillDialog = std::make_unique<SelectSkillDialog>();
2012-10-03 15:06:54 +02:00
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>();
2012-10-03 15:06:54 +02:00
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);
2012-10-03 15:06:54 +02:00
}
2012-09-24 08:09:16 +02:00
}
void EffectEditorBase::onEffectModified(ESM::ENAMstruct effect)
2012-10-03 15:06:54 +02:00
{
mEffects[mSelectedEffect] = effect;
updateEffectsView();
}
void EffectEditorBase::onEffectRemoved(ESM::ENAMstruct effect)
2012-10-03 15:06:54 +02:00
{
mEffects.erase(mEffects.begin() + mSelectedEffect);
updateEffectsView();
}
void EffectEditorBase::updateEffectsView()
2012-10-03 15:06:54 +02:00
{
MyGUI::EnumeratorWidgetPtr oldWidgets = mUsedEffectsView->getEnumerator();
MyGUI::Gui::getInstance().destroyWidgets(oldWidgets);
MyGUI::IntSize size(0, 0);
int i = 0;
for (const ESM::ENAMstruct& effectInfo : mEffects)
2012-10-03 15:06:54 +02:00
{
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;
2012-10-03 15:06:54 +02:00
MyGUI::Button* button = mUsedEffectsView->createWidget<MyGUI::Button>(
{}, MyGUI::IntCoord(0, size.height, 0, 24), MyGUI::Align::Default);
2012-10-03 15:06:54 +02:00
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);
2012-10-03 15:06:54 +02:00
mUsedEffectsView->setCanvasSize(size);
mUsedEffectsView->setVisibleHScroll(true);
2012-10-23 11:42:38 +02:00
notifyEffectsChanged();
2012-10-03 15:06:54 +02:00
}
void EffectEditorBase::onEffectAdded(ESM::ENAMstruct effect)
2012-10-03 15:06:54 +02:00
{
mEffects.push_back(effect);
mSelectedEffect = mEffects.size() - 1;
2012-10-03 15:06:54 +02:00
updateEffectsView();
}
void EffectEditorBase::onEditEffect(MyGUI::Widget* sender)
2012-10-03 15:06:54 +02:00
{
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)
{
2023-04-20 21:07:53 +02:00
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;
}
}
2012-09-23 00:36:20 +02:00
}