1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 20:19:57 +00:00

Merge remote-tracking branch 'jeffreyhaines/master'

Conflicts:
	apps/openmw/CMakeLists.txt
This commit is contained in:
Marc Zinnschlag 2014-04-15 11:31:48 +02:00
commit 86e65944b8
26 changed files with 396 additions and 75 deletions

View file

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

View file

@ -812,7 +812,13 @@ namespace MWClass
return boost::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("#{sActorInCombat}"));
if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak))
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // stealing
// player got activated by another NPC
if(ptr.getRefData().getHandle() == "player")
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(actor));
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
}
MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr)
@ -1297,6 +1303,11 @@ namespace MWClass
return ref->mBase->mNpdt12.mGold;
}
bool Npc::isClass(const MWWorld::Ptr& ptr, const std::string &className) const
{
return ptr.get<ESM::NPC>()->mBase->mClass == className;
}
const ESM::GameSetting *Npc::fMinWalkSpeed;
const ESM::GameSetting *Npc::fMaxWalkSpeed;
const ESM::GameSetting *Npc::fEncumberedMoveEffect;

View file

@ -168,6 +168,8 @@ namespace MWClass
///< Write additional state from \a ptr into \a state.
virtual int getBaseGold(const MWWorld::Ptr& ptr) const;
virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const;
};
}

View file

@ -29,6 +29,7 @@
#include "aicombat.hpp"
#include "aifollow.hpp"
#include "aipersue.hpp"
namespace
{
@ -175,14 +176,16 @@ namespace MWMechanics
adjustMagicEffects (ptr);
if (ptr.getClass().getCreatureStats(ptr).needToRecalcDynamicStats())
calculateDynamicStats (ptr);
calculateCreatureStatModifiers (ptr, duration);
// AI
if(MWBase::Environment::get().getMechanicsManager()->isAIActive())
{
CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
//engage combat or not?
CreatureStats& creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr);
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
//engage combat or not?
if(ptr != player && !creatureStats.isHostile())
{
ESM::Position playerpos = player.getRefData().getPosition();
@ -218,7 +221,7 @@ namespace MWMechanics
}
}
}
updateCrimePersuit(ptr, duration);
creatureStats.getAiSequence().execute (ptr,duration);
}
@ -717,6 +720,72 @@ namespace MWMechanics
}
}
void Actors::updateCrimePersuit(const MWWorld::Ptr& ptr, float duration)
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
if (ptr != player && ptr.getClass().isNpc())
{
// get stats of witness
CreatureStats& creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr);
NpcStats& npcStats = MWWorld::Class::get(ptr).getNpcStats(ptr);
// If I'm a guard and I'm not hostile
if (ptr.getClass().isClass(ptr, "Guard") && !creatureStats.isHostile())
{
/// \todo Move me! I shouldn't be here...
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
float cutoff = float(esmStore.get<ESM::GameSetting>().find("iCrimeThreshold")->getInt()) *
float(esmStore.get<ESM::GameSetting>().find("iCrimeThresholdMultiplier")->getInt()) *
esmStore.get<ESM::GameSetting>().find("fCrimeGoldDiscountMult")->getFloat();
// Attack on sight if bounty is greater than the cutoff
if ( player.getClass().getNpcStats(player).getBounty() >= cutoff
&& MWBase::Environment::get().getWorld()->getLOS(ptr, player)
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr))
{
creatureStats.getAiSequence().stack(AiCombat(player));
creatureStats.setHostile(true);
npcStats.setCrimeId( MWBase::Environment::get().getWorld()->getPlayer().getCrimeId() );
}
}
// if I was a witness to a crime
if (npcStats.getCrimeId() != -1)
{
// if you've payed for your crimes and I havent noticed
if( npcStats.getCrimeId() <= MWBase::Environment::get().getWorld()->getPlayer().getCrimeId() )
{
// Calm witness down
if (ptr.getClass().isClass(ptr, "Guard"))
creatureStats.getAiSequence().stopPersue();
creatureStats.getAiSequence().stopCombat();
// Reset factors to attack
// TODO: Not a complete list, disposition changes?
creatureStats.setHostile(false);
creatureStats.setAttacked(false);
// Update witness crime id
npcStats.setCrimeId(-1);
}
else if (!creatureStats.isHostile())
{
if (ptr.getClass().isClass(ptr, "Guard"))
creatureStats.getAiSequence().stack(AiPersue(player.getClass().getId(player)));
else
creatureStats.getAiSequence().stack(AiCombat(player));
creatureStats.setHostile(true);
}
}
// if I didn't report a crime was I attacked?
else if (creatureStats.getAttacked() && !creatureStats.isHostile())
{
creatureStats.getAiSequence().stack(AiCombat(player));
creatureStats.setHostile(true);
}
}
}
Actors::Actors() {}
Actors::~Actors()

