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/apps/openmw/mwclass/misc.cpp

250 lines
8.6 KiB
C++

#include "misc.hpp"
#include <MyGUI_TextIterator.h>
#include <components/esm3/loadcrea.hpp>
#include <components/esm3/loadmisc.hpp>
#include <components/esm3/loadnpc.hpp>
#include <components/settings/settings.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/actionsoulgem.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/manualref.hpp"
#include "../mwworld/nullaction.hpp"
#include "../mwworld/worldmodel.hpp"
#include "../mwgui/tooltips.hpp"
#include "../mwgui/ustring.hpp"
#include "../mwrender/objects.hpp"
#include "../mwrender/renderinginterface.hpp"
#include "classmodel.hpp"
namespace MWClass
{
Miscellaneous::Miscellaneous()
: MWWorld::RegisteredClass<Miscellaneous>(ESM::Miscellaneous::sRecordId)
{
}
bool Miscellaneous::isGold(const MWWorld::ConstPtr& ptr) const
{
return ptr.getCellRef().getRefId() == "gold_001" || ptr.getCellRef().getRefId() == "gold_005"
|| ptr.getCellRef().getRefId() == "gold_010" || ptr.getCellRef().getRefId() == "gold_025"
|| ptr.getCellRef().getRefId() == "gold_100";
}
void Miscellaneous::insertObjectRendering(
const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
{
if (!model.empty())
{
renderingInterface.getObjects().insertModel(ptr, model);
}
}
std::string Miscellaneous::getModel(const MWWorld::ConstPtr& ptr) const
{
return getClassModel<ESM::Miscellaneous>(ptr);
}
std::string_view Miscellaneous::getName(const MWWorld::ConstPtr& ptr) const
{
const MWWorld::LiveCellRef<ESM::Miscellaneous>* ref = ptr.get<ESM::Miscellaneous>();
const std::string& name = ref->mBase->mName;
return !name.empty() ? name : ref->mBase->mId.getRefIdString();
}
std::unique_ptr<MWWorld::Action> Miscellaneous::activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const
{
return defaultItemActivate(ptr, actor);
}
ESM::RefId Miscellaneous::getScript(const MWWorld::ConstPtr& ptr) const
{
const MWWorld::LiveCellRef<ESM::Miscellaneous>* ref = ptr.get<ESM::Miscellaneous>();
return ref->mBase->mScript;
}
int Miscellaneous::getValue(const MWWorld::ConstPtr& ptr) const
{
const MWWorld::LiveCellRef<ESM::Miscellaneous>* ref = ptr.get<ESM::Miscellaneous>();
int value = ref->mBase->mData.mValue;
if (ptr.getCellRef().getGoldValue() > 1 && ptr.getRefData().getCount() == 1)
value = ptr.getCellRef().getGoldValue();
if (!ptr.getCellRef().getSoul().empty())
{
const ESM::Creature* creature
= MWBase::Environment::get().getESMStore()->get<ESM::Creature>().search(ref->mRef.getSoul());
if (creature)
{
int soul = creature->mData.mSoul;
if (Settings::Manager::getBool("rebalance soul gem values", "Game"))
{
// use the 'soul gem value rebalance' formula from the Morrowind Code Patch
float soulValue = 0.0001 * pow(soul, 3) + 2 * soul;
// for Azura's star add the unfilled value
if (ptr.getCellRef().getRefId() == "Misc_SoulGem_Azura")
value += soulValue;
else
value = soulValue;
}
else
value *= soul;
}
}
return value;
}
const ESM::RefId& Miscellaneous::getUpSoundId(const MWWorld::ConstPtr& ptr) const
{
static const ESM::RefId soundGold = ESM::RefId::stringRefId("Item Gold Up");
static const ESM::RefId soundMisc = ESM::RefId::stringRefId("Item Misc Up");
if (isGold(ptr))
return soundGold;
return soundMisc;
}
const ESM::RefId& Miscellaneous::getDownSoundId(const MWWorld::ConstPtr& ptr) const
{
static const ESM::RefId soundGold = ESM::RefId::stringRefId("Item Gold Down");
static const ESM::RefId soundMisc = ESM::RefId::stringRefId("Item Misc Down");
if (isGold(ptr))
return soundGold;
return soundMisc;
}
const std::string& Miscellaneous::getInventoryIcon(const MWWorld::ConstPtr& ptr) const
{
const MWWorld::LiveCellRef<ESM::Miscellaneous>* ref = ptr.get<ESM::Miscellaneous>();
return ref->mBase->mIcon;
}
MWGui::ToolTipInfo Miscellaneous::getToolTipInfo(const MWWorld::ConstPtr& ptr, int count) const
{
const MWWorld::LiveCellRef<ESM::Miscellaneous>* ref = ptr.get<ESM::Miscellaneous>();
MWGui::ToolTipInfo info;
bool gold = isGold(ptr);
if (gold)
count *= getValue(ptr);
std::string countString;
if (!gold)
countString = MWGui::ToolTips::getCountString(count);
else // gold displays its count also if it's 1.
countString = " (" + std::to_string(count) + ")";
std::string_view name = getName(ptr);
info.caption = MyGUI::TextIterator::toTagsString(MWGui::toUString(name))
+ MWGui::ToolTips::getCountString(count) + MWGui::ToolTips::getSoulString(ptr.getCellRef());
info.icon = ref->mBase->mIcon;
std::string text;
text += MWGui::ToolTips::getWeightString(ref->mBase->mData.mWeight, "#{sWeight}");
if (!gold && !(ref->mBase->mData.mFlags & ESM::Miscellaneous::Key))
text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
{
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
}
info.text = text;
return info;
}
MWWorld::Ptr Miscellaneous::copyToCell(const MWWorld::ConstPtr& ptr, MWWorld::CellStore& cell, int count) const
{
MWWorld::Ptr newPtr;
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
if (isGold(ptr))
{
int goldAmount = getValue(ptr) * count;
std::string_view base = "gold_001";
if (goldAmount >= 100)
base = "gold_100";
else if (goldAmount >= 25)
base = "gold_025";
else if (goldAmount >= 10)
base = "gold_010";
else if (goldAmount >= 5)
base = "gold_005";
// Really, I have no idea why moving ref out of conditional
// scope causes list::push_back throwing std::bad_alloc
MWWorld::ManualRef newRef(store, ESM::RefId::stringRefId(base));
const MWWorld::LiveCellRef<ESM::Miscellaneous>* ref = newRef.getPtr().get<ESM::Miscellaneous>();
newPtr = MWWorld::Ptr(cell.insert(ref), &cell);
newPtr.getCellRef().setGoldValue(goldAmount);
newPtr.getRefData().setCount(1);
}
else
{
const MWWorld::LiveCellRef<ESM::Miscellaneous>* ref = ptr.get<ESM::Miscellaneous>();
newPtr = MWWorld::Ptr(cell.insert(ref), &cell);
newPtr.getRefData().setCount(count);
}
newPtr.getCellRef().unsetRefNum();
MWBase::Environment::get().getWorldModel()->registerPtr(newPtr);
return newPtr;
}
std::unique_ptr<MWWorld::Action> Miscellaneous::use(const MWWorld::Ptr& ptr, bool force) const
{
if (isSoulGem(ptr))
return std::make_unique<MWWorld::ActionSoulgem>(ptr);
return std::make_unique<MWWorld::NullAction>();
}
bool Miscellaneous::canSell(const MWWorld::ConstPtr& item, int npcServices) const
{
const MWWorld::LiveCellRef<ESM::Miscellaneous>* ref = item.get<ESM::Miscellaneous>();
return !(ref->mBase->mData.mFlags & ESM::Miscellaneous::Key) && (npcServices & ESM::NPC::Misc) && !isGold(item);
}
float Miscellaneous::getWeight(const MWWorld::ConstPtr& ptr) const
{
const MWWorld::LiveCellRef<ESM::Miscellaneous>* ref = ptr.get<ESM::Miscellaneous>();
return ref->mBase->mData.mWeight;
}
bool Miscellaneous::isKey(const MWWorld::ConstPtr& ptr) const
{
const MWWorld::LiveCellRef<ESM::Miscellaneous>* ref = ptr.get<ESM::Miscellaneous>();
return ref->mBase->mData.mFlags & ESM::Miscellaneous::Key;
}
bool Miscellaneous::isSoulGem(const MWWorld::ConstPtr& ptr) const
{
return ptr.getCellRef().getRefId().startsWith("misc_soulgem");
}
}