You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw-tes3mp/apps/openmw/mwgui/hud.cpp

627 lines
22 KiB
C++

#include "hud.hpp"
#include <boost/lexical_cast.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwworld/player.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"
namespace MWGui
{
HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop)
: Layout("openmw_hud.layout")
, mHealth(NULL)
, mMagicka(NULL)
, mStamina(NULL)
, mDrowning(NULL)
, mDrowningFrame(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(0)
{
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");
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)
{
static const char *ids[] =
{
"HBar", "MBar", "FBar", 0
};
for (int i=0; ids[i]; ++i)
if (ids[i]==id)
{
MyGUI::Widget* w;
std::string valStr = boost::lexical_cast<std::string>(value.getCurrent()) + "/" + boost::lexical_cast<std::string>(value.getModified());
switch (i)
{
case 0:
mHealth->setProgressRange (value.getModified());
mHealth->setProgressPosition (value.getCurrent());
getWidget(w, "HealthFrame");
w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr);
break;
case 1:
mMagicka->setProgressRange (value.getModified());
mMagicka->setProgressPosition (value.getCurrent());
getWidget(w, "MagickaFrame");
w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr);
break;
case 2:
mStamina->setProgressRange (value.getModified());
mStamina->setProgressPosition (value.getCurrent());
getWidget(w, "FatigueFrame");
w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr);
break;
}
}
}
void HUD::setDrowningTimeLeft(float time)
{
mDrowning->setProgressPosition(time/20.0*200.0);
}
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
MWWorld::Ptr object = mDragAndDrop->mItem.mBase;
MWBase::World* world = MWBase::Environment::get().getWorld();
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);
int origCount = object.getRefData().getCount();
object.getRefData().setCount(mDragAndDrop->mDraggedCount);
if (world->canPlaceObject(mouseX, mouseY))
world->placeObject(object, mouseX, mouseY);
else
world->dropObjectOnGround(world->getPlayer().getPlayer(), object);
MWBase::Environment::get().getWindowManager()->changePointer("arrow");
std::string sound = MWWorld::Class::get(object).getDownSoundId(object);
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
object.getRefData().setCount(origCount);
// remove object from the container it was coming from
mDragAndDrop->mSourceModel->removeItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount);
mDragAndDrop->finish();
mDragAndDrop->mSourceModel->update();
}
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
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()->getPlayer().getPlayer();
if (MWWorld::Class::get(player).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()->getPlayer().getPlayer();
if (MWWorld::Class::get(player).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));
}
}
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 = MWWorld::Class::get(item).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+=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);
}
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+=MWWorld::Class::get(item).getInventoryIcon(item);
Widgets::fixTexturePath(path);
if (MWWorld::Class::get(item).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->getPlayer().getPlayer();
if (MWWorld::Class::get(player).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 ();
mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop());
}
void HUD::update()
{
mSpellIcons->updateWidgets(mEffectBox, true);
if (!mEnemy.isEmpty() && mEnemyHealth->getVisible())
{
MWMechanics::CreatureStats& stats = MWWorld::Class::get(mEnemy).getCreatureStats(mEnemy);
mEnemyHealth->setProgressRange(100);
mEnemyHealth->setProgressPosition(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100);
}
}
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);
MWMechanics::CreatureStats& stats = MWWorld::Class::get(mEnemy).getCreatureStats(mEnemy);
mEnemyHealth->setProgressRange(100);
mEnemyHealth->setProgressPosition(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100);
}
}