View file

@ -42,6 +42,8 @@ namespace MWMechanics
void updateEquippedLight (const MWWorld::Ptr& ptr, float duration);
void updateCrimePersuit (const MWWorld::Ptr& ptr, float duration);
public:
Actors();

View file

@ -19,7 +19,8 @@ namespace MWMechanics
TypeIdEscort = 2,
TypeIdFollow = 3,
TypeIdActivate = 4,
TypeIdCombat = 5
TypeIdCombat = 5,
TypeIdPersue = 6
};
virtual ~AiPackage();

View file

@ -0,0 +1,106 @@
#include "aipersue.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/action.hpp"
#include "../mwworld/cellstore.hpp"
#include "steering.hpp"
#include "movement.hpp"
#include "creaturestats.hpp"
MWMechanics::AiPersue::AiPersue(const std::string &objectId)
: mObjectId(objectId)
{
}
MWMechanics::AiPersue *MWMechanics::AiPersue::clone() const
{
return new AiPersue(*this);
}
bool MWMechanics::AiPersue::execute (const MWWorld::Ptr& actor, float duration)
{
MWBase::World *world = MWBase::Environment::get().getWorld();
ESM::Position pos = actor.getRefData().getPosition();
Movement &movement = actor.getClass().getMovementSettings(actor);
const ESM::Cell *cell = actor.getCell()->getCell();
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
MWWorld::Ptr player = world->getPlayerPtr();
if(cell->mData.mX != player.getCell()->getCell()->mData.mX)
{
int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX);
//check if actor is near the border of an inactive cell. If so, stop walking.
if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) >
sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
{
movement.mPosition[1] = 0;
return false;
}
}
if(cell->mData.mY != player.getCell()->getCell()->mData.mY)
{
int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY);
//check if actor is near the border of an inactive cell. If so, stop walking.
if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) >
sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
{
movement.mPosition[1] = 0;
return false;
}
}
MWWorld::Ptr target = world->getPtr(mObjectId,false);
ESM::Position targetPos = target.getRefData().getPosition();
bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY;
if(!mPathFinder.isPathConstructed() || cellChange)
{
mCellX = cell->mData.mX;
mCellY = cell->mData.mY;
ESM::Pathgrid::Point dest;
dest.mX = targetPos.pos[0];
dest.mY = targetPos.pos[1];
dest.mZ = targetPos.pos[2];
ESM::Pathgrid::Point start;
start.mX = pos.pos[0];
start.mY = pos.pos[1];
start.mZ = pos.pos[2];
mPathFinder.buildPath(start, dest, actor.getCell(), true);
}
if((pos.pos[0]-targetPos.pos[0])*(pos.pos[0]-targetPos.pos[0])+
(pos.pos[1]-targetPos.pos[1])*(pos.pos[1]-targetPos.pos[1])+
(pos.pos[2]-targetPos.pos[2])*(pos.pos[2]-targetPos.pos[2]) < 200*200)
{
movement.mPosition[1] = 0;
MWWorld::Ptr target = world->getPtr(mObjectId,false);
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor);
return true;
}
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
{
movement.mPosition[1] = 0;
MWWorld::Ptr target = world->getPtr(mObjectId,false);
MWWorld::Class::get(target).activate(target,actor).get()->execute(actor);
return true;
}
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
zTurn(actor, Ogre::Degree(zAngle));
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
movement.mPosition[1] = 1;
return false;
}
int MWMechanics::AiPersue::getTypeId() const
{
return TypeIdPersue;
}

