Merge remote-tracking branch 'jeffreyhaines/master'

Conflicts:
	apps/openmw/CMakeLists.txt
actorid
Marc Zinnschlag 11 years ago
commit 86e65944b8

@ -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
)

@ -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;

@ -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;
};
}

@ -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()

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

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

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

@ -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;
}

@ -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

@ -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;

@ -49,6 +49,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?

@ -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

@ -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;

@ -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))
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
// 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 )
{
// 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)
// Will the witness report the crime?
if (it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm)
{
// TODO: stats.setAlarmed(true) on NPCs within earshot
// fAlarmRadius ?
reported=true;
break;
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)

@ -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;

@ -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);

@ -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();
}
};

@ -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;
}
}

@ -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;
};
}

@ -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;
}
}

@ -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

@ -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);

@ -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);
}

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

@ -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);
}

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

Loading…
Cancel
Save