Implement pickpocket detection. Play a voiced dialogue entry when detected.

actorid
scrawl 11 years ago
parent ea3ee4407f
commit 780bf5a2cd

@ -74,7 +74,7 @@ add_openmw_dir (mwmechanics
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting
disease disease pickpocket
) )
add_openmw_dir (mwbase add_openmw_dir (mwbase

@ -6,10 +6,13 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/dialoguemanager.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
#include "../mwmechanics/pickpocket.hpp"
#include "countdialog.hpp" #include "countdialog.hpp"
#include "tradewindow.hpp" #include "tradewindow.hpp"
#include "inventorywindow.hpp" #include "inventorywindow.hpp"
@ -123,6 +126,7 @@ namespace MWGui
, mSelectedItem(-1) , mSelectedItem(-1)
, mModel(NULL) , mModel(NULL)
, mSortModel(NULL) , mSortModel(NULL)
, mPickpocketDetected(false)
{ {
getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); getWidget(mDisposeCorpseButton, "DisposeCorpseButton");
getWidget(mTakeButton, "TakeButton"); getWidget(mTakeButton, "TakeButton");
@ -171,6 +175,9 @@ namespace MWGui
void ContainerWindow::dragItem(MyGUI::Widget* sender, int count) void ContainerWindow::dragItem(MyGUI::Widget* sender, int count)
{ {
if (!onTakeItem(mModel->getItem(mSelectedItem), count))
return;
mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count); mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count);
} }
@ -208,6 +215,7 @@ namespace MWGui
void ContainerWindow::open(const MWWorld::Ptr& container, bool loot) void ContainerWindow::open(const MWWorld::Ptr& container, bool loot)
{ {
mPickpocketDetected = false;
mPtr = container; mPtr = container;
if (mPtr.getTypeName() == typeid(ESM::NPC).name() && !loot) if (mPtr.getTypeName() == typeid(ESM::NPC).name() && !loot)
@ -230,6 +238,28 @@ namespace MWGui
setTitle(MWWorld::Class::get(container).getName(container)); setTitle(MWWorld::Class::get(container).getName(container));
} }
void ContainerWindow::close()
{
WindowBase::close();
// 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)
&& !mPickpocketDetected // If it was already detected while taking an item, no need to check now
)
{
MWMechanics::Pickpocket pickpocket(MWBase::Environment::get().getWorld()->getPlayer().getPlayer(),
mPtr);
if (pickpocket.finish())
{
// TODO: crime
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief");
mPickpocketDetected = true;
return;
}
}
}
void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender)
{ {
if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop)
@ -255,8 +285,13 @@ namespace MWGui
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
} }
playerModel->copyItem(mModel->getItem(i), mModel->getItem(i).mCount); const ItemStack& item = mModel->getItem(i);
mModel->removeItem(mModel->getItem(i), mModel->getItem(i).mCount);
if (!onTakeItem(item, item.mCount))
break;
playerModel->copyItem(item, item.mCount);
mModel->removeItem(item, item.mCount);
} }
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container);
@ -283,4 +318,22 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container);
} }
bool ContainerWindow::onTakeItem(const ItemStack &item, int count)
{
if (dynamic_cast<PickpocketItemModel*>(mModel))
{
MWMechanics::Pickpocket pickpocket(MWBase::Environment::get().getWorld()->getPlayer().getPlayer(),
mPtr);
if (pickpocket.pick(item.mBase, count))
{
// TODO: crime
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief");
mPickpocketDetected = true;
return false;
}
}
return true;
}
} }

