mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 18:19:55 +00:00
Implement pickpocket detection. Play a voiced dialogue entry when detected.
This commit is contained in:
parent
ea3ee4407f
commit
780bf5a2cd
6 changed files with 160 additions and 3 deletions
|
@ -74,7 +74,7 @@ add_openmw_dir (mwmechanics
|
|||
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
||||
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
|
||||
aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting
|
||||
disease
|
||||
disease pickpocket
|
||||
)
|
||||
|
||||
add_openmw_dir (mwbase
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/dialoguemanager.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
|
||||
#include "../mwmechanics/pickpocket.hpp"
|
||||
|
||||
#include "countdialog.hpp"
|
||||
#include "tradewindow.hpp"
|
||||
#include "inventorywindow.hpp"
|
||||
|
@ -123,6 +126,7 @@ namespace MWGui
|
|||
, mSelectedItem(-1)
|
||||
, mModel(NULL)
|
||||
, mSortModel(NULL)
|
||||
, mPickpocketDetected(false)
|
||||
{
|
||||
getWidget(mDisposeCorpseButton, "DisposeCorpseButton");
|
||||
getWidget(mTakeButton, "TakeButton");
|
||||
|
@ -171,6 +175,9 @@ namespace MWGui
|
|||
|
||||
void ContainerWindow::dragItem(MyGUI::Widget* sender, int count)
|
||||
{
|
||||
if (!onTakeItem(mModel->getItem(mSelectedItem), count))
|
||||
return;
|
||||
|
||||
mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count);
|
||||
}
|
||||
|
||||
|
@ -208,6 +215,7 @@ namespace MWGui
|
|||
|
||||
void ContainerWindow::open(const MWWorld::Ptr& container, bool loot)
|
||||
{
|
||||
mPickpocketDetected = false;
|
||||
mPtr = container;
|
||||
|
||||
if (mPtr.getTypeName() == typeid(ESM::NPC).name() && !loot)
|
||||
|
@ -230,6 +238,28 @@ namespace MWGui
|
|||
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)
|
||||
{
|
||||
if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop)
|
||||
|
@ -255,8 +285,13 @@ namespace MWGui
|
|||
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
|
||||
}
|
||||
|
||||
playerModel->copyItem(mModel->getItem(i), mModel->getItem(i).mCount);
|
||||
mModel->removeItem(mModel->getItem(i), mModel->getItem(i).mCount);
|
||||
const ItemStack& item = mModel->getItem(i);
|
||||
|
||||
if (!onTakeItem(item, item.mCount))
|
||||
break;
|
||||
|
||||
playerModel->copyItem(item, item.mCount);
|
||||
mModel->removeItem(item, item.mCount);
|
||||
}
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container);
|
||||
|
@ -283,4 +318,22 @@ namespace MWGui
|
|||
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);
|
||||
|
||||
void open(const MWWorld::Ptr& container, bool loot=false);
|
||||
virtual void close();
|
||||
|
||||
private:
|
||||
DragAndDrop* mDragAndDrop;
|
||||
|
||||
bool mPickpocketDetected;
|
||||
|
||||
MWGui::ItemView* mItemView;
|
||||
SortFilterItemModel* mSortModel;
|
||||
ItemModel* mModel;
|
||||
|
@ -73,6 +76,9 @@ namespace MWGui
|
|||
void onTakeAllButtonClicked(MyGUI::Widget* _sender);
|
||||
void onDisposeCorpseButtonClicked(MyGUI::Widget* sender);
|
||||
|
||||
/// @return is taking the item allowed?
|
||||
bool onTakeItem(const ItemStack& item, int count);
|
||||
|
||||
virtual void onReferenceUnavailable();
|
||||
};
|
||||
}
|
||||
|
|
67
apps/openmw/mwmechanics/pickpocket.cpp
Normal file
67
apps/openmw/mwmechanics/pickpocket.cpp
Normal file
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
30
apps/openmw/mwmechanics/pickpocket.hpp
Normal file
30
apps/openmw/mwmechanics/pickpocket.hpp
Normal file
|
@ -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">
|
||||
<Widget type="Window" skin="MW_Window" layer="Windows" position="0 0 600 300" name="_Main">
|
||||
<Property key="MinSize" value="245 145"/>
|
||||
<Property key="Visible" value="false"/>
|
||||
|
||||
<!-- Items -->
|
||||
<Widget type="ItemView" skin="MW_ItemView" position="5 5 575 225" name="ItemView" align="Left Top Stretch">
|
||||
|
|
Loading…
Reference in a new issue