mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 18:19:55 +00:00
Recharge items outside of player's inventory (bug #4077)
This commit is contained in:
parent
9a27714766
commit
c51aba0b13
20 changed files with 332 additions and 146 deletions
|
@ -18,6 +18,7 @@
|
|||
Bug #3778: [Mod] Improved Thrown Weapon Projectiles - weapons have wrong transformation during throw animation
|
||||
Bug #3812: Wrong multiline tooltips width when word-wrapping is enabled
|
||||
Bug #3894: Hostile spell effects not detected/present on first frame of OnPCHitMe
|
||||
Bug #4077: Enchanted items are not recharged if they are not in the player's inventory
|
||||
Bug #4202: Open .omwaddon files without needing toopen openmw-cs first
|
||||
Bug #4240: Ash storm origin coordinates and hand shielding animation behavior are incorrect
|
||||
Bug #4270: Closing doors while they are obstructed desyncs closing sfx
|
||||
|
|
|
@ -81,7 +81,7 @@ add_openmw_dir (mwclass
|
|||
add_openmw_dir (mwmechanics
|
||||
mechanicsmanagerimp stat creaturestats magiceffects movement actorutil
|
||||
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aibreathe
|
||||
aicast aiescort aiface aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
|
||||
aicast aiescort aiface aiactivate aicombat recharge repair enchanting pathfinding pathgrid security spellsuccess spellcasting
|
||||
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
|
||||
character actors objects aistate coordinateconverter trading weaponpriority spellpriority weapontype
|
||||
)
|
||||
|
|
|
@ -133,6 +133,7 @@ bool OMW::Engine::frame(float frametime)
|
|||
{
|
||||
double hours = (frametime * mEnvironment.getWorld()->getTimeScaleFactor()) / 3600.0;
|
||||
mEnvironment.getWorld()->advanceTime(hours, true);
|
||||
mEnvironment.getWorld()->rechargeItems(frametime, true);
|
||||
}
|
||||
}
|
||||
osg::Timer_t afterScriptTick = osg::Timer::instance()->tick();
|
||||
|
|
|
@ -73,8 +73,6 @@ namespace MWBase
|
|||
/// \param paused In game type does not currently advance (this usually means some GUI
|
||||
/// component is up).
|
||||
|
||||
virtual void advanceTime (float duration) = 0;
|
||||
|
||||
virtual void setPlayerName (const std::string& name) = 0;
|
||||
///< Set player name.
|
||||
|
||||
|
|
|
@ -584,6 +584,7 @@ namespace MWBase
|
|||
virtual bool isPlayerInJail() const = 0;
|
||||
|
||||
virtual void rest(double hours) = 0;
|
||||
virtual void rechargeItems(double duration, bool activeOnly) = 0;
|
||||
|
||||
virtual void setPlayerTraveling(bool traveling) = 0;
|
||||
virtual bool isPlayerTraveling() const = 0;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
#include "../mwmechanics/recharge.hpp"
|
||||
|
||||
#include "itemwidget.hpp"
|
||||
#include "itemchargeview.hpp"
|
||||
|
@ -130,62 +131,9 @@ void Recharge::onItemCancel()
|
|||
void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item)
|
||||
{
|
||||
MWWorld::Ptr gem = *mGemIcon->getUserData<MWWorld::Ptr>();
|
||||
|
||||
if (!gem.getRefData().getCount())
|
||||
if (!MWMechanics::rechargeItem(item, gem))
|
||||
return;
|
||||
|
||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||
|
||||
float luckTerm = 0.1f * stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
if (luckTerm < 1|| luckTerm > 10)
|
||||
luckTerm = 1;
|
||||
|
||||
float intelligenceTerm = 0.2f * stats.getAttribute(ESM::Attribute::Intelligence).getModified();
|
||||
|
||||
if (intelligenceTerm > 20)
|
||||
intelligenceTerm = 20;
|
||||
if (intelligenceTerm < 1)
|
||||
intelligenceTerm = 1;
|
||||
|
||||
float x = (player.getClass().getSkill(player, ESM::Skill::Enchant) + intelligenceTerm + luckTerm) * stats.getFatigueTerm();
|
||||
int roll = Misc::Rng::roll0to99();
|
||||
if (roll < x)
|
||||
{
|
||||
std::string soul = gem.getCellRef().getSoul();
|
||||
const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get<ESM::Creature>().find(soul);
|
||||
|
||||
float restored = creature->mData.mSoul * (roll / x);
|
||||
|
||||
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(
|
||||
item.getClass().getEnchantment(item));
|
||||
item.getCellRef().setEnchantmentCharge(
|
||||
std::min(item.getCellRef().getEnchantmentCharge() + restored, static_cast<float>(enchantment->mData.mCharge)));
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->playSound("Enchant Success");
|
||||
|
||||
player.getClass().getContainerStore(player).restack(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->playSound("Enchant Fail");
|
||||
}
|
||||
|
||||
player.getClass().skillUsageSucceeded (player, ESM::Skill::Enchant, 0);
|
||||
gem.getContainerStore()->remove(gem, 1, player);
|
||||
|
||||
if (gem.getRefData().getCount() == 0)
|
||||
{
|
||||
std::string message = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sNotifyMessage51")->mValue.getString();
|
||||
message = Misc::StringUtils::format(message, gem.getClass().getName(gem));
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->messageBox(message);
|
||||
|
||||
// special case: readd Azura's Star
|
||||
if (Misc::StringUtils::ciEqual(gem.get<ESM::Miscellaneous>()->mBase->mId, "Misc_SoulGem_Azura"))
|
||||
player.getClass().getContainerStore(player).add("Misc_SoulGem_Azura", 1, player);
|
||||
}
|
||||
|
||||
updateView();
|
||||
}
|
||||
|
||||
|
|
|
@ -287,16 +287,6 @@ namespace MWMechanics
|
|||
mWatched = ptr;
|
||||
}
|
||||
|
||||
void MechanicsManager::advanceTime (float duration)
|
||||
{
|
||||
// Uses ingame time, but scaled to real time
|
||||
const float timeScaleFactor = MWBase::Environment::get().getWorld()->getTimeScaleFactor();
|
||||
if (timeScaleFactor != 0.0f)
|
||||
duration /= timeScaleFactor;
|
||||
MWWorld::Ptr player = getPlayer();
|
||||
player.getClass().getInventoryStore(player).rechargeItems(duration);
|
||||
}
|
||||
|
||||
void MechanicsManager::update(float duration, bool paused)
|
||||
{
|
||||
if(!mWatched.isEmpty())
|
||||
|
|
|
@ -78,8 +78,6 @@ namespace MWMechanics
|
|||
/// \param paused In game type does not currently advance (this usually means some GUI
|
||||
/// component is up).
|
||||
|
||||
virtual void advanceTime (float duration) override;
|
||||
|
||||
virtual void setPlayerName (const std::string& name) override;
|
||||
///< Set player name.
|
||||
|
||||
|
|
92
apps/openmw/mwmechanics/recharge.cpp
Normal file
92
apps/openmw/mwmechanics/recharge.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
#include "recharge.hpp"
|
||||
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "creaturestats.hpp"
|
||||
#include "actorutil.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
||||
bool rechargeItem(const MWWorld::Ptr &item, const float maxCharge, const float duration)
|
||||
{
|
||||
float charge = item.getCellRef().getEnchantmentCharge();
|
||||
if (charge == -1 || charge == maxCharge)
|
||||
return false;
|
||||
|
||||
static const float fMagicItemRechargePerSecond = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||
"fMagicItemRechargePerSecond")->mValue.getFloat();
|
||||
|
||||
item.getCellRef().setEnchantmentCharge(std::min(charge + fMagicItemRechargePerSecond * duration, maxCharge));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rechargeItem(const MWWorld::Ptr &item, const MWWorld::Ptr &gem)
|
||||
{
|
||||
if (!gem.getRefData().getCount())
|
||||
return false;
|
||||
|
||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||
|
||||
float luckTerm = 0.1f * stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
if (luckTerm < 1 || luckTerm > 10)
|
||||
luckTerm = 1;
|
||||
|
||||
float intelligenceTerm = 0.2f * stats.getAttribute(ESM::Attribute::Intelligence).getModified();
|
||||
|
||||
if (intelligenceTerm > 20)
|
||||
intelligenceTerm = 20;
|
||||
if (intelligenceTerm < 1)
|
||||
intelligenceTerm = 1;
|
||||
|
||||
float x = (player.getClass().getSkill(player, ESM::Skill::Enchant) + intelligenceTerm + luckTerm) * stats.getFatigueTerm();
|
||||
int roll = Misc::Rng::roll0to99();
|
||||
if (roll < x)
|
||||
{
|
||||
std::string soul = gem.getCellRef().getSoul();
|
||||
const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get<ESM::Creature>().find(soul);
|
||||
|
||||
float restored = creature->mData.mSoul * (roll / x);
|
||||
|
||||
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(
|
||||
item.getClass().getEnchantment(item));
|
||||
item.getCellRef().setEnchantmentCharge(
|
||||
std::min(item.getCellRef().getEnchantmentCharge() + restored, static_cast<float>(enchantment->mData.mCharge)));
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->playSound("Enchant Success");
|
||||
|
||||
player.getClass().getContainerStore(player).restack(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->playSound("Enchant Fail");
|
||||
}
|
||||
|
||||
player.getClass().skillUsageSucceeded (player, ESM::Skill::Enchant, 0);
|
||||
gem.getContainerStore()->remove(gem, 1, player);
|
||||
|
||||
if (gem.getRefData().getCount() == 0)
|
||||
{
|
||||
std::string message = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sNotifyMessage51")->mValue.getString();
|
||||
message = Misc::StringUtils::format(message, gem.getClass().getName(gem));
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->messageBox(message);
|
||||
|
||||
// special case: readd Azura's Star
|
||||
if (Misc::StringUtils::ciEqual(gem.get<ESM::Miscellaneous>()->mBase->mId, "Misc_SoulGem_Azura"))
|
||||
player.getClass().getContainerStore(player).add("Misc_SoulGem_Azura", 1, player);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
15
apps/openmw/mwmechanics/recharge.hpp
Normal file
15
apps/openmw/mwmechanics/recharge.hpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef MWMECHANICS_RECHARGE_H
|
||||
#define MWMECHANICS_RECHARGE_H
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
||||
bool rechargeItem(const MWWorld::Ptr &item, const float maxCharge, const float duration);
|
||||
|
||||
bool rechargeItem(const MWWorld::Ptr &item, const MWWorld::Ptr &gem);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -163,6 +163,19 @@ void MWWorld::Cells::rest (double hours)
|
|||
}
|
||||
}
|
||||
|
||||
void MWWorld::Cells::recharge (float duration)
|
||||
{
|
||||
for (auto &interior : mInteriors)
|
||||
{
|
||||
interior.second.recharge(duration);
|
||||
}
|
||||
|
||||
for (auto &exterior : mExteriors)
|
||||
{
|
||||
exterior.second.recharge(duration);
|
||||
}
|
||||
}
|
||||
|
||||
MWWorld::CellStore *MWWorld::Cells::getCell (const ESM::CellId& id)
|
||||
{
|
||||
if (id.mPaged)
|
||||
|
|
|
@ -61,7 +61,9 @@ namespace MWWorld
|
|||
|
||||
/// @note name must be lower case
|
||||
Ptr getPtr (const std::string& name);
|
||||
|
||||
void rest (double hours);
|
||||
void recharge (float duration);
|
||||
|
||||
/// Get all Ptrs referencing \a name in exterior cells
|
||||
/// @note Due to the current implementation of getPtr this only supports one Ptr per cell.
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/recharge.hpp"
|
||||
|
||||
#include "ptr.hpp"
|
||||
#include "esmstore.hpp"
|
||||
|
@ -328,6 +329,7 @@ namespace MWWorld
|
|||
void CellStore::updateMergedRefs()
|
||||
{
|
||||
mMergedRefs.clear();
|
||||
mRechargingItemsUpToDate = false;
|
||||
MergeVisitor visitor(mMergedRefs, mMovedHere, mMovedToAnotherCell);
|
||||
forEachInternal(visitor);
|
||||
visitor.merge();
|
||||
|
@ -345,7 +347,7 @@ namespace MWWorld
|
|||
}
|
||||
|
||||
CellStore::CellStore (const ESM::Cell *cell, const MWWorld::ESMStore& esmStore, std::vector<ESM::ESMReader>& readerList)
|
||||
: mStore(esmStore), mReader(readerList), mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0)
|
||||
: mStore(esmStore), mReader(readerList), mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0), mRechargingItemsUpToDate(false)
|
||||
{
|
||||
mWaterLevel = cell->mWater;
|
||||
}
|
||||
|
@ -992,6 +994,42 @@ namespace MWWorld
|
|||
}
|
||||
}
|
||||
|
||||
void CellStore::recharge(float duration)
|
||||
{
|
||||
if (duration <= 0)
|
||||
return;
|
||||
|
||||
if (mState == State_Loaded)
|
||||
{
|
||||
for (CellRefList<ESM::Creature>::List::iterator it (mCreatures.mList.begin()); it!=mCreatures.mList.end(); ++it)
|
||||
{
|
||||
Ptr ptr = getCurrentPtr(&*it);
|
||||
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
|
||||
{
|
||||
ptr.getClass().getContainerStore(ptr).rechargeItems(duration);
|
||||
}
|
||||
}
|
||||
for (CellRefList<ESM::NPC>::List::iterator it (mNpcs.mList.begin()); it!=mNpcs.mList.end(); ++it)
|
||||
{
|
||||
Ptr ptr = getCurrentPtr(&*it);
|
||||
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
|
||||
{
|
||||
ptr.getClass().getContainerStore(ptr).rechargeItems(duration);
|
||||
}
|
||||
}
|
||||
for (CellRefList<ESM::Container>::List::iterator it (mContainers.mList.begin()); it!=mContainers.mList.end(); ++it)
|
||||
{
|
||||
Ptr ptr = getCurrentPtr(&*it);
|
||||
if (!ptr.isEmpty() && ptr.getRefData().getCustomData() != nullptr && ptr.getRefData().getCount() > 0)
|
||||
{
|
||||
ptr.getClass().getContainerStore(ptr).rechargeItems(duration);
|
||||
}
|
||||
}
|
||||
|
||||
rechargeItems(duration);
|
||||
}
|
||||
}
|
||||
|
||||
void CellStore::respawn()
|
||||
{
|
||||
if (mState == State_Loaded)
|
||||
|
@ -1027,4 +1065,73 @@ namespace MWWorld
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MWWorld::CellStore::rechargeItems(float duration)
|
||||
{
|
||||
if (!mRechargingItemsUpToDate)
|
||||
{
|
||||
updateRechargingItems();
|
||||
mRechargingItemsUpToDate = true;
|
||||
}
|
||||
for (TRechargingItems::iterator it = mRechargingItems.begin(); it != mRechargingItems.end(); ++it)
|
||||
{
|
||||
MWMechanics::rechargeItem(it->first, it->second, duration);
|
||||
}
|
||||
}
|
||||
|
||||
void MWWorld::CellStore::updateRechargingItems()
|
||||
{
|
||||
mRechargingItems.clear();
|
||||
|
||||
for (CellRefList<ESM::Weapon>::List::iterator it (mWeapons.mList.begin()); it!=mWeapons.mList.end(); ++it)
|
||||
{
|
||||
Ptr ptr = getCurrentPtr(&*it);
|
||||
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
|
||||
{
|
||||
checkItem(ptr);
|
||||
}
|
||||
}
|
||||
for (CellRefList<ESM::Armor>::List::iterator it (mArmors.mList.begin()); it!=mArmors.mList.end(); ++it)
|
||||
{
|
||||
Ptr ptr = getCurrentPtr(&*it);
|
||||
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
|
||||
{
|
||||
checkItem(ptr);
|
||||
}
|
||||
}
|
||||
for (CellRefList<ESM::Clothing>::List::iterator it (mClothes.mList.begin()); it!=mClothes.mList.end(); ++it)
|
||||
{
|
||||
Ptr ptr = getCurrentPtr(&*it);
|
||||
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
|
||||
{
|
||||
checkItem(ptr);
|
||||
}
|
||||
}
|
||||
for (CellRefList<ESM::Book>::List::iterator it (mBooks.mList.begin()); it!=mBooks.mList.end(); ++it)
|
||||
{
|
||||
Ptr ptr = getCurrentPtr(&*it);
|
||||
if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0)
|
||||
{
|
||||
checkItem(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MWWorld::CellStore::checkItem(Ptr ptr)
|
||||
{
|
||||
if (ptr.getClass().getEnchantment(ptr).empty())
|
||||
return;
|
||||
|
||||
std::string enchantmentId = ptr.getClass().getEnchantment(ptr);
|
||||
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchantmentId);
|
||||
if (!enchantment)
|
||||
{
|
||||
Log(Debug::Warning) << "Warning: Can't find enchantment '" << enchantmentId << "' on item " << ptr.getCellRef().getRefId();
|
||||
return;
|
||||
}
|
||||
|
||||
if (enchantment->mData.mType == ESM::Enchantment::WhenUsed
|
||||
|| enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
||||
mRechargingItems.emplace_back(ptr.getBase(), static_cast<float>(enchantment->mData.mCharge));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,6 +118,16 @@ namespace MWWorld
|
|||
/// Repopulate mMergedRefs.
|
||||
void updateMergedRefs();
|
||||
|
||||
// (item, max charge)
|
||||
typedef std::vector<std::pair<LiveCellRefBase*, float> > TRechargingItems;
|
||||
TRechargingItems mRechargingItems;
|
||||
|
||||
bool mRechargingItemsUpToDate;
|
||||
|
||||
void updateRechargingItems();
|
||||
void rechargeItems(float duration);
|
||||
void checkItem(Ptr ptr);
|
||||
|
||||
// helper function for forEachInternal
|
||||
template<class Visitor, class List>
|
||||
bool forEachImp (Visitor& visitor, List& list)
|
||||
|
@ -184,6 +194,7 @@ namespace MWWorld
|
|||
MWWorld::Ptr moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo);
|
||||
|
||||
void rest(double hours);
|
||||
void recharge(float duration);
|
||||
|
||||
/// Make a copy of the given object and insert it into this cell.
|
||||
/// @note If you get a linker error here, this means the given type can not be inserted into a cell.
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/levelledlist.hpp"
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
#include "../mwmechanics/recharge.hpp"
|
||||
|
||||
#include "manualref.hpp"
|
||||
#include "refdata.hpp"
|
||||
|
@ -114,7 +115,11 @@ void MWWorld::ContainerStore::storeStates (const CellRefList<T>& collection,
|
|||
|
||||
const std::string MWWorld::ContainerStore::sGoldId = "gold_001";
|
||||
|
||||
MWWorld::ContainerStore::ContainerStore() : mListener(nullptr), mCachedWeight (0), mWeightUpToDate (false) {}
|
||||
MWWorld::ContainerStore::ContainerStore()
|
||||
: mListener(nullptr)
|
||||
, mRechargingItemsUpToDate(false)
|
||||
, mCachedWeight (0)
|
||||
, mWeightUpToDate (false) {}
|
||||
|
||||
MWWorld::ContainerStore::~ContainerStore() {}
|
||||
|
||||
|
@ -408,6 +413,46 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack (const Cons
|
|||
return it;
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::rechargeItems(float duration)
|
||||
{
|
||||
if (!mRechargingItemsUpToDate)
|
||||
{
|
||||
updateRechargingItems();
|
||||
mRechargingItemsUpToDate = true;
|
||||
}
|
||||
for (TRechargingItems::iterator it = mRechargingItems.begin(); it != mRechargingItems.end(); ++it)
|
||||
{
|
||||
if (!MWMechanics::rechargeItem(*it->first, it->second, duration))
|
||||
continue;
|
||||
|
||||
// attempt to restack when fully recharged
|
||||
if (it->first->getCellRef().getEnchantmentCharge() == it->second)
|
||||
it->first = restack(*it->first);
|
||||
}
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::updateRechargingItems()
|
||||
{
|
||||
mRechargingItems.clear();
|
||||
for (ContainerStoreIterator it = begin(); it != end(); ++it)
|
||||
{
|
||||
const std::string& enchantmentId = it->getClass().getEnchantment(*it);
|
||||
if (!enchantmentId.empty())
|
||||
{
|
||||
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchantmentId);
|
||||
if (!enchantment)
|
||||
{
|
||||
Log(Debug::Warning) << "Warning: Can't find enchantment '" << enchantmentId << "' on item " << it->getCellRef().getRefId();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (enchantment->mData.mType == ESM::Enchantment::WhenUsed
|
||||
|| enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
||||
mRechargingItems.emplace_back(it, static_cast<float>(enchantment->mData.mCharge));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const Ptr& actor)
|
||||
{
|
||||
int toRemove = count;
|
||||
|
@ -633,6 +678,7 @@ void MWWorld::ContainerStore::clear()
|
|||
void MWWorld::ContainerStore::flagAsModified()
|
||||
{
|
||||
mWeightUpToDate = false;
|
||||
mRechargingItemsUpToDate = false;
|
||||
}
|
||||
|
||||
float MWWorld::ContainerStore::getWeight() const
|
||||
|
|
|
@ -71,6 +71,12 @@ namespace MWWorld
|
|||
protected:
|
||||
ContainerStoreListener* mListener;
|
||||
|
||||
// (item, max charge)
|
||||
typedef std::vector<std::pair<ContainerStoreIterator, float> > TRechargingItems;
|
||||
TRechargingItems mRechargingItems;
|
||||
|
||||
bool mRechargingItemsUpToDate;
|
||||
|
||||
private:
|
||||
|
||||
MWWorld::CellRefList<ESM::Potion> potions;
|
||||
|
@ -108,6 +114,7 @@ namespace MWWorld
|
|||
ESM::InventoryState& inventory, int& index,
|
||||
bool equipable = false) const;
|
||||
|
||||
void updateRechargingItems();
|
||||
|
||||
virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const;
|
||||
|
||||
|
@ -156,6 +163,9 @@ namespace MWWorld
|
|||
///
|
||||
/// @return the number of items actually removed
|
||||
|
||||
void rechargeItems (float duration);
|
||||
///< Restore charge on enchanted items. Note this should only be done for the player.
|
||||
|
||||
ContainerStoreIterator unstack (const Ptr& ptr, const Ptr& container, int count = 1);
|
||||
///< Unstack an item in this container. The item's count will be set to count, then a new stack will be added with (origCount-count).
|
||||
///
|
||||
|
|
|
@ -101,7 +101,6 @@ MWWorld::InventoryStore::InventoryStore()
|
|||
, mUpdatesEnabled (true)
|
||||
, mFirstAutoEquip(true)
|
||||
, mSelectedEnchantItem(end())
|
||||
, mRechargingItemsUpToDate(false)
|
||||
{
|
||||
initSlots (mSlots);
|
||||
}
|
||||
|
@ -114,7 +113,6 @@ MWWorld::InventoryStore::InventoryStore (const InventoryStore& store)
|
|||
, mFirstAutoEquip(store.mFirstAutoEquip)
|
||||
, mPermanentMagicEffectMagnitudes(store.mPermanentMagicEffectMagnitudes)
|
||||
, mSelectedEnchantItem(end())
|
||||
, mRechargingItemsUpToDate(false)
|
||||
{
|
||||
copySlots (store);
|
||||
}
|
||||
|
@ -709,12 +707,6 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
|
|||
mFirstAutoEquip = false;
|
||||
}
|
||||
|
||||
void MWWorld::InventoryStore::flagAsModified()
|
||||
{
|
||||
ContainerStore::flagAsModified();
|
||||
mRechargingItemsUpToDate = false;
|
||||
}
|
||||
|
||||
bool MWWorld::InventoryStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2) const
|
||||
{
|
||||
bool canStack = MWWorld::ContainerStore::stacks(ptr1, ptr2);
|
||||
|
@ -957,57 +949,6 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito
|
|||
}
|
||||
}
|
||||
|
||||
void MWWorld::InventoryStore::updateRechargingItems()
|
||||
{
|
||||
mRechargingItems.clear();
|
||||
for (ContainerStoreIterator it = begin(); it != end(); ++it)
|
||||
{
|
||||
if (it->getClass().getEnchantment(*it) != "")
|
||||
{
|
||||
std::string enchantmentId = it->getClass().getEnchantment(*it);
|
||||
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(
|
||||
enchantmentId);
|
||||
if (!enchantment)
|
||||
{
|
||||
Log(Debug::Warning) << "Warning: Can't find enchantment '" << enchantmentId << "' on item " << it->getCellRef().getRefId();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (enchantment->mData.mType == ESM::Enchantment::WhenUsed
|
||||
|| enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
||||
mRechargingItems.push_back(std::make_pair(it, static_cast<float>(enchantment->mData.mCharge)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MWWorld::InventoryStore::rechargeItems(float duration)
|
||||
{
|
||||
if (!mRechargingItemsUpToDate)
|
||||
{
|
||||
updateRechargingItems();
|
||||
mRechargingItemsUpToDate = true;
|
||||
}
|
||||
for (TRechargingItems::iterator it = mRechargingItems.begin(); it != mRechargingItems.end(); ++it)
|
||||
{
|
||||
if (it->first->getCellRef().getEnchantmentCharge() == -1
|
||||
|| it->first->getCellRef().getEnchantmentCharge() == it->second)
|
||||
continue;
|
||||
|
||||
static float fMagicItemRechargePerSecond = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||
"fMagicItemRechargePerSecond")->mValue.getFloat();
|
||||
|
||||
if (it->first->getCellRef().getEnchantmentCharge() <= it->second)
|
||||
{
|
||||
it->first->getCellRef().setEnchantmentCharge(std::min (it->first->getCellRef().getEnchantmentCharge() + fMagicItemRechargePerSecond * duration,
|
||||
it->second));
|
||||
|
||||
// attempt to restack when fully recharged
|
||||
if (it->first->getCellRef().getEnchantmentCharge() == it->second)
|
||||
it->first = restack(*it->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MWWorld::InventoryStore::purgeEffect(short effectId)
|
||||
{
|
||||
for (TSlots::const_iterator it = mSlots.begin(); it != mSlots.end(); ++it)
|
||||
|
|
|
@ -101,18 +101,11 @@ namespace MWWorld
|
|||
// selected magic item (for using enchantments of type "Cast once" or "Cast when used")
|
||||
ContainerStoreIterator mSelectedEnchantItem;
|
||||
|
||||
// (item, max charge)
|
||||
typedef std::vector<std::pair<ContainerStoreIterator, float> > TRechargingItems;
|
||||
TRechargingItems mRechargingItems;
|
||||
|
||||
bool mRechargingItemsUpToDate;
|
||||
|
||||
void copySlots (const InventoryStore& store);
|
||||
|
||||
void initSlots (TSlots& slots_);
|
||||
|
||||
void updateMagicEffects(const Ptr& actor);
|
||||
void updateRechargingItems();
|
||||
|
||||
void fireEquipmentChangedEvent(const Ptr& actor);
|
||||
|
||||
|
@ -171,10 +164,6 @@ namespace MWWorld
|
|||
const MWMechanics::MagicEffects& getMagicEffects() const;
|
||||
///< Return magic effects from worn items.
|
||||
|
||||
virtual void flagAsModified();
|
||||
///< \attention This function is internal to the world model and should not be called from
|
||||
/// outside.
|
||||
|
||||
virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2) const;
|
||||
///< @return true if the two specified objects can stack with each other
|
||||
|
||||
|
@ -216,9 +205,6 @@ namespace MWWorld
|
|||
|
||||
void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor);
|
||||
|
||||
void rechargeItems (float duration);
|
||||
///< Restore charge on enchanted items. Note this should only be done for the player.
|
||||
|
||||
void purgeEffect (short effectId);
|
||||
///< Remove a magic effect
|
||||
|
||||
|
|
|
@ -857,7 +857,17 @@ namespace MWWorld
|
|||
|
||||
void World::advanceTime (double hours, bool incremental)
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast<float>(hours * 3600));
|
||||
if (!incremental)
|
||||
{
|
||||
// When we fast-forward time, we should recharge magic items
|
||||
// in all loaded cells, using game world time
|
||||
float duration = hours * 3600;
|
||||
const float timeScaleFactor = getTimeScaleFactor();
|
||||
if (timeScaleFactor != 0.0f)
|
||||
duration /= timeScaleFactor;
|
||||
|
||||
rechargeItems(duration, false);
|
||||
}
|
||||
|
||||
mWeatherManager->advanceTime (hours, incremental);
|
||||
|
||||
|
@ -3305,7 +3315,6 @@ namespace MWWorld
|
|||
closestDistance = distance;
|
||||
closestMarker = marker;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return closestMarker;
|
||||
|
@ -3316,6 +3325,22 @@ namespace MWWorld
|
|||
mCells.rest(hours);
|
||||
}
|
||||
|
||||
void World::rechargeItems(double duration, bool activeOnly)
|
||||
{
|
||||
MWWorld::Ptr player = getPlayerPtr();
|
||||
player.getClass().getInventoryStore(player).rechargeItems(duration);
|
||||
|
||||
if (activeOnly)
|
||||
{
|
||||
for (auto &cell : mWorldScene->getActiveCells())
|
||||
{
|
||||
cell->recharge(duration);
|
||||
}
|
||||
}
|
||||
else
|
||||
mCells.recharge(duration);
|
||||
}
|
||||
|
||||
void World::teleportToClosestMarker (const MWWorld::Ptr& ptr,
|
||||
const std::string& id)
|
||||
{
|
||||
|
|
|
@ -574,6 +574,7 @@ namespace MWWorld
|
|||
///< check if the player is allowed to rest
|
||||
|
||||
void rest(double hours) override;
|
||||
void rechargeItems(double duration, bool activeOnly) override;
|
||||
|
||||
/// \todo Probably shouldn't be here
|
||||
MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) override;
|
||||
|
|
Loading…
Reference in a new issue