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