@ -52,10 +52,13 @@ namespace MWGui
ContainerWindow(DragAndDrop* dragAndDrop); ContainerWindow(DragAndDrop* dragAndDrop);
void open(const MWWorld::Ptr& container, bool loot=false); void open(const MWWorld::Ptr& container, bool loot=false);
virtual void close();
private: private:
DragAndDrop* mDragAndDrop; DragAndDrop* mDragAndDrop;
bool mPickpocketDetected;
MWGui::ItemView* mItemView; MWGui::ItemView* mItemView;
SortFilterItemModel* mSortModel; SortFilterItemModel* mSortModel;
ItemModel* mModel; ItemModel* mModel;
@ -73,6 +76,9 @@ namespace MWGui
void onTakeAllButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender);
void onDisposeCorpseButtonClicked(MyGUI::Widget* sender); void onDisposeCorpseButtonClicked(MyGUI::Widget* sender);
/// @return is taking the item allowed?
bool onTakeItem(const ItemStack& item, int count);
virtual void onReferenceUnavailable(); virtual void onReferenceUnavailable();
}; };
} }

@ -0,0 +1,67 @@
#include "pickpocket.hpp"
#include "../mwworld/class.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "npcstats.hpp"
namespace MWMechanics
{
Pickpocket::Pickpocket(const MWWorld::Ptr &thief, const MWWorld::Ptr &victim)
: mThief(thief)
, mVictim(victim)
{
}
float Pickpocket::getChanceModifier(const MWWorld::Ptr &ptr, float add)
{
NpcStats& stats = ptr.getClass().getNpcStats(ptr);
float agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
float sneak = stats.getSkill(ESM::Skill::Sneak).getModified();
return (add + 0.2 * agility + 0.1 * luck + sneak) * stats.getFatigueTerm();
}
bool Pickpocket::getDetected(float valueTerm)
{
float x = getChanceModifier(mThief);
float y = getChanceModifier(mVictim, valueTerm);
float t = 2*x - y;
NpcStats& pcStats = mThief.getClass().getNpcStats(mThief);
float pcSneak = pcStats.getSkill(ESM::Skill::Sneak).getModified();
int iPickMinChance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
.find("iPickMinChance")->getInt();
int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
.find("iPickMaxChance")->getInt();
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (t < pcSneak / iPickMinChance)
{
return (roll > int(pcSneak / iPickMinChance));
}
else
{
t = std::min(float(iPickMaxChance), t);
return (roll > int(t));
}
}
bool Pickpocket::pick(MWWorld::Ptr item, int count)
{
float stackValue = item.getClass().getValue(item) * count;
float fPickPocketMod = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
.find("fPickPocketMod")->getFloat();
float valueTerm = 10 * fPickPocketMod * stackValue;
return getDetected(valueTerm);
}
bool Pickpocket::finish()
{
return getDetected(0.f);
}
}

@ -0,0 +1,30 @@
#ifndef OPENMW_MECHANICS_PICKPOCKET_H
#define OPENMW_MECHANICS_PICKPOCKET_H
#include "../mwworld/ptr.hpp"
namespace MWMechanics
{
class Pickpocket
{
public:
Pickpocket (const MWWorld::Ptr& thief, const MWWorld::Ptr& victim);
/// Steal some items
/// @return Was the thief detected?
bool pick (MWWorld::Ptr item, int count);
/// End the pickpocketing process
/// @return Was the thief detected?
bool finish ();
private:
bool getDetected(float valueTerm);
float getChanceModifier(const MWWorld::Ptr& ptr, float add=0);
MWWorld::Ptr mThief;
MWWorld::Ptr mVictim;
};
}
#endif

@ -3,6 +3,7 @@
<MyGUI type="Layout"> <MyGUI type="Layout">
<Widget type="Window" skin="MW_Window" layer="Windows" position="0 0 600 300" name="_Main"> <Widget type="Window" skin="MW_Window" layer="Windows" position="0 0 600 300" name="_Main">
<Property key="MinSize" value="245 145"/> <Property key="MinSize" value="245 145"/>
<Property key="Visible" value="false"/>
<!-- Items --> <!-- Items -->
<Widget type="ItemView" skin="MW_ItemView" position="5 5 575 225" name="ItemView" align="Left Top Stretch"> <Widget type="ItemView" skin="MW_ItemView" position="5 5 575 225" name="ItemView" align="Left Top Stretch">

Loading…
Cancel
Save