forked from teamnwah/openmw-tes3coop
Merge remote branch 'scrawl/spellwindow'
This commit is contained in:
commit
2bbbff2b75
23 changed files with 950 additions and 56 deletions
|
@ -28,7 +28,7 @@ add_openmw_dir (mwgui
|
||||||
dialogue_history window_base stats_window messagebox journalwindow charactercreation
|
dialogue_history window_base stats_window messagebox journalwindow charactercreation
|
||||||
map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list
|
map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list
|
||||||
formatting inventorywindow container hud countdialog tradewindow settingswindow
|
formatting inventorywindow container hud countdialog tradewindow settingswindow
|
||||||
confirmationdialog alchemywindow referenceinterface
|
confirmationdialog alchemywindow referenceinterface spellwindow
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwdialogue
|
add_openmw_dir (mwdialogue
|
||||||
|
|
|
@ -347,7 +347,6 @@ void ContainerBase::setFilter(ContainerBase::Filter filter)
|
||||||
void ContainerBase::openContainer(MWWorld::Ptr container)
|
void ContainerBase::openContainer(MWWorld::Ptr container)
|
||||||
{
|
{
|
||||||
mPtr = container;
|
mPtr = container;
|
||||||
drawItems();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerBase::drawItems()
|
void ContainerBase::drawItems()
|
||||||
|
@ -535,6 +534,8 @@ void ContainerBase::drawItems()
|
||||||
MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x+42), mItemView->getSize().height);
|
MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x+42), mItemView->getSize().height);
|
||||||
mItemView->setCanvasSize(size);
|
mItemView->setCanvasSize(size);
|
||||||
mContainerWidget->setSize(size);
|
mContainerWidget->setSize(size);
|
||||||
|
|
||||||
|
notifyContentChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ContainerBase::getCountString(const int count)
|
std::string ContainerBase::getCountString(const int count)
|
||||||
|
@ -636,6 +637,7 @@ void ContainerWindow::open(MWWorld::Ptr container)
|
||||||
{
|
{
|
||||||
openContainer(container);
|
openContainer(container);
|
||||||
setTitle(MWWorld::Class::get(container).getName(container));
|
setTitle(MWWorld::Class::get(container).getName(container));
|
||||||
|
drawItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender)
|
void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender)
|
||||||
|
|
|
@ -120,6 +120,8 @@ namespace MWGui
|
||||||
|
|
||||||
virtual bool ignoreEquippedItems() { return false; }
|
virtual bool ignoreEquippedItems() { return false; }
|
||||||
virtual std::vector<MWWorld::Ptr> itemsToIgnore() { return std::vector<MWWorld::Ptr>(); }
|
virtual std::vector<MWWorld::Ptr> itemsToIgnore() { return std::vector<MWWorld::Ptr>(); }
|
||||||
|
|
||||||
|
virtual void notifyContentChanged() { ; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class ContainerWindow : public ContainerBase, public WindowBase
|
class ContainerWindow : public ContainerBase, public WindowBase
|
||||||
|
|
|
@ -44,15 +44,18 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop)
|
||||||
, mCellNameTimer(0.0f)
|
, mCellNameTimer(0.0f)
|
||||||
, mCellNameBox(NULL)
|
, mCellNameBox(NULL)
|
||||||
, mMapVisible(true)
|
, mMapVisible(true)
|
||||||
|
, mWeaponVisible(true)
|
||||||
|
, mSpellVisible(true)
|
||||||
{
|
{
|
||||||
setCoord(0,0, width, height);
|
setCoord(0,0, width, height);
|
||||||
|
|
||||||
// Energy bars
|
// Energy bars
|
||||||
|
getWidget(mHealthFrame, "HealthFrame");
|
||||||
getWidget(health, "Health");
|
getWidget(health, "Health");
|
||||||
getWidget(magicka, "Magicka");
|
getWidget(magicka, "Magicka");
|
||||||
getWidget(stamina, "Stamina");
|
getWidget(stamina, "Stamina");
|
||||||
|
|
||||||
hmsBaseLeft = health->getLeft();
|
hmsBaseLeft = mHealthFrame->getLeft();
|
||||||
|
|
||||||
MyGUI::Widget *healthFrame, *magickaFrame, *fatigueFrame;
|
MyGUI::Widget *healthFrame, *magickaFrame, *fatigueFrame;
|
||||||
getWidget(healthFrame, "HealthFrame");
|
getWidget(healthFrame, "HealthFrame");
|
||||||
|
@ -62,6 +65,8 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop)
|
||||||
magickaFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked);
|
magickaFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked);
|
||||||
fatigueFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked);
|
fatigueFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked);
|
||||||
|
|
||||||
|
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
|
||||||
|
|
||||||
// Item and spell images and status bars
|
// Item and spell images and status bars
|
||||||
getWidget(weapBox, "WeapBox");
|
getWidget(weapBox, "WeapBox");
|
||||||
getWidget(weapImage, "WeapImage");
|
getWidget(weapImage, "WeapImage");
|
||||||
|
@ -77,16 +82,17 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop)
|
||||||
|
|
||||||
getWidget(effectBox, "EffectBox");
|
getWidget(effectBox, "EffectBox");
|
||||||
getWidget(effect1, "Effect1");
|
getWidget(effect1, "Effect1");
|
||||||
effectBoxBaseRight = effectBox->getRight();
|
effectBoxBaseRight = viewSize.width - effectBox->getRight();
|
||||||
effectBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked);
|
effectBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked);
|
||||||
|
|
||||||
getWidget(minimapBox, "MiniMapBox");
|
getWidget(minimapBox, "MiniMapBox");
|
||||||
minimapBoxBaseRight = minimapBox->getRight();
|
minimapBoxBaseRight = viewSize.width - minimapBox->getRight();
|
||||||
minimapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked);
|
minimapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked);
|
||||||
getWidget(minimap, "MiniMap");
|
getWidget(minimap, "MiniMap");
|
||||||
getWidget(compass, "Compass");
|
getWidget(compass, "Compass");
|
||||||
|
|
||||||
getWidget(mCellNameBox, "CellName");
|
getWidget(mCellNameBox, "CellName");
|
||||||
|
getWidget(mWeaponSpellBox, "WeaponSpellName");
|
||||||
|
|
||||||
getWidget(crosshair, "Crosshair");
|
getWidget(crosshair, "Crosshair");
|
||||||
|
|
||||||
|
@ -95,12 +101,6 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop)
|
||||||
getWidget(trianglecounter, "TriangleCounter");
|
getWidget(trianglecounter, "TriangleCounter");
|
||||||
getWidget(batchcounter, "BatchCounter");
|
getWidget(batchcounter, "BatchCounter");
|
||||||
|
|
||||||
// These are just demo values, you should replace these with
|
|
||||||
// real calls from outside the class later.
|
|
||||||
setWeapIcon("icons\\w\\tx_knife_iron.dds");
|
|
||||||
setWeapStatus(90, 100);
|
|
||||||
setSpellIcon("icons\\s\\b_tx_s_rstor_health.dds");
|
|
||||||
setSpellStatus(65, 100);
|
|
||||||
setEffect("icons\\s\\tx_s_chameleon.dds");
|
setEffect("icons\\s\\tx_s_chameleon.dds");
|
||||||
|
|
||||||
LocalMapBase::init(minimap, compass, this);
|
LocalMapBase::init(minimap, compass, this);
|
||||||
|
@ -112,6 +112,8 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop)
|
||||||
|
|
||||||
void HUD::setFpsLevel(int level)
|
void HUD::setFpsLevel(int level)
|
||||||
{
|
{
|
||||||
|
fpscounter = 0;
|
||||||
|
|
||||||
MyGUI::Widget* fps;
|
MyGUI::Widget* fps;
|
||||||
getWidget(fps, "FPSBoxAdv");
|
getWidget(fps, "FPSBoxAdv");
|
||||||
fps->setVisible(false);
|
fps->setVisible(false);
|
||||||
|
@ -134,7 +136,8 @@ void HUD::setFpsLevel(int level)
|
||||||
|
|
||||||
void HUD::setFPS(float fps)
|
void HUD::setFPS(float fps)
|
||||||
{
|
{
|
||||||
fpscounter->setCaption(boost::lexical_cast<std::string>((int)fps));
|
if (fpscounter)
|
||||||
|
fpscounter->setCaption(boost::lexical_cast<std::string>((int)fps));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HUD::setTriangleCount(size_t count)
|
void HUD::setTriangleCount(size_t count)
|
||||||
|
@ -147,28 +150,6 @@ void HUD::setBatchCount(size_t count)
|
||||||
batchcounter->setCaption(boost::lexical_cast<std::string>(count));
|
batchcounter->setCaption(boost::lexical_cast<std::string>(count));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HUD::setWeapIcon(const char *str)
|
|
||||||
{
|
|
||||||
weapImage->setImageTexture(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HUD::setSpellIcon(const char *str)
|
|
||||||
{
|
|
||||||
spellImage->setImageTexture(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HUD::setWeapStatus(int s, int smax)
|
|
||||||
{
|
|
||||||
weapStatus->setProgressRange(smax);
|
|
||||||
weapStatus->setProgressPosition(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HUD::setSpellStatus(int s, int smax)
|
|
||||||
{
|
|
||||||
spellStatus->setProgressRange(smax);
|
|
||||||
spellStatus->setProgressPosition(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HUD::setEffect(const char *img)
|
void HUD::setEffect(const char *img)
|
||||||
{
|
{
|
||||||
effect1->setImageTexture(img);
|
effect1->setImageTexture(img);
|
||||||
|
@ -217,7 +198,12 @@ void HUD::setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellV
|
||||||
spellDx = weapDx = weapBoxBaseLeft - hmsBaseLeft;
|
spellDx = weapDx = weapBoxBaseLeft - hmsBaseLeft;
|
||||||
|
|
||||||
if (!weapVisible)
|
if (!weapVisible)
|
||||||
spellDx -= spellBoxBaseLeft - weapBoxBaseLeft;
|
spellDx += spellBoxBaseLeft - weapBoxBaseLeft;
|
||||||
|
|
||||||
|
mWeaponVisible = weapVisible;
|
||||||
|
mSpellVisible = spellVisible;
|
||||||
|
if (!mWeaponVisible && !mSpellVisible)
|
||||||
|
mWeaponSpellBox->setVisible(false);
|
||||||
|
|
||||||
health->setVisible(hmsVisible);
|
health->setVisible(hmsVisible);
|
||||||
stamina->setVisible(hmsVisible);
|
stamina->setVisible(hmsVisible);
|
||||||
|
@ -230,14 +216,16 @@ void HUD::setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellV
|
||||||
|
|
||||||
void HUD::setBottomRightVisibility(bool effectBoxVisible, bool minimapBoxVisible)
|
void HUD::setBottomRightVisibility(bool effectBoxVisible, bool minimapBoxVisible)
|
||||||
{
|
{
|
||||||
|
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
|
||||||
|
|
||||||
// effect box can have variable width -> variable left coordinate
|
// effect box can have variable width -> variable left coordinate
|
||||||
int effectsDx = 0;
|
int effectsDx = 0;
|
||||||
if (!minimapBoxVisible)
|
if (!minimapBoxVisible)
|
||||||
effectsDx = minimapBoxBaseRight - effectBoxBaseRight;
|
effectsDx = (viewSize.width - minimapBoxBaseRight) - (viewSize.width - effectBoxBaseRight);
|
||||||
|
|
||||||
mMapVisible = minimapBoxVisible;
|
mMapVisible = minimapBoxVisible;
|
||||||
minimapBox->setVisible(minimapBoxVisible);
|
minimapBox->setVisible(minimapBoxVisible);
|
||||||
effectBox->setPosition(effectBoxBaseRight - effectBox->getWidth() + effectsDx, effectBox->getTop());
|
effectBox->setPosition((viewSize.width - effectBoxBaseRight) - effectBox->getWidth() + effectsDx, effectBox->getTop());
|
||||||
effectBox->setVisible(effectBoxVisible);
|
effectBox->setVisible(effectBoxVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,11 +334,150 @@ void HUD::setCellName(const std::string& cellName)
|
||||||
void HUD::onFrame(float dt)
|
void HUD::onFrame(float dt)
|
||||||
{
|
{
|
||||||
mCellNameTimer -= dt;
|
mCellNameTimer -= dt;
|
||||||
|
mWeaponSpellTimer -= dt;
|
||||||
if (mCellNameTimer < 0)
|
if (mCellNameTimer < 0)
|
||||||
mCellNameBox->setVisible(false);
|
mCellNameBox->setVisible(false);
|
||||||
|
if (mWeaponSpellTimer < 0)
|
||||||
|
mWeaponSpellBox->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HUD::onResChange(int width, int height)
|
void HUD::onResChange(int width, int height)
|
||||||
{
|
{
|
||||||
setCoord(0, 0, width, height);
|
setCoord(0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent)
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId);
|
||||||
|
std::string spellName = spell->name;
|
||||||
|
if (spellName != mSpellName && mSpellVisible)
|
||||||
|
{
|
||||||
|
mWeaponSpellTimer = 5.0f;
|
||||||
|
mSpellName = spellName;
|
||||||
|
mWeaponSpellBox->setCaption(mSpellName);
|
||||||
|
mWeaponSpellBox->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
spellStatus->setProgressRange(100);
|
||||||
|
spellStatus->setProgressPosition(successChancePercent);
|
||||||
|
|
||||||
|
if (spellImage->getChildCount())
|
||||||
|
MyGUI::Gui::getInstance().destroyWidget(spellImage->getChildAt(0));
|
||||||
|
|
||||||
|
spellBox->setUserString("ToolTipType", "Spell");
|
||||||
|
spellBox->setUserString("Spell", spellId);
|
||||||
|
|
||||||
|
// use the icon of the first effect
|
||||||
|
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(spell->effects.list.front().effectID);
|
||||||
|
std::string icon = effect->icon;
|
||||||
|
int slashPos = icon.find("\\");
|
||||||
|
icon.insert(slashPos+1, "b_");
|
||||||
|
icon = std::string("icons\\") + icon;
|
||||||
|
Widgets::fixTexturePath(icon);
|
||||||
|
spellImage->setImageTexture(icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent)
|
||||||
|
{
|
||||||
|
std::string itemName = MWWorld::Class::get(item).getName(item);
|
||||||
|
if (itemName != mSpellName && mSpellVisible)
|
||||||
|
{
|
||||||
|
mWeaponSpellTimer = 5.0f;
|
||||||
|
mSpellName = itemName;
|
||||||
|
mWeaponSpellBox->setCaption(mSpellName);
|
||||||
|
mWeaponSpellBox->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
spellStatus->setProgressRange(100);
|
||||||
|
spellStatus->setProgressPosition(chargePercent);
|
||||||
|
|
||||||
|
if (spellImage->getChildCount())
|
||||||
|
MyGUI::Gui::getInstance().destroyWidget(spellImage->getChildAt(0));
|
||||||
|
|
||||||
|
spellBox->setUserString("ToolTipType", "ItemPtr");
|
||||||
|
spellBox->setUserData(item);
|
||||||
|
|
||||||
|
spellImage->setImageTexture("textures\\menu_icon_magic_mini.dds");
|
||||||
|
MyGUI::ImageBox* itemBox = spellImage->createWidgetReal<MyGUI::ImageBox>("ImageBox", MyGUI::FloatCoord(0,0,1,1)
|
||||||
|
, MyGUI::Align::Stretch);
|
||||||
|
|
||||||
|
std::string path = std::string("icons\\");
|
||||||
|
path+=MWWorld::Class::get(item).getInventoryIcon(item);
|
||||||
|
Widgets::fixTexturePath(path);
|
||||||
|
itemBox->setImageTexture(path);
|
||||||
|
itemBox->setNeedMouseFocus(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HUD::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent)
|
||||||
|
{
|
||||||
|
std::string itemName = MWWorld::Class::get(item).getName(item);
|
||||||
|
if (itemName != mWeaponName && mWeaponVisible)
|
||||||
|
{
|
||||||
|
mWeaponSpellTimer = 5.0f;
|
||||||
|
mWeaponName = itemName;
|
||||||
|
mWeaponSpellBox->setCaption(mWeaponName);
|
||||||
|
mWeaponSpellBox->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
weapBox->setUserString("ToolTipType", "ItemPtr");
|
||||||
|
weapBox->setUserData(item);
|
||||||
|
|
||||||
|
weapStatus->setProgressRange(100);
|
||||||
|
weapStatus->setProgressPosition(durabilityPercent);
|
||||||
|
|
||||||
|
if (weapImage->getChildCount())
|
||||||
|
MyGUI::Gui::getInstance().destroyWidget(weapImage->getChildAt(0));
|
||||||
|
|
||||||
|
std::string path = std::string("icons\\");
|
||||||
|
path+=MWWorld::Class::get(item).getInventoryIcon(item);
|
||||||
|
Widgets::fixTexturePath(path);
|
||||||
|
|
||||||
|
if (MWWorld::Class::get(item).getEnchantment(item) != "")
|
||||||
|
{
|
||||||
|
weapImage->setImageTexture("textures\\menu_icon_magic_mini.dds");
|
||||||
|
MyGUI::ImageBox* itemBox = weapImage->createWidgetReal<MyGUI::ImageBox>("ImageBox", MyGUI::FloatCoord(0,0,1,1)
|
||||||
|
, MyGUI::Align::Stretch);
|
||||||
|
itemBox->setImageTexture(path);
|
||||||
|
itemBox->setNeedMouseFocus(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
weapImage->setImageTexture(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HUD::unsetSelectedSpell()
|
||||||
|
{
|
||||||
|
std::string spellName = "#{sNone}";
|
||||||
|
if (spellName != mSpellName && mSpellVisible)
|
||||||
|
{
|
||||||
|
mWeaponSpellTimer = 5.0f;
|
||||||
|
mSpellName = spellName;
|
||||||
|
mWeaponSpellBox->setCaptionWithReplacing(mSpellName);
|
||||||
|
mWeaponSpellBox->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spellImage->getChildCount())
|
||||||
|
MyGUI::Gui::getInstance().destroyWidget(spellImage->getChildAt(0));
|
||||||
|
spellStatus->setProgressRange(100);
|
||||||
|
spellStatus->setProgressPosition(0);
|
||||||
|
spellImage->setImageTexture("");
|
||||||
|
spellBox->clearUserStrings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HUD::unsetSelectedWeapon()
|
||||||
|
{
|
||||||
|
std::string itemName = "#{sSkillHandtohand}";
|
||||||
|
if (itemName != mWeaponName && mWeaponVisible)
|
||||||
|
{
|
||||||
|
mWeaponSpellTimer = 5.0f;
|
||||||
|
mWeaponName = itemName;
|
||||||
|
mWeaponSpellBox->setCaptionWithReplacing(mWeaponName);
|
||||||
|
mWeaponSpellBox->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weapImage->getChildCount())
|
||||||
|
MyGUI::Gui::getInstance().destroyWidget(weapImage->getChildAt(0));
|
||||||
|
weapStatus->setProgressRange(100);
|
||||||
|
weapStatus->setProgressPosition(0);
|
||||||
|
weapImage->setImageTexture("icons\\k\\stealth_handtohand.dds");
|
||||||
|
weapBox->clearUserStrings();
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <openengine/gui/layout.hpp>
|
#include <openengine/gui/layout.hpp>
|
||||||
|
|
||||||
#include "../mwmechanics/stat.hpp"
|
#include "../mwmechanics/stat.hpp"
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
@ -12,10 +13,6 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop);
|
HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop);
|
||||||
void setWeapIcon(const char *str);
|
|
||||||
void setSpellIcon(const char *str);
|
|
||||||
void setWeapStatus(int s, int smax);
|
|
||||||
void setSpellStatus(int s, int smax);
|
|
||||||
void setEffect(const char *img);
|
void setEffect(const char *img);
|
||||||
void setValue (const std::string& id, const MWMechanics::DynamicStat<int>& value);
|
void setValue (const std::string& id, const MWMechanics::DynamicStat<int>& value);
|
||||||
void setFPS(float fps);
|
void setFPS(float fps);
|
||||||
|
@ -25,12 +22,19 @@ namespace MWGui
|
||||||
void setBottomRightVisibility(bool effectBoxVisible, bool minimapVisible);
|
void setBottomRightVisibility(bool effectBoxVisible, bool minimapVisible);
|
||||||
void setFpsLevel(const int level);
|
void setFpsLevel(const int level);
|
||||||
|
|
||||||
|
void setSelectedSpell(const std::string& spellId, int successChancePercent);
|
||||||
|
void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent);
|
||||||
|
void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent);
|
||||||
|
void unsetSelectedSpell();
|
||||||
|
void unsetSelectedWeapon();
|
||||||
|
|
||||||
void onFrame(float dt);
|
void onFrame(float dt);
|
||||||
void onResChange(int width, int height);
|
void onResChange(int width, int height);
|
||||||
|
|
||||||
void setCellName(const std::string& cellName);
|
void setCellName(const std::string& cellName);
|
||||||
|
|
||||||
MyGUI::ProgressPtr health, magicka, stamina;
|
MyGUI::ProgressPtr health, magicka, stamina;
|
||||||
|
MyGUI::Widget* mHealthFrame;
|
||||||
MyGUI::Widget *weapBox, *spellBox;
|
MyGUI::Widget *weapBox, *spellBox;
|
||||||
MyGUI::ImageBox *weapImage, *spellImage;
|
MyGUI::ImageBox *weapImage, *spellImage;
|
||||||
MyGUI::ProgressPtr weapStatus, spellStatus;
|
MyGUI::ProgressPtr weapStatus, spellStatus;
|
||||||
|
@ -40,6 +44,7 @@ namespace MWGui
|
||||||
MyGUI::ImageBox* compass;
|
MyGUI::ImageBox* compass;
|
||||||
MyGUI::ImageBox* crosshair;
|
MyGUI::ImageBox* crosshair;
|
||||||
MyGUI::TextBox* mCellNameBox;
|
MyGUI::TextBox* mCellNameBox;
|
||||||
|
MyGUI::TextBox* mWeaponSpellBox;
|
||||||
|
|
||||||
MyGUI::WidgetPtr fpsbox;
|
MyGUI::WidgetPtr fpsbox;
|
||||||
MyGUI::TextBox* fpscounter;
|
MyGUI::TextBox* fpscounter;
|
||||||
|
@ -57,7 +62,13 @@ namespace MWGui
|
||||||
std::string mCellName;
|
std::string mCellName;
|
||||||
float mCellNameTimer;
|
float mCellNameTimer;
|
||||||
|
|
||||||
|
std::string mWeaponName;
|
||||||
|
std::string mSpellName;
|
||||||
|
float mWeaponSpellTimer;
|
||||||
|
|
||||||
bool mMapVisible;
|
bool mMapVisible;
|
||||||
|
bool mWeaponVisible;
|
||||||
|
bool mSpellVisible;
|
||||||
|
|
||||||
void onWorldClicked(MyGUI::Widget* _sender);
|
void onWorldClicked(MyGUI::Widget* _sender);
|
||||||
void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y);
|
void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y);
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "widgets.hpp"
|
#include "widgets.hpp"
|
||||||
#include "bookwindow.hpp"
|
#include "bookwindow.hpp"
|
||||||
#include "scrollwindow.hpp"
|
#include "scrollwindow.hpp"
|
||||||
|
#include "spellwindow.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -91,7 +92,7 @@ namespace MWGui
|
||||||
|
|
||||||
mFilterAll->setStateSelected(true);
|
mFilterAll->setStateSelected(true);
|
||||||
|
|
||||||
setCoord(0, 342, 600, 258);
|
setCoord(0, 342, 498, 258);
|
||||||
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||||
openContainer(player);
|
openContainer(player);
|
||||||
|
@ -187,6 +188,15 @@ namespace MWGui
|
||||||
mWindowManager.setDragDrop(false);
|
mWindowManager.setDragDrop(false);
|
||||||
|
|
||||||
drawItems();
|
drawItems();
|
||||||
|
|
||||||
|
// update selected weapon icon
|
||||||
|
MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
|
||||||
|
MWWorld::ContainerStoreIterator weaponSlot = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
|
if (weaponSlot == invStore.end())
|
||||||
|
mWindowManager.unsetSelectedWeapon();
|
||||||
|
else
|
||||||
|
mWindowManager.setSelectedWeapon(*weaponSlot, 100); /// \todo track weapon durability
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,4 +269,20 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
mTrading = true;
|
mTrading = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InventoryWindow::notifyContentChanged()
|
||||||
|
{
|
||||||
|
// update the spell window just in case new enchanted items were added to inventory
|
||||||
|
if (mWindowManager.getSpellWindow())
|
||||||
|
mWindowManager.getSpellWindow()->updateSpells();
|
||||||
|
|
||||||
|
// update selected weapon icon
|
||||||
|
MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
|
||||||
|
MWWorld::ContainerStoreIterator weaponSlot = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
|
if (weaponSlot == invStore.end())
|
||||||
|
mWindowManager.unsetSelectedWeapon();
|
||||||
|
else
|
||||||
|
mWindowManager.setSelectedWeapon(*weaponSlot, 100); /// \todo track weapon durability
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,8 @@ namespace MWGui
|
||||||
virtual void _unequipItem(MWWorld::Ptr item);
|
virtual void _unequipItem(MWWorld::Ptr item);
|
||||||
|
|
||||||
virtual void onReferenceUnavailable() { ; }
|
virtual void onReferenceUnavailable() { ; }
|
||||||
|
|
||||||
|
virtual void notifyContentChanged();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
449
apps/openmw/mwgui/spellwindow.cpp
Normal file
449
apps/openmw/mwgui/spellwindow.cpp
Normal file
|
@ -0,0 +1,449 @@
|
||||||
|
#include "spellwindow.hpp"
|
||||||
|
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
|
#include "../mwworld/world.hpp"
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwmechanics/spells.hpp"
|
||||||
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
|
#include "../mwmechanics/spellsuccess.hpp"
|
||||||
|
#include "../mwsound/soundmanager.hpp"
|
||||||
|
|
||||||
|
#include "window_manager.hpp"
|
||||||
|
#include "inventorywindow.hpp"
|
||||||
|
#include "confirmationdialog.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool sortSpells(const std::string& left, const std::string& right)
|
||||||
|
{
|
||||||
|
const ESM::Spell* a = MWBase::Environment::get().getWorld()->getStore().spells.find(left);
|
||||||
|
const ESM::Spell* b = MWBase::Environment::get().getWorld()->getStore().spells.find(right);
|
||||||
|
|
||||||
|
int cmp = a->name.compare(b->name);
|
||||||
|
return cmp < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sortItems(const MWWorld::Ptr& left, const MWWorld::Ptr& right)
|
||||||
|
{
|
||||||
|
int cmp = MWWorld::Class::get(left).getName(left).compare(
|
||||||
|
MWWorld::Class::get(right).getName(right));
|
||||||
|
return cmp < 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWGui
|
||||||
|
{
|
||||||
|
SpellWindow::SpellWindow(WindowManager& parWindowManager)
|
||||||
|
: WindowPinnableBase("openmw_spell_window_layout.xml", parWindowManager)
|
||||||
|
, mHeight(0)
|
||||||
|
, mWidth(0)
|
||||||
|
{
|
||||||
|
getWidget(mSpellView, "SpellView");
|
||||||
|
getWidget(mEffectBox, "EffectsBox");
|
||||||
|
|
||||||
|
setCoord(498, 300, 302, 300);
|
||||||
|
|
||||||
|
updateSpells();
|
||||||
|
|
||||||
|
mMainWidget->castType<MyGUI::Window>()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SpellWindow::onWindowResize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellWindow::onPinToggled()
|
||||||
|
{
|
||||||
|
mWindowManager.setSpellVisibility(!mPinned);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellWindow::open()
|
||||||
|
{
|
||||||
|
updateSpells();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellWindow::updateSpells()
|
||||||
|
{
|
||||||
|
const int spellHeight = 18;
|
||||||
|
|
||||||
|
mHeight = 0;
|
||||||
|
while (mSpellView->getChildCount())
|
||||||
|
MyGUI::Gui::getInstance().destroyWidget(mSpellView->getChildAt(0));
|
||||||
|
|
||||||
|
// retrieve all player spells, divide them into Powers and Spells and sort them
|
||||||
|
std::vector<std::string> spellList;
|
||||||
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||||
|
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
|
||||||
|
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
||||||
|
MWMechanics::Spells& spells = stats.mSpells;
|
||||||
|
|
||||||
|
// the following code switches between selected enchanted item and selected spell (only one of these
|
||||||
|
// can be active at a time)
|
||||||
|
std::string selectedSpell = spells.getSelectedSpell();
|
||||||
|
MWWorld::Ptr selectedItem;
|
||||||
|
if (store.getSelectedEnchantItem() != store.end())
|
||||||
|
{
|
||||||
|
selectedSpell = "";
|
||||||
|
selectedItem = *store.getSelectedEnchantItem();
|
||||||
|
|
||||||
|
bool allowSelectedItem = true;
|
||||||
|
|
||||||
|
// if the selected item can be equipped, make sure that it actually is equipped
|
||||||
|
std::pair<std::vector<int>, bool> slots;
|
||||||
|
slots = MWWorld::Class::get(selectedItem).getEquipmentSlots(selectedItem);
|
||||||
|
if (!slots.first.empty())
|
||||||
|
{
|
||||||
|
bool equipped = false;
|
||||||
|
for (int i=0; i < MWWorld::InventoryStore::Slots; ++i)
|
||||||
|
{
|
||||||
|
if (store.getSlot(i) != store.end() && *store.getSlot(i) == selectedItem)
|
||||||
|
{
|
||||||
|
equipped = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!equipped)
|
||||||
|
allowSelectedItem = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allowSelectedItem)
|
||||||
|
{
|
||||||
|
store.setSelectedEnchantItem(store.end());
|
||||||
|
spells.setSelectedSpell("");
|
||||||
|
mWindowManager.unsetSelectedSpell();
|
||||||
|
selectedItem = MWWorld::Ptr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
||||||
|
{
|
||||||
|
spellList.push_back(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> powers;
|
||||||
|
std::vector<std::string>::iterator it = spellList.begin();
|
||||||
|
while (it != spellList.end())
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it);
|
||||||
|
if (spell->data.type == ESM::Spell::ST_Power)
|
||||||
|
{
|
||||||
|
powers.push_back(*it);
|
||||||
|
it = spellList.erase(it);
|
||||||
|
}
|
||||||
|
else if (spell->data.type == ESM::Spell::ST_Ability)
|
||||||
|
{
|
||||||
|
// abilities are always active and don't show in the spell window.
|
||||||
|
it = spellList.erase(it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
std::sort(powers.begin(), powers.end(), sortSpells);
|
||||||
|
std::sort(spellList.begin(), spellList.end(), sortSpells);
|
||||||
|
|
||||||
|
// retrieve player's enchanted items
|
||||||
|
std::vector<MWWorld::Ptr> items;
|
||||||
|
for (MWWorld::ContainerStoreIterator it(store.begin()); it != store.end(); ++it)
|
||||||
|
{
|
||||||
|
std::string enchantId = MWWorld::Class::get(*it).getEnchantment(*it);
|
||||||
|
if (enchantId != "")
|
||||||
|
{
|
||||||
|
// only add items with "Cast once" or "Cast on use"
|
||||||
|
const ESM::Enchantment* enchant = MWBase::Environment::get().getWorld()->getStore().enchants.find(enchantId);
|
||||||
|
int type = enchant->data.type;
|
||||||
|
if (type != ESM::Enchantment::CastOnce
|
||||||
|
&& type != ESM::Enchantment::WhenUsed)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
items.push_back(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::sort(items.begin(), items.end(), sortItems);
|
||||||
|
|
||||||
|
|
||||||
|
int height = estimateHeight(items.size() + powers.size() + spellList.size());
|
||||||
|
bool scrollVisible = height > mSpellView->getHeight();
|
||||||
|
mWidth = mSpellView->getWidth() - (scrollVisible ? 18 : 0);
|
||||||
|
|
||||||
|
// powers
|
||||||
|
addGroup("#{sPowers}", "");
|
||||||
|
|
||||||
|
for (std::vector<std::string>::const_iterator it = powers.begin(); it != powers.end(); ++it)
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it);
|
||||||
|
MyGUI::Button* t = mSpellView->createWidget<MyGUI::Button>("SpellText",
|
||||||
|
MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||||
|
t->setCaption(spell->name);
|
||||||
|
t->setTextAlign(MyGUI::Align::Left);
|
||||||
|
t->setUserString("ToolTipType", "Spell");
|
||||||
|
t->setUserString("Spell", *it);
|
||||||
|
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
|
||||||
|
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected);
|
||||||
|
|
||||||
|
if (*it == selectedSpell)
|
||||||
|
t->setStateSelected(true);
|
||||||
|
|
||||||
|
mHeight += spellHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// other spells
|
||||||
|
addGroup("#{sSpells}", "#{sCostChance}");
|
||||||
|
for (std::vector<std::string>::const_iterator it = spellList.begin(); it != spellList.end(); ++it)
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it);
|
||||||
|
MyGUI::Button* t = mSpellView->createWidget<MyGUI::Button>("SpellText",
|
||||||
|
MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||||
|
t->setCaption(spell->name);
|
||||||
|
t->setTextAlign(MyGUI::Align::Left);
|
||||||
|
t->setUserString("ToolTipType", "Spell");
|
||||||
|
t->setUserString("Spell", *it);
|
||||||
|
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
|
||||||
|
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected);
|
||||||
|
t->setStateSelected(*it == selectedSpell);
|
||||||
|
|
||||||
|
// cost / success chance
|
||||||
|
MyGUI::Button* costChance = mSpellView->createWidget<MyGUI::Button>("SpellText",
|
||||||
|
MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||||
|
std::string cost = boost::lexical_cast<std::string>(spell->data.cost);
|
||||||
|
std::string chance = boost::lexical_cast<std::string>(int(MWMechanics::getSpellSuccessChance(*it, player)));
|
||||||
|
costChance->setCaption(cost + "/" + chance);
|
||||||
|
costChance->setTextAlign(MyGUI::Align::Right);
|
||||||
|
costChance->setNeedMouseFocus(false);
|
||||||
|
costChance->setStateSelected(*it == selectedSpell);
|
||||||
|
|
||||||
|
|
||||||
|
mHeight += spellHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// enchanted items
|
||||||
|
addGroup("#{sMagicItem}", "#{sCostCharge}");
|
||||||
|
|
||||||
|
for (std::vector<MWWorld::Ptr>::const_iterator it = items.begin(); it != items.end(); ++it)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr item = *it;
|
||||||
|
|
||||||
|
const ESM::Enchantment* enchant = MWBase::Environment::get().getWorld()->getStore().enchants.find(MWWorld::Class::get(item).getEnchantment(item));
|
||||||
|
|
||||||
|
// check if the item is currently equipped (will display in a different color)
|
||||||
|
bool equipped = false;
|
||||||
|
for (int i=0; i < MWWorld::InventoryStore::Slots; ++i)
|
||||||
|
{
|
||||||
|
if (store.getSlot(i) != store.end() && *store.getSlot(i) == item)
|
||||||
|
{
|
||||||
|
equipped = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MyGUI::Button* t = mSpellView->createWidget<MyGUI::Button>(equipped ? "SpellText" : "SpellTextUnequipped",
|
||||||
|
MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||||
|
t->setCaption(MWWorld::Class::get(item).getName(item));
|
||||||
|
t->setTextAlign(MyGUI::Align::Left);
|
||||||
|
t->setUserData(item);
|
||||||
|
t->setUserString("ToolTipType", "ItemPtr");
|
||||||
|
t->setUserString("Equipped", equipped ? "true" : "false");
|
||||||
|
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onEnchantedItemSelected);
|
||||||
|
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
|
||||||
|
t->setStateSelected(item == selectedItem);
|
||||||
|
|
||||||
|
// cost / charge
|
||||||
|
MyGUI::Button* costCharge = mSpellView->createWidget<MyGUI::Button>(equipped ? "SpellText" : "SpellTextUnequipped",
|
||||||
|
MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||||
|
|
||||||
|
std::string cost = boost::lexical_cast<std::string>(enchant->data.cost);
|
||||||
|
std::string charge = boost::lexical_cast<std::string>(enchant->data.charge); /// \todo track current charge
|
||||||
|
if (enchant->data.type == ESM::Enchantment::CastOnce)
|
||||||
|
{
|
||||||
|
// this is Morrowind behaviour
|
||||||
|
cost = "100";
|
||||||
|
charge = "100";
|
||||||
|
}
|
||||||
|
|
||||||
|
costCharge->setCaption(cost + "/" + charge);
|
||||||
|
costCharge->setTextAlign(MyGUI::Align::Right);
|
||||||
|
costCharge->setNeedMouseFocus(false);
|
||||||
|
costCharge->setStateSelected(item == selectedItem);
|
||||||
|
|
||||||
|
mHeight += spellHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
mSpellView->setCanvasSize(mSpellView->getWidth(), std::max(mSpellView->getHeight(), mHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellWindow::addGroup(const std::string &label, const std::string& label2)
|
||||||
|
{
|
||||||
|
if (mSpellView->getChildCount() > 0)
|
||||||
|
{
|
||||||
|
MyGUI::ImageBox* separator = mSpellView->createWidget<MyGUI::ImageBox>("MW_HLine",
|
||||||
|
MyGUI::IntCoord(4, mHeight, mWidth-8, 18),
|
||||||
|
MyGUI::Align::Left | MyGUI::Align::Top);
|
||||||
|
separator->setNeedMouseFocus(false);
|
||||||
|
mHeight += 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
MyGUI::TextBox* groupWidget = mSpellView->createWidget<MyGUI::TextBox>("SandBrightText",
|
||||||
|
MyGUI::IntCoord(0, mHeight, mWidth, 24),
|
||||||
|
MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch);
|
||||||
|
groupWidget->setCaptionWithReplacing(label);
|
||||||
|
groupWidget->setTextAlign(MyGUI::Align::Left);
|
||||||
|
groupWidget->setNeedMouseFocus(false);
|
||||||
|
|
||||||
|
if (label2 != "")
|
||||||
|
{
|
||||||
|
MyGUI::TextBox* groupWidget2 = mSpellView->createWidget<MyGUI::TextBox>("SandBrightText",
|
||||||
|
MyGUI::IntCoord(0, mHeight, mWidth-4, 24),
|
||||||
|
MyGUI::Align::Left | MyGUI::Align::Top);
|
||||||
|
groupWidget2->setCaptionWithReplacing(label2);
|
||||||
|
groupWidget2->setTextAlign(MyGUI::Align::Right);
|
||||||
|
groupWidget2->setNeedMouseFocus(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
mHeight += 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellWindow::onWindowResize(MyGUI::Window* _sender)
|
||||||
|
{
|
||||||
|
updateSpells();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellWindow::onEnchantedItemSelected(MyGUI::Widget* _sender)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||||
|
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
||||||
|
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
|
||||||
|
MWMechanics::Spells& spells = stats.mSpells;
|
||||||
|
MWWorld::Ptr item = *_sender->getUserData<MWWorld::Ptr>();
|
||||||
|
|
||||||
|
// retrieve ContainerStoreIterator to the item
|
||||||
|
MWWorld::ContainerStoreIterator it = store.begin();
|
||||||
|
for (; it != store.end(); ++it)
|
||||||
|
{
|
||||||
|
if (*it == item)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(it != store.end());
|
||||||
|
|
||||||
|
// equip, if it can be equipped and is not already equipped
|
||||||
|
if (_sender->getUserString("Equipped") == "false"
|
||||||
|
&& !MWWorld::Class::get(item).getEquipmentSlots(item).first.empty())
|
||||||
|
{
|
||||||
|
// sound
|
||||||
|
MWBase::Environment::get().getSoundManager()->playSound(MWWorld::Class::get(item).getUpSoundId(item), 1.0, 1.0);
|
||||||
|
|
||||||
|
// Note: can't use Class::use here because enchanted scrolls for example would then open the scroll window instead of equipping
|
||||||
|
|
||||||
|
/// \todo the following code is pretty much copy&paste from ActionEquip, put it in a function?
|
||||||
|
// slots that this item can be equipped in
|
||||||
|
std::pair<std::vector<int>, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item);
|
||||||
|
|
||||||
|
// equip the item in the first free slot
|
||||||
|
for (std::vector<int>::const_iterator slot=slots.first.begin();
|
||||||
|
slot!=slots.first.end(); ++slot)
|
||||||
|
{
|
||||||
|
// if all slots are occupied, replace the last slot
|
||||||
|
if (slot == --slots.first.end())
|
||||||
|
{
|
||||||
|
store.equip(*slot, it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store.getSlot(*slot) == store.end())
|
||||||
|
{
|
||||||
|
// slot is not occupied
|
||||||
|
store.equip(*slot, it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// \todo scripts?
|
||||||
|
|
||||||
|
// since we changed equipping status, update the inventory window
|
||||||
|
mWindowManager.getInventoryWindow()->drawItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
store.setSelectedEnchantItem(it);
|
||||||
|
spells.setSelectedSpell("");
|
||||||
|
mWindowManager.setSelectedEnchantItem(item, 100); /// \todo track charge %
|
||||||
|
|
||||||
|
updateSpells();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellWindow::onSpellSelected(MyGUI::Widget* _sender)
|
||||||
|
{
|
||||||
|
std::string spellId = _sender->getUserString("Spell");
|
||||||
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||||
|
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
||||||
|
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
|
||||||
|
MWMechanics::Spells& spells = stats.mSpells;
|
||||||
|
|
||||||
|
if (MyGUI::InputManager::getInstance().isShiftPressed())
|
||||||
|
{
|
||||||
|
// delete spell, if allowed
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId);
|
||||||
|
if (spell->data.flags & ESM::Spell::F_Always
|
||||||
|
|| spell->data.type == ESM::Spell::ST_Power)
|
||||||
|
{
|
||||||
|
mWindowManager.messageBox("#{sDeleteSpellError}", std::vector<std::string>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// ask for confirmation
|
||||||
|
mSpellToDelete = spellId;
|
||||||
|
ConfirmationDialog* dialog = mWindowManager.getConfirmationDialog();
|
||||||
|
std::string question = mWindowManager.getGameSettingString("sQuestionDeleteSpell", "Delete %s?");
|
||||||
|
question = boost::str(boost::format(question) % spell->name);
|
||||||
|
dialog->open(question);
|
||||||
|
dialog->eventOkClicked.clear();
|
||||||
|
dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept);
|
||||||
|
dialog->eventCancelClicked.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
spells.setSelectedSpell(spellId);
|
||||||
|
store.setSelectedEnchantItem(store.end());
|
||||||
|
mWindowManager.setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSpells();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SpellWindow::estimateHeight(int numSpells) const
|
||||||
|
{
|
||||||
|
int height = 0;
|
||||||
|
height += 24 * 3 + 18 * 2; // group headings
|
||||||
|
height += numSpells * 18;
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel)
|
||||||
|
{
|
||||||
|
if (mSpellView->getViewOffset().top + _rel*0.3 > 0)
|
||||||
|
mSpellView->setViewOffset(MyGUI::IntPoint(0, 0));
|
||||||
|
else
|
||||||
|
mSpellView->setViewOffset(MyGUI::IntPoint(0, mSpellView->getViewOffset().top + _rel*0.3));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellWindow::onDeleteSpellAccept()
|
||||||
|
{
|
||||||
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||||
|
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
||||||
|
MWMechanics::Spells& spells = stats.mSpells;
|
||||||
|
|
||||||
|
if (spells.getSelectedSpell() == mSpellToDelete)
|
||||||
|
{
|
||||||
|
spells.setSelectedSpell("");
|
||||||
|
mWindowManager.unsetSelectedSpell();
|
||||||
|
}
|
||||||
|
|
||||||
|
spells.remove(mSpellToDelete);
|
||||||
|
|
||||||
|
updateSpells();
|
||||||
|
}
|
||||||
|
}
|
39
apps/openmw/mwgui/spellwindow.hpp
Normal file
39
apps/openmw/mwgui/spellwindow.hpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef MWGUI_SPELLWINDOW_H
|
||||||
|
#define MWGUI_SPELLWINDOW_H
|
||||||
|
|
||||||
|
#include "window_pinnable_base.hpp"
|
||||||
|
|
||||||
|
namespace MWGui
|
||||||
|
{
|
||||||
|
class SpellWindow : public WindowPinnableBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SpellWindow(WindowManager& parWindowManager);
|
||||||
|
|
||||||
|
void updateSpells();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MyGUI::ScrollView* mSpellView;
|
||||||
|
MyGUI::Widget* mEffectBox;
|
||||||
|
|
||||||
|
int mHeight;
|
||||||
|
int mWidth;
|
||||||
|
|
||||||
|
std::string mSpellToDelete;
|
||||||
|
|
||||||
|
void addGroup(const std::string& label, const std::string& label2);
|
||||||
|
|
||||||
|
int estimateHeight(int numSpells) const;
|
||||||
|
|
||||||
|
void onWindowResize(MyGUI::Window* _sender);
|
||||||
|
void onEnchantedItemSelected(MyGUI::Widget* _sender);
|
||||||
|
void onSpellSelected(MyGUI::Widget* _sender);
|
||||||
|
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
|
||||||
|
void onDeleteSpellAccept();
|
||||||
|
|
||||||
|
virtual void onPinToggled();
|
||||||
|
virtual void open();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -67,6 +67,11 @@ void ToolTips::onFrame(float frameDuration)
|
||||||
if (!mGameMode)
|
if (!mGameMode)
|
||||||
{
|
{
|
||||||
const MyGUI::IntPoint& mousePos = InputManager::getInstance().getMousePosition();
|
const MyGUI::IntPoint& mousePos = InputManager::getInstance().getMousePosition();
|
||||||
|
const MyGUI::IntPoint& lastPressed = InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left);
|
||||||
|
|
||||||
|
if (mousePos == lastPressed) // mouseclick makes tooltip disappear
|
||||||
|
return;
|
||||||
|
|
||||||
if (mousePos.left == mLastMouseX && mousePos.top == mLastMouseY)
|
if (mousePos.left == mLastMouseX && mousePos.top == mLastMouseY)
|
||||||
{
|
{
|
||||||
mRemainingDelay -= frameDuration;
|
mRemainingDelay -= frameDuration;
|
||||||
|
@ -397,7 +402,6 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info)
|
||||||
|
|
||||||
TextBox* chargeText = enchantArea->createWidget<TextBox>("SandText", IntCoord(0, 0, 10, 18), Align::Default, "ToolTipEnchantChargeText");
|
TextBox* chargeText = enchantArea->createWidget<TextBox>("SandText", IntCoord(0, 0, 10, 18), Align::Default, "ToolTipEnchantChargeText");
|
||||||
chargeText->setCaption(store.gameSettings.search("sCharges")->str);
|
chargeText->setCaption(store.gameSettings.search("sCharges")->str);
|
||||||
chargeText->setProperty("Static", "true");
|
|
||||||
const int chargeTextWidth = chargeText->getTextSize().width + 5;
|
const int chargeTextWidth = chargeText->getTextSize().width + 5;
|
||||||
|
|
||||||
const int chargeAndTextWidth = chargeWidth + chargeTextWidth;
|
const int chargeAndTextWidth = chargeWidth + chargeTextWidth;
|
||||||
|
|
|
@ -104,6 +104,8 @@ namespace MWGui
|
||||||
ContainerBase::openContainer(actor);
|
ContainerBase::openContainer(actor);
|
||||||
|
|
||||||
updateLabels();
|
updateLabels();
|
||||||
|
|
||||||
|
drawItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TradeWindow::onFilterChanged(MyGUI::Widget* _sender)
|
void TradeWindow::onFilterChanged(MyGUI::Widget* _sender)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "settingswindow.hpp"
|
#include "settingswindow.hpp"
|
||||||
#include "confirmationdialog.hpp"
|
#include "confirmationdialog.hpp"
|
||||||
#include "alchemywindow.hpp"
|
#include "alchemywindow.hpp"
|
||||||
|
#include "spellwindow.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/mechanicsmanager.hpp"
|
#include "../mwmechanics/mechanicsmanager.hpp"
|
||||||
#include "../mwinput/inputmanager.hpp"
|
#include "../mwinput/inputmanager.hpp"
|
||||||
|
@ -56,6 +57,7 @@ WindowManager::WindowManager(
|
||||||
, mSettingsWindow(NULL)
|
, mSettingsWindow(NULL)
|
||||||
, mConfirmationDialog(NULL)
|
, mConfirmationDialog(NULL)
|
||||||
, mAlchemyWindow(NULL)
|
, mAlchemyWindow(NULL)
|
||||||
|
, mSpellWindow(NULL)
|
||||||
, mCharGen(NULL)
|
, mCharGen(NULL)
|
||||||
, playerClass()
|
, playerClass()
|
||||||
, playerName()
|
, playerName()
|
||||||
|
@ -124,6 +126,7 @@ WindowManager::WindowManager(
|
||||||
mSettingsWindow = new SettingsWindow(*this);
|
mSettingsWindow = new SettingsWindow(*this);
|
||||||
mConfirmationDialog = new ConfirmationDialog(*this);
|
mConfirmationDialog = new ConfirmationDialog(*this);
|
||||||
mAlchemyWindow = new AlchemyWindow(*this);
|
mAlchemyWindow = new AlchemyWindow(*this);
|
||||||
|
mSpellWindow = new SpellWindow(*this);
|
||||||
|
|
||||||
// The HUD is always on
|
// The HUD is always on
|
||||||
hud->setVisible(true);
|
hud->setVisible(true);
|
||||||
|
@ -141,6 +144,9 @@ WindowManager::WindowManager(
|
||||||
playerSkillValues.insert(std::make_pair(ESM::Skill::skillIds[i], MWMechanics::Stat<float>()));
|
playerSkillValues.insert(std::make_pair(ESM::Skill::skillIds[i], MWMechanics::Stat<float>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsetSelectedSpell();
|
||||||
|
unsetSelectedWeapon();
|
||||||
|
|
||||||
// Set up visibility
|
// Set up visibility
|
||||||
updateVisible();
|
updateVisible();
|
||||||
}
|
}
|
||||||
|
@ -167,6 +173,7 @@ WindowManager::~WindowManager()
|
||||||
delete mSettingsWindow;
|
delete mSettingsWindow;
|
||||||
delete mConfirmationDialog;
|
delete mConfirmationDialog;
|
||||||
delete mAlchemyWindow;
|
delete mAlchemyWindow;
|
||||||
|
delete mSpellWindow;
|
||||||
|
|
||||||
cleanupGarbage();
|
cleanupGarbage();
|
||||||
}
|
}
|
||||||
|
@ -187,12 +194,10 @@ void WindowManager::cleanupGarbage()
|
||||||
void WindowManager::update()
|
void WindowManager::update()
|
||||||
{
|
{
|
||||||
cleanupGarbage();
|
cleanupGarbage();
|
||||||
if (showFPSLevel > 0)
|
|
||||||
{
|
hud->setFPS(mFPS);
|
||||||
hud->setFPS(mFPS);
|
hud->setTriangleCount(mTriangleCount);
|
||||||
hud->setTriangleCount(mTriangleCount);
|
hud->setBatchCount(mBatchCount);
|
||||||
hud->setBatchCount(mBatchCount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::updateVisible()
|
void WindowManager::updateVisible()
|
||||||
|
@ -211,6 +216,7 @@ void WindowManager::updateVisible()
|
||||||
mTradeWindow->setVisible(false);
|
mTradeWindow->setVisible(false);
|
||||||
mSettingsWindow->setVisible(false);
|
mSettingsWindow->setVisible(false);
|
||||||
mAlchemyWindow->setVisible(false);
|
mAlchemyWindow->setVisible(false);
|
||||||
|
mSpellWindow->setVisible(false);
|
||||||
|
|
||||||
// Mouse is visible whenever we're not in game mode
|
// Mouse is visible whenever we're not in game mode
|
||||||
MyGUI::PointerManager::getInstance().setVisible(isGuiMode());
|
MyGUI::PointerManager::getInstance().setVisible(isGuiMode());
|
||||||
|
@ -224,7 +230,7 @@ void WindowManager::updateVisible()
|
||||||
|
|
||||||
setMinimapVisibility((allowed & GW_Map) && !map->pinned());
|
setMinimapVisibility((allowed & GW_Map) && !map->pinned());
|
||||||
setWeaponVisibility((allowed & GW_Inventory) && !mInventoryWindow->pinned());
|
setWeaponVisibility((allowed & GW_Inventory) && !mInventoryWindow->pinned());
|
||||||
setSpellVisibility((allowed & GW_Magic)); /// \todo add pin state when spells window is implemented
|
setSpellVisibility((allowed & GW_Magic) && !mSpellWindow->pinned());
|
||||||
setHMSVisibility((allowed & GW_Stats) && !mStatsWindow->pinned());
|
setHMSVisibility((allowed & GW_Stats) && !mStatsWindow->pinned());
|
||||||
|
|
||||||
// If in game mode, don't show anything.
|
// If in game mode, don't show anything.
|
||||||
|
@ -271,9 +277,10 @@ void WindowManager::updateVisible()
|
||||||
int eff = shown & allowed;
|
int eff = shown & allowed;
|
||||||
|
|
||||||
// Show the windows we want
|
// Show the windows we want
|
||||||
map -> setVisible( (eff & GW_Map) );
|
map -> setVisible(eff & GW_Map);
|
||||||
mStatsWindow -> setVisible( (eff & GW_Stats) );
|
mStatsWindow -> setVisible(eff & GW_Stats);
|
||||||
mInventoryWindow->setVisible( (eff & GW_Inventory));
|
mInventoryWindow->setVisible(eff & GW_Inventory);
|
||||||
|
mSpellWindow->setVisible(eff & GW_Magic);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GM_Container:
|
case GM_Container:
|
||||||
|
@ -670,3 +677,34 @@ void WindowManager::removeGuiMode(GuiMode mode)
|
||||||
|
|
||||||
updateVisible();
|
updateVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent)
|
||||||
|
{
|
||||||
|
hud->setSelectedSpell(spellId, successChancePercent);
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId);
|
||||||
|
mSpellWindow->setTitle(spell->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent)
|
||||||
|
{
|
||||||
|
hud->setSelectedEnchantItem(item, chargePercent);
|
||||||
|
mSpellWindow->setTitle(MWWorld::Class::get(item).getName(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent)
|
||||||
|
{
|
||||||
|
hud->setSelectedWeapon(item, durabilityPercent);
|
||||||
|
mInventoryWindow->setTitle(MWWorld::Class::get(item).getName(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowManager::unsetSelectedSpell()
|
||||||
|
{
|
||||||
|
hud->unsetSelectedSpell();
|
||||||
|
mSpellWindow->setTitle("#{sNone}");
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowManager::unsetSelectedWeapon()
|
||||||
|
{
|
||||||
|
hud->unsetSelectedWeapon();
|
||||||
|
mInventoryWindow->setTitle("#{sSkillHandtohand}");
|
||||||
|
}
|
||||||
|
|
|
@ -81,6 +81,7 @@ namespace MWGui
|
||||||
class SettingsWindow;
|
class SettingsWindow;
|
||||||
class ConfirmationDialog;
|
class ConfirmationDialog;
|
||||||
class AlchemyWindow;
|
class AlchemyWindow;
|
||||||
|
class SpellWindow;
|
||||||
|
|
||||||
struct ClassPoint
|
struct ClassPoint
|
||||||
{
|
{
|
||||||
|
@ -153,6 +154,7 @@ namespace MWGui
|
||||||
MWGui::CountDialog* getCountDialog() {return mCountDialog;}
|
MWGui::CountDialog* getCountDialog() {return mCountDialog;}
|
||||||
MWGui::ConfirmationDialog* getConfirmationDialog() {return mConfirmationDialog;}
|
MWGui::ConfirmationDialog* getConfirmationDialog() {return mConfirmationDialog;}
|
||||||
MWGui::TradeWindow* getTradeWindow() {return mTradeWindow;}
|
MWGui::TradeWindow* getTradeWindow() {return mTradeWindow;}
|
||||||
|
MWGui::SpellWindow* getSpellWindow() {return mSpellWindow;}
|
||||||
|
|
||||||
MyGUI::Gui* getGui() const { return gui; }
|
MyGUI::Gui* getGui() const { return gui; }
|
||||||
|
|
||||||
|
@ -202,6 +204,12 @@ namespace MWGui
|
||||||
void setWeaponVisibility(bool visible);
|
void setWeaponVisibility(bool visible);
|
||||||
void setSpellVisibility(bool visible);
|
void setSpellVisibility(bool visible);
|
||||||
|
|
||||||
|
void setSelectedSpell(const std::string& spellId, int successChancePercent);
|
||||||
|
void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent);
|
||||||
|
void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent);
|
||||||
|
void unsetSelectedSpell();
|
||||||
|
void unsetSelectedWeapon();
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void removeDialog(T*& dialog); ///< Casts to OEngine::GUI::Layout and calls removeDialog, then resets pointer to nullptr.
|
void removeDialog(T*& dialog); ///< Casts to OEngine::GUI::Layout and calls removeDialog, then resets pointer to nullptr.
|
||||||
void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted.
|
void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted.
|
||||||
|
@ -250,6 +258,7 @@ namespace MWGui
|
||||||
SettingsWindow* mSettingsWindow;
|
SettingsWindow* mSettingsWindow;
|
||||||
ConfirmationDialog* mConfirmationDialog;
|
ConfirmationDialog* mConfirmationDialog;
|
||||||
AlchemyWindow* mAlchemyWindow;
|
AlchemyWindow* mAlchemyWindow;
|
||||||
|
SpellWindow* mSpellWindow;
|
||||||
|
|
||||||
CharacterCreation* mCharGen;
|
CharacterCreation* mCharGen;
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
void Spells::add (const std::string& spellId)
|
void Spells::add (const std::string& spellId)
|
||||||
{
|
{
|
||||||
if (std::find (mSpells.begin(), mSpells.end(), spellId)!=mSpells.end())
|
if (std::find (mSpells.begin(), mSpells.end(), spellId)==mSpells.end())
|
||||||
mSpells.push_back (spellId);
|
mSpells.push_back (spellId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
99
apps/openmw/mwmechanics/spellsuccess.hpp
Normal file
99
apps/openmw/mwmechanics/spellsuccess.hpp
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
#ifndef MWMECHANICS_SPELLSUCCESS_H
|
||||||
|
#define MWMECHANICS_SPELLSUCCESS_H
|
||||||
|
|
||||||
|
#include "../mwworld/ptr.hpp"
|
||||||
|
#include "../mwworld/world.hpp"
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
|
|
||||||
|
#include "npcstats.hpp"
|
||||||
|
|
||||||
|
namespace MWMechanics
|
||||||
|
{
|
||||||
|
inline int spellSchoolToSkill(int school)
|
||||||
|
{
|
||||||
|
std::map<int, int> schoolSkillMap; // maps spell school to skill id
|
||||||
|
schoolSkillMap[0] = 11; // alteration
|
||||||
|
schoolSkillMap[1] = 13; // conjuration
|
||||||
|
schoolSkillMap[3] = 12; // illusion
|
||||||
|
schoolSkillMap[2] = 10; // destruction
|
||||||
|
schoolSkillMap[4] = 14; // mysticism
|
||||||
|
schoolSkillMap[5] = 15; // restoration
|
||||||
|
assert(schoolSkillMap.find(school) != schoolSkillMap.end());
|
||||||
|
return schoolSkillMap[school];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int getSpellSchool(const std::string& spellId, const MWWorld::Ptr& actor)
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId);
|
||||||
|
NpcStats& stats = MWWorld::Class::get(actor).getNpcStats(actor);
|
||||||
|
|
||||||
|
// determine the spell's school
|
||||||
|
// this is always the school where the player's respective skill is the least advanced
|
||||||
|
// out of all the magic effects' schools
|
||||||
|
const std::vector<ESM::ENAMstruct>& effects = spell->effects.list;
|
||||||
|
int school = -1;
|
||||||
|
int skillLevel = -1;
|
||||||
|
for (std::vector<ESM::ENAMstruct>::const_iterator it = effects.begin();
|
||||||
|
it != effects.end(); ++it)
|
||||||
|
{
|
||||||
|
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(it->effectID);
|
||||||
|
int _school = effect->data.school;
|
||||||
|
int _skillLevel = stats.mSkill[spellSchoolToSkill(_school)].getModified();
|
||||||
|
|
||||||
|
if (school == -1)
|
||||||
|
{
|
||||||
|
school = _school;
|
||||||
|
skillLevel = _skillLevel;
|
||||||
|
}
|
||||||
|
else if (_skillLevel < skillLevel)
|
||||||
|
{
|
||||||
|
school = _school;
|
||||||
|
skillLevel = _skillLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return school;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// UESP wiki / Morrowind/Spells:
|
||||||
|
// Chance of success is (Spell's skill * 2 + Willpower / 5 + Luck / 10 - Spell cost - Sound magnitude) * (Current fatigue + Maximum Fatigue * 1.5) / Maximum fatigue * 2
|
||||||
|
/**
|
||||||
|
* @param spellId ID of spell
|
||||||
|
* @param actor calculate spell success chance for this actor (depends on actor's skills)
|
||||||
|
* @attention actor has to be an NPC and not a creature!
|
||||||
|
* @return success chance from 0 to 100 (in percent)
|
||||||
|
*/
|
||||||
|
inline float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor)
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId);
|
||||||
|
|
||||||
|
if (spell->data.flags & ESM::Spell::F_Always // spells with this flag always succeed (usually birthsign spells)
|
||||||
|
|| spell->data.type == ESM::Spell::ST_Power) // powers always succeed, but can be cast only once per day
|
||||||
|
return 100.0;
|
||||||
|
|
||||||
|
NpcStats& stats = MWWorld::Class::get(actor).getNpcStats(actor);
|
||||||
|
CreatureStats& creatureStats = MWWorld::Class::get(actor).getCreatureStats(actor);
|
||||||
|
|
||||||
|
int skillLevel = stats.mSkill[getSpellSchool(spellId, actor)].getModified();
|
||||||
|
|
||||||
|
// Sound magic effect (reduces spell casting chance)
|
||||||
|
int soundMagnitude = creatureStats.mMagicEffects.get (MWMechanics::EffectKey (48)).mMagnitude;
|
||||||
|
|
||||||
|
int willpower = creatureStats.mAttributes[ESM::Attribute::Willpower].getModified();
|
||||||
|
int luck = creatureStats.mAttributes[ESM::Attribute::Luck].getModified();
|
||||||
|
int currentFatigue = creatureStats.mDynamic[2].getCurrent();
|
||||||
|
int maxFatigue = creatureStats.mDynamic[2].getModified();
|
||||||
|
int spellCost = spell->data.cost;
|
||||||
|
|
||||||
|
// There we go, all needed variables are there, lets go
|
||||||
|
float chance = (float(skillLevel * 2) + float(willpower)/5.0 + float(luck)/ 10.0 - spellCost - soundMagnitude) * (float(currentFatigue + maxFatigue * 1.5)) / float(maxFatigue * 2.0);
|
||||||
|
|
||||||
|
chance = std::max(0.0f, std::min(100.0f, chance)); // clamp to 0 .. 100
|
||||||
|
|
||||||
|
return chance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -61,6 +61,7 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2)
|
||||||
/// \todo add current weapon/armor health, remaining lockpick/repair uses, current enchantment charge here as soon as they are implemented
|
/// \todo add current weapon/armor health, remaining lockpick/repair uses, current enchantment charge here as soon as they are implemented
|
||||||
if ( ptr1.mCellRef->refID == ptr2.mCellRef->refID
|
if ( ptr1.mCellRef->refID == ptr2.mCellRef->refID
|
||||||
&& MWWorld::Class::get(ptr1).getScript(ptr1) == "" // item with a script never stacks
|
&& MWWorld::Class::get(ptr1).getScript(ptr1) == "" // item with a script never stacks
|
||||||
|
&& MWWorld::Class::get(ptr1).getEnchantment(ptr1) == "" // item with enchantment never stacks (we could revisit this later, but for now it makes selecting items in the spell window much easier)
|
||||||
&& ptr1.mCellRef->owner == ptr2.mCellRef->owner
|
&& ptr1.mCellRef->owner == ptr2.mCellRef->owner
|
||||||
&& ptr1.mCellRef->soul == ptr2.mCellRef->soul
|
&& ptr1.mCellRef->soul == ptr2.mCellRef->soul
|
||||||
&& ptr1.mCellRef->charge == ptr2.mCellRef->charge)
|
&& ptr1.mCellRef->charge == ptr2.mCellRef->charge)
|
||||||
|
|
|
@ -39,15 +39,18 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots)
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::InventoryStore::InventoryStore() : mMagicEffectsUpToDate (false)
|
MWWorld::InventoryStore::InventoryStore() : mMagicEffectsUpToDate (false)
|
||||||
|
, mSelectedEnchantItem(end())
|
||||||
{
|
{
|
||||||
initSlots (mSlots);
|
initSlots (mSlots);
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::InventoryStore::InventoryStore (const InventoryStore& store)
|
MWWorld::InventoryStore::InventoryStore (const InventoryStore& store)
|
||||||
: ContainerStore (store)
|
: ContainerStore (store)
|
||||||
|
, mSelectedEnchantItem(end())
|
||||||
{
|
{
|
||||||
mMagicEffects = store.mMagicEffects;
|
mMagicEffects = store.mMagicEffects;
|
||||||
mMagicEffectsUpToDate = store.mMagicEffectsUpToDate;
|
mMagicEffectsUpToDate = store.mMagicEffectsUpToDate;
|
||||||
|
mSelectedEnchantItem = store.mSelectedEnchantItem;
|
||||||
copySlots (store);
|
copySlots (store);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,3 +263,13 @@ bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MWWorld::InventoryStore::setSelectedEnchantItem(const ContainerStoreIterator& iterator)
|
||||||
|
{
|
||||||
|
mSelectedEnchantItem = iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSelectedEnchantItem()
|
||||||
|
{
|
||||||
|
return mSelectedEnchantItem;
|
||||||
|
}
|
||||||
|
|
|
@ -50,6 +50,9 @@ namespace MWWorld
|
||||||
|
|
||||||
mutable TSlots mSlots;
|
mutable TSlots mSlots;
|
||||||
|
|
||||||
|
// selected magic item (for using enchantments of type "Cast once" or "Cast when used")
|
||||||
|
ContainerStoreIterator mSelectedEnchantItem;
|
||||||
|
|
||||||
void copySlots (const InventoryStore& store);
|
void copySlots (const InventoryStore& store);
|
||||||
|
|
||||||
void initSlots (TSlots& slots);
|
void initSlots (TSlots& slots);
|
||||||
|
@ -63,7 +66,15 @@ namespace MWWorld
|
||||||
InventoryStore& operator= (const InventoryStore& store);
|
InventoryStore& operator= (const InventoryStore& store);
|
||||||
|
|
||||||
void equip (int slot, const ContainerStoreIterator& iterator);
|
void equip (int slot, const ContainerStoreIterator& iterator);
|
||||||
///< \note \a iteartor can be an end-iterator
|
///< \note \a iterator can be an end-iterator
|
||||||
|
|
||||||
|
void setSelectedEnchantItem(const ContainerStoreIterator& iterator);
|
||||||
|
///< set the selected magic item (for using enchantments of type "Cast once" or "Cast when used")
|
||||||
|
/// \note to unset the selected item, call this method with end() iterator
|
||||||
|
|
||||||
|
ContainerStoreIterator getSelectedEnchantItem();
|
||||||
|
///< @return selected magic item (for using enchantments of type "Cast once" or "Cast when used")
|
||||||
|
/// \note if no item selected, return end() iterator
|
||||||
|
|
||||||
ContainerStoreIterator getSlot (int slot);
|
ContainerStoreIterator getSlot (int slot);
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ configure_file("${SDIR}/openmw_trade_window_layout.xml" "${DDIR}/openmw_trade_wi
|
||||||
configure_file("${SDIR}/openmw_settings_window_layout.xml" "${DDIR}/openmw_settings_window_layout.xml" COPYONLY)
|
configure_file("${SDIR}/openmw_settings_window_layout.xml" "${DDIR}/openmw_settings_window_layout.xml" COPYONLY)
|
||||||
configure_file("${SDIR}/openmw_confirmation_dialog_layout.xml" "${DDIR}/openmw_confirmation_dialog_layout.xml" COPYONLY)
|
configure_file("${SDIR}/openmw_confirmation_dialog_layout.xml" "${DDIR}/openmw_confirmation_dialog_layout.xml" COPYONLY)
|
||||||
configure_file("${SDIR}/openmw_alchemy_window_layout.xml" "${DDIR}/openmw_alchemy_window_layout.xml" COPYONLY)
|
configure_file("${SDIR}/openmw_alchemy_window_layout.xml" "${DDIR}/openmw_alchemy_window_layout.xml" COPYONLY)
|
||||||
|
configure_file("${SDIR}/openmw_spell_window_layout.xml" "${DDIR}/openmw_spell_window_layout.xml" COPYONLY)
|
||||||
configure_file("${SDIR}/atlas1.cfg" "${DDIR}/atlas1.cfg" COPYONLY)
|
configure_file("${SDIR}/atlas1.cfg" "${DDIR}/atlas1.cfg" COPYONLY)
|
||||||
configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY)
|
configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY)
|
||||||
configure_file("${SDIR}/EBGaramond-Regular.ttf" "${DDIR}/EBGaramond-Regular.ttf" COPYONLY)
|
configure_file("${SDIR}/EBGaramond-Regular.ttf" "${DDIR}/EBGaramond-Regular.ttf" COPYONLY)
|
||||||
|
|
|
@ -28,6 +28,14 @@
|
||||||
</Widget>
|
</Widget>
|
||||||
</Widget>
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Equipped weapon/selected spell name display for a few seconds after it changes -->
|
||||||
|
<Widget type="TextBox" skin="SandText" position="13 118 270 24" name="WeaponSpellName" align="Left Bottom HStretch">
|
||||||
|
<Property key="Visible" value="false"/>
|
||||||
|
<Property key="TextAlign" value="Left"/>
|
||||||
|
<Property key="TextShadow" value="true"/>
|
||||||
|
<Property key="TextShadowColour" value="0 0 0"/>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
<!-- Equipped weapon box -->
|
<!-- Equipped weapon box -->
|
||||||
<Widget type="Button" skin="" position="82 146 36 41" align="Left Bottom" name="WeapBox">
|
<Widget type="Button" skin="" position="82 146 36 41" align="Left Bottom" name="WeapBox">
|
||||||
<Widget type="Widget" skin="HUD_Box" position="0 0 36 36">
|
<Widget type="Widget" skin="HUD_Box" position="0 0 36 36">
|
||||||
|
|
20
files/mygui/openmw_spell_window_layout.xml
Normal file
20
files/mygui/openmw_spell_window_layout.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<MyGUI type="Layout">
|
||||||
|
<Widget type="Window" skin="MW_Window_Pinnable" layer="Windows" position="0 0 300 600" name="_Main">
|
||||||
|
|
||||||
|
<!-- Effect box-->
|
||||||
|
<Widget type="Widget" skin="MW_Box" position="8 8 268 24" align="Left Top HStretch">
|
||||||
|
<Widget type="Widget" skin="" position="4 4 260 16" align="Left Top Stretch" name="EffectsBox">
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
<!-- Spell list -->
|
||||||
|
<Widget type="Widget" skin="MW_Box" position="8 38 268 518" align="Left Top Stretch">
|
||||||
|
<Widget type="ScrollView" skin="MW_ScrollView" position="4 4 260 510" align="Left Top Stretch" name="SpellView">
|
||||||
|
<Property key="CanvasAlign" value="Left Top"/>
|
||||||
|
</Widget>
|
||||||
|
</Widget>
|
||||||
|
|
||||||
|
</Widget>
|
||||||
|
</MyGUI>
|
|
@ -99,6 +99,36 @@
|
||||||
</BasisSkin>
|
</BasisSkin>
|
||||||
</Skin>
|
</Skin>
|
||||||
|
|
||||||
|
<Skin name = "SpellText" size = "16 16">
|
||||||
|
<Property key="FontName" value = "Default" />
|
||||||
|
<Property key="TextAlign" value = "ALIGN_LEFT ALIGN_BOTTOM" />
|
||||||
|
<BasisSkin type="SimpleText" offset = "0 0 16 16" align = "ALIGN_STRETCH">
|
||||||
|
<State name="disabled" colour="0.5 0.5 0.5" shift="0"/>
|
||||||
|
<State name="normal" colour="0.75 0.6 0.35" shift="0"/>
|
||||||
|
<State name="highlighted" colour="0.85 0.76 0.60" shift="0"/>
|
||||||
|
<State name="pushed" colour="1 1 1" shift="0"/>
|
||||||
|
<State name="disabled_checked" colour="0.33 0.38 0.67" shift="0"/>
|
||||||
|
<State name="normal_checked" colour="0.33 0.38 0.67" shift="0"/>
|
||||||
|
<State name="highlighted_checked" colour="0.33 0.38 0.67" shift="0"/>
|
||||||
|
<State name="pushed_checked" colour="0.33 0.38 0.67" shift="0"/>
|
||||||
|
</BasisSkin>
|
||||||
|
</Skin>
|
||||||
|
|
||||||
|
<Skin name = "SpellTextUnequipped" size = "16 16">
|
||||||
|
<Property key="FontName" value = "Default" />
|
||||||
|
<Property key="TextAlign" value = "ALIGN_LEFT ALIGN_BOTTOM" />
|
||||||
|
<BasisSkin type="SimpleText" offset = "0 0 16 16" align = "ALIGN_STRETCH">
|
||||||
|
<State name="disabled" colour="0.5 0.5 0.5" shift="0"/>
|
||||||
|
<State name="normal" colour="0.5 0.5 0.5" shift="0"/>
|
||||||
|
<State name="highlighted" colour="0.85 0.76 0.60" shift="0"/>
|
||||||
|
<State name="pushed" colour="1 1 1" shift="0"/>
|
||||||
|
<State name="disabled_checked" colour="0.33 0.38 0.67" shift="0"/>
|
||||||
|
<State name="normal_checked" colour="0.33 0.38 0.67" shift="0"/>
|
||||||
|
<State name="highlighted_checked" colour="0.33 0.38 0.67" shift="0"/>
|
||||||
|
<State name="pushed_checked" colour="0.33 0.38 0.67" shift="0"/>
|
||||||
|
</BasisSkin>
|
||||||
|
</Skin>
|
||||||
|
|
||||||
<Skin name = "MW_StatNameButtonC" size = "200 18">
|
<Skin name = "MW_StatNameButtonC" size = "200 18">
|
||||||
<Child type="Button" skin="SandTextButtonC" offset = "0 0 200 18" align = "LEFT HSTRETCH" name = "StatNameButton" />
|
<Child type="Button" skin="SandTextButtonC" offset = "0 0 200 18" align = "LEFT HSTRETCH" name = "StatNameButton" />
|
||||||
</Skin>
|
</Skin>
|
||||||
|
|
|
@ -118,7 +118,7 @@ namespace GUI
|
||||||
void setTitle(const std::string& title)
|
void setTitle(const std::string& title)
|
||||||
{
|
{
|
||||||
// NOTE: this assume that mMainWidget is of type Window.
|
// NOTE: this assume that mMainWidget is of type Window.
|
||||||
static_cast<MyGUI::Window*>(mMainWidget)->setCaption(title);
|
static_cast<MyGUI::Window*>(mMainWidget)->setCaptionWithReplacing(title);
|
||||||
adjustWindowCaption();
|
adjustWindowCaption();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue