From 6c866deb1b0123c8f620448fa07cdfbb904910b8 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Sat, 29 Mar 2014 21:23:34 -0400 Subject: [PATCH 01/16] Feature #1154 Not all NPCs get aggressive when one is attacked Partially implemented --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 71 ++++++++++++------- .../mwmechanics/mechanicsmanagerimp.hpp | 2 +- 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 22dda0ce0..36b8df519 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -111,7 +111,7 @@ namespace MWBase * @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen. * @return was the crime reported? */ - virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, + virtual bool commitCrime (const MWWorld::Ptr& offender, 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; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 4c8f35edb..2c51e0083 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -3,6 +3,7 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/cellstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -12,6 +13,8 @@ #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" +#include "aicombat.hpp" + #include #include "spellcasting.hpp" @@ -798,37 +801,55 @@ namespace MWMechanics return; commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } - - bool MechanicsManager::commitCrime(const MWWorld::Ptr &ptr, const MWWorld::Ptr &victim, OffenseType type, int arg) + + bool MechanicsManager::commitCrime(const MWWorld::Ptr& offender, const MWWorld::Ptr& victim, OffenseType type, int arg) { - if (ptr.getRefData().getHandle() != "player") + if (offender.getRefData().getHandle() != "player") 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"); - } + MWWorld::Ptr ptr; - // 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; - } + bool reported=false; + MWWorld::CellStore* cell = victim.getCell(); + + // TODO: implement and check the distance of actors to victim using fAlarmRadius + // get all NPCs in victims cell + for (MWWorld::CellRefList::List::iterator it (cell->get().mList.begin()); it != cell->get().mList.end(); ++it) + { + MWWorld::Ptr ptr (&*it, cell); + + // offender can't be ally to themselves + if (ptr == offender) + continue; + + CreatureStats& creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr); + + // curse at the thief + if (ptr == victim && type == OT_Theft) + MWBase::Environment::get().getDialogueManager()->say(victim, "Thief"); + + // TODO: Make guards persue unless other factors, such as bounty stops them + // If the actor is a guard + + // TODO: An actor reacts differently based on different values of AI_Alarm. + // Actor has witnessed a crime. Will he report it? + if (creatureStats.getAiSetting(CreatureStats::AI_Alarm).getModified() > 0) + { + creatureStats.setAlarmed(true); + reported=true; + } + else + continue; + + // TODO: An actor reacts differently based on different values of AI_Fight and AI_Flee. + // Actor has reported the crime, will the actor fight the offender? + if (creatureStats.getAiSetting(CreatureStats::AI_Fight).getModified > 0) + { + creatureStats.getAiSequence().stack(AiCombat(offender)); + creatureStats.setHostile(true); + creatureStats.getAiSequence().execute(ptr, 0); } } - if (reported) reportCrime(ptr, victim, type, arg); return reported; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 761caf586..3327cf8b8 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -111,7 +111,7 @@ namespace MWMechanics * @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen. * @return was the crime reported? */ - virtual bool commitCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, + virtual bool commitCrime (const MWWorld::Ptr& offender, 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); From 98fd381564309f4d1cd15423821b2f2e8d65a00c Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Sat, 29 Mar 2014 21:25:20 -0400 Subject: [PATCH 02/16] Feature #1154 Not all NPCs get aggressive when one is attacked Compiling fix --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 2c51e0083..534fc941b 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -843,7 +843,7 @@ namespace MWMechanics // TODO: An actor reacts differently based on different values of AI_Fight and AI_Flee. // Actor has reported the crime, will the actor fight the offender? - if (creatureStats.getAiSetting(CreatureStats::AI_Fight).getModified > 0) + if (creatureStats.getAiSetting(CreatureStats::AI_Fight).getModified() > 0) { creatureStats.getAiSequence().stack(AiCombat(offender)); creatureStats.setHostile(true); From 8ce938c6f1537c63fb5a230a1188dbc3d42c8fdd Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Sat, 29 Mar 2014 22:26:53 -0400 Subject: [PATCH 03/16] Revert 6b28c06..98fd381 This rolls back to commit 6b28c06b2c6401d7a54a2df4e2f329b948acd7ed. --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 65 +++++++------------ .../mwmechanics/mechanicsmanagerimp.hpp | 2 +- 3 files changed, 24 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 36b8df519..22dda0ce0 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -111,7 +111,7 @@ namespace MWBase * @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen. * @return was the crime reported? */ - virtual bool commitCrime (const MWWorld::Ptr& offender, const MWWorld::Ptr& victim, + virtual bool 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; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 534fc941b..4c8f35edb 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -3,7 +3,6 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/cellstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -13,8 +12,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" -#include "aicombat.hpp" - #include #include "spellcasting.hpp" @@ -801,55 +798,37 @@ namespace MWMechanics return; commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } - - bool MechanicsManager::commitCrime(const MWWorld::Ptr& offender, const MWWorld::Ptr& victim, OffenseType type, int arg) + + bool MechanicsManager::commitCrime(const MWWorld::Ptr &ptr, const MWWorld::Ptr &victim, OffenseType type, int arg) { - if (offender.getRefData().getHandle() != "player") + if (ptr.getRefData().getHandle() != "player") return false; - MWWorld::Ptr ptr; - bool reported=false; - MWWorld::CellStore* cell = victim.getCell(); - - // TODO: implement and check the distance of actors to victim using fAlarmRadius - // get all NPCs in victims cell - for (MWWorld::CellRefList::List::iterator it (cell->get().mList.begin()); it != cell->get().mList.end(); ++it) + for (Actors::PtrControllerMap::const_iterator it = mActors.begin(); it != mActors.end(); ++it) { - MWWorld::Ptr ptr (&*it, cell); - - // offender can't be ally to themselves - if (ptr == offender) - continue; - - CreatureStats& creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr); - - // curse at the thief - if (ptr == victim && type == OT_Theft) - MWBase::Environment::get().getDialogueManager()->say(victim, "Thief"); - - // TODO: Make guards persue unless other factors, such as bounty stops them - // If the actor is a guard - - // TODO: An actor reacts differently based on different values of AI_Alarm. - // Actor has witnessed a crime. Will he report it? - if (creatureStats.getAiSetting(CreatureStats::AI_Alarm).getModified() > 0) + if (it->first != ptr && + MWBase::Environment::get().getWorld()->getLOS(ptr, it->first) && + awarenessCheck(ptr, it->first)) { - creatureStats.setAlarmed(true); - reported=true; - } - else - continue; + // 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"); + } - // TODO: An actor reacts differently based on different values of AI_Fight and AI_Flee. - // Actor has reported the crime, will the actor fight the offender? - if (creatureStats.getAiSetting(CreatureStats::AI_Fight).getModified() > 0) - { - creatureStats.getAiSequence().stack(AiCombat(offender)); - creatureStats.setHostile(true); - creatureStats.getAiSequence().execute(ptr, 0); + // 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; + } } } + if (reported) reportCrime(ptr, victim, type, arg); return reported; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 3327cf8b8..761caf586 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -111,7 +111,7 @@ namespace MWMechanics * @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen. * @return was the crime reported? */ - virtual bool commitCrime (const MWWorld::Ptr& offender, const MWWorld::Ptr& victim, + virtual bool 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); From 4037f3705e8855933a04a76b1bc717840ac99fd7 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Tue, 1 Apr 2014 14:15:55 -0400 Subject: [PATCH 04/16] Feature 1154 & 73: NPCs react to crime --- apps/openmw/mwclass/npc.cpp | 5 + apps/openmw/mwclass/npc.hpp | 2 + apps/openmw/mwmechanics/aiactivate.cpp | 9 +- apps/openmw/mwmechanics/aiactivate.hpp | 25 +-- apps/openmw/mwmechanics/aisequence.cpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 150 ++++++++++++------ apps/openmw/mwscript/aiextensions.cpp | 2 +- apps/openmw/mwworld/class.cpp | 5 + apps/openmw/mwworld/class.hpp | 2 + 9 files changed, 140 insertions(+), 62 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d41f7002a..4b84bd03e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1297,6 +1297,11 @@ namespace MWClass return ref->mBase->mNpdt12.mGold; } + bool Npc::isClass(const MWWorld::Ptr& ptr, const std::string &className) const + { + return ptr.get()->mBase->mClass == className; + } + const ESM::GameSetting *Npc::fMinWalkSpeed; const ESM::GameSetting *Npc::fMaxWalkSpeed; const ESM::GameSetting *Npc::fEncumberedMoveEffect; diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index fb45a2f1f..596bf0e56 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -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; }; } diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index 8610cf4b2..b3fe40e1f 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -10,8 +10,9 @@ #include "steering.hpp" #include "movement.hpp" -MWMechanics::AiActivate::AiActivate(const std::string &objectId) - : mObjectId(objectId) +MWMechanics::AiActivate::AiActivate(const std::string &objectId, int arg) + : mObjectId(objectId), + mArg(arg) { } MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const @@ -25,6 +26,10 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration) Movement &movement = actor.getClass().getMovementSettings(actor); const ESM::Cell *cell = actor.getCell()->getCell(); + // Make guard chase player + //if (mArg == 1) + // actor.getClass().getNpcStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); + MWWorld::Ptr player = world->getPlayerPtr(); if(cell->mData.mX != player.getCell()->getCell()->mData.mX) { diff --git a/apps/openmw/mwmechanics/aiactivate.hpp b/apps/openmw/mwmechanics/aiactivate.hpp index 7c94c2589..aa8725db2 100644 --- a/apps/openmw/mwmechanics/aiactivate.hpp +++ b/apps/openmw/mwmechanics/aiactivate.hpp @@ -1,25 +1,26 @@ #ifndef GAME_MWMECHANICS_AIACTIVATE_H #define GAME_MWMECHANICS_AIACTIVATE_H -#include "aipackage.hpp" -#include - -#include "pathfinding.hpp" - -namespace MWMechanics -{ +#include "aipackage.hpp" +#include + +#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, int arg); + 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; + int mArg; PathFinder mPathFinder; int mCellX; diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 2110393fd..ba69b8098 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -161,7 +161,7 @@ void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list) else if (it->mType == ESM::AI_Activate) { ESM::AIActivate data = it->mActivate; - package = new MWMechanics::AiActivate(data.mName.toString()); + package = new MWMechanics::AiActivate(data.mName.toString(), 0); } else //if (it->mType == ESM::AI_Follow) { diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 4c8f35edb..b7ff10381 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -12,6 +12,9 @@ #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" +#include "aicombat.hpp" +#include "aiactivate.hpp" + #include #include "spellcasting.hpp" @@ -801,42 +804,121 @@ 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) + // What amount of alarm did this crime generate? + int alarm; + if (type == OT_Trespassing || type == OT_SleepingInOwnedBed) + alarm = esmStore.get().find("iAlarmTresspass")->getInt(); + else if (type == OT_Pickpocket) + alarm = esmStore.get().find("iAlarmPickPocket")->getInt(); + else if (type == OT_Assault) + alarm = esmStore.get().find("iAlarmAttack")->getInt(); + else if (type == OT_Murder) + alarm = esmStore.get().find("iAlarmKilling")->getInt(); + else if (type == OT_Theft) + alarm = esmStore.get().find("iAlarmStealing")->getInt(); + + // Innocent until proven guilty + bool reported = false; + + // Find all the NPC's close enough, ie. within fAlarmRadius of the player + std::vector neighbors; + mActors.getObjectsInRange(Ogre::Vector3(ptr.getRefData().getPosition().pos), + esmStore.get().find("fAlarmRadius")->getInt(), neighbors); + + // Did anyone see the crime? + for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) + { + if (*it == ptr) // Not the player + continue; + + CreatureStats& creatureStats = MWWorld::Class::get(*it).getCreatureStats(*it); + + // Did the witness see the crime? + if ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) + { + // Say something! + // TODO: Add more messages + if (type == OT_Theft) + MWBase::Environment::get().getDialogueManager()->say(*it, "Thief"); + + // Will the witness report the crime? + if (creatureStats.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) { - // TODO: stats.setAlarmed(true) on NPCs within earshot - // fAlarmRadius ? - reported=true; - break; + creatureStats.setAlarmed(true); + reported = true; + reportCrime(ptr, victim, type, arg); + + // Is it a guard? Or will the witness fight? + if (it->getClass().isClass(*it, "Guard")) + { + // TODO: Persue player, concider bounty? + creatureStats.getAiSequence().stack(AiActivate(ptr.getClass().getId(ptr), 1)); + creatureStats.getAiSequence().execute(*it,0); + } + else if (creatureStats.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) + { + creatureStats.getAiSequence().stack(AiCombat(ptr)); + creatureStats.setHostile(true); + creatureStats.getAiSequence().execute(*it,0); + } + else if (type == OT_Assault) + { + creatureStats.getAiSequence().stack(AiCombat(ptr)); + creatureStats.setHostile(true); + creatureStats.getAiSequence().execute(*it,0); + } + + // Tell everyone else + for (std::vector::iterator it1 = neighbors.begin(); it1 != neighbors.end(); ++it1) + { + if (it == it1 || // Don't tell the witness or the player + ptr == *it1) + continue; + + // Is it a guard? Or will the witness fight? + CreatureStats& creatureStats1 = MWWorld::Class::get(*it1).getCreatureStats(*it1); + if (it1->getClass().isClass(*it1, "Guard")) + { + // TODO: Persue player, concider bounty? + creatureStats1.getAiSequence().stack(AiActivate(ptr.getClass().getId(ptr), 1)); + creatureStats1.getAiSequence().execute(*it1,0); + continue; + } + else if (creatureStats1.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) + { + creatureStats1.getAiSequence().stack(AiCombat(ptr)); + creatureStats1.setHostile(true); + creatureStats1.getAiSequence().execute(*it1,0); + } + else if (type == OT_Assault) + { + creatureStats.getAiSequence().stack(AiCombat(ptr)); + creatureStats.setHostile(true); + creatureStats.getAiSequence().execute(*it,0); + } + } + + break; // Someone saw the crime and everyone has been told } } } - if (reported) - reportCrime(ptr, victim, type, arg); return reported; } void MechanicsManager::reportCrime(const MWWorld::Ptr &ptr, const MWWorld::Ptr &victim, OffenseType type, int arg) { const MWWorld::Store& store = MWBase::Environment::get().getWorld()->getStore().get(); + // Bounty for each type of crime if (type == OT_Trespassing || type == OT_SleepingInOwnedBed) arg = store.find("iCrimeTresspass")->getInt(); @@ -849,32 +931,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()) { @@ -886,8 +946,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) diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 8314d011a..898788bf1 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -47,7 +47,7 @@ namespace MWScript // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i instance); virtual int getBaseGold(const MWWorld::Ptr& ptr) const; + + virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const; }; } From 50dac98a2befb0722a043c5f29fd73f1eaec440e Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Tue, 1 Apr 2014 20:24:25 -0400 Subject: [PATCH 05/16] Feature 1154 & 73: Crime and NPC reactions --- apps/openmw/mwbase/world.hpp | 2 + apps/openmw/mwclass/npc.cpp | 6 ++ apps/openmw/mwmechanics/aiactivate.cpp | 6 +- apps/openmw/mwmechanics/creaturestats.cpp | 14 ++++ apps/openmw/mwmechanics/creaturestats.hpp | 6 ++ .../mwmechanics/mechanicsmanagerimp.cpp | 69 ++++++++----------- apps/openmw/mwworld/worldimp.cpp | 16 +++++ apps/openmw/mwworld/worldimp.hpp | 1 + 8 files changed, 78 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index bb6f5741d..170e6705a 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -513,6 +513,8 @@ namespace MWBase virtual void explodeSpell (const Ogre::Vector3& origin, const MWWorld::Ptr& object, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName) = 0; + + virtual void resetCrimes(const MWWorld::Ptr& ptr) = 0; }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 4b84bd03e..5a3ff10de 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -812,7 +812,13 @@ namespace MWClass return boost::shared_ptr(new MWWorld::FailedAction("#{sActorInCombat}")); if(getCreatureStats(actor).getStance(MWMechanics::CreatureStats::Stance_Sneak)) return boost::shared_ptr(new MWWorld::ActionOpen(ptr)); // stealing + + // player got activated by another NPC + if(ptr.getRefData().getHandle() == "player") + return boost::shared_ptr(new MWWorld::ActionTalk(actor)); + return boost::shared_ptr(new MWWorld::ActionTalk(ptr)); + } MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index b3fe40e1f..472bca88f 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -9,6 +9,7 @@ #include "steering.hpp" #include "movement.hpp" +#include "creaturestats.hpp" MWMechanics::AiActivate::AiActivate(const std::string &objectId, int arg) : mObjectId(objectId), @@ -26,9 +27,8 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration) Movement &movement = actor.getClass().getMovementSettings(actor); const ESM::Cell *cell = actor.getCell()->getCell(); - // Make guard chase player - //if (mArg == 1) - // actor.getClass().getNpcStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); + if (mArg == 1) // run to actor + actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); MWWorld::Ptr player = world->getPlayerPtr(); if(cell->mData.mX != player.getCell()->getCell()->mData.mX) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index feed8d182..cb1d8e275 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -17,6 +17,7 @@ namespace MWMechanics mAttacked (false), mHostile (false), mAttackingOrSpell(false), mIsWerewolf(false), + mWitnesses(), mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mHitRecovery(false), mBlock(false), mMovementFlags(0), mDrawState (DrawState_Nothing), mAttackStrength(0.f) { @@ -496,4 +497,17 @@ namespace MWMechanics { return mGoldPool; } + + void CreatureStats::addPlayerWitnesses(std::vector witnesses) + { + mWitnesses.insert(mWitnesses.end(), witnesses.begin(), witnesses.end()); + } + std::vector CreatureStats::getPlayerWitnesses() const + { + return mWitnesses; + } + void CreatureStats::resetPlayerWitnesses() + { + mWitnesses.clear(); + } } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 20a9a5799..527adf8c0 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -59,6 +59,8 @@ namespace MWMechanics int mGoldPool; // the pool of merchant gold not in inventory + std::vector mWitnesses; // the witnesses to players crimes + protected: bool mIsWerewolf; AttributeValue mWerewolfAttributes[8]; @@ -233,6 +235,10 @@ namespace MWMechanics void setGoldPool(int pool); int getGoldPool() const; + + void addPlayerWitnesses(std::vector witnesses); + std::vector getPlayerWitnesses() const; + void resetPlayerWitnesses(); }; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b7ff10381..4d1fca72d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -826,6 +826,11 @@ namespace MWMechanics else if (type == OT_Theft) alarm = esmStore.get().find("iAlarmStealing")->getInt(); + // what is the bounty cutoff? To high the guards will attack + float cutoff = float(esmStore.get().find("iCrimeThreshold")->getInt()) * + float(esmStore.get().find("iCrimeThresholdMultiplier")->getInt()) * + esmStore.get().find("fCrimeGoldDiscountMult")->getFloat(); + // Innocent until proven guilty bool reported = false; @@ -842,7 +847,7 @@ namespace MWMechanics CreatureStats& creatureStats = MWWorld::Class::get(*it).getCreatureStats(*it); - // Did the witness see the crime? + // Did a witness see the crime? if ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) { // Say something! @@ -853,65 +858,51 @@ namespace MWMechanics // Will the witness report the crime? if (creatureStats.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) { - creatureStats.setAlarmed(true); reported = true; - reportCrime(ptr, victim, type, arg); - - // Is it a guard? Or will the witness fight? - if (it->getClass().isClass(*it, "Guard")) - { - // TODO: Persue player, concider bounty? - creatureStats.getAiSequence().stack(AiActivate(ptr.getClass().getId(ptr), 1)); - creatureStats.getAiSequence().execute(*it,0); - } - else if (creatureStats.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) - { - creatureStats.getAiSequence().stack(AiCombat(ptr)); - creatureStats.setHostile(true); - creatureStats.getAiSequence().execute(*it,0); - } - else if (type == OT_Assault) - { - creatureStats.getAiSequence().stack(AiCombat(ptr)); - creatureStats.setHostile(true); - creatureStats.getAiSequence().execute(*it,0); - } + reportCrime(ptr, victim, type, arg); // Tell everyone else for (std::vector::iterator it1 = neighbors.begin(); it1 != neighbors.end(); ++it1) { - if (it == it1 || // Don't tell the witness or the player - ptr == *it1) + if (*it1 == ptr) // Not the player continue; - // Is it a guard? Or will the witness fight? + // was the witness alarmed? CreatureStats& creatureStats1 = MWWorld::Class::get(*it1).getCreatureStats(*it1); + if (creatureStats1.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) + creatureStats1.setAlarmed(true); + + // was the witness a guard? if (it1->getClass().isClass(*it1, "Guard")) { - // TODO: Persue player, concider bounty? - creatureStats1.getAiSequence().stack(AiActivate(ptr.getClass().getId(ptr), 1)); - creatureStats1.getAiSequence().execute(*it1,0); - continue; + // will the guard try to kill the player? + if (ptr.getClass().getNpcStats(ptr).getBounty() >= cutoff) + { + creatureStats1.getAiSequence().stack(AiCombat(ptr)); + creatureStats1.setHostile(true); + creatureStats1.getAiSequence().execute(*it,0); + } + else // will the guard persue the player? + { + creatureStats1.getAiSequence().stack(AiActivate(ptr.getClass().getId(ptr), 1)); + creatureStats1.getAiSequence().execute(*it,0); + } } - else if (creatureStats1.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) + // will the witness fight the player? + else if (creatureStats1.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm || + type == OT_Assault) { creatureStats1.getAiSequence().stack(AiCombat(ptr)); creatureStats1.setHostile(true); creatureStats1.getAiSequence().execute(*it1,0); } - else if (type == OT_Assault) - { - creatureStats.getAiSequence().stack(AiCombat(ptr)); - creatureStats.setHostile(true); - creatureStats.getAiSequence().execute(*it,0); - } } - break; // Someone saw the crime and everyone has been told } } } - + if (reported) + ptr.getClass().getCreatureStats(ptr).addPlayerWitnesses(neighbors); return reported; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 81afc394a..3c53cabee 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2762,12 +2762,28 @@ namespace MWWorld message += "\n" + skillMsg; } + resetCrimes(player); + std::vector buttons; buttons.push_back("#{sOk}"); MWBase::Environment::get().getWindowManager()->messageBox(message, buttons); } } + void World::resetCrimes(const MWWorld::Ptr& ptr) + { + // Reset witnesses to the players crimes + std::vector neighbors = ptr.getClass().getCreatureStats(ptr).getPlayerWitnesses(); + for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) + { + // This to reset for each witness: + // TODO: More research is needed to complete this list + it->getClass().getCreatureStats(*it).setHostile(false); + it->getClass().getCreatureStats(*it).setAlarmed(false); + } + ptr.getClass().getCreatureStats(ptr).resetPlayerWitnesses(); + } + void World::spawnRandomCreature(const std::string &creatureList) { const ESM::CreatureLevList* list = getStore().get().find(creatureList); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 42f52cb61..06d49ad24 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -611,6 +611,7 @@ namespace MWWorld virtual void explodeSpell (const Ogre::Vector3& origin, const MWWorld::Ptr& object, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName); + virtual void resetCrimes(const MWWorld::Ptr& ptr); }; } From 7c0b51fb7e6a3757c3fbe4047b88826512bc0897 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 2 Apr 2014 00:18:22 -0400 Subject: [PATCH 06/16] Ai pursue now controls guards pursuit of crimes Should extend AiActivate in the future --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/aiactivate.cpp | 9 +- apps/openmw/mwmechanics/aiactivate.hpp | 3 +- apps/openmw/mwmechanics/aipackage.hpp | 3 +- apps/openmw/mwmechanics/aipersue.cpp | 108 ++++++++++++++++++ apps/openmw/mwmechanics/aipersue.hpp | 29 +++++ apps/openmw/mwmechanics/aisequence.cpp | 11 +- apps/openmw/mwmechanics/aisequence.hpp | 3 + .../mwmechanics/mechanicsmanagerimp.cpp | 9 +- apps/openmw/mwscript/aiextensions.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 11 +- 11 files changed, 171 insertions(+), 19 deletions(-) create mode 100644 apps/openmw/mwmechanics/aipersue.cpp create mode 100644 apps/openmw/mwmechanics/aipersue.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 20011b0d9..f7977dc59 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -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 security spellsuccess spellcasting disease pickpocket levelledlist combat steering ) diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp index 472bca88f..8610cf4b2 100644 --- a/apps/openmw/mwmechanics/aiactivate.cpp +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -9,11 +9,9 @@ #include "steering.hpp" #include "movement.hpp" -#include "creaturestats.hpp" -MWMechanics::AiActivate::AiActivate(const std::string &objectId, int arg) - : mObjectId(objectId), - mArg(arg) +MWMechanics::AiActivate::AiActivate(const std::string &objectId) + : mObjectId(objectId) { } MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const @@ -27,9 +25,6 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration) Movement &movement = actor.getClass().getMovementSettings(actor); const ESM::Cell *cell = actor.getCell()->getCell(); - if (mArg == 1) // run to actor - actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); - MWWorld::Ptr player = world->getPlayerPtr(); if(cell->mData.mX != player.getCell()->getCell()->mData.mX) { diff --git a/apps/openmw/mwmechanics/aiactivate.hpp b/apps/openmw/mwmechanics/aiactivate.hpp index aa8725db2..fd54869f6 100644 --- a/apps/openmw/mwmechanics/aiactivate.hpp +++ b/apps/openmw/mwmechanics/aiactivate.hpp @@ -12,7 +12,7 @@ namespace MWMechanics class AiActivate : public AiPackage { public: - AiActivate(const std::string &objectId, int arg); + AiActivate(const std::string &objectId); virtual AiActivate *clone() const; virtual bool execute (const MWWorld::Ptr& actor,float duration); ///< \return Package completed? @@ -20,7 +20,6 @@ namespace MWMechanics private: std::string mObjectId; - int mArg; PathFinder mPathFinder; int mCellX; diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 74c77bf97..8e015da15 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -19,7 +19,8 @@ namespace MWMechanics TypeIdEscort = 2, TypeIdFollow = 3, TypeIdActivate = 4, - TypeIdCombat = 5 + TypeIdCombat = 5, + TypeIdPersue = 6 }; virtual ~AiPackage(); diff --git a/apps/openmw/mwmechanics/aipersue.cpp b/apps/openmw/mwmechanics/aipersue.cpp new file mode 100644 index 000000000..21239860f --- /dev/null +++ b/apps/openmw/mwmechanics/aipersue.cpp @@ -0,0 +1,108 @@ +#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) +{ + //TODO: Guards should not dialague with player after crime reset + + 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; +} diff --git a/apps/openmw/mwmechanics/aipersue.hpp b/apps/openmw/mwmechanics/aipersue.hpp new file mode 100644 index 000000000..3fd708ab3 --- /dev/null +++ b/apps/openmw/mwmechanics/aipersue.hpp @@ -0,0 +1,29 @@ +#ifndef GAME_MWMECHANICS_AIPERSUE_H +#define GAME_MWMECHANICS_AIPERSUE_H + +#include "aipackage.hpp" +#include + +#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 diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index ba69b8098..c67367a6c 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -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; @@ -161,7 +170,7 @@ void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list) else if (it->mType == ESM::AI_Activate) { ESM::AIActivate data = it->mActivate; - package = new MWMechanics::AiActivate(data.mName.toString(), 0); + package = new MWMechanics::AiActivate(data.mName.toString()); } else //if (it->mType == ESM::AI_Follow) { diff --git a/apps/openmw/mwmechanics/aisequence.hpp b/apps/openmw/mwmechanics/aisequence.hpp index 62f48f981..07b7c898c 100644 --- a/apps/openmw/mwmechanics/aisequence.hpp +++ b/apps/openmw/mwmechanics/aisequence.hpp @@ -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? diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 4d1fca72d..6b9d6902e 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -13,6 +13,7 @@ #include "../mwworld/player.hpp" #include "aicombat.hpp" +#include "aipersue.hpp" #include "aiactivate.hpp" #include @@ -838,8 +839,6 @@ namespace MWMechanics std::vector neighbors; mActors.getObjectsInRange(Ogre::Vector3(ptr.getRefData().getPosition().pos), esmStore.get().find("fAlarmRadius")->getInt(), neighbors); - - // Did anyone see the crime? for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { if (*it == ptr) // Not the player @@ -880,12 +879,12 @@ namespace MWMechanics { creatureStats1.getAiSequence().stack(AiCombat(ptr)); creatureStats1.setHostile(true); - creatureStats1.getAiSequence().execute(*it,0); + creatureStats1.getAiSequence().execute(*it1,0); } else // will the guard persue the player? { - creatureStats1.getAiSequence().stack(AiActivate(ptr.getClass().getId(ptr), 1)); - creatureStats1.getAiSequence().execute(*it,0); + creatureStats1.getAiSequence().stack(AiPersue(ptr.getClass().getId(ptr))); + creatureStats1.getAiSequence().execute(*it1,0); } } // will the witness fight the player? diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 898788bf1..8314d011a 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -47,7 +47,7 @@ namespace MWScript // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i buttons; @@ -2776,10 +2780,15 @@ namespace MWWorld std::vector neighbors = ptr.getClass().getCreatureStats(ptr).getPlayerWitnesses(); for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { - // This to reset for each witness: + // Reset states // TODO: More research is needed to complete this list it->getClass().getCreatureStats(*it).setHostile(false); it->getClass().getCreatureStats(*it).setAlarmed(false); + + // Stop guard persue + if(it->getClass().isClass(*it, "Guard")) + it->getClass().getCreatureStats(*it).getAiSequence().stopPersue(); + } ptr.getClass().getCreatureStats(ptr).resetPlayerWitnesses(); } From 6f1211dd8d8140585a20d24693645561fa4611cc Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 2 Apr 2014 12:23:38 -0400 Subject: [PATCH 07/16] Moved mWitnesses into Player. resetCrime for paying fine. --- apps/openmw/mwmechanics/creaturestats.cpp | 14 -------------- apps/openmw/mwmechanics/creaturestats.hpp | 6 ------ apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwscript/miscextensions.cpp | 6 +++++- apps/openmw/mwworld/player.cpp | 13 +++++++++++++ apps/openmw/mwworld/player.hpp | 6 ++++++ apps/openmw/mwworld/worldimp.cpp | 4 ++-- 7 files changed, 27 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index cb1d8e275..feed8d182 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -17,7 +17,6 @@ namespace MWMechanics mAttacked (false), mHostile (false), mAttackingOrSpell(false), mIsWerewolf(false), - mWitnesses(), mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mHitRecovery(false), mBlock(false), mMovementFlags(0), mDrawState (DrawState_Nothing), mAttackStrength(0.f) { @@ -497,17 +496,4 @@ namespace MWMechanics { return mGoldPool; } - - void CreatureStats::addPlayerWitnesses(std::vector witnesses) - { - mWitnesses.insert(mWitnesses.end(), witnesses.begin(), witnesses.end()); - } - std::vector CreatureStats::getPlayerWitnesses() const - { - return mWitnesses; - } - void CreatureStats::resetPlayerWitnesses() - { - mWitnesses.clear(); - } } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 527adf8c0..20a9a5799 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -59,8 +59,6 @@ namespace MWMechanics int mGoldPool; // the pool of merchant gold not in inventory - std::vector mWitnesses; // the witnesses to players crimes - protected: bool mIsWerewolf; AttributeValue mWerewolfAttributes[8]; @@ -235,10 +233,6 @@ namespace MWMechanics void setGoldPool(int pool); int getGoldPool() const; - - void addPlayerWitnesses(std::vector witnesses); - std::vector getPlayerWitnesses() const; - void resetPlayerWitnesses(); }; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 6b9d6902e..8714e3eaf 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -901,7 +901,7 @@ namespace MWMechanics } } if (reported) - ptr.getClass().getCreatureStats(ptr).addPlayerWitnesses(neighbors); + MWBase::Environment::get().getWorld()->getPlayer().addPlayerWitnesses(neighbors); return reported; } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index fa8441aa5..781a34368 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -810,9 +810,11 @@ namespace MWScript public: virtual void execute(Interpreter::Runtime &runtime) { + MWBase::World* world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); player.getClass().getNpcStats(player).setBounty(0); - MWBase::Environment::get().getWorld()->confiscateStolenItems(player); + world->confiscateStolenItems(player); + world->resetCrimes(player); } }; @@ -821,8 +823,10 @@ namespace MWScript public: virtual void execute(Interpreter::Runtime &runtime) { + MWBase::World* world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); player.getClass().getNpcStats(player).setBounty(0); + world->resetCrimes(player); } }; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 6d551ecf1..7db2afb3f 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -274,4 +274,17 @@ namespace MWWorld return false; } + + void Player::addPlayerWitnesses(std::vector witnesses) + { + mWitnesses.insert(mWitnesses.end(), witnesses.begin(), witnesses.end()); + } + std::vector Player::getPlayerWitnesses() const + { + return mWitnesses; + } + void Player::resetPlayerWitnesses() + { + mWitnesses.clear(); + } } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 7eb023a2b..001d3b7a6 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -41,6 +41,8 @@ namespace MWWorld bool mAutoMove; int mForwardBackward; bool mTeleported; + + std::vector mWitnesses; public: Player(const ESM::NPC *player, const MWBase::World& world); @@ -94,6 +96,10 @@ namespace MWWorld void write (ESM::ESMWriter& writer) const; bool readRecord (ESM::ESMReader& reader, int32_t type); + + void addPlayerWitnesses(std::vector witnesses); + std::vector getPlayerWitnesses() const; + void resetPlayerWitnesses(); }; } #endif diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 726176c07..848b57b54 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2777,7 +2777,7 @@ namespace MWWorld void World::resetCrimes(const MWWorld::Ptr& ptr) { // Reset witnesses to the players crimes - std::vector neighbors = ptr.getClass().getCreatureStats(ptr).getPlayerWitnesses(); + std::vector neighbors = mPlayer->getPlayerWitnesses(); for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { // Reset states @@ -2790,7 +2790,7 @@ namespace MWWorld it->getClass().getCreatureStats(*it).getAiSequence().stopPersue(); } - ptr.getClass().getCreatureStats(ptr).resetPlayerWitnesses(); + mPlayer->resetPlayerWitnesses(); } void World::spawnRandomCreature(const std::string &creatureList) From 510f2d10ac38f16c0fc0d9846a2ecdd2a9212df9 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Wed, 2 Apr 2014 14:20:33 -0400 Subject: [PATCH 08/16] Replaces broken code with todo --- apps/openmw/mwworld/worldimp.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 848b57b54..954b8e126 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2763,8 +2763,7 @@ namespace MWWorld message += "\n" + skillMsg; } - // sleep the player, this doesn't work - //player.getClass().calculateRestoration(player, days, true); + // TODO: Sleep the player resetCrimes(player); From 58b135a2be7d23f77192b2471702fd4ec960310f Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Thu, 3 Apr 2014 00:50:09 -0400 Subject: [PATCH 09/16] Crime is now checked every frame call --- apps/openmw/mwbase/world.hpp | 2 - apps/openmw/mwmechanics/actors.cpp | 53 +++++++++++++++++-- apps/openmw/mwmechanics/actors.hpp | 2 + apps/openmw/mwmechanics/aipersue.cpp | 4 +- apps/openmw/mwmechanics/creaturestats.cpp | 12 ++++- apps/openmw/mwmechanics/creaturestats.hpp | 5 ++ .../mwmechanics/mechanicsmanagerimp.cpp | 47 +++------------- apps/openmw/mwscript/miscextensions.cpp | 5 -- apps/openmw/mwworld/player.cpp | 13 ----- apps/openmw/mwworld/player.hpp | 4 -- apps/openmw/mwworld/worldimp.cpp | 21 -------- apps/openmw/mwworld/worldimp.hpp | 1 - 12 files changed, 76 insertions(+), 93 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 170e6705a..bb6f5741d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -513,8 +513,6 @@ namespace MWBase virtual void explodeSpell (const Ogre::Vector3& origin, const MWWorld::Ptr& object, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName) = 0; - - virtual void resetCrimes(const MWWorld::Ptr& ptr) = 0; }; } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 92be89f2f..11469c1a9 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -29,6 +29,9 @@ #include "aicombat.hpp" #include "aifollow.hpp" +#include "aipersue.hpp" + +#include "../mwbase/dialoguemanager.hpp" //------------------------ namespace { @@ -175,14 +178,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(); @@ -214,7 +219,7 @@ namespace MWMechanics creatureStats.setHostile(true); } } - + updateCrimePersuit(ptr, duration); creatureStats.getAiSequence().execute (ptr,duration); } @@ -711,6 +716,48 @@ namespace MWMechanics } } + void Actors::updateCrimePersuit(const MWWorld::Ptr& ptr, float duration) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + int bounty = player.getClass().getNpcStats(player).getBounty(); + + // TODO: Move me! I shouldn't be here... + const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); + float cutoff = float(esmStore.get().find("iCrimeThreshold")->getInt()) * + float(esmStore.get().find("iCrimeThresholdMultiplier")->getInt()) * + esmStore.get().find("fCrimeGoldDiscountMult")->getFloat(); + + if (ptr != player) + { + CreatureStats& creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr); + // Alarmed or not, I will kill you because you've commited heinous against the empire + if ((!creatureStats.isAlarmed() || creatureStats.isAlarmed()) && + ptr.getClass().isClass(ptr, "Guard") && bounty >= cutoff && !creatureStats.isHostile()) + creatureStats.getAiSequence().stack(AiPersue(player.getClass().getId(player))); + else if (creatureStats.isAlarmed()) + { + MWBase::Environment::get().getDialogueManager()->say(ptr, "Thief"); + if(bounty == 0) + { + creatureStats.setAlarmed(false); + creatureStats.setHostile(false); + if (ptr.getClass().isClass(ptr, "Guard")) + creatureStats.getAiSequence().stopPersue(); + creatureStats.getAiSequence().stopCombat(); + + } + + if (ptr.getClass().isClass(ptr, "Guard") && !creatureStats.isHostile()) + creatureStats.getAiSequence().stack(AiPersue(player.getClass().getId(player))); + else if (!creatureStats.isHostile()) + { + creatureStats.getAiSequence().stack(AiCombat(player)); + creatureStats.setHostile(true); + } + } + } + } + Actors::Actors() {} Actors::~Actors() diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 4b18ac862..d61d74258 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -42,6 +42,8 @@ namespace MWMechanics void updateEquippedLight (const MWWorld::Ptr& ptr, float duration); + void updateCrimePersuit (const MWWorld::Ptr& ptr, float duration); + public: Actors(); diff --git a/apps/openmw/mwmechanics/aipersue.cpp b/apps/openmw/mwmechanics/aipersue.cpp index 21239860f..36e18946c 100644 --- a/apps/openmw/mwmechanics/aipersue.cpp +++ b/apps/openmw/mwmechanics/aipersue.cpp @@ -19,10 +19,8 @@ MWMechanics::AiPersue *MWMechanics::AiPersue::clone() const { return new AiPersue(*this); } -bool MWMechanics::AiPersue::execute (const MWWorld::Ptr& actor,float duration) +bool MWMechanics::AiPersue::execute (const MWWorld::Ptr& actor, float duration) { - //TODO: Guards should not dialague with player after crime reset - MWBase::World *world = MWBase::Environment::get().getWorld(); ESM::Position pos = actor.getRefData().getPosition(); Movement &movement = actor.getClass().getMovementSettings(actor); diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index feed8d182..a358917de 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -14,7 +14,7 @@ namespace MWMechanics CreatureStats::CreatureStats() : mLevel (0), mDead (false), mDied (false), mFriendlyHits (0), mTalkedTo (false), mAlarmed (false), - mAttacked (false), mHostile (false), + mAttacked (false), mHostile (false), mAssaulted(false), mAttackingOrSpell(false), mIsWerewolf(false), mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mHitRecovery(false), mBlock(false), @@ -316,6 +316,16 @@ namespace MWMechanics mHostile = hostile; } + bool CreatureStats::isAssaulted() const + { + return mAssaulted; + } + + void CreatureStats::setAssaulted (bool assaulted) + { + mAssaulted = assaulted; + } + bool CreatureStats::getCreatureTargetted() const { std::string target; diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 20a9a5799..7db895dab 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -39,6 +39,7 @@ namespace MWMechanics bool mAlarmed; bool mAttacked; bool mHostile; + bool mAssaulted; bool mAttackingOrSpell; bool mKnockdown; bool mHitRecovery; @@ -186,6 +187,10 @@ namespace MWMechanics void setHostile (bool hostile); + bool isAssaulted() const; + + void setAssaulted (bool assaulted); + bool getCreatureTargetted() const; float getEvasion() const; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8714e3eaf..2edb3d177 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1,5 +1,6 @@ #include "mechanicsmanagerimp.hpp" +#include "npcstats.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/inventorystore.hpp" @@ -12,10 +13,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" -#include "aicombat.hpp" -#include "aipersue.hpp" -#include "aiactivate.hpp" - #include #include "spellcasting.hpp" @@ -827,11 +824,6 @@ namespace MWMechanics else if (type == OT_Theft) alarm = esmStore.get().find("iAlarmStealing")->getInt(); - // what is the bounty cutoff? To high the guards will attack - float cutoff = float(esmStore.get().find("iCrimeThreshold")->getInt()) * - float(esmStore.get().find("iCrimeThresholdMultiplier")->getInt()) * - esmStore.get().find("fCrimeGoldDiscountMult")->getFloat(); - // Innocent until proven guilty bool reported = false; @@ -846,8 +838,9 @@ namespace MWMechanics CreatureStats& creatureStats = MWWorld::Class::get(*it).getCreatureStats(*it); - // Did a witness see the crime? - if ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) + // Was the crime seen or the victim assulted? + if ( ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) || + type == OT_Assault) { // Say something! // TODO: Add more messages @@ -858,7 +851,6 @@ namespace MWMechanics if (creatureStats.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) { reported = true; - reportCrime(ptr, victim, type, arg); // Tell everyone else for (std::vector::iterator it1 = neighbors.begin(); it1 != neighbors.end(); ++it1) @@ -870,38 +862,13 @@ namespace MWMechanics CreatureStats& creatureStats1 = MWWorld::Class::get(*it1).getCreatureStats(*it1); if (creatureStats1.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) creatureStats1.setAlarmed(true); - - // was the witness a guard? - if (it1->getClass().isClass(*it1, "Guard")) - { - // will the guard try to kill the player? - if (ptr.getClass().getNpcStats(ptr).getBounty() >= cutoff) - { - creatureStats1.getAiSequence().stack(AiCombat(ptr)); - creatureStats1.setHostile(true); - creatureStats1.getAiSequence().execute(*it1,0); - } - else // will the guard persue the player? - { - creatureStats1.getAiSequence().stack(AiPersue(ptr.getClass().getId(ptr))); - creatureStats1.getAiSequence().execute(*it1,0); - } - } - // will the witness fight the player? - else if (creatureStats1.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm || - type == OT_Assault) - { - creatureStats1.getAiSequence().stack(AiCombat(ptr)); - creatureStats1.setHostile(true); - creatureStats1.getAiSequence().execute(*it1,0); - } } break; // Someone saw the crime and everyone has been told - } + } } } - if (reported) - MWBase::Environment::get().getWorld()->getPlayer().addPlayerWitnesses(neighbors); + if(reported) + reportCrime(ptr, victim, type, arg); return reported; } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 781a34368..cd29e2c91 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -810,11 +810,8 @@ namespace MWScript public: virtual void execute(Interpreter::Runtime &runtime) { - MWBase::World* world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); player.getClass().getNpcStats(player).setBounty(0); - world->confiscateStolenItems(player); - world->resetCrimes(player); } }; @@ -823,10 +820,8 @@ namespace MWScript public: virtual void execute(Interpreter::Runtime &runtime) { - MWBase::World* world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); player.getClass().getNpcStats(player).setBounty(0); - world->resetCrimes(player); } }; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 7db2afb3f..6d551ecf1 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -274,17 +274,4 @@ namespace MWWorld return false; } - - void Player::addPlayerWitnesses(std::vector witnesses) - { - mWitnesses.insert(mWitnesses.end(), witnesses.begin(), witnesses.end()); - } - std::vector Player::getPlayerWitnesses() const - { - return mWitnesses; - } - void Player::resetPlayerWitnesses() - { - mWitnesses.clear(); - } } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 001d3b7a6..b41e6fc9f 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -96,10 +96,6 @@ namespace MWWorld void write (ESM::ESMWriter& writer) const; bool readRecord (ESM::ESMReader& reader, int32_t type); - - void addPlayerWitnesses(std::vector witnesses); - std::vector getPlayerWitnesses() const; - void resetPlayerWitnesses(); }; } #endif diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 954b8e126..f3e404c35 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2765,33 +2765,12 @@ namespace MWWorld // TODO: Sleep the player - resetCrimes(player); - std::vector buttons; buttons.push_back("#{sOk}"); MWBase::Environment::get().getWindowManager()->messageBox(message, buttons); } } - void World::resetCrimes(const MWWorld::Ptr& ptr) - { - // Reset witnesses to the players crimes - std::vector neighbors = mPlayer->getPlayerWitnesses(); - for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) - { - // Reset states - // TODO: More research is needed to complete this list - it->getClass().getCreatureStats(*it).setHostile(false); - it->getClass().getCreatureStats(*it).setAlarmed(false); - - // Stop guard persue - if(it->getClass().isClass(*it, "Guard")) - it->getClass().getCreatureStats(*it).getAiSequence().stopPersue(); - - } - mPlayer->resetPlayerWitnesses(); - } - void World::spawnRandomCreature(const std::string &creatureList) { const ESM::CreatureLevList* list = getStore().get().find(creatureList); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 06d49ad24..42f52cb61 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -611,7 +611,6 @@ namespace MWWorld virtual void explodeSpell (const Ogre::Vector3& origin, const MWWorld::Ptr& object, const ESM::EffectList& effects, const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName); - virtual void resetCrimes(const MWWorld::Ptr& ptr); }; } From b1abef7a38a9e21b2fcffcf3473829dfbbb8149c Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Thu, 3 Apr 2014 01:07:56 -0400 Subject: [PATCH 10/16] Cleaned up code --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwscript/miscextensions.cpp | 1 + apps/openmw/mwworld/player.hpp | 3 +-- apps/openmw/mwworld/worldimp.cpp | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 2edb3d177..39cf63cd0 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -867,7 +867,7 @@ namespace MWMechanics } } } - if(reported) + if (reported) reportCrime(ptr, victim, type, arg); return reported; } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index cd29e2c91..a7f31c80b 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -822,6 +822,7 @@ namespace MWScript { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); player.getClass().getNpcStats(player).setBounty(0); + MWBase::Environment::get().getWorld()->confiscateStolenItems(player); } }; diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index b41e6fc9f..9d3fbbeec 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -41,8 +41,7 @@ namespace MWWorld bool mAutoMove; int mForwardBackward; bool mTeleported; - - std::vector mWitnesses; + public: Player(const ESM::NPC *player, const MWBase::World& world); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f3e404c35..ac6f9d380 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -29,7 +29,6 @@ #include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/levelledlist.hpp" #include "../mwmechanics/combat.hpp" -#include "../mwmechanics/actors.hpp" #include "../mwrender/sky.hpp" #include "../mwrender/animation.hpp" From 0c957a3cde6c93830c587b3bb6e5a4687f6184be Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Thu, 3 Apr 2014 14:53:31 -0400 Subject: [PATCH 11/16] Added witnesses to the mix --- apps/openmw/mwmechanics/actors.cpp | 44 ++++++++++++------- apps/openmw/mwmechanics/creaturestats.cpp | 12 ++++- apps/openmw/mwmechanics/creaturestats.hpp | 5 +++ .../mwmechanics/mechanicsmanagerimp.cpp | 11 ++++- apps/openmw/mwworld/player.cpp | 13 +++++- apps/openmw/mwworld/player.hpp | 6 +++ 6 files changed, 70 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 11469c1a9..6d9f23aa2 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -719,9 +719,9 @@ namespace MWMechanics void Actors::updateCrimePersuit(const MWWorld::Ptr& ptr, float duration) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - int bounty = player.getClass().getNpcStats(player).getBounty(); + CreatureStats& creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr); - // TODO: Move me! I shouldn't be here... + /// \todo Move me! I shouldn't be here... const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); float cutoff = float(esmStore.get().find("iCrimeThreshold")->getInt()) * float(esmStore.get().find("iCrimeThresholdMultiplier")->getInt()) * @@ -729,30 +729,40 @@ namespace MWMechanics if (ptr != player) { - CreatureStats& creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr); - // Alarmed or not, I will kill you because you've commited heinous against the empire - if ((!creatureStats.isAlarmed() || creatureStats.isAlarmed()) && - ptr.getClass().isClass(ptr, "Guard") && bounty >= cutoff && !creatureStats.isHostile()) - creatureStats.getAiSequence().stack(AiPersue(player.getClass().getId(player))); - else if (creatureStats.isAlarmed()) + // If I'm a guard and I'm not hostile + if (ptr.getClass().isClass(ptr, "Guard") && !creatureStats.isHostile()) { - MWBase::Environment::get().getDialogueManager()->say(ptr, "Thief"); - if(bounty == 0) + // 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); + } + } + + // if I was a witness to a crime + if (creatureStats.getCrimeId() != -1) + { + if(player.getClass().getNpcStats(player).getBounty() == 0) { creatureStats.setAlarmed(false); creatureStats.setHostile(false); if (ptr.getClass().isClass(ptr, "Guard")) creatureStats.getAiSequence().stopPersue(); creatureStats.getAiSequence().stopCombat(); - + creatureStats.setCrimeId(-1); } - - if (ptr.getClass().isClass(ptr, "Guard") && !creatureStats.isHostile()) - creatureStats.getAiSequence().stack(AiPersue(player.getClass().getId(player))); - else if (!creatureStats.isHostile()) + else if (creatureStats.isAlarmed()) { - creatureStats.getAiSequence().stack(AiCombat(player)); - creatureStats.setHostile(true); + if (ptr.getClass().isClass(ptr, "Guard") && !creatureStats.isHostile()) + creatureStats.getAiSequence().stack(AiPersue(player.getClass().getId(player))); + else if (!creatureStats.isHostile()) + { + creatureStats.getAiSequence().stack(AiCombat(player)); + creatureStats.setHostile(true); + } } } } diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index a358917de..17d36be79 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -15,7 +15,7 @@ namespace MWMechanics : mLevel (0), mDead (false), mDied (false), mFriendlyHits (0), mTalkedTo (false), mAlarmed (false), mAttacked (false), mHostile (false), mAssaulted(false), - mAttackingOrSpell(false), + mAttackingOrSpell(false), mCrimeId(-1), mIsWerewolf(false), mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mHitRecovery(false), mBlock(false), mMovementFlags(0), mDrawState (DrawState_Nothing), mAttackStrength(0.f) @@ -326,6 +326,16 @@ namespace MWMechanics mAssaulted = assaulted; } + int CreatureStats::getCrimeId() const + { + return mCrimeId; + } + + void CreatureStats::setCrimeId (int id) + { + mCrimeId = id; + } + bool CreatureStats::getCreatureTargetted() const { std::string target; diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 7db895dab..67afd9f25 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -40,6 +40,7 @@ namespace MWMechanics bool mAttacked; bool mHostile; bool mAssaulted; + int mCrimeId; bool mAttackingOrSpell; bool mKnockdown; bool mHitRecovery; @@ -191,6 +192,10 @@ namespace MWMechanics void setAssaulted (bool assaulted); + int getCrimeId() const; + + void setCrimeId (int id); + bool getCreatureTargetted() const; float getEvasion() const; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 39cf63cd0..54622c0b4 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -810,6 +810,7 @@ namespace MWMechanics return false; const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); + MWWorld::Player player = MWBase::Environment::get().getWorld()->getPlayer(); // What amount of alarm did this crime generate? int alarm; @@ -858,13 +859,19 @@ namespace MWMechanics if (*it1 == ptr) // Not the player continue; - // was the witness alarmed? + // Will the witness be affected by the crime? CreatureStats& creatureStats1 = MWWorld::Class::get(*it1).getCreatureStats(*it1); if (creatureStats1.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) + { creatureStats1.setAlarmed(true); + creatureStats1.setCrimeId(player.getWitnessTotal()); + player.addWitness(); + } } break; // Someone saw the crime and everyone has been told - } + } + else if (type == OT_Assault) + creatureStats.setAlarmed(true); } } if (reported) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 6d551ecf1..7c576960f 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -28,8 +28,9 @@ namespace MWWorld : mCellStore(0), mLastKnownExteriorPosition(0,0,0), mAutoMove(false), - mForwardBackward (0), + mForwardBackward(0), mTeleported(false), + mWitnessTotal(0), mMarkedCell(NULL) { mPlayer.mBase = player; @@ -65,6 +66,16 @@ namespace MWWorld return mSign; } + void Player::addWitness() + { + mWitnessTotal++; + } + + int Player::getWitnessTotal() const + { + return mWitnessTotal; + } + void Player::setDrawState (MWMechanics::DrawState_ state) { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 9d3fbbeec..71c231481 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -41,6 +41,8 @@ namespace MWWorld bool mAutoMove; int mForwardBackward; bool mTeleported; + + int mWitnessTotal; public: @@ -65,6 +67,10 @@ namespace MWWorld void setBirthSign(const std::string &sign); + void addWitness(); + + int getWitnessTotal() const; + const std::string &getBirthSign() const; void setDrawState (MWMechanics::DrawState_ state); From 70919ba60ae596bab066e34bfb860ca5a4aa539e Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Thu, 3 Apr 2014 16:13:14 -0400 Subject: [PATCH 12/16] Removed witnesses and minor changes --- apps/openmw/mwmechanics/actors.cpp | 19 +++++++++------ apps/openmw/mwmechanics/creaturestats.cpp | 24 ++----------------- apps/openmw/mwmechanics/creaturestats.hpp | 9 ------- .../mwmechanics/mechanicsmanagerimp.cpp | 11 ++------- apps/openmw/mwworld/player.cpp | 11 --------- apps/openmw/mwworld/player.hpp | 6 ----- 6 files changed, 16 insertions(+), 64 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 6d9f23aa2..56f24a747 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -739,11 +739,12 @@ namespace MWMechanics { creatureStats.getAiSequence().stack(AiCombat(player)); creatureStats.setHostile(true); + creatureStats.setAlarmed(true); } } // if I was a witness to a crime - if (creatureStats.getCrimeId() != -1) + if (creatureStats.isAlarmed()) { if(player.getClass().getNpcStats(player).getBounty() == 0) { @@ -752,19 +753,23 @@ namespace MWMechanics if (ptr.getClass().isClass(ptr, "Guard")) creatureStats.getAiSequence().stopPersue(); creatureStats.getAiSequence().stopCombat(); - creatureStats.setCrimeId(-1); } - else if (creatureStats.isAlarmed()) + else if (!creatureStats.isHostile()) { - if (ptr.getClass().isClass(ptr, "Guard") && !creatureStats.isHostile()) + if (ptr.getClass().isClass(ptr, "Guard")) creatureStats.getAiSequence().stack(AiPersue(player.getClass().getId(player))); - else if (!creatureStats.isHostile()) - { + 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); + } } } diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 17d36be79..feed8d182 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -14,8 +14,8 @@ namespace MWMechanics CreatureStats::CreatureStats() : mLevel (0), mDead (false), mDied (false), mFriendlyHits (0), mTalkedTo (false), mAlarmed (false), - mAttacked (false), mHostile (false), mAssaulted(false), - mAttackingOrSpell(false), mCrimeId(-1), + mAttacked (false), mHostile (false), + mAttackingOrSpell(false), mIsWerewolf(false), mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mHitRecovery(false), mBlock(false), mMovementFlags(0), mDrawState (DrawState_Nothing), mAttackStrength(0.f) @@ -316,26 +316,6 @@ namespace MWMechanics mHostile = hostile; } - bool CreatureStats::isAssaulted() const - { - return mAssaulted; - } - - void CreatureStats::setAssaulted (bool assaulted) - { - mAssaulted = assaulted; - } - - int CreatureStats::getCrimeId() const - { - return mCrimeId; - } - - void CreatureStats::setCrimeId (int id) - { - mCrimeId = id; - } - bool CreatureStats::getCreatureTargetted() const { std::string target; diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 67afd9f25..97bcd719c 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -40,7 +40,6 @@ namespace MWMechanics bool mAttacked; bool mHostile; bool mAssaulted; - int mCrimeId; bool mAttackingOrSpell; bool mKnockdown; bool mHitRecovery; @@ -188,14 +187,6 @@ namespace MWMechanics void setHostile (bool hostile); - bool isAssaulted() const; - - void setAssaulted (bool assaulted); - - int getCrimeId() const; - - void setCrimeId (int id); - bool getCreatureTargetted() const; float getEvasion() const; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 54622c0b4..9119b3ab6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -839,9 +839,8 @@ namespace MWMechanics CreatureStats& creatureStats = MWWorld::Class::get(*it).getCreatureStats(*it); - // Was the crime seen or the victim assulted? - if ( ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) || - type == OT_Assault) + // Was the crime seen? + if ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) { // Say something! // TODO: Add more messages @@ -862,16 +861,10 @@ namespace MWMechanics // Will the witness be affected by the crime? CreatureStats& creatureStats1 = MWWorld::Class::get(*it1).getCreatureStats(*it1); if (creatureStats1.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) - { creatureStats1.setAlarmed(true); - creatureStats1.setCrimeId(player.getWitnessTotal()); - player.addWitness(); - } } break; // Someone saw the crime and everyone has been told } - else if (type == OT_Assault) - creatureStats.setAlarmed(true); } } if (reported) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 7c576960f..bfeca9653 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -30,7 +30,6 @@ namespace MWWorld mAutoMove(false), mForwardBackward(0), mTeleported(false), - mWitnessTotal(0), mMarkedCell(NULL) { mPlayer.mBase = player; @@ -66,16 +65,6 @@ namespace MWWorld return mSign; } - void Player::addWitness() - { - mWitnessTotal++; - } - - int Player::getWitnessTotal() const - { - return mWitnessTotal; - } - void Player::setDrawState (MWMechanics::DrawState_ state) { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 71c231481..9d3fbbeec 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -41,8 +41,6 @@ namespace MWWorld bool mAutoMove; int mForwardBackward; bool mTeleported; - - int mWitnessTotal; public: @@ -67,10 +65,6 @@ namespace MWWorld void setBirthSign(const std::string &sign); - void addWitness(); - - int getWitnessTotal() const; - const std::string &getBirthSign() const; void setDrawState (MWMechanics::DrawState_ state); From df5cbe5dec98b1c14cd4aa8916d692b40c5b18f1 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Fri, 4 Apr 2014 08:10:35 -0400 Subject: [PATCH 13/16] Minor changes --- apps/openmw/mwmechanics/actors.cpp | 1 + apps/openmw/mwmechanics/creaturestats.cpp | 3 ++- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 ++++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 56f24a747..fcec5a3fb 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -750,6 +750,7 @@ namespace MWMechanics { creatureStats.setAlarmed(false); creatureStats.setHostile(false); + creatureStats.setAttacked(false); if (ptr.getClass().isClass(ptr, "Guard")) creatureStats.getAiSequence().stopPersue(); creatureStats.getAiSequence().stopCombat(); diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index feed8d182..f81613ed1 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -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 diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 9119b3ab6..8d546b598 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -840,7 +840,8 @@ namespace MWMechanics CreatureStats& creatureStats = MWWorld::Class::get(*it).getCreatureStats(*it); // Was the crime seen? - if ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) + if ( ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) || + type == OT_Assault ) { // Say something! // TODO: Add more messages @@ -860,7 +861,8 @@ namespace MWMechanics // Will the witness be affected by the crime? CreatureStats& creatureStats1 = MWWorld::Class::get(*it1).getCreatureStats(*it1); - if (creatureStats1.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) + if (creatureStats1.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm || + type == OT_Assault) creatureStats1.setAlarmed(true); } break; // Someone saw the crime and everyone has been told From 940c88d2ecd6b25a3919596eff3a60b7a7d2d0fe Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Sat, 5 Apr 2014 10:26:14 -0400 Subject: [PATCH 14/16] Cleaned up code, implemented crime ids There is a problem with my game freezing. ToggleAi stops my character --- apps/openmw/mwmechanics/actors.cpp | 57 +++++++++++-------- apps/openmw/mwmechanics/creaturestats.hpp | 4 -- .../mwmechanics/mechanicsmanagerimp.cpp | 35 ++++++------ apps/openmw/mwmechanics/npcstats.cpp | 11 ++++ apps/openmw/mwmechanics/npcstats.hpp | 6 +- apps/openmw/mwscript/miscextensions.cpp | 4 ++ apps/openmw/mwworld/player.cpp | 19 ++++++- apps/openmw/mwworld/player.hpp | 12 ++-- 8 files changed, 95 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index fcec5a3fb..ee30dae6d 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -31,8 +31,6 @@ #include "aifollow.hpp" #include "aipersue.hpp" -#include "../mwbase/dialoguemanager.hpp" //------------------------ - namespace { @@ -718,49 +716,58 @@ namespace MWMechanics void Actors::updateCrimePersuit(const MWWorld::Ptr& ptr, float duration) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - CreatureStats& creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr); - - /// \todo Move me! I shouldn't be here... - const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - float cutoff = float(esmStore.get().find("iCrimeThreshold")->getInt()) * - float(esmStore.get().find("iCrimeThresholdMultiplier")->getInt()) * - esmStore.get().find("fCrimeGoldDiscountMult")->getFloat(); - - if (ptr != player) + MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + if (ptr != playerPtr) { + // get stats of witness + CreatureStats& creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr); + NpcStats& npcStats = MWWorld::Class::get(ptr).getNpcStats(ptr); + MWWorld::Player player = MWBase::Environment::get().getWorld()->getPlayer(); + // 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().find("iCrimeThreshold")->getInt()) * + float(esmStore.get().find("iCrimeThresholdMultiplier")->getInt()) * + esmStore.get().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)) + if ( playerPtr.getClass().getNpcStats(playerPtr).getBounty() >= cutoff + && MWBase::Environment::get().getWorld()->getLOS(ptr, playerPtr) + && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(playerPtr, ptr)) { - creatureStats.getAiSequence().stack(AiCombat(player)); + creatureStats.getAiSequence().stack(AiCombat(playerPtr)); creatureStats.setHostile(true); - creatureStats.setAlarmed(true); + npcStats.setCrimeId(player.getNewCrimeId()); } } // if I was a witness to a crime - if (creatureStats.isAlarmed()) + if (npcStats.getCrimeId() != -1) { - if(player.getClass().getNpcStats(player).getBounty() == 0) + // if you've payed for your crimes and I havent noticed + if(npcStats.getCrimeId() < player.getCrimeId() ) { - creatureStats.setAlarmed(false); - creatureStats.setHostile(false); - creatureStats.setAttacked(false); + // 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))); + creatureStats.getAiSequence().stack(AiPersue(playerPtr.getClass().getId(playerPtr))); else - creatureStats.getAiSequence().stack(AiCombat(player)); + creatureStats.getAiSequence().stack(AiCombat(playerPtr)); creatureStats.setHostile(true); } } @@ -768,7 +775,7 @@ namespace MWMechanics // if I didn't report a crime was I attacked? else if (creatureStats.getAttacked() && !creatureStats.isHostile()) { - creatureStats.getAiSequence().stack(AiCombat(player)); + creatureStats.getAiSequence().stack(AiCombat(playerPtr)); creatureStats.setHostile(true); } } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 97bcd719c..5dc59e5ab 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -39,7 +39,6 @@ namespace MWMechanics bool mAlarmed; bool mAttacked; bool mHostile; - bool mAssaulted; bool mAttackingOrSpell; bool mKnockdown; bool mHitRecovery; @@ -176,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; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8d546b598..a26520fc7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -828,42 +828,43 @@ namespace MWMechanics // Innocent until proven guilty bool reported = false; - // Find all the NPC's close enough, ie. within fAlarmRadius of the player + // Find all the NPCs within the alarm radius std::vector neighbors; mActors.getObjectsInRange(Ogre::Vector3(ptr.getRefData().getPosition().pos), - esmStore.get().find("fAlarmRadius")->getInt(), neighbors); + esmStore.get().find("fAlarmRadius")->getInt(), neighbors); + + // Find an actor who witnessed the crime for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { - if (*it == ptr) // Not the player - continue; - - CreatureStats& creatureStats = MWWorld::Class::get(*it).getCreatureStats(*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 ) { - // Say something! // TODO: Add more messages if (type == OT_Theft) - MWBase::Environment::get().getDialogueManager()->say(*it, "Thief"); + MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); + else if (type == OT_Assault) + MWBase::Environment::get().getDialogueManager()->say(*it, "attack"); // Will the witness report the crime? - if (creatureStats.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) + if (it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) { reported = true; + int id = player.getNewCrimeId(); - // Tell everyone else + // Tell everyone, including yourself for (std::vector::iterator it1 = neighbors.begin(); it1 != neighbors.end(); ++it1) { - if (*it1 == ptr) // Not the player - continue; + if (*it1 == ptr) continue; // not the player - // Will the witness be affected by the crime? - CreatureStats& creatureStats1 = MWWorld::Class::get(*it1).getCreatureStats(*it1); - if (creatureStats1.getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm || - type == OT_Assault) - creatureStats1.setAlarmed(true); + // 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 } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 74587a626..4f014102d 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -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) diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index ad493be3c..0ae596a54 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -37,6 +37,7 @@ namespace MWMechanics std::set mExpelled; std::map 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); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index a7f31c80b..aa554adc3 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -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,6 +814,7 @@ namespace MWScript { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); player.getClass().getNpcStats(player).setBounty(0); + MWBase::Environment::get().getWorld()->getPlayer().recordCrimeId(); } }; @@ -823,6 +826,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(); } }; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index bfeca9653..d39ec2c0f 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -30,7 +30,9 @@ namespace MWWorld mAutoMove(false), mForwardBackward(0), mTeleported(false), - mMarkedCell(NULL) + mMarkedCell(NULL), + mCurrentCrimeId(-1), + mPayedCrimeId(-1) { mPlayer.mBase = player; mPlayer.mRef.mRefID = "player"; @@ -274,4 +276,19 @@ namespace MWWorld return false; } + + int Player::getNewCrimeId() + { + return mCurrentCrimeId++; + } + + void Player::recordCrimeId() + { + mPayedCrimeId = mCurrentCrimeId; + } + + int Player::getCrimeId() const + { + return mCurrentCrimeId; + } } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 9d3fbbeec..7dbaaddb4 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -41,6 +41,9 @@ namespace MWWorld bool mAutoMove; int mForwardBackward; bool mTeleported; + + int mCurrentCrimeId; // the id assigned witnesses + int mPayedCrimeId; // the last id payed off (0 bounty) public: @@ -64,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); @@ -95,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 From a274b48f2f8c136f03a43d2ba62c5771277f52ef Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Sat, 5 Apr 2014 22:45:40 -0400 Subject: [PATCH 15/16] States are saved. Crime is reacted to. Issues where some crime is ignored. Needs a lot more work --- apps/openmw/mwmechanics/actors.cpp | 23 +++++++++---------- .../mwmechanics/mechanicsmanagerimp.cpp | 14 +++++------ apps/openmw/mwworld/player.cpp | 4 ++-- components/esm/npcstats.cpp | 6 +++++ components/esm/npcstats.hpp | 1 + components/esm/player.cpp | 6 +++++ components/esm/player.hpp | 3 +++ 7 files changed, 36 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ee30dae6d..ca37b152c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -716,13 +716,12 @@ namespace MWMechanics void Actors::updateCrimePersuit(const MWWorld::Ptr& ptr, float duration) { - MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); - if (ptr != playerPtr) + 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); - MWWorld::Player player = MWBase::Environment::get().getWorld()->getPlayer(); // If I'm a guard and I'm not hostile if (ptr.getClass().isClass(ptr, "Guard") && !creatureStats.isHostile()) @@ -733,13 +732,13 @@ namespace MWMechanics float(esmStore.get().find("iCrimeThresholdMultiplier")->getInt()) * esmStore.get().find("fCrimeGoldDiscountMult")->getFloat(); // Attack on sight if bounty is greater than the cutoff - if ( playerPtr.getClass().getNpcStats(playerPtr).getBounty() >= cutoff - && MWBase::Environment::get().getWorld()->getLOS(ptr, playerPtr) - && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(playerPtr, ptr)) + 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(playerPtr)); + creatureStats.getAiSequence().stack(AiCombat(player)); creatureStats.setHostile(true); - npcStats.setCrimeId(player.getNewCrimeId()); + npcStats.setCrimeId( MWBase::Environment::get().getWorld()->getPlayer().getCrimeId() ); } } @@ -747,7 +746,7 @@ namespace MWMechanics if (npcStats.getCrimeId() != -1) { // if you've payed for your crimes and I havent noticed - if(npcStats.getCrimeId() < player.getCrimeId() ) + if( npcStats.getCrimeId() <= MWBase::Environment::get().getWorld()->getPlayer().getCrimeId() ) { // Calm witness down if (ptr.getClass().isClass(ptr, "Guard")) @@ -765,9 +764,9 @@ namespace MWMechanics else if (!creatureStats.isHostile()) { if (ptr.getClass().isClass(ptr, "Guard")) - creatureStats.getAiSequence().stack(AiPersue(playerPtr.getClass().getId(playerPtr))); + creatureStats.getAiSequence().stack(AiPersue(player.getClass().getId(player))); else - creatureStats.getAiSequence().stack(AiCombat(playerPtr)); + creatureStats.getAiSequence().stack(AiCombat(player)); creatureStats.setHostile(true); } } @@ -775,7 +774,7 @@ namespace MWMechanics // if I didn't report a crime was I attacked? else if (creatureStats.getAttacked() && !creatureStats.isHostile()) { - creatureStats.getAiSequence().stack(AiCombat(playerPtr)); + creatureStats.getAiSequence().stack(AiCombat(player)); creatureStats.setHostile(true); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index a26520fc7..d162e1037 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -810,7 +810,6 @@ namespace MWMechanics return false; const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - MWWorld::Player player = MWBase::Environment::get().getWorld()->getPlayer(); // What amount of alarm did this crime generate? int alarm; @@ -842,22 +841,23 @@ namespace MWMechanics if ( ( MWBase::Environment::get().getWorld()->getLOS(ptr, *it) && awarenessCheck(ptr, *it) ) || type == OT_Assault ) { - // TODO: Add more messages - if (type == OT_Theft) - MWBase::Environment::get().getDialogueManager()->say(*it, "thief"); - else if (type == OT_Assault) - MWBase::Environment::get().getDialogueManager()->say(*it, "attack"); // Will the witness report the crime? if (it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) { reported = true; - int id = player.getNewCrimeId(); + int id = MWBase::Environment::get().getWorld()->getPlayer().getNewCrimeId(); // Tell everyone, including yourself for (std::vector::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 diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index d39ec2c0f..e8179b9f3 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -279,7 +279,7 @@ namespace MWWorld int Player::getNewCrimeId() { - return mCurrentCrimeId++; + return ++mCurrentCrimeId; } void Player::recordCrimeId() @@ -289,6 +289,6 @@ namespace MWWorld int Player::getCrimeId() const { - return mCurrentCrimeId; + return mPayedCrimeId; } } diff --git a/components/esm/npcstats.cpp b/components/esm/npcstats.cpp index 531424ab2..80238ad68 100644 --- a/components/esm/npcstats.cpp +++ b/components/esm/npcstats.cpp @@ -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); } \ No newline at end of file diff --git a/components/esm/npcstats.hpp b/components/esm/npcstats.hpp index b3f70db25..504cd0163 100644 --- a/components/esm/npcstats.hpp +++ b/components/esm/npcstats.hpp @@ -45,6 +45,7 @@ namespace ESM float mTimeToStartDrowning; float mLastDrowningHit; float mLevelHealthBonus; + int mCrimeId; void load (ESMReader &esm); void save (ESMWriter &esm) const; diff --git a/components/esm/player.cpp b/components/esm/player.cpp index d5ddc74d0..e41cc535e 100644 --- a/components/esm/player.cpp +++ b/components/esm/player.cpp @@ -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); } \ No newline at end of file diff --git a/components/esm/player.hpp b/components/esm/player.hpp index 0d70ee090..377c8547a 100644 --- a/components/esm/player.hpp +++ b/components/esm/player.hpp @@ -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; From e2fab228f9956fb68e850dfbbe6d579d174184d3 Mon Sep 17 00:00:00 2001 From: Jeffrey Haines Date: Mon, 14 Apr 2014 18:11:04 -0400 Subject: [PATCH 16/16] Save state is handled correctly now. --- apps/openmw/mwmechanics/npcstats.cpp | 3 +++ apps/openmw/mwworld/player.cpp | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 4f014102d..e11e3b0c4 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -452,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::const_iterator iter (mExpelled.begin()); @@ -504,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; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index e8179b9f3..a4a4e9568 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -196,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; @@ -241,6 +244,9 @@ namespace MWWorld !world.getStore().get().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];