1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-27 12:35:46 +00:00
florent.teppe 1ced0c912e partially revert "Store: moved all the template specialization to its own heaper file, included where it's needed"
This reverts commit 80a25bcd3021f7ebfaf2f864e34532009b9b8aeb.
It didn't really make sense to do all those changes in the same MR

partially Revert "Store refactoring: more forgotten storeSpecialization.hpp"

This reverts commit 9943a5bc96b9025f06cbaac5bb7f1bf51ebc746f.

removed remaining references to storeSpecialization  CMakeLists.txt,  and landmanager.cpp
2022-09-05 17:35:06 +02:00

651 lines
22 KiB
C++

#include "hud.hpp"
#include <MyGUI_RenderManager.h>
#include <MyGUI_ProgressBar.h>
#include <MyGUI_Button.h>
#include <MyGUI_InputManager.h>
#include <MyGUI_ImageBox.h>
#include <MyGUI_ScrollView.h>
#include <components/settings/settings.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/actorutil.hpp"
#include "inventorywindow.hpp"
#include "spellicons.hpp"
#include "itemmodel.hpp"
#include "draganddrop.hpp"
#include "itemwidget.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() override {}
MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool /*allowAutoEquip*/) override
{
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);
dropped.getCellRef().setOwner("");
return dropped;
}
void removeItem (const ItemStack& item, size_t count) override { throw std::runtime_error("removeItem not implemented"); }
ModelIndex getIndex (const ItemStack &item) override { throw std::runtime_error("getIndex not implemented"); }
void update() override {}
size_t getItemCount() override { return 0; }
ItemStack getItem (ModelIndex index) override { throw std::runtime_error("getItem not implemented"); }
bool usesContainer(const MWWorld::Ptr&) override { return false; }
private:
// Where to drop the item
float mLeft;
float mTop;
};
HUD::HUD(CustomMarkerCollection &customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender)
: WindowBase("openmw_hud.layout")
, LocalMapBase(customMarkers, localMapRender, Settings::Manager::getBool("local map hud fog of war", "Map"))
, mHealth(nullptr)
, mMagicka(nullptr)
, mStamina(nullptr)
, mDrowning(nullptr)
, mWeapImage(nullptr)
, mSpellImage(nullptr)
, mWeapStatus(nullptr)
, mSpellStatus(nullptr)
, mEffectBox(nullptr)
, mMinimap(nullptr)
, mCrosshair(nullptr)
, mCellNameBox(nullptr)
, mDrowningBar(nullptr)
, mDrowningFlash(nullptr)
, mHealthManaStaminaBaseLeft(0)
, mWeapBoxBaseLeft(0)
, mSpellBoxBaseLeft(0)
, mMinimapBoxBaseRight(0)
, mEffectBoxBaseRight(0)
, mDragAndDrop(dragAndDrop)
, mCellNameTimer(0.0f)
, mWeaponSpellTimer(0.f)
, mMapVisible(true)
, mWeaponVisible(true)
, mSpellVisible(true)
, mWorldMouseOver(false)
, mEnemyActorId(-1)
, mEnemyHealthTimer(-1)
, mIsDrowning(false)
, mDrowningFlashTheta(0.f)
{
// 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(mDrowningBar, "DrowningBar");
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");
LocalMapBase::init(mMinimap, mCompass);
mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked);
mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver);
mMainWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &HUD::onWorldMouseLostFocus);
mSpellIcons = std::make_unique<SpellIcons>();
}
HUD::~HUD()
{
mMainWidget->eventMouseLostFocus.clear();
mMainWidget->eventMouseMove.clear();
mMainWidget->eventMouseButtonClick.clear();
}
void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value)
{
int current = static_cast<int>(value.getCurrent());
int modified = static_cast<int>(value.getModified());
// Fatigue can be negative
if (id != "FBar")
current = std::max(0, current);
MyGUI::Widget* w;
std::string valStr = MyGUI::utility::toString(current) + " / " + MyGUI::utility::toString(modified);
if (id == "HBar")
{
mHealth->setProgressRange(std::max(0, modified));
mHealth->setProgressPosition(std::max(0, current));
getWidget(w, "HealthFrame");
w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr);
}
else if (id == "MBar")
{
mMagicka->setProgressRange(std::max(0, modified));
mMagicka->setProgressPosition(std::max(0, current));
getWidget(w, "MagickaFrame");
w->setUserString("Caption_HealthDescription", "#{sMagDesc}\n" + valStr);
}
else if (id == "FBar")
{
mStamina->setProgressRange(std::max(0, modified));
mStamina->setProgressPosition(std::max(0, current));
getWidget(w, "FatigueFrame");
w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr);
}
}
void HUD::setDrowningTimeLeft(float time, float maxTime)
{
size_t progress = static_cast<size_t>(time / maxTime * 200);
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)
{
mDrowningBar->setVisible(visible);
}
void HUD::onWorldClicked(MyGUI::Widget* _sender)
{
if (!MWBase::Environment::get().getWindowManager ()->isGuiMode ())
return;
MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager();
if (mDragAndDrop->mIsOnDragAndDrop)
{
// drop item into the gameworld
MWBase::Environment::get().getWorld()->breakInvisibility(
MWMechanics::getPlayer());
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, nullptr);
winMgr->changePointer("arrow");
}
else
{
GuiMode mode = winMgr->getMode();
if (!winMgr->isConsoleMode() && (mode != GM_Container) && (mode != GM_Inventory))
return;
MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject();
if (winMgr->isConsoleMode())
winMgr->setConsoleSelectedObject(object);
else //if ((mode == GM_Container) || (mode == GM_Inventory))
{
// pick up object
if (!object.isEmpty())
winMgr->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 = MWMechanics::getPlayer();
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 = MWMechanics::getPlayer();
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)
{
LocalMapBase::onFrame(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));
}
mSpellIcons->updateWidgets(mEffectBox, true);
if (mEnemyActorId != -1 && mEnemyHealth->getVisible())
{
updateEnemyHealthBar();
}
if (mDrowningBar->getVisible())
mDrowningBar->setPosition(mMainWidget->getWidth()/2 - mDrowningFrame->getWidth()/2, mMainWidget->getTop());
if (mIsDrowning)
{
mDrowningFlashTheta += dt * osg::PI*2;
float intensity = (cos(mDrowningFlashTheta) + 2.0f) / 3.0f;
mDrowningFlash->setAlpha(intensity);
}
}
void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent)
{
const ESM::Spell* spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId);
const 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);
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.rfind('\\');
icon.insert(slashPos+1, "b_");
icon = Misc::ResourceHelpers::correctIconPath(icon, MWBase::Environment::get().getResourceSystem()->getVFS());
mSpellImage->setSpellIcon(icon);
}
void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent)
{
std::string_view 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);
mSpellBox->setUserString("ToolTipType", "ItemPtr");
mSpellBox->setUserData(MWWorld::Ptr(item));
mSpellImage->setItem(item);
}
void HUD::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent)
{
std::string_view itemName = item.getClass().getName(item);
if (itemName != mWeaponName && mWeaponVisible)
{
mWeaponSpellTimer = 5.0f;
mWeaponName = itemName;
mWeaponSpellBox->setCaption(mWeaponName);
mWeaponSpellBox->setVisible(true);
}
mWeapBox->clearUserStrings();
mWeapBox->setUserString("ToolTipType", "ItemPtr");
mWeapBox->setUserData(MWWorld::Ptr(item));
mWeapStatus->setProgressRange(100);
mWeapStatus->setProgressPosition(durabilityPercent);
mWeapImage->setItem(item);
}
void HUD::unsetSelectedSpell()
{
std::string_view spellName = "#{sNone}";
if (spellName != mSpellName && mSpellVisible)
{
mWeaponSpellTimer = 5.0f;
mSpellName = spellName;
mWeaponSpellBox->setCaptionWithReplacing(mSpellName);
mWeaponSpellBox->setVisible(true);
}
mSpellStatus->setProgressRange(100);
mSpellStatus->setProgressPosition(0);
mSpellImage->setItem(MWWorld::Ptr());
mSpellBox->clearUserStrings();
}
void HUD::unsetSelectedWeapon()
{
std::string itemName = "#{sSkillHandtohand}";
if (itemName != mWeaponName && mWeaponVisible)
{
mWeaponSpellTimer = 5.0f;
mWeaponName = itemName;
mWeaponSpellBox->setCaptionWithReplacing(mWeaponName);
mWeaponSpellBox->setVisible(true);
}
mWeapStatus->setProgressRange(100);
mWeapStatus->setProgressPosition(0);
MWBase::World *world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayerPtr();
mWeapImage->setItem(MWWorld::Ptr());
std::string icon = (player.getClass().getNpcStats(player).isWerewolf()) ? "icons\\k\\tx_werewolf_hand.dds" : "icons\\k\\stealth_handtohand.dds";
mWeapImage->setIcon(icon);
mWeapBox->clearUserStrings();
mWeapBox->setUserString("ToolTipType", "Layout");
mWeapBox->setUserString("ToolTipLayout", "HandToHandToolTip");
mWeapBox->setUserString("Caption_HandToHandText", itemName);
mWeapBox->setUserString("ImageTexture_HandToHandImage", icon);
}
void HUD::setCrosshairVisible(bool visible)
{
mCrosshair->setVisible (visible);
}
void HUD::setCrosshairOwned(bool owned)
{
if(owned)
{
mCrosshair->changeWidgetSkin("HUD_Crosshair_Owned");
}
else
{
mCrosshair->changeWidgetSkin("HUD_Crosshair");
}
}
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 = mEffectBoxBaseRight - mMinimapBoxBaseRight;
mMapVisible = mMinimapBox->getVisible ();
if (!mMapVisible)
mCellNameBox->setVisible(false);
mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop());
}
void HUD::updateEnemyHealthBar()
{
MWWorld::Ptr enemy = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mEnemyActorId);
if (enemy.isEmpty())
return;
MWMechanics::CreatureStats& stats = enemy.getClass().getCreatureStats(enemy);
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(static_cast<size_t>(stats.getHealth().getRatio() * 100));
static const float fNPCHealthBarFade = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fNPCHealthBarFade")->mValue.getFloat();
if (fNPCHealthBarFade > 0.f)
mEnemyHealth->setAlpha(std::clamp(mEnemyHealthTimer / fNPCHealthBarFade, 0.f, 1.f));
}
void HUD::setEnemy(const MWWorld::Ptr &enemy)
{
mEnemyActorId = enemy.getClass().getCreatureStats(enemy).getActorId();
mEnemyHealthTimer = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fNPCHealthBarTime")->mValue.getFloat();
if (!mEnemyHealth->getVisible())
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20));
mEnemyHealth->setVisible(true);
updateEnemyHealthBar();
}
void HUD::resetEnemy()
{
mEnemyActorId = -1;
mEnemyHealthTimer = -1;
}
void HUD::clear()
{
unsetSelectedSpell();
unsetSelectedWeapon();
resetEnemy();
}
void HUD::customMarkerCreated(MyGUI::Widget *marker)
{
marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked);
}
void HUD::doorMarkerCreated(MyGUI::Widget *marker)
{
marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked);
}
}