1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 10:49:57 +00:00
openmw-tes3mp/apps/openmw/mwgui/hud.cpp
Emanuel Guevel 1e4a854433 Remove static method MWWorld::Class::get(&Ptr)
It was just adding a level of indirection to Ptr.getClass().
All the call were replaced by that instead. The number of lines changed
is important, but the change itself is trivial, so everything should be
fine. :)
2014-05-22 20:50:00 +02:00

678 lines
23 KiB
C++

#include "hud.hpp"
#include <boost/lexical_cast.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "inventorywindow.hpp"
#include "console.hpp"
#include "spellicons.hpp"
#include "itemmodel.hpp"
#include "container.hpp"
#include "itemmodel.hpp"
namespace MWGui
{
/**
* Makes it possible to use ItemModel::moveItem to move an item from an inventory to the world.
*/
class WorldItemModel : public ItemModel
{
public:
WorldItemModel(float left, float top) : mLeft(left), mTop(top) {}
virtual ~WorldItemModel() {}
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false)
{
MWBase::World* world = MWBase::Environment::get().getWorld();
MWWorld::Ptr dropped;
if (world->canPlaceObject(mLeft, mTop))
dropped = world->placeObject(item.mBase, mLeft, mTop, count);
else
dropped = world->dropObjectOnGround(world->getPlayerPtr(), item.mBase, count);
if (setNewOwner)
dropped.getCellRef().mOwner = "";
return dropped;
}
virtual void removeItem (const ItemStack& item, size_t count) { throw std::runtime_error("removeItem not implemented"); }
virtual ModelIndex getIndex (ItemStack item) { throw std::runtime_error("getIndex not implemented"); }
virtual void update() {}
virtual size_t getItemCount() { return 0; }
virtual ItemStack getItem (ModelIndex index) { throw std::runtime_error("getItem not implemented"); }
private:
// Where to drop the item
float mLeft;
float mTop;
};
HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop)
: Layout("openmw_hud.layout")
, mHealth(NULL)
, mMagicka(NULL)
, mStamina(NULL)
, mDrowning(NULL)
, mDrowningFrame(NULL)
, mDrowningFlash(NULL)
, mWeapImage(NULL)
, mSpellImage(NULL)
, mWeapStatus(NULL)
, mSpellStatus(NULL)
, mEffectBox(NULL)
, mMinimap(NULL)
, mCompass(NULL)
, mCrosshair(NULL)
, mFpsBox(NULL)
, mFpsCounter(NULL)
, mTriangleCounter(NULL)
, mBatchCounter(NULL)
, mHealthManaStaminaBaseLeft(0)
, mWeapBoxBaseLeft(0)
, mSpellBoxBaseLeft(0)
, mEffectBoxBaseRight(0)
, mMinimapBoxBaseRight(0)
, mDragAndDrop(dragAndDrop)
, mCellNameTimer(0.0f)
, mCellNameBox(NULL)
, mMapVisible(true)
, mWeaponVisible(true)
, mSpellVisible(true)
, mWorldMouseOver(false)
, mEnemyHealthTimer(-1)
, mIsDrowning(false)
, mWeaponSpellTimer(0.f)
, mDrowningFlashTheta(0.f)
{
setCoord(0,0, width, height);
// Energy bars
getWidget(mHealthFrame, "HealthFrame");
getWidget(mHealth, "Health");
getWidget(mMagicka, "Magicka");
getWidget(mStamina, "Stamina");
getWidget(mEnemyHealth, "EnemyHealth");
mHealthManaStaminaBaseLeft = mHealthFrame->getLeft();
MyGUI::Widget *healthFrame, *magickaFrame, *fatigueFrame;
getWidget(healthFrame, "HealthFrame");
getWidget(magickaFrame, "MagickaFrame");
getWidget(fatigueFrame, "FatigueFrame");
healthFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked);
magickaFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked);
fatigueFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked);
//Drowning bar
getWidget(mDrowningFrame, "DrowningFrame");
getWidget(mDrowning, "Drowning");
getWidget(mDrowningFlash, "Flash");
mDrowning->setProgressRange(200);
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
// Item and spell images and status bars
getWidget(mWeapBox, "WeapBox");
getWidget(mWeapImage, "WeapImage");
getWidget(mWeapStatus, "WeapStatus");
mWeapBoxBaseLeft = mWeapBox->getLeft();
mWeapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWeaponClicked);
getWidget(mSpellBox, "SpellBox");
getWidget(mSpellImage, "SpellImage");
getWidget(mSpellStatus, "SpellStatus");
mSpellBoxBaseLeft = mSpellBox->getLeft();
mSpellBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked);
getWidget(mSneakBox, "SneakBox");
mSneakBoxBaseLeft = mSneakBox->getLeft();
getWidget(mEffectBox, "EffectBox");
mEffectBoxBaseRight = viewSize.width - mEffectBox->getRight();
getWidget(mMinimapBox, "MiniMapBox");
mMinimapBoxBaseRight = viewSize.width - mMinimapBox->getRight();
getWidget(mMinimap, "MiniMap");
getWidget(mCompass, "Compass");
getWidget(mMinimapButton, "MiniMapButton");
mMinimapButton->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked);
getWidget(mCellNameBox, "CellName");
getWidget(mWeaponSpellBox, "WeaponSpellName");
getWidget(mCrosshair, "Crosshair");
setFpsLevel(fpsLevel);
getWidget(mTriangleCounter, "TriangleCounter");
getWidget(mBatchCounter, "BatchCounter");
LocalMapBase::init(mMinimap, mCompass, this);
mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked);
mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver);
mMainWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &HUD::onWorldMouseLostFocus);
mSpellIcons = new SpellIcons();
}
HUD::~HUD()
{
delete mSpellIcons;
}
void HUD::setFpsLevel(int level)
{
mFpsCounter = 0;
MyGUI::Widget* fps;
getWidget(fps, "FPSBoxAdv");
fps->setVisible(false);
getWidget(fps, "FPSBox");
fps->setVisible(false);
if (level == 2)
{
getWidget(mFpsBox, "FPSBoxAdv");
mFpsBox->setVisible(true);
getWidget(mFpsCounter, "FPSCounterAdv");
}
else if (level == 1)
{
getWidget(mFpsBox, "FPSBox");
mFpsBox->setVisible(true);
getWidget(mFpsCounter, "FPSCounter");
}
}
void HUD::setFPS(float fps)
{
if (mFpsCounter)
mFpsCounter->setCaption(boost::lexical_cast<std::string>((int)fps));
}
void HUD::setTriangleCount(unsigned int count)
{
mTriangleCounter->setCaption(boost::lexical_cast<std::string>(count));
}
void HUD::setBatchCount(unsigned int count)
{
mBatchCounter->setCaption(boost::lexical_cast<std::string>(count));
}
void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value)
{
int current = std::max(0, static_cast<int>(value.getCurrent()));
int modified = static_cast<int>(value.getModified());
MyGUI::Widget* w;
std::string valStr = boost::lexical_cast<std::string>(current) + "/" + boost::lexical_cast<std::string>(modified);
if (id == "HBar")
{
mHealth->setProgressRange(modified);
mHealth->setProgressPosition(current);
getWidget(w, "HealthFrame");
w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr);
}
else if (id == "MBar")
{
mMagicka->setProgressRange (modified);
mMagicka->setProgressPosition (current);
getWidget(w, "MagickaFrame");
w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr);
}
else if (id == "FBar")
{
mStamina->setProgressRange (modified);
mStamina->setProgressPosition (current);
getWidget(w, "FatigueFrame");
w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr);
}
}
void HUD::setDrowningTimeLeft(float time, float maxTime)
{
size_t progress = time/maxTime*200.0;
mDrowning->setProgressPosition(progress);
bool isDrowning = (progress == 0);
if (isDrowning && !mIsDrowning) // Just started drowning
mDrowningFlashTheta = 0.0f; // Start out on bright red every time.
mDrowningFlash->setVisible(isDrowning);
mIsDrowning = isDrowning;
}
void HUD::setDrowningBarVisible(bool visible)
{
mDrowningFrame->setVisible(visible);
}
void HUD::onWorldClicked(MyGUI::Widget* _sender)
{
if (!MWBase::Environment::get().getWindowManager ()->isGuiMode ())
return;
if (mDragAndDrop->mIsOnDragAndDrop)
{
// drop item into the gameworld
MWBase::Environment::get().getWorld()->breakInvisibility(
MWBase::Environment::get().getWorld()->getPlayerPtr());
MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize();
MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition();
float mouseX = cursorPosition.left / float(viewSize.width);
float mouseY = cursorPosition.top / float(viewSize.height);
WorldItemModel drop (mouseX, mouseY);
mDragAndDrop->drop(&drop, NULL);
MWBase::Environment::get().getWindowManager()->changePointer("arrow");
}
else
{
GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode();
if ( (mode != GM_Console) && (mode != GM_Container) && (mode != GM_Inventory) )
return;
MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject();
if (mode == GM_Console)
MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object);
else if ((mode == GM_Container) || (mode == GM_Inventory))
{
// pick up object
if (!object.isEmpty())
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->pickUpObject(object);
}
}
}
void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y)
{
if (mDragAndDrop->mIsOnDragAndDrop)
{
mWorldMouseOver = false;
MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize();
MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition();
float mouseX = cursorPosition.left / float(viewSize.width);
float mouseY = cursorPosition.top / float(viewSize.height);
MWBase::World* world = MWBase::Environment::get().getWorld();
// if we can't drop the object at the wanted position, show the "drop on ground" cursor.
bool canDrop = world->canPlaceObject(mouseX, mouseY);
if (!canDrop)
MWBase::Environment::get().getWindowManager()->changePointer("drop_ground");
else
MWBase::Environment::get().getWindowManager()->changePointer("arrow");
}
else
{
MWBase::Environment::get().getWindowManager()->changePointer("arrow");
mWorldMouseOver = true;
}
}
void HUD::onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new)
{
MWBase::Environment::get().getWindowManager()->changePointer("arrow");
mWorldMouseOver = false;
}
void HUD::onHMSClicked(MyGUI::Widget* _sender)
{
MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Stats);
}
void HUD::onMapClicked(MyGUI::Widget* _sender)
{
MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Map);
}
void HUD::onWeaponClicked(MyGUI::Widget* _sender)
{
const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr();
if (player.getClass().getNpcStats(player).isWerewolf())
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}");
return;
}
MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Inventory);
}
void HUD::onMagicClicked(MyGUI::Widget* _sender)
{
const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr();
if (player.getClass().getNpcStats(player).isWerewolf())
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}");
return;
}
MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Magic);
}
void HUD::setCellName(const std::string& cellName)
{
if (mCellName != cellName)
{
mCellNameTimer = 5.0f;
mCellName = cellName;
mCellNameBox->setCaptionWithReplacing("#{sCell=" + mCellName + "}");
mCellNameBox->setVisible(mMapVisible);
}
}
void HUD::onFrame(float dt)
{
mCellNameTimer -= dt;
mWeaponSpellTimer -= dt;
if (mCellNameTimer < 0)
mCellNameBox->setVisible(false);
if (mWeaponSpellTimer < 0)
mWeaponSpellBox->setVisible(false);
mEnemyHealthTimer -= dt;
if (mEnemyHealth->getVisible() && mEnemyHealthTimer < 0)
{
mEnemyHealth->setVisible(false);
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() + MyGUI::IntPoint(0,20));
}
if (mIsDrowning)
mDrowningFlashTheta += dt * Ogre::Math::TWO_PI;
}
void HUD::onResChange(int width, int height)
{
setCoord(0, 0, width, height);
}
void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent)
{
const ESM::Spell* spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId);
std::string spellName = spell->mName;
if (spellName != mSpellName && mSpellVisible)
{
mWeaponSpellTimer = 5.0f;
mSpellName = spellName;
mWeaponSpellBox->setCaption(mSpellName);
mWeaponSpellBox->setVisible(true);
}
mSpellStatus->setProgressRange(100);
mSpellStatus->setProgressPosition(successChancePercent);
if (mSpellImage->getChildCount())
MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0));
mSpellBox->setUserString("ToolTipType", "Spell");
mSpellBox->setUserString("Spell", spellId);
// use the icon of the first effect
const ESM::MagicEffect* effect =
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(spell->mEffects.mList.front().mEffectID);
std::string icon = effect->mIcon;
int slashPos = icon.find("\\");
icon.insert(slashPos+1, "b_");
icon = std::string("icons\\") + icon;
Widgets::fixTexturePath(icon);
mSpellImage->setImageTexture(icon);
}
void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent)
{
std::string itemName = item.getClass().getName(item);
if (itemName != mSpellName && mSpellVisible)
{
mWeaponSpellTimer = 5.0f;
mSpellName = itemName;
mWeaponSpellBox->setCaption(mSpellName);
mWeaponSpellBox->setVisible(true);
}
mSpellStatus->setProgressRange(100);
mSpellStatus->setProgressPosition(chargePercent);
if (mSpellImage->getChildCount())
MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0));
mSpellBox->setUserString("ToolTipType", "ItemPtr");
mSpellBox->setUserData(item);
mSpellImage->setImageTexture("textures\\menu_icon_magic_mini.dds");
MyGUI::ImageBox* itemBox = mSpellImage->createWidgetReal<MyGUI::ImageBox>("ImageBox", MyGUI::FloatCoord(0,0,1,1)
, MyGUI::Align::Stretch);
std::string path = std::string("icons\\");
path+=item.getClass().getInventoryIcon(item);
Widgets::fixTexturePath(path);
itemBox->setImageTexture(path);
itemBox->setNeedMouseFocus(false);
}
void HUD::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent)
{
std::string itemName = item.getClass().getName(item);
if (itemName != mWeaponName && mWeaponVisible)
{
mWeaponSpellTimer = 5.0f;
mWeaponName = itemName;
mWeaponSpellBox->setCaption(mWeaponName);
mWeaponSpellBox->setVisible(true);
}
mWeapBox->setUserString("ToolTipType", "ItemPtr");
mWeapBox->setUserData(item);
mWeapStatus->setProgressRange(100);
mWeapStatus->setProgressPosition(durabilityPercent);
if (mWeapImage->getChildCount())
MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0));
std::string path = std::string("icons\\");
path+=item.getClass().getInventoryIcon(item);
Widgets::fixTexturePath(path);
if (item.getClass().getEnchantment(item) != "")
{
mWeapImage->setImageTexture("textures\\menu_icon_magic_mini.dds");
MyGUI::ImageBox* itemBox = mWeapImage->createWidgetReal<MyGUI::ImageBox>("ImageBox", MyGUI::FloatCoord(0,0,1,1)
, MyGUI::Align::Stretch);
itemBox->setImageTexture(path);
itemBox->setNeedMouseFocus(false);
}
else
mWeapImage->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 (mSpellImage->getChildCount())
MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0));
mSpellStatus->setProgressRange(100);
mSpellStatus->setProgressPosition(0);
mSpellImage->setImageTexture("");
mSpellBox->clearUserStrings();
}
void HUD::unsetSelectedWeapon()
{
std::string itemName = "#{sSkillHandtohand}";
if (itemName != mWeaponName && mWeaponVisible)
{
mWeaponSpellTimer = 5.0f;
mWeaponName = itemName;
mWeaponSpellBox->setCaptionWithReplacing(mWeaponName);
mWeaponSpellBox->setVisible(true);
}
if (mWeapImage->getChildCount())
MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0));
mWeapStatus->setProgressRange(100);
mWeapStatus->setProgressPosition(0);
MWBase::World *world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayerPtr();
if (player.getClass().getNpcStats(player).isWerewolf())
mWeapImage->setImageTexture("icons\\k\\tx_werewolf_hand.dds");
else
mWeapImage->setImageTexture("icons\\k\\stealth_handtohand.dds");
mWeapBox->clearUserStrings();
}
void HUD::setCrosshairVisible(bool visible)
{
mCrosshair->setVisible (visible);
}
void HUD::setHmsVisible(bool visible)
{
mHealth->setVisible(visible);
mMagicka->setVisible(visible);
mStamina->setVisible(visible);
updatePositions();
}
void HUD::setWeapVisible(bool visible)
{
mWeapBox->setVisible(visible);
updatePositions();
}
void HUD::setSpellVisible(bool visible)
{
mSpellBox->setVisible(visible);
updatePositions();
}
void HUD::setSneakVisible(bool visible)
{
mSneakBox->setVisible(visible);
updatePositions();
}
void HUD::setEffectVisible(bool visible)
{
mEffectBox->setVisible (visible);
updatePositions();
}
void HUD::setMinimapVisible(bool visible)
{
mMinimapBox->setVisible (visible);
updatePositions();
}
void HUD::updatePositions()
{
int weapDx = 0, spellDx = 0, sneakDx = 0;
if (!mHealth->getVisible())
sneakDx = spellDx = weapDx = mWeapBoxBaseLeft - mHealthManaStaminaBaseLeft;
if (!mWeapBox->getVisible())
{
spellDx += mSpellBoxBaseLeft - mWeapBoxBaseLeft;
sneakDx = spellDx;
}
if (!mSpellBox->getVisible())
sneakDx += mSneakBoxBaseLeft - mSpellBoxBaseLeft;
mWeaponVisible = mWeapBox->getVisible();
mSpellVisible = mSpellBox->getVisible();
if (!mWeaponVisible && !mSpellVisible)
mWeaponSpellBox->setVisible(false);
mWeapBox->setPosition(mWeapBoxBaseLeft - weapDx, mWeapBox->getTop());
mSpellBox->setPosition(mSpellBoxBaseLeft - spellDx, mSpellBox->getTop());
mSneakBox->setPosition(mSneakBoxBaseLeft - sneakDx, mSneakBox->getTop());
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
// effect box can have variable width -> variable left coordinate
int effectsDx = 0;
if (!mMinimapBox->getVisible ())
effectsDx = (viewSize.width - mMinimapBoxBaseRight) - (viewSize.width - mEffectBoxBaseRight);
mMapVisible = mMinimapBox->getVisible ();
if (!mMapVisible)
mCellNameBox->setVisible(false);
mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop());
}
void HUD::updateEnemyHealthBar()
{
MWMechanics::CreatureStats& stats = mEnemy.getClass().getCreatureStats(mEnemy);
mEnemyHealth->setProgressRange(100);
// Health is usually cast to int before displaying. Actors die whenever they are < 1 health.
// Therefore any value < 1 should show as an empty health bar. We do the same in statswindow :)
mEnemyHealth->setProgressPosition(int(stats.getHealth().getCurrent()) / stats.getHealth().getModified() * 100);
}
void HUD::update()
{
mSpellIcons->updateWidgets(mEffectBox, true);
if (!mEnemy.isEmpty() && mEnemyHealth->getVisible())
{
updateEnemyHealthBar();
}
if (mIsDrowning)
{
float intensity = (cos(mDrowningFlashTheta) + 1.0f) / 2.0f;
mDrowningFlash->setColour(MyGUI::Colour(intensity, 0, 0));
}
}
void HUD::setEnemy(const MWWorld::Ptr &enemy)
{
mEnemy = enemy;
mEnemyHealthTimer = 5;
if (!mEnemyHealth->getVisible())
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20));
mEnemyHealth->setVisible(true);
updateEnemyHealthBar();
}
void HUD::resetEnemy()
{
mEnemy = MWWorld::Ptr();
mEnemyHealthTimer = -1;
}
}