View file

@ -0,0 +1,29 @@
#ifndef GAME_MWMECHANICS_AIPERSUE_H
#define GAME_MWMECHANICS_AIPERSUE_H
#include "aipackage.hpp"
#include <string>
#include "pathfinding.hpp"
namespace MWMechanics
{
class AiPersue : public AiPackage
{
public:
AiPersue(const std::string &objectId);
virtual AiPersue *clone() const;
virtual bool execute (const MWWorld::Ptr& actor,float duration);
///< \return Package completed?
virtual int getTypeId() const;
private:
std::string mObjectId;
PathFinder mPathFinder;
int mCellX;
int mCellY;
};
}
#endif

View file

@ -73,6 +73,15 @@ void MWMechanics::AiSequence::stopCombat()
}
}
void MWMechanics::AiSequence::stopPersue()
{
while (getTypeId() == AiPackage::TypeIdPersue)
{
delete *mPackages.begin();
mPackages.erase (mPackages.begin());
}
}
bool MWMechanics::AiSequence::isPackageDone() const
{
return mDone;

View file

@ -50,6 +50,9 @@ namespace MWMechanics
void stopCombat();
///< Removes all combat packages until first non-combat or stack empty.
void stopPersue();
///< Removes all persue packages until first non-persue or stack empty.
bool isPackageDone() const;
///< Has a package been completed during the last update?

View file

@ -435,8 +435,9 @@ namespace MWMechanics
return getMovementFlag (Flag_Run) || getMovementFlag (Flag_ForceRun);
case Stance_Sneak:
return getMovementFlag (Flag_Sneak) || getMovementFlag (Flag_ForceSneak);
default:
return false;
}
return false; // shut up, compiler
}
DrawState_ CreatureStats::getDrawState() const

View file

@ -175,15 +175,12 @@ namespace MWMechanics
void talkedToPlayer();
bool isAlarmed() const;
void setAlarmed (bool alarmed);
bool getAttacked() const;
void setAttacked (bool attacked);
bool isHostile() const;
void setHostile (bool hostile);
bool getCreatureTargetted() const;

View file

@ -1,5 +1,6 @@
#include "mechanicsmanagerimp.hpp"
#include "npcstats.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/inventorystore.hpp"
@ -802,34 +803,74 @@ namespace MWMechanics
bool MechanicsManager::commitCrime(const MWWorld::Ptr &ptr, const MWWorld::Ptr &victim, OffenseType type, int arg)
{
if (ptr.getRefData().getHandle() != "player")
// NOTE: int arg can be from itemTaken() so DON'T modify it, since it is
// passed to reportCrime later on in this function.
// Only player can commit crime and no victimless crimes
if (ptr.getRefData().getHandle() != "player" || victim.isEmpty())
return false;
bool reported=false;
for (Actors::PtrControllerMap::const_iterator it = mActors.begin(); it != mActors.end(); ++it)
{
if (it->first != ptr &&
MWBase::Environment::get().getWorld()->getLOS(ptr, it->first) &&
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");
}
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
// 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)
{
// TODO: stats.setAlarmed(true) on NPCs within earshot
// fAlarmRadius ?
reported=true;
break;
}
}
}
// What amount of alarm did this crime generate?
int alarm;
if (type == OT_Trespassing || type == OT_SleepingInOwnedBed)
alarm = esmStore.get<ESM::GameSetting>().find("iAlarmTresspass")->getInt();
else if (type == OT_Pickpocket)
alarm = esmStore.get<ESM::GameSetting>().find("iAlarmPickPocket")->getInt();
else if (type == OT_Assault)
alarm = esmStore.get<ESM::GameSetting>().find("iAlarmAttack")->getInt();
else if (type == OT_Murder)
alarm = esmStore.get<ESM::GameSetting>().find("iAlarmKilling")->getInt();
else if (type == OT_Theft)
alarm = esmStore.get<ESM::GameSetting>().find("iAlarmStealing")->getInt();
// Innocent until proven guilty
bool reported = false;
// Find all the NPCs within the alarm radius
std::vector<MWWorld::Ptr> neighbors;
mActors.getObjectsInRange(Ogre::Vector3(ptr.getRefData().getPosition().pos),
esmStore.get<ESM::GameSetting>().find("fAlarmRadius")->getInt(), neighbors);
// Find an actor who witnessed the crime
for (std::vector<MWWorld::Ptr>::iterator it = neighbors.begin(); it != neighbors.end(); ++it)
{
if (*it == ptr) continue; // not the player
// Was the crime seen?
if ( ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) ||
type == OT_Assault )
{
// Will the witness report the crime?
if (it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm)
{
reported = true;
int id = MWBase::Environment::get().getWorld()->getPlayer().getNewCrimeId();
// Tell everyone, including yourself
for (std::vector<MWWorld::Ptr>::iterator it1 = neighbors.begin(); it1 != neighbors.end(); ++it1)
{
if (*it1 == ptr) continue; // not the player
// TODO: Add more messages
if (type == OT_Theft)
MWBase::Environment::get().getDialogueManager()->say(*it1, "thief");
else if (type == OT_Assault)
MWBase::Environment::get().getDialogueManager()->say(*it1, "attack");
// Will other witnesses paticipate in crime
if ( it1->getClass().getCreatureStats(*it1).getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm
|| type == OT_Assault )
{
it1->getClass().getNpcStats(*it1).setCrimeId(id);
}
}
break; // Someone saw the crime and everyone has been told
}
}
}
if (reported)
reportCrime(ptr, victim, type, arg);
return reported;
@ -838,6 +879,7 @@ namespace MWMechanics
void MechanicsManager::reportCrime(const MWWorld::Ptr &ptr, const MWWorld::Ptr &victim, OffenseType type, int arg)
{
const MWWorld::Store<ESM::GameSetting>& store = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
// Bounty for each type of crime
if (type == OT_Trespassing || type == OT_SleepingInOwnedBed)
arg = store.find("iCrimeTresspass")->getInt();
@ -850,32 +892,10 @@ namespace MWMechanics
else if (type == OT_Theft)
arg *= store.find("fCrimeStealing")->getFloat();
// TODO: In some cases (type == Assault), if no NPCs are within earshot, the report will have no effect.
// however other crime types seem to be always produce a bounty.
MWBase::Environment::get().getWindowManager()->messageBox("#{sCrimeMessage}");
ptr.getClass().getNpcStats(ptr).setBounty(ptr.getClass().getNpcStats(ptr).getBounty()
+ arg);
if (!victim.isEmpty())
{
int fight = 0;
// Increase in fight rating for each type of crime
if (type == OT_Trespassing || type == OT_SleepingInOwnedBed)
fight = store.find("iFightTrespass")->getFloat();
else if (type == OT_Pickpocket)
fight = store.find("iFightPickpocket")->getInt();
else if (type == OT_Assault)
fight = store.find("iFightAttack")->getInt();
else if (type == OT_Murder)
fight = store.find("iFightKilling")->getInt();
else if (type == OT_Theft)
fight = store.find("fFightStealing")->getFloat();
// Not sure if this should be permanent?
fight = victim.getClass().getCreatureStats(victim).getAiSetting(CreatureStats::AI_Fight).getBase() + fight;
victim.getClass().getCreatureStats(victim).setAiSetting(CreatureStats::AI_Fight, fight);
}
// If committing a crime against a faction member, expell from the faction
if (!victim.isEmpty() && victim.getClass().isNpc())
{
@ -887,8 +907,6 @@ namespace MWMechanics
ptr.getClass().getNpcStats(ptr).expell(factionID);
}
}
// TODO: make any guards in the area try to arrest the player
}
bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer)

View file

@ -29,6 +29,7 @@ MWMechanics::NpcStats::NpcStats()
, mLevelProgress(0)
, mDisposition(0)
, mReputation(0)
, mCrimeId(-1)
, mWerewolfKills (0)
, mProfit(0)
, mTimeToStartDrowning(20.0)
@ -340,6 +341,16 @@ void MWMechanics::NpcStats::setReputation(int reputation)
mReputation = reputation;
}
int MWMechanics::NpcStats::getCrimeId() const
{
return mCrimeId;
}
void MWMechanics::NpcStats::setCrimeId(int id)
{
mCrimeId = id;
}
bool MWMechanics::NpcStats::hasSkillsForRank (const std::string& factionId, int rank) const
{
if (rank<0 || rank>=10)
@ -441,6 +452,8 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const
mWerewolfSkill[i].writeState (state.mSkills[i].mWerewolf);
}
state.mCrimeId = mCrimeId;
state.mBounty = mBounty;
for (std::set<std::string>::const_iterator iter (mExpelled.begin());
@ -493,6 +506,7 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state)
mWerewolfSkill[i].readState (state.mSkills[i].mWerewolf);
}
mCrimeId = state.mCrimeId;
mBounty = state.mBounty;
mReputation = state.mReputation;
mWerewolfKills = state.mWerewolfKills;

View file

@ -37,6 +37,7 @@ namespace MWMechanics
std::set<std::string> mExpelled;
std::map<std::string, int> mFactionReputation;
int mReputation;
int mCrimeId;
int mWerewolfKills;
int mProfit;
float mAttackStrength;
@ -63,13 +64,14 @@ namespace MWMechanics
void modifyProfit(int diff);
int getBaseDisposition() const;
void setBaseDisposition(int disposition);
int getReputation() const;
void setReputation(int reputation);
int getCrimeId() const;
void setCrimeId(int id);
const SkillValue& getSkill (int index) const;
SkillValue& getSkill (int index);

View file

@ -21,6 +21,7 @@
#include "../mwbase/scriptmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwworld/esmstore.hpp"
@ -802,6 +803,7 @@ namespace MWScript
{
MWBase::World* world = MWBase::Environment::get().getWorld();
world->goToJail();
MWBase::Environment::get().getWorld()->getPlayer().recordCrimeId();
}
};
@ -812,7 +814,7 @@ namespace MWScript
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
player.getClass().getNpcStats(player).setBounty(0);
MWBase::Environment::get().getWorld()->confiscateStolenItems(player);
MWBase::Environment::get().getWorld()->getPlayer().recordCrimeId();
}
};
@ -823,6 +825,8 @@ namespace MWScript
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
player.getClass().getNpcStats(player).setBounty(0);
MWBase::Environment::get().getWorld()->confiscateStolenItems(player);
MWBase::Environment::get().getWorld()->getPlayer().recordCrimeId();
}
};

View file

@ -401,4 +401,9 @@ namespace MWWorld
{
throw std::runtime_error("class does not support base gold");
}
bool Class::isClass(const MWWorld::Ptr& ptr, const std::string &className) const
{
return false;
}
}

View file

@ -334,6 +334,8 @@ namespace MWWorld
static void registerClass (const std::string& key, boost::shared_ptr<Class> instance);
virtual int getBaseGold(const MWWorld::Ptr& ptr) const;
virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const;
};
}

View file

@ -28,9 +28,11 @@ namespace MWWorld
: mCellStore(0),
mLastKnownExteriorPosition(0,0,0),
mAutoMove(false),
mForwardBackward (0),
mForwardBackward(0),
mTeleported(false),
mMarkedCell(NULL)
mMarkedCell(NULL),
mCurrentCrimeId(-1),
mPayedCrimeId(-1)
{
mPlayer.mBase = player;
mPlayer.mRef.mRefID = "player";
@ -194,6 +196,9 @@ namespace MWWorld
mPlayer.save (player.mObject);
player.mCellId = mCellStore->getCell()->getCellId();
player.mCurrentCrimeId = mCurrentCrimeId;
player.mPayedCrimeId = mPayedCrimeId;
player.mBirthsign = mSign;
player.mLastKnownExteriorPosition[0] = mLastKnownExteriorPosition.x;
@ -239,6 +244,9 @@ namespace MWWorld
!world.getStore().get<ESM::BirthSign>().search (player.mBirthsign))
throw std::runtime_error ("invalid player state record (birthsign)");
mCurrentCrimeId = player.mCurrentCrimeId;
mPayedCrimeId = player.mPayedCrimeId;
mSign = player.mBirthsign;
mLastKnownExteriorPosition.x = player.mLastKnownExteriorPosition[0];
@ -274,4 +282,19 @@ namespace MWWorld
return false;
}
int Player::getNewCrimeId()
{
return ++mCurrentCrimeId;
}
void Player::recordCrimeId()
{
mPayedCrimeId = mCurrentCrimeId;
}
int Player::getCrimeId() const
{
return mPayedCrimeId;
}
}

View file

@ -41,6 +41,10 @@ namespace MWWorld
bool mAutoMove;
int mForwardBackward;
bool mTeleported;
int mCurrentCrimeId; // the id assigned witnesses
int mPayedCrimeId; // the last id payed off (0 bounty)
public:
Player(const ESM::NPC *player, const MWBase::World& world);
@ -63,15 +67,12 @@ namespace MWWorld
MWWorld::Ptr getPlayer();
void setBirthSign(const std::string &sign);
const std::string &getBirthSign() const;
void setDrawState (MWMechanics::DrawState_ state);
bool getAutoMove() const;
MWMechanics::DrawState_ getDrawState(); /// \todo constness
bool getAutoMove() const;
void setAutoMove (bool enable);
void setLeftRight (int value);
@ -94,6 +95,10 @@ namespace MWWorld
void write (ESM::ESMWriter& writer) const;
bool readRecord (ESM::ESMReader& reader, int32_t type);
int getNewCrimeId(); // get new id for witnesses
void recordCrimeId(); // record the payed crime id when bounty is 0
int getCrimeId() const; // get the last payed crime id
};
}
#endif

View file

@ -2791,6 +2791,8 @@ namespace MWWorld
message += "\n" + skillMsg;
}
// TODO: Sleep the player
std::vector<std::string> buttons;
buttons.push_back("#{sOk}");
MWBase::Environment::get().getWindowManager()->messageBox(message, buttons);

View file

@ -67,6 +67,9 @@ void ESM::NpcStats::load (ESMReader &esm)
mLevelHealthBonus = 0;
esm.getHNOT (mLevelHealthBonus, "LVLH");
mCrimeId = -1;
esm.getHNOT (mCrimeId, "CRID");
}
void ESM::NpcStats::save (ESMWriter &esm) const
@ -130,4 +133,7 @@ void ESM::NpcStats::save (ESMWriter &esm) const
if (mLevelHealthBonus)
esm.writeHNT ("LVLH", mLevelHealthBonus);
if (mCrimeId != -1)
esm.writeHNT ("CRID", mCrimeId);
}

View file

@ -45,6 +45,7 @@ namespace ESM
float mTimeToStartDrowning;
float mLastDrowningHit;
float mLevelHealthBonus;
int mCrimeId;
void load (ESMReader &esm);
void save (ESMWriter &esm) const;

View file

@ -25,6 +25,9 @@ void ESM::Player::load (ESMReader &esm)
esm.getHNOT (mAutoMove, "AMOV");
mBirthsign = esm.getHNString ("SIGN");
esm.getHNT (mCurrentCrimeId, "CURD");
esm.getHNT (mPayedCrimeId, "PAYD");
}
void ESM::Player::save (ESMWriter &esm) const
@ -45,4 +48,7 @@ void ESM::Player::save (ESMWriter &esm) const
esm.writeHNT ("AMOV", mAutoMove);
esm.writeHNString ("SIGN", mBirthsign);
esm.writeHNT ("CURD", mCurrentCrimeId);
esm.writeHNT ("PAYD", mPayedCrimeId);
}

View file

@ -25,6 +25,9 @@ namespace ESM
unsigned char mAutoMove;
std::string mBirthsign;
int mCurrentCrimeId;
int mPayedCrimeId;
void load (ESMReader &esm);
void save (ESMWriter &esm) const;
};