mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 19:19:56 +00:00
Stolen item tracking overhaul part 2 (Fixes #2338)
This commit is contained in:
parent
c1862cbfc2
commit
bea88c3643
23 changed files with 289 additions and 92 deletions
|
@ -138,9 +138,6 @@ namespace MWBase
|
|||
/// @return was it illegal, and someone saw you doing it?
|
||||
virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed) = 0;
|
||||
|
||||
/// @return is \a ptr allowed to take/use \a item or is it a crime?
|
||||
virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim) = 0;
|
||||
|
||||
enum PersuasionType
|
||||
{
|
||||
PT_Admire,
|
||||
|
@ -205,6 +202,15 @@ namespace MWBase
|
|||
virtual void keepPlayerAlive() = 0;
|
||||
|
||||
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0;
|
||||
|
||||
virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer) = 0;
|
||||
|
||||
/// List the owners that the player has stolen this item from (the owner can be an NPC or a faction).
|
||||
/// <Owner, item count>
|
||||
virtual std::vector<std::pair<std::string, int> > getStolenItemOwners(const std::string& itemid) = 0;
|
||||
|
||||
/// Has the player stolen this item from the given owner?
|
||||
virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -59,8 +59,10 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Container> *ref =
|
||||
ptr.get<ESM::Container>();
|
||||
|
||||
// setting ownership not needed, since taking items from a container inherits the
|
||||
// container's owner automatically
|
||||
data->mContainerStore.fill(
|
||||
ref->mBase->mInventory, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank(), MWBase::Environment::get().getWorld()->getStore());
|
||||
ref->mBase->mInventory, "");
|
||||
|
||||
// store
|
||||
ptr.getRefData().setCustomData (data.release());
|
||||
|
@ -82,7 +84,10 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
|
||||
const ESM::InventoryList& list = ref->mBase->mInventory;
|
||||
MWWorld::ContainerStore& store = getContainerStore(ptr);
|
||||
store.restock(list, ptr, ptr.getCellRef().getOwner(), ptr.getCellRef().getFaction(), ptr.getCellRef().getFactionRank());
|
||||
|
||||
// setting ownership not needed, since taking items from a container inherits the
|
||||
// container's owner automatically
|
||||
store.restock(list, ptr, "");
|
||||
}
|
||||
|
||||
void Container::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
|
||||
|
|
|
@ -139,8 +139,7 @@ namespace MWClass
|
|||
// store
|
||||
ptr.getRefData().setCustomData(data.release());
|
||||
|
||||
getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr), "", -1,
|
||||
MWBase::Environment::get().getWorld()->getStore());
|
||||
getContainerStore(ptr).fill(ref->mBase->mInventory, getId(ptr));
|
||||
|
||||
if (ref->mBase->mFlags & ESM::Creature::Weapon)
|
||||
getInventoryStore(ptr).autoEquip(ptr);
|
||||
|
@ -886,7 +885,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||
const ESM::InventoryList& list = ref->mBase->mInventory;
|
||||
MWWorld::ContainerStore& store = getContainerStore(ptr);
|
||||
store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1);
|
||||
store.restock(list, ptr, ptr.getCellRef().getRefId());
|
||||
}
|
||||
|
||||
int Creature::getBaseFightRating(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -384,8 +384,8 @@ namespace MWClass
|
|||
}
|
||||
|
||||
// inventory
|
||||
data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr), "", -1,
|
||||
MWBase::Environment::get().getWorld()->getStore());
|
||||
// setting ownership is used to make the NPC auto-equip his initial equipment only, and not bartered items
|
||||
data->mInventoryStore.fill(ref->mBase->mInventory, getId(ptr));
|
||||
|
||||
data->mNpcStats.setGoldPool(gold);
|
||||
|
||||
|
@ -1328,7 +1328,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
||||
const ESM::InventoryList& list = ref->mBase->mInventory;
|
||||
MWWorld::ContainerStore& store = getContainerStore(ptr);
|
||||
store.restock(list, ptr, ptr.getCellRef().getRefId(), "", -1);
|
||||
store.restock(list, ptr, ptr.getCellRef().getRefId());
|
||||
}
|
||||
|
||||
int Npc::getBaseFightRating (const MWWorld::Ptr& ptr) const
|
||||
|
|
|
@ -339,7 +339,8 @@ namespace MWGui
|
|||
for (int i=0; i<2; ++i)
|
||||
{
|
||||
MWWorld::Ptr item = (i == 0) ? mEnchanting.getOldItem() : mEnchanting.getGem();
|
||||
if (Misc::StringUtils::ciEqual(item.getCellRef().getOwner(), mPtr.getCellRef().getRefId()))
|
||||
if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(item.getCellRef().getRefId(),
|
||||
mPtr.getCellRef().getRefId()))
|
||||
{
|
||||
std::string msg = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sNotifyMessage49")->getString();
|
||||
if (msg.find("%s") != std::string::npos)
|
||||
|
|
|
@ -65,16 +65,7 @@ MWWorld::Ptr InventoryItemModel::moveItem(const ItemStack &item, size_t count, I
|
|||
if (item.mFlags & ItemStack::Flag_Bound)
|
||||
return MWWorld::Ptr();
|
||||
|
||||
bool setNewOwner = false;
|
||||
|
||||
// Are you dead? Then you wont need that anymore
|
||||
if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead()
|
||||
// Make sure that the item is actually owned by the dead actor
|
||||
// Prevents a potential exploit for resetting the owner of any item, by placing the item in a corpse
|
||||
&& Misc::StringUtils::ciEqual(item.mBase.getCellRef().getOwner(), mActor.getCellRef().getRefId()))
|
||||
setNewOwner = true;
|
||||
|
||||
MWWorld::Ptr ret = otherModel->copyItem(item, count, setNewOwner);
|
||||
MWWorld::Ptr ret = otherModel->copyItem(item, count, false);
|
||||
removeItem(item, count);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -46,20 +46,27 @@ namespace MWGui
|
|||
ItemModel();
|
||||
virtual ~ItemModel() {}
|
||||
|
||||
typedef int ModelIndex;
|
||||
typedef int ModelIndex; // -1 means invalid index
|
||||
|
||||
/// Throws for invalid index or out of range index
|
||||
virtual ItemStack getItem (ModelIndex index) = 0;
|
||||
///< throws for invalid index
|
||||
|
||||
/// The number of items in the model, this specifies the range of indices you can pass to
|
||||
/// the getItem function (but this range is only valid until the next call to update())
|
||||
virtual size_t getItemCount() = 0;
|
||||
|
||||
/// Returns an invalid index if the item was not found
|
||||
virtual ModelIndex getIndex (ItemStack item) = 0;
|
||||
|
||||
/// Rebuild the item model, this will invalidate existing model indices
|
||||
virtual void update() = 0;
|
||||
|
||||
/// Move items from this model to \a otherModel.
|
||||
/// @note Derived implementations may return an empty Ptr if the move was unsuccessful.
|
||||
virtual MWWorld::Ptr moveItem (const ItemStack& item, size_t count, ItemModel* otherModel);
|
||||
|
||||
/// @param setNewOwner Set the copied item's owner to the actor we are copying to, or keep the original owner?
|
||||
/// @param setNewOwner If true, set the copied item's owner to the actor we are copying to,
|
||||
/// otherwise reset owner to ""
|
||||
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) = 0;
|
||||
virtual void removeItem (const ItemStack& item, size_t count) = 0;
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
@ -586,6 +587,15 @@ namespace MWGui
|
|||
ret += getMiscString(cellref.getFaction(), "Faction");
|
||||
if (cellref.getFactionRank() > 0)
|
||||
ret += getValueString(cellref.getFactionRank(), "Rank");
|
||||
|
||||
std::vector<std::pair<std::string, int> > itemOwners =
|
||||
MWBase::Environment::get().getMechanicsManager()->getStolenItemOwners(cellref.getRefId());
|
||||
|
||||
for (std::vector<std::pair<std::string, int> >::const_iterator it = itemOwners.begin(); it != itemOwners.end(); ++it)
|
||||
{
|
||||
ret += std::string("\nStolen ") + MyGUI::utility::toString(it->second) + " from " + it->first;
|
||||
}
|
||||
|
||||
ret += getMiscString(cellref.getGlobalVariable(), "Global");
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -135,11 +135,9 @@ namespace MWGui
|
|||
if (i == sourceModel->getItemCount())
|
||||
throw std::runtime_error("The borrowed item disappeared");
|
||||
|
||||
// reset owner while copying, but only for items bought by the player
|
||||
bool setNewOwner = (mMerchant.isEmpty());
|
||||
const ItemStack& item = sourceModel->getItem(i);
|
||||
// copy the borrowed items to our model
|
||||
copyItem(item, it->mCount, setNewOwner);
|
||||
copyItem(item, it->mCount);
|
||||
// then remove them from the source model
|
||||
sourceModel->removeItem(item, it->mCount);
|
||||
}
|
||||
|
|
|
@ -300,7 +300,8 @@ namespace MWGui
|
|||
// check if the player is attempting to sell back an item stolen from this actor
|
||||
for (std::vector<ItemStack>::iterator it = merchantBought.begin(); it != merchantBought.end(); ++it)
|
||||
{
|
||||
if (Misc::StringUtils::ciEqual(it->mBase.getCellRef().getOwner(), mPtr.getCellRef().getRefId()))
|
||||
if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(it->mBase.getCellRef().getRefId(),
|
||||
mPtr.getCellRef().getRefId()))
|
||||
{
|
||||
std::string msg = gmst.find("sNotifyMessage49")->getString();
|
||||
if (msg.find("%s") != std::string::npos)
|
||||
|
@ -315,6 +316,8 @@ namespace MWGui
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: move to mwmechanics
|
||||
|
||||
// Is the player buying?
|
||||
bool buying = (mCurrentMerchantOffer < 0);
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#include "mechanicsmanagerimp.hpp"
|
||||
#include "npcstats.hpp"
|
||||
|
||||
#include <components/esm/stolenitems.hpp>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
|
@ -873,31 +875,31 @@ namespace MWMechanics
|
|||
mAI = true;
|
||||
}
|
||||
|
||||
bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim)
|
||||
bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim)
|
||||
{
|
||||
const std::string& owner = item.getCellRef().getOwner();
|
||||
const std::string& owner = cellref.getOwner();
|
||||
bool isOwned = !owner.empty() && owner != "player";
|
||||
|
||||
const std::string& faction = item.getCellRef().getFaction();
|
||||
const std::string& faction = cellref.getFaction();
|
||||
bool isFactionOwned = false;
|
||||
if (!faction.empty() && ptr.getClass().isNpc())
|
||||
{
|
||||
const std::map<std::string, int>& factions = ptr.getClass().getNpcStats(ptr).getFactionRanks();
|
||||
std::map<std::string, int>::const_iterator found = factions.find(Misc::StringUtils::lowerCase(faction));
|
||||
if (found == factions.end()
|
||||
|| found->second < item.getCellRef().getFactionRank())
|
||||
|| found->second < cellref.getFactionRank())
|
||||
isFactionOwned = true;
|
||||
}
|
||||
|
||||
const std::string& globalVariable = item.getCellRef().getGlobalVariable();
|
||||
const std::string& globalVariable = cellref.getGlobalVariable();
|
||||
if (!globalVariable.empty() && MWBase::Environment::get().getWorld()->getGlobalInt(Misc::StringUtils::lowerCase(globalVariable)) == 1)
|
||||
{
|
||||
isOwned = false;
|
||||
isFactionOwned = false;
|
||||
}
|
||||
|
||||
if (!item.getCellRef().getOwner().empty())
|
||||
victim = MWBase::Environment::get().getWorld()->searchPtr(item.getCellRef().getOwner(), true);
|
||||
if (!cellref.getOwner().empty())
|
||||
victim = MWBase::Environment::get().getWorld()->searchPtr(cellref.getOwner(), true);
|
||||
|
||||
return (!isOwned && !isFactionOwned);
|
||||
}
|
||||
|
@ -916,7 +918,7 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
MWWorld::Ptr victim;
|
||||
if (isAllowedToUse(ptr, bed, victim))
|
||||
if (isAllowedToUse(ptr, bed.getCellRef(), victim))
|
||||
return false;
|
||||
|
||||
if(commitCrime(ptr, victim, OT_SleepingInOwnedBed))
|
||||
|
@ -931,27 +933,82 @@ namespace MWMechanics
|
|||
void MechanicsManager::objectOpened(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item)
|
||||
{
|
||||
MWWorld::Ptr victim;
|
||||
if (isAllowedToUse(ptr, item, victim))
|
||||
if (isAllowedToUse(ptr, item.getCellRef(), victim))
|
||||
return;
|
||||
commitCrime(ptr, victim, OT_Trespassing);
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, int> > MechanicsManager::getStolenItemOwners(const std::string& itemid)
|
||||
{
|
||||
std::vector<std::pair<std::string, int> > result;
|
||||
StolenItemsMap::const_iterator it = mStolenItems.find(Misc::StringUtils::lowerCase(itemid));
|
||||
if (it == mStolenItems.end())
|
||||
return result;
|
||||
else
|
||||
{
|
||||
const OwnerMap& owners = it->second;
|
||||
for (OwnerMap::const_iterator ownerIt = owners.begin(); ownerIt != owners.end(); ++ownerIt)
|
||||
result.push_back(std::make_pair(ownerIt->first.first, ownerIt->second));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
bool MechanicsManager::isItemStolenFrom(const std::string &itemid, const std::string &ownerid)
|
||||
{
|
||||
StolenItemsMap::const_iterator it = mStolenItems.find(Misc::StringUtils::lowerCase(itemid));
|
||||
if (it == mStolenItems.end())
|
||||
return false;
|
||||
const OwnerMap& owners = it->second;
|
||||
OwnerMap::const_iterator ownerFound = owners.find(std::make_pair(Misc::StringUtils::lowerCase(ownerid), false));
|
||||
return ownerFound != owners.end();
|
||||
}
|
||||
|
||||
void MechanicsManager::confiscateStolenItems(const MWWorld::Ptr &player, const MWWorld::Ptr &targetContainer)
|
||||
{
|
||||
MWWorld::ContainerStore& store = player.getClass().getContainerStore(player);
|
||||
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
|
||||
{
|
||||
StolenItemsMap::iterator stolenIt = mStolenItems.find(Misc::StringUtils::lowerCase(it->getClass().getId(*it)));
|
||||
if (stolenIt == mStolenItems.end())
|
||||
continue;
|
||||
OwnerMap& owners = stolenIt->second;
|
||||
int itemCount = it->getRefData().getCount();
|
||||
for (OwnerMap::iterator ownerIt = owners.begin(); ownerIt != owners.end();)
|
||||
{
|
||||
int toRemove = std::min(itemCount, ownerIt->second);
|
||||
itemCount -= toRemove;
|
||||
ownerIt->second -= toRemove;
|
||||
if (ownerIt->second == 0)
|
||||
owners.erase(ownerIt++);
|
||||
else
|
||||
++ownerIt;
|
||||
}
|
||||
|
||||
int toMove = it->getRefData().getCount() - itemCount;
|
||||
|
||||
targetContainer.getClass().getContainerStore(targetContainer).add(*it, toMove, targetContainer);
|
||||
store.remove(*it, toMove, player);
|
||||
}
|
||||
// TODO: unhardcode the locklevel
|
||||
targetContainer.getClass().lock(targetContainer,50);
|
||||
}
|
||||
|
||||
void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container,
|
||||
int count)
|
||||
{
|
||||
if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
return;
|
||||
|
||||
MWWorld::Ptr victim;
|
||||
|
||||
const MWWorld::CellRef* ownerCellRef = &item.getCellRef();
|
||||
if (!container.isEmpty())
|
||||
{
|
||||
// Inherit the owner of the container
|
||||
if (isAllowedToUse(ptr, container, victim))
|
||||
return;
|
||||
ownerCellRef = &container.getCellRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isAllowedToUse(ptr, item, victim))
|
||||
return;
|
||||
|
||||
if (!item.getCellRef().hasContentFile())
|
||||
{
|
||||
// this is a manually placed item, which means it was already stolen
|
||||
|
@ -959,6 +1016,20 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
if (isAllowedToUse(ptr, *ownerCellRef, victim))
|
||||
return;
|
||||
|
||||
Owner owner;
|
||||
owner.first = ownerCellRef->getOwner();
|
||||
owner.second = false;
|
||||
if (owner.first.empty())
|
||||
{
|
||||
owner.first = ownerCellRef->getFaction();
|
||||
owner.second = true;
|
||||
}
|
||||
Misc::StringUtils::toLower(owner.first);
|
||||
mStolenItems[Misc::StringUtils::lowerCase(item.getClass().getId(item))][owner] += count;
|
||||
|
||||
commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count);
|
||||
}
|
||||
|
||||
|
@ -967,7 +1038,7 @@ namespace MWMechanics
|
|||
// NOTE: victim may be empty
|
||||
|
||||
// Only player can commit crime
|
||||
if (player.getRefData().getHandle() != "player")
|
||||
if (player != MWBase::Environment::get().getWorld()->getPlayerPtr())
|
||||
return false;
|
||||
|
||||
// Find all the actors within the alarm radius
|
||||
|
@ -1369,22 +1440,37 @@ namespace MWMechanics
|
|||
|
||||
int MechanicsManager::countSavedGameRecords() const
|
||||
{
|
||||
return 1; // Death counter
|
||||
return 1 // Death counter
|
||||
+1; // Stolen items
|
||||
}
|
||||
|
||||
void MechanicsManager::write(ESM::ESMWriter &writer, Loading::Listener &listener) const
|
||||
{
|
||||
mActors.write(writer, listener);
|
||||
|
||||
ESM::StolenItems items;
|
||||
items.mStolenItems = mStolenItems;
|
||||
writer.startRecord(ESM::REC_STLN);
|
||||
items.write(writer);
|
||||
writer.endRecord(ESM::REC_STLN);
|
||||
}
|
||||
|
||||
void MechanicsManager::readRecord(ESM::ESMReader &reader, uint32_t type)
|
||||
{
|
||||
if (type == ESM::REC_STLN)
|
||||
{
|
||||
ESM::StolenItems items;
|
||||
items.load(reader);
|
||||
mStolenItems = items.mStolenItems;
|
||||
}
|
||||
else
|
||||
mActors.readRecord(reader, type);
|
||||
}
|
||||
|
||||
void MechanicsManager::clear()
|
||||
{
|
||||
mActors.clear();
|
||||
mStolenItems.clear();
|
||||
}
|
||||
|
||||
bool MechanicsManager::isAggressive(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target)
|
||||
|
|
|
@ -35,6 +35,11 @@ namespace MWMechanics
|
|||
Objects mObjects;
|
||||
Actors mActors;
|
||||
|
||||
typedef std::pair<std::string, bool> Owner; // < Owner id, bool isFaction >
|
||||
typedef std::map<Owner, int> OwnerMap; // < Owner, number of stolen items with this id from this owner >
|
||||
typedef std::map<std::string, OwnerMap> StolenItemsMap;
|
||||
StolenItemsMap mStolenItems;
|
||||
|
||||
public:
|
||||
|
||||
void buildPlayer();
|
||||
|
@ -130,9 +135,6 @@ namespace MWMechanics
|
|||
/// @return was it illegal, and someone saw you doing it? Also returns fail when enemies are nearby
|
||||
virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed);
|
||||
|
||||
/// @return is \a ptr allowed to take/use \a item or is it a crime?
|
||||
virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim);
|
||||
|
||||
virtual void forceStateUpdate(const MWWorld::Ptr &ptr);
|
||||
|
||||
virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number);
|
||||
|
@ -170,9 +172,21 @@ namespace MWMechanics
|
|||
|
||||
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual void confiscateStolenItems (const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer);
|
||||
|
||||
/// List the owners that the player has stolen this item from (the owner can be an NPC or a faction).
|
||||
/// <Owner, item count>
|
||||
virtual std::vector<std::pair<std::string, int> > getStolenItemOwners(const std::string& itemid);
|
||||
|
||||
/// Has the player stolen this item from the given owner?
|
||||
virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid);
|
||||
|
||||
private:
|
||||
void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
|
||||
OffenseType type, int arg=0);
|
||||
|
||||
/// @return is \a ptr allowed to take/use \a cellref or is it a crime?
|
||||
virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::CellRef& cellref, MWWorld::Ptr& victim);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -421,6 +421,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
|
|||
break;
|
||||
|
||||
case ESM::REC_DCOU:
|
||||
case ESM::REC_STLN:
|
||||
|
||||
MWBase::Environment::get().getMechanicsManager()->readRecord(reader, n.val);
|
||||
break;
|
||||
|
|
|
@ -117,6 +117,15 @@ namespace MWWorld
|
|||
return mCellRef.mGlobalVariable;
|
||||
}
|
||||
|
||||
void CellRef::resetGlobalVariable()
|
||||
{
|
||||
if (!mCellRef.mGlobalVariable.empty())
|
||||
{
|
||||
mChanged = true;
|
||||
mCellRef.mGlobalVariable.erase();
|
||||
}
|
||||
}
|
||||
|
||||
void CellRef::setFactionRank(int factionRank)
|
||||
{
|
||||
if (factionRank != mCellRef.mFactionRank)
|
||||
|
|
|
@ -75,6 +75,8 @@ namespace MWWorld
|
|||
// Used by bed rent scripts to allow the player to use the bed for the duration of the rent.
|
||||
std::string getGlobalVariable() const;
|
||||
|
||||
void resetGlobalVariable();
|
||||
|
||||
// ID of creature trapped in this soul gem
|
||||
std::string getSoul() const;
|
||||
void setSoul(const std::string& soul);
|
||||
|
|
|
@ -80,6 +80,8 @@ namespace MWWorld
|
|||
virtual std::string getId (const Ptr& ptr) const;
|
||||
///< Return ID of \a ptr or throw an exception, if class does not support ID retrieval
|
||||
/// (default implementation: throw an exception)
|
||||
/// @note This function is currently redundant; the same ID can be retrieved by CellRef::getRefId.
|
||||
/// Leaving it here for now in case we want to optimize later.
|
||||
|
||||
virtual void insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const;
|
||||
virtual void insertObject(const Ptr& ptr, const std::string& mesh, MWWorld::PhysicsSystem& physics) const;
|
||||
|
|
|
@ -222,28 +222,21 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr
|
|||
|
||||
MWWorld::ContainerStoreIterator it = end();
|
||||
|
||||
if (setOwner && actorPtr.getClass().isActor())
|
||||
{
|
||||
// HACK: Set owner on the original item, then reset it after we have copied it
|
||||
// If we set the owner on the copied item, it would not stack correctly...
|
||||
std::string oldOwner = itemPtr.getCellRef().getOwner();
|
||||
if (actorPtr == player)
|
||||
if (!setOwner || actorPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) // No point in setting owner to the player - NPCs will not respect this anyway
|
||||
{
|
||||
// No point in setting owner to the player - NPCs will not respect this anyway
|
||||
// Additionally, setting it to "player" would make those items not stack with items that don't have an owner
|
||||
itemPtr.getCellRef().setOwner("");
|
||||
}
|
||||
else
|
||||
{
|
||||
itemPtr.getCellRef().setOwner(actorPtr.getCellRef().getRefId());
|
||||
}
|
||||
|
||||
it = addImp(itemPtr, count);
|
||||
|
||||
itemPtr.getCellRef().setOwner(oldOwner);
|
||||
}
|
||||
else
|
||||
{
|
||||
it = addImp(itemPtr, count);
|
||||
}
|
||||
|
||||
// The copy of the original item we just made
|
||||
MWWorld::Ptr item = *it;
|
||||
|
@ -258,6 +251,14 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr
|
|||
pos.pos[1] = 0;
|
||||
pos.pos[2] = 0;
|
||||
item.getCellRef().setPosition(pos);
|
||||
|
||||
// reset ownership stuff, owner was already handled above
|
||||
item.getCellRef().resetGlobalVariable();
|
||||
item.getCellRef().setFaction("");
|
||||
item.getCellRef().setFactionRank(-1);
|
||||
|
||||
// must reset the RefNum on the copied item, so that the RefNum on the original item stays unique
|
||||
// maybe we should do this in the copy constructor instead?
|
||||
item.getCellRef().unsetRefNum(); // destroy link to content file
|
||||
|
||||
std::string script = item.getClass().getScript(item);
|
||||
|
@ -399,19 +400,19 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor
|
|||
return count - toRemove;
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, int factionRank, const MWWorld::ESMStore& store)
|
||||
void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner)
|
||||
{
|
||||
for (std::vector<ESM::ContItem>::const_iterator iter (items.mList.begin()); iter!=items.mList.end();
|
||||
++iter)
|
||||
{
|
||||
std::string id = Misc::StringUtils::lowerCase(iter->mItem.toString());
|
||||
addInitialItem(id, owner, faction, factionRank, iter->mCount);
|
||||
addInitialItem(id, owner, iter->mCount);
|
||||
}
|
||||
|
||||
flagAsModified();
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int factionRank,
|
||||
void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner,
|
||||
int count, bool topLevel, const std::string& levItem)
|
||||
{
|
||||
ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count);
|
||||
|
@ -423,7 +424,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
|
|||
if (topLevel && std::abs(count) > 1 && levItem->mFlags & ESM::ItemLevList::Each)
|
||||
{
|
||||
for (int i=0; i<std::abs(count); ++i)
|
||||
addInitialItem(id, owner, faction, factionRank, count > 0 ? 1 : -1, true, levItem->mId);
|
||||
addInitialItem(id, owner, count > 0 ? 1 : -1, true, levItem->mId);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
@ -431,7 +432,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
|
|||
std::string id = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false);
|
||||
if (id.empty())
|
||||
return;
|
||||
addInitialItem(id, owner, faction, factionRank, count, false, levItem->mId);
|
||||
addInitialItem(id, owner, count, false, levItem->mId);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -447,13 +448,11 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
|
|||
count = std::abs(count);
|
||||
|
||||
ref.getPtr().getCellRef().setOwner(owner);
|
||||
ref.getPtr().getCellRef().setFaction(faction);
|
||||
ref.getPtr().getCellRef().setFactionRank(factionRank);
|
||||
addImp (ref.getPtr(), count);
|
||||
}
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction, int factionRank)
|
||||
void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner)
|
||||
{
|
||||
// Remove the items already spawned by levelled items that will restock
|
||||
for (std::map<std::string, int>::iterator it = mLevelledItemMap.begin(); it != mLevelledItemMap.end(); ++it)
|
||||
|
@ -472,13 +471,13 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW
|
|||
|
||||
if (MWBase::Environment::get().getWorld()->getStore().get<ESM::ItemLevList>().search(it->mItem.toString()))
|
||||
{
|
||||
addInitialItem(item, owner, faction, factionRank, it->mCount, true);
|
||||
addInitialItem(item, owner, it->mCount, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
int currentCount = count(item);
|
||||
if (currentCount < std::abs(it->mCount))
|
||||
addInitialItem(item, owner, faction, factionRank, std::abs(it->mCount) - currentCount, true);
|
||||
addInitialItem(item, owner, std::abs(it->mCount) - currentCount, true);
|
||||
}
|
||||
}
|
||||
flagAsModified();
|
||||
|
|
|
@ -75,7 +75,7 @@ namespace MWWorld
|
|||
mutable float mCachedWeight;
|
||||
mutable bool mWeightUpToDate;
|
||||
ContainerStoreIterator addImp (const Ptr& ptr, int count);
|
||||
void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int factionRank, int count, bool topLevel=true, const std::string& levItem = "");
|
||||
void addInitialItem (const std::string& id, const std::string& owner, int count, bool topLevel=true, const std::string& levItem = "");
|
||||
|
||||
template<typename T>
|
||||
ContainerStoreIterator getState (CellRefList<T>& collection,
|
||||
|
@ -112,7 +112,7 @@ namespace MWWorld
|
|||
/// \attention Do not add items to an existing stack by increasing the count instead of
|
||||
/// calling this function!
|
||||
///
|
||||
/// @param setOwner Set the owner of the added item to \a actorPtr?
|
||||
/// @param setOwner Set the owner of the added item to \a actorPtr? If false, the owner is reset to "".
|
||||
///
|
||||
/// @return if stacking happened, return iterator to the item that was stacked against, otherwise iterator to the newly inserted item.
|
||||
|
||||
|
@ -151,10 +151,10 @@ namespace MWWorld
|
|||
virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2);
|
||||
///< @return true if the two specified objects can stack with each other
|
||||
|
||||
void fill (const ESM::InventoryList& items, const std::string& owner, const std::string& faction, int factionRank, const MWWorld::ESMStore& store);
|
||||
void fill (const ESM::InventoryList& items, const std::string& owner);
|
||||
///< Insert items into *this.
|
||||
|
||||
void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner, const std::string& faction, int factionRank);
|
||||
void restock (const ESM::InventoryList& items, const MWWorld::Ptr& ptr, const std::string& owner);
|
||||
|
||||
virtual void clear();
|
||||
///< Empty container.
|
||||
|
|
|
@ -2980,18 +2980,10 @@ namespace MWWorld
|
|||
|
||||
if (!closestChest.isEmpty()) //Found a close chest
|
||||
{
|
||||
ContainerStore& store = ptr.getClass().getContainerStore(ptr);
|
||||
for (ContainerStoreIterator it = store.begin(); it != store.end(); ++it) //Move all stolen stuff into chest
|
||||
{
|
||||
MWWorld::Ptr dummy;
|
||||
if (!MWBase::Environment::get().getMechanicsManager()->isAllowedToUse(getPlayerPtr(), *it, dummy))
|
||||
{
|
||||
closestChest.getClass().getContainerStore(closestChest).add(*it, it->getRefData().getCount(), closestChest);
|
||||
store.remove(*it, it->getRefData().getCount(), ptr);
|
||||
}
|
||||
}
|
||||
closestChest.getClass().lock(closestChest,50);
|
||||
MWBase::Environment::get().getMechanicsManager()->confiscateStolenItems(ptr, closestChest);
|
||||
}
|
||||
else
|
||||
std::cerr << "Failed to confiscate items: no stolen_goods container found" << std::endl;
|
||||
}
|
||||
|
||||
void World::goToJail()
|
||||
|
|
|
@ -63,7 +63,7 @@ add_component_dir (esm
|
|||
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
|
||||
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate
|
||||
npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile
|
||||
aisequence magiceffects util custommarkerstate
|
||||
aisequence magiceffects util custommarkerstate stolenitems
|
||||
)
|
||||
|
||||
add_component_dir (esmterrain
|
||||
|
|
|
@ -117,6 +117,7 @@ enum RecNameInts
|
|||
REC_MARK = FourCC<'M','A','R','K'>::value,
|
||||
REC_ENAB = FourCC<'E','N','A','B'>::value,
|
||||
REC_CAM_ = FourCC<'C','A','M','_'>::value,
|
||||
REC_STLN = FourCC<'S','T','L','N'>::value,
|
||||
|
||||
// format 1
|
||||
REC_FILT = FourCC<'F','I','L','T'>::value,
|
||||
|
|
47
components/esm/stolenitems.cpp
Normal file
47
components/esm/stolenitems.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include "stolenitems.hpp"
|
||||
|
||||
#include <components/esm/esmreader.hpp>
|
||||
#include <components/esm/esmwriter.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
||||
void StolenItems::write(ESMWriter &esm) const
|
||||
{
|
||||
for (StolenItemsMap::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it)
|
||||
{
|
||||
esm.writeHNString("NAME", it->first);
|
||||
for (std::map<std::pair<std::string, bool>, int>::const_iterator ownerIt = it->second.begin();
|
||||
ownerIt != it->second.end(); ++ownerIt)
|
||||
{
|
||||
if (ownerIt->first.second)
|
||||
esm.writeHNString("FNAM", ownerIt->first.first);
|
||||
else
|
||||
esm.writeHNString("ONAM", ownerIt->first.first);
|
||||
esm.writeHNT("COUN", ownerIt->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StolenItems::load(ESMReader &esm)
|
||||
{
|
||||
while (esm.isNextSub("NAME"))
|
||||
{
|
||||
std::string itemid = esm.getHString();
|
||||
|
||||
std::map<std::pair<std::string, bool>, int> ownerMap;
|
||||
while (esm.isNextSub("FNAM") || esm.isNextSub("ONAM"))
|
||||
{
|
||||
std::string subname = esm.retSubName().toString();
|
||||
std::string owner = esm.getHString();
|
||||
bool isFaction = (subname == "FNAM");
|
||||
int count;
|
||||
esm.getHNT(count, "COUN");
|
||||
ownerMap.insert(std::make_pair(std::make_pair(owner, isFaction), count));
|
||||
}
|
||||
|
||||
mStolenItems[itemid] = ownerMap;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
24
components/esm/stolenitems.hpp
Normal file
24
components/esm/stolenitems.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef OPENMW_COMPONENTS_ESM_STOLENITEMS_H
|
||||
#define OPENMW_COMPONENTS_ESM_STOLENITEMS_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
class ESMWriter;
|
||||
|
||||
// format 0, saved games only
|
||||
struct StolenItems
|
||||
{
|
||||
typedef std::map<std::string, std::map<std::pair<std::string, bool>, int> > StolenItemsMap;
|
||||
StolenItemsMap mStolenItems;
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
void write(ESM::ESMWriter& esm) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue