Merge pull request #336 from TES3MP/master

Add master commits up to 12 Nov 2017
new-script-api
David Cernat 7 years ago committed by GitHub
commit a21f5d18d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -150,7 +150,7 @@ namespace MWBase
/// Utility to check if taking this item is illegal and calling commitCrime if so /// Utility to check if taking this item is illegal and calling commitCrime if so
/// @param container The container the item is in; may be empty for an item in the world /// @param container The container the item is in; may be empty for an item in the world
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
int count) = 0; int count, bool alarm = true) = 0;
/// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so
virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0; virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0;
/// Attempt sleeping in a bed. If this is illegal, call commitCrime. /// Attempt sleeping in a bed. If this is illegal, call commitCrime.
@ -248,6 +248,7 @@ namespace MWBase
/// Has the player stolen this item from the given owner? /// Has the player stolen this item from the given owner?
virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0; virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid) = 0;
virtual bool isBoundItem(const MWWorld::Ptr& item) = 0;
virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) = 0; virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) = 0;
/// Turn actor into werewolf or normal form. /// Turn actor into werewolf or normal form.
@ -260,7 +261,6 @@ namespace MWBase
virtual void cleanupSummonedCreature(const MWWorld::Ptr& caster, int creatureActorId) = 0; virtual void cleanupSummonedCreature(const MWWorld::Ptr& caster, int creatureActorId) = 0;
virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) = 0; virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) = 0;
virtual bool isAttackPrepairing(const MWWorld::Ptr& ptr) = 0; virtual bool isAttackPrepairing(const MWWorld::Ptr& ptr) = 0;
virtual bool isRunning(const MWWorld::Ptr& ptr) = 0; virtual bool isRunning(const MWWorld::Ptr& ptr) = 0;
virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0; virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0;

@ -22,12 +22,10 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/dialoguemanager.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwmechanics/actorutil.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwmechanics/pickpocket.hpp"
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "countdialog.hpp" #include "countdialog.hpp"
@ -47,7 +45,6 @@ namespace MWGui
ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop)
: WindowBase("openmw_container_window.layout") : WindowBase("openmw_container_window.layout")
, mDragAndDrop(dragAndDrop) , mDragAndDrop(dragAndDrop)
, mPickpocketDetected(false)
, mSortModel(NULL) , mSortModel(NULL)
, mModel(NULL) , mModel(NULL)
, mSelectedItem(-1) , mSelectedItem(-1)
@ -69,10 +66,9 @@ namespace MWGui
void ContainerWindow::onItemSelected(int index) void ContainerWindow::onItemSelected(int index)
{ {
if (mDragAndDrop->mIsOnDragAndDrop) if (mDragAndDrop->mIsOnDragAndDrop && mModel)
{ {
if (mModel && mModel->allowedToInsertItems()) dropItem();
dropItem();
return; return;
} }
@ -151,71 +147,56 @@ namespace MWGui
void ContainerWindow::dropItem() void ContainerWindow::dropItem()
{ {
if (mPtr.getTypeName() == typeid(ESM::Container).name()) bool success = mModel->onDropItem(mDragAndDrop->mItem.mBase, mDragAndDrop->mDraggedCount);
{
// check container organic flag
MWWorld::LiveCellRef<ESM::Container>* ref = mPtr.get<ESM::Container>();
if (ref->mBase->mFlags & ESM::Container::Organic)
{
MWBase::Environment::get().getWindowManager()->
messageBox("#{sContentsMessage2}");
return;
}
// check that we don't exceed container capacity
MWWorld::Ptr item = mDragAndDrop->mItem.mBase;
float weight = item.getClass().getWeight(item) * mDragAndDrop->mDraggedCount;
if (mPtr.getClass().getCapacity(mPtr) < mPtr.getClass().getEncumbrance(mPtr) + weight)
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sContentsMessage3}");
return;
}
}
/* /*
Start of tes3mp addition Start of tes3mp addition
Send an ID_CONTAINER packet every time an item is dropped in a container Send an ID_CONTAINER packet every time an item is dropped in a container
*/ */
mwmp::WorldEvent *worldEvent = mwmp::Main::get().getNetworking()->getWorldEvent(); if (success)
worldEvent->reset(); {
worldEvent->cell = *mPtr.getCell()->getCell(); mwmp::WorldEvent *worldEvent = mwmp::Main::get().getNetworking()->getWorldEvent();
worldEvent->action = mwmp::BaseEvent::ADD; worldEvent->reset();
worldEvent->cell = *mPtr.getCell()->getCell();
worldEvent->action = mwmp::BaseEvent::ADD;
mwmp::WorldObject worldObject; mwmp::WorldObject worldObject;
worldObject.refId = mPtr.getCellRef().getRefId(); worldObject.refId = mPtr.getCellRef().getRefId();
worldObject.refNumIndex = mPtr.getCellRef().getRefNum().mIndex; worldObject.refNumIndex = mPtr.getCellRef().getRefNum().mIndex;
worldObject.mpNum = mPtr.getCellRef().getMpNum(); worldObject.mpNum = mPtr.getCellRef().getMpNum();
MWWorld::Ptr itemPtr = mDragAndDrop->mItem.mBase; MWWorld::Ptr itemPtr = mDragAndDrop->mItem.mBase;
mwmp::ContainerItem containerItem; mwmp::ContainerItem containerItem;
containerItem.refId = itemPtr.getCellRef().getRefId(); containerItem.refId = itemPtr.getCellRef().getRefId();
// Make sure we get the drag and drop count, not the count of the original item // Make sure we get the drag and drop count, not the count of the original item
containerItem.count = mDragAndDrop->mDraggedCount; containerItem.count = mDragAndDrop->mDraggedCount;
containerItem.charge = itemPtr.getCellRef().getCharge(); containerItem.charge = itemPtr.getCellRef().getCharge();
worldObject.containerItems.push_back(containerItem); worldObject.containerItems.push_back(containerItem);
worldEvent->addObject(worldObject); worldEvent->addObject(worldObject);
mwmp::Main::get().getNetworking()->getWorldPacket(ID_CONTAINER)->setEvent(worldEvent); mwmp::Main::get().getNetworking()->getWorldPacket(ID_CONTAINER)->setEvent(worldEvent);
mwmp::Main::get().getNetworking()->getWorldPacket(ID_CONTAINER)->Send(); mwmp::Main::get().getNetworking()->getWorldPacket(ID_CONTAINER)->Send();
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_CONTAINER about\n- Ptr cellRef: %s, %i\n- cell: %s\n- item: %s, %i", LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_CONTAINER about\n- Ptr cellRef: %s, %i\n- cell: %s\n- item: %s, %i",
worldObject.refId.c_str(), worldObject.refNumIndex, worldEvent->cell.getDescription().c_str(), worldObject.refId.c_str(), worldObject.refNumIndex, worldEvent->cell.getDescription().c_str(),
containerItem.refId.c_str(), containerItem.count); containerItem.refId.c_str(), containerItem.count);
}
/* /*
End of tes3mp addition End of tes3mp addition
*/ */
mDragAndDrop->drop(mModel, mItemView); if (success)
mDragAndDrop->drop(mModel, mItemView);
} }
void ContainerWindow::onBackgroundSelected() void ContainerWindow::onBackgroundSelected()
{ {
if (mDragAndDrop->mIsOnDragAndDrop && mModel && mModel->allowedToInsertItems()) if (mDragAndDrop->mIsOnDragAndDrop && mModel)
dropItem(); dropItem();
} }
@ -231,7 +212,6 @@ namespace MWGui
End of tes3mp addition End of tes3mp addition
*/ */
mPickpocketDetected = false;
mPtr = container; mPtr = container;
bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead(); bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead();
@ -241,8 +221,7 @@ namespace MWGui
if (mPtr.getClass().isNpc() && !loot) if (mPtr.getClass().isNpc() && !loot)
{ {
// we are stealing stuff // we are stealing stuff
MWWorld::Ptr player = MWMechanics::getPlayer(); mModel = new PickpocketItemModel(mPtr, new InventoryItemModel(container),
mModel = new PickpocketItemModel(player, new InventoryItemModel(container),
!mPtr.getClass().getCreatureStats(mPtr).getKnockedDown()); !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown());
} }
else else
@ -287,24 +266,7 @@ namespace MWGui
WindowBase::onClose(); WindowBase::onClose();
if (dynamic_cast<PickpocketItemModel*>(mModel) mModel->onClose();
// Make sure we were actually closed, rather than just temporarily hidden (e.g. console or main menu opened)
&& !MWBase::Environment::get().getWindowManager()->containsMode(GM_Container)
// If it was already detected while taking an item, no need to check now
&& !mPickpocketDetected
)
{
MWWorld::Ptr player = MWMechanics::getPlayer();
MWMechanics::Pickpocket pickpocket(player, mPtr);
if (pickpocket.finish())
{
MWBase::Environment::get().getMechanicsManager()->commitCrime(
player, mPtr, MWBase::MechanicsManager::OT_Pickpocket, 0, true);
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
mPickpocketDetected = true;
return;
}
}
} }
void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender)
@ -422,32 +384,7 @@ namespace MWGui
bool ContainerWindow::onTakeItem(const ItemStack &item, int count) bool ContainerWindow::onTakeItem(const ItemStack &item, int count)
{ {
MWWorld::Ptr player = MWMechanics::getPlayer(); return mModel->onTakeItem(item.mBase, count);
// TODO: move to ItemModels
if (dynamic_cast<PickpocketItemModel*>(mModel)
&& !mPtr.getClass().getCreatureStats(mPtr).getKnockedDown())
{
MWMechanics::Pickpocket pickpocket(player, mPtr);
if (pickpocket.pick(item.mBase, count))
{
MWBase::Environment::get().getMechanicsManager()->commitCrime(
player, mPtr, MWBase::MechanicsManager::OT_Pickpocket, 0, true);
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
mPickpocketDetected = true;
return false;
}
else
player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, 1);
}
else
{
// Looting a dead corpse is considered OK
if (mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead())
return true;
else
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, mPtr, count);
}
return true;
} }
} }

@ -44,8 +44,6 @@ namespace MWGui
private: private:
DragAndDrop* mDragAndDrop; DragAndDrop* mDragAndDrop;
bool mPickpocketDetected;
MWGui::ItemView* mItemView; MWGui::ItemView* mItemView;
SortFilterItemModel* mSortModel; SortFilterItemModel* mSortModel;
ItemModel* mModel; ItemModel* mModel;

@ -2,12 +2,16 @@
#include <algorithm> #include <algorithm>
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/actorutil.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/actorutil.hpp"
@ -185,5 +189,51 @@ void ContainerItemModel::update()
} }
} }
} }
bool ContainerItemModel::onDropItem(const MWWorld::Ptr &item, int count)
{
if (mItemSources.empty())
return false;
MWWorld::Ptr target = mItemSources[0];
if (target.getTypeName() != typeid(ESM::Container).name())
return true;
// check container organic flag
MWWorld::LiveCellRef<ESM::Container>* ref = target.get<ESM::Container>();
if (ref->mBase->mFlags & ESM::Container::Organic)
{
MWBase::Environment::get().getWindowManager()->
messageBox("#{sContentsMessage2}");
return false;
}
// check that we don't exceed container capacity
float weight = item.getClass().getWeight(item) * count;
if (target.getClass().getCapacity(target) < target.getClass().getEncumbrance(target) + weight)
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sContentsMessage3}");
return false;
}
return true;
}
bool ContainerItemModel::onTakeItem(const MWWorld::Ptr &item, int count)
{
if (mItemSources.empty())
return false;
MWWorld::Ptr target = mItemSources[0];
// Looting a dead corpse is considered OK
if (target.getClass().isActor() && target.getClass().getCreatureStats(target).isDead())
return true;
MWWorld::Ptr player = MWMechanics::getPlayer();
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item, target, count);
return true;
}
} }

@ -18,6 +18,10 @@ namespace MWGui
ContainerItemModel (const MWWorld::Ptr& source); ContainerItemModel (const MWWorld::Ptr& source);
virtual bool allowedToUseItems() const; virtual bool allowedToUseItems() const;
virtual bool onDropItem(const MWWorld::Ptr &item, int count);
virtual bool onTakeItem(const MWWorld::Ptr &item, int count);
virtual ItemStack getItem (ModelIndex index); virtual ItemStack getItem (ModelIndex index);
virtual ModelIndex getIndex (ItemStack item); virtual ModelIndex getIndex (ItemStack item);
virtual size_t getItemCount(); virtual size_t getItemCount();

@ -9,6 +9,9 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp"
namespace MWGui namespace MWGui
{ {
@ -116,4 +119,16 @@ void InventoryItemModel::update()
} }
} }
bool InventoryItemModel::onTakeItem(const MWWorld::Ptr &item, int count)
{
// Looting a dead corpse is considered OK
if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead())
return true;
MWWorld::Ptr player = MWMechanics::getPlayer();
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item, mActor, count);
return true;
}
} }

@ -15,6 +15,8 @@ namespace MWGui
virtual ModelIndex getIndex (ItemStack item); virtual ModelIndex getIndex (ItemStack item);
virtual size_t getItemCount(); virtual size_t getItemCount();
virtual bool onTakeItem(const MWWorld::Ptr &item, int count);
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false);
virtual void removeItem (const ItemStack& item, size_t count); virtual void removeItem (const ItemStack& item, size_t count);

@ -9,6 +9,7 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp"
namespace MWGui namespace MWGui
{ {
@ -23,38 +24,7 @@ namespace MWGui
if (base.getClass().getEnchantment(base) != "") if (base.getClass().getEnchantment(base) != "")
mFlags |= Flag_Enchanted; mFlags |= Flag_Enchanted;
static std::set<std::string> boundItemIDCache; if (MWBase::Environment::get().getMechanicsManager()->isBoundItem(base))
// If this is empty then we haven't executed the GMST cache logic yet; or there isn't any sMagicBound* GMST's for some reason
if (boundItemIDCache.empty())
{
// Build a list of known bound item ID's
const MWWorld::Store<ESM::GameSetting> &gameSettings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
for (MWWorld::Store<ESM::GameSetting>::iterator currentIteration = gameSettings.begin(); currentIteration != gameSettings.end(); ++currentIteration)
{
const ESM::GameSetting &currentSetting = *currentIteration;
std::string currentGMSTID = currentSetting.mId;
Misc::StringUtils::lowerCaseInPlace(currentGMSTID);
// Don't bother checking this GMST if it's not a sMagicBound* one.
const std::string& toFind = "smagicbound";
if (currentGMSTID.compare(0, toFind.length(), toFind) != 0)
continue;
// All sMagicBound* GMST's should be of type string
std::string currentGMSTValue = currentSetting.getString();
Misc::StringUtils::lowerCaseInPlace(currentGMSTValue);
boundItemIDCache.insert(currentGMSTValue);
}
}
// Perform bound item check and assign the Flag_Bound bit if it passes
std::string tempItemID = base.getCellRef().getRefId();
Misc::StringUtils::lowerCaseInPlace(tempItemID);
if (boundItemIDCache.count(tempItemID) != 0)
mFlags |= Flag_Bound; mFlags |= Flag_Bound;
} }
@ -124,7 +94,12 @@ namespace MWGui
return true; return true;
} }
bool ItemModel::allowedToInsertItems() const bool ItemModel::onDropItem(const MWWorld::Ptr &item, int count)
{
return true;
}
bool ItemModel::onTakeItem(const MWWorld::Ptr &item, int count)
{ {
return true; return true;
} }
@ -198,4 +173,18 @@ namespace MWGui
mSourceModel = sourceModel; mSourceModel = sourceModel;
} }
void ProxyItemModel::onClose()
{
mSourceModel->onClose();
}
bool ProxyItemModel::onDropItem(const MWWorld::Ptr &item, int count)
{
return mSourceModel->onDropItem(item, count);
}
bool ProxyItemModel::onTakeItem(const MWWorld::Ptr &item, int count)
{
return mSourceModel->onTakeItem(item, count);
}
} }

@ -72,9 +72,11 @@ namespace MWGui
/// Is the player allowed to use items from this item model? (default true) /// Is the player allowed to use items from this item model? (default true)
virtual bool allowedToUseItems() const; virtual bool allowedToUseItems() const;
virtual void onClose()
/// Is the player allowed to insert items into this model? (default true) {
virtual bool allowedToInsertItems() const; }
virtual bool onDropItem(const MWWorld::Ptr &item, int count);
virtual bool onTakeItem(const MWWorld::Ptr &item, int count);
private: private:
ItemModel(const ItemModel&); ItemModel(const ItemModel&);
@ -91,6 +93,10 @@ namespace MWGui
bool allowedToUseItems() const; bool allowedToUseItems() const;
virtual void onClose();
virtual bool onDropItem(const MWWorld::Ptr &item, int count);
virtual bool onTakeItem(const MWWorld::Ptr &item, int count);
virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false); virtual MWWorld::Ptr copyItem (const ItemStack& item, size_t count, bool setNewOwner=false);
virtual void removeItem (const ItemStack& item, size_t count); virtual void removeItem (const ItemStack& item, size_t count);
virtual ModelIndex getIndex (ItemStack item); virtual ModelIndex getIndex (ItemStack item);

@ -3,15 +3,26 @@
#include <components/misc/rng.hpp> #include <components/misc/rng.hpp>
#include <components/esm/loadskil.hpp> #include <components/esm/loadskil.hpp>
#include "../mwmechanics/actorutil.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/pickpocket.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/windowmanager.hpp"
namespace MWGui namespace MWGui
{ {
PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& thief, ItemModel *sourceModel, bool hideItems) PickpocketItemModel::PickpocketItemModel(const MWWorld::Ptr& actor, ItemModel *sourceModel, bool hideItems)
: mActor(actor), mPickpocketDetected(false)
{ {
MWWorld::Ptr player = MWMechanics::getPlayer();
mSourceModel = sourceModel; mSourceModel = sourceModel;
int chance = thief.getClass().getSkill(thief, ESM::Skill::Sneak); int chance = player.getClass().getSkill(player, ESM::Skill::Sneak);
mSourceModel->update(); mSourceModel->update();
@ -66,13 +77,63 @@ namespace MWGui
void PickpocketItemModel::removeItem (const ItemStack &item, size_t count) void PickpocketItemModel::removeItem (const ItemStack &item, size_t count)
{ {
ProxyItemModel::removeItem(item, count); ProxyItemModel::removeItem(item, count);
/// \todo check if player is detected
} }
bool PickpocketItemModel::allowedToInsertItems() const bool PickpocketItemModel::onDropItem(const MWWorld::Ptr &item, int count)
{ {
// don't allow "reverse pickpocket" (yet) // don't allow "reverse pickpocket" (it will be handled by scripts after 1.0)
return false; return false;
} }
void PickpocketItemModel::onClose()
{
// Make sure we were actually closed, rather than just temporarily hidden (e.g. console or main menu opened)
if (MWBase::Environment::get().getWindowManager()->containsMode(GM_Container)
// If it was already detected while taking an item, no need to check now
|| mPickpocketDetected)
return;
MWWorld::Ptr player = MWMechanics::getPlayer();
MWMechanics::Pickpocket pickpocket(player, mActor);
if (pickpocket.finish())
{
MWBase::Environment::get().getMechanicsManager()->commitCrime(
player, mActor, MWBase::MechanicsManager::OT_Pickpocket, 0, true);
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
mPickpocketDetected = true;
}
}
bool PickpocketItemModel::onTakeItem(const MWWorld::Ptr &item, int count)
{
if (mActor.getClass().getCreatureStats(mActor).getKnockedDown())
return mSourceModel->onTakeItem(item, count);
bool success = stealItem(item, count);
if (success)
{
MWWorld::Ptr player = MWMechanics::getPlayer();
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item, mActor, count, false);
}
return success;
}
bool PickpocketItemModel::stealItem(const MWWorld::Ptr &item, int count)
{
MWWorld::Ptr player = MWMechanics::getPlayer();
MWMechanics::Pickpocket pickpocket(player, mActor);
if (pickpocket.pick(item, count))
{
MWBase::Environment::get().getMechanicsManager()->commitCrime(
player, mActor, MWBase::MechanicsManager::OT_Pickpocket, 0, true);
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
mPickpocketDetected = true;
return false;
}
else
player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, 1);
return true;
}
} }

@ -17,7 +17,14 @@ namespace MWGui
virtual size_t getItemCount(); virtual size_t getItemCount();
virtual void update(); virtual void update();
virtual void removeItem (const ItemStack& item, size_t count); virtual void removeItem (const ItemStack& item, size_t count);
virtual bool allowedToInsertItems() const; virtual void onClose();
virtual bool onDropItem(const MWWorld::Ptr &item, int count);
virtual bool onTakeItem(const MWWorld::Ptr &item, int count);
protected:
MWWorld::Ptr mActor;
bool mPickpocketDetected;
bool stealItem(const MWWorld::Ptr &item, int count);
private: private:
std::vector<ItemStack> mHiddenItems; std::vector<ItemStack> mHiddenItems;

@ -311,4 +311,18 @@ namespace MWGui
std::sort(mItems.begin(), mItems.end(), cmp); std::sort(mItems.begin(), mItems.end(), cmp);
} }
void SortFilterItemModel::onClose()
{
mSourceModel->onClose();
}
bool SortFilterItemModel::onDropItem(const MWWorld::Ptr &item, int count)
{
return mSourceModel->onDropItem(item, count);
}
bool SortFilterItemModel::onTakeItem(const MWWorld::Ptr &item, int count)
{
return mSourceModel->onTakeItem(item, count);
}
} }

@ -29,6 +29,10 @@ namespace MWGui
/// Use ItemStack::Type for sorting? /// Use ItemStack::Type for sorting?
void setSortByType(bool sort) { mSortByType = sort; } void setSortByType(bool sort) { mSortByType = sort; }
void onClose();
bool onDropItem(const MWWorld::Ptr &item, int count);
bool onTakeItem(const MWWorld::Ptr &item, int count);
static const int Category_Weapon = (1<<1); static const int Category_Weapon = (1<<1);
static const int Category_Apparel = (1<<2); static const int Category_Apparel = (1<<2);
static const int Category_Misc = (1<<3); static const int Category_Misc = (1<<3);

@ -1381,8 +1381,13 @@ namespace MWMechanics
float sqrHeadTrackDistance = std::numeric_limits<float>::max(); float sqrHeadTrackDistance = std::numeric_limits<float>::max();
MWWorld::Ptr headTrackTarget; MWWorld::Ptr headTrackTarget;
MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
// Unconsious actor can not track target // Unconsious actor can not track target
if (!iter->first.getClass().getCreatureStats(iter->first).getKnockedDown()) // Also actors in combat and pursue mode do not bother to headtrack
if (!stats.getKnockedDown() &&
!stats.getAiSequence().isInCombat() &&
!stats.getAiSequence().hasPackage(AiPackage::TypeIdPursue))
{ {
for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it) for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
{ {
@ -1390,8 +1395,9 @@ namespace MWMechanics
continue; continue;
updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance); updateHeadTracking(iter->first, it->first, headTrackTarget, sqrHeadTrackDistance);
} }
iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget);
} }
iter->second->getCharacterController()->setHeadTrackTarget(headTrackTarget);
} }
if (iter->first.getClass().isNpc() && iter->first != player && (isLocalActor || isAIActive)) if (iter->first.getClass().isNpc() && iter->first != player && (isLocalActor || isAIActive))

@ -558,6 +558,22 @@ namespace MWMechanics
void AiCombatStorage::startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target) void AiCombatStorage::startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target)
{ {
// get the range of the target's weapon
MWWorld::Ptr targetWeapon = MWWorld::Ptr();
const MWWorld::Class& targetClass = target.getClass();
if (targetClass.hasInventoryStore(target))
{
MWMechanics::WeaponType weapType = WeapType_None;
MWWorld::ContainerStoreIterator weaponSlot =
MWMechanics::getActiveWeapon(targetClass.getCreatureStats(target), targetClass.getInventoryStore(target), &weapType);
if (weapType != WeapType_PickProbe && weapType != WeapType_Spell && weapType != WeapType_None && weapType != WeapType_HandToHand)
targetWeapon = *weaponSlot;
}
bool targetUsesRanged = false;
float rangeAttackOfTarget = ActionWeapon(targetWeapon).getCombatRange(targetUsesRanged);
if (mMovement.mPosition[0] || mMovement.mPosition[1]) if (mMovement.mPosition[0] || mMovement.mPosition[1])
{ {
mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability();
@ -566,28 +582,6 @@ namespace MWMechanics
// dodge movements (for NPCs and bipedal creatures) // dodge movements (for NPCs and bipedal creatures)
else if (actor.getClass().isBipedal(actor)) else if (actor.getClass().isBipedal(actor))
{ {
// get the range of the target's weapon
float rangeAttackOfTarget = 0.f;
MWWorld::Ptr targetWeapon = MWWorld::Ptr();
const MWWorld::Class& targetClass = target.getClass();
if (targetClass.hasInventoryStore(target))
{
MWMechanics::WeaponType weapType = WeapType_None;
MWWorld::ContainerStoreIterator weaponSlot =
MWMechanics::getActiveWeapon(targetClass.getCreatureStats(target), targetClass.getInventoryStore(target), &weapType);
if (weapType != WeapType_PickProbe && weapType != WeapType_Spell && weapType != WeapType_None && weapType != WeapType_HandToHand)
targetWeapon = *weaponSlot;
}
std::shared_ptr<Action> targetWeaponAction (new ActionWeapon(targetWeapon));
if (targetWeaponAction.get())
{
bool isRangedCombat = false;
rangeAttackOfTarget = targetWeaponAction->getCombatRange(isRangedCombat);
}
// apply sideway movement (kind of dodging) with some probability // apply sideway movement (kind of dodging) with some probability
// if actor is within range of target's weapon // if actor is within range of target's weapon
if (distToTarget <= rangeAttackOfTarget && Misc::Rng::rollClosedProbability() < 0.25) if (distToTarget <= rangeAttackOfTarget && Misc::Rng::rollClosedProbability() < 0.25)
@ -598,16 +592,18 @@ namespace MWMechanics
} }
} }
// Below behavior for backing up during ranged combat differs from vanilla. // Backing up behaviour
// Vanilla is observed as backing up only as far as fCombatDistance or // Actor backs up slightly further away than opponent's weapon range
// opponent's weapon range, or not backing up if opponent is also using a ranged weapon // (in vanilla - only as far as oponent's weapon range),
if (isDistantCombat && distToTarget < rangeAttack / 4) // or not at all if opponent is using a ranged weapon
if (isDistantCombat)
{ {
// actor should not back up into water // actor should not back up into water
if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.5f)) if (MWBase::Environment::get().getWorld()->isUnderwater(MWWorld::ConstPtr(actor), 0.5f))
return; return;
mMovement.mPosition[1] = -1; if (!targetUsesRanged && distToTarget <= rangeAttackOfTarget*1.5) // Don't back up if the target is wielding ranged weapon
mMovement.mPosition[1] = -1;
} }
} }

@ -115,6 +115,7 @@ namespace MWMechanics
isRanged = false; isRanged = false;
static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fCombatDistance")->getFloat(); static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fCombatDistance")->getFloat();
static const float fProjectileMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fProjectileMaxSpeed")->getFloat();
if (mWeapon.isEmpty()) if (mWeapon.isEmpty())
{ {
@ -128,7 +129,7 @@ namespace MWMechanics
if (weapon->mData.mType >= ESM::Weapon::MarksmanBow) if (weapon->mData.mType >= ESM::Weapon::MarksmanBow)
{ {
isRanged = true; isRanged = true;
return 1000.f; return fProjectileMaxSpeed;
} }
else else
return weapon->mData.mReach * fCombatDistance; return weapon->mData.mReach * fCombatDistance;

@ -866,6 +866,45 @@ namespace MWMechanics
mAI = true; mAI = true;
} }
bool MechanicsManager::isBoundItem(const MWWorld::Ptr& item)
{
static std::set<std::string> boundItemIDCache;
// If this is empty then we haven't executed the GMST cache logic yet; or there isn't any sMagicBound* GMST's for some reason
if (boundItemIDCache.empty())
{
// Build a list of known bound item ID's
const MWWorld::Store<ESM::GameSetting> &gameSettings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
for (MWWorld::Store<ESM::GameSetting>::iterator currentIteration = gameSettings.begin(); currentIteration != gameSettings.end(); ++currentIteration)
{
const ESM::GameSetting &currentSetting = *currentIteration;
std::string currentGMSTID = currentSetting.mId;
Misc::StringUtils::lowerCaseInPlace(currentGMSTID);
// Don't bother checking this GMST if it's not a sMagicBound* one.
const std::string& toFind = "smagicbound";
if (currentGMSTID.compare(0, toFind.length(), toFind) != 0)
continue;
// All sMagicBound* GMST's should be of type string
std::string currentGMSTValue = currentSetting.getString();
Misc::StringUtils::lowerCaseInPlace(currentGMSTValue);
boundItemIDCache.insert(currentGMSTValue);
}
}
// Perform bound item check and assign the Flag_Bound bit if it passes
std::string tempItemID = item.getCellRef().getRefId();
Misc::StringUtils::lowerCaseInPlace(tempItemID);
if (boundItemIDCache.count(tempItemID) != 0)
return true;
return false;
}
bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim) bool MechanicsManager::isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim)
{ {
if (target.isEmpty()) if (target.isEmpty())
@ -1050,7 +1089,7 @@ namespace MWMechanics
} }
void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container, void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, const MWWorld::Ptr& container,
int count) int count, bool alarm)
{ {
if (ptr != getPlayer()) if (ptr != getPlayer())
return; return;
@ -1079,19 +1118,29 @@ namespace MWMechanics
return; return;
Owner owner; Owner owner;
owner.first = ownerCellRef->getOwner();
owner.second = false; owner.second = false;
if (owner.first.empty()) if (!container.isEmpty() && container.getClass().isActor())
{ {
owner.first = ownerCellRef->getFaction(); // "container" is an actor inventory, so just take actor's ID
owner.second = true; owner.first = ownerCellRef->getRefId();
} }
else
{
owner.first = ownerCellRef->getOwner();
if (owner.first.empty())
{
owner.first = ownerCellRef->getFaction();
owner.second = true;
}
}
Misc::StringUtils::lowerCaseInPlace(owner.first); Misc::StringUtils::lowerCaseInPlace(owner.first);
if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId))
mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count; mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count;
commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); if (alarm)
commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count);
} }

@ -145,7 +145,7 @@ namespace MWMechanics
/// Utility to check if taking this item is illegal and calling commitCrime if so /// Utility to check if taking this item is illegal and calling commitCrime if so
/// @param container The container the item is in; may be empty for an item in the world /// @param container The container the item is in; may be empty for an item in the world
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
int count); int count, bool alarm = true);
/// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so
virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item); virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item);
/// Attempt sleeping in a bed. If this is illegal, call commitCrime. /// Attempt sleeping in a bed. If this is illegal, call commitCrime.
@ -214,6 +214,8 @@ namespace MWMechanics
/// Has the player stolen this item from the given owner? /// Has the player stolen this item from the given owner?
virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid); virtual bool isItemStolenFrom(const std::string& itemid, const std::string& ownerid);
virtual bool isBoundItem(const MWWorld::Ptr& item);
/// @return is \a ptr allowed to take/use \a target or is it a crime? /// @return is \a ptr allowed to take/use \a target or is it a crime?
virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim); virtual bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim);

Loading…
Cancel
Save