mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-21 18:39:40 +00:00
implement additem/removeitem for non-unique actors
This commit is contained in:
parent
49b78ef463
commit
040a92c373
10 changed files with 133 additions and 0 deletions
|
@ -874,6 +874,11 @@ namespace MWClass
|
||||||
MWMechanics::setBaseAISetting<ESM::Creature>(id, setting, value);
|
MWMechanics::setBaseAISetting<ESM::Creature>(id, setting, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Creature::modifyBaseInventory(const std::string& actorId, const std::string& itemId, int amount) const
|
||||||
|
{
|
||||||
|
MWMechanics::modifyBaseInventory<ESM::Creature>(actorId, itemId, amount);
|
||||||
|
}
|
||||||
|
|
||||||
float Creature::getWalkSpeed(const MWWorld::Ptr& ptr) const
|
float Creature::getWalkSpeed(const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
||||||
|
|
|
@ -132,6 +132,8 @@ namespace MWClass
|
||||||
|
|
||||||
virtual void setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const;
|
virtual void setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const;
|
||||||
|
|
||||||
|
virtual void modifyBaseInventory(const std::string& actorId, const std::string& itemId, int amount) const;
|
||||||
|
|
||||||
float getWalkSpeed(const MWWorld::Ptr& ptr) const final;
|
float getWalkSpeed(const MWWorld::Ptr& ptr) const final;
|
||||||
|
|
||||||
float getRunSpeed(const MWWorld::Ptr& ptr) const final;
|
float getRunSpeed(const MWWorld::Ptr& ptr) const final;
|
||||||
|
|
|
@ -1447,6 +1447,11 @@ namespace MWClass
|
||||||
MWMechanics::setBaseAISetting<ESM::NPC>(id, setting, value);
|
MWMechanics::setBaseAISetting<ESM::NPC>(id, setting, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Npc::modifyBaseInventory(const std::string& actorId, const std::string& itemId, int amount) const
|
||||||
|
{
|
||||||
|
MWMechanics::modifyBaseInventory<ESM::NPC>(actorId, itemId, amount);
|
||||||
|
}
|
||||||
|
|
||||||
float Npc::getWalkSpeed(const MWWorld::Ptr& ptr) const
|
float Npc::getWalkSpeed(const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
const GMST& gmst = getGmst();
|
const GMST& gmst = getGmst();
|
||||||
|
|
|
@ -167,6 +167,8 @@ namespace MWClass
|
||||||
|
|
||||||
virtual void setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const;
|
virtual void setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const;
|
||||||
|
|
||||||
|
virtual void modifyBaseInventory(const std::string& actorId, const std::string& itemId, int amount) const;
|
||||||
|
|
||||||
float getWalkSpeed(const MWWorld::Ptr& ptr) const final;
|
float getWalkSpeed(const MWWorld::Ptr& ptr) const final;
|
||||||
|
|
||||||
float getRunSpeed(const MWWorld::Ptr& ptr) const final;
|
float getRunSpeed(const MWWorld::Ptr& ptr) const final;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef OPENMW_MWMECHANICS_ACTORUTIL_H
|
#ifndef OPENMW_MWMECHANICS_ACTORUTIL_H
|
||||||
#define OPENMW_MWMECHANICS_ACTORUTIL_H
|
#define OPENMW_MWMECHANICS_ACTORUTIL_H
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <components/esm/loadcrea.hpp>
|
#include <components/esm/loadcrea.hpp>
|
||||||
#include <components/esm/loadnpc.hpp>
|
#include <components/esm/loadnpc.hpp>
|
||||||
|
|
||||||
|
@ -53,8 +55,34 @@ namespace MWMechanics
|
||||||
MWBase::Environment::get().getWorld()->createOverrideRecord(copy);
|
MWBase::Environment::get().getWorld()->createOverrideRecord(copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void modifyBaseInventory(const std::string& actorId, const std::string& itemId, int amount)
|
||||||
|
{
|
||||||
|
ESM::NPC copy = *MWBase::Environment::get().getWorld()->getStore().get<ESM::NPC>().find(actorId);
|
||||||
|
for(auto& it : copy.mInventory.mList)
|
||||||
|
{
|
||||||
|
if(Misc::StringUtils::ciEqual(it.mItem, itemId))
|
||||||
|
{
|
||||||
|
int sign = it.mCount < 1 ? -1 : 1;
|
||||||
|
it.mCount = sign * std::max(it.mCount * sign + amount, 0);
|
||||||
|
MWBase::Environment::get().getWorld()->createOverrideRecord(copy);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(amount > 0)
|
||||||
|
{
|
||||||
|
ESM::ContItem cont;
|
||||||
|
cont.mItem = itemId;
|
||||||
|
cont.mCount = amount;
|
||||||
|
copy.mInventory.mList.push_back(cont);
|
||||||
|
MWBase::Environment::get().getWorld()->createOverrideRecord(copy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template void setBaseAISetting<ESM::Creature>(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value);
|
template void setBaseAISetting<ESM::Creature>(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value);
|
||||||
template void setBaseAISetting<ESM::NPC>(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value);
|
template void setBaseAISetting<ESM::NPC>(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value);
|
||||||
|
template void modifyBaseInventory<ESM::Creature>(const std::string& actorId, const std::string& itemId, int amount);
|
||||||
|
template void modifyBaseInventory<ESM::NPC>(const std::string& actorId, const std::string& itemId, int amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -60,6 +60,13 @@ namespace MWScript
|
||||||
|| ::Misc::StringUtils::ciEqual(item, "gold_100"))
|
|| ::Misc::StringUtils::ciEqual(item, "gold_100"))
|
||||||
item = "gold_001";
|
item = "gold_001";
|
||||||
|
|
||||||
|
// Explicit calls to non-unique actors affect the base record
|
||||||
|
if(!R::implicit && ptr.getClass().isActor() && MWBase::Environment::get().getWorld()->getStore().getRefCount(ptr.getCellRef().getRefId()) > 1)
|
||||||
|
{
|
||||||
|
ptr.getClass().modifyBaseInventory(ptr.getCellRef().getRefId(), item, count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr);
|
MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr);
|
||||||
// Create a Ptr for the first added item to recover the item name later
|
// Create a Ptr for the first added item to recover the item name later
|
||||||
MWWorld::Ptr itemPtr = *store.add (item, 1, ptr);
|
MWWorld::Ptr itemPtr = *store.add (item, 1, ptr);
|
||||||
|
@ -147,6 +154,13 @@ namespace MWScript
|
||||||
|| ::Misc::StringUtils::ciEqual(item, "gold_100"))
|
|| ::Misc::StringUtils::ciEqual(item, "gold_100"))
|
||||||
item = "gold_001";
|
item = "gold_001";
|
||||||
|
|
||||||
|
// Explicit calls to non-unique actors affect the base record
|
||||||
|
if(!R::implicit && ptr.getClass().isActor() && MWBase::Environment::get().getWorld()->getStore().getRefCount(ptr.getCellRef().getRefId()) > 1)
|
||||||
|
{
|
||||||
|
ptr.getClass().modifyBaseInventory(ptr.getCellRef().getRefId(), item, -count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr);
|
MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr);
|
||||||
|
|
||||||
std::string itemName;
|
std::string itemName;
|
||||||
|
|
|
@ -522,6 +522,11 @@ namespace MWWorld
|
||||||
throw std::runtime_error ("class does not have creature stats");
|
throw std::runtime_error ("class does not have creature stats");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Class::modifyBaseInventory(const std::string& actorId, const std::string& itemId, int amount) const
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("class does not have an inventory store");
|
||||||
|
}
|
||||||
|
|
||||||
float Class::getWalkSpeed(const Ptr& /*ptr*/) const
|
float Class::getWalkSpeed(const Ptr& /*ptr*/) const
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -363,6 +363,8 @@ namespace MWWorld
|
||||||
|
|
||||||
virtual void setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const;
|
virtual void setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const;
|
||||||
|
|
||||||
|
virtual void modifyBaseInventory(const std::string& actorId, const std::string& itemId, int amount) const;
|
||||||
|
|
||||||
virtual float getWalkSpeed(const Ptr& ptr) const;
|
virtual float getWalkSpeed(const Ptr& ptr) const;
|
||||||
|
|
||||||
virtual float getRunSpeed(const Ptr& ptr) const;
|
virtual float getRunSpeed(const Ptr& ptr) const;
|
||||||
|
|
|
@ -9,6 +9,45 @@
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
#include <components/esm/esmwriter.hpp>
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void readRefs(const ESM::Cell& cell, std::map<ESM::RefNum, std::string>& refs, std::vector<ESM::ESMReader>& readers)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < cell.mContextList.size(); i++)
|
||||||
|
{
|
||||||
|
size_t index = cell.mContextList[i].index;
|
||||||
|
if (readers.size() <= index)
|
||||||
|
readers.resize(index + 1);
|
||||||
|
cell.restore(readers[index], i);
|
||||||
|
ESM::CellRef ref;
|
||||||
|
ref.mRefNum.mContentFile = ESM::RefNum::RefNum_NoContentFile;
|
||||||
|
bool deleted = false;
|
||||||
|
while(cell.getNextRef(readers[index], ref, deleted))
|
||||||
|
{
|
||||||
|
if(deleted)
|
||||||
|
refs.erase(ref.mRefNum);
|
||||||
|
else if (std::find(cell.mMovedRefs.begin(), cell.mMovedRefs.end(), ref.mRefNum) == cell.mMovedRefs.end())
|
||||||
|
{
|
||||||
|
Misc::StringUtils::lowerCaseInPlace(ref.mRefID);
|
||||||
|
refs[ref.mRefNum] = ref.mRefID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(const auto& it : cell.mLeasedRefs)
|
||||||
|
{
|
||||||
|
bool deleted = it.second;
|
||||||
|
if(deleted)
|
||||||
|
refs.erase(it.first.mRefNum);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ESM::CellRef ref = it.first;
|
||||||
|
Misc::StringUtils::lowerCaseInPlace(ref.mRefID);
|
||||||
|
refs[ref.mRefNum] = ref.mRefID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -146,7 +185,33 @@ void ESMStore::setUp(bool validateRecords)
|
||||||
mDialogs.setUp();
|
mDialogs.setUp();
|
||||||
|
|
||||||
if (validateRecords)
|
if (validateRecords)
|
||||||
|
{
|
||||||
validate();
|
validate();
|
||||||
|
countRecords();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESMStore::countRecords()
|
||||||
|
{
|
||||||
|
if(!mRefCount.empty())
|
||||||
|
return;
|
||||||
|
std::map<ESM::RefNum, std::string> refs;
|
||||||
|
std::vector<ESM::ESMReader> readers;
|
||||||
|
for(auto it = mCells.intBegin(); it != mCells.intEnd(); it++)
|
||||||
|
readRefs(*it, refs, readers);
|
||||||
|
for(auto it = mCells.extBegin(); it != mCells.extEnd(); it++)
|
||||||
|
readRefs(*it, refs, readers);
|
||||||
|
for(const auto& pair : refs)
|
||||||
|
mRefCount[pair.second]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ESMStore::getRefCount(const std::string& id) const
|
||||||
|
{
|
||||||
|
const std::string lowerId = Misc::StringUtils::lowerCase(id);
|
||||||
|
auto it = mRefCount.find(lowerId);
|
||||||
|
if(it == mRefCount.end())
|
||||||
|
return 0;
|
||||||
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESMStore::validate()
|
void ESMStore::validate()
|
||||||
|
|
|
@ -70,6 +70,8 @@ namespace MWWorld
|
||||||
std::map<std::string, int> mIds;
|
std::map<std::string, int> mIds;
|
||||||
std::map<std::string, int> mStaticIds;
|
std::map<std::string, int> mStaticIds;
|
||||||
|
|
||||||
|
std::map<std::string, int> mRefCount;
|
||||||
|
|
||||||
std::map<int, StoreBase *> mStores;
|
std::map<int, StoreBase *> mStores;
|
||||||
|
|
||||||
ESM::NPC mPlayerTemplate;
|
ESM::NPC mPlayerTemplate;
|
||||||
|
@ -79,6 +81,7 @@ namespace MWWorld
|
||||||
/// Validate entries in store after setup
|
/// Validate entries in store after setup
|
||||||
void validate();
|
void validate();
|
||||||
|
|
||||||
|
void countRecords();
|
||||||
public:
|
public:
|
||||||
/// \todo replace with SharedIterator<StoreBase>
|
/// \todo replace with SharedIterator<StoreBase>
|
||||||
typedef std::map<int, StoreBase *>::const_iterator iterator;
|
typedef std::map<int, StoreBase *>::const_iterator iterator;
|
||||||
|
@ -252,6 +255,8 @@ namespace MWWorld
|
||||||
|
|
||||||
// To be called when we are done with dynamic record loading
|
// To be called when we are done with dynamic record loading
|
||||||
void checkPlayer();
|
void checkPlayer();
|
||||||
|
|
||||||
|
int getRefCount(const std::string& id) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
|
Loading…
Reference in a new issue