forked from teamnwah/openmw-tes3coop
Implement theft detection
This commit is contained in:
parent
d2d76f4f47
commit
3c0080d2c1
7 changed files with 129 additions and 10 deletions
|
@ -91,6 +91,27 @@ namespace MWBase
|
|||
/// Check if \a observer is potentially aware of \a ptr. Does not do a line of sight check!
|
||||
virtual bool awarenessCheck (const MWWorld::Ptr& ptr, const MWWorld::Ptr& observer) = 0;
|
||||
|
||||
enum OffenseType
|
||||
{
|
||||
OT_Theft, // Taking items owned by an NPC or a faction you are not a member of
|
||||
OT_Assault, // Attacking a peaceful NPC
|
||||
OT_Murder, // Murdering a peaceful NPC
|
||||
OT_Trespassing, // Staying in a cell you are not allowed in (where is this defined?)
|
||||
OT_SleepingInOwnedBed, // Sleeping in a bed owned by an NPC or a faction you are not a member of
|
||||
OT_Pickpocket // Entering pickpocket mode, leaving it, and being detected. Any items stolen are a separate crime (Theft)
|
||||
};
|
||||
/**
|
||||
* @brief Commit a crime. If any actors witness the crime and report it,
|
||||
* reportCrime will be called automatically.
|
||||
* @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen.
|
||||
*/
|
||||
virtual void commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
|
||||
OffenseType type, int arg=0) = 0;
|
||||
virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
|
||||
OffenseType type, int arg=0) = 0;
|
||||
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
||||
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count) = 0;
|
||||
|
||||
enum PersuasionType
|
||||
{
|
||||
PT_Admire,
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/dialoguemanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
|
||||
#include "../mwmechanics/pickpocket.hpp"
|
||||
|
||||
|
@ -249,11 +251,12 @@ namespace MWGui
|
|||
&& !mPickpocketDetected
|
||||
)
|
||||
{
|
||||
MWMechanics::Pickpocket pickpocket(MWBase::Environment::get().getWorld()->getPlayer().getPlayer(),
|
||||
mPtr);
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
MWMechanics::Pickpocket pickpocket(player, mPtr);
|
||||
if (pickpocket.finish())
|
||||
{
|
||||
// TODO: crime
|
||||
MWBase::Environment::get().getMechanicsManager()->reportCrime(
|
||||
player, MWWorld::Ptr(), MWBase::MechanicsManager::OT_Pickpocket);
|
||||
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
|
||||
MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief");
|
||||
mPickpocketDetected = true;
|
||||
|
@ -322,19 +325,25 @@ namespace MWGui
|
|||
|
||||
bool ContainerWindow::onTakeItem(const ItemStack &item, int count)
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
if (dynamic_cast<PickpocketItemModel*>(mModel))
|
||||
{
|
||||
MWMechanics::Pickpocket pickpocket(MWBase::Environment::get().getWorld()->getPlayer().getPlayer(),
|
||||
mPtr);
|
||||
MWMechanics::Pickpocket pickpocket(player, mPtr);
|
||||
if (pickpocket.pick(item.mBase, count))
|
||||
{
|
||||
// TODO: crime
|
||||
int value = item.mBase.getClass().getValue(item.mBase) * count;
|
||||
MWBase::Environment::get().getMechanicsManager()->reportCrime(
|
||||
player, MWWorld::Ptr(), MWBase::MechanicsManager::OT_Theft, value);
|
||||
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container);
|
||||
MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief");
|
||||
mPickpocketDetected = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, count);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
@ -533,6 +534,8 @@ namespace MWGui
|
|||
if (i == mTradeModel->getItemCount())
|
||||
throw std::runtime_error("Added item not found");
|
||||
mDragAndDrop->startDrag(i, mSortModel, mTradeModel, mItemView, count);
|
||||
|
||||
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, count);
|
||||
}
|
||||
|
||||
MyGUI::IntCoord InventoryWindow::getAvatarScreenCoord ()
|
||||
|
|
|
@ -25,9 +25,6 @@ namespace MWMechanics
|
|||
{
|
||||
class Actors
|
||||
{
|
||||
typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap;
|
||||
PtrControllerMap mActors;
|
||||
|
||||
std::map<std::string, int> mDeathCount;
|
||||
|
||||
void updateNpc(const MWWorld::Ptr &ptr, float duration, bool paused);
|
||||
|
@ -50,6 +47,11 @@ namespace MWMechanics
|
|||
Actors();
|
||||
~Actors();
|
||||
|
||||
typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap;
|
||||
|
||||
PtrControllerMap::const_iterator begin() { return mActors.begin(); }
|
||||
PtrControllerMap::const_iterator end() { return mActors.end(); }
|
||||
|
||||
/// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently
|
||||
/// paused we may want to do it manually (after equipping permanent enchantment)
|
||||
void updateMagicEffects (const MWWorld::Ptr& ptr) { adjustMagicEffects(ptr); }
|
||||
|
@ -88,6 +90,10 @@ namespace MWMechanics
|
|||
void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number);
|
||||
void skipAnimation(const MWWorld::Ptr& ptr);
|
||||
bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName);
|
||||
|
||||
private:
|
||||
PtrControllerMap mActors;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -728,6 +728,72 @@ namespace MWMechanics
|
|||
return mAI;
|
||||
}
|
||||
|
||||
void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, int count)
|
||||
{
|
||||
const std::string& owner = item.getCellRef().mOwner;
|
||||
if (owner.empty())
|
||||
return;
|
||||
const std::string& faction = item.getCellRef().mFaction;
|
||||
if (faction.empty())
|
||||
return;
|
||||
const std::map<std::string, int>& factions = ptr.getClass().getNpcStats(ptr).getFactionRanks();
|
||||
if (factions.find(Misc::StringUtils::lowerCase(faction)) != factions.end())
|
||||
return;
|
||||
|
||||
MWWorld::Ptr victim = MWBase::Environment::get().getWorld()->getPtr(owner, true);
|
||||
|
||||
commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count);
|
||||
}
|
||||
|
||||
void MechanicsManager::commitCrime(const MWWorld::Ptr &ptr, const MWWorld::Ptr &victim, OffenseType type, int arg)
|
||||
{
|
||||
bool reported=false;
|
||||
for (Actors::PtrControllerMap::const_iterator it = mActors.begin(); it != mActors.end(); ++it)
|
||||
{
|
||||
if (it->first != ptr && awarenessCheck(ptr, it->first))
|
||||
{
|
||||
// NPCs will always curse you when they notice you steal their items, even if they don't report the crime
|
||||
if (it->first == victim && type == OT_Theft)
|
||||
{
|
||||
MWBase::Environment::get().getDialogueManager()->say(victim, "Thief");
|
||||
}
|
||||
|
||||
// Actor has witnessed a crime. Will he report it?
|
||||
// (not sure, is > 0 correct?)
|
||||
if (it->first.getClass().getCreatureStats(it->first).getAiSetting(CreatureStats::AI_Alarm).getModified() > 0
|
||||
// This is a bit inconsistent, but AFAIK assaulted NPCs can not report if they are alone
|
||||
&& (type != OT_Assault || it->first != victim)
|
||||
)
|
||||
{
|
||||
reported=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (reported)
|
||||
reportCrime(ptr, victim, type, arg);
|
||||
}
|
||||
|
||||
void MechanicsManager::reportCrime(const MWWorld::Ptr &ptr, const MWWorld::Ptr &victim, OffenseType type, int arg)
|
||||
{
|
||||
// Bounty for each type of crime
|
||||
if (type == OT_Trespassing || type == OT_SleepingInOwnedBed)
|
||||
arg = 5;
|
||||
else if (type == OT_Pickpocket)
|
||||
arg = 25;
|
||||
else if (type == OT_Assault)
|
||||
arg = 40;
|
||||
else if (type == OT_Murder)
|
||||
arg = 1000;
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sCrimeMessage}");
|
||||
ptr.getClass().getNpcStats(ptr).setBounty(ptr.getClass().getNpcStats(ptr).getBounty()
|
||||
+ arg);
|
||||
|
||||
// TODO: make any guards in the area try to arrest the player
|
||||
}
|
||||
|
||||
bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer)
|
||||
{
|
||||
const MWWorld::Store<ESM::GameSetting>& store = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
|
|
@ -101,6 +101,18 @@ namespace MWMechanics
|
|||
/// Check if \a observer is potentially aware of \a ptr. Does not do a line of sight check!
|
||||
virtual bool awarenessCheck (const MWWorld::Ptr& ptr, const MWWorld::Ptr& observer);
|
||||
|
||||
/**
|
||||
* @brief Commit a crime. If any actors witness the crime and report it,
|
||||
* reportCrime will be called automatically.
|
||||
* @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen.
|
||||
*/
|
||||
virtual void commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
|
||||
OffenseType type, int arg=0);
|
||||
virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim,
|
||||
OffenseType type, int arg=0);
|
||||
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
||||
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count);
|
||||
|
||||
virtual void forceStateUpdate(const MWWorld::Ptr &ptr);
|
||||
|
||||
virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include "class.hpp"
|
||||
#include "containerstore.hpp"
|
||||
|
@ -14,8 +15,9 @@ namespace MWWorld
|
|||
|
||||
void ActionTake::executeImp (const Ptr& actor)
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager()->itemTaken(
|
||||
actor, getTarget(), getTarget().getRefData().getCount());
|
||||
actor.getClass().getContainerStore (actor).add (getTarget(), getTarget().getRefData().getCount(), actor);
|
||||
|
||||
MWBase::Environment::get().getWorld()->deleteObject (getTarget